Skip to content

change unsatisfiable trivial bounds detection #140313

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 25 additions & 12 deletions compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,8 @@ use rustc_middle::query::Providers;
use rustc_middle::traits::solve::NoSolution;
use rustc_middle::ty::trait_def::TraitSpecializationKind;
use rustc_middle::ty::{
self, AdtKind, GenericArgKind, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeFlags,
TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode,
Upcast,
self, AdtKind, GenericArgKind, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeFoldable,
TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, Upcast,
};
use rustc_middle::{bug, span_bug};
use rustc_session::parse::feature_err;
Expand Down Expand Up @@ -111,16 +110,17 @@ where

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

if !tcx.features().trivial_bounds() {
wfcx.check_false_global_bounds()
}
f(&mut wfcx)?;

let errors = wfcx.select_all_or_error();
if !errors.is_empty() {
return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
}

if !tcx.features().trivial_bounds() {
wfcx.check_false_global_bounds()?;
}

let assumed_wf_types = wfcx.ocx.assumed_wf_types_and_report_errors(param_env, body_def_id)?;
debug!(?assumed_wf_types);

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

let mut global_obligations = vec![];
for (pred, obligation_span) in implied_obligations {
// We lower empty bounds like `Vec<dyn Copy>:` as
// `WellFormed(Vec<dyn Copy>)`, which will later get checked by
// regular WF checking
if let ty::ClauseKind::WellFormed(..) = pred.kind().skip_binder() {
continue;
}
// Match the existing behavior.
if pred.is_global() && !pred.has_type_flags(TypeFlags::HAS_BINDER_VARS) {
let pred = self.normalize(span, None, pred);

// Match the existing behavior. We normalize first to handle where-bounds
// like `u32: Trait<Assoc = T>`.
let clause = ObligationCause::misc(span, self.body_def_id);
let Ok(pred) = self.deeply_normalize(&clause, self.param_env, pred) else {
tcx.dcx().delayed_bug("encountered errors when normalizing where-clauses");
continue;
};
if pred.is_global() && pred.kind().bound_vars().is_empty() {
// only use the span of the predicate clause (#90869)
let hir_node = tcx.hir_node_by_def_id(self.body_def_id);
if let Some(hir::Generics { predicates, .. }) = hir_node.generics() {
Expand All @@ -2315,9 +2320,17 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
empty_env,
pred,
);
self.ocx.register_obligation(obligation);
global_obligations.push(obligation);
}
}

self.register_obligations(global_obligations);
let errors = self.select_all_or_error();
if !errors.is_empty() {
Err(self.infcx.err_ctxt().report_fulfillment_errors(errors))
} else {
Ok(())
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ fn take(
K = { () }
>,
) {}
//~^^^^^^ ERROR implementation of `Project` is not general enough
//~^^^^ ERROR higher-ranked subtype error
//~^^^ ERROR higher-ranked subtype error
//~| ERROR higher-ranked subtype error

trait Project { type Out; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,5 @@ LL | K = { () }
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error: implementation of `Project` is not general enough
--> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:9:4
|
LL | fn take(
| ^^^^ implementation of `Project` is not general enough
|
= note: `Project` would have to be implemented for the type `for<'a> fn(&'a str) -> &'a str`
= note: ...but `Project` is actually implemented for the type `fn(&'0 str) -> &'0 str`, for some specific lifetime `'0`

error: aborting due to 3 previous errors
error: aborting due to 2 previous errors

1 change: 1 addition & 0 deletions tests/ui/associated-types/issue-69398.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//@ check-pass
#![feature(trivial_bounds)]

pub trait Foo {
type Bar;
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/consts/issue-67696-const-prop-ice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//@ compile-flags: --emit=mir,link -Zmir-opt-level=4
// Checks that we don't ICE due to attempting to run const prop
// on a function with unsatisifable 'where' clauses

#![feature(trivial_bounds)]
#![allow(unused)]

trait A {
Expand Down
4 changes: 1 addition & 3 deletions tests/ui/feature-gates/feature-gate-trivial_bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,7 @@ fn return_str() -> str where str: Sized { //~ ERROR
*"Sized".to_string().into_boxed_str()
}

// This is currently accepted because the function pointer isn't
// considered global.
fn global_hr(x: fn(&())) where fn(&()): Foo { // OK
fn global_hr(x: fn(&())) where fn(&()): Foo { //~ ERROR
x.test();
}

Expand Down
15 changes: 14 additions & 1 deletion tests/ui/feature-gates/feature-gate-trivial_bounds.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,19 @@ help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
LL + #![feature(trivial_bounds)]
|

error: aborting due to 11 previous errors
error[E0277]: the trait bound `for<'a> fn(&'a ()): Foo` is not satisfied
--> $DIR/feature-gate-trivial_bounds.rs:63:32
|
LL | fn global_hr(x: fn(&())) where fn(&()): Foo {
| ^^^^^^^^^^^^ the trait `Foo` is not implemented for `for<'a> fn(&'a ())`
|
= help: the trait `Foo` is implemented for `()`
= help: see issue #48214
help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
|
LL + #![feature(trivial_bounds)]
|

error: aborting due to 12 previous errors

For more information about this error, try `rustc --explain E0277`.
1 change: 1 addition & 0 deletions tests/ui/issues/issue-36839.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//@ check-pass
#![feature(trivial_bounds)]

pub trait Foo {
type Bar;
Expand Down
1 change: 1 addition & 0 deletions tests/ui/issues/issue-42796.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![feature(trivial_bounds)]
pub trait Mirror<Smoke> {
type Image;
}
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/issues/issue-42796.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0382]: borrow of moved value: `s`
--> $DIR/issue-42796.rs:18:20
--> $DIR/issue-42796.rs:19:20
|
LL | let s = "Hello!".to_owned();
| - move occurs because `s` has type `String`, which does not implement the `Copy` trait
Expand Down
10 changes: 3 additions & 7 deletions tests/ui/layout/unsatisfiable-sized-ungated.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
//@ check-pass
// issue: #123134

//! This is a variant of `trivial-bounds-sized.rs` that compiles without any
//! feature gates and used to trigger a delayed bug.
// Regression test for #123134. This is a variant of `trivial-bounds-sized.rs`
// that previously compiled without any feature gate and used to trigger a delayed bug.

trait Api: Sized {
type Device: ?Sized;
Expand Down Expand Up @@ -36,8 +33,7 @@ impl<T> Adapter for T {
fn open() -> OpenDevice<Self::A>
where
<Self::A as Api>::Device: Sized,
// ^ the bound expands to `<<T as Adapter>::A as Api>::Device: Sized`, which
// is not considered trivial due to containing the type parameter `T`
//~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
{
unreachable!()
}
Expand Down
16 changes: 16 additions & 0 deletions tests/ui/layout/unsatisfiable-sized-ungated.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
--> $DIR/unsatisfiable-sized-ungated.rs:35:9
|
LL | <Self::A as Api>::Device: Sized,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `[u8]`
= help: see issue #48214
help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
|
LL + #![feature(trivial_bounds)]
|

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0277`.
1 change: 1 addition & 0 deletions tests/ui/mir/issue-91745.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![feature(trivial_bounds)]
//@ check-pass

pub trait Foo {
Expand Down
3 changes: 3 additions & 0 deletions tests/ui/trait-bounds/issue-94999.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//@ check-pass
#![feature(trivial_bounds)]

trait Identity<Q> {
type T;
Expand All @@ -25,6 +26,8 @@ impl<Q> Clone for X
where
<S as Identity<Q>>::T: Clone,
X: Holds<Q = Q>,
//~^ WARN trait bound X: Holds does not depend on any type or lifetime parameters
// FIXME(#140311): This shouldn't lint
{
fn clone(&self) -> Self {
Self(self.0.clone())
Expand Down
10 changes: 10 additions & 0 deletions tests/ui/trait-bounds/issue-94999.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
warning: trait bound X: Holds does not depend on any type or lifetime parameters
--> $DIR/issue-94999.rs:28:8
|
LL | X: Holds<Q = Q>,
| ^^^^^^^^^^^^
|
= note: `#[warn(trivial_bounds)]` on by default

warning: 1 warning emitted

23 changes: 23 additions & 0 deletions tests/ui/trivial-bounds/not-trivial-after-norm-1.next.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
error[E0283]: type annotations needed
--> $DIR/not-trivial-after-norm-1.rs:28:5
|
LL | impls_incomplete::<(), _>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `impls_incomplete`
|
note: multiple `impl`s or `where` clauses satisfying `(): Incomplete<_>` found
--> $DIR/not-trivial-after-norm-1.rs:14:1
|
LL | impl<T> Incomplete<T> for () {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
LL | (): Incomplete<<u32 as With>::Assoc>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: required by a bound in `impls_incomplete`
--> $DIR/not-trivial-after-norm-1.rs:15:24
|
LL | fn impls_incomplete<T: Incomplete<U>, U>() {}
| ^^^^^^^^^^^^^ required by this bound in `impls_incomplete`

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0283`.
33 changes: 33 additions & 0 deletions tests/ui/trivial-bounds/not-trivial-after-norm-1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//@[current] check-pass
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver

trait With {
type Assoc;
}
impl<T> With for T {
type Assoc = T;
}

trait Incomplete<T> {}
impl<T> Incomplete<T> for () {}
fn impls_incomplete<T: Incomplete<U>, U>() {}
fn foo<T>()
where
u32: With<Assoc = T>,
// This where-bound is global before normalization
// and references `T` afterwards. We check whether
// global where-bounds hold by proving them in an empty
// `param_env`.
//
// Make sure we don't introduce params by normalizing after
// checking whether the where-bound is global.
(): Incomplete<<u32 as With>::Assoc>,
{
impls_incomplete::<(), _>();
//[next]~^ ERROR type annotations needed
// FIXME(-Znext-solver): This should match the behavior of the old solver
}

fn main() {}
32 changes: 32 additions & 0 deletions tests/ui/trivial-bounds/not-trivial-after-norm-2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//@ check-pass
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver

trait With {
type Assoc;
}
impl With for u32 {
type Assoc = [u32; 0];
}

trait Trait {}
impl<const N: usize> Trait for [u32; N] {}

fn foo<const N: usize>()
where
u32: With<Assoc = [u32; N]>,
// This where-bound is global before normalization
// and references `T` afterwards. We check whether
// global where-bounds hold by proving them in an empty
// `param_env`.
//
// Make sure we don't introduce params by normalizing after
// checking whether the where-bound is global. Proving
// `[u32; N]: Trait` then caused an ICE when trying to fetch
// the type of `N`.
<u32 as With>::Assoc: Trait,
{
}

fn main() {}
20 changes: 20 additions & 0 deletions tests/ui/trivial-bounds/trivial-after-norm.current.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
error[E0277]: the trait bound `u32: Trait` is not satisfied
--> $DIR/trivial-after-norm.rs:18:5
|
LL | T::Assoc: Trait,
| ^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `u32`
|
help: this trait has no implementations, consider adding one
--> $DIR/trivial-after-norm.rs:12:1
|
LL | trait Trait {}
| ^^^^^^^^^^^
= help: see issue #48214
help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
|
LL + #![feature(trivial_bounds)]
|

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0277`.
20 changes: 20 additions & 0 deletions tests/ui/trivial-bounds/trivial-after-norm.next.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
error[E0277]: the trait bound `u32: Trait` is not satisfied
--> $DIR/trivial-after-norm.rs:18:5
|
LL | T::Assoc: Trait,
| ^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `u32`
|
help: this trait has no implementations, consider adding one
--> $DIR/trivial-after-norm.rs:12:1
|
LL | trait Trait {}
| ^^^^^^^^^^^
= help: see issue #48214
help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
|
LL + #![feature(trivial_bounds)]
|

error: aborting due to 1 previous error

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