Don't normalize associated types when in region binders, wait until we instantiate
them. Also fix some assertions and handling of builtin bounds.
This commit is contained in:
parent
2bbd2f9cea
commit
3657ae13f5
@ -109,6 +109,10 @@ impl<'tcx> FulfillmentContext<'tcx> {
|
||||
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 @@ impl<'tcx> FulfillmentContext<'tcx> {
|
||||
});
|
||||
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 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
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 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
-> 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 @@ impl RegionEscape for Region {
|
||||
|
||||
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 @@ impl<'tcx> RegionEscape for EquatePredicate<'tcx> {
|
||||
}
|
||||
|
||||
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 @@ impl<T:RegionEscape,U:RegionEscape> RegionEscape for OutlivesPredicate<T,U> {
|
||||
}
|
||||
|
||||
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 @@ impl<'a,'tcx> TypeFolder<'tcx> for AssociatedTypeNormalizer<'a,'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 super::{check_fn, Expectation, FnCtxt};
|
||||
|
||||
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 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
||||
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);
|
||||
// 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_ty.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 @@ impl<'a, 'tcx, 'v> Visitor<'v> for GatherLocalsVisitor<'a, 'tcx> {
|
||||
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 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
/// 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_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
}
|
||||
};
|
||||
|
||||
// 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 @@ impl<'a, 'tcx> Wf<'a, '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 @@ impl<'a, 'tcx> Wf<'a, '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 @@ impl<'a, 'tcx> Wf<'a, 'tcx> {
|
||||
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 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'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 @@ pub trait Visitor<'v> {
|
||||
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) => {
|
||||
|
Loading…
x
Reference in New Issue
Block a user