Skip to content

Commit 37f147e

Browse files
committed
change false trivial bounds detection, see PR descr
1 parent e3e432d commit 37f147e

22 files changed

+232
-38
lines changed

compiler/rustc_hir_analysis/src/check/wfcheck.rs

+25-12
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,8 @@ use rustc_middle::query::Providers;
1919
use rustc_middle::traits::solve::NoSolution;
2020
use rustc_middle::ty::trait_def::TraitSpecializationKind;
2121
use rustc_middle::ty::{
22-
self, AdtKind, GenericArgKind, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeFlags,
23-
TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode,
24-
Upcast,
22+
self, AdtKind, GenericArgKind, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeFoldable,
23+
TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, Upcast,
2524
};
2625
use rustc_middle::{bug, span_bug};
2726
use rustc_session::parse::feature_err;
@@ -111,16 +110,17 @@ where
111110

112111
let mut wfcx = WfCheckingCtxt { ocx, span, body_def_id, param_env };
113112

114-
if !tcx.features().trivial_bounds() {
115-
wfcx.check_false_global_bounds()
116-
}
117113
f(&mut wfcx)?;
118114

119115
let errors = wfcx.select_all_or_error();
120116
if !errors.is_empty() {
121117
return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
122118
}
123119

120+
if !tcx.features().trivial_bounds() {
121+
wfcx.check_false_global_bounds()?;
122+
}
123+
124124
let assumed_wf_types = wfcx.ocx.assumed_wf_types_and_report_errors(param_env, body_def_id)?;
125125
debug!(?assumed_wf_types);
126126

