about summary refs log tree commit diff
diff options
context:
space:
mode:
authorStuart Cook <Zalathar@users.noreply.github.com>2024-12-24 14:05:21 +1100
committerGitHub <noreply@github.com>2024-12-24 14:05:21 +1100
commitc2f44cd32c08323849ee459c504b0430cfcb02f9 (patch)
treeb8312bfbd6b0b23549f4cedc02b3efe65b7d8994
parent65fe42a5f46a17ac63b21684b7ec8327f1a4c86b (diff)
parent535bc781f81d26883783b726770da94e4918c711 (diff)
downloadrust-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
-rw-r--r--compiler/rustc_trait_selection/src/traits/effects.rs165
-rw-r--r--tests/ui/traits/const-traits/assoc-type-const-bound-usage-0.rs3
-rw-r--r--tests/ui/traits/const-traits/assoc-type-const-bound-usage-1.rs3
-rw-r--r--tests/ui/traits/const-traits/assoc-type-const-bound-usage-1.stderr35
-rw-r--r--tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.current.stderr15
-rw-r--r--tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.next.stderr (renamed from tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.stderr)4
-rw-r--r--tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.rs9
-rw-r--r--tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.current.stderr (renamed from tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.stderr)4
-rw-r--r--tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.next.stderr15
-rw-r--r--tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.rs3
-rw-r--r--tests/ui/traits/const-traits/assoc-type.current.stderr (renamed from tests/ui/traits/const-traits/assoc-type.stderr)4
-rw-r--r--tests/ui/traits/const-traits/assoc-type.next.stderr15
-rw-r--r--tests/ui/traits/const-traits/assoc-type.rs3
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)]