1
Fork 0

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:
bors 2022-01-18 09:58:39 +00:00
commit 7bc7be860f
83 changed files with 776 additions and 382 deletions

View file

@ -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,
})

View file

@ -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,

View file

@ -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)
}
}

View file

@ -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

View file

@ -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,
)

View file

@ -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()))

View file

@ -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()

View file

@ -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(&param.bounds),
GenericParamKind::Type { .. } | GenericParamKind::Const { .. }
if param.hir_id == param_id =>
{
Some(&param.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>(

View file

@ -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))
})
}

View file

@ -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;
}

View file

@ -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 {

View file

@ -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)
}
}
}
}