Auto merge of #87648 - JulianKnodt:const_eq_constrain, r=oli-obk
allow eq constraints on associated constants Updates #70256 (cc `@varkor,` `@Centril)`
This commit is contained in:
commit
7bc7be860f
83 changed files with 776 additions and 382 deletions
|
@ -151,8 +151,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
.bindings
|
||||
.iter()
|
||||
.find_map(|b| match (b.ident.name == sym::Output, &b.kind) {
|
||||
(true, hir::TypeBindingKind::Equality { ty }) => {
|
||||
sess.source_map().span_to_snippet(ty.span).ok()
|
||||
(true, hir::TypeBindingKind::Equality { term }) => {
|
||||
let span = match term {
|
||||
hir::Term::Ty(ty) => ty.span,
|
||||
hir::Term::Const(c) => self.tcx().hir().span(c.hir_id),
|
||||
};
|
||||
sess.source_map().span_to_snippet(span).ok()
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
|
|
|
@ -123,7 +123,7 @@ struct ConvertedBinding<'a, 'tcx> {
|
|||
|
||||
#[derive(Debug)]
|
||||
enum ConvertedBindingKind<'a, 'tcx> {
|
||||
Equality(Ty<'tcx>),
|
||||
Equality(ty::Term<'tcx>),
|
||||
Constraint(&'a [hir::GenericBound<'a>]),
|
||||
}
|
||||
|
||||
|
@ -601,10 +601,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
.iter()
|
||||
.map(|binding| {
|
||||
let kind = match binding.kind {
|
||||
hir::TypeBindingKind::Equality { ty } => {
|
||||
ConvertedBindingKind::Equality(self.ast_ty_to_ty(ty))
|
||||
}
|
||||
hir::TypeBindingKind::Constraint { bounds } => {
|
||||
hir::TypeBindingKind::Equality { ref term } => match term {
|
||||
hir::Term::Ty(ref ty) => {
|
||||
ConvertedBindingKind::Equality(self.ast_ty_to_ty(ty).into())
|
||||
}
|
||||
hir::Term::Const(ref c) => {
|
||||
let local_did = self.tcx().hir().local_def_id(c.hir_id);
|
||||
let c = Const::from_anon_const(self.tcx(), local_did);
|
||||
ConvertedBindingKind::Equality(c.into())
|
||||
}
|
||||
},
|
||||
hir::TypeBindingKind::Constraint { ref bounds } => {
|
||||
ConvertedBindingKind::Constraint(bounds)
|
||||
}
|
||||
};
|
||||
|
@ -867,6 +874,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
.find_by_name_and_kind(self.tcx(), assoc_name, ty::AssocKind::Type, trait_def_id)
|
||||
.is_some()
|
||||
}
|
||||
fn trait_defines_associated_named(&self, trait_def_id: DefId, assoc_name: Ident) -> bool {
|
||||
self.tcx()
|
||||
.associated_items(trait_def_id)
|
||||
.find_by_name_and_kinds(
|
||||
self.tcx(),
|
||||
assoc_name,
|
||||
&[ty::AssocKind::Type, ty::AssocKind::Const],
|
||||
trait_def_id,
|
||||
)
|
||||
.is_some()
|
||||
}
|
||||
|
||||
// Sets `implicitly_sized` to true on `Bounds` if necessary
|
||||
pub(crate) fn add_implicitly_sized<'hir>(
|
||||
|
@ -1118,9 +1136,18 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
.associated_items(candidate.def_id())
|
||||
.filter_by_name_unhygienic(assoc_ident.name)
|
||||
.find(|i| {
|
||||
i.kind == ty::AssocKind::Type && i.ident.normalize_to_macros_2_0() == assoc_ident
|
||||
(i.kind == ty::AssocKind::Type || i.kind == ty::AssocKind::Const)
|
||||
&& i.ident.normalize_to_macros_2_0() == assoc_ident
|
||||
})
|
||||
.expect("missing associated type");
|
||||
// FIXME(associated_const_equality): need to handle assoc_consts here as well.
|
||||
if assoc_ty.kind == ty::AssocKind::Const {
|
||||
tcx.sess
|
||||
.struct_span_err(path_span, &format!("associated const equality is incomplete"))
|
||||
.span_label(path_span, "cannot yet relate associated const")
|
||||
.emit();
|
||||
return Err(ErrorReported);
|
||||
}
|
||||
|
||||
if !assoc_ty.vis.is_accessible_from(def_scope, tcx) {
|
||||
tcx.sess
|
||||
|
@ -1215,18 +1242,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
}
|
||||
|
||||
match binding.kind {
|
||||
ConvertedBindingKind::Equality(ty) => {
|
||||
ConvertedBindingKind::Equality(term) => {
|
||||
// "Desugar" a constraint like `T: Iterator<Item = u32>` this to
|
||||
// the "projection predicate" for:
|
||||
//
|
||||
// `<T as Iterator>::Item = u32`
|
||||
bounds.projection_bounds.push((
|
||||
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 }
|
||||
projection_ty.map_bound(|projection_ty| ty::ProjectionPredicate {
|
||||
projection_ty,
|
||||
term: term,
|
||||
}),
|
||||
binding.span,
|
||||
));
|
||||
|
@ -1377,8 +1401,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
let pred = bound_predicate.rebind(pred);
|
||||
// A `Self` within the original bound will be substituted with a
|
||||
// `trait_object_dummy_self`, so check for that.
|
||||
let references_self =
|
||||
pred.skip_binder().ty.walk().any(|arg| arg == dummy_self.into());
|
||||
let references_self = match pred.skip_binder().term {
|
||||
ty::Term::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()),
|
||||
ty::Term::Const(c) => c.ty.walk().any(|arg| arg == dummy_self.into()),
|
||||
};
|
||||
|
||||
// If the projection output contains `Self`, force the user to
|
||||
// elaborate it explicitly to avoid a lot of complexity.
|
||||
|
@ -1601,7 +1627,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
|
||||
{
|
||||
let mut matching_candidates = all_candidates()
|
||||
.filter(|r| self.trait_defines_associated_type_named(r.def_id(), assoc_name));
|
||||
.filter(|r| self.trait_defines_associated_named(r.def_id(), assoc_name));
|
||||
|
||||
let bound = match matching_candidates.next() {
|
||||
Some(bound) => bound,
|
||||
|
|
|
@ -48,14 +48,19 @@ impl<'tcx> Bounds<'tcx> {
|
|||
/// where-clauses). Because some of our bounds listings (e.g.,
|
||||
/// regions) don't include the self-type, you must supply the
|
||||
/// self-type here (the `param_ty` parameter).
|
||||
pub fn predicates(
|
||||
&self,
|
||||
pub fn predicates<'out, 's>(
|
||||
&'s self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_ty: Ty<'tcx>,
|
||||
) -> Vec<(ty::Predicate<'tcx>, Span)> {
|
||||
// the output must live shorter than the duration of the borrow of self and 'tcx.
|
||||
) -> impl Iterator<Item = (ty::Predicate<'tcx>, Span)> + 'out
|
||||
where
|
||||
'tcx: 'out,
|
||||
's: 'out,
|
||||
{
|
||||
// If it could be sized, and is, add the `Sized` predicate.
|
||||
let sized_predicate = self.implicitly_sized.and_then(|span| {
|
||||
tcx.lang_items().sized_trait().map(|sized| {
|
||||
tcx.lang_items().sized_trait().map(move |sized| {
|
||||
let trait_ref = ty::Binder::dummy(ty::TraitRef {
|
||||
def_id: sized,
|
||||
substs: tcx.mk_substs_trait(param_ty, &[]),
|
||||
|
@ -64,25 +69,22 @@ impl<'tcx> Bounds<'tcx> {
|
|||
})
|
||||
});
|
||||
|
||||
sized_predicate
|
||||
.into_iter()
|
||||
.chain(self.region_bounds.iter().map(|&(region_bound, span)| {
|
||||
(
|
||||
region_bound
|
||||
.map_bound(|region_bound| ty::OutlivesPredicate(param_ty, region_bound))
|
||||
.to_predicate(tcx),
|
||||
span,
|
||||
)
|
||||
}))
|
||||
.chain(self.trait_bounds.iter().map(|&(bound_trait_ref, span, constness)| {
|
||||
let region_preds = self.region_bounds.iter().map(move |&(region_bound, span)| {
|
||||
let pred = region_bound
|
||||
.map_bound(|region_bound| ty::OutlivesPredicate(param_ty, region_bound))
|
||||
.to_predicate(tcx);
|
||||
(pred, span)
|
||||
});
|
||||
let trait_bounds =
|
||||
self.trait_bounds.iter().map(move |&(bound_trait_ref, span, constness)| {
|
||||
let predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx);
|
||||
(predicate, span)
|
||||
}))
|
||||
.chain(
|
||||
self.projection_bounds
|
||||
.iter()
|
||||
.map(|&(projection, span)| (projection.to_predicate(tcx), span)),
|
||||
)
|
||||
.collect()
|
||||
});
|
||||
let projection_bounds = self
|
||||
.projection_bounds
|
||||
.iter()
|
||||
.map(move |&(projection, span)| (projection.to_predicate(tcx), span));
|
||||
|
||||
sized_predicate.into_iter().chain(region_preds).chain(trait_bounds).chain(projection_bounds)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -279,7 +279,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
return None;
|
||||
};
|
||||
|
||||
let ret_param_ty = projection.skip_binder().ty;
|
||||
// Since this is a return parameter type it is safe to unwrap.
|
||||
let ret_param_ty = projection.skip_binder().term.ty().unwrap();
|
||||
let ret_param_ty = self.resolve_vars_if_possible(ret_param_ty);
|
||||
debug!("deduce_sig_from_projection: ret_param_ty={:?}", ret_param_ty);
|
||||
|
||||
|
@ -706,9 +707,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// Extract the type from the projection. Note that there can
|
||||
// be no bound variables in this type because the "self type"
|
||||
// does not have any regions in it.
|
||||
let output_ty = self.resolve_vars_if_possible(predicate.ty);
|
||||
let output_ty = self.resolve_vars_if_possible(predicate.term);
|
||||
debug!("deduce_future_output_from_projection: output_ty={:?}", output_ty);
|
||||
Some(output_ty)
|
||||
// This is a projection on a Fn trait so will always be a type.
|
||||
Some(output_ty.ty().unwrap())
|
||||
}
|
||||
|
||||
/// Converts the types that the user supplied, in case that doing
|
||||
|
|
|
@ -1353,7 +1353,7 @@ pub fn check_type_bounds<'tcx>(
|
|||
item_def_id: trait_ty.def_id,
|
||||
substs: rebased_substs,
|
||||
},
|
||||
ty: impl_ty_value,
|
||||
term: impl_ty_value.into(),
|
||||
},
|
||||
bound_vars,
|
||||
)
|
||||
|
|
|
@ -789,10 +789,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
item_def_id: projection_ty.item_def_id,
|
||||
};
|
||||
|
||||
let ty = pred.skip_binder().ty;
|
||||
let term = pred.skip_binder().term;
|
||||
|
||||
let obligation = format!("{} = {}", projection_ty, ty);
|
||||
let quiet = format!("{} = {}", quiet_projection_ty, ty);
|
||||
let obligation = format!("{} = {}", projection_ty, term);
|
||||
let quiet = format!("{} = {}", quiet_projection_ty, term);
|
||||
|
||||
bound_span_label(projection_ty.self_ty(), &obligation, &quiet);
|
||||
Some((obligation, projection_ty.self_ty()))
|
||||
|
|
|
@ -716,7 +716,11 @@ fn bounds_from_generic_predicates<'tcx>(
|
|||
// insert the associated types where they correspond, but for now let's be "lazy" and
|
||||
// propose this instead of the following valid resugaring:
|
||||
// `T: Trait, Trait::Assoc = K` → `T: Trait<Assoc = K>`
|
||||
where_clauses.push(format!("{} = {}", tcx.def_path_str(p.projection_ty.item_def_id), p.ty));
|
||||
where_clauses.push(format!(
|
||||
"{} = {}",
|
||||
tcx.def_path_str(p.projection_ty.item_def_id),
|
||||
p.term,
|
||||
));
|
||||
}
|
||||
let where_clauses = if where_clauses.is_empty() {
|
||||
String::new()
|
||||
|
|
|
@ -659,7 +659,11 @@ impl<'tcx> ItemCtxt<'tcx> {
|
|||
.params
|
||||
.iter()
|
||||
.filter_map(|param| match param.kind {
|
||||
GenericParamKind::Type { .. } if param.hir_id == param_id => Some(¶m.bounds),
|
||||
GenericParamKind::Type { .. } | GenericParamKind::Const { .. }
|
||||
if param.hir_id == param_id =>
|
||||
{
|
||||
Some(¶m.bounds)
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.flat_map(|bounds| bounds.iter())
|
||||
|
@ -2527,7 +2531,7 @@ fn predicates_from_bound<'tcx>(
|
|||
) -> Vec<(ty::Predicate<'tcx>, Span)> {
|
||||
let mut bounds = Bounds::default();
|
||||
astconv.add_bounds(param_ty, [bound].into_iter(), &mut bounds, bound_vars);
|
||||
bounds.predicates(astconv.tcx(), param_ty)
|
||||
bounds.predicates(astconv.tcx(), param_ty).collect()
|
||||
}
|
||||
|
||||
fn compute_sig_of_foreign_fn_decl<'tcx>(
|
||||
|
|
|
@ -67,11 +67,7 @@ fn opaque_type_bounds<'tcx>(
|
|||
let mut bounds = <dyn AstConv<'_>>::compute_bounds(&icx, item_ty, ast_bounds);
|
||||
// Opaque types are implicitly sized unless a `?Sized` bound is found
|
||||
<dyn AstConv<'_>>::add_implicitly_sized(&icx, &mut bounds, ast_bounds, None, span);
|
||||
let bounds = bounds.predicates(tcx, item_ty);
|
||||
|
||||
debug!("opaque_type_bounds({}) = {:?}", tcx.def_path_str(opaque_def_id), bounds);
|
||||
|
||||
tcx.arena.alloc_slice(&bounds)
|
||||
tcx.arena.alloc_from_iter(bounds.predicates(tcx, item_ty))
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -203,7 +203,7 @@ pub fn setup_constraining_predicates<'tcx>(
|
|||
if !relies_only_on_inputs {
|
||||
continue;
|
||||
}
|
||||
input_parameters.extend(parameters_for(&projection.ty, false));
|
||||
input_parameters.extend(parameters_for(&projection.term, false));
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -199,7 +199,7 @@ fn unconstrained_parent_impl_substs<'tcx>(
|
|||
for (predicate, _) in impl_generic_predicates.predicates.iter() {
|
||||
if let ty::PredicateKind::Projection(proj) = predicate.kind().skip_binder() {
|
||||
let projection_ty = proj.projection_ty;
|
||||
let projected_ty = proj.ty;
|
||||
let projected_ty = proj.term;
|
||||
|
||||
let unbound_trait_ref = projection_ty.trait_ref(tcx);
|
||||
if Some(unbound_trait_ref) == impl_trait_ref {
|
||||
|
|
|
@ -308,11 +308,14 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
|||
}
|
||||
|
||||
for projection in data.projection_bounds() {
|
||||
self.add_constraints_from_ty(
|
||||
current,
|
||||
projection.skip_binder().ty,
|
||||
self.invariant,
|
||||
);
|
||||
match projection.skip_binder().term {
|
||||
ty::Term::Ty(ty) => {
|
||||
self.add_constraints_from_ty(current, ty, self.invariant);
|
||||
}
|
||||
ty::Term::Const(c) => {
|
||||
self.add_constraints_from_const(current, c, self.invariant)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue