From 5f3bdde8e41b228d92b12dbfaba1e632944c1890 Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Thu, 19 Feb 2026 03:58:47 +0900 Subject: [PATCH] Check for region dependent goals on type_op itself as well --- .../src/traits/query/type_op/custom.rs | 35 ++++++++++++++++++- ...ity-due-to-uniquification-4.current.stderr | 20 +++++++++++ ...iguity-due-to-uniquification-4.next.stderr | 9 +++++ .../ambiguity-due-to-uniquification-4.rs | 21 +++++++++++ .../return-type-non-wf-no-ice.current.stderr | 22 ++++++++++++ .../wf/return-type-non-wf-no-ice.next.stderr | 22 ++++++++++++ tests/ui/wf/return-type-non-wf-no-ice.rs | 18 ++++++++++ 7 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 tests/ui/traits/next-solver/assembly/ambiguity-due-to-uniquification-4.current.stderr create mode 100644 tests/ui/traits/next-solver/assembly/ambiguity-due-to-uniquification-4.next.stderr create mode 100644 tests/ui/traits/next-solver/assembly/ambiguity-due-to-uniquification-4.rs create mode 100644 tests/ui/wf/return-type-non-wf-no-ice.current.stderr create mode 100644 tests/ui/wf/return-type-non-wf-no-ice.next.stderr create mode 100644 tests/ui/wf/return-type-non-wf-no-ice.rs diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs index 2b58a65051e1a..812e087a0cf69 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs @@ -92,7 +92,40 @@ where let value = infcx.commit_if_ok(|_| { let ocx = ObligationCtxt::new(infcx); let value = op(&ocx).map_err(|_| { - infcx.dcx().span_delayed_bug(span, format!("error performing operation: {name}")) + infcx.tcx.check_potentially_region_dependent_goals(root_def_id).err().unwrap_or_else( + // FIXME: In this region-dependent context, `type_op` should only fail due to + // region-dependent goals. Any other kind of failure indicates a bug and we + // should ICE. + // + // In principle, all non-region errors are expected to be emitted before + // borrowck. Such errors should taint the body and prevent borrowck from + // running at all. However, this invariant does not currently hold. + // + // Consider: + // + // ```ignore (illustrative) + // struct Foo(T) + // where + // T: Iterator, + // ::Item: Default; + // + // fn foo() -> Foo { + // loop {} + // } + // ``` + // + // Here, `fn foo` ought to error and taint the body before MIR build, since + // `Foo` is not well-formed. However, we currently avoid checking this + // during HIR typeck to prevent duplicate diagnostics. + // + // If we ICE here on any non-region-dependent failure, we would trigger ICEs + // too often for such cases. For now, we emit a delayed bug instead. + || { + infcx + .dcx() + .span_delayed_bug(span, format!("error performing operation: {name}")) + }, + ) })?; let errors = ocx.evaluate_obligations_error_on_ambiguity(); if errors.is_empty() { diff --git a/tests/ui/traits/next-solver/assembly/ambiguity-due-to-uniquification-4.current.stderr b/tests/ui/traits/next-solver/assembly/ambiguity-due-to-uniquification-4.current.stderr new file mode 100644 index 0000000000000..779f143b64f92 --- /dev/null +++ b/tests/ui/traits/next-solver/assembly/ambiguity-due-to-uniquification-4.current.stderr @@ -0,0 +1,20 @@ +error[E0284]: type annotations needed + --> $DIR/ambiguity-due-to-uniquification-4.rs:17:47 + | +LL | pub fn f<'a, 'b, T: Trait<'a> + Trait<'b>>(v: >::Type) {} + | ^^^^^^^^^^^^^^^^^^^^^^ cannot infer type + | + = note: cannot satisfy `>::Type == _` + +error[E0284]: type annotations needed + --> $DIR/ambiguity-due-to-uniquification-4.rs:17:47 + | +LL | pub fn f<'a, 'b, T: Trait<'a> + Trait<'b>>(v: >::Type) {} + | ^^^^^^^^^^^^^^^^^^^^^^ cannot infer type + | + = note: cannot satisfy `>::Type == _` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/traits/next-solver/assembly/ambiguity-due-to-uniquification-4.next.stderr b/tests/ui/traits/next-solver/assembly/ambiguity-due-to-uniquification-4.next.stderr new file mode 100644 index 0000000000000..c7d774644c2ba --- /dev/null +++ b/tests/ui/traits/next-solver/assembly/ambiguity-due-to-uniquification-4.next.stderr @@ -0,0 +1,9 @@ +error[E0284]: type annotations needed: cannot normalize `>::Type` + --> $DIR/ambiguity-due-to-uniquification-4.rs:17:44 + | +LL | pub fn f<'a, 'b, T: Trait<'a> + Trait<'b>>(v: >::Type) {} + | ^ cannot normalize `>::Type` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/traits/next-solver/assembly/ambiguity-due-to-uniquification-4.rs b/tests/ui/traits/next-solver/assembly/ambiguity-due-to-uniquification-4.rs new file mode 100644 index 0000000000000..c40b472678d4b --- /dev/null +++ b/tests/ui/traits/next-solver/assembly/ambiguity-due-to-uniquification-4.rs @@ -0,0 +1,21 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) + +// A regression test for https://github.com/rust-lang/rust/issues/151318. +// +// Unlike in the previous other tests, this fails to compile with the old solver as well. +// Although we were already stashing goals which depend on inference variables and then +// reproving them at the end of HIR typeck to avoid causing an ICE during MIR borrowck, +// it wasn't enough because the type op itself can result in an error due to uniquification, +// e.g. while normalizing a projection type. + +pub trait Trait<'a> { + type Type; +} + +pub fn f<'a, 'b, T: Trait<'a> + Trait<'b>>(v: >::Type) {} +//~^ ERROR type annotations needed +//[current]~| ERROR type annotations needed + +fn main() {} diff --git a/tests/ui/wf/return-type-non-wf-no-ice.current.stderr b/tests/ui/wf/return-type-non-wf-no-ice.current.stderr new file mode 100644 index 0000000000000..888f0893ec7c4 --- /dev/null +++ b/tests/ui/wf/return-type-non-wf-no-ice.current.stderr @@ -0,0 +1,22 @@ +error[E0277]: `T` is not an iterator + --> $DIR/return-type-non-wf-no-ice.rs:13:16 + | +LL | fn foo() -> Foo { + | ^^^^^^ `T` is not an iterator + | +note: required by a bound in `Foo` + --> $DIR/return-type-non-wf-no-ice.rs:10:8 + | +LL | pub struct Foo(T) + | --- required by a bound in this struct +LL | where +LL | T: Iterator, + | ^^^^^^^^ required by this bound in `Foo` +help: consider restricting type parameter `T` with trait `Iterator` + | +LL | fn foo() -> Foo { + | +++++++++++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/wf/return-type-non-wf-no-ice.next.stderr b/tests/ui/wf/return-type-non-wf-no-ice.next.stderr new file mode 100644 index 0000000000000..888f0893ec7c4 --- /dev/null +++ b/tests/ui/wf/return-type-non-wf-no-ice.next.stderr @@ -0,0 +1,22 @@ +error[E0277]: `T` is not an iterator + --> $DIR/return-type-non-wf-no-ice.rs:13:16 + | +LL | fn foo() -> Foo { + | ^^^^^^ `T` is not an iterator + | +note: required by a bound in `Foo` + --> $DIR/return-type-non-wf-no-ice.rs:10:8 + | +LL | pub struct Foo(T) + | --- required by a bound in this struct +LL | where +LL | T: Iterator, + | ^^^^^^^^ required by this bound in `Foo` +help: consider restricting type parameter `T` with trait `Iterator` + | +LL | fn foo() -> Foo { + | +++++++++++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/wf/return-type-non-wf-no-ice.rs b/tests/ui/wf/return-type-non-wf-no-ice.rs new file mode 100644 index 0000000000000..915e33418d7c0 --- /dev/null +++ b/tests/ui/wf/return-type-non-wf-no-ice.rs @@ -0,0 +1,18 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@ [next] compile-flags: -Znext-solver + +// Ensure we do not ICE if a non-well-formed return type manages to slip past HIR typeck. +// See for details. + +pub struct Foo(T) +where + T: Iterator, + ::Item: Default; + +fn foo() -> Foo { + //~^ ERROR: `T` is not an iterator + loop {} +} + +fn main() {}