substitutions in trait predicates
This commit is contained in:
parent
760a6654fb
commit
da2cf9b9d1
@ -112,12 +112,15 @@ pub enum SizedByDefault {
|
|||||||
No,
|
No,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
struct ConvertedBinding<'a, 'tcx> {
|
struct ConvertedBinding<'a, 'tcx> {
|
||||||
item_name: Ident,
|
item_name: Ident,
|
||||||
kind: ConvertedBindingKind<'a, 'tcx>,
|
kind: ConvertedBindingKind<'a, 'tcx>,
|
||||||
|
gen_args: &'a GenericArgs<'a>,
|
||||||
span: Span,
|
span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
enum ConvertedBindingKind<'a, 'tcx> {
|
enum ConvertedBindingKind<'a, 'tcx> {
|
||||||
Equality(Ty<'tcx>),
|
Equality(Ty<'tcx>),
|
||||||
Constraint(&'a [hir::GenericBound<'a>]),
|
Constraint(&'a [hir::GenericBound<'a>]),
|
||||||
@ -323,6 +326,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
|
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
let generics = tcx.generics_of(def_id);
|
let generics = tcx.generics_of(def_id);
|
||||||
|
debug!("generics: {:?}", generics);
|
||||||
|
|
||||||
if generics.has_self {
|
if generics.has_self {
|
||||||
if generics.parent.is_some() {
|
if generics.parent.is_some() {
|
||||||
@ -557,7 +561,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
ConvertedBindingKind::Constraint(bounds)
|
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();
|
.collect();
|
||||||
|
|
||||||
@ -918,61 +927,28 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
dup_bindings: &mut FxHashMap<DefId, Span>,
|
dup_bindings: &mut FxHashMap<DefId, Span>,
|
||||||
path_span: Span,
|
path_span: Span,
|
||||||
) -> Result<(), ErrorReported> {
|
) -> 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();
|
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 =
|
let candidate =
|
||||||
if self.trait_defines_associated_type_named(trait_ref.def_id(), binding.item_name) {
|
if self.trait_defines_associated_type_named(trait_ref.def_id(), binding.item_name) {
|
||||||
// Simple case: X is defined in the current trait.
|
// Simple case: X is defined in the current trait.
|
||||||
@ -1030,6 +1006,72 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
.or_insert(binding.span);
|
.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 {
|
match binding.kind {
|
||||||
ConvertedBindingKind::Equality(ref ty) => {
|
ConvertedBindingKind::Equality(ref ty) => {
|
||||||
// "Desugar" a constraint like `T: Iterator<Item = u32>` this to
|
// "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`
|
// `<T as Iterator>::Item = u32`
|
||||||
bounds.projection_bounds.push((
|
bounds.projection_bounds.push((
|
||||||
candidate.map_bound(|trait_ref| ty::ProjectionPredicate {
|
projection_ty.map_bound(|projection_ty| {
|
||||||
projection_ty: ty::ProjectionTy::from_ref_and_name(
|
debug!(
|
||||||
tcx,
|
"add_predicates_for_ast_type_binding: projection_ty {:?}, substs: {:?}",
|
||||||
trait_ref,
|
projection_ty, projection_ty.substs
|
||||||
binding.item_name,
|
);
|
||||||
),
|
ty::ProjectionPredicate { projection_ty, ty }
|
||||||
ty,
|
|
||||||
}),
|
}),
|
||||||
binding.span,
|
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`
|
// Calling `skip_binder` is okay, because `add_bounds` expects the `param_ty`
|
||||||
// parameter to have a skipped binder.
|
// 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);
|
self.add_bounds(param_ty, ast_bounds, bounds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user