@@ -2274,7 +2274,7 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
22742274
/// Feature gates RFC 2056 -- trivial bounds, checking for global bounds that
22752275
/// aren't true.
22762276
#[instrument(level = "debug", skip(self))]
2277-
fn check_false_global_bounds(&mut self) {
2277+
fn check_false_global_bounds(&mut self) -> Result<(), ErrorGuaranteed> {
22782278
let tcx = self.ocx.infcx.tcx;
22792279
let mut span = self.span;
22802280
let empty_env = ty::ParamEnv::empty();
@@ -2283,17 +2283,22 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
22832283
// Check elaborated bounds.
22842284
let implied_obligations = traits::elaborate(tcx, predicates_with_span);
22852285

2286+
let mut global_obligations = vec![];
22862287
for (pred, obligation_span) in implied_obligations {
22872288
// We lower empty bounds like `Vec<dyn Copy>:` as
22882289
// `WellFormed(Vec<dyn Copy>)`, which will later get checked by
22892290
// regular WF checking
22902291
if let ty::ClauseKind::WellFormed(..) = pred.kind().skip_binder() {
22912292
continue;
22922293
}
2293-
// Match the existing behavior.
2294-
if pred.is_global() && !pred.has_type_flags(TypeFlags::HAS_BINDER_VARS) {
2295-
let pred = self.normalize(span, None, pred);
2296-
2294+
// Match the existing behavior. We normalize first to handle where-bounds
2295+
// like `u32: Trait<Assoc = T>`.
2296+
let clause = ObligationCause::misc(span, self.body_def_id);
2297+
let Ok(pred) = self.deeply_normalize(&clause, self.param_env, pred) else {
2298+
tcx.dcx().delayed_bug("encountered errors when normalizing where-clauses");
2299+
continue;
2300+
};
2301+
if pred.is_global() && pred.kind().bound_vars().is_empty() {
22972302
// only use the span of the predicate clause (#90869)
22982303
let hir_node = tcx.hir_node_by_def_id(self.body_def_id);
22992304
if let Some(hir::Generics { predicates, .. }) = hir_node.generics() {
@@ -2315,9 +2320,17 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
23152320
empty_env,
23162321
pred,
23172322
);
2318-
self.ocx.register_obligation(obligation);
2323+
global_obligations.push(obligation);
23192324
}
23202325
}
2326+
2327+
self.register_obligations(global_obligations);
2328+
let errors = self.select_all_or_error();
2329+
if !errors.is_empty() {
2330+
Err(self.infcx.err_ctxt().report_fulfillment_errors(errors))
2331+
} else {
2332+
Ok(())
2333+
}
23212334
}
23222335
}
23232336

tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@ fn take(
1212
K = { () }
1313
>,
1414
) {}
15-
//~^^^^^^ ERROR implementation of `Project` is not general enough
16-
//~^^^^ ERROR higher-ranked subtype error
15+
//~^^^ ERROR higher-ranked subtype error
1716
//~| ERROR higher-ranked subtype error
1817

1918
trait Project { type Out; }

tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr

+1-10
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,5 @@ LL | K = { () }
1212
|
1313
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
1414

15-
error: implementation of `Project` is not general enough
16-
--> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:9:4
17-
|
18-
LL | fn take(
19-
| ^^^^ implementation of `Project` is not general enough
20-
|
21-
= note: `Project` would have to be implemented for the type `for<'a> fn(&'a str) -> &'a str`
22-
= note: ...but `Project` is actually implemented for the type `fn(&'0 str) -> &'0 str`, for some specific lifetime `'0`
23-
24-
error: aborting due to 3 previous errors
15+
error: aborting due to 2 previous errors
2516

tests/ui/associated-types/issue-69398.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
//@ check-pass
2+
#![feature(trivial_bounds)]
23

34
pub trait Foo {
45
type Bar;

tests/ui/consts/issue-67696-const-prop-ice.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//@ compile-flags: --emit=mir,link -Zmir-opt-level=4
33
// Checks that we don't ICE due to attempting to run const prop
44
// on a function with unsatisifable 'where' clauses
5-
5+
#![feature(trivial_bounds)]
66
#![allow(unused)]
77

88
trait A {

tests/ui/feature-gates/feature-gate-trivial_bounds.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,7 @@ fn return_str() -> str where str: Sized { //~ ERROR
6060
*"Sized".to_string().into_boxed_str()
6161
}
6262

63-
// This is currently accepted because the function pointer isn't
64-
// considered global.
65-
fn global_hr(x: fn(&())) where fn(&()): Foo { // OK
63+
fn global_hr(x: fn(&())) where fn(&()): Foo { //~ ERROR
6664
x.test();
6765
}
6866

tests/ui/feature-gates/feature-gate-trivial_bounds.stderr

+14-1
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,19 @@ help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
145145
LL + #![feature(trivial_bounds)]
146146
|
147147

148-
error: aborting due to 11 previous errors
148+
error[E0277]: the trait bound `for<'a> fn(&'a ()): Foo` is not satisfied
149+
--> $DIR/feature-gate-trivial_bounds.rs:63:32
150+
|
151+
LL | fn global_hr(x: fn(&())) where fn(&()): Foo {
152+
| ^^^^^^^^^^^^ the trait `Foo` is not implemented for `for<'a> fn(&'a ())`
153+
|
154+
= help: the trait `Foo` is implemented for `()`
155+
= help: see issue #48214
156+
help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
157+
|
158+
LL + #![feature(trivial_bounds)]
159+
|
160+
161+
error: aborting due to 12 previous errors
149162

150163
For more information about this error, try `rustc --explain E0277`.

tests/ui/issues/issue-36839.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
//@ check-pass
2+
#![feature(trivial_bounds)]
23

34
pub trait Foo {
45
type Bar;

tests/ui/issues/issue-42796.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#![feature(trivial_bounds)]
12
pub trait Mirror<Smoke> {
23
type Image;
34
}

tests/ui/issues/issue-42796.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0382]: borrow of moved value: `s`
2-
--> $DIR/issue-42796.rs:18:20
2+
--> $DIR/issue-42796.rs:19:20
33
|
44
LL | let s = "Hello!".to_owned();
55
| - move occurs because `s` has type `String`, which does not implement the `Copy` trait

tests/ui/layout/unsatisfiable-sized-ungated.rs

+3-7
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
1-
//@ check-pass
2-
// issue: #123134
3-
4-
//! This is a variant of `trivial-bounds-sized.rs` that compiles without any
5-
//! feature gates and used to trigger a delayed bug.
1+
// Regression test for #123134. This is a variant of `trivial-bounds-sized.rs`
2+
// that previously compiled without any feature gate and used to trigger a delayed bug.
63

74
trait Api: Sized {
85
type Device: ?Sized;
@@ -36,8 +33,7 @@ impl<T> Adapter for T {
3633
fn open() -> OpenDevice<Self::A>
3734
where
3835
<Self::A as Api>::Device: Sized,
39-
// ^ the bound expands to `<<T as Adapter>::A as Api>::Device: Sized`, which
40-
// is not considered trivial due to containing the type parameter `T`
36+
//~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
4137
{
4238
unreachable!()
4339
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
2+
--> $DIR/unsatisfiable-sized-ungated.rs:35:9
3+
|
4+
LL | <Self::A as Api>::Device: Sized,
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
6+
|
7+
= help: the trait `Sized` is not implemented for `[u8]`
8+
= help: see issue #48214
9+
help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
10+
|
11+
LL + #![feature(trivial_bounds)]
12+
|
13+
14+
error: aborting due to 1 previous error
15+
16+
For more information about this error, try `rustc --explain E0277`.

tests/ui/mir/issue-91745.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#![feature(trivial_bounds)]
12
//@ check-pass
23

34
pub trait Foo {

tests/ui/trait-bounds/issue-94999.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
//@ check-pass
2+
#![feature(trivial_bounds)]
23

34
trait Identity<Q> {
45
type T;
@@ -25,6 +26,8 @@ impl<Q> Clone for X
2526
where
2627
<S as Identity<Q>>::T: Clone,
2728
X: Holds<Q = Q>,
29+
//~^ WARN trait bound X: Holds does not depend on any type or lifetime parameters
30+
// FIXME(#140311): This shouldn't lint
2831
{
2932
fn clone(&self) -> Self {
3033
Self(self.0.clone())
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
warning: trait bound X: Holds does not depend on any type or lifetime parameters
2+
--> $DIR/issue-94999.rs:28:8
3+
|
4+
LL | X: Holds<Q = Q>,
5+
| ^^^^^^^^^^^^
6+
|
7+
= note: `#[warn(trivial_bounds)]` on by default
8+
9+
warning: 1 warning emitted
10+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
error[E0283]: type annotations needed
2+
--> $DIR/not-trivial-after-norm-1.rs:28:5
3+
|
4+
LL | impls_incomplete::<(), _>();
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `impls_incomplete`
6+
|
7+
note: multiple `impl`s or `where` clauses satisfying `(): Incomplete<_>` found
8+
--> $DIR/not-trivial-after-norm-1.rs:14:1
9+
|
10+
LL | impl<T> Incomplete<T> for () {}
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
...
13+
LL | (): Incomplete<<u32 as With>::Assoc>,
14+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
15+
note: required by a bound in `impls_incomplete`
16+
--> $DIR/not-trivial-after-norm-1.rs:15:24
17+
|
18+
LL | fn impls_incomplete<T: Incomplete<U>, U>() {}
19+
| ^^^^^^^^^^^^^ required by this bound in `impls_incomplete`
20+
21+
error: aborting due to 1 previous error
22+
23+
For more information about this error, try `rustc --explain E0283`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//@[current] check-pass
2+
//@ revisions: current next
3+
//@ ignore-compare-mode-next-solver (explicit revisions)
4+
//@[next] compile-flags: -Znext-solver
5+
6+
trait With {
7+
type Assoc;
8+
}
9+
impl<T> With for T {
10+
type Assoc = T;
11+
}
12+
13+
trait Incomplete<T> {}
14+
impl<T> Incomplete<T> for () {}
15+
fn impls_incomplete<T: Incomplete<U>, U>() {}
16+
fn foo<T>()
17+
where
18+
u32: With<Assoc = T>,
19+
// This where-bound is global before normalization
20+
// and references `T` afterwards. We check whether
21+
// global where-bounds hold by proving them in an empty
22+
// `param_env`.
23+
//
24+
// Make sure we don't introduce params by normalizing after
25+
// checking whether the where-bound is global.
26+
(): Incomplete<<u32 as With>::Assoc>,
27+
{
28+
impls_incomplete::<(), _>();
29+
//[next]~^ ERROR type annotations needed
30+
// FIXME(-Znext-solver): This should match the behavior of the old solver
31+
}
32+
33+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//@ check-pass
2+
//@ revisions: current next
3+
//@ ignore-compare-mode-next-solver (explicit revisions)
4+
//@[next] compile-flags: -Znext-solver
5+
6+
trait With {
7+
type Assoc;
8+
}
9+
impl With for u32 {
10+
type Assoc = [u32; 0];
11+
}
12+
13+
trait Trait {}
14+
impl<const N: usize> Trait for [u32; N] {}
15+
16+
fn foo<const N: usize>()
17+
where
18+
u32: With<Assoc = [u32; N]>,
19+
// This where-bound is global before normalization
20+
// and references `T` afterwards. We check whether
21+
// global where-bounds hold by proving them in an empty
22+
// `param_env`.
23+
//
24+
// Make sure we don't introduce params by normalizing after
25+
// checking whether the where-bound is global. Proving
26+
// `[u32; N]: Trait` then caused an ICE when trying to fetch
27+
// the type of `N`.
28+
<u32 as With>::Assoc: Trait,
29+
{
30+
}
31+
32+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error[E0277]: the trait bound `u32: Trait` is not satisfied
2+
--> $DIR/trivial-after-norm.rs:18:5
3+
|
4+
LL | T::Assoc: Trait,
5+
| ^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `u32`
6+
|
7+
help: this trait has no implementations, consider adding one
8+
--> $DIR/trivial-after-norm.rs:12:1
9+
|
10+
LL | trait Trait {}
11+
| ^^^^^^^^^^^
12+
= help: see issue #48214
13+
help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
14+
|
15+
LL + #![feature(trivial_bounds)]
16+
|
17+
18+
error: aborting due to 1 previous error
19+
20+
For more information about this error, try `rustc --explain E0277`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error[E0277]: the trait bound `u32: Trait` is not satisfied
2+
--> $DIR/trivial-after-norm.rs:18:5
3+
|
4+
LL | T::Assoc: Trait,
5+
| ^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `u32`
6+
|
7+
help: this trait has no implementations, consider adding one
8+
--> $DIR/trivial-after-norm.rs:12:1
9+
|
10+
LL | trait Trait {}
11+
| ^^^^^^^^^^^
12+
= help: see issue #48214
13+
help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
14+
|
15+
LL + #![feature(trivial_bounds)]
16+
|
17+
18+
error: aborting due to 1 previous error
19+
20+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)