From 22d582a38d3a25e9ec1a6062a91ae0d805e0cd26 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 1 Feb 2024 23:48:04 +0000 Subject: [PATCH 1/4] For a rigid projection, recursively look at the self type's item bounds --- .../src/solve/assembly/mod.rs | 129 ++++++++++++------ .../src/traits/project.rs | 61 +++++---- .../src/traits/select/candidate_assembly.rs | 54 +++++++- .../src/traits/select/confirmation.rs | 29 ++-- .../src/traits/select/mod.rs | 95 +++++-------- .../bad-bounds-on-assoc-in-trait.rs | 32 +---- .../bad-bounds-on-assoc-in-trait.stderr | 39 ------ .../bounds-on-assoc-in-trait.rs | 5 +- .../bounds-on-assoc-in-trait.stderr | 26 ---- tests/ui/associated-type-bounds/duplicate.rs | 3 - .../associated-type-bounds/duplicate.stderr | 50 ++----- .../hr-associated-type-bound-object.stderr | 4 + ...elf-auto-trait-issue-109924.current.stderr | 28 +--- ...g-self-auto-trait-issue-109924.next.stderr | 2 +- ...ormalizing-self-auto-trait-issue-109924.rs | 5 +- .../feature-gate-associated_type_bounds.rs | 1 - ...feature-gate-associated_type_bounds.stderr | 47 +++---- .../bugs/issue-88460.rs | 5 +- .../bugs/issue-88460.stderr | 29 ---- .../normalize-under-binder/issue-90950.rs | 3 +- .../normalize-under-binder/issue-90950.stderr | 29 ---- .../norm-before-method-resolution.rs | 3 +- .../norm-before-method-resolution.stderr | 23 ---- 23 files changed, 272 insertions(+), 430 deletions(-) delete mode 100644 tests/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr delete mode 100644 tests/ui/associated-type-bounds/bounds-on-assoc-in-trait.stderr delete mode 100644 tests/ui/generic-associated-types/bugs/issue-88460.stderr delete mode 100644 tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90950.stderr delete mode 100644 tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution.stderr diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 239072dfc8e0e..150894ba83e05 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -542,50 +542,97 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { goal: Goal<'tcx, G>, candidates: &mut Vec>, ) { - let alias_ty = match goal.predicate.self_ty().kind() { - ty::Bool - | ty::Char - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::Adt(_, _) - | ty::Foreign(_) - | ty::Str - | ty::Array(_, _) - | ty::Slice(_) - | ty::RawPtr(_) - | ty::Ref(_, _, _) - | ty::FnDef(_, _) - | ty::FnPtr(_) - | ty::Dynamic(..) - | ty::Closure(..) - | ty::CoroutineClosure(..) - | ty::Coroutine(..) - | ty::CoroutineWitness(..) - | ty::Never - | ty::Tuple(_) - | ty::Param(_) - | ty::Placeholder(..) - | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) - | ty::Alias(ty::Inherent, _) - | ty::Alias(ty::Weak, _) - | ty::Error(_) => return, - ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) - | ty::Bound(..) => bug!("unexpected self type for `{goal:?}`"), - // Excluding IATs and type aliases here as they don't have meaningful item bounds. - ty::Alias(ty::Projection | ty::Opaque, alias_ty) => alias_ty, - }; + let _ = self.probe(|_| ProbeKind::NormalizedSelfTyAssembly).enter(|ecx| { + let mut self_ty = goal.predicate.self_ty(); + + // For some deeply nested `::A::B::C::D` rigid associated type, + // we should explore the item bounds for all levels, since the + // `associated_type_bounds` feature means that a parent associated + // type may carry bounds for a nested associated type. + loop { + let (kind, alias_ty) = match *self_ty.kind() { + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Adt(_, _) + | ty::Foreign(_) + | ty::Str + | ty::Array(_, _) + | ty::Slice(_) + | ty::RawPtr(_) + | ty::Ref(_, _, _) + | ty::FnDef(_, _) + | ty::FnPtr(_) + | ty::Dynamic(..) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(..) + | ty::CoroutineWitness(..) + | ty::Never + | ty::Tuple(_) + | ty::Param(_) + | ty::Placeholder(..) + | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::Error(_) => break, + ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) + | ty::Bound(..) => bug!("unexpected self type for `{goal:?}`"), + + // If we hit infer when normalizing the self type of an alias, + // then bail with ambiguity. + ty::Infer(ty::TyVar(_)) => { + if let Ok(result) = ecx + .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) + { + candidates + .push(Candidate { source: CandidateSource::AliasBound, result }); + } + break; + } - for assumption in - self.tcx().item_bounds(alias_ty.def_id).instantiate(self.tcx(), alias_ty.args) - { - match G::consider_alias_bound_candidate(self, goal, assumption) { - Ok(result) => { - candidates.push(Candidate { source: CandidateSource::AliasBound, result }) + ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) => (kind, alias_ty), + ty::Alias(ty::Inherent | ty::Weak, _) => { + unreachable!("Weak and Inherent aliases should have been normalized away") + } + }; + + for assumption in + ecx.tcx().item_bounds(alias_ty.def_id).instantiate(ecx.tcx(), alias_ty.args) + { + match G::consider_alias_bound_candidate(ecx, goal, assumption) { + Ok(result) => { + candidates + .push(Candidate { source: CandidateSource::AliasBound, result }); + } + Err(NoSolution) => {} + } + } + + // If we have a projection, check that its self type is a rigid projection. + // If so, continue searching. + if kind == ty::Projection { + match ecx.try_normalize_ty(goal.param_env, alias_ty.self_ty()) { + Some(next_self_ty) => self_ty = next_self_ty, + None => { + if let Ok(result) = ecx + .evaluate_added_goals_and_make_canonical_response( + Certainty::OVERFLOW, + ) + { + candidates.push(Candidate { + source: CandidateSource::AliasBound, + result, + }); + } + break; + } + } + } else { + break; } - Err(NoSolution) => (), } - } + }); } /// Check that we are allowed to use an alias bound originating from the self diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index fd8306bbc0b69..8f47e45df0c6c 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -40,6 +40,7 @@ use rustc_middle::ty::{self, Term, ToPredicate, Ty, TyCtxt}; use rustc_span::symbol::sym; use std::collections::BTreeMap; +use std::ops::ControlFlow; pub use rustc_middle::traits::Reveal; @@ -1614,32 +1615,46 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>( candidate_set: &mut ProjectionCandidateSet<'tcx>, ) { debug!("assemble_candidates_from_trait_def(..)"); + let mut ambiguous = false; + selcx.for_each_item_bound( + obligation.predicate.self_ty(), + |selcx, clause, _| { + let Some(clause) = clause.as_projection_clause() else { + return ControlFlow::Continue(()); + }; - let tcx = selcx.tcx(); - // Check whether the self-type is itself a projection. - // If so, extract what we know from the trait and try to come up with a good answer. - let bounds = match *obligation.predicate.self_ty().kind() { - // Excluding IATs and type aliases here as they don't have meaningful item bounds. - ty::Alias(ty::Projection | ty::Opaque, ref data) => { - tcx.item_bounds(data.def_id).instantiate(tcx, data.args) - } - ty::Infer(ty::TyVar(_)) => { - // If the self-type is an inference variable, then it MAY wind up - // being a projected type, so induce an ambiguity. - candidate_set.mark_ambiguous(); - return; - } - _ => return, - }; + let is_match = + selcx.infcx.probe(|_| selcx.match_projection_projections(obligation, clause, true)); - assemble_candidates_from_predicates( - selcx, - obligation, - candidate_set, - ProjectionCandidate::TraitDef, - bounds.iter(), - true, + match is_match { + ProjectionMatchesProjection::Yes => { + candidate_set.push_candidate(ProjectionCandidate::TraitDef(clause)); + + if !obligation.predicate.has_non_region_infer() { + // HACK: Pick the first trait def candidate for a fully + // inferred predicate. This is to allow duplicates that + // differ only in normalization. + return ControlFlow::Break(()); + } + } + ProjectionMatchesProjection::Ambiguous => { + candidate_set.mark_ambiguous(); + } + ProjectionMatchesProjection::No => {} + } + + ControlFlow::Continue(()) + }, + || { + // `ProjectionCandidateSet` is borrowed in the above closure, + // so just mark ambiguous outside of the closure. + ambiguous = true; + }, ); + + if ambiguous { + candidate_set.mark_ambiguous(); + } } /// In the case of a trait object like diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index d056dd51f507e..248d75aaec713 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -6,13 +6,16 @@ //! //! [rustc dev guide]:https://rustc-dev-guide.rust-lang.org/traits/resolution.html#candidate-assembly +use std::ops::ControlFlow; + use hir::def_id::DefId; use hir::LangItem; +use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_infer::traits::ObligationCause; use rustc_infer::traits::{Obligation, PolyTraitObligation, SelectionError}; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; -use rustc_middle::ty::{self, Ty, TypeVisitableExt}; +use rustc_middle::ty::{self, ToPolyTraitRef, Ty, TypeVisitableExt}; use crate::traits; use crate::traits::query::evaluate_obligation::InferCtxtExt; @@ -158,11 +161,52 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { _ => return, } - let result = self - .infcx - .probe(|_| self.match_projection_obligation_against_definition_bounds(obligation)); + self.infcx.probe(|_| { + let poly_trait_predicate = self.infcx.resolve_vars_if_possible(obligation.predicate); + let placeholder_trait_predicate = + self.infcx.enter_forall_and_leak_universe(poly_trait_predicate); + debug!(?placeholder_trait_predicate); + + // The bounds returned by `item_bounds` may contain duplicates after + // normalization, so try to deduplicate when possible to avoid + // unnecessary ambiguity. + let mut distinct_normalized_bounds = FxHashSet::default(); + self.for_each_item_bound::( + placeholder_trait_predicate.self_ty(), + |selcx, bound, idx| { + let Some(bound) = bound.as_trait_clause() else { + return ControlFlow::Continue(()); + }; + if bound.polarity() != placeholder_trait_predicate.polarity { + return ControlFlow::Continue(()); + } + + selcx.infcx.probe(|_| { + match selcx.match_normalize_trait_ref( + obligation, + bound.to_poly_trait_ref(), + placeholder_trait_predicate.trait_ref, + ) { + Ok(None) => { + candidates.vec.push(ProjectionCandidate(idx)); + } + Ok(Some(normalized_trait)) + if distinct_normalized_bounds.insert(normalized_trait) => + { + candidates.vec.push(ProjectionCandidate(idx)); + } + _ => {} + } + }); - candidates.vec.extend(result.into_iter().map(|idx| ProjectionCandidate(idx))); + ControlFlow::Continue(()) + }, + || { + // On ambiguity. + candidates.ambiguous = true; + }, + ); + }); } /// Given an obligation like ``, searches the obligations that the caller diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index f0c49253dbd7a..42074f4a079e2 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -162,20 +162,26 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.infcx.enter_forall_and_leak_universe(trait_predicate).trait_ref; let placeholder_self_ty = placeholder_trait_predicate.self_ty(); let placeholder_trait_predicate = ty::Binder::dummy(placeholder_trait_predicate); - let (def_id, args) = match *placeholder_self_ty.kind() { - // Excluding IATs and type aliases here as they don't have meaningful item bounds. - ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, args, .. }) => { - (def_id, args) - } - _ => bug!("projection candidate for unexpected type: {:?}", placeholder_self_ty), - }; - let candidate_predicate = - tcx.item_bounds(def_id).map_bound(|i| i[idx]).instantiate(tcx, args); + let candidate_predicate = self + .for_each_item_bound( + placeholder_self_ty, + |_, clause, clause_idx| { + if clause_idx == idx { + ControlFlow::Break(clause) + } else { + ControlFlow::Continue(()) + } + }, + || unreachable!(), + ) + .break_value() + .expect("expected to index into clause that exists"); let candidate = candidate_predicate .as_trait_clause() .expect("projection candidate is not a trait predicate") .map_bound(|t| t.trait_ref); + let mut obligations = Vec::new(); let candidate = normalize_with_depth_to( self, @@ -194,8 +200,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .map_err(|_| Unimplemented) })?); - if let ty::Alias(ty::Projection, ..) = placeholder_self_ty.kind() { - let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, args); + // FIXME(compiler-errors): I don't think this is needed. + if let ty::Alias(ty::Projection, alias_ty) = placeholder_self_ty.kind() { + let predicates = tcx.predicates_of(alias_ty.def_id).instantiate_own(tcx, alias_ty.args); for (predicate, _) in predicates { let normalized = normalize_with_depth_to( self, diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 5befff5372aa4..ac6cfcdeb5950 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -52,6 +52,7 @@ use std::cell::{Cell, RefCell}; use std::cmp; use std::fmt::{self, Display}; use std::iter; +use std::ops::ControlFlow; pub use rustc_middle::traits::select::*; use rustc_middle::ty::print::with_no_trimmed_paths; @@ -1592,71 +1593,41 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.infcx.selection_cache.insert((param_env, pred), dep_node, candidate); } - /// Matches a predicate against the bounds of its self type. - /// - /// Given an obligation like `::Bar: Baz` where the self type is - /// a projection, look at the bounds of `T::Bar`, see if we can find a - /// `Baz` bound. We return indexes into the list returned by - /// `tcx.item_bounds` for any applicable bounds. - #[instrument(level = "debug", skip(self), ret)] - fn match_projection_obligation_against_definition_bounds( + /// Looks at the item bounds of the projection or opaque type. + /// If this is a nested rigid projection, such as + /// `<::Assoc as Tr2>::Assoc`, consider the item bounds + /// on both `Tr1::Assoc` and `Tr2::Assoc`, since we may encounter + /// relative bounds on both via the `associated_type_bounds` feature. + pub(super) fn for_each_item_bound( &mut self, - obligation: &PolyTraitObligation<'tcx>, - ) -> smallvec::SmallVec<[usize; 2]> { - let poly_trait_predicate = self.infcx.resolve_vars_if_possible(obligation.predicate); - let placeholder_trait_predicate = - self.infcx.enter_forall_and_leak_universe(poly_trait_predicate); - debug!(?placeholder_trait_predicate); - - let tcx = self.infcx.tcx; - let (def_id, args) = match *placeholder_trait_predicate.trait_ref.self_ty().kind() { - ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, args, .. }) => { - (def_id, args) - } - _ => { - span_bug!( - obligation.cause.span, - "match_projection_obligation_against_definition_bounds() called \ - but self-ty is not a projection: {:?}", - placeholder_trait_predicate.trait_ref.self_ty() - ); - } - }; - let bounds = tcx.item_bounds(def_id).instantiate(tcx, args); + mut self_ty: Ty<'tcx>, + mut for_each: impl FnMut(&mut Self, ty::Clause<'tcx>, usize) -> ControlFlow, + on_ambiguity: impl FnOnce(), + ) -> ControlFlow { + let mut idx = 0; + loop { + let (kind, alias_ty) = match *self_ty.kind() { + ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) => (kind, alias_ty), + ty::Infer(ty::TyVar(_)) => { + on_ambiguity(); + return ControlFlow::Continue(()); + } + _ => return ControlFlow::Continue(()), + }; - // The bounds returned by `item_bounds` may contain duplicates after - // normalization, so try to deduplicate when possible to avoid - // unnecessary ambiguity. - let mut distinct_normalized_bounds = FxHashSet::default(); + for bound in + self.tcx().item_bounds(alias_ty.def_id).instantiate(self.tcx(), alias_ty.args) + { + for_each(self, bound, idx)?; + idx += 1; + } - bounds - .iter() - .enumerate() - .filter_map(|(idx, bound)| { - let bound_predicate = bound.kind(); - if let ty::ClauseKind::Trait(pred) = bound_predicate.skip_binder() { - let bound = bound_predicate.rebind(pred.trait_ref); - if self.infcx.probe(|_| { - match self.match_normalize_trait_ref( - obligation, - bound, - placeholder_trait_predicate.trait_ref, - ) { - Ok(None) => true, - Ok(Some(normalized_trait)) - if distinct_normalized_bounds.insert(normalized_trait) => - { - true - } - _ => false, - } - }) { - return Some(idx); - } - } - None - }) - .collect() + if kind == ty::Projection { + self_ty = alias_ty.self_ty(); + } else { + return ControlFlow::Continue(()); + } + } } /// Equates the trait in `obligation` with trait bound. If the two traits diff --git a/tests/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs b/tests/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs index d180de9be3bf3..1c48aadecceb9 100644 --- a/tests/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs +++ b/tests/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs @@ -1,5 +1,4 @@ -// NOTE: rustc cannot currently handle bounds of the form `for<'a> >::Assoc: Baz`. -// This should hopefully be fixed with Chalk. +// check-pass #![feature(associated_type_bounds)] @@ -24,9 +23,6 @@ impl<'a, 'b> Lam<&'a &'b u8> for L2 { trait Case1 { type C: Clone + Iterator Lam<&'a u8, App: Debug>> + Sync>; - //~^ ERROR `<::C as Iterator>::Item` is not an iterator - //~| ERROR `<::C as Iterator>::Item` cannot be sent between threads safely - //~| ERROR `<::C as Iterator>::Item` cannot be shared between threads safely } pub struct S1; @@ -35,33 +31,17 @@ impl Case1 for S1 { } fn assume_case1() { - fn assert_a<_0, A>() - where - A: Iterator, - _0: Debug, - { - } - assert_a::<_, T::A>(); - - fn assert_b<_0, B>() - where - B: Iterator, - _0: 'static, - { - } - assert_b::<_, T::B>(); - - fn assert_c<_0, _1, _2, C>() + fn assert_c<_1, _2, C>() where C: Clone + Iterator, _2: Send + Iterator, - _1: for<'a> Lam<&'a u8, App = _0>, - _0: Debug, + _1: for<'a> Lam<&'a u8>, + for<'a> <_1 as Lam<&'a u8>>::App: Debug, { } - assert_c::<_, _, _, T::C>(); + assert_c::<_, _, T::C>(); } fn main() { - assume_case1(S1); + assume_case1::(); } diff --git a/tests/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr b/tests/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr deleted file mode 100644 index c23e54594ee30..0000000000000 --- a/tests/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr +++ /dev/null @@ -1,39 +0,0 @@ -error[E0277]: `<::C as Iterator>::Item` cannot be sent between threads safely - --> $DIR/bad-bounds-on-assoc-in-trait.rs:26:36 - | -LL | type C: Clone + Iterator Lam<&'a u8, App: Debug>> + Sync>; - | ^^^^ `<::C as Iterator>::Item` cannot be sent between threads safely - | - = help: the trait `Send` is not implemented for `<::C as Iterator>::Item` -help: consider further restricting the associated type - | -LL | trait Case1 where <::C as Iterator>::Item: Send { - | ++++++++++++++++++++++++++++++++++++++++++++++++++ - -error[E0277]: `<::C as Iterator>::Item` is not an iterator - --> $DIR/bad-bounds-on-assoc-in-trait.rs:26:43 - | -LL | type C: Clone + Iterator Lam<&'a u8, App: Debug>> + Sync>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `<::C as Iterator>::Item` is not an iterator - | - = help: the trait `Iterator` is not implemented for `<::C as Iterator>::Item` -help: consider further restricting the associated type - | -LL | trait Case1 where <::C as Iterator>::Item: Iterator { - | ++++++++++++++++++++++++++++++++++++++++++++++++++++++ - -error[E0277]: `<::C as Iterator>::Item` cannot be shared between threads safely - --> $DIR/bad-bounds-on-assoc-in-trait.rs:26:93 - | -LL | type C: Clone + Iterator Lam<&'a u8, App: Debug>> + Sync>; - | ^^^^ `<::C as Iterator>::Item` cannot be shared between threads safely - | - = help: the trait `Sync` is not implemented for `<::C as Iterator>::Item` -help: consider further restricting the associated type - | -LL | trait Case1 where <::C as Iterator>::Item: Sync { - | ++++++++++++++++++++++++++++++++++++++++++++++++++ - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/associated-type-bounds/bounds-on-assoc-in-trait.rs b/tests/ui/associated-type-bounds/bounds-on-assoc-in-trait.rs index 23be735010bf3..7bc2970ade9a2 100644 --- a/tests/ui/associated-type-bounds/bounds-on-assoc-in-trait.rs +++ b/tests/ui/associated-type-bounds/bounds-on-assoc-in-trait.rs @@ -1,3 +1,5 @@ +// check-pass + #![feature(associated_type_bounds)] use std::fmt::Debug; @@ -16,8 +18,6 @@ impl<'a, 'b> Lam<&'a &'b u8> for L2 { type App = u8; } trait Case1 { type A: Iterator; - //~^ ERROR `<::A as Iterator>::Item` doesn't implement `Debug` - type B: Iterator; } @@ -33,7 +33,6 @@ impl Case1 for S1 { // bounds of `Out`, but trait selection can't find the bound since it applies // to a type other than `Self::Out`. pub trait Foo { type Out: Baz; } -//~^ ERROR trait bound `<::Out as Baz>::Assoc: Default` is not satisfied pub trait Baz { type Assoc; } #[derive(Default)] diff --git a/tests/ui/associated-type-bounds/bounds-on-assoc-in-trait.stderr b/tests/ui/associated-type-bounds/bounds-on-assoc-in-trait.stderr deleted file mode 100644 index 4e2313bd4e4a9..0000000000000 --- a/tests/ui/associated-type-bounds/bounds-on-assoc-in-trait.stderr +++ /dev/null @@ -1,26 +0,0 @@ -error[E0277]: `<::A as Iterator>::Item` doesn't implement `Debug` - --> $DIR/bounds-on-assoc-in-trait.rs:18:28 - | -LL | type A: Iterator; - | ^^^^^ `<::A as Iterator>::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug` - | - = help: the trait `Debug` is not implemented for `<::A as Iterator>::Item` -help: consider further restricting the associated type - | -LL | trait Case1 where <::A as Iterator>::Item: Debug { - | +++++++++++++++++++++++++++++++++++++++++++++++++++ - -error[E0277]: the trait bound `<::Out as Baz>::Assoc: Default` is not satisfied - --> $DIR/bounds-on-assoc-in-trait.rs:35:38 - | -LL | pub trait Foo { type Out: Baz; } - | ^^^^^^^ the trait `Default` is not implemented for `<::Out as Baz>::Assoc` - | -help: consider further restricting the associated type - | -LL | pub trait Foo where <::Out as Baz>::Assoc: Default { type Out: Baz; } - | +++++++++++++++++++++++++++++++++++++++++++++++++ - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/associated-type-bounds/duplicate.rs b/tests/ui/associated-type-bounds/duplicate.rs index 160b524c881c9..036f8ede1b3b7 100644 --- a/tests/ui/associated-type-bounds/duplicate.rs +++ b/tests/ui/associated-type-bounds/duplicate.rs @@ -251,13 +251,10 @@ where trait TRA1 { type A: Iterator; //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] - //~| ERROR `<::A as Iterator>::Item` cannot be sent between threads safely - //~| ERROR the trait bound `<::A as Iterator>::Item: Copy` is not satisfied } trait TRA2 { type A: Iterator; //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719] - //~| ERROR the trait bound `<::A as Iterator>::Item: Copy` is not satisfied } trait TRA3 { type A: Iterator; diff --git a/tests/ui/associated-type-bounds/duplicate.stderr b/tests/ui/associated-type-bounds/duplicate.stderr index accb366dd1552..bf6aab96dc726 100644 --- a/tests/ui/associated-type-bounds/duplicate.stderr +++ b/tests/ui/associated-type-bounds/duplicate.stderr @@ -7,7 +7,7 @@ LL | struct SI1> { | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:267:40 + --> $DIR/duplicate.rs:264:40 | LL | type TADyn1 = dyn Iterator; | ---------- ^^^^^^^^^^ re-bound here @@ -15,7 +15,7 @@ LL | type TADyn1 = dyn Iterator; | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:269:44 + --> $DIR/duplicate.rs:266:44 | LL | type TADyn2 = Box>; | ---------- ^^^^^^^^^^ re-bound here @@ -23,7 +23,7 @@ LL | type TADyn2 = Box>; | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:271:43 + --> $DIR/duplicate.rs:268:43 | LL | type TADyn3 = dyn Iterator; | ------------- ^^^^^^^^^^^^^ re-bound here @@ -523,7 +523,7 @@ LL | type A: Iterator; | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:258:34 + --> $DIR/duplicate.rs:256:34 | LL | type A: Iterator; | ---------- ^^^^^^^^^^ re-bound here @@ -531,7 +531,7 @@ LL | type A: Iterator; | `Item` bound here first error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate.rs:263:37 + --> $DIR/duplicate.rs:260:37 | LL | type A: Iterator; | ------------- ^^^^^^^^^^^^^ re-bound here @@ -631,41 +631,7 @@ LL | Self: Iterator, | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0277]: the trait bound `<::A as Iterator>::Item: Copy` is not satisfied - --> $DIR/duplicate.rs:252:28 - | -LL | type A: Iterator; - | ^^^^ the trait `Copy` is not implemented for `<::A as Iterator>::Item` - | -help: consider further restricting the associated type - | -LL | trait TRA1 where <::A as Iterator>::Item: Copy { - | +++++++++++++++++++++++++++++++++++++++++++++++++ - -error[E0277]: `<::A as Iterator>::Item` cannot be sent between threads safely - --> $DIR/duplicate.rs:252:40 - | -LL | type A: Iterator; - | ^^^^ `<::A as Iterator>::Item` cannot be sent between threads safely - | - = help: the trait `Send` is not implemented for `<::A as Iterator>::Item` -help: consider further restricting the associated type - | -LL | trait TRA1 where <::A as Iterator>::Item: Send { - | +++++++++++++++++++++++++++++++++++++++++++++++++ - -error[E0277]: the trait bound `<::A as Iterator>::Item: Copy` is not satisfied - --> $DIR/duplicate.rs:258:28 - | -LL | type A: Iterator; - | ^^^^ the trait `Copy` is not implemented for `<::A as Iterator>::Item` - | -help: consider further restricting the associated type - | -LL | trait TRA2 where <::A as Iterator>::Item: Copy { - | +++++++++++++++++++++++++++++++++++++++++++++++++ - -error: aborting due to 78 previous errors +error: aborting due to 75 previous errors -Some errors have detailed explanations: E0277, E0282, E0719. -For more information about an error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0282, E0719. +For more information about an error, try `rustc --explain E0282`. diff --git a/tests/ui/associated-types/hr-associated-type-bound-object.stderr b/tests/ui/associated-types/hr-associated-type-bound-object.stderr index 8c91211b964b4..87a048d0a134c 100644 --- a/tests/ui/associated-types/hr-associated-type-bound-object.stderr +++ b/tests/ui/associated-types/hr-associated-type-bound-object.stderr @@ -12,6 +12,10 @@ LL | trait X<'a> LL | where LL | for<'b> >::U: Clone, | ^^^^^ required by this bound in `X` +help: consider further restricting the associated type + | +LL | fn f<'a, T: X<'a> + ?Sized>(x: &>::U) where for<'b> >::U: Clone { + | ++++++++++++++++++++++++++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.current.stderr b/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.current.stderr index d2db6abe3132c..2e82a3fcdb4c3 100644 --- a/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.current.stderr +++ b/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.current.stderr @@ -1,5 +1,5 @@ warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/normalizing-self-auto-trait-issue-109924.rs:7:12 + --> $DIR/normalizing-self-auto-trait-issue-109924.rs:6:12 | LL | #![feature(return_type_notation)] | ^^^^^^^^^^^^^^^^^^^^ @@ -7,29 +7,5 @@ LL | #![feature(return_type_notation)] = note: see issue #109417 for more information = note: `#[warn(incomplete_features)]` on by default -error[E0277]: `impl Future { <_ as Foo>::bar() }` cannot be sent between threads safely - --> $DIR/normalizing-self-auto-trait-issue-109924.rs:22:11 - | -LL | build(Bar); - | ----- ^^^ `impl Future { <_ as Foo>::bar() }` cannot be sent between threads safely - | | - | required by a bound introduced by this call - | - = help: the trait `for<'a> Send` is not implemented for `impl Future { <_ as Foo>::bar() }` -note: this is a known limitation of the trait solver that will be lifted in the future - --> $DIR/normalizing-self-auto-trait-issue-109924.rs:22:11 - | -LL | build(Bar); - | ------^^^- - | | | - | | the trait solver is unable to infer the generic types that should be inferred from this argument - | add turbofish arguments to this call to specify the types manually, even if it's redundant -note: required by a bound in `build` - --> $DIR/normalizing-self-auto-trait-issue-109924.rs:19:39 - | -LL | fn build(_: T) where T: Foo {} - | ^^^^ required by this bound in `build` - -error: aborting due to 1 previous error; 1 warning emitted +warning: 1 warning emitted -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.next.stderr b/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.next.stderr index 4837815fad4ad..2e82a3fcdb4c3 100644 --- a/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.next.stderr +++ b/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.next.stderr @@ -1,5 +1,5 @@ warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/normalizing-self-auto-trait-issue-109924.rs:7:12 + --> $DIR/normalizing-self-auto-trait-issue-109924.rs:6:12 | LL | #![feature(return_type_notation)] | ^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.rs b/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.rs index 6097c7f1073ed..5341c39a975aa 100644 --- a/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.rs +++ b/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.rs @@ -1,11 +1,10 @@ +// check-pass // revisions: current next -//[current] known-bug: #109924 -//[next] check-pass //[next] compile-flags: -Znext-solver // edition:2021 #![feature(return_type_notation)] -//[next]~^ WARN the feature `return_type_notation` is incomplete +//~^ WARN the feature `return_type_notation` is incomplete trait Foo { async fn bar(&self); diff --git a/tests/ui/feature-gates/feature-gate-associated_type_bounds.rs b/tests/ui/feature-gates/feature-gate-associated_type_bounds.rs index 073599edad7b9..f87d3aab635c0 100644 --- a/tests/ui/feature-gates/feature-gate-associated_type_bounds.rs +++ b/tests/ui/feature-gates/feature-gate-associated_type_bounds.rs @@ -11,7 +11,6 @@ impl Tr1 for S1 { type As1 = S2; } trait _Tr3 { type A: Iterator; //~^ ERROR associated type bounds are unstable - //~| ERROR the trait bound `<::A as Iterator>::Item: Copy` is not satisfied type B: Iterator; //~^ ERROR associated type bounds are unstable diff --git a/tests/ui/feature-gates/feature-gate-associated_type_bounds.stderr b/tests/ui/feature-gates/feature-gate-associated_type_bounds.stderr index efab91f25f0d2..855a29953f1b0 100644 --- a/tests/ui/feature-gates/feature-gate-associated_type_bounds.stderr +++ b/tests/ui/feature-gates/feature-gate-associated_type_bounds.stderr @@ -9,7 +9,7 @@ LL | type A: Iterator; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: associated type bounds are unstable - --> $DIR/feature-gate-associated_type_bounds.rs:16:22 + --> $DIR/feature-gate-associated_type_bounds.rs:15:22 | LL | type B: Iterator; | ^^^^^^^^^^^^^ @@ -19,7 +19,7 @@ LL | type B: Iterator; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: associated type bounds are unstable - --> $DIR/feature-gate-associated_type_bounds.rs:20:20 + --> $DIR/feature-gate-associated_type_bounds.rs:19:20 | LL | struct _St1> { | ^^^^^^^^ @@ -29,7 +29,7 @@ LL | struct _St1> { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: associated type bounds are unstable - --> $DIR/feature-gate-associated_type_bounds.rs:27:18 + --> $DIR/feature-gate-associated_type_bounds.rs:26:18 | LL | enum _En1> { | ^^^^^^^^ @@ -39,7 +39,7 @@ LL | enum _En1> { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: associated type bounds are unstable - --> $DIR/feature-gate-associated_type_bounds.rs:34:19 + --> $DIR/feature-gate-associated_type_bounds.rs:33:19 | LL | union _Un1> { | ^^^^^^^^ @@ -49,7 +49,7 @@ LL | union _Un1> { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: associated type bounds are unstable - --> $DIR/feature-gate-associated_type_bounds.rs:41:37 + --> $DIR/feature-gate-associated_type_bounds.rs:40:37 | LL | type _TaWhere1 where T: Iterator = T; | ^^^^^^^^^^ @@ -59,7 +59,7 @@ LL | type _TaWhere1 where T: Iterator = T; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: associated type bounds are unstable - --> $DIR/feature-gate-associated_type_bounds.rs:44:22 + --> $DIR/feature-gate-associated_type_bounds.rs:43:22 | LL | fn _apit(_: impl Tr1) {} | ^^^^^^^^^ @@ -69,7 +69,7 @@ LL | fn _apit(_: impl Tr1) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: associated type bounds are unstable - --> $DIR/feature-gate-associated_type_bounds.rs:46:26 + --> $DIR/feature-gate-associated_type_bounds.rs:45:26 | LL | fn _apit_dyn(_: &dyn Tr1) {} | ^^^^^^^^^ @@ -79,7 +79,7 @@ LL | fn _apit_dyn(_: &dyn Tr1) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: associated type bounds are unstable - --> $DIR/feature-gate-associated_type_bounds.rs:49:24 + --> $DIR/feature-gate-associated_type_bounds.rs:48:24 | LL | fn _rpit() -> impl Tr1 { S1 } | ^^^^^^^^^ @@ -89,7 +89,7 @@ LL | fn _rpit() -> impl Tr1 { S1 } = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: associated type bounds are unstable - --> $DIR/feature-gate-associated_type_bounds.rs:52:31 + --> $DIR/feature-gate-associated_type_bounds.rs:51:31 | LL | fn _rpit_dyn() -> Box> { Box::new(S1) } | ^^^^^^^^^ @@ -99,7 +99,7 @@ LL | fn _rpit_dyn() -> Box> { Box::new(S1) } = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: associated type bounds are unstable - --> $DIR/feature-gate-associated_type_bounds.rs:55:23 + --> $DIR/feature-gate-associated_type_bounds.rs:54:23 | LL | const _cdef: impl Tr1 = S1; | ^^^^^^^^^ @@ -109,7 +109,7 @@ LL | const _cdef: impl Tr1 = S1; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: associated type bounds are unstable - --> $DIR/feature-gate-associated_type_bounds.rs:61:24 + --> $DIR/feature-gate-associated_type_bounds.rs:60:24 | LL | static _sdef: impl Tr1 = S1; | ^^^^^^^^^ @@ -119,7 +119,7 @@ LL | static _sdef: impl Tr1 = S1; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: associated type bounds are unstable - --> $DIR/feature-gate-associated_type_bounds.rs:68:21 + --> $DIR/feature-gate-associated_type_bounds.rs:67:21 | LL | let _: impl Tr1 = S1; | ^^^^^^^^^ @@ -129,7 +129,7 @@ LL | let _: impl Tr1 = S1; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0562]: `impl Trait` is not allowed in const types - --> $DIR/feature-gate-associated_type_bounds.rs:55:14 + --> $DIR/feature-gate-associated_type_bounds.rs:54:14 | LL | const _cdef: impl Tr1 = S1; | ^^^^^^^^^^^^^^^^^^^ @@ -137,7 +137,7 @@ LL | const _cdef: impl Tr1 = S1; = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in static types - --> $DIR/feature-gate-associated_type_bounds.rs:61:15 + --> $DIR/feature-gate-associated_type_bounds.rs:60:15 | LL | static _sdef: impl Tr1 = S1; | ^^^^^^^^^^^^^^^^^^^ @@ -145,25 +145,14 @@ LL | static _sdef: impl Tr1 = S1; = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0562]: `impl Trait` is not allowed in the type of variable bindings - --> $DIR/feature-gate-associated_type_bounds.rs:68:12 + --> $DIR/feature-gate-associated_type_bounds.rs:67:12 | LL | let _: impl Tr1 = S1; | ^^^^^^^^^^^^^^^^^^^ | = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0277]: the trait bound `<::A as Iterator>::Item: Copy` is not satisfied - --> $DIR/feature-gate-associated_type_bounds.rs:12:28 - | -LL | type A: Iterator; - | ^^^^ the trait `Copy` is not implemented for `<::A as Iterator>::Item` - | -help: consider further restricting the associated type - | -LL | trait _Tr3 where <::A as Iterator>::Item: Copy { - | +++++++++++++++++++++++++++++++++++++++++++++++++ - -error: aborting due to 17 previous errors +error: aborting due to 16 previous errors -Some errors have detailed explanations: E0277, E0562, E0658. -For more information about an error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0562, E0658. +For more information about an error, try `rustc --explain E0562`. diff --git a/tests/ui/generic-associated-types/bugs/issue-88460.rs b/tests/ui/generic-associated-types/bugs/issue-88460.rs index 224e696ad2c9c..3d2b225f0cd01 100644 --- a/tests/ui/generic-associated-types/bugs/issue-88460.rs +++ b/tests/ui/generic-associated-types/bugs/issue-88460.rs @@ -1,7 +1,4 @@ -// check-fail -// known-bug: #88460 - -// This should pass, but has a missed normalization due to HRTB. +// check-pass pub trait Marker {} diff --git a/tests/ui/generic-associated-types/bugs/issue-88460.stderr b/tests/ui/generic-associated-types/bugs/issue-88460.stderr deleted file mode 100644 index 74418a0c0bd52..0000000000000 --- a/tests/ui/generic-associated-types/bugs/issue-88460.stderr +++ /dev/null @@ -1,29 +0,0 @@ -error[E0277]: the trait bound `for<'a> <_ as Trait>::Assoc<'a>: Marker` is not satisfied - --> $DIR/issue-88460.rs:28:10 - | -LL | test(Foo); - | ---- ^^^ the trait `for<'a> Marker` is not implemented for `<_ as Trait>::Assoc<'a>` - | | - | required by a bound introduced by this call - | - = help: the trait `Marker` is implemented for `()` -note: this is a known limitation of the trait solver that will be lifted in the future - --> $DIR/issue-88460.rs:28:10 - | -LL | test(Foo); - | -----^^^- - | | | - | | the trait solver is unable to infer the generic types that should be inferred from this argument - | add turbofish arguments to this call to specify the types manually, even if it's redundant -note: required by a bound in `test` - --> $DIR/issue-88460.rs:15:27 - | -LL | fn test(value: T) - | ---- required by a bound in this function -... -LL | for<'a> T::Assoc<'a>: Marker, - | ^^^^^^ required by this bound in `test` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90950.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90950.rs index ab9d9a7ce6f08..7072f41066b3a 100644 --- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90950.rs +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90950.rs @@ -1,5 +1,4 @@ -// check-fail -// known-bug: #90950 +// check-pass trait Yokeable<'a>: 'static { type Output: 'a; diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90950.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90950.stderr deleted file mode 100644 index 075e422e29c0b..0000000000000 --- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90950.stderr +++ /dev/null @@ -1,29 +0,0 @@ -error[E0277]: the trait bound `for<'a> <_ as Yokeable<'a>>::Output: IsCovariant<'a>` is not satisfied - --> $DIR/issue-90950.rs:50:12 - | -LL | upcast(y) - | ------ ^ the trait `for<'a> IsCovariant<'a>` is not implemented for `<_ as Yokeable<'a>>::Output` - | | - | required by a bound introduced by this call - | - = help: the trait `IsCovariant<'a>` is implemented for `std::borrow::Cow<'a, T>` -note: this is a known limitation of the trait solver that will be lifted in the future - --> $DIR/issue-90950.rs:50:12 - | -LL | upcast(y) - | -------^- - | | | - | | the trait solver is unable to infer the generic types that should be inferred from this argument - | add turbofish arguments to this call to specify the types manually, even if it's redundant -note: required by a bound in `upcast` - --> $DIR/issue-90950.rs:27:42 - | -LL | fn upcast(x: Yoke) -> Yoke + 'static>> where - | ------ required by a bound in this function -LL | Y: for<'a> Yokeable<'a>, -LL | for<'a> >::Output: IsCovariant<'a> - | ^^^^^^^^^^^^^^^ required by this bound in `upcast` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution.rs index 7693b11824762..58ca5b0c1874a 100644 --- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution.rs +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution.rs @@ -1,5 +1,4 @@ -// check-fail -// known-bug: #89196 +// check-pass // Should pass, but we normalize and check bounds before we resolve the generics // of the function (which we know because of the return type). diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution.stderr deleted file mode 100644 index f42fc59536c43..0000000000000 --- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution.stderr +++ /dev/null @@ -1,23 +0,0 @@ -error[E0277]: the trait bound `for<'a> <_ as Trait<'a>>::Out: Copy` is not satisfied - --> $DIR/norm-before-method-resolution.rs:22:17 - | -LL | let _: () = weird_bound(); - | ^^^^^^^^^^^^^ the trait `for<'a> Copy` is not implemented for `<_ as Trait<'a>>::Out` - | -note: this is a known limitation of the trait solver that will be lifted in the future - --> $DIR/norm-before-method-resolution.rs:22:17 - | -LL | let _: () = weird_bound(); - | ^^^^^^^^^^^^^ try adding turbofish arguments to this expression to specify the types manually, even if it's redundant -note: required by a bound in `weird_bound` - --> $DIR/norm-before-method-resolution.rs:18:40 - | -LL | fn weird_bound() -> X - | ----------- required by a bound in this function -... -LL | for<'a> >::Out: Copy - | ^^^^ required by this bound in `weird_bound` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. From 548929dc5e7558880108065e088b56a4a7e11205 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 2 Feb 2024 00:41:26 +0000 Subject: [PATCH 2/4] Don't unnecessarily lower associated type bounds to impl trait --- compiler/rustc_ast_lowering/src/lib.rs | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index b570a0611c3f3..ee798aa85920f 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1094,24 +1094,22 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Piggy-back on the `impl Trait` context to figure out the correct behavior. let desugar_kind = match itctx { - // We are in the return position: - // - // fn foo() -> impl Iterator - // - // so desugar to - // - // fn foo() -> impl Iterator - ImplTraitContext::ReturnPositionOpaqueTy { .. } - | ImplTraitContext::TypeAliasesOpaqueTy { .. } => DesugarKind::ImplTrait, - - // We are in the argument position, but within a dyn type: + // in an argument, RPIT, or TAIT, if we are within a dyn type: // // fn foo(x: dyn Iterator) // - // so desugar to + // then desugar to: // // fn foo(x: dyn Iterator) - ImplTraitContext::Universal if self.is_in_dyn_type => DesugarKind::ImplTrait, + // + // This is because dyn traits must have all of their associated types specified. + ImplTraitContext::ReturnPositionOpaqueTy { .. } + | ImplTraitContext::TypeAliasesOpaqueTy { .. } + | ImplTraitContext::Universal + if self.is_in_dyn_type => + { + DesugarKind::ImplTrait + } ImplTraitContext::Disallowed(position) if self.is_in_dyn_type => { DesugarKind::Error(position) From 7a63d3f16a44ade84f7fd99a7257ff753eb1da1d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 2 Feb 2024 17:51:16 +0000 Subject: [PATCH 3/4] Add tests for untested capabilities --- .../associated-type-bounds/higher-ranked.rs | 17 +++++++++ ...sted-bounds-dont-eliminate-alias-bounds.rs | 37 +++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 tests/ui/associated-type-bounds/higher-ranked.rs create mode 100644 tests/ui/associated-type-bounds/nested-bounds-dont-eliminate-alias-bounds.rs diff --git a/tests/ui/associated-type-bounds/higher-ranked.rs b/tests/ui/associated-type-bounds/higher-ranked.rs new file mode 100644 index 0000000000000..2bd5f316811d9 --- /dev/null +++ b/tests/ui/associated-type-bounds/higher-ranked.rs @@ -0,0 +1,17 @@ +// check-pass + +#![feature(associated_type_bounds)] + +trait A<'a> { + type Assoc: ?Sized; +} + +impl<'a> A<'a> for () { + type Assoc = &'a (); +} + +fn hello() -> impl for<'a> A<'a, Assoc: Sized> { + () +} + +fn main() {} diff --git a/tests/ui/associated-type-bounds/nested-bounds-dont-eliminate-alias-bounds.rs b/tests/ui/associated-type-bounds/nested-bounds-dont-eliminate-alias-bounds.rs new file mode 100644 index 0000000000000..05e4e323d879d --- /dev/null +++ b/tests/ui/associated-type-bounds/nested-bounds-dont-eliminate-alias-bounds.rs @@ -0,0 +1,37 @@ +// check-pass + +#![feature(associated_type_bounds)] + +trait Trait1 { + type Assoc1: Bar; + + fn assoc(self) -> Self::Assoc1; +} + +impl Trait1 for () { + type Assoc1 = (); + fn assoc(self) {} +} + +trait Foo {} +impl Foo for () {} +trait Bar {} +impl Bar for () {} + +fn hello() -> impl Trait1 { + () +} + +fn world() { + // Tests that `Assoc1: Foo` bound in the RPIT doesn't disqualify + // the `Assoc1: Bar` bound in the item, as a nested RPIT desugaring + // would do. + + fn is_foo(_: impl Foo) {} + is_foo(hello().assoc()); + + fn is_bar(_: impl Bar) {} + is_bar(hello().assoc()); +} + +fn main() {} From 7057188c549cb38e72843c9c344f77659bf67bc9 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 7 Feb 2024 00:19:12 +0000 Subject: [PATCH 4/4] make it recursive --- .../src/solve/assembly/mod.rs | 174 +++++++++--------- .../src/traits/project.rs | 8 +- .../src/traits/select/candidate_assembly.rs | 6 +- 3 files changed, 95 insertions(+), 93 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 150894ba83e05..380f7ac2d2da8 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -542,97 +542,103 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { goal: Goal<'tcx, G>, candidates: &mut Vec>, ) { - let _ = self.probe(|_| ProbeKind::NormalizedSelfTyAssembly).enter(|ecx| { - let mut self_ty = goal.predicate.self_ty(); - - // For some deeply nested `::A::B::C::D` rigid associated type, - // we should explore the item bounds for all levels, since the - // `associated_type_bounds` feature means that a parent associated - // type may carry bounds for a nested associated type. - loop { - let (kind, alias_ty) = match *self_ty.kind() { - ty::Bool - | ty::Char - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::Adt(_, _) - | ty::Foreign(_) - | ty::Str - | ty::Array(_, _) - | ty::Slice(_) - | ty::RawPtr(_) - | ty::Ref(_, _, _) - | ty::FnDef(_, _) - | ty::FnPtr(_) - | ty::Dynamic(..) - | ty::Closure(..) - | ty::CoroutineClosure(..) - | ty::Coroutine(..) - | ty::CoroutineWitness(..) - | ty::Never - | ty::Tuple(_) - | ty::Param(_) - | ty::Placeholder(..) - | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) - | ty::Error(_) => break, - ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) - | ty::Bound(..) => bug!("unexpected self type for `{goal:?}`"), - - // If we hit infer when normalizing the self type of an alias, - // then bail with ambiguity. - ty::Infer(ty::TyVar(_)) => { - if let Ok(result) = ecx - .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) - { - candidates - .push(Candidate { source: CandidateSource::AliasBound, result }); - } - break; - } + let () = self.probe(|_| ProbeKind::NormalizedSelfTyAssembly).enter(|ecx| { + ecx.assemble_alias_bound_candidates_recur(goal.predicate.self_ty(), goal, candidates); + }); + } - ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) => (kind, alias_ty), - ty::Alias(ty::Inherent | ty::Weak, _) => { - unreachable!("Weak and Inherent aliases should have been normalized away") - } - }; + /// For some deeply nested `::A::B::C::D` rigid associated type, + /// we should explore the item bounds for all levels, since the + /// `associated_type_bounds` feature means that a parent associated + /// type may carry bounds for a nested associated type. + /// + /// If we have a projection, check that its self type is a rigid projection. + /// If so, continue searching by recursively calling after normalization. + // FIXME: This may recurse infinitely, but I can't seem to trigger it without + // hitting another overflow error something. Add a depth parameter needed later. + fn assemble_alias_bound_candidates_recur>( + &mut self, + self_ty: Ty<'tcx>, + goal: Goal<'tcx, G>, + candidates: &mut Vec>, + ) { + let (kind, alias_ty) = match *self_ty.kind() { + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Adt(_, _) + | ty::Foreign(_) + | ty::Str + | ty::Array(_, _) + | ty::Slice(_) + | ty::RawPtr(_) + | ty::Ref(_, _, _) + | ty::FnDef(_, _) + | ty::FnPtr(_) + | ty::Dynamic(..) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(..) + | ty::CoroutineWitness(..) + | ty::Never + | ty::Tuple(_) + | ty::Param(_) + | ty::Placeholder(..) + | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::Error(_) => return, + ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) | ty::Bound(..) => { + bug!("unexpected self type for `{goal:?}`") + } - for assumption in - ecx.tcx().item_bounds(alias_ty.def_id).instantiate(ecx.tcx(), alias_ty.args) + ty::Infer(ty::TyVar(_)) => { + // If we hit infer when normalizing the self type of an alias, + // then bail with ambiguity. We should never encounter this on + // the *first* iteration of this recursive function. + if let Ok(result) = + self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) { - match G::consider_alias_bound_candidate(ecx, goal, assumption) { - Ok(result) => { - candidates - .push(Candidate { source: CandidateSource::AliasBound, result }); - } - Err(NoSolution) => {} - } + candidates.push(Candidate { source: CandidateSource::AliasBound, result }); } + return; + } - // If we have a projection, check that its self type is a rigid projection. - // If so, continue searching. - if kind == ty::Projection { - match ecx.try_normalize_ty(goal.param_env, alias_ty.self_ty()) { - Some(next_self_ty) => self_ty = next_self_ty, - None => { - if let Ok(result) = ecx - .evaluate_added_goals_and_make_canonical_response( - Certainty::OVERFLOW, - ) - { - candidates.push(Candidate { - source: CandidateSource::AliasBound, - result, - }); - } - break; - } - } - } else { - break; + ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) => (kind, alias_ty), + ty::Alias(ty::Inherent | ty::Weak, _) => { + unreachable!("Weak and Inherent aliases should have been normalized away already") + } + }; + + for assumption in + self.tcx().item_bounds(alias_ty.def_id).instantiate(self.tcx(), alias_ty.args) + { + match G::consider_alias_bound_candidate(self, goal, assumption) { + Ok(result) => { + candidates.push(Candidate { source: CandidateSource::AliasBound, result }); } + Err(NoSolution) => {} } - }); + } + + if kind != ty::Projection { + return; + } + + match self.try_normalize_ty(goal.param_env, alias_ty.self_ty()) { + // Recurse on the self type of the projection. + Some(next_self_ty) => { + self.assemble_alias_bound_candidates_recur(next_self_ty, goal, candidates); + } + // Bail if we overflow when normalizing, adding an ambiguous candidate. + None => { + if let Ok(result) = + self.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW) + { + candidates.push(Candidate { source: CandidateSource::AliasBound, result }); + } + } + } } /// Check that we are allowed to use an alias bound originating from the self diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 8f47e45df0c6c..8cfbd7d3ce6af 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1645,11 +1645,9 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>( ControlFlow::Continue(()) }, - || { - // `ProjectionCandidateSet` is borrowed in the above closure, - // so just mark ambiguous outside of the closure. - ambiguous = true; - }, + // `ProjectionCandidateSet` is borrowed in the above closure, + // so just mark ambiguous outside of the closure. + || ambiguous = true, ); if ambiguous { diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 248d75aaec713..27dbe0351da12 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -201,10 +201,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ControlFlow::Continue(()) }, - || { - // On ambiguity. - candidates.ambiguous = true; - }, + // On ambiguity. + || candidates.ambiguous = true, ); }); }