substitutions in trait predicates
This commit is contained in:
parent
760a6654fb
commit
da2cf9b9d1
@ -112,12 +112,15 @@ pub enum SizedByDefault {
|
||||
No,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ConvertedBinding<'a, 'tcx> {
|
||||
item_name: Ident,
|
||||
kind: ConvertedBindingKind<'a, 'tcx>,
|
||||
gen_args: &'a GenericArgs<'a>,
|
||||
span: Span,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum ConvertedBindingKind<'a, 'tcx> {
|
||||
Equality(Ty<'tcx>),
|
||||
Constraint(&'a [hir::GenericBound<'a>]),
|
||||
@ -323,6 +326,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
|
||||
let tcx = self.tcx();
|
||||
let generics = tcx.generics_of(def_id);
|
||||
debug!("generics: {:?}", generics);
|
||||
|
||||
if generics.has_self {
|
||||
if generics.parent.is_some() {
|
||||
@ -557,7 +561,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
ConvertedBindingKind::Constraint(bounds)
|
||||
}
|
||||
};
|
||||
ConvertedBinding { item_name: binding.ident, kind, span: binding.span }
|
||||
ConvertedBinding {
|
||||
item_name: binding.ident,
|
||||
kind,
|
||||
gen_args: binding.gen_args,
|
||||
span: binding.span,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
@ -918,61 +927,28 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
dup_bindings: &mut FxHashMap<DefId, Span>,
|
||||
path_span: Span,
|
||||
) -> Result<(), ErrorReported> {
|
||||
// Given something like `U: SomeTrait<T = X>`, we want to produce a
|
||||
// predicate like `<U as SomeTrait>::T = X`. This is somewhat
|
||||
// subtle in the event that `T` is defined in a supertrait of
|
||||
// `SomeTrait`, because in that case we need to upcast.
|
||||
//
|
||||
// That is, consider this case:
|
||||
//
|
||||
// ```
|
||||
// trait SubTrait: SuperTrait<i32> { }
|
||||
// trait SuperTrait<A> { type T; }
|
||||
//
|
||||
// ... B: SubTrait<T = foo> ...
|
||||
// ```
|
||||
//
|
||||
// We want to produce `<B as SuperTrait<i32>>::T == foo`.
|
||||
|
||||
debug!(
|
||||
"add_predicates_for_ast_type_binding(hir_ref_id {:?}, trait_ref {:?}, binding {:?}, bounds {:?}",
|
||||
hir_ref_id, trait_ref, binding, bounds
|
||||
);
|
||||
let tcx = self.tcx();
|
||||
|
||||
if !speculative {
|
||||
// Given something like `U: SomeTrait<T = X>`, we want to produce a
|
||||
// predicate like `<U as SomeTrait>::T = X`. This is somewhat
|
||||
// subtle in the event that `T` is defined in a supertrait of
|
||||
// `SomeTrait`, because in that case we need to upcast.
|
||||
//
|
||||
// That is, consider this case:
|
||||
//
|
||||
// ```
|
||||
// trait SubTrait: SuperTrait<i32> { }
|
||||
// trait SuperTrait<A> { type T; }
|
||||
//
|
||||
// ... B: SubTrait<T = foo> ...
|
||||
// ```
|
||||
//
|
||||
// We want to produce `<B as SuperTrait<i32>>::T == foo`.
|
||||
|
||||
// Find any late-bound regions declared in `ty` that are not
|
||||
// declared in the trait-ref. These are not well-formed.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
|
||||
// for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
|
||||
if let ConvertedBindingKind::Equality(ty) = binding.kind {
|
||||
let late_bound_in_trait_ref =
|
||||
tcx.collect_constrained_late_bound_regions(&trait_ref);
|
||||
let late_bound_in_ty =
|
||||
tcx.collect_referenced_late_bound_regions(&ty::Binder::bind(ty));
|
||||
debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref);
|
||||
debug!("late_bound_in_ty = {:?}", late_bound_in_ty);
|
||||
|
||||
// FIXME: point at the type params that don't have appropriate lifetimes:
|
||||
// struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
|
||||
// ---- ---- ^^^^^^^
|
||||
self.validate_late_bound_regions(
|
||||
late_bound_in_trait_ref,
|
||||
late_bound_in_ty,
|
||||
|br_name| {
|
||||
struct_span_err!(
|
||||
tcx.sess,
|
||||
binding.span,
|
||||
E0582,
|
||||
"binding for associated type `{}` references {}, \
|
||||
which does not appear in the trait input types",
|
||||
binding.item_name,
|
||||
br_name
|
||||
)
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let candidate =
|
||||
if self.trait_defines_associated_type_named(trait_ref.def_id(), binding.item_name) {
|
||||
// Simple case: X is defined in the current trait.
|
||||
@ -1030,6 +1006,72 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
.or_insert(binding.span);
|
||||
}
|
||||
|
||||
// Include substitutions for generic parameters of associated types
|
||||
let projection_ty = candidate.map_bound(|trait_ref| {
|
||||
let item_segment = hir::PathSegment {
|
||||
ident: assoc_ty.ident,
|
||||
hir_id: None,
|
||||
res: None,
|
||||
args: Some(binding.gen_args),
|
||||
infer_args: false,
|
||||
};
|
||||
|
||||
let substs_trait_ref_and_assoc_item = self.create_substs_for_associated_item(
|
||||
tcx,
|
||||
path_span,
|
||||
assoc_ty.def_id,
|
||||
&item_segment,
|
||||
trait_ref.substs,
|
||||
);
|
||||
|
||||
debug!(
|
||||
"add_predicates_for_ast_type_binding: substs for trait-ref and assoc_item: {:?}",
|
||||
substs_trait_ref_and_assoc_item
|
||||
);
|
||||
|
||||
ty::ProjectionTy {
|
||||
item_def_id: assoc_ty.def_id,
|
||||
substs: substs_trait_ref_and_assoc_item,
|
||||
}
|
||||
});
|
||||
|
||||
if !speculative {
|
||||
// Find any late-bound regions declared in `ty` that are not
|
||||
// declared in the trait-ref or assoc_ty. These are not well-formed.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
|
||||
// for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
|
||||
if let ConvertedBindingKind::Equality(ty) = binding.kind {
|
||||
let late_bound_in_trait_ref =
|
||||
tcx.collect_constrained_late_bound_regions(&projection_ty);
|
||||
let late_bound_in_ty =
|
||||
tcx.collect_referenced_late_bound_regions(&ty::Binder::bind(ty));
|
||||
debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref);
|
||||
debug!("late_bound_in_ty = {:?}", late_bound_in_ty);
|
||||
|
||||
// FIXME: point at the type params that don't have appropriate lifetimes:
|
||||
// struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
|
||||
// ---- ---- ^^^^^^^
|
||||
self.validate_late_bound_regions(
|
||||
late_bound_in_trait_ref,
|
||||
late_bound_in_ty,
|
||||
|br_name| {
|
||||
struct_span_err!(
|
||||
tcx.sess,
|
||||
binding.span,
|
||||
E0582,
|
||||
"binding for associated type `{}` references {}, \
|
||||
which does not appear in the trait input types",
|
||||
binding.item_name,
|
||||
br_name
|
||||
)
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
match binding.kind {
|
||||
ConvertedBindingKind::Equality(ref ty) => {
|
||||
// "Desugar" a constraint like `T: Iterator<Item = u32>` this to
|
||||
@ -1037,13 +1079,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
//
|
||||
// `<T as Iterator>::Item = u32`
|
||||
bounds.projection_bounds.push((
|
||||
candidate.map_bound(|trait_ref| ty::ProjectionPredicate {
|
||||
projection_ty: ty::ProjectionTy::from_ref_and_name(
|
||||
tcx,
|
||||
trait_ref,
|
||||
binding.item_name,
|
||||
),
|
||||
ty,
|
||||
projection_ty.map_bound(|projection_ty| {
|
||||
debug!(
|
||||
"add_predicates_for_ast_type_binding: projection_ty {:?}, substs: {:?}",
|
||||
projection_ty, projection_ty.substs
|
||||
);
|
||||
ty::ProjectionPredicate { projection_ty, ty }
|
||||
}),
|
||||
binding.span,
|
||||
));
|
||||
@ -1055,7 +1096,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
//
|
||||
// Calling `skip_binder` is okay, because `add_bounds` expects the `param_ty`
|
||||
// parameter to have a skipped binder.
|
||||
let param_ty = tcx.mk_projection(assoc_ty.def_id, candidate.skip_binder().substs);
|
||||
let param_ty =
|
||||
tcx.mk_projection(assoc_ty.def_id, projection_ty.skip_binder().substs);
|
||||
self.add_bounds(param_ty, ast_bounds, bounds);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user