diff options
| author | Stuart Cook <Zalathar@users.noreply.github.com> | 2024-12-24 14:05:21 +1100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-12-24 14:05:21 +1100 |
| commit | c2f44cd32c08323849ee459c504b0430cfcb02f9 (patch) | |
| tree | b8312bfbd6b0b23549f4cedc02b3efe65b7d8994 | |
| parent | 65fe42a5f46a17ac63b21684b7ec8327f1a4c86b (diff) | |
| parent | 535bc781f81d26883783b726770da94e4918c711 (diff) | |
| download | rust-c2f44cd32c08323849ee459c504b0430cfcb02f9.tar.gz rust-c2f44cd32c08323849ee459c504b0430cfcb02f9.zip | |
Rollup merge of #134638 - compiler-errors:fx-item-bounds, r=lcnr
Fix effect predicates from item bounds in old solver r? lcnr
13 files changed, 201 insertions, 77 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs index b17a489a857..91484ef99db 100644 --- a/compiler/rustc_trait_selection/src/traits/effects.rs +++ b/compiler/rustc_trait_selection/src/traits/effects.rs @@ -1,13 +1,15 @@ use rustc_hir as hir; -use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt}; +use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes}; use rustc_infer::traits::{ImplSource, Obligation, PredicateObligation}; use rustc_middle::span_bug; use rustc_middle::ty::fast_reject::DeepRejectCtxt; use rustc_middle::ty::{self, TypingMode}; +use rustc_type_ir::elaborate::elaborate; use rustc_type_ir::solve::NoSolution; -use thin_vec::ThinVec; +use thin_vec::{ThinVec, thin_vec}; use super::SelectionContext; +use super::normalize::normalize_with_depth_to; pub type HostEffectObligation<'tcx> = Obligation<'tcx, ty::HostEffectPredicate<'tcx>>; @@ -38,6 +40,12 @@ pub fn evaluate_host_effect_obligation<'tcx>( Err(EvaluationFailure::NoSolution) => {} } + match evaluate_host_effect_from_item_bounds(selcx, obligation) { + Ok(result) => return Ok(result), + Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous), + Err(EvaluationFailure::NoSolution) => {} + } + match evaluate_host_effect_from_selection_candiate(selcx, obligation) { Ok(result) => return Ok(result), Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous), @@ -48,24 +56,45 @@ pub fn evaluate_host_effect_obligation<'tcx>( } fn match_candidate<'tcx>( - infcx: &InferCtxt<'tcx>, + selcx: &mut SelectionContext<'_, 'tcx>, obligation: &HostEffectObligation<'tcx>, candidate: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>, + candidate_is_unnormalized: bool, + more_nested: impl FnOnce(&mut SelectionContext<'_, 'tcx>, &mut ThinVec<PredicateObligation<'tcx>>), ) -> Result<ThinVec<PredicateObligation<'tcx>>, NoSolution> { if !candidate.skip_binder().constness.satisfies(obligation.predicate.constness) { return Err(NoSolution); } - let candidate = infcx.instantiate_binder_with_fresh_vars( + let mut candidate = selcx.infcx.instantiate_binder_with_fresh_vars( obligation.cause.span, BoundRegionConversionTime::HigherRankedType, candidate, ); - let mut nested = infcx - .at(&obligation.cause, obligation.param_env) - .eq(DefineOpaqueTypes::Yes, obligation.predicate.trait_ref, candidate.trait_ref)? - .into_obligations(); + let mut nested = thin_vec![]; + + // Unlike param-env bounds, item bounds may not be normalized. + if candidate_is_unnormalized { + candidate = normalize_with_depth_to( + selcx, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth, + candidate, + &mut nested, + ); + } + + nested.extend( + selcx + .infcx + .at(&obligation.cause, obligation.param_env) + .eq(DefineOpaqueTypes::Yes, obligation.predicate.trait_ref, candidate.trait_ref)? + .into_obligations(), + ); + + more_nested(selcx, &mut nested); for nested in &mut nested { nested.set_depth_from_parent(obligation.recursion_depth); @@ -82,36 +111,116 @@ fn evaluate_host_effect_from_bounds<'tcx>( let drcx = DeepRejectCtxt::relate_rigid_rigid(selcx.tcx()); let mut candidate = None; - for predicate in obligation.param_env.caller_bounds() { - let bound_predicate = predicate.kind(); - if let ty::ClauseKind::HostEffect(data) = predicate.kind().skip_binder() { - let data = bound_predicate.rebind(data); - if data.skip_binder().trait_ref.def_id != obligation.predicate.trait_ref.def_id { - continue; + for clause in obligation.param_env.caller_bounds() { + let bound_clause = clause.kind(); + let ty::ClauseKind::HostEffect(data) = bound_clause.skip_binder() else { + continue; + }; + let data = bound_clause.rebind(data); + if data.skip_binder().trait_ref.def_id != obligation.predicate.trait_ref.def_id { + continue; + } + + if !drcx + .args_may_unify(obligation.predicate.trait_ref.args, data.skip_binder().trait_ref.args) + { + continue; + } + + let is_match = + infcx.probe(|_| match_candidate(selcx, obligation, data, false, |_, _| {}).is_ok()); + + if is_match { + if candidate.is_some() { + return Err(EvaluationFailure::Ambiguous); + } else { + candidate = Some(data); } + } + } - if !drcx.args_may_unify( - obligation.predicate.trait_ref.args, - data.skip_binder().trait_ref.args, + if let Some(data) = candidate { + Ok(match_candidate(selcx, obligation, data, false, |_, _| {}) + .expect("candidate matched before, so it should match again")) + } else { + Err(EvaluationFailure::NoSolution) + } +} + +fn evaluate_host_effect_from_item_bounds<'tcx>( + selcx: &mut SelectionContext<'_, 'tcx>, + obligation: &HostEffectObligation<'tcx>, +) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> { + let infcx = selcx.infcx; + let tcx = infcx.tcx; + let drcx = DeepRejectCtxt::relate_rigid_rigid(selcx.tcx()); + let mut candidate = None; + + let mut consider_ty = obligation.predicate.self_ty(); + while let ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) = *consider_ty.kind() { + if tcx.is_conditionally_const(alias_ty.def_id) { + for clause in elaborate( + tcx, + tcx.explicit_implied_const_bounds(alias_ty.def_id) + .iter_instantiated_copied(tcx, alias_ty.args) + .map(|(trait_ref, _)| { + trait_ref.to_host_effect_clause(tcx, obligation.predicate.constness) + }), ) { - continue; - } + let bound_clause = clause.kind(); + let ty::ClauseKind::HostEffect(data) = bound_clause.skip_binder() else { + unreachable!("should not elaborate non-HostEffect from HostEffect") + }; + let data = bound_clause.rebind(data); + if data.skip_binder().trait_ref.def_id != obligation.predicate.trait_ref.def_id { + continue; + } - let is_match = infcx.probe(|_| match_candidate(infcx, obligation, data).is_ok()); + if !drcx.args_may_unify( + obligation.predicate.trait_ref.args, + data.skip_binder().trait_ref.args, + ) { + continue; + } - if is_match { - if candidate.is_some() { - return Err(EvaluationFailure::Ambiguous); - } else { - candidate = Some(data); + let is_match = infcx + .probe(|_| match_candidate(selcx, obligation, data, true, |_, _| {}).is_ok()); + + if is_match { + if candidate.is_some() { + return Err(EvaluationFailure::Ambiguous); + } else { + candidate = Some((data, alias_ty)); + } } } } + + if kind != ty::Projection { + break; + } + + consider_ty = alias_ty.self_ty(); } - if let Some(data) = candidate { - Ok(match_candidate(infcx, obligation, data) - .expect("candidate matched before, so it should match again")) + if let Some((data, alias_ty)) = candidate { + Ok(match_candidate(selcx, obligation, data, true, |selcx, nested| { + // An alias bound only holds if we also check the const conditions + // of the alias, so we need to register those, too. + let const_conditions = normalize_with_depth_to( + selcx, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth, + tcx.const_conditions(alias_ty.def_id).instantiate(tcx, alias_ty.args), + nested, + ); + nested.extend(const_conditions.into_iter().map(|(trait_ref, _)| { + obligation + .with(tcx, trait_ref.to_host_effect_clause(tcx, obligation.predicate.constness)) + })); + }) + .expect("candidate matched before, so it should match again")) } else { Err(EvaluationFailure::NoSolution) } diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-0.rs b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-0.rs index bac7ee023f4..9141d327aee 100644 --- a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-0.rs +++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-0.rs @@ -1,4 +1,5 @@ -//@ compile-flags: -Znext-solver +//@ revisions: current next +//@[next] compile-flags: -Znext-solver //@ check-pass #![feature(const_trait_impl)] diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-1.rs b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-1.rs index a0375cda079..19e86b50d33 100644 --- a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-1.rs +++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-1.rs @@ -1,5 +1,4 @@ -//@ compile-flags: -Znext-solver -//@ known-bug: unknown +//@ check-pass #![feature(const_trait_impl, generic_const_exprs)] #![allow(incomplete_features)] diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-1.stderr b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-1.stderr deleted file mode 100644 index 8d1c85c0c8a..00000000000 --- a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-1.stderr +++ /dev/null @@ -1,35 +0,0 @@ -error: `-Znext-solver=globally` and `generic_const_exprs` are incompatible, using them at the same time is not allowed - --> $DIR/assoc-type-const-bound-usage-1.rs:4:30 - | -LL | #![feature(const_trait_impl, generic_const_exprs)] - | ^^^^^^^^^^^^^^^^^^^ - | - = help: remove one of these features - -error[E0284]: type annotations needed: cannot normalize `unqualified<T>::{constant#0}` - --> $DIR/assoc-type-const-bound-usage-1.rs:15:37 - | -LL | fn unqualified<T: const Trait>() -> Type<{ T::Assoc::func() }> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `unqualified<T>::{constant#0}` - -error[E0284]: type annotations needed: cannot normalize `qualified<T>::{constant#0}` - --> $DIR/assoc-type-const-bound-usage-1.rs:19:35 - | -LL | fn qualified<T: const Trait>() -> Type<{ <T as Trait>::Assoc::func() }> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `qualified<T>::{constant#0}` - -error[E0284]: type annotations needed: cannot normalize `unqualified<T>::{constant#0}` - --> $DIR/assoc-type-const-bound-usage-1.rs:16:5 - | -LL | Type - | ^^^^ cannot normalize `unqualified<T>::{constant#0}` - -error[E0284]: type annotations needed: cannot normalize `qualified<T>::{constant#0}` - --> $DIR/assoc-type-const-bound-usage-1.rs:20:5 - | -LL | Type - | ^^^^ cannot normalize `qualified<T>::{constant#0}` - -error: aborting due to 5 previous errors - -For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.current.stderr b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.current.stderr new file mode 100644 index 00000000000..03da9159bea --- /dev/null +++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.current.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `U: ~const Other` is not satisfied + --> $DIR/assoc-type-const-bound-usage-fail-2.rs:24:5 + | +LL | T::Assoc::<U>::func(); + | ^^^^^^^^^^^^^ + +error[E0277]: the trait bound `U: ~const Other` is not satisfied + --> $DIR/assoc-type-const-bound-usage-fail-2.rs:27:5 + | +LL | <T as Trait>::Assoc::<U>::func(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.stderr b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.next.stderr index c7af0a220ca..ce58b486a16 100644 --- a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.stderr +++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.next.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `<T as Trait>::Assoc<U>: ~const Trait` is not satisfied - --> $DIR/assoc-type-const-bound-usage-fail-2.rs:23:5 + --> $DIR/assoc-type-const-bound-usage-fail-2.rs:24:5 | LL | T::Assoc::<U>::func(); | ^^^^^^^^^^^^^ error[E0277]: the trait bound `<T as Trait>::Assoc<U>: ~const Trait` is not satisfied - --> $DIR/assoc-type-const-bound-usage-fail-2.rs:25:5 + --> $DIR/assoc-type-const-bound-usage-fail-2.rs:27:5 | LL | <T as Trait>::Assoc::<U>::func(); | ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.rs b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.rs index b3a636b0f71..bdd98eaf541 100644 --- a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.rs +++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.rs @@ -1,4 +1,5 @@ -//@ compile-flags: -Znext-solver +//@ revisions: current next +//@[next] compile-flags: -Znext-solver // Check that `~const` item bounds only hold if the where clauses on the // associated type are also const. @@ -21,9 +22,11 @@ trait Other {} const fn fails<T: ~const Trait, U: Other>() { T::Assoc::<U>::func(); - //~^ ERROR the trait bound `<T as Trait>::Assoc<U>: ~const Trait` is not satisfied + //[current]~^ ERROR the trait bound `U: ~const Other` is not satisfied + //[next]~^^ ERROR the trait bound `<T as Trait>::Assoc<U>: ~const Trait` is not satisfied <T as Trait>::Assoc::<U>::func(); - //~^ ERROR the trait bound `<T as Trait>::Assoc<U>: ~const Trait` is not satisfied + //[current]~^ ERROR the trait bound `U: ~const Other` is not satisfied + //[next]~^^ ERROR the trait bound `<T as Trait>::Assoc<U>: ~const Trait` is not satisfied } const fn works<T: ~const Trait, U: ~const Other>() { diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.stderr b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.current.stderr index 99fc924ad06..9c29a894749 100644 --- a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.stderr +++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.current.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `T: ~const Trait` is not satisfied - --> $DIR/assoc-type-const-bound-usage-fail.rs:16:5 + --> $DIR/assoc-type-const-bound-usage-fail.rs:17:5 | LL | T::Assoc::func(); | ^^^^^^^^ error[E0277]: the trait bound `T: ~const Trait` is not satisfied - --> $DIR/assoc-type-const-bound-usage-fail.rs:18:5 + --> $DIR/assoc-type-const-bound-usage-fail.rs:19:5 | LL | <T as Trait>::Assoc::func(); | ^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.next.stderr b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.next.stderr new file mode 100644 index 00000000000..9c29a894749 --- /dev/null +++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.next.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `T: ~const Trait` is not satisfied + --> $DIR/assoc-type-const-bound-usage-fail.rs:17:5 + | +LL | T::Assoc::func(); + | ^^^^^^^^ + +error[E0277]: the trait bound `T: ~const Trait` is not satisfied + --> $DIR/assoc-type-const-bound-usage-fail.rs:19:5 + | +LL | <T as Trait>::Assoc::func(); + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.rs b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.rs index ce01086f0dc..3761fea1968 100644 --- a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.rs +++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.rs @@ -1,4 +1,5 @@ -//@ compile-flags: -Znext-solver +//@ revisions: current next +//@[next] compile-flags: -Znext-solver // Check that `~const` item bounds only hold if the parent trait is `~const`. // i.e. check that we validate the const conditions for the associated type diff --git a/tests/ui/traits/const-traits/assoc-type.stderr b/tests/ui/traits/const-traits/assoc-type.current.stderr index b318675b612..4bf9acfbd65 100644 --- a/tests/ui/traits/const-traits/assoc-type.stderr +++ b/tests/ui/traits/const-traits/assoc-type.current.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `NonConstAdd: ~const Add` is not satisfied - --> $DIR/assoc-type.rs:36:16 + --> $DIR/assoc-type.rs:37:16 | LL | type Bar = NonConstAdd; | ^^^^^^^^^^^ | note: required by a bound in `Foo::Bar` - --> $DIR/assoc-type.rs:32:15 + --> $DIR/assoc-type.rs:33:15 | LL | type Bar: ~const Add; | ^^^^^^ required by this bound in `Foo::Bar` diff --git a/tests/ui/traits/const-traits/assoc-type.next.stderr b/tests/ui/traits/const-traits/assoc-type.next.stderr new file mode 100644 index 00000000000..4bf9acfbd65 --- /dev/null +++ b/tests/ui/traits/const-traits/assoc-type.next.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `NonConstAdd: ~const Add` is not satisfied + --> $DIR/assoc-type.rs:37:16 + | +LL | type Bar = NonConstAdd; + | ^^^^^^^^^^^ + | +note: required by a bound in `Foo::Bar` + --> $DIR/assoc-type.rs:33:15 + | +LL | type Bar: ~const Add; + | ^^^^^^ required by this bound in `Foo::Bar` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/assoc-type.rs b/tests/ui/traits/const-traits/assoc-type.rs index 32c91fa51f1..a169b61994c 100644 --- a/tests/ui/traits/const-traits/assoc-type.rs +++ b/tests/ui/traits/const-traits/assoc-type.rs @@ -1,4 +1,5 @@ -//@ compile-flags: -Znext-solver +//@ revisions: current next +//@[next] compile-flags: -Znext-solver #![feature(const_trait_impl)] |
