From a01d3b13eae1a42ed39f02c5bfed58ff7818e1c7 Mon Sep 17 00:00:00 2001 From: Michael Goulet <michael@errs.io> Date: Thu, 20 Apr 2023 21:02:30 +0000 Subject: [PATCH 1/4] Print ty placeholders pretty --- compiler/rustc_middle/src/ty/print/pretty.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index af76cf7cc4e0d..7c90a33609dae 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -738,7 +738,9 @@ pub trait PrettyPrinter<'tcx>: } } ty::Placeholder(placeholder) => match placeholder.bound.kind { - ty::BoundTyKind::Anon => p!(write("Placeholder({:?})", placeholder)), + ty::BoundTyKind::Anon => { + self.pretty_print_placeholder_var(placeholder.universe, placeholder.bound.var)? + } ty::BoundTyKind::Param(_, name) => p!(write("{}", name)), }, ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { @@ -1172,6 +1174,18 @@ pub trait PrettyPrinter<'tcx>: } } + fn pretty_print_placeholder_var( + &mut self, + ui: ty::UniverseIndex, + var: ty::BoundVar, + ) -> Result<(), Self::Error> { + if ui == ty::UniverseIndex::ROOT { + write!(self, "!{}", var.index()) + } else { + write!(self, "!{}_{}", ui.index(), var.index()) + } + } + fn ty_infer_name(&self, _: ty::TyVid) -> Option<Symbol> { None } From 2fadce5390b356f28f689b889fbf01fbd562b32f Mon Sep 17 00:00:00 2001 From: Michael Goulet <michael@errs.io> Date: Thu, 20 Apr 2023 21:36:51 +0000 Subject: [PATCH 2/4] Only consider alias bound candidates for types that come 'from' the param-env --- .../src/solve/assembly/mod.rs | 65 ++++++++++++++++++- .../src/solve/project_goals.rs | 24 +++++++ .../src/solve/trait_goals.rs | 24 +++++++ .../traits/new-solver/alias-bound-unsound.rs | 27 ++++++++ .../new-solver/alias-bound-unsound.stderr | 24 +++++++ 5 files changed, 162 insertions(+), 2 deletions(-) create mode 100644 tests/ui/traits/new-solver/alias-bound-unsound.rs create mode 100644 tests/ui/traits/new-solver/alias-bound-unsound.stderr diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index bacb0e32efc1a..ac642be4e0ad8 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -8,6 +8,7 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_hir::def_id::DefId; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::util::elaborate; +use rustc_infer::traits::Reveal; use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, MaybeCause, QueryResult}; use rustc_middle::ty::fast_reject::TreatProjections; use rustc_middle::ty::TypeFoldable; @@ -87,7 +88,9 @@ pub(super) enum CandidateSource { } /// Methods used to assemble candidates for either trait or projection goals. -pub(super) trait GoalKind<'tcx>: TypeFoldable<TyCtxt<'tcx>> + Copy + Eq { +pub(super) trait GoalKind<'tcx>: + TypeFoldable<TyCtxt<'tcx>> + Copy + Eq + std::fmt::Display +{ fn self_ty(self) -> Ty<'tcx>; fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx>; @@ -106,6 +109,12 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<TyCtxt<'tcx>> + Copy + Eq { requirements: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>, ) -> QueryResult<'tcx>; + fn consider_alias_bound_clause( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + assumption: ty::Predicate<'tcx>, + ) -> QueryResult<'tcx>; + // Consider a clause specifically for a `dyn Trait` self type. This requires // additionally checking all of the supertraits and object bounds to hold, // since they're not implied by the well-formedness of the object type. @@ -463,7 +472,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { for assumption in self.tcx().item_bounds(alias_ty.def_id).subst(self.tcx(), alias_ty.substs) { - match G::consider_implied_clause(self, goal, assumption, []) { + match G::consider_alias_bound_clause(self, goal, assumption) { Ok(result) => { candidates.push(Candidate { source: CandidateSource::AliasBound, result }) } @@ -602,4 +611,56 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } self.flounder(&responses) } + + #[instrument(level = "debug", skip(self), ret)] + pub(super) fn evaluate_alias_bound_self_is_well_formed<G: GoalKind<'tcx>>( + &mut self, + goal: Goal<'tcx, G>, + ) -> QueryResult<'tcx> { + match *goal.predicate.self_ty().kind() { + ty::Alias(ty::Projection, projection_ty) => { + let mut param_env_candidates = vec![]; + let projection_trait_ref = projection_ty.trait_ref(self.tcx()); + + if projection_trait_ref.self_ty().is_ty_var() { + return self + .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); + } + + let trait_goal = goal.with( + self.tcx(), + ty::TraitPredicate { + trait_ref: projection_trait_ref, + constness: ty::BoundConstness::NotConst, + polarity: ty::ImplPolarity::Positive, + }, + ); + self.assemble_param_env_candidates(trait_goal, &mut param_env_candidates); + + // FIXME: Bad bad bad bad bad !!!!! + let lang_items = self.tcx().lang_items(); + let trait_def_id = projection_trait_ref.def_id; + let funky_built_in_res = if lang_items.pointee_trait() == Some(trait_def_id) { + G::consider_builtin_pointee_candidate(self, goal) + } else if lang_items.discriminant_kind_trait() == Some(trait_def_id) { + G::consider_builtin_discriminant_kind_candidate(self, goal) + } else { + Err(NoSolution) + }; + if let Ok(result) = funky_built_in_res { + param_env_candidates + .push(Candidate { source: CandidateSource::BuiltinImpl, result }); + } + + self.merge_candidates(param_env_candidates) + } + ty::Alias(ty::Opaque, _opaque_ty) => match goal.param_env.reveal() { + Reveal::UserFacing => { + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } + Reveal::All => return Err(NoSolution), + }, + _ => bug!("we shouldn't have gotten here!"), + } + } } diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 14cb43b89c3aa..5f5b702ad4a81 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -82,6 +82,30 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { } } + fn consider_alias_bound_clause( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + assumption: ty::Predicate<'tcx>, + ) -> QueryResult<'tcx> { + if let Some(poly_projection_pred) = assumption.to_opt_poly_projection_pred() + && poly_projection_pred.projection_def_id() == goal.predicate.def_id() + { + ecx.probe(|ecx| { + let assumption_projection_pred = + ecx.instantiate_binder_with_infer(poly_projection_pred); + ecx.eq( + goal.param_env, + goal.predicate.projection_ty, + assumption_projection_pred.projection_ty, + )?; + ecx.eq(goal.param_env, goal.predicate.term, assumption_projection_pred.term)?; + ecx.evaluate_alias_bound_self_is_well_formed(goal) + }) + } else { + Err(NoSolution) + } + } + fn consider_object_bound_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 1abcc80d01a32..a911a365aa0a1 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -104,6 +104,30 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } } + fn consider_alias_bound_clause( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + assumption: ty::Predicate<'tcx>, + ) -> QueryResult<'tcx> { + if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred() + && poly_trait_pred.def_id() == goal.predicate.def_id() + { + // FIXME: Constness and polarity + ecx.probe(|ecx| { + let assumption_trait_pred = + ecx.instantiate_binder_with_infer(poly_trait_pred); + ecx.eq( + goal.param_env, + goal.predicate.trait_ref, + assumption_trait_pred.trait_ref, + )?; + ecx.evaluate_alias_bound_self_is_well_formed(goal) + }) + } else { + Err(NoSolution) + } + } + fn consider_object_bound_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, diff --git a/tests/ui/traits/new-solver/alias-bound-unsound.rs b/tests/ui/traits/new-solver/alias-bound-unsound.rs new file mode 100644 index 0000000000000..00294c708f1fa --- /dev/null +++ b/tests/ui/traits/new-solver/alias-bound-unsound.rs @@ -0,0 +1,27 @@ +// compile-flags: -Ztrait-solver=next + +// Makes sure that alias bounds are not unsound! + +#![feature(trivial_bounds)] + +trait Foo { + type Item: Copy + where + <Self as Foo>::Item: Copy; + + fn copy_me(x: &Self::Item) -> Self::Item { + *x + } +} + +impl Foo for () { + type Item = String where String: Copy; +} + +fn main() { + let x = String::from("hello, world"); + drop(<() as Foo>::copy_me(&x)); + //~^ ERROR `<() as Foo>::Item: Copy` is not satisfied + //~| ERROR `<() as Foo>::Item` is not well-formed + println!("{x}"); +} diff --git a/tests/ui/traits/new-solver/alias-bound-unsound.stderr b/tests/ui/traits/new-solver/alias-bound-unsound.stderr new file mode 100644 index 0000000000000..9a43d2a6639ce --- /dev/null +++ b/tests/ui/traits/new-solver/alias-bound-unsound.stderr @@ -0,0 +1,24 @@ +error[E0277]: the trait bound `<() as Foo>::Item: Copy` is not satisfied + --> $DIR/alias-bound-unsound.rs:23:10 + | +LL | drop(<() as Foo>::copy_me(&x)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `<() as Foo>::Item` + | +note: required by a bound in `Foo::Item` + --> $DIR/alias-bound-unsound.rs:10:30 + | +LL | type Item: Copy + | ---- required by a bound in this associated type +LL | where +LL | <Self as Foo>::Item: Copy; + | ^^^^ required by this bound in `Foo::Item` + +error: the type `<() as Foo>::Item` is not well-formed + --> $DIR/alias-bound-unsound.rs:23:10 + | +LL | drop(<() as Foo>::copy_me(&x)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. From b39846f85c3c198428d5bc09b6053dea2a79f59f Mon Sep 17 00:00:00 2001 From: Michael Goulet <michael@errs.io> Date: Thu, 20 Apr 2023 22:14:43 +0000 Subject: [PATCH 3/4] Make object bound confirmation simpler in new solver --- compiler/rustc_middle/src/ty/mod.rs | 3 + .../src/solve/assembly/mod.rs | 9 +- .../src/solve/assembly/structural_traits.rs | 109 +----------------- .../src/solve/project_goals.rs | 10 +- .../src/solve/search_graph/mod.rs | 1 + .../src/solve/trait_goals.rs | 9 +- .../new-solver/higher-ranked-dyn-bounds.rs | 5 +- .../higher-ranked-dyn-bounds.stderr | 18 +++ .../new-solver/more-object-bound.stderr | 4 - 9 files changed, 41 insertions(+), 127 deletions(-) create mode 100644 tests/ui/traits/new-solver/higher-ranked-dyn-bounds.stderr diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 1061c32079305..e3c82cac36cef 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -522,6 +522,9 @@ impl<'tcx> Predicate<'tcx> { #[instrument(level = "debug", skip(tcx), ret)] pub fn is_coinductive(self, tcx: TyCtxt<'tcx>) -> bool { match self.kind().skip_binder() { + // Always coinductive in the new solver. + _ if tcx.trait_solver_next() => true, + ty::PredicateKind::Clause(ty::Clause::Trait(data)) => { tcx.trait_is_coinductive(data.def_id()) } diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index ac642be4e0ad8..e768189235845 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -115,10 +115,11 @@ pub(super) trait GoalKind<'tcx>: assumption: ty::Predicate<'tcx>, ) -> QueryResult<'tcx>; - // Consider a clause specifically for a `dyn Trait` self type. This requires + // FIXME: better wording here. + // Consider a clause that is spooky and we cannot trust. This requires // additionally checking all of the supertraits and object bounds to hold, - // since they're not implied by the well-formedness of the object type. - fn consider_object_bound_candidate( + // since they're not implied by the well-formedness of anything necessarily. + fn consider_non_wf_assumption( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, assumption: ty::Predicate<'tcx>, @@ -538,7 +539,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { continue; } - match G::consider_object_bound_candidate(self, goal, assumption) { + match G::consider_non_wf_assumption(self, goal, assumption) { Ok(result) => { candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result }) } diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index 1a566e87dc8e3..f7831dcf68baf 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -1,9 +1,6 @@ -use rustc_data_structures::fx::FxHashMap; -use rustc_hir::{def_id::DefId, Movability, Mutability}; +use rustc_hir::{Movability, Mutability}; use rustc_infer::traits::query::NoSolution; -use rustc_middle::ty::{ - self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, -}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; use crate::solve::EvalCtxt; @@ -301,51 +298,11 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>( } } -/// Assemble a list of predicates that would be present on a theoretical -/// user impl for an object type. These predicates must be checked any time -/// we assemble a built-in object candidate for an object type, since they -/// are not implied by the well-formedness of the type. -/// -/// For example, given the following traits: -/// -/// ```rust,ignore (theoretical code) -/// trait Foo: Baz { -/// type Bar: Copy; -/// } -/// -/// trait Baz {} -/// ``` -/// -/// For the dyn type `dyn Foo<Item = Ty>`, we can imagine there being a -/// pair of theoretical impls: -/// -/// ```rust,ignore (theoretical code) -/// impl Foo for dyn Foo<Item = Ty> -/// where -/// Self: Baz, -/// <Self as Foo>::Bar: Copy, -/// { -/// type Bar = Ty; -/// } -/// -/// impl Baz for dyn Foo<Item = Ty> {} -/// ``` -/// -/// However, in order to make such impls well-formed, we need to do an -/// additional step of eagerly folding the associated types in the where -/// clauses of the impl. In this example, that means replacing -/// `<Self as Foo>::Bar` with `Ty` in the first impl. -/// -// FIXME: This is only necessary as `<Self as Trait>::Assoc: ItemBound` -// bounds in impls are trivially proven using the item bound candidates. -// This is unsound in general and once that is fixed, we don't need to -// normalize eagerly here. See https://github.com/lcnr/solver-woes/issues/9 -// for more details. -pub(in crate::solve) fn predicates_for_object_candidate<'tcx>( +/// Assemble a list of predicates that need to hold for a trait implementation +/// to be WF. +pub(in crate::solve) fn requirements_for_trait_wf<'tcx>( ecx: &EvalCtxt<'_, 'tcx>, - param_env: ty::ParamEnv<'tcx>, trait_ref: ty::TraitRef<'tcx>, - object_bound: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, ) -> Vec<ty::Predicate<'tcx>> { let tcx = ecx.tcx(); let mut requirements = vec![]; @@ -359,59 +316,5 @@ pub(in crate::solve) fn predicates_for_object_candidate<'tcx>( requirements.extend(tcx.item_bounds(item.def_id).subst(tcx, trait_ref.substs)); } } - - let mut replace_projection_with = FxHashMap::default(); - for bound in object_bound { - if let ty::ExistentialPredicate::Projection(proj) = bound.skip_binder() { - let proj = proj.with_self_ty(tcx, trait_ref.self_ty()); - let old_ty = replace_projection_with.insert(proj.def_id(), bound.rebind(proj)); - assert_eq!( - old_ty, - None, - "{} has two substitutions: {} and {}", - proj.projection_ty, - proj.term, - old_ty.unwrap() - ); - } - } - - requirements.fold_with(&mut ReplaceProjectionWith { - ecx, - param_env, - mapping: replace_projection_with, - }) -} - -struct ReplaceProjectionWith<'a, 'tcx> { - ecx: &'a EvalCtxt<'a, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - mapping: FxHashMap<DefId, ty::PolyProjectionPredicate<'tcx>>, -} - -impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceProjectionWith<'_, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { - self.ecx.tcx() - } - - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - if let ty::Alias(ty::Projection, alias_ty) = *ty.kind() - && let Some(replacement) = self.mapping.get(&alias_ty.def_id) - { - // We may have a case where our object type's projection bound is higher-ranked, - // but the where clauses we instantiated are not. We can solve this by instantiating - // the binder at the usage site. - let proj = self.ecx.instantiate_binder_with_infer(*replacement); - // FIXME: Technically this folder could be fallible? - let nested = self - .ecx - .eq_and_get_goals(self.param_env, alias_ty, proj.projection_ty) - .expect("expected to be able to unify goal projection with dyn's projection"); - // FIXME: Technically we could register these too.. - assert!(nested.is_empty(), "did not expect unification to have any nested goals"); - proj.term.ty().unwrap() - } else { - ty.super_fold_with(self) - } - } + requirements } diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 5f5b702ad4a81..7b4e9125748f2 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -106,7 +106,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { } } - fn consider_object_bound_candidate( + fn consider_non_wf_assumption( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, assumption: ty::Predicate<'tcx>, @@ -124,16 +124,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { goal.predicate.projection_ty, assumption_projection_pred.projection_ty, )?; - - let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else { - bug!("expected object type in `consider_object_bound_candidate`"); - }; ecx.add_goals( - structural_traits::predicates_for_object_candidate( + structural_traits::requirements_for_trait_wf( &ecx, - goal.param_env, goal.predicate.projection_ty.trait_ref(tcx), - bounds, ) .into_iter() .map(|pred| goal.with(tcx, pred)), diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs index 050269fa973e9..c47ffb04ebe35 100644 --- a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs @@ -18,6 +18,7 @@ rustc_index::newtype_index! { pub struct StackDepth {} } +#[derive(Debug)] struct StackElem<'tcx> { goal: CanonicalGoal<'tcx>, has_been_used: bool, diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index a911a365aa0a1..c85e43189447f 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -128,7 +128,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } } - fn consider_object_bound_candidate( + fn consider_non_wf_assumption( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, assumption: ty::Predicate<'tcx>, @@ -147,15 +147,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { )?; let tcx = ecx.tcx(); - let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else { - bug!("expected object type in `consider_object_bound_candidate`"); - }; ecx.add_goals( - structural_traits::predicates_for_object_candidate( + structural_traits::requirements_for_trait_wf( &ecx, - goal.param_env, goal.predicate.trait_ref, - bounds, ) .into_iter() .map(|pred| goal.with(tcx, pred)), diff --git a/tests/ui/traits/new-solver/higher-ranked-dyn-bounds.rs b/tests/ui/traits/new-solver/higher-ranked-dyn-bounds.rs index c886aeeda3e46..5d1a1d0bba794 100644 --- a/tests/ui/traits/new-solver/higher-ranked-dyn-bounds.rs +++ b/tests/ui/traits/new-solver/higher-ranked-dyn-bounds.rs @@ -1,5 +1,8 @@ // compile-flags: -Ztrait-solver=next -// check-pass +// known-bug: unknown + +// Remove this when we fix this bug. +#![recursion_limit = "10"] trait Trait<'a> { type Item: for<'b> Trait2<'b>; diff --git a/tests/ui/traits/new-solver/higher-ranked-dyn-bounds.stderr b/tests/ui/traits/new-solver/higher-ranked-dyn-bounds.stderr new file mode 100644 index 0000000000000..d2803ccd6ff80 --- /dev/null +++ b/tests/ui/traits/new-solver/higher-ranked-dyn-bounds.stderr @@ -0,0 +1,18 @@ +error[E0275]: overflow evaluating the requirement `for<'a> dyn for<'a> Trait<'a, for<'a> Item = ()>: Trait<'a>` + --> $DIR/higher-ranked-dyn-bounds.rs:17:17 + | +LL | needs_trait(x); + | ----------- ^ + | | + | required by a bound introduced by this call + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]` attribute to your crate (`higher_ranked_dyn_bounds`) +note: required by a bound in `needs_trait` + --> $DIR/higher-ranked-dyn-bounds.rs:14:28 + | +LL | fn needs_trait(_: Box<impl for<'a> Trait<'a> + ?Sized>) {} + | ^^^^^^^^^^^^^^^^^ required by this bound in `needs_trait` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/new-solver/more-object-bound.stderr b/tests/ui/traits/new-solver/more-object-bound.stderr index 4554b8c7473cb..51a33429f2086 100644 --- a/tests/ui/traits/new-solver/more-object-bound.stderr +++ b/tests/ui/traits/new-solver/more-object-bound.stderr @@ -12,10 +12,6 @@ LL | fn foo<A, B, T: ?Sized>(x: T::A) -> B LL | where LL | T: Trait<B = B>, | ^^^^^^^^^^^^ required by this bound in `foo` -help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement - | -LL | fn transmute<A, B>(x: A) -> B where dyn Trait<A = A, B = B>: Trait { - | ++++++++++++++++++++++++++++++++++++ error: aborting due to previous error From 6da9e7f1c53485c3803f40be644a881d0aea2cdc Mon Sep 17 00:00:00 2001 From: Michael Goulet <michael@errs.io> Date: Thu, 20 Apr 2023 23:49:36 +0000 Subject: [PATCH 4/4] Nested alias bounds --- .../src/solve/assembly/mod.rs | 5 +++++ .../traits/new-solver/nested-alias-bound.rs | 20 +++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 tests/ui/traits/new-solver/nested-alias-bound.rs diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index e768189235845..8bcaf37bfd7e6 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -636,7 +636,12 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { polarity: ty::ImplPolarity::Positive, }, ); + + // FIXME: We probably need some sort of recursion depth incr here. + // Can't come up with an example yet, though, and the worst case + // we can have is a compiler stack overflow... self.assemble_param_env_candidates(trait_goal, &mut param_env_candidates); + self.assemble_alias_bound_candidates(trait_goal, &mut param_env_candidates); // FIXME: Bad bad bad bad bad !!!!! let lang_items = self.tcx().lang_items(); diff --git a/tests/ui/traits/new-solver/nested-alias-bound.rs b/tests/ui/traits/new-solver/nested-alias-bound.rs new file mode 100644 index 0000000000000..c365902dbe5e8 --- /dev/null +++ b/tests/ui/traits/new-solver/nested-alias-bound.rs @@ -0,0 +1,20 @@ +// compile-flags: -Ztrait-solver=next +// check-pass + +trait A { + type A: B; +} + +trait B { + type B: C; +} + +trait C {} + +fn needs_c<T: C>() {} + +fn test<T: A>() { + needs_c::<<T::A as B>::B>(); +} + +fn main() {}