mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-08 05:47:40 +00:00
Some refactoring and WIP on issue #2263.
This commit is contained in:
parent
ef33c5c9bc
commit
7e70412711
@ -81,7 +81,7 @@ export ty_opaque_box, mk_opaque_box;
|
||||
export ty_constr_arg;
|
||||
export ty_float, mk_float, mk_mach_float, type_is_fp;
|
||||
export ty_fn, fn_ty, mk_fn;
|
||||
export ty_fn_proto, ty_fn_ret, ty_fn_ret_style;
|
||||
export ty_fn_proto, ty_fn_ret, ty_fn_ret_style, tys_in_fn_ty;
|
||||
export ty_int, mk_int, mk_mach_int, mk_char;
|
||||
export ty_str, mk_str, type_is_str;
|
||||
export ty_vec, mk_vec, type_is_vec;
|
||||
@ -2090,6 +2090,11 @@ fn is_fn_ty(fty: t) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a vec of all the input and output types of fty.
|
||||
fn tys_in_fn_ty(fty: fn_ty) -> [t] {
|
||||
fty.inputs.map({|a| a.ty}) + [fty.output]
|
||||
}
|
||||
|
||||
// Just checks whether it's a fn that returns bool,
|
||||
// not its purity.
|
||||
fn is_pred_ty(fty: t) -> bool {
|
||||
|
@ -69,7 +69,8 @@ type parameter).
|
||||
import astconv::{ast_conv, ast_ty_to_ty};
|
||||
import collect::{methods}; // ccx.to_ty()
|
||||
import method::{methods}; // methods for method::lookup
|
||||
import regionmanip::{universally_quantify_regions_before_call,
|
||||
import middle::ty::tys_in_fn_ty;
|
||||
import regionmanip::{universally_quantify_from_sty,
|
||||
region_of, replace_bound_regions,
|
||||
collect_bound_regions_in_tys};
|
||||
import rscope::*;
|
||||
@ -718,7 +719,31 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
|
||||
|
||||
let mut bot = false;
|
||||
|
||||
let fty = universally_quantify_regions_before_call(fcx, sp, fty);
|
||||
// Replace all region parameters in the arguments and return
|
||||
// type with fresh region variables.
|
||||
|
||||
#debug["check_call_or_bind: before universal quant., fty=%s",
|
||||
fcx.ty_to_str(fty)];
|
||||
|
||||
// This is subtle: we expect `fty` to be a function type, which
|
||||
// normally introduce a level of binding. In this case, we want to
|
||||
// process the types bound by the function but not by any nested
|
||||
// functions. Therefore, we match one level of structure.
|
||||
let fty =
|
||||
alt structure_of(fcx, sp, fty) {
|
||||
sty @ ty::ty_fn(inner_fty) {
|
||||
let all_tys = tys_in_fn_ty(inner_fty);
|
||||
universally_quantify_from_sty(fcx, sp, all_tys, sty)
|
||||
}
|
||||
sty {
|
||||
#debug["not a fn ty: %?", sty];
|
||||
|
||||
// if not a function type, we're gonna' report an error at
|
||||
// some point, since the user is trying to call this thing
|
||||
fty
|
||||
}
|
||||
};
|
||||
|
||||
#debug["check_call_or_bind: after universal quant., fty=%s",
|
||||
fcx.ty_to_str(fty)];
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* Code to handle method lookups (which can be quite complex) */
|
||||
|
||||
import syntax::ast_map;
|
||||
import regionmanip::universally_quantify_regions;
|
||||
import regionmanip::universally_quantify_from_sty;
|
||||
import middle::typeck::infer::{ty_and_region_var_methods};
|
||||
|
||||
enum lookup = {
|
||||
@ -188,13 +188,12 @@ impl methods for lookup {
|
||||
|
||||
// Here "self" refers to the callee side...
|
||||
let self_ty =
|
||||
universally_quantify_regions(
|
||||
self.fcx, self.expr.span, self_ty);
|
||||
universally_quantify_from_sty(
|
||||
self.fcx, self.expr.span, [self_ty],
|
||||
ty::get(self_ty).struct);
|
||||
|
||||
// ... and "ty" refers to the caller side.
|
||||
let ty =
|
||||
universally_quantify_regions(
|
||||
self.fcx, self.expr.span, self.self_ty);
|
||||
let ty = self.self_ty;
|
||||
|
||||
// if we can assign the caller to the callee, that's a
|
||||
// potential match. Collect those in the vector.
|
||||
|
@ -1,11 +1,11 @@
|
||||
import middle::typeck::infer::{ty_and_region_var_methods};
|
||||
import syntax::print::pprust::{expr_to_str};
|
||||
|
||||
// Helper functions related to manipulating region types.
|
||||
|
||||
// Helper for the other universally_quantify_*() routines. Extracts the bound
|
||||
// regions from bound_tys and then replaces those same regions with fresh
|
||||
// variables in `sty`, returning the resulting type.
|
||||
// Extracts the bound regions from bound_tys and then replaces those same
|
||||
// regions in `sty` with fresh region variables, returning the resulting type.
|
||||
// Does not descend into fn types. This is used when deciding whether an impl
|
||||
// applies at a given call site. See also universally_quantify_before_call().
|
||||
fn universally_quantify_from_sty(fcx: @fn_ctxt,
|
||||
span: span,
|
||||
bound_tys: [ty::t],
|
||||
@ -30,44 +30,6 @@ fn universally_quantify_from_sty(fcx: @fn_ctxt,
|
||||
}
|
||||
}
|
||||
|
||||
// Replaces all region parameters in the given type with region variables.
|
||||
// Does not descend into fn types. This is used when deciding whether an impl
|
||||
// applies at a given call site. See also universally_quantify_before_call().
|
||||
fn universally_quantify_regions(fcx: @fn_ctxt,
|
||||
span: span,
|
||||
ty: ty::t) -> ty::t {
|
||||
universally_quantify_from_sty(fcx, span, [ty], ty::get(ty).struct)
|
||||
}
|
||||
|
||||
// Expects a function type. Replaces all region parameters in the arguments
|
||||
// and return type with fresh region variables. This is used when typechecking
|
||||
// function calls, bind expressions, and method calls.
|
||||
fn universally_quantify_regions_before_call(fcx: @fn_ctxt,
|
||||
span: span,
|
||||
ty: ty::t) -> ty::t {
|
||||
|
||||
#debug["universally_quantify_before_call(ty=%s)",
|
||||
fcx.ty_to_str(ty)];
|
||||
|
||||
// This is subtle: we expect `ty` to be a function type, which normally
|
||||
// introduce a level of binding. In this case, we want to process the
|
||||
// types bound by the function but not by any nested functions.
|
||||
// Therefore, we match one level of structure.
|
||||
alt structure_of(fcx, span, ty) {
|
||||
sty @ ty::ty_fn(fty) {
|
||||
let all_tys = fty.inputs.map({|a| a.ty}) + [fty.output];
|
||||
universally_quantify_from_sty(fcx, span, all_tys, sty)
|
||||
}
|
||||
sty {
|
||||
#debug["not a fn ty: %?", sty];
|
||||
|
||||
// if not a function type, we're gonna' report an error
|
||||
// at some point, since the user is trying to call this thing
|
||||
ty
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn replace_bound_regions(
|
||||
tcx: ty::ctxt,
|
||||
span: span,
|
||||
|
@ -147,12 +147,14 @@ import std::smallintmap::smallintmap;
|
||||
import std::smallintmap::map;
|
||||
import std::map::hashmap;
|
||||
import middle::ty;
|
||||
import middle::ty::{ty_vid, region_vid, vid};
|
||||
import syntax::ast;
|
||||
import middle::ty::{ty_vid, tys_in_fn_ty, region_vid, vid};
|
||||
import syntax::{ast, ast_util};
|
||||
import syntax::ast::{ret_style};
|
||||
import util::ppaux::{ty_to_str, mt_to_str};
|
||||
import result::{result, extensions, ok, err, map, map2, iter2};
|
||||
import ty::type_is_bot;
|
||||
import ty::{mk_fn, type_is_bot};
|
||||
import check::regionmanip::{collect_bound_regions_in_tys,
|
||||
replace_bound_regions};
|
||||
import driver::session::session;
|
||||
import util::common::{indent, indenter};
|
||||
|
||||
@ -453,6 +455,18 @@ impl ty_and_region_var_methods for infer_ctxt {
|
||||
fn next_region_var() -> ty::region {
|
||||
ret ty::re_var(self.next_region_var_id());
|
||||
}
|
||||
|
||||
fn ty_to_str(t: ty::t) -> str {
|
||||
ty_to_str(self.tcx,
|
||||
self.resolve_type_vars_if_possible(t))
|
||||
}
|
||||
|
||||
fn resolve_type_vars_if_possible(typ: ty::t) -> ty::t {
|
||||
alt infer::resolve_deep(self, typ, false) {
|
||||
result::ok(new_type) { ret new_type; }
|
||||
result::err(_) { ret typ; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl unify_methods for infer_ctxt {
|
||||
@ -1579,6 +1593,67 @@ impl of combine for sub {
|
||||
}
|
||||
}
|
||||
|
||||
fn fns(a: ty::fn_ty, b: ty::fn_ty) -> cres<ty::fn_ty> {
|
||||
// Rather than checking the subtype relationship between `a` and `b`
|
||||
// as-is, we need to do some extra work here in order to make sure
|
||||
// that function subtyping works correctly with respect to regions
|
||||
// (issue #2263).
|
||||
|
||||
// First, we instantiate each bound region in the subtype with a fresh
|
||||
// region variable.
|
||||
let a_isr =
|
||||
collect_bound_regions_in_tys(self.tcx,
|
||||
@nil,
|
||||
tys_in_fn_ty(a)) {
|
||||
|br|
|
||||
let rvar = self.infcx().next_region_var();
|
||||
#debug["Bound region %s maps to %s",
|
||||
bound_region_to_str(self.tcx, br),
|
||||
region_to_str(self.tcx, rvar)];
|
||||
rvar
|
||||
};
|
||||
|
||||
let a_ty = replace_bound_regions(self.tcx,
|
||||
ast_util::dummy_sp(),
|
||||
a_isr,
|
||||
mk_fn(self.tcx, a));
|
||||
#debug["a_ty: %s", self.infcx().ty_to_str(a_ty)];
|
||||
|
||||
// Second, we instantiate each bound region in the supertype with a
|
||||
// fresh concrete region.
|
||||
let b_isr =
|
||||
collect_bound_regions_in_tys(self.tcx,
|
||||
@nil,
|
||||
tys_in_fn_ty(b)) {
|
||||
|br| ty::re_bound(br) };
|
||||
// FIXME: or maybe re_skolemized? What would that look like?
|
||||
// (issue #2263)
|
||||
|
||||
let b_ty = replace_bound_regions(self.tcx,
|
||||
ast_util::dummy_sp(),
|
||||
b_isr,
|
||||
mk_fn(self.tcx, b));
|
||||
#debug["b_ty: %s", self.infcx().ty_to_str(b_ty)];
|
||||
|
||||
// Turn back into ty::fn_ty.
|
||||
alt (ty::get(a_ty).struct, ty::get(b_ty).struct) {
|
||||
(ty::ty_fn(a_fn_ty), ty::ty_fn(b_fn_ty)) {
|
||||
// Try to compare the supertype and subtype now that they've been
|
||||
// instantiated.
|
||||
super_fns(self, a_fn_ty, b_fn_ty)
|
||||
|
||||
}
|
||||
_ {
|
||||
// Shouldn't happen.
|
||||
self.infcx().tcx.sess.bug(
|
||||
#fmt["%s: at least one of %s and %s isn't a fn_ty",
|
||||
self.tag(),
|
||||
self.infcx().ty_to_str(a_ty),
|
||||
self.infcx().ty_to_str(b_ty)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Traits please:
|
||||
|
||||
fn flds(a: ty::field, b: ty::field) -> cres<ty::field> {
|
||||
@ -1598,10 +1673,6 @@ impl of combine for sub {
|
||||
super_args(self, a, b)
|
||||
}
|
||||
|
||||
fn fns(a: ty::fn_ty, b: ty::fn_ty) -> cres<ty::fn_ty> {
|
||||
super_fns(self, a, b)
|
||||
}
|
||||
|
||||
fn substs(as: ty::substs, bs: ty::substs) -> cres<ty::substs> {
|
||||
super_substs(self, as, bs)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user