about summary refs log tree commit diff
diff options
context:
space:
mode:
author许杰友 Jieyou Xu (Joe) <39484203+jieyouxu@users.noreply.github.com>2025-08-19 19:45:40 +0800
committerGitHub <noreply@github.com>2025-08-19 19:45:40 +0800
commit4090d98b6729714d58de5d73588a103fffc8ad4e (patch)
treee5ac4f9ca3170bb265588326eaea5a72bd9b167b
parente39295235c0a0fa1cea9d554121f47d9ee1a9163 (diff)
parentc7cd1b3b9da1ffce791ec33dbcad82559dbc4447 (diff)
downloadrust-4090d98b6729714d58de5d73588a103fffc8ad4e.tar.gz
rust-4090d98b6729714d58de5d73588a103fffc8ad4e.zip
Rollup merge of #145537 - zachs18:metasized-negative-bound-fix, r=davidtwco
Do not consider a `T: !Sized` candidate to satisfy a `T: !MetaSized` obligation.

This example should fail to compile (and does under this PR, with the old and new solvers), but currently compiles successfully ([playground](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2024&gist=6e0e5d0ae0cdf0571dea97938fb4a86d)), because (IIUC) the old solver's `lazily_elaborate_sizedness_candidate`/callers and the new solver's `TraitPredicate::fast_reject_assumption`/`match_assumption` consider a `T: _ Sized` candidate to satisfy a `T: _ MetaSized` obligation, for either polarity `_`, when that should only hold for positive polarity.

```rs
#![feature(negative_bounds)]
#![feature(sized_hierarchy)]

use std::marker::MetaSized;

fn foo<T: !MetaSized>() {}

fn bar<T: !Sized + MetaSized>() {
    foo::<T>();
    //~^ ERROR the trait bound `T: !MetaSized` is not satisfied // error under this PR
}
```

Only observable with the internal-only `feature(negative_bounds)`, so might just be "wontfix".

This example is added as a test in this PR (as well as testing that `foo<()>` and `foo<str>` are disallowed for `fn foo<T: !MetaSized`).

cc `@davidtwco` for `feature(sized_hierarchy)`

Maybe similar to 91c53c9 from <https://github.com/rust-lang/rust/pull/143307>
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/trait_goals.rs17
-rw-r--r--compiler/rustc_trait_selection/src/traits/util.rs8
-rw-r--r--tests/ui/traits/negative-bounds/negative-metasized.current.stderr39
-rw-r--r--tests/ui/traits/negative-bounds/negative-metasized.next.stderr39
-rw-r--r--tests/ui/traits/negative-bounds/negative-metasized.rs21
5 files changed, 117 insertions, 7 deletions
diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
index 04ede365a21..891ecab041a 100644
--- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
@@ -6,8 +6,8 @@ use rustc_type_ir::inherent::*;
 use rustc_type_ir::lang_items::TraitSolverLangItem;
 use rustc_type_ir::solve::{CanonicalResponse, SizedTraitKind};
 use rustc_type_ir::{
-    self as ty, Interner, Movability, TraitPredicate, TraitRef, TypeVisitableExt as _, TypingMode,
-    Upcast as _, elaborate,
+    self as ty, Interner, Movability, PredicatePolarity, TraitPredicate, TraitRef,
+    TypeVisitableExt as _, TypingMode, Upcast as _, elaborate,
 };
 use tracing::{debug, instrument, trace};
 
@@ -133,19 +133,26 @@ where
             cx: I,
             clause_def_id: I::DefId,
             goal_def_id: I::DefId,
+            polarity: PredicatePolarity,
         ) -> bool {
             clause_def_id == goal_def_id
             // PERF(sized-hierarchy): Sizedness supertraits aren't elaborated to improve perf, so
             // check for a `MetaSized` supertrait being matched against a `Sized` assumption.
             //
             // `PointeeSized` bounds are syntactic sugar for a lack of bounds so don't need this.
-                || (cx.is_lang_item(clause_def_id, TraitSolverLangItem::Sized)
+                || (polarity == PredicatePolarity::Positive
+                    && cx.is_lang_item(clause_def_id, TraitSolverLangItem::Sized)
                     && cx.is_lang_item(goal_def_id, TraitSolverLangItem::MetaSized))
         }
 
         if let Some(trait_clause) = assumption.as_trait_clause()
             && trait_clause.polarity() == goal.predicate.polarity
-            && trait_def_id_matches(ecx.cx(), trait_clause.def_id(), goal.predicate.def_id())
+            && trait_def_id_matches(
+                ecx.cx(),
+                trait_clause.def_id(),
+                goal.predicate.def_id(),
+                goal.predicate.polarity,
+            )
             && DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify(
                 goal.predicate.trait_ref.args,
                 trait_clause.skip_binder().trait_ref.args,
@@ -168,6 +175,8 @@ where
         // PERF(sized-hierarchy): Sizedness supertraits aren't elaborated to improve perf, so
         // check for a `Sized` subtrait when looking for `MetaSized`. `PointeeSized` bounds
         // are syntactic sugar for a lack of bounds so don't need this.
+        // We don't need to check polarity, `fast_reject_assumption` already rejected non-`Positive`
+        // polarity `Sized` assumptions as matching non-`Positive` `MetaSized` goals.
         if ecx.cx().is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::MetaSized)
             && ecx.cx().is_lang_item(trait_clause.def_id(), TraitSolverLangItem::Sized)
         {
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index 83c0969762f..335942d5bcc 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -9,8 +9,8 @@ pub use rustc_infer::traits::util::*;
 use rustc_middle::bug;
 use rustc_middle::ty::fast_reject::DeepRejectCtxt;
 use rustc_middle::ty::{
-    self, PolyTraitPredicate, SizedTraitKind, TraitPredicate, TraitRef, Ty, TyCtxt, TypeFoldable,
-    TypeFolder, TypeSuperFoldable, TypeVisitableExt,
+    self, PolyTraitPredicate, PredicatePolarity, SizedTraitKind, TraitPredicate, TraitRef, Ty,
+    TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
 };
 pub use rustc_next_trait_solver::placeholder::BoundVarReplacer;
 use rustc_span::Span;
@@ -427,7 +427,9 @@ pub(crate) fn lazily_elaborate_sizedness_candidate<'tcx>(
         return candidate;
     }
 
-    if obligation.predicate.polarity() != candidate.polarity() {
+    if obligation.predicate.polarity() != PredicatePolarity::Positive
+        || candidate.polarity() != PredicatePolarity::Positive
+    {
         return candidate;
     }
 
diff --git a/tests/ui/traits/negative-bounds/negative-metasized.current.stderr b/tests/ui/traits/negative-bounds/negative-metasized.current.stderr
new file mode 100644
index 00000000000..4ff51651336
--- /dev/null
+++ b/tests/ui/traits/negative-bounds/negative-metasized.current.stderr
@@ -0,0 +1,39 @@
+error[E0277]: the trait bound `T: !MetaSized` is not satisfied
+  --> $DIR/negative-metasized.rs:12:11
+   |
+LL |     foo::<T>();
+   |           ^ the trait bound `T: !MetaSized` is not satisfied
+   |
+note: required by a bound in `foo`
+  --> $DIR/negative-metasized.rs:9:11
+   |
+LL | fn foo<T: !MetaSized>() {}
+   |           ^^^^^^^^^^ required by this bound in `foo`
+
+error[E0277]: the trait bound `(): !MetaSized` is not satisfied
+  --> $DIR/negative-metasized.rs:17:11
+   |
+LL |     foo::<()>();
+   |           ^^ the trait bound `(): !MetaSized` is not satisfied
+   |
+note: required by a bound in `foo`
+  --> $DIR/negative-metasized.rs:9:11
+   |
+LL | fn foo<T: !MetaSized>() {}
+   |           ^^^^^^^^^^ required by this bound in `foo`
+
+error[E0277]: the trait bound `str: !MetaSized` is not satisfied
+  --> $DIR/negative-metasized.rs:19:11
+   |
+LL |     foo::<str>();
+   |           ^^^ the trait bound `str: !MetaSized` is not satisfied
+   |
+note: required by a bound in `foo`
+  --> $DIR/negative-metasized.rs:9:11
+   |
+LL | fn foo<T: !MetaSized>() {}
+   |           ^^^^^^^^^^ required by this bound in `foo`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/negative-bounds/negative-metasized.next.stderr b/tests/ui/traits/negative-bounds/negative-metasized.next.stderr
new file mode 100644
index 00000000000..4ff51651336
--- /dev/null
+++ b/tests/ui/traits/negative-bounds/negative-metasized.next.stderr
@@ -0,0 +1,39 @@
+error[E0277]: the trait bound `T: !MetaSized` is not satisfied
+  --> $DIR/negative-metasized.rs:12:11
+   |
+LL |     foo::<T>();
+   |           ^ the trait bound `T: !MetaSized` is not satisfied
+   |
+note: required by a bound in `foo`
+  --> $DIR/negative-metasized.rs:9:11
+   |
+LL | fn foo<T: !MetaSized>() {}
+   |           ^^^^^^^^^^ required by this bound in `foo`
+
+error[E0277]: the trait bound `(): !MetaSized` is not satisfied
+  --> $DIR/negative-metasized.rs:17:11
+   |
+LL |     foo::<()>();
+   |           ^^ the trait bound `(): !MetaSized` is not satisfied
+   |
+note: required by a bound in `foo`
+  --> $DIR/negative-metasized.rs:9:11
+   |
+LL | fn foo<T: !MetaSized>() {}
+   |           ^^^^^^^^^^ required by this bound in `foo`
+
+error[E0277]: the trait bound `str: !MetaSized` is not satisfied
+  --> $DIR/negative-metasized.rs:19:11
+   |
+LL |     foo::<str>();
+   |           ^^^ the trait bound `str: !MetaSized` is not satisfied
+   |
+note: required by a bound in `foo`
+  --> $DIR/negative-metasized.rs:9:11
+   |
+LL | fn foo<T: !MetaSized>() {}
+   |           ^^^^^^^^^^ required by this bound in `foo`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/negative-bounds/negative-metasized.rs b/tests/ui/traits/negative-bounds/negative-metasized.rs
new file mode 100644
index 00000000000..479037be852
--- /dev/null
+++ b/tests/ui/traits/negative-bounds/negative-metasized.rs
@@ -0,0 +1,21 @@
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+#![feature(negative_bounds)]
+#![feature(sized_hierarchy)]
+
+use std::marker::MetaSized;
+
+fn foo<T: !MetaSized>() {}
+
+fn bar<T: !Sized + MetaSized>() {
+    foo::<T>();
+    //~^ ERROR the trait bound `T: !MetaSized` is not satisfied
+}
+
+fn main() {
+    foo::<()>();
+    //~^ ERROR the trait bound `(): !MetaSized` is not satisfied
+    foo::<str>();
+    //~^ ERROR the trait bound `str: !MetaSized` is not satisfied
+}