diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index dbb5064c4f546..7e757d48209d7 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -2478,9 +2478,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!(), }; diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 0e685205069cb..98fde3707f70e 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -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>, depth: usize, + universes: Vec>, } 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>, ) -> AssocTypeNormalizer<'a, 'b, 'tcx> { - AssocTypeNormalizer { selcx, param_env, cause, obligations, depth } + AssocTypeNormalizer { selcx, param_env, cause, obligations, depth, universes: vec![] } } fn fold>(&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>( + &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, + mapped_types: BTreeMap, + mapped_consts: BTreeMap, 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>, +} + +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>( + infcx: &'me InferCtxt<'me, 'tcx>, + universe_indices: &'me mut Vec>, + value: T, + ) -> ( + T, + BTreeMap, + BTreeMap, + BTreeMap, ty::BoundVar>, + ) { + let mapped_regions: BTreeMap = BTreeMap::new(); + let mapped_types: BTreeMap = BTreeMap::new(); + let mapped_consts: BTreeMap, 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>( + &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, + mapped_types: BTreeMap, + mapped_consts: BTreeMap, ty::BoundVar>, + universe_indices: &'me Vec>, + current_index: ty::DebruijnIndex, +} + +impl<'me, 'tcx> PlaceholderReplacer<'me, 'tcx> { + pub fn replace_placeholders>( + infcx: &'me InferCtxt<'me, 'tcx>, + mapped_regions: BTreeMap, + mapped_types: BTreeMap, + mapped_consts: BTreeMap, ty::BoundVar>, + universe_indices: &'me Vec>, + 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>( + &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 `::Item`. The result is always a type (and possibly /// additional obligations). If ambiguity arises, which implies that diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 6673e021bf308..94539eda0f89e 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -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>>, error: bool, anon_depth: usize, + universes: Vec>, } 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>( + &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, })(); diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index 0e063c86f2f4e..c7a28cd9f3ef4 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -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 @@ -902,8 +900,8 @@ fn check_fn_or_method<'fcx, 'tcx>( def_id: DefId, implied_bounds: &mut Vec>, ) { - 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); @@ -1081,8 +1079,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); diff --git a/src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr b/src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr index 6d7289bd0712b..e8c11a32bf7fd 100644 --- a/src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr +++ b/src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr @@ -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(&self, foo: U, bar: ::Value) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self` + | ^^^^ the trait `Get` is not implemented for `Self` | help: consider further restricting `Self` | diff --git a/src/test/ui/associated-types/associated-types-no-suitable-bound.stderr b/src/test/ui/associated-types/associated-types-no-suitable-bound.stderr index 0b5dee611e489..e3be434698ab9 100644 --- a/src/test/ui/associated-types/associated-types-no-suitable-bound.stderr +++ b/src/test/ui/associated-types/associated-types-no-suitable-bound.stderr @@ -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(foo: ::Value) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `T` + | ^^^^ the trait `Get` is not implemented for `T` | help: consider restricting type parameter `T` | diff --git a/src/test/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr b/src/test/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr index dfe62aa5d6b00..9dc3414e9edf0 100644 --- a/src/test/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr +++ b/src/test/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr @@ -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(&self, foo: U, bar: ::Value) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self` + | ^^^^ the trait `Get` is not implemented for `Self` | help: consider further restricting `Self` | diff --git a/src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr b/src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr index f0f2451a1ecea..c2aed3f9de548 100644 --- a/src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr +++ b/src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr @@ -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(&self, foo: U, bar: ::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(&self, foo: U, bar: ::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(&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 diff --git a/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr b/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr index 4528f03c54a63..fb842d968676d 100644 --- a/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr +++ b/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr @@ -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(&self, foo: U, bar: ::Value); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self` + | ^^^^ the trait `Get` is not implemented for `Self` | help: consider further restricting `Self` | diff --git a/src/test/ui/associated-types/normalization-debruijn-1.rs b/src/test/ui/associated-types/normalization-debruijn-1.rs new file mode 100644 index 0000000000000..a5abf1ba99d6a --- /dev/null +++ b/src/test/ui/associated-types/normalization-debruijn-1.rs @@ -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 { + 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>>>; +} +impl<'r, T: FromRequest<'r>> FromRequest<'r> for Option { + type Error = (); + fn from_request<'life0>( + request: &'r Request<'life0>, + ) -> Pin>>> { + Box::pin(async move { + let request = request; + match T::from_request(request).await { + _ => todo!(), + } + }); + todo!() + } +} + +fn main() {} diff --git a/src/test/ui/associated-types/normalization-debruijn-2.rs b/src/test/ui/associated-types/normalization-debruijn-2.rs new file mode 100644 index 0000000000000..abe248e16a198 --- /dev/null +++ b/src/test/ui/associated-types/normalization-debruijn-2.rs @@ -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 { + 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>>>; +} +pub struct S { + _marker: std::marker::PhantomData, +} +impl<'r, T: FromRequest<'r>> S { + pub async fn from_request(request: &'r Request<'_>) { + let _ = T::from_request(request).await; + } +} + +fn main() {} diff --git a/src/test/ui/associated-types/normalization-debruijn-3.rs b/src/test/ui/associated-types/normalization-debruijn-3.rs new file mode 100644 index 0000000000000..2bea78cf7bd69 --- /dev/null +++ b/src/test/ui/associated-types/normalization-debruijn-3.rs @@ -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(addr: A) { + let _ = addr.to_socket_addr().await; +} +pub trait ToSocketAddr { + type Future: Future; + 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(self, _fun: F) -> AndThen { + unimplemented!() + } +} +struct AndThen { + _marker: std::marker::PhantomData, +} +pub async fn run(_: F) { +} +fn main() { + let _ = async { + let server = Server; + let verification_route = server.and_then(read); + run(verification_route).await; + }; +} diff --git a/src/test/ui/associated-types/normalization-generality.rs b/src/test/ui/associated-types/normalization-generality.rs new file mode 100644 index 0000000000000..f8e3f5b58d1b3 --- /dev/null +++ b/src/test/ui/associated-types/normalization-generality.rs @@ -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 Yokeable<'a>> { + _yokeable: Y, +} + +impl Yokeable<'a>> Yoke { + pub fn project<'this, P>( + &'this self, + _f: for<'a> fn(>::Output, &'a ()) ->

>::Output, + ) -> Yoke

+ 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() {} diff --git a/src/test/ui/generic-associated-types/issue-76407.rs b/src/test/ui/generic-associated-types/issue-76407.rs new file mode 100644 index 0000000000000..42f19feb5f132 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-76407.rs @@ -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() +where + T: MyTrait, + for<'a> T::Item<'a>: Marker +{} + +fn main() { + ty_check::(); +} diff --git a/src/test/ui/generic-associated-types/issue-76826.rs b/src/test/ui/generic-associated-types/issue-76826.rs new file mode 100644 index 0000000000000..a905ef4eb13fd --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-76826.rs @@ -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>; + + fn for_each(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 { + items: Vec, + start: usize, + len: usize, +} + +impl Windows { + pub fn new(items: Vec, len: usize) -> Self { + Self { items, start: 0, len } + } +} + +impl Iter for Windows { + type Item<'a> where T: 'a = &'a mut [T]; + + fn next<'a>(&'a mut self) -> Option> { + 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)); +} diff --git a/src/test/ui/issues/issue-18611.stderr b/src/test/ui/issues/issue-18611.stderr index 22c3470b61ede..8872f51753c94 100644 --- a/src/test/ui/issues/issue-18611.stderr +++ b/src/test/ui/issues/issue-18611.stderr @@ -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: ::State) { -LL | | -LL | | } - | |_^ the trait `HasState` is not implemented for `isize` +LL | fn add_state(op: ::State) { + | ^^^^^^^^^ the trait `HasState` is not implemented for `isize` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20831-debruijn.stderr b/src/test/ui/issues/issue-20831-debruijn.stderr index e68482d1caf69..03e3311e0f39b 100644 --- a/src/test/ui/issues/issue-20831-debruijn.stderr +++ b/src/test/ui/issues/issue-20831-debruijn.stderr @@ -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::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::Output> + 'a>) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^ = note: expected `Publisher<'_>` found `Publisher<'_>` diff --git a/src/test/ui/nll/normalization-bounds-error.stderr b/src/test/ui/nll/normalization-bounds-error.stderr index d003acd879a77..8c7c8918f3fc6 100644 --- a/src/test/ui/nll/normalization-bounds-error.stderr +++ b/src/test/ui/nll/normalization-bounds-error.stderr @@ -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<'_>` diff --git a/src/test/ui/wf/wf-foreign-fn-decl-ret.stderr b/src/test/ui/wf/wf-foreign-fn-decl-ret.stderr index 9081b7929d935..a0eb7d10bd94a 100644 --- a/src/test/ui/wf/wf-foreign-fn-decl-ret.stderr +++ b/src/test/ui/wf/wf-foreign-fn-decl-ret.stderr @@ -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