Auto merge of #86993 - jackh726:project-gat-binders, r=nikomatsakis
Replace associated item bound vars with placeholders when projecting Fixes #76407 Fixes #76826 Similar, but more limited, to #85499. This allows us to handle things like `for<'a> <T as Trait>::Assoc<'a>` but not `for<'a> <T as Trait<'a>>::Assoc`, unblocking GATs. r? `@nikomatsakis`
This commit is contained in:
commit
27e4205881
19 changed files with 671 additions and 33 deletions
|
@ -2483,9 +2483,10 @@ impl<'tcx> ty::Instance<'tcx> {
|
|||
// `src/test/ui/polymorphization/normalized_sig_types.rs`), and codegen not keeping
|
||||
// track of a polymorphization `ParamEnv` to allow normalizing later.
|
||||
let mut sig = match *ty.kind() {
|
||||
ty::FnDef(def_id, substs) => tcx
|
||||
ty::FnDef(def_id, substs) if tcx.sess.opts.debugging_opts.polymorphize => tcx
|
||||
.normalize_erasing_regions(tcx.param_env(def_id), tcx.fn_sig(def_id))
|
||||
.subst(tcx, substs),
|
||||
ty::FnDef(def_id, substs) => tcx.fn_sig(def_id).subst(tcx, substs),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
|
|
|
@ -29,6 +29,8 @@ use rustc_middle::ty::subst::Subst;
|
|||
use rustc_middle::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness};
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
pub use rustc_middle::traits::Reveal;
|
||||
|
||||
pub type PolyProjectionObligation<'tcx> = Obligation<'tcx, ty::PolyProjectionPredicate<'tcx>>;
|
||||
|
@ -296,6 +298,7 @@ struct AssocTypeNormalizer<'a, 'b, 'tcx> {
|
|||
cause: ObligationCause<'tcx>,
|
||||
obligations: &'a mut Vec<PredicateObligation<'tcx>>,
|
||||
depth: usize,
|
||||
universes: Vec<Option<ty::UniverseIndex>>,
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> {
|
||||
|
@ -306,12 +309,18 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> {
|
|||
depth: usize,
|
||||
obligations: &'a mut Vec<PredicateObligation<'tcx>>,
|
||||
) -> AssocTypeNormalizer<'a, 'b, 'tcx> {
|
||||
AssocTypeNormalizer { selcx, param_env, cause, obligations, depth }
|
||||
AssocTypeNormalizer { selcx, param_env, cause, obligations, depth, universes: vec![] }
|
||||
}
|
||||
|
||||
fn fold<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
|
||||
let value = self.selcx.infcx().resolve_vars_if_possible(value);
|
||||
|
||||
assert!(
|
||||
!value.has_escaping_bound_vars(),
|
||||
"Normalizing {:?} without wrapping in a `Binder`",
|
||||
value
|
||||
);
|
||||
|
||||
if !value.has_projections() { value } else { value.fold_with(self) }
|
||||
}
|
||||
}
|
||||
|
@ -321,6 +330,16 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
|
|||
self.selcx.tcx()
|
||||
}
|
||||
|
||||
fn fold_binder<T: TypeFoldable<'tcx>>(
|
||||
&mut self,
|
||||
t: ty::Binder<'tcx, T>,
|
||||
) -> ty::Binder<'tcx, T> {
|
||||
self.universes.push(None);
|
||||
let t = t.super_fold_with(self);
|
||||
self.universes.pop();
|
||||
t
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
if !ty.has_projections() {
|
||||
return ty;
|
||||
|
@ -396,6 +415,52 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
|
|||
normalized_ty
|
||||
}
|
||||
|
||||
ty::Projection(data) if !data.trait_ref(self.tcx()).has_escaping_bound_vars() => {
|
||||
// Okay, so you thought the previous branch was hacky. Well, to
|
||||
// extend upon this, when the *trait ref* doesn't have escaping
|
||||
// bound vars, but the associated item *does* (can only occur
|
||||
// with GATs), then we might still be able to project the type.
|
||||
// For this, we temporarily replace the bound vars with
|
||||
// placeholders. Note though, that in the case that we still
|
||||
// can't project for whatever reason (e.g. self type isn't
|
||||
// known enough), we *can't* register an obligation and return
|
||||
// an inference variable (since then that obligation would have
|
||||
// bound vars and that's a can of worms). Instead, we just
|
||||
// give up and fall back to pretending like we never tried!
|
||||
|
||||
let infcx = self.selcx.infcx();
|
||||
let (data, mapped_regions, mapped_types, mapped_consts) =
|
||||
BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data);
|
||||
let normalized_ty = opt_normalize_projection_type(
|
||||
self.selcx,
|
||||
self.param_env,
|
||||
data,
|
||||
self.cause.clone(),
|
||||
self.depth,
|
||||
&mut self.obligations,
|
||||
)
|
||||
.ok()
|
||||
.flatten()
|
||||
.unwrap_or_else(|| ty);
|
||||
|
||||
let normalized_ty = PlaceholderReplacer::replace_placeholders(
|
||||
infcx,
|
||||
mapped_regions,
|
||||
mapped_types,
|
||||
mapped_consts,
|
||||
&self.universes,
|
||||
normalized_ty,
|
||||
);
|
||||
debug!(
|
||||
?self.depth,
|
||||
?ty,
|
||||
?normalized_ty,
|
||||
obligations.len = ?self.obligations.len(),
|
||||
"AssocTypeNormalizer: normalized type"
|
||||
);
|
||||
normalized_ty
|
||||
}
|
||||
|
||||
_ => ty,
|
||||
}
|
||||
}
|
||||
|
@ -410,6 +475,279 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct BoundVarReplacer<'me, 'tcx> {
|
||||
infcx: &'me InferCtxt<'me, 'tcx>,
|
||||
// These three maps track the bound variable that were replaced by placeholders. It might be
|
||||
// nice to remove these since we already have the `kind` in the placeholder; we really just need
|
||||
// the `var` (but we *could* bring that into scope if we were to track them as we pass them).
|
||||
mapped_regions: BTreeMap<ty::PlaceholderRegion, ty::BoundRegion>,
|
||||
mapped_types: BTreeMap<ty::PlaceholderType, ty::BoundTy>,
|
||||
mapped_consts: BTreeMap<ty::PlaceholderConst<'tcx>, ty::BoundVar>,
|
||||
// The current depth relative to *this* folding, *not* the entire normalization. In other words,
|
||||
// the depth of binders we've passed here.
|
||||
current_index: ty::DebruijnIndex,
|
||||
// The `UniverseIndex` of the binding levels above us. These are optional, since we are lazy:
|
||||
// we don't actually create a universe until we see a bound var we have to replace.
|
||||
universe_indices: &'me mut Vec<Option<ty::UniverseIndex>>,
|
||||
}
|
||||
|
||||
impl<'me, 'tcx> BoundVarReplacer<'me, 'tcx> {
|
||||
/// Returns `Some` if we *were* able to replace bound vars. If there are any bound vars that
|
||||
/// use a binding level above `universe_indices.len()`, we fail.
|
||||
pub fn replace_bound_vars<T: TypeFoldable<'tcx>>(
|
||||
infcx: &'me InferCtxt<'me, 'tcx>,
|
||||
universe_indices: &'me mut Vec<Option<ty::UniverseIndex>>,
|
||||
value: T,
|
||||
) -> (
|
||||
T,
|
||||
BTreeMap<ty::PlaceholderRegion, ty::BoundRegion>,
|
||||
BTreeMap<ty::PlaceholderType, ty::BoundTy>,
|
||||
BTreeMap<ty::PlaceholderConst<'tcx>, ty::BoundVar>,
|
||||
) {
|
||||
let mapped_regions: BTreeMap<ty::PlaceholderRegion, ty::BoundRegion> = BTreeMap::new();
|
||||
let mapped_types: BTreeMap<ty::PlaceholderType, ty::BoundTy> = BTreeMap::new();
|
||||
let mapped_consts: BTreeMap<ty::PlaceholderConst<'tcx>, ty::BoundVar> = BTreeMap::new();
|
||||
|
||||
let mut replacer = BoundVarReplacer {
|
||||
infcx,
|
||||
mapped_regions,
|
||||
mapped_types,
|
||||
mapped_consts,
|
||||
current_index: ty::INNERMOST,
|
||||
universe_indices,
|
||||
};
|
||||
|
||||
let value = value.super_fold_with(&mut replacer);
|
||||
|
||||
(value, replacer.mapped_regions, replacer.mapped_types, replacer.mapped_consts)
|
||||
}
|
||||
|
||||
fn universe_for(&mut self, debruijn: ty::DebruijnIndex) -> ty::UniverseIndex {
|
||||
let infcx = self.infcx;
|
||||
let index =
|
||||
self.universe_indices.len() - debruijn.as_usize() + self.current_index.as_usize() - 1;
|
||||
let universe = self.universe_indices[index].unwrap_or_else(|| {
|
||||
for i in self.universe_indices.iter_mut().take(index + 1) {
|
||||
*i = i.or_else(|| Some(infcx.create_next_universe()))
|
||||
}
|
||||
self.universe_indices[index].unwrap()
|
||||
});
|
||||
universe
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeFolder<'tcx> for BoundVarReplacer<'_, 'tcx> {
|
||||
fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
|
||||
self.infcx.tcx
|
||||
}
|
||||
|
||||
fn fold_binder<T: TypeFoldable<'tcx>>(
|
||||
&mut self,
|
||||
t: ty::Binder<'tcx, T>,
|
||||
) -> ty::Binder<'tcx, T> {
|
||||
self.current_index.shift_in(1);
|
||||
let t = t.super_fold_with(self);
|
||||
self.current_index.shift_out(1);
|
||||
t
|
||||
}
|
||||
|
||||
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
|
||||
match *r {
|
||||
ty::ReLateBound(debruijn, _)
|
||||
if debruijn.as_usize() + 1
|
||||
> self.current_index.as_usize() + self.universe_indices.len() =>
|
||||
{
|
||||
bug!("Bound vars outside of `self.universe_indices`");
|
||||
}
|
||||
ty::ReLateBound(debruijn, br) if debruijn >= self.current_index => {
|
||||
let universe = self.universe_for(debruijn);
|
||||
let p = ty::PlaceholderRegion { universe, name: br.kind };
|
||||
self.mapped_regions.insert(p.clone(), br);
|
||||
self.infcx.tcx.mk_region(ty::RePlaceholder(p))
|
||||
}
|
||||
_ => r,
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
|
||||
match *t.kind() {
|
||||
ty::Bound(debruijn, _)
|
||||
if debruijn.as_usize() + 1
|
||||
> self.current_index.as_usize() + self.universe_indices.len() =>
|
||||
{
|
||||
bug!("Bound vars outside of `self.universe_indices`");
|
||||
}
|
||||
ty::Bound(debruijn, bound_ty) if debruijn >= self.current_index => {
|
||||
let universe = self.universe_for(debruijn);
|
||||
let p = ty::PlaceholderType { universe, name: bound_ty.var };
|
||||
self.mapped_types.insert(p.clone(), bound_ty);
|
||||
self.infcx.tcx.mk_ty(ty::Placeholder(p))
|
||||
}
|
||||
_ if t.has_vars_bound_at_or_above(self.current_index) => t.super_fold_with(self),
|
||||
_ => t,
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
|
||||
match *ct {
|
||||
ty::Const { val: ty::ConstKind::Bound(debruijn, _), ty: _ }
|
||||
if debruijn.as_usize() + 1
|
||||
> self.current_index.as_usize() + self.universe_indices.len() =>
|
||||
{
|
||||
bug!("Bound vars outside of `self.universe_indices`");
|
||||
}
|
||||
ty::Const { val: ty::ConstKind::Bound(debruijn, bound_const), ty }
|
||||
if debruijn >= self.current_index =>
|
||||
{
|
||||
let universe = self.universe_for(debruijn);
|
||||
let p = ty::PlaceholderConst {
|
||||
universe,
|
||||
name: ty::BoundConst { var: bound_const, ty },
|
||||
};
|
||||
self.mapped_consts.insert(p.clone(), bound_const);
|
||||
self.infcx.tcx.mk_const(ty::Const { val: ty::ConstKind::Placeholder(p), ty })
|
||||
}
|
||||
_ if ct.has_vars_bound_at_or_above(self.current_index) => ct.super_fold_with(self),
|
||||
_ => ct,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The inverse of `BoundVarReplacer`: replaces placeholders with the bound vars from which they came.
|
||||
pub struct PlaceholderReplacer<'me, 'tcx> {
|
||||
infcx: &'me InferCtxt<'me, 'tcx>,
|
||||
mapped_regions: BTreeMap<ty::PlaceholderRegion, ty::BoundRegion>,
|
||||
mapped_types: BTreeMap<ty::PlaceholderType, ty::BoundTy>,
|
||||
mapped_consts: BTreeMap<ty::PlaceholderConst<'tcx>, ty::BoundVar>,
|
||||
universe_indices: &'me Vec<Option<ty::UniverseIndex>>,
|
||||
current_index: ty::DebruijnIndex,
|
||||
}
|
||||
|
||||
impl<'me, 'tcx> PlaceholderReplacer<'me, 'tcx> {
|
||||
pub fn replace_placeholders<T: TypeFoldable<'tcx>>(
|
||||
infcx: &'me InferCtxt<'me, 'tcx>,
|
||||
mapped_regions: BTreeMap<ty::PlaceholderRegion, ty::BoundRegion>,
|
||||
mapped_types: BTreeMap<ty::PlaceholderType, ty::BoundTy>,
|
||||
mapped_consts: BTreeMap<ty::PlaceholderConst<'tcx>, ty::BoundVar>,
|
||||
universe_indices: &'me Vec<Option<ty::UniverseIndex>>,
|
||||
value: T,
|
||||
) -> T {
|
||||
let mut replacer = PlaceholderReplacer {
|
||||
infcx,
|
||||
mapped_regions,
|
||||
mapped_types,
|
||||
mapped_consts,
|
||||
universe_indices,
|
||||
current_index: ty::INNERMOST,
|
||||
};
|
||||
value.super_fold_with(&mut replacer)
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeFolder<'tcx> for PlaceholderReplacer<'_, 'tcx> {
|
||||
fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
|
||||
self.infcx.tcx
|
||||
}
|
||||
|
||||
fn fold_binder<T: TypeFoldable<'tcx>>(
|
||||
&mut self,
|
||||
t: ty::Binder<'tcx, T>,
|
||||
) -> ty::Binder<'tcx, T> {
|
||||
if !t.has_placeholders() && !t.has_infer_regions() {
|
||||
return t;
|
||||
}
|
||||
self.current_index.shift_in(1);
|
||||
let t = t.super_fold_with(self);
|
||||
self.current_index.shift_out(1);
|
||||
t
|
||||
}
|
||||
|
||||
fn fold_region(&mut self, r0: ty::Region<'tcx>) -> ty::Region<'tcx> {
|
||||
let r1 = match r0 {
|
||||
ty::ReVar(_) => self
|
||||
.infcx
|
||||
.inner
|
||||
.borrow_mut()
|
||||
.unwrap_region_constraints()
|
||||
.opportunistic_resolve_region(self.infcx.tcx, r0),
|
||||
_ => r0,
|
||||
};
|
||||
|
||||
let r2 = match *r1 {
|
||||
ty::RePlaceholder(p) => {
|
||||
let replace_var = self.mapped_regions.get(&p);
|
||||
match replace_var {
|
||||
Some(replace_var) => {
|
||||
let index = self
|
||||
.universe_indices
|
||||
.iter()
|
||||
.position(|u| matches!(u, Some(pu) if *pu == p.universe))
|
||||
.unwrap_or_else(|| bug!("Unexpected placeholder universe."));
|
||||
let db = ty::DebruijnIndex::from_usize(
|
||||
self.universe_indices.len() - index + self.current_index.as_usize() - 1,
|
||||
);
|
||||
self.tcx().mk_region(ty::ReLateBound(db, *replace_var))
|
||||
}
|
||||
None => r1,
|
||||
}
|
||||
}
|
||||
_ => r1,
|
||||
};
|
||||
|
||||
debug!(?r0, ?r1, ?r2, "fold_region");
|
||||
|
||||
r2
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
match *ty.kind() {
|
||||
ty::Placeholder(p) => {
|
||||
let replace_var = self.mapped_types.get(&p);
|
||||
match replace_var {
|
||||
Some(replace_var) => {
|
||||
let index = self
|
||||
.universe_indices
|
||||
.iter()
|
||||
.position(|u| matches!(u, Some(pu) if *pu == p.universe))
|
||||
.unwrap_or_else(|| bug!("Unexpected placeholder universe."));
|
||||
let db = ty::DebruijnIndex::from_usize(
|
||||
self.universe_indices.len() - index + self.current_index.as_usize() - 1,
|
||||
);
|
||||
self.tcx().mk_ty(ty::Bound(db, *replace_var))
|
||||
}
|
||||
None => ty,
|
||||
}
|
||||
}
|
||||
|
||||
_ if ty.has_placeholders() || ty.has_infer_regions() => ty.super_fold_with(self),
|
||||
_ => ty,
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
|
||||
if let ty::Const { val: ty::ConstKind::Placeholder(p), ty } = *ct {
|
||||
let replace_var = self.mapped_consts.get(&p);
|
||||
match replace_var {
|
||||
Some(replace_var) => {
|
||||
let index = self
|
||||
.universe_indices
|
||||
.iter()
|
||||
.position(|u| matches!(u, Some(pu) if *pu == p.universe))
|
||||
.unwrap_or_else(|| bug!("Unexpected placeholder universe."));
|
||||
let db = ty::DebruijnIndex::from_usize(
|
||||
self.universe_indices.len() - index + self.current_index.as_usize() - 1,
|
||||
);
|
||||
self.tcx()
|
||||
.mk_const(ty::Const { val: ty::ConstKind::Bound(db, *replace_var), ty })
|
||||
}
|
||||
None => ct,
|
||||
}
|
||||
} else {
|
||||
ct.super_fold_with(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The guts of `normalize`: normalize a specific projection like `<T
|
||||
/// as Trait>::Item`. The result is always a type (and possibly
|
||||
/// additional obligations). If ambiguity arises, which implies that
|
||||
|
|
|
@ -61,6 +61,7 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> {
|
|||
error: false,
|
||||
cache: SsoHashMap::new(),
|
||||
anon_depth: 0,
|
||||
universes: vec![],
|
||||
};
|
||||
|
||||
let result = value.fold_with(&mut normalizer);
|
||||
|
@ -91,6 +92,7 @@ struct QueryNormalizer<'cx, 'tcx> {
|
|||
cache: SsoHashMap<Ty<'tcx>, Ty<'tcx>>,
|
||||
error: bool,
|
||||
anon_depth: usize,
|
||||
universes: Vec<Option<ty::UniverseIndex>>,
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
|
||||
|
@ -98,6 +100,16 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
|
|||
self.infcx.tcx
|
||||
}
|
||||
|
||||
fn fold_binder<T: TypeFoldable<'tcx>>(
|
||||
&mut self,
|
||||
t: ty::Binder<'tcx, T>,
|
||||
) -> ty::Binder<'tcx, T> {
|
||||
self.universes.push(None);
|
||||
let t = t.super_fold_with(self);
|
||||
self.universes.pop();
|
||||
t
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
if !ty.has_projections() {
|
||||
|
@ -204,6 +216,80 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
ty::Projection(data) if !data.trait_ref(self.infcx.tcx).has_escaping_bound_vars() => {
|
||||
// See note in `rustc_trait_selection::traits::project`
|
||||
|
||||
// One other point mentioning: In `traits::project`, if a
|
||||
// projection can't be normalized, we return an inference variable
|
||||
// and register an obligation to later resolve that. Here, the query
|
||||
// will just return ambiguity. In both cases, the effect is the same: we only want
|
||||
// to return `ty` because there are bound vars that we aren't yet handling in a more
|
||||
// complete way.
|
||||
|
||||
// `BoundVarReplacer` can't handle escaping bound vars. Ideally, we want this before even calling
|
||||
// `QueryNormalizer`, but some const-generics tests pass escaping bound vars.
|
||||
// Also, use `ty` so we get that sweet `outer_exclusive_binder` optimization
|
||||
assert!(!ty.has_vars_bound_at_or_above(ty::DebruijnIndex::from_usize(
|
||||
self.universes.len()
|
||||
)));
|
||||
|
||||
let tcx = self.infcx.tcx;
|
||||
let infcx = self.infcx;
|
||||
let (data, mapped_regions, mapped_types, mapped_consts) =
|
||||
crate::traits::project::BoundVarReplacer::replace_bound_vars(
|
||||
infcx,
|
||||
&mut self.universes,
|
||||
data,
|
||||
);
|
||||
let data = data.super_fold_with(self);
|
||||
|
||||
let mut orig_values = OriginalQueryValues::default();
|
||||
// HACK(matthewjasper) `'static` is special-cased in selection,
|
||||
// so we cannot canonicalize it.
|
||||
let c_data = self
|
||||
.infcx
|
||||
.canonicalize_hr_query_hack(self.param_env.and(data), &mut orig_values);
|
||||
debug!("QueryNormalizer: c_data = {:#?}", c_data);
|
||||
debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
|
||||
let normalized_ty = match tcx.normalize_projection_ty(c_data) {
|
||||
Ok(result) => {
|
||||
// We don't expect ambiguity.
|
||||
if result.is_ambiguous() {
|
||||
self.error = true;
|
||||
return ty;
|
||||
}
|
||||
match self.infcx.instantiate_query_response_and_region_obligations(
|
||||
self.cause,
|
||||
self.param_env,
|
||||
&orig_values,
|
||||
result,
|
||||
) {
|
||||
Ok(InferOk { value: result, obligations }) => {
|
||||
debug!("QueryNormalizer: result = {:#?}", result);
|
||||
debug!("QueryNormalizer: obligations = {:#?}", obligations);
|
||||
self.obligations.extend(obligations);
|
||||
result.normalized_ty
|
||||
}
|
||||
Err(_) => {
|
||||
self.error = true;
|
||||
ty
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(NoSolution) => {
|
||||
self.error = true;
|
||||
ty
|
||||
}
|
||||
};
|
||||
crate::traits::project::PlaceholderReplacer::replace_placeholders(
|
||||
infcx,
|
||||
mapped_regions,
|
||||
mapped_types,
|
||||
mapped_consts,
|
||||
&self.universes,
|
||||
normalized_ty,
|
||||
)
|
||||
}
|
||||
|
||||
_ => ty,
|
||||
})();
|
||||
|
|
|
@ -406,7 +406,6 @@ fn check_associated_item(
|
|||
}
|
||||
ty::AssocKind::Fn => {
|
||||
let sig = fcx.tcx.fn_sig(item.def_id);
|
||||
let sig = fcx.normalize_associated_types_in(span, sig);
|
||||
let hir_sig = sig_if_method.expect("bad signature for method");
|
||||
check_fn_or_method(
|
||||
fcx,
|
||||
|
@ -611,7 +610,6 @@ fn check_item_fn(
|
|||
for_id(tcx, item_id, span).with_fcx(|fcx| {
|
||||
let def_id = tcx.hir().local_def_id(item_id);
|
||||
let sig = tcx.fn_sig(def_id);
|
||||
let sig = fcx.normalize_associated_types_in(span, sig);
|
||||
let mut implied_bounds = vec![];
|
||||
check_fn_or_method(fcx, ident.span, sig, decl, def_id.to_def_id(), &mut implied_bounds);
|
||||
implied_bounds
|
||||
|
@ -898,8 +896,8 @@ fn check_fn_or_method<'fcx, 'tcx>(
|
|||
def_id: DefId,
|
||||
implied_bounds: &mut Vec<Ty<'tcx>>,
|
||||
) {
|
||||
let sig = fcx.normalize_associated_types_in(span, sig);
|
||||
let sig = fcx.tcx.liberate_late_bound_regions(def_id, sig);
|
||||
let sig = fcx.normalize_associated_types_in(span, sig);
|
||||
|
||||
for (&input_ty, ty) in iter::zip(sig.inputs(), hir_decl.inputs) {
|
||||
fcx.register_wf_obligation(input_ty.into(), ty.span, ObligationCauseCode::MiscObligation);
|
||||
|
@ -1077,8 +1075,8 @@ fn check_method_receiver<'fcx, 'tcx>(
|
|||
let span = fn_sig.decl.inputs[0].span;
|
||||
|
||||
let sig = fcx.tcx.fn_sig(method.def_id);
|
||||
let sig = fcx.normalize_associated_types_in(span, sig);
|
||||
let sig = fcx.tcx.liberate_late_bound_regions(method.def_id, sig);
|
||||
let sig = fcx.normalize_associated_types_in(span, sig);
|
||||
|
||||
debug!("check_method_receiver: sig={:?}", sig);
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
error[E0277]: the trait bound `Self: Get` is not satisfied
|
||||
--> $DIR/associated-types-for-unimpl-trait.rs:10:5
|
||||
--> $DIR/associated-types-for-unimpl-trait.rs:10:8
|
||||
|
|
||||
LL | fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
|
||||
| ^^^^ the trait `Get` is not implemented for `Self`
|
||||
|
|
||||
help: consider further restricting `Self`
|
||||
|
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
error[E0277]: the trait bound `T: Get` is not satisfied
|
||||
--> $DIR/associated-types-no-suitable-bound.rs:11:5
|
||||
--> $DIR/associated-types-no-suitable-bound.rs:11:8
|
||||
|
|
||||
LL | fn uhoh<T>(foo: <T as Get>::Value) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `T`
|
||||
| ^^^^ the trait `Get` is not implemented for `T`
|
||||
|
|
||||
help: consider restricting type parameter `T`
|
||||
|
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
error[E0277]: the trait bound `Self: Get` is not satisfied
|
||||
--> $DIR/associated-types-no-suitable-supertrait-2.rs:17:5
|
||||
--> $DIR/associated-types-no-suitable-supertrait-2.rs:17:8
|
||||
|
|
||||
LL | fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
|
||||
| ^^^^ the trait `Get` is not implemented for `Self`
|
||||
|
|
||||
help: consider further restricting `Self`
|
||||
|
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
error[E0277]: the trait bound `Self: Get` is not satisfied
|
||||
--> $DIR/associated-types-no-suitable-supertrait.rs:17:5
|
||||
--> $DIR/associated-types-no-suitable-supertrait.rs:17:8
|
||||
|
|
||||
LL | fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
|
||||
| ^^^^ the trait `Get` is not implemented for `Self`
|
||||
|
|
||||
help: consider further restricting `Self`
|
||||
|
|
||||
|
@ -10,10 +10,10 @@ LL | fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) where Self: Ge
|
|||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0277]: the trait bound `(T, U): Get` is not satisfied
|
||||
--> $DIR/associated-types-no-suitable-supertrait.rs:22:5
|
||||
--> $DIR/associated-types-no-suitable-supertrait.rs:22:8
|
||||
|
|
||||
LL | fn uhoh<U:Get>(&self, foo: U, bar: <(T, U) as Get>::Value) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `(T, U)`
|
||||
| ^^^^ the trait `Get` is not implemented for `(T, U)`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
error[E0277]: the trait bound `Self: Get` is not satisfied
|
||||
--> $DIR/associated-types-projection-to-unrelated-trait-in-method-without-default.rs:10:5
|
||||
--> $DIR/associated-types-projection-to-unrelated-trait-in-method-without-default.rs:10:8
|
||||
|
|
||||
LL | fn okay<U:Get>(&self, foo: U, bar: <Self as Get>::Value);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
|
||||
| ^^^^ the trait `Get` is not implemented for `Self`
|
||||
|
|
||||
help: consider further restricting `Self`
|
||||
|
|
||||
|
|
36
src/test/ui/associated-types/normalization-debruijn-1.rs
Normal file
36
src/test/ui/associated-types/normalization-debruijn-1.rs
Normal file
|
@ -0,0 +1,36 @@
|
|||
// build-pass
|
||||
// edition:2018
|
||||
|
||||
// Regression test to ensure we handle debruijn indices correctly in projection
|
||||
// normalization under binders. Found in crater run for #85499
|
||||
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
pub enum Outcome<S, E> {
|
||||
Success((S, E)),
|
||||
}
|
||||
pub struct Request<'r> {
|
||||
_marker: std::marker::PhantomData<&'r ()>,
|
||||
}
|
||||
pub trait FromRequest<'r>: Sized {
|
||||
type Error;
|
||||
fn from_request<'life0>(
|
||||
request: &'r Request<'life0>,
|
||||
) -> Pin<Box<dyn Future<Output = Outcome<Self, Self::Error>>>>;
|
||||
}
|
||||
impl<'r, T: FromRequest<'r>> FromRequest<'r> for Option<T> {
|
||||
type Error = ();
|
||||
fn from_request<'life0>(
|
||||
request: &'r Request<'life0>,
|
||||
) -> Pin<Box<dyn Future<Output = Outcome<Self, Self::Error>>>> {
|
||||
Box::pin(async move {
|
||||
let request = request;
|
||||
match T::from_request(request).await {
|
||||
_ => todo!(),
|
||||
}
|
||||
});
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
31
src/test/ui/associated-types/normalization-debruijn-2.rs
Normal file
31
src/test/ui/associated-types/normalization-debruijn-2.rs
Normal file
|
@ -0,0 +1,31 @@
|
|||
// build-pass
|
||||
// edition:2018
|
||||
|
||||
// Regression test to ensure we handle debruijn indices correctly in projection
|
||||
// normalization under binders. Found in crater run for #85499
|
||||
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
pub enum Outcome<S, E> {
|
||||
Success(S),
|
||||
Failure(E),
|
||||
}
|
||||
pub struct Request<'r> {
|
||||
_marker: std::marker::PhantomData<&'r ()>,
|
||||
}
|
||||
pub trait FromRequest<'r>: Sized {
|
||||
type Error;
|
||||
fn from_request<'life0>(
|
||||
request: &'r Request<'life0>,
|
||||
) -> Pin<Box<dyn Future<Output = Outcome<Self, Self::Error>>>>;
|
||||
}
|
||||
pub struct S<T> {
|
||||
_marker: std::marker::PhantomData<T>,
|
||||
}
|
||||
impl<'r, T: FromRequest<'r>> S<T> {
|
||||
pub async fn from_request(request: &'r Request<'_>) {
|
||||
let _ = T::from_request(request).await;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
41
src/test/ui/associated-types/normalization-debruijn-3.rs
Normal file
41
src/test/ui/associated-types/normalization-debruijn-3.rs
Normal file
|
@ -0,0 +1,41 @@
|
|||
// build-pass
|
||||
// edition:2018
|
||||
|
||||
// Regression test to ensure we handle debruijn indices correctly in projection
|
||||
// normalization under binders. Found in crater run for #85499
|
||||
|
||||
use std::future::{Future, Ready};
|
||||
async fn read() {
|
||||
let _ = connect(&()).await;
|
||||
}
|
||||
async fn connect<A: ToSocketAddr>(addr: A) {
|
||||
let _ = addr.to_socket_addr().await;
|
||||
}
|
||||
pub trait ToSocketAddr {
|
||||
type Future: Future<Output = ()>;
|
||||
fn to_socket_addr(&self) -> Self::Future;
|
||||
}
|
||||
impl ToSocketAddr for &() {
|
||||
type Future = Ready<()>;
|
||||
fn to_socket_addr(&self) -> Self::Future {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
struct Server;
|
||||
impl Server {
|
||||
fn and_then<F>(self, _fun: F) -> AndThen<F> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
struct AndThen<F> {
|
||||
_marker: std::marker::PhantomData<F>,
|
||||
}
|
||||
pub async fn run<F>(_: F) {
|
||||
}
|
||||
fn main() {
|
||||
let _ = async {
|
||||
let server = Server;
|
||||
let verification_route = server.and_then(read);
|
||||
run(verification_route).await;
|
||||
};
|
||||
}
|
36
src/test/ui/associated-types/normalization-generality.rs
Normal file
36
src/test/ui/associated-types/normalization-generality.rs
Normal file
|
@ -0,0 +1,36 @@
|
|||
// build-pass
|
||||
|
||||
// Ensures that we don't regress on "implementation is not general enough" when
|
||||
// normalizating under binders.
|
||||
|
||||
#![feature(no_core)]
|
||||
|
||||
pub trait Yokeable<'a> {
|
||||
type Output: 'a;
|
||||
}
|
||||
|
||||
pub struct Yoke<Y: for<'a> Yokeable<'a>> {
|
||||
_yokeable: Y,
|
||||
}
|
||||
|
||||
impl<Y: for<'a> Yokeable<'a>> Yoke<Y> {
|
||||
pub fn project<'this, P>(
|
||||
&'this self,
|
||||
_f: for<'a> fn(<Y as Yokeable<'a>>::Output, &'a ()) -> <P as Yokeable<'a>>::Output,
|
||||
) -> Yoke<P>
|
||||
where
|
||||
P: for<'a> Yokeable<'a>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn slice(y: Yoke<&'static ()>) -> Yoke<&'static ()> {
|
||||
y.project(move |yk, _| yk)
|
||||
}
|
||||
|
||||
impl<'a, T> Yokeable<'a> for &'static T {
|
||||
type Output = &'a T;
|
||||
}
|
||||
|
||||
fn main() {}
|
28
src/test/ui/generic-associated-types/issue-76407.rs
Normal file
28
src/test/ui/generic-associated-types/issue-76407.rs
Normal file
|
@ -0,0 +1,28 @@
|
|||
// check-pass
|
||||
|
||||
#![feature(generic_associated_types)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
trait Marker {}
|
||||
|
||||
impl Marker for u32 {}
|
||||
|
||||
trait MyTrait {
|
||||
type Item<'a>;
|
||||
}
|
||||
|
||||
struct MyStruct;
|
||||
|
||||
impl MyTrait for MyStruct {
|
||||
type Item<'a> = u32;
|
||||
}
|
||||
|
||||
fn ty_check<T>()
|
||||
where
|
||||
T: MyTrait,
|
||||
for<'a> T::Item<'a>: Marker
|
||||
{}
|
||||
|
||||
fn main() {
|
||||
ty_check::<MyStruct>();
|
||||
}
|
45
src/test/ui/generic-associated-types/issue-76826.rs
Normal file
45
src/test/ui/generic-associated-types/issue-76826.rs
Normal file
|
@ -0,0 +1,45 @@
|
|||
// run-pass
|
||||
|
||||
#![feature(generic_associated_types)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
pub trait Iter {
|
||||
type Item<'a> where Self: 'a;
|
||||
|
||||
fn next<'a>(&'a mut self) -> Option<Self::Item<'a>>;
|
||||
|
||||
fn for_each<F>(mut self, mut f: F)
|
||||
where Self: Sized, F: for<'a> FnMut(Self::Item<'a>)
|
||||
{
|
||||
while let Some(item) = self.next() {
|
||||
f(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Windows<T> {
|
||||
items: Vec<T>,
|
||||
start: usize,
|
||||
len: usize,
|
||||
}
|
||||
|
||||
impl<T> Windows<T> {
|
||||
pub fn new(items: Vec<T>, len: usize) -> Self {
|
||||
Self { items, start: 0, len }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Iter for Windows<T> {
|
||||
type Item<'a> where T: 'a = &'a mut [T];
|
||||
|
||||
fn next<'a>(&'a mut self) -> Option<Self::Item<'a>> {
|
||||
let slice = self.items.get_mut(self.start..self.start + self.len)?;
|
||||
self.start += 1;
|
||||
Some(slice)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
Windows::new(vec![1, 2, 3, 4, 5], 3)
|
||||
.for_each(|slice| println!("{:?}", slice));
|
||||
}
|
|
@ -1,10 +1,8 @@
|
|||
error[E0277]: the trait bound `isize: HasState` is not satisfied
|
||||
--> $DIR/issue-18611.rs:1:1
|
||||
--> $DIR/issue-18611.rs:1:4
|
||||
|
|
||||
LL | / fn add_state(op: <isize as HasState>::State) {
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_^ the trait `HasState` is not implemented for `isize`
|
||||
LL | fn add_state(op: <isize as HasState>::State) {
|
||||
| ^^^^^^^^^ the trait `HasState` is not implemented for `isize`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
|
||||
--> $DIR/issue-20831-debruijn.rs:28:33
|
||||
--> $DIR/issue-20831-debruijn.rs:28:8
|
||||
|
|
||||
LL | fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
note: first, the lifetime cannot outlive the anonymous lifetime defined on the method body at 28:58...
|
||||
--> $DIR/issue-20831-debruijn.rs:28:58
|
||||
|
@ -15,10 +15,10 @@ note: ...but the lifetime must also be valid for the lifetime `'a` as defined on
|
|||
LL | impl<'a> Publisher<'a> for MyStruct<'a> {
|
||||
| ^^
|
||||
note: ...so that the types are compatible
|
||||
--> $DIR/issue-20831-debruijn.rs:28:33
|
||||
--> $DIR/issue-20831-debruijn.rs:28:8
|
||||
|
|
||||
LL | fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^
|
||||
= note: expected `Publisher<'_>`
|
||||
found `Publisher<'_>`
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'d` due to conflicting requirements
|
||||
--> $DIR/normalization-bounds-error.rs:12:1
|
||||
--> $DIR/normalization-bounds-error.rs:12:4
|
||||
|
|
||||
LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
note: first, the lifetime cannot outlive the lifetime `'d` as defined on the function body at 12:14...
|
||||
--> $DIR/normalization-bounds-error.rs:12:14
|
||||
|
@ -15,10 +15,10 @@ note: ...but the lifetime must also be valid for the lifetime `'a` as defined on
|
|||
LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {}
|
||||
| ^^
|
||||
note: ...so that the types are compatible
|
||||
--> $DIR/normalization-bounds-error.rs:12:1
|
||||
--> $DIR/normalization-bounds-error.rs:12:4
|
||||
|
|
||||
LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^
|
||||
= note: expected `Visitor<'d>`
|
||||
found `Visitor<'_>`
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
error[E0277]: the trait bound `(): Foo` is not satisfied
|
||||
--> $DIR/wf-foreign-fn-decl-ret.rs:11:5
|
||||
--> $DIR/wf-foreign-fn-decl-ret.rs:11:12
|
||||
|
|
||||
LL | pub fn lint_me() -> <() as Foo>::Assoc;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()`
|
||||
| ^^^^^^^ the trait `Foo` is not implemented for `()`
|
||||
|
||||
error[E0277]: the trait bound `u32: Unsatisfied` is not satisfied
|
||||
--> $DIR/wf-foreign-fn-decl-ret.rs:14:32
|
||||
|
|
Loading…
Add table
Reference in a new issue