提交 3657ae13 编写于 作者: N Niko Matsakis

Don't normalize associated types when in region binders, wait until we instantiate

them. Also fix some assertions and handling of builtin bounds.
上级 2bbd2f9c
......@@ -109,6 +109,10 @@ pub fn normalize_associated_type<'a>(&mut self,
cause: ObligationCause<'tcx>)
-> Ty<'tcx>
{
debug!("normalize_associated_type(trait_ref={}, item_name={})",
trait_ref.repr(infcx.tcx),
item_name.repr(infcx.tcx));
assert!(!trait_ref.has_escaping_regions());
let ty_var = infcx.next_ty_var();
......@@ -120,6 +124,9 @@ pub fn normalize_associated_type<'a>(&mut self,
});
let obligation = Obligation::new(cause, projection.as_predicate());
self.register_predicate(infcx, obligation);
debug!("normalize_associated_type: result={}", ty_var.repr(infcx.tcx));
ty_var
}
......
......@@ -1141,7 +1141,11 @@ fn builtin_bound(&mut self,
obligation: &TraitObligation<'tcx>)
-> Result<BuiltinBoundConditions<'tcx>,SelectionError<'tcx>>
{
// TODO seems like we ought to skolemize here, oder?
// Note: these tests operate on types that may contain bound
// regions. To be proper, we ought to skolemize here, but we
// forego the skolemization and defer it until the
// confirmation step.
let self_ty = self.infcx.shallow_resolve(obligation.predicate.0.self_ty());
return match self_ty.sty {
ty::ty_infer(ty::IntVar(_)) |
......@@ -1627,13 +1631,31 @@ fn vtable_builtin_data(&mut self,
-> VtableBuiltinData<PredicateObligation<'tcx>>
{
let derived_cause = self.derived_cause(obligation, BuiltinDerivedObligation);
let obligations = nested.iter().map(|&t| {
util::predicate_for_builtin_bound(
self.tcx(),
derived_cause.clone(),
bound,
obligation.recursion_depth + 1,
t)
let obligations = nested.iter().map(|&bound_ty| {
// the obligation might be higher-ranked, e.g. for<'a> &'a
// int : Copy. In that case, we will wind up with
// late-bound regions in the `nested` vector. So for each
// one we instantiate to a skolemized region, do our work
// to produce something like `&'0 int : Copy`, and then
// re-bind it. This is a bit of busy-work but preserves
// the invariant that we only manipulate free regions, not
// bound ones.
self.infcx.try(|snapshot| {
let (skol_ty, skol_map) =
self.infcx().skolemize_late_bound_regions(&ty::Binder(bound_ty), snapshot);
let skol_predicate =
util::predicate_for_builtin_bound(
self.tcx(),
derived_cause.clone(),
bound,
obligation.recursion_depth + 1,
skol_ty);
match skol_predicate {
Ok(skol_predicate) => Ok(self.infcx().plug_leaks(skol_map, snapshot,
&skol_predicate)),
Err(ErrorReported) => Err(ErrorReported)
}
})
}).collect::<Result<_, _>>();
let mut obligations = match obligations {
Ok(o) => o,
......
......@@ -6903,8 +6903,19 @@ fn has_regions_escaping_depth(&self, depth: u32) -> bool {
impl<'tcx> RegionEscape for TraitRef<'tcx> {
fn has_regions_escaping_depth(&self, depth: u32) -> bool {
self.substs.types.iter().any(|t| t.has_regions_escaping_depth(depth)) &&
self.substs.regions().iter().any(|t| t.has_regions_escaping_depth(depth))
self.substs.types.iter().any(|t| t.has_regions_escaping_depth(depth)) ||
self.substs.regions.has_regions_escaping_depth(depth)
}
}
impl<'tcx> RegionEscape for subst::RegionSubsts {
fn has_regions_escaping_depth(&self, depth: u32) -> bool {
match *self {
subst::ErasedRegions => false,
subst::NonerasedRegions(ref r) => {
r.iter().any(|t| t.has_regions_escaping_depth(depth))
}
}
}
}
......@@ -6921,7 +6932,7 @@ fn has_regions_escaping_depth(&self, depth: u32) -> bool {
}
impl<'tcx> RegionEscape for TraitPredicate<'tcx> {
fn has_regions_escaping_depth(&self, depth: uint) -> bool {
fn has_regions_escaping_depth(&self, depth: u32) -> bool {
self.trait_ref.has_regions_escaping_depth(depth)
}
}
......@@ -6933,14 +6944,14 @@ fn has_regions_escaping_depth(&self, depth: u32) -> bool {
}
impl<'tcx> RegionEscape for ProjectionPredicate<'tcx> {
fn has_regions_escaping_depth(&self, depth: uint) -> bool {
fn has_regions_escaping_depth(&self, depth: u32) -> bool {
self.projection_ty.has_regions_escaping_depth(depth) ||
self.ty.has_regions_escaping_depth(depth)
}
}
impl<'tcx> RegionEscape for ProjectionTy<'tcx> {
fn has_regions_escaping_depth(&self, depth: uint) -> bool {
fn has_regions_escaping_depth(&self, depth: u32) -> bool {
self.trait_ref.has_regions_escaping_depth(depth)
}
}
......
......@@ -33,7 +33,8 @@ pub fn normalize_associated_types_in<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
let mut normalizer = AssociatedTypeNormalizer { span: span,
body_id: body_id,
infcx: infcx,
fulfillment_cx: fulfillment_cx };
fulfillment_cx: fulfillment_cx,
region_binders: 0 };
value.fold_with(&mut normalizer)
}
......@@ -42,6 +43,7 @@ struct AssociatedTypeNormalizer<'a,'tcx:'a> {
fulfillment_cx: &'a mut FulfillmentContext<'tcx>,
span: Span,
body_id: ast::NodeId,
region_binders: uint,
}
impl<'a,'tcx> TypeFolder<'tcx> for AssociatedTypeNormalizer<'a,'tcx> {
......@@ -49,9 +51,29 @@ fn tcx(&self) -> &ty::ctxt<'tcx> {
self.infcx.tcx
}
fn enter_region_binder(&mut self) {
self.region_binders += 1;
}
fn exit_region_binder(&mut self) {
self.region_binders -= 1;
}
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
// We don't want to normalize associated types that occur inside of region
// binders, because they may contain bound regions, and we can't cope with that.
//
// Example:
//
// for<'a> fn(<T as Foo<&'a>>::A)
//
// Instead of normalizing `<T as Foo<&'a>>::A` here, we'll
// normalize it when we instantiate those bound regions (which
// should occur eventually).
let no_region_binders = self.region_binders == 0;
match ty.sty {
ty::ty_projection(ref data) => {
ty::ty_projection(ref data) if no_region_binders => {
let cause =
ObligationCause::new(
self.span,
......
......@@ -14,6 +14,7 @@
use astconv;
use middle::infer;
use middle::region::CodeExtent;
use middle::subst;
use middle::ty::{mod, ToPolyTraitRef, Ty};
use rscope::RegionScope;
......@@ -132,10 +133,13 @@ fn check_unboxed_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
fcx.write_ty(expr.id, closure_type);
let fn_sig =
ty::liberate_late_bound_regions(fcx.tcx(), CodeExtent::from_node_id(body.id), &fn_ty.sig);
check_fn(fcx.ccx,
ast::Unsafety::Normal,
expr.id,
&fn_ty.sig,
&fn_sig,
decl,
expr.id,
&*body,
......@@ -310,7 +314,7 @@ fn check_boxed_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
decl,
abi::Rust,
expected_sig);
let fty_sig = fn_ty.sig.clone();
let fn_sig = fn_ty.sig.clone();
let fty = ty::mk_closure(tcx, fn_ty);
debug!("check_expr_fn fty={}", fcx.infcx().ty_to_string(fty));
......@@ -325,10 +329,13 @@ fn check_boxed_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
ty::UniqTraitStore => (ast::Unsafety::Normal, expr.id)
};
let fn_sig =
ty::liberate_late_bound_regions(tcx, CodeExtent::from_node_id(body.id), &fn_sig);
check_fn(fcx.ccx,
inherited_style,
inherited_style_id,
&fty_sig,
&fn_sig,
&*decl,
expr.id,
&*body,
......
......@@ -424,17 +424,18 @@ fn instantiate_method_sig(&mut self,
debug!("method_bounds after subst = {}",
method_bounds.repr(self.tcx()));
// Substitute the type/early-bound-regions into the method
// signature. In addition, the method signature may bind
// late-bound regions, so instantiate those.
let method_sig = self.fcx.instantiate_type_scheme(self.span,
&all_substs,
&pick.method_ty.fty.sig);
debug!("late-bound lifetimes from method substituted, method_sig={}",
// Instantiate late-bound regions and substitute the trait
// parameters into the method type to get the actual method type.
//
// NB: Instantiate late-bound regions first so that
// `instantiate_type_scheme` can normalize associated types that
// may reference those regions.
let method_sig = self.replace_late_bound_regions_with_fresh_var(&pick.method_ty.fty.sig);
debug!("late-bound lifetimes from method instantiated, method_sig={}",
method_sig.repr(self.tcx()));
let method_sig = self.replace_late_bound_regions_with_fresh_var(&method_sig);
debug!("late-bound lifetimes from method instantiated, method_sig={}",
let method_sig = self.fcx.instantiate_type_scheme(self.span, &all_substs, &method_sig);
debug!("type scheme substituted, method_sig={}",
method_sig.repr(self.tcx()));
InstantiatedMethodSig {
......
......@@ -190,19 +190,21 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>,
debug!("lookup_in_trait_adjusted: method_num={} method_ty={}",
method_num, method_ty.repr(fcx.tcx()));
// Substitute the trait parameters into the method type and
// instantiate late-bound regions to get the actual method type.
let bare_fn_ty = fcx.instantiate_type_scheme(span,
&trait_ref.substs,
&method_ty.fty);
// Instantiate late-bound regions and substitute the trait
// parameters into the method type to get the actual method type.
//
// NB: Instantiate late-bound regions first so that
// `instantiate_type_scheme` can normalize associated types that
// may reference those regions.
let fn_sig = fcx.infcx().replace_late_bound_regions_with_fresh_var(span,
infer::FnCall,
&bare_fn_ty.sig).0;
&method_ty.fty.sig).0;
let fn_sig = fcx.instantiate_type_scheme(span, &trait_ref.substs, &fn_sig);
let transformed_self_ty = fn_sig.inputs[0];
let fty = ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(ty::BareFnTy {
sig: ty::Binder(fn_sig),
unsafety: bare_fn_ty.unsafety,
abi: bare_fn_ty.abi.clone(),
unsafety: method_ty.fty.unsafety,
abi: method_ty.fty.abi.clone(),
}));
debug!("lookup_in_trait_adjusted: matched method fty={} obligation={}",
......
......@@ -432,13 +432,15 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
ty::ty_bare_fn(_, ref fn_ty) => {
let inh = Inherited::new(ccx.tcx, param_env);
// Compute the fty from point of view of inside fn
// (replace any type-scheme with a type, and normalize
// associated types appearing in the fn signature).
let fn_ty = fn_ty.subst(ccx.tcx, &inh.param_env.free_substs);
let fn_ty = inh.normalize_associated_types_in(body.span, body.id, &fn_ty);
let fcx = check_fn(ccx, fn_ty.unsafety, id, &fn_ty.sig,
// Compute the fty from point of view of inside fn.
let fn_sig =
fn_ty.sig.subst(ccx.tcx, &inh.param_env.free_substs);
let fn_sig =
liberate_late_bound_regions(ccx.tcx, CodeExtent::from_node_id(body.id), &fn_sig);
let fn_sig =
inh.normalize_associated_types_in(body.span, body.id, &fn_sig);
let fcx = check_fn(ccx, fn_ty.unsafety, id, &fn_sig,
decl, id, body, &inh);
vtable::select_all_fcx_obligations_or_error(&fcx);
......@@ -542,7 +544,7 @@ fn visit_item(&mut self, _: &ast::Item) { }
fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
unsafety: ast::Unsafety,
unsafety_id: ast::NodeId,
fn_sig: &ty::PolyFnSig<'tcx>,
fn_sig: &ty::FnSig<'tcx>,
decl: &ast::FnDecl,
fn_id: ast::NodeId,
body: &ast::Block,
......@@ -552,10 +554,6 @@ fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
let tcx = ccx.tcx;
let err_count_on_creation = tcx.sess.err_count();
// First, we have to replace any bound regions in the fn type with free ones.
// The free region references will be bound the node_id of the body block.
let fn_sig = liberate_late_bound_regions(tcx, CodeExtent::from_node_id(body.id), fn_sig);
let arg_tys = fn_sig.inputs[];
let ret_ty = fn_sig.output;
......@@ -1161,39 +1159,80 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
}
}
// We now need to check that the signature of the impl method is
// compatible with that of the trait method. We do this by
// checking that `impl_fty <: trait_fty`.
//
// FIXME. Unfortunately, this doesn't quite work right now because
// associated type normalization is not integrated into subtype
// checks. For the comparison to be valid, we need to
// normalize the associated types in the impl/trait methods
// first. However, because function types bind regions, just
// calling `normalize_associated_types_in` would have no effect on
// any associated types appearing in the fn arguments or return
// type.
// Compute skolemized form of impl and trait method tys.
let impl_fty = ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(impl_m.fty.clone()));
let impl_fty = impl_fty.subst(tcx, impl_to_skol_substs);
let trait_fty = ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(trait_m.fty.clone()));
let trait_fty = trait_fty.subst(tcx, &trait_to_skol_substs);
let trait_fty =
assoc::normalize_associated_types_in(&infcx,
&mut fulfillment_cx,
impl_m_span,
impl_m_body_id,
&trait_fty);
// Check the impl method type IM is a subtype of the trait method
// type TM. To see why this makes sense, think of a vtable. The
// expected type of the function pointers in the vtable is the
// type TM of the trait method. The actual type will be the type
// IM of the impl method. Because we know that IM <: TM, that
// means that anywhere a TM is expected, a IM will do instead. In
// other words, anyone expecting to call a method with the type
// from the trait, can safely call a method with the type from the
// impl instead.
debug!("checking trait method for compatibility: impl ty {}, trait ty {}",
impl_fty.repr(tcx),
trait_fty.repr(tcx));
match infer::mk_subty(&infcx, false, infer::MethodCompatCheck(impl_m_span),
impl_fty, trait_fty) {
Ok(()) => {}
Err(ref terr) => {
let err = infcx.try(|snapshot| {
let origin = infer::MethodCompatCheck(impl_m_span);
let (impl_sig, _) =
infcx.replace_late_bound_regions_with_fresh_var(impl_m_span,
infer::HigherRankedType,
&impl_m.fty.sig);
let impl_sig =
impl_sig.subst(tcx, impl_to_skol_substs);
let impl_sig =
assoc::normalize_associated_types_in(&infcx,
&mut fulfillment_cx,
impl_m_span,
impl_m_body_id,
&impl_sig);
let impl_fty = ty::mk_bare_fn(tcx, None, ty::BareFnTy { unsafety: impl_m.fty.unsafety,
abi: impl_m.fty.abi,
sig: ty::Binder(impl_sig) });
debug!("compare_impl_method: impl_fty={}",
impl_fty.repr(tcx));
let (trait_sig, skol_map) =
infcx.skolemize_late_bound_regions(&trait_m.fty.sig, snapshot);
let trait_sig =
trait_sig.subst(tcx, &trait_to_skol_substs);
let trait_sig =
assoc::normalize_associated_types_in(&infcx,
&mut fulfillment_cx,
impl_m_span,
impl_m_body_id,
&trait_sig);
let trait_fty = ty::mk_bare_fn(tcx, None, ty::BareFnTy { unsafety: trait_m.fty.unsafety,
abi: trait_m.fty.abi,
sig: ty::Binder(trait_sig) });
debug!("compare_impl_method: trait_fty={}",
trait_fty.repr(tcx));
try!(infer::mk_subty(&infcx, false, origin, impl_fty, trait_fty));
infcx.leak_check(&skol_map, snapshot)
});
match err {
Ok(()) => { }
Err(terr) => {
debug!("checking trait method for compatibility: impl ty {}, trait ty {}",
impl_fty.repr(tcx),
trait_fty.repr(tcx));
span_err!(tcx.sess, impl_m_span, E0053,
"method `{}` has an incompatible type for trait: {}",
token::get_name(trait_m.name),
ty::type_err_to_str(tcx, terr));
ty::note_and_explain_type_err(tcx, terr);
"method `{}` has an incompatible type for trait: {}",
token::get_name(trait_m.name),
ty::type_err_to_str(tcx, &terr));
return;
}
}
......@@ -1791,7 +1830,7 @@ fn register_unsize_obligations(&self,
/// Also returns the substitution from the type parameters on `def_id` to the fresh variables.
/// Registers any trait obligations specified on `def_id` at the same time.
///
/// Note that function is only intended to be used with types (notably, not impls). This is
/// Note that function is only intended to be used with types (notably, not fns). This is
/// because it doesn't do any instantiation of late-bound regions.
pub fn instantiate_type(&self,
span: Span,
......@@ -3061,12 +3100,18 @@ fn check_call(fcx: &FnCtxt,
}
};
// Replace any bound regions that appear in the function
// signature with region variables
// Replace any late-bound regions that appear in the function
// signature with region variables. We also have to
// renormalize the associated types at this point, since they
// previously appeared within a `Binder<>` and hence would not
// have been normalized before.
let fn_sig =
fcx.infcx().replace_late_bound_regions_with_fresh_var(call_expr.span,
infer::FnCall,
fn_sig).0;
let fn_sig =
fcx.normalize_associated_types_in(call_expr.span,
&fn_sig);
// Call the generic checker.
check_argument_types(fcx,
......
......@@ -104,7 +104,8 @@ fn accumulate_from_ty(&mut self, ty: Ty<'tcx>) {
ty::ty_enum(def_id, substs) |
ty::ty_struct(def_id, substs) => {
self.accumulate_from_adt(ty, def_id, substs)
let item_scheme = ty::lookup_item_type(self.tcx, def_id);
self.accumulate_from_adt(ty, def_id, &item_scheme.generics, substs)
}
ty::ty_vec(t, _) |
......@@ -127,7 +128,9 @@ fn accumulate_from_ty(&mut self, ty: Ty<'tcx>) {
// TODO What region constraints are necessary here, if any??
// this seems like a minimal requirement:
self.accumulate_from_ty(data.trait_ref.self_ty());
let trait_def = ty::lookup_trait_def(self.tcx, data.trait_ref.def_id);
self.accumulate_from_adt(ty, data.trait_ref.def_id,
&trait_def.generics, &data.trait_ref.substs)
}
ty::ty_tup(ref tuptys) => {
......@@ -222,14 +225,12 @@ fn push_param_constraint(&mut self,
fn accumulate_from_adt(&mut self,
ty: Ty<'tcx>,
def_id: ast::DefId,
generics: &ty::Generics<'tcx>,
substs: &Substs<'tcx>)
{
// The generic declarations from the type, appropriately
// substituted for the actual substitutions.
let generics =
ty::lookup_item_type(self.tcx, def_id)
.generics
.subst(self.tcx, substs);
let generics = generics.subst(self.tcx, substs);
// Variance of each type/region parameter.
let variances = ty::item_variances(self.tcx, def_id);
......
......@@ -349,8 +349,7 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
//
// (I believe we should do the same for traits, but
// that will require an RFC. -nmatsakis)
let bounds = type_scheme
.generics.to_bounds(self.tcx(), substs);
let bounds = type_scheme.generics.to_bounds(self.tcx(), substs);
let bounds = filter_to_trait_obligations(bounds);
self.fcx.add_obligations_for_parameters(
traits::ObligationCause::new(self.span,
......
......@@ -133,6 +133,9 @@ fn visit_path_segment(&mut self, path_span: Span, path_segment: &'v PathSegment)
fn visit_path_parameters(&mut self, path_span: Span, path_parameters: &'v PathParameters) {
walk_path_parameters(self, path_span, path_parameters)
}
fn visit_assoc_type_binding(&mut self, type_binding: &'v TypeBinding) {
walk_assoc_type_binding(self, type_binding)
}
fn visit_attribute(&mut self, _attr: &'v Attribute) {}
}
......@@ -467,6 +470,9 @@ pub fn walk_path_parameters<'v, V: Visitor<'v>>(visitor: &mut V,
for lifetime in data.lifetimes.iter() {
visitor.visit_lifetime_ref(lifetime);
}
for binding in data.bindings.iter() {
visitor.visit_assoc_type_binding(&**binding);
}
}
ast::ParenthesizedParameters(ref data) => {
for typ in data.inputs.iter() {
......@@ -479,6 +485,12 @@ pub fn walk_path_parameters<'v, V: Visitor<'v>>(visitor: &mut V,
}
}
pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(visitor: &mut V,
type_binding: &'v TypeBinding) {
visitor.visit_ident(type_binding.span, type_binding.ident);
visitor.visit_ty(&*type_binding.ty);
}
pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) {
match pattern.node {
PatEnum(ref path, ref children) => {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册