From d19a07b2a9d7f0a18409485451c12632b93ff674 Mon Sep 17 00:00:00 2001 From: Guillaume Date: Wed, 4 Mar 2026 00:47:53 +0100 Subject: [PATCH 1/7] Fix LegacyKeyValueFormat report from docker build: x86_64-gnu --- .../docker/host-x86_64/x86_64-gnu-aux/Dockerfile | 4 ++-- .../docker/host-x86_64/x86_64-gnu-debug/Dockerfile | 14 ++++++-------- .../host-x86_64/x86_64-gnu-distcheck/Dockerfile | 6 +++--- .../docker/host-x86_64/x86_64-gnu-gcc/Dockerfile | 11 +++++------ .../host-x86_64/x86_64-gnu-llvm-21/Dockerfile | 11 +++++------ .../docker/host-x86_64/x86_64-gnu-miri/Dockerfile | 9 ++++----- .../docker/host-x86_64/x86_64-gnu-nopt/Dockerfile | 8 ++++---- .../docker/host-x86_64/x86_64-gnu-tools/Dockerfile | 11 +++++------ src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile | 7 +++---- 9 files changed, 37 insertions(+), 44 deletions(-) diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile index d4113736b544b..95ddaab7f44b5 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile @@ -29,5 +29,5 @@ RUN sh /scripts/sccache.sh ENV NO_DEBUG_ASSERTIONS=1 ENV NO_OVERFLOW_CHECKS=1 -ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu -ENV RUST_CHECK_TARGET check-aux +ENV RUST_CONFIGURE_ARGS="--build=x86_64-unknown-linux-gnu" +ENV RUST_CHECK_TARGET="check-aux" diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile index 54b13c4397f47..5287d6b8956ff 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile @@ -29,20 +29,19 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh -ENV RUSTBUILD_FORCE_CLANG_BASED_TESTS 1 +ENV RUSTBUILD_FORCE_CLANG_BASED_TESTS="1" # llvm.use-linker conflicts with downloading CI LLVM -ENV NO_DOWNLOAD_CI_LLVM 1 +ENV NO_DOWNLOAD_CI_LLVM="1" -ENV RUST_CONFIGURE_ARGS \ - --build=x86_64-unknown-linux-gnu \ +ENV RUST_CONFIGURE_ARGS="--build=x86_64-unknown-linux-gnu \ --enable-debug \ --enable-lld \ --set rust.debuginfo-level-tests=2 \ --set llvm.use-linker=lld \ --set target.x86_64-unknown-linux-gnu.linker=clang \ --set target.x86_64-unknown-linux-gnu.cc=clang \ - --set target.x86_64-unknown-linux-gnu.cxx=clang++ + --set target.x86_64-unknown-linux-gnu.cxx=clang++" # This job checks: # - That ui tests can be built with `-Cdebuginfo=1` @@ -53,7 +52,6 @@ ENV RUST_CONFIGURE_ARGS \ # - That the tests with `//@ needs-force-clang-based-tests` pass, since they # don't run by default unless RUSTBUILD_FORCE_CLANG_BASED_TESTS is set. -ENV SCRIPT \ - python3 ../x.py --stage 2 build && \ +ENV SCRIPT="python3 ../x.py --stage 2 build && \ python3 ../x.py --stage 2 test tests/ui && \ - python3 ../x.py --stage 2 test tests/run-make tests/run-make-cargo + python3 ../x.py --stage 2 test tests/run-make tests/run-make-cargo" diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile index 5bafd89cfd91d..5ab44df7a8033 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile @@ -1,5 +1,5 @@ # Runs `distcheck`, which is a collection of smoke tests: -# +# # - Run `make check` from an unpacked dist tarball to make sure we can at the # minimum run check steps from those sources. # - Check that selected dist components at least have expected directory shape @@ -34,6 +34,6 @@ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh # Make distcheck builds faster -ENV DISTCHECK_CONFIGURE_ARGS "--enable-sccache" +ENV DISTCHECK_CONFIGURE_ARGS="--enable-sccache" -ENV SCRIPT python3 ../x.py test distcheck +ENV SCRIPT="python3 ../x.py test distcheck" diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-gcc/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-gcc/Dockerfile index f9c1ea531add5..2208ed3ffbe15 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-gcc/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-gcc/Dockerfile @@ -31,15 +31,14 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh -ENV NO_DEBUG_ASSERTIONS 1 -ENV RUST_CONFIGURE_ARGS \ - --build=x86_64-unknown-linux-gnu \ +ENV NO_DEBUG_ASSERTIONS="1" +ENV RUST_CONFIGURE_ARGS="--build=x86_64-unknown-linux-gnu \ --enable-sanitizers \ --enable-profiler \ --enable-compiler-docs \ --set llvm.libzstd=true \ - --set 'rust.codegen-backends=[\"llvm\",\"gcc\"]' -ENV SCRIPT python3 ../x.py \ + --set rust.codegen-backends=[\\\"llvm\\\",\\\"gcc\\\"]" +ENV SCRIPT="python3 ../x.py \ --stage 2 \ test tests \ --test-codegen-backend gcc \ @@ -51,4 +50,4 @@ ENV SCRIPT python3 ../x.py \ --skip tests/rustdoc-js-std \ --skip tests/rustdoc-json \ --skip tests/rustdoc-ui \ - --set 'rust.codegen-backends=[\"llvm\",\"gcc\"]' + --set rust.codegen-backends=[\\\"llvm\\\",\\\"gcc\\\"]" diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-21/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-21/Dockerfile index f0314854411f2..fc96735521077 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-21/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-21/Dockerfile @@ -44,16 +44,15 @@ RUN sh /scripts/sccache.sh # We are disabling CI LLVM since this builder is intentionally using a host # LLVM, rather than the typical src/llvm-project LLVM. -ENV NO_DOWNLOAD_CI_LLVM 1 -ENV EXTERNAL_LLVM 1 +ENV NO_DOWNLOAD_CI_LLVM="1" +ENV EXTERNAL_LLVM="1" # Using llvm-link-shared due to libffi issues -- see #34486 -ENV RUST_CONFIGURE_ARGS \ - --build=x86_64-unknown-linux-gnu \ +ENV RUST_CONFIGURE_ARGS="--build=x86_64-unknown-linux-gnu \ --llvm-root=/usr/lib/llvm-21 \ --enable-llvm-link-shared \ --set rust.randomize-layout=true \ - --set rust.thin-lto-import-instr-limit=10 + --set rust.thin-lto-import-instr-limit=10" COPY scripts/shared.sh /scripts/ @@ -63,4 +62,4 @@ COPY scripts/x86_64-gnu-llvm3.sh /scripts/ COPY scripts/stage_2_test_set1.sh /scripts/ COPY scripts/stage_2_test_set2.sh /scripts/ -ENV SCRIPT "Must specify DOCKER_SCRIPT for this image" +ENV SCRIPT="Must specify DOCKER_SCRIPT for this image" diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-miri/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-miri/Dockerfile index db4fca71d6376..e478b80044215 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-miri/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-miri/Dockerfile @@ -34,11 +34,10 @@ ENV GCC_EXEC_PREFIX="/usr/lib/gcc/" COPY host-x86_64/x86_64-gnu-miri/check-miri.sh /tmp/ -ENV RUST_CONFIGURE_ARGS \ - --build=x86_64-unknown-linux-gnu \ - --enable-new-symbol-mangling +ENV RUST_CONFIGURE_ARGS="--build=x86_64-unknown-linux-gnu \ + --enable-new-symbol-mangling" -ENV HOST_TARGET x86_64-unknown-linux-gnu +ENV HOST_TARGET="x86_64-unknown-linux-gnu" # FIXME(#133381): currently rustc alt builds do *not* have rustc debug # assertions enabled! Therefore, we cannot force download CI rustc. @@ -46,4 +45,4 @@ ENV HOST_TARGET x86_64-unknown-linux-gnu COPY scripts/shared.sh /scripts/ -ENV SCRIPT /tmp/check-miri.sh ../x.py +ENV SCRIPT="/tmp/check-miri.sh ../x.py" diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile index 854c36ee01c19..6020dc8877c16 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile @@ -22,8 +22,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh -ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu \ +ENV RUST_CONFIGURE_ARGS="--build=x86_64-unknown-linux-gnu \ --disable-optimize-tests \ - --set rust.test-compare-mode -ENV SCRIPT python3 ../x.py test --stage 1 --set rust.optimize=false library/std \ - && python3 ../x.py --stage 2 test + --set rust.test-compare-mode" +ENV SCRIPT="python3 ../x.py test --stage 1 --set rust.optimize=false library/std \ + && python3 ../x.py --stage 2 test" diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile index 278e40eb71fac..3eb424ceef4a3 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile @@ -76,12 +76,11 @@ COPY scripts/nodejs.sh /scripts/ RUN sh /scripts/nodejs.sh /node ENV PATH="/node/bin:${PATH}" -ENV RUST_CONFIGURE_ARGS \ - --build=x86_64-unknown-linux-gnu \ +ENV RUST_CONFIGURE_ARGS="--build=x86_64-unknown-linux-gnu \ --save-toolstates=/tmp/toolstate/toolstates.json \ - --enable-new-symbol-mangling + --enable-new-symbol-mangling" -ENV HOST_TARGET x86_64-unknown-linux-gnu +ENV HOST_TARGET="x86_64-unknown-linux-gnu" # FIXME(#133381): currently rustc alt builds do *not* have rustc debug # assertions enabled! Therefore, we cannot force download CI rustc. @@ -89,5 +88,5 @@ ENV HOST_TARGET x86_64-unknown-linux-gnu COPY scripts/shared.sh /scripts/ -ENV SCRIPT /tmp/checktools.sh ../x.py && \ - python3 ../x.py test tests/rustdoc-gui --stage 2 --test-args "'--jobs 1'" +ENV SCRIPT="/tmp/checktools.sh ../x.py && \ + python3 ../x.py test tests/rustdoc-gui --stage 2 --test-args '--jobs 1'" diff --git a/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile index 83c2aa8cfb3b7..7ca2dbb7d9f36 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile @@ -24,10 +24,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh -ENV RUST_CONFIGURE_ARGS \ - --build=x86_64-unknown-linux-gnu \ +ENV RUST_CONFIGURE_ARGS="--build=x86_64-unknown-linux-gnu \ --enable-sanitizers \ --enable-profiler \ --enable-compiler-docs \ - --set llvm.libzstd=true -ENV SCRIPT python3 ../x.py --stage 2 test + --set llvm.libzstd=true" +ENV SCRIPT="python3 ../x.py --stage 2 test" From 39631fdac191893a6eb4d000d5b258e92cae2304 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 15 Mar 2026 01:50:36 +0000 Subject: [PATCH 2/7] Point at unit structs on foreign crates in type errors when they are the pattern of a let binding Consts and unit structs in patterns can be confusing if they are mistaken for new bindings. We already provide some context for unit structs and consts that come from the current crate, we now also point at those from foreign crates, and we properly skip cases where the pattern has type parameters which can't be confused with a new binding. Make new binding suggestion verbose. --- compiler/rustc_hir_typeck/src/pat.rs | 122 +++++++-------- tests/ui/blind/blind-item-block-middle.stderr | 6 +- .../const_in_pattern/arrays-and-slices.stderr | 24 ++- tests/ui/issues/issue-33504.stderr | 7 +- tests/ui/issues/issue-5100.stderr | 3 - tests/ui/match/issue-12552.stderr | 14 +- .../match-const-tuple-type-mismatch.stderr | 6 +- tests/ui/match/match-tag-nullary.stderr | 3 - .../mismatched-types-in-match-7867.stderr | 3 - .../private-unit-struct-assignment.stderr | 3 - tests/ui/resolve/name-clash-nullary.stderr | 10 ++ .../const.stderr | 7 +- tests/ui/suggestions/field-access.stderr | 9 -- .../suggest-deref-in-match-issue-132784.rs | 8 + ...suggest-deref-in-match-issue-132784.stderr | 140 +++++++++++++++--- .../type/pattern_types/matching_fail.stderr | 6 +- 16 files changed, 260 insertions(+), 111 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 7b5f5f3f520e4..314b50a12fc37 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -1636,69 +1636,75 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span_bug!(pat_span, "unexpected resolution for path pattern: {resolved_pat:?}"); }; - if let Some(span) = self.tcx.hir_res_span(pat_res) { + let span = match (self.tcx.hir_res_span(pat_res), res.opt_def_id()) { + (Some(span), _) => span, + (None, Some(def_id)) => self.tcx.def_span(def_id), + (None, None) => { + e.emit(); + return; + } + }; + if let [hir::PathSegment { ident, args: None, .. }] = segments { e.span_label(span, format!("{} defined here", res.descr())); - if let [hir::PathSegment { ident, .. }] = segments { - e.span_label( - pat_span, - format!( - "`{}` is interpreted as {} {}, not a new binding", - ident, - res.article(), - res.descr(), - ), - ); - match self.tcx.parent_hir_node(hir_id) { - hir::Node::PatField(..) => { + e.span_label( + pat_span, + format!( + "`{}` is interpreted as {} {}, not a new binding", + ident, + res.article(), + res.descr(), + ), + ); + match self.tcx.parent_hir_node(hir_id) { + hir::Node::PatField(..) => { + e.span_suggestion_verbose( + ident.span.shrink_to_hi(), + "bind the struct field to a different name instead", + format!(": other_{}", ident.as_str().to_lowercase()), + Applicability::HasPlaceholders, + ); + } + _ => { + let (type_def_id, item_def_id) = match resolved_pat.ty.kind() { + ty::Adt(def, _) => match res { + Res::Def(DefKind::Const { .. }, def_id) => { + (Some(def.did()), Some(def_id)) + } + _ => (None, None), + }, + _ => (None, None), + }; + + let is_range = matches!( + type_def_id.and_then(|id| self.tcx.as_lang_item(id)), + Some( + LangItem::Range + | LangItem::RangeFrom + | LangItem::RangeTo + | LangItem::RangeFull + | LangItem::RangeInclusiveStruct + | LangItem::RangeToInclusive, + ) + ); + if is_range { + if !self.maybe_suggest_range_literal(&mut e, item_def_id, *ident) { + let msg = "constants only support matching by type, \ + if you meant to match against a range of values, \ + consider using a range pattern like `min ..= max` in the match block"; + e.note(msg); + } + } else { + let msg = "introduce a new binding instead"; + let sugg = format!("other_{}", ident.as_str().to_lowercase()); e.span_suggestion_verbose( - ident.span.shrink_to_hi(), - "bind the struct field to a different name instead", - format!(": other_{}", ident.as_str().to_lowercase()), + ident.span, + msg, + sugg, Applicability::HasPlaceholders, ); } - _ => { - let (type_def_id, item_def_id) = match resolved_pat.ty.kind() { - ty::Adt(def, _) => match res { - Res::Def(DefKind::Const { .. }, def_id) => { - (Some(def.did()), Some(def_id)) - } - _ => (None, None), - }, - _ => (None, None), - }; - - let is_range = matches!( - type_def_id.and_then(|id| self.tcx.as_lang_item(id)), - Some( - LangItem::Range - | LangItem::RangeFrom - | LangItem::RangeTo - | LangItem::RangeFull - | LangItem::RangeInclusiveStruct - | LangItem::RangeToInclusive, - ) - ); - if is_range { - if !self.maybe_suggest_range_literal(&mut e, item_def_id, *ident) { - let msg = "constants only support matching by type, \ - if you meant to match against a range of values, \ - consider using a range pattern like `min ..= max` in the match block"; - e.note(msg); - } - } else { - let msg = "introduce a new binding instead"; - let sugg = format!("other_{}", ident.as_str().to_lowercase()); - e.span_suggestion( - ident.span, - msg, - sugg, - Applicability::HasPlaceholders, - ); - } - } - }; - } + } + }; } e.emit(); } diff --git a/tests/ui/blind/blind-item-block-middle.stderr b/tests/ui/blind/blind-item-block-middle.stderr index b2ae169013a62..5c05f31ab8953 100644 --- a/tests/ui/blind/blind-item-block-middle.stderr +++ b/tests/ui/blind/blind-item-block-middle.stderr @@ -9,7 +9,11 @@ LL | let bar = 5; | | | expected integer, found `bar` | `bar` is interpreted as a unit struct, not a new binding - | help: introduce a new binding instead: `other_bar` + | +help: introduce a new binding instead + | +LL | let other_bar = 5; + | ++++++ error: aborting due to 1 previous error diff --git a/tests/ui/consts/const_in_pattern/arrays-and-slices.stderr b/tests/ui/consts/const_in_pattern/arrays-and-slices.stderr index 412caf60f7d85..8aa86c8b05f53 100644 --- a/tests/ui/consts/const_in_pattern/arrays-and-slices.stderr +++ b/tests/ui/consts/const_in_pattern/arrays-and-slices.stderr @@ -11,10 +11,14 @@ LL | BSTR_SIZED => {} | | | expected `&[u8]`, found `&[u8; 3]` | `BSTR_SIZED` is interpreted as a constant, not a new binding - | help: introduce a new binding instead: `other_bstr_sized` | = note: expected reference `&[u8]` found reference `&'static [u8; 3]` +help: introduce a new binding instead + | +LL - BSTR_SIZED => {} +LL + other_bstr_sized => {} + | error[E0308]: mismatched types --> $DIR/arrays-and-slices.rs:23:9 @@ -29,10 +33,14 @@ LL | STRUCT_SIZED => {} | | | expected `&SomeStruct<[u8]>`, found `&SomeStruct<[u8; 3]>` | `STRUCT_SIZED` is interpreted as a constant, not a new binding - | help: introduce a new binding instead: `other_struct_sized` | = note: expected reference `&SomeStruct<[u8]>` found reference `&'static SomeStruct<[u8; 3]>` +help: introduce a new binding instead + | +LL - STRUCT_SIZED => {} +LL + other_struct_sized => {} + | error[E0308]: mismatched types --> $DIR/arrays-and-slices.rs:30:9 @@ -47,10 +55,14 @@ LL | BSTR_SIZED => {} | | | expected `&[u8]`, found `&[u8; 3]` | `BSTR_SIZED` is interpreted as a constant, not a new binding - | help: introduce a new binding instead: `other_bstr_sized` | = note: expected reference `&[u8]` found reference `&'static [u8; 3]` +help: introduce a new binding instead + | +LL - BSTR_SIZED => {} +LL + other_bstr_sized => {} + | error[E0308]: mismatched types --> $DIR/arrays-and-slices.rs:37:9 @@ -65,10 +77,14 @@ LL | STRUCT_SIZED => {} | | | expected `&SomeStruct<[u8]>`, found `&SomeStruct<[u8; 3]>` | `STRUCT_SIZED` is interpreted as a constant, not a new binding - | help: introduce a new binding instead: `other_struct_sized` | = note: expected reference `&SomeStruct<[u8]>` found reference `&'static SomeStruct<[u8; 3]>` +help: introduce a new binding instead + | +LL - STRUCT_SIZED => {} +LL + other_struct_sized => {} + | error: cannot use unsized non-slice type `SomeStruct<[u8]>` in constant patterns --> $DIR/arrays-and-slices.rs:47:9 diff --git a/tests/ui/issues/issue-33504.stderr b/tests/ui/issues/issue-33504.stderr index f3e1ca08b6fc3..e5a2eea751d0e 100644 --- a/tests/ui/issues/issue-33504.stderr +++ b/tests/ui/issues/issue-33504.stderr @@ -9,7 +9,12 @@ LL | let Test = 1; | | | expected integer, found `Test` | `Test` is interpreted as a unit struct, not a new binding - | help: introduce a new binding instead: `other_test` + | +help: introduce a new binding instead + | +LL - let Test = 1; +LL + let other_test = 1; + | error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-5100.stderr b/tests/ui/issues/issue-5100.stderr index 24d41a1a8afae..c545f70415c13 100644 --- a/tests/ui/issues/issue-5100.stderr +++ b/tests/ui/issues/issue-5100.stderr @@ -1,9 +1,6 @@ error[E0308]: mismatched types --> $DIR/issue-5100.rs:9:9 | -LL | enum A { B, C } - | - unit variant defined here -... LL | match (true, false) { | ------------- this expression has type `(bool, bool)` LL | A::B => (), diff --git a/tests/ui/match/issue-12552.stderr b/tests/ui/match/issue-12552.stderr index 195192fbd8240..397265cd540f1 100644 --- a/tests/ui/match/issue-12552.stderr +++ b/tests/ui/match/issue-12552.stderr @@ -20,7 +20,14 @@ LL | match t { | - this expression has type `Result<_, {integer}>` ... LL | None => () - | ^^^^ expected `Result<_, {integer}>`, found `Option<_>` + | ^^^^ + | | + | expected `Result<_, {integer}>`, found `Option<_>` + | `None` is interpreted as a unit variant, not a new binding + | + --> $SRC_DIR/core/src/option.rs:LL:COL + | + = note: unit variant defined here | = note: expected enum `Result<_, {integer}>` found enum `Option<_>` @@ -28,6 +35,11 @@ help: try wrapping the pattern in `Ok` | LL | Ok(None) => () | +++ + +help: introduce a new binding instead + | +LL - None => () +LL + other_none => () + | error: aborting due to 2 previous errors diff --git a/tests/ui/match/match-const-tuple-type-mismatch.stderr b/tests/ui/match/match-const-tuple-type-mismatch.stderr index e7dd97c4e9a60..06f65b257069d 100644 --- a/tests/ui/match/match-const-tuple-type-mismatch.stderr +++ b/tests/ui/match/match-const-tuple-type-mismatch.stderr @@ -11,10 +11,14 @@ LL | A => (), | | | expected integer, found `(isize, isize)` | `A` is interpreted as a constant, not a new binding - | help: introduce a new binding instead: `other_a` | = note: expected type `{integer}` found tuple `(isize, isize)` +help: introduce a new binding instead + | +LL - A => (), +LL + other_a => (), + | error: aborting due to 1 previous error diff --git a/tests/ui/match/match-tag-nullary.stderr b/tests/ui/match/match-tag-nullary.stderr index c9446d164337c..2822d715ab319 100644 --- a/tests/ui/match/match-tag-nullary.stderr +++ b/tests/ui/match/match-tag-nullary.stderr @@ -1,9 +1,6 @@ error[E0308]: mismatched types --> $DIR/match-tag-nullary.rs:4:40 | -LL | enum B { B } - | - unit variant defined here -LL | LL | fn main() { let x: A = A::A; match x { B::B => { } } } | - ^^^^ expected `A`, found `B` | | diff --git a/tests/ui/match/mismatched-types-in-match-7867.stderr b/tests/ui/match/mismatched-types-in-match-7867.stderr index e41a61e42f4b0..6f25175209dcc 100644 --- a/tests/ui/match/mismatched-types-in-match-7867.stderr +++ b/tests/ui/match/mismatched-types-in-match-7867.stderr @@ -1,9 +1,6 @@ error[E0308]: mismatched types --> $DIR/mismatched-types-in-match-7867.rs:10:9 | -LL | enum A { B, C } - | - unit variant defined here -... LL | match (true, false) { | ------------- this expression has type `(bool, bool)` LL | A::B => (), diff --git a/tests/ui/privacy/private-unit-struct-assignment.stderr b/tests/ui/privacy/private-unit-struct-assignment.stderr index 8c36a08846d81..110ee19d5ff4d 100644 --- a/tests/ui/privacy/private-unit-struct-assignment.stderr +++ b/tests/ui/privacy/private-unit-struct-assignment.stderr @@ -13,9 +13,6 @@ LL | struct C; error[E0308]: mismatched types --> $DIR/private-unit-struct-assignment.rs:8:5 | -LL | struct C; - | -------- unit struct defined here -... LL | A::C = 1; | ^^^^ - this expression has type `{integer}` | | diff --git a/tests/ui/resolve/name-clash-nullary.stderr b/tests/ui/resolve/name-clash-nullary.stderr index 08e7fe9a678a1..1a3f434b62770 100644 --- a/tests/ui/resolve/name-clash-nullary.stderr +++ b/tests/ui/resolve/name-clash-nullary.stderr @@ -5,9 +5,19 @@ LL | let None: isize = 42; | ^^^^ ----- expected due to this | | | expected `isize`, found `Option<_>` + | `None` is interpreted as a unit variant, not a new binding + | + --> $SRC_DIR/core/src/option.rs:LL:COL + | + = note: unit variant defined here | = note: expected type `isize` found enum `Option<_>` +help: introduce a new binding instead + | +LL - let None: isize = 42; +LL + let other_none: isize = 42; + | error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/const.stderr b/tests/ui/rfcs/rfc-2005-default-binding-mode/const.stderr index 1c8e8d5b0a7db..12b89ba10bfd1 100644 --- a/tests/ui/rfcs/rfc-2005-default-binding-mode/const.stderr +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/const.stderr @@ -11,7 +11,12 @@ LL | FOO => {}, | | | expected `&Foo`, found `Foo` | `FOO` is interpreted as a constant, not a new binding - | help: introduce a new binding instead: `other_foo` + | +help: introduce a new binding instead + | +LL - FOO => {}, +LL + other_foo => {}, + | error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/field-access.stderr b/tests/ui/suggestions/field-access.stderr index 362dae172c78f..36e126176ee96 100644 --- a/tests/ui/suggestions/field-access.stderr +++ b/tests/ui/suggestions/field-access.stderr @@ -1,9 +1,6 @@ error[E0308]: mismatched types --> $DIR/field-access.rs:20:12 | -LL | Fst, - | --- unit variant defined here -... LL | if let B::Fst = a {}; | ^^^^^^ - this expression has type `A` | | @@ -17,9 +14,6 @@ LL | if let B::Fst = a.b {}; error[E0308]: mismatched types --> $DIR/field-access.rs:25:9 | -LL | Fst, - | --- unit variant defined here -... LL | match a { | - this expression has type `A` ... @@ -34,9 +28,6 @@ LL | match a.b { error[E0308]: mismatched types --> $DIR/field-access.rs:26:9 | -LL | Snd, - | --- unit variant defined here -... LL | match a { | - this expression has type `A` ... diff --git a/tests/ui/suggestions/suggest-deref-in-match-issue-132784.rs b/tests/ui/suggestions/suggest-deref-in-match-issue-132784.rs index 205e57f4a9ff5..77074e8c3a3b1 100644 --- a/tests/ui/suggestions/suggest-deref-in-match-issue-132784.rs +++ b/tests/ui/suggestions/suggest-deref-in-match-issue-132784.rs @@ -8,6 +8,7 @@ fn main() { //~^ ERROR mismatched types None => {} //~^ ERROR mismatched types + //~| HELP introduce a new binding instead } match &x { @@ -17,6 +18,7 @@ fn main() { //~^ ERROR mismatched types None => {} //~^ ERROR mismatched types + //~| HELP introduce a new binding instead } let mut y = Box::new(Some(1)); @@ -27,6 +29,7 @@ fn main() { //~^ ERROR mismatched types None => {} //~^ ERROR mismatched types + //~| HELP introduce a new binding instead } let mut z = Arc::new(Some(1)); @@ -37,6 +40,7 @@ fn main() { //~^ ERROR mismatched types None => {} //~^ ERROR mismatched types + //~| HELP introduce a new binding instead } let z_const: &Arc> = &z; @@ -47,6 +51,7 @@ fn main() { //~^ ERROR mismatched types None => {} //~^ ERROR mismatched types + //~| HELP introduce a new binding instead } // Normal reference because Arc doesn't implement DerefMut. @@ -58,6 +63,7 @@ fn main() { //~^ ERROR mismatched types None => {} //~^ ERROR mismatched types + //~| HELP introduce a new binding instead } // Mutable reference because Box does implement DerefMut. @@ -69,6 +75,7 @@ fn main() { //~^ ERROR mismatched types None => {} //~^ ERROR mismatched types + //~| HELP introduce a new binding instead } // Difficult expression. @@ -80,5 +87,6 @@ fn main() { //~^ ERROR mismatched types None => {} //~^ ERROR mismatched types + //~| HELP introduce a new binding instead } } diff --git a/tests/ui/suggestions/suggest-deref-in-match-issue-132784.stderr b/tests/ui/suggestions/suggest-deref-in-match-issue-132784.stderr index 6092272aa8c5a..a5ce44b256004 100644 --- a/tests/ui/suggestions/suggest-deref-in-match-issue-132784.stderr +++ b/tests/ui/suggestions/suggest-deref-in-match-issue-132784.stderr @@ -21,7 +21,14 @@ LL | match x { | - this expression has type `Arc>` ... LL | None => {} - | ^^^^ expected `Arc>`, found `Option<_>` + | ^^^^ + | | + | expected `Arc>`, found `Option<_>` + | `None` is interpreted as a unit variant, not a new binding + | + --> $SRC_DIR/core/src/option.rs:LL:COL + | + = note: unit variant defined here | = note: expected struct `Arc>` found enum `Option<_>` @@ -29,9 +36,14 @@ help: consider dereferencing to access the inner value using the Deref trait | LL | match *x { | + +help: introduce a new binding instead + | +LL - None => {} +LL + other_none => {} + | error[E0308]: mismatched types - --> $DIR/suggest-deref-in-match-issue-132784.rs:16:9 + --> $DIR/suggest-deref-in-match-issue-132784.rs:17:9 | LL | match &x { | -- this expression has type `&Arc>` @@ -47,13 +59,20 @@ LL | match &*x { | + error[E0308]: mismatched types - --> $DIR/suggest-deref-in-match-issue-132784.rs:18:9 + --> $DIR/suggest-deref-in-match-issue-132784.rs:19:9 | LL | match &x { | -- this expression has type `&Arc>` ... LL | None => {} - | ^^^^ expected `Arc>`, found `Option<_>` + | ^^^^ + | | + | expected `Arc>`, found `Option<_>` + | `None` is interpreted as a unit variant, not a new binding + | + --> $SRC_DIR/core/src/option.rs:LL:COL + | + = note: unit variant defined here | = note: expected struct `Arc>` found enum `Option<_>` @@ -61,9 +80,14 @@ help: consider dereferencing to access the inner value using the Deref trait | LL | match &*x { | + +help: introduce a new binding instead + | +LL - None => {} +LL + other_none => {} + | error[E0308]: mismatched types - --> $DIR/suggest-deref-in-match-issue-132784.rs:26:9 + --> $DIR/suggest-deref-in-match-issue-132784.rs:28:9 | LL | match y { | - this expression has type `Box>` @@ -79,13 +103,20 @@ LL | match *y { | + error[E0308]: mismatched types - --> $DIR/suggest-deref-in-match-issue-132784.rs:28:9 + --> $DIR/suggest-deref-in-match-issue-132784.rs:30:9 | LL | match y { | - this expression has type `Box>` ... LL | None => {} - | ^^^^ expected `Box>`, found `Option<_>` + | ^^^^ + | | + | expected `Box>`, found `Option<_>` + | `None` is interpreted as a unit variant, not a new binding + | + --> $SRC_DIR/core/src/option.rs:LL:COL + | + = note: unit variant defined here | = note: expected struct `Box>` found enum `Option<_>` @@ -93,9 +124,14 @@ help: consider dereferencing to access the inner value using the Deref trait | LL | match *y { | + +help: introduce a new binding instead + | +LL - None => {} +LL + other_none => {} + | error[E0308]: mismatched types - --> $DIR/suggest-deref-in-match-issue-132784.rs:36:9 + --> $DIR/suggest-deref-in-match-issue-132784.rs:39:9 | LL | match z as Arc> { | --------------------- this expression has type `Arc>` @@ -112,13 +148,20 @@ LL + match *(z as Arc>) { | error[E0308]: mismatched types - --> $DIR/suggest-deref-in-match-issue-132784.rs:38:9 + --> $DIR/suggest-deref-in-match-issue-132784.rs:41:9 | LL | match z as Arc> { | --------------------- this expression has type `Arc>` ... LL | None => {} - | ^^^^ expected `Arc>`, found `Option<_>` + | ^^^^ + | | + | expected `Arc>`, found `Option<_>` + | `None` is interpreted as a unit variant, not a new binding + | + --> $SRC_DIR/core/src/option.rs:LL:COL + | + = note: unit variant defined here | = note: expected struct `Arc>` found enum `Option<_>` @@ -127,9 +170,14 @@ help: consider dereferencing to access the inner value using the Deref trait LL - match z as Arc> { LL + match *(z as Arc>) { | +help: introduce a new binding instead + | +LL - None => {} +LL + other_none => {} + | error[E0308]: mismatched types - --> $DIR/suggest-deref-in-match-issue-132784.rs:46:9 + --> $DIR/suggest-deref-in-match-issue-132784.rs:50:9 | LL | match z_const { | ------- this expression has type `&Arc>` @@ -145,13 +193,20 @@ LL | match &**z_const { | +++ error[E0308]: mismatched types - --> $DIR/suggest-deref-in-match-issue-132784.rs:48:9 + --> $DIR/suggest-deref-in-match-issue-132784.rs:52:9 | LL | match z_const { | ------- this expression has type `&Arc>` ... LL | None => {} - | ^^^^ expected `Arc>`, found `Option<_>` + | ^^^^ + | | + | expected `Arc>`, found `Option<_>` + | `None` is interpreted as a unit variant, not a new binding + | + --> $SRC_DIR/core/src/option.rs:LL:COL + | + = note: unit variant defined here | = note: expected struct `Arc>` found enum `Option<_>` @@ -159,9 +214,14 @@ help: consider dereferencing to access the inner value using the Deref trait | LL | match &**z_const { | +++ +help: introduce a new binding instead + | +LL - None => {} +LL + other_none => {} + | error[E0308]: mismatched types - --> $DIR/suggest-deref-in-match-issue-132784.rs:57:9 + --> $DIR/suggest-deref-in-match-issue-132784.rs:62:9 | LL | match z_mut { | ----- this expression has type `&mut Arc>` @@ -177,13 +237,20 @@ LL | match &**z_mut { | +++ error[E0308]: mismatched types - --> $DIR/suggest-deref-in-match-issue-132784.rs:59:9 + --> $DIR/suggest-deref-in-match-issue-132784.rs:64:9 | LL | match z_mut { | ----- this expression has type `&mut Arc>` ... LL | None => {} - | ^^^^ expected `Arc>`, found `Option<_>` + | ^^^^ + | | + | expected `Arc>`, found `Option<_>` + | `None` is interpreted as a unit variant, not a new binding + | + --> $SRC_DIR/core/src/option.rs:LL:COL + | + = note: unit variant defined here | = note: expected struct `Arc>` found enum `Option<_>` @@ -191,9 +258,14 @@ help: consider dereferencing to access the inner value using the Deref trait | LL | match &**z_mut { | +++ +help: introduce a new binding instead + | +LL - None => {} +LL + other_none => {} + | error[E0308]: mismatched types - --> $DIR/suggest-deref-in-match-issue-132784.rs:68:9 + --> $DIR/suggest-deref-in-match-issue-132784.rs:74:9 | LL | match y_mut { | ----- this expression has type `&mut Box>` @@ -209,13 +281,20 @@ LL | match &**y_mut { | +++ error[E0308]: mismatched types - --> $DIR/suggest-deref-in-match-issue-132784.rs:70:9 + --> $DIR/suggest-deref-in-match-issue-132784.rs:76:9 | LL | match y_mut { | ----- this expression has type `&mut Box>` ... LL | None => {} - | ^^^^ expected `Box>`, found `Option<_>` + | ^^^^ + | | + | expected `Box>`, found `Option<_>` + | `None` is interpreted as a unit variant, not a new binding + | + --> $SRC_DIR/core/src/option.rs:LL:COL + | + = note: unit variant defined here | = note: expected struct `Box>` found enum `Option<_>` @@ -223,9 +302,14 @@ help: consider dereferencing to access the inner value using the Deref trait | LL | match &**y_mut { | +++ +help: introduce a new binding instead + | +LL - None => {} +LL + other_none => {} + | error[E0308]: mismatched types - --> $DIR/suggest-deref-in-match-issue-132784.rs:79:9 + --> $DIR/suggest-deref-in-match-issue-132784.rs:86:9 | LL | match (& (&difficult) ) { | ------------------ this expression has type `&&Arc>` @@ -242,13 +326,20 @@ LL + match &*difficult { | error[E0308]: mismatched types - --> $DIR/suggest-deref-in-match-issue-132784.rs:81:9 + --> $DIR/suggest-deref-in-match-issue-132784.rs:88:9 | LL | match (& (&difficult) ) { | ------------------ this expression has type `&&Arc>` ... LL | None => {} - | ^^^^ expected `Arc>`, found `Option<_>` + | ^^^^ + | | + | expected `Arc>`, found `Option<_>` + | `None` is interpreted as a unit variant, not a new binding + | + --> $SRC_DIR/core/src/option.rs:LL:COL + | + = note: unit variant defined here | = note: expected struct `Arc>` found enum `Option<_>` @@ -257,6 +348,11 @@ help: consider dereferencing to access the inner value using the Deref trait LL - match (& (&difficult) ) { LL + match &*difficult { | +help: introduce a new binding instead + | +LL - None => {} +LL + other_none => {} + | error: aborting due to 16 previous errors diff --git a/tests/ui/type/pattern_types/matching_fail.stderr b/tests/ui/type/pattern_types/matching_fail.stderr index 446180d80f24b..495d739078782 100644 --- a/tests/ui/type/pattern_types/matching_fail.stderr +++ b/tests/ui/type/pattern_types/matching_fail.stderr @@ -33,10 +33,14 @@ LL | THREE => {} | | | expected integer, found `(u32) is 1..` | `THREE` is interpreted as a constant, not a new binding - | help: introduce a new binding instead: `other_three` | = note: expected type `{integer}` found pattern type `(u32) is 1..` +help: introduce a new binding instead + | +LL - THREE => {} +LL + other_three => {} + | error: aborting due to 3 previous errors From 408066f31094c0284d5c4684e9839ae3594100df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 15 Mar 2026 03:51:25 +0000 Subject: [PATCH 3/7] Do not suggest introducing new binding when other suggestions are present --- compiler/rustc_errors/src/lib.rs | 8 + compiler/rustc_hir_typeck/src/pat.rs | 4 +- .../compatible-variants-in-pat.rs | 2 - .../compatible-variants-in-pat.stderr | 28 +--- tests/ui/match/issue-12552.stderr | 14 +- .../suggest-deref-in-match-issue-132784.rs | 8 - ...suggest-deref-in-match-issue-132784.stderr | 140 +++--------------- 7 files changed, 37 insertions(+), 167 deletions(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 9b3dba15f55e2..8c57544c54b8f 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -138,6 +138,14 @@ impl Suggestions { Suggestions::Disabled => Vec::new(), } } + + pub fn len(&self) -> usize { + match self { + Suggestions::Enabled(suggestions) => suggestions.len(), + Suggestions::Sealed(suggestions) => suggestions.len(), + Suggestions::Disabled => 0, + } + } } impl Default for Suggestions { diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 314b50a12fc37..26f7d1ccffc93 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -1644,7 +1644,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; } }; - if let [hir::PathSegment { ident, args: None, .. }] = segments { + if let [hir::PathSegment { ident, args: None, .. }] = segments + && e.suggestions.len() == 0 + { e.span_label(span, format!("{} defined here", res.descr())); e.span_label( pat_span, diff --git a/tests/ui/did_you_mean/compatible-variants-in-pat.rs b/tests/ui/did_you_mean/compatible-variants-in-pat.rs index 09e12dab2d3fc..5633c28be208f 100644 --- a/tests/ui/did_you_mean/compatible-variants-in-pat.rs +++ b/tests/ui/did_you_mean/compatible-variants-in-pat.rs @@ -21,7 +21,6 @@ fn b(s: Option) { S => { //~^ ERROR mismatched types //~| HELP try wrapping - //~| HELP introduce a new binding instead } _ => {} } @@ -32,7 +31,6 @@ fn c(s: Result) { S => { //~^ ERROR mismatched types //~| HELP try wrapping - //~| HELP introduce a new binding instead } _ => {} } diff --git a/tests/ui/did_you_mean/compatible-variants-in-pat.stderr b/tests/ui/did_you_mean/compatible-variants-in-pat.stderr index 09cf094e6bd72..f18965f5d080c 100644 --- a/tests/ui/did_you_mean/compatible-variants-in-pat.stderr +++ b/tests/ui/did_you_mean/compatible-variants-in-pat.stderr @@ -14,16 +14,10 @@ LL | Foo::Bar(Bar { x }) => { error[E0308]: mismatched types --> $DIR/compatible-variants-in-pat.rs:21:9 | -LL | struct S; - | -------- unit struct defined here -... LL | match s { | - this expression has type `Option` LL | S => { - | ^ - | | - | expected `Option`, found `S` - | `S` is interpreted as a unit struct, not a new binding + | ^ expected `Option`, found `S` | = note: expected enum `Option` found struct `S` @@ -31,25 +25,14 @@ help: try wrapping the pattern in `Some` | LL | Some(S) => { | +++++ + -help: introduce a new binding instead - | -LL - S => { -LL + other_s => { - | error[E0308]: mismatched types - --> $DIR/compatible-variants-in-pat.rs:32:9 + --> $DIR/compatible-variants-in-pat.rs:31:9 | -LL | struct S; - | -------- unit struct defined here -... LL | match s { | - this expression has type `Result` LL | S => { - | ^ - | | - | expected `Result`, found `S` - | `S` is interpreted as a unit struct, not a new binding + | ^ expected `Result`, found `S` | = note: expected enum `Result` found struct `S` @@ -59,11 +42,6 @@ LL | Ok(S) => { | +++ + LL | Err(S) => { | ++++ + -help: introduce a new binding instead - | -LL - S => { -LL + other_s => { - | error: aborting due to 3 previous errors diff --git a/tests/ui/match/issue-12552.stderr b/tests/ui/match/issue-12552.stderr index 397265cd540f1..195192fbd8240 100644 --- a/tests/ui/match/issue-12552.stderr +++ b/tests/ui/match/issue-12552.stderr @@ -20,14 +20,7 @@ LL | match t { | - this expression has type `Result<_, {integer}>` ... LL | None => () - | ^^^^ - | | - | expected `Result<_, {integer}>`, found `Option<_>` - | `None` is interpreted as a unit variant, not a new binding - | - --> $SRC_DIR/core/src/option.rs:LL:COL - | - = note: unit variant defined here + | ^^^^ expected `Result<_, {integer}>`, found `Option<_>` | = note: expected enum `Result<_, {integer}>` found enum `Option<_>` @@ -35,11 +28,6 @@ help: try wrapping the pattern in `Ok` | LL | Ok(None) => () | +++ + -help: introduce a new binding instead - | -LL - None => () -LL + other_none => () - | error: aborting due to 2 previous errors diff --git a/tests/ui/suggestions/suggest-deref-in-match-issue-132784.rs b/tests/ui/suggestions/suggest-deref-in-match-issue-132784.rs index 77074e8c3a3b1..205e57f4a9ff5 100644 --- a/tests/ui/suggestions/suggest-deref-in-match-issue-132784.rs +++ b/tests/ui/suggestions/suggest-deref-in-match-issue-132784.rs @@ -8,7 +8,6 @@ fn main() { //~^ ERROR mismatched types None => {} //~^ ERROR mismatched types - //~| HELP introduce a new binding instead } match &x { @@ -18,7 +17,6 @@ fn main() { //~^ ERROR mismatched types None => {} //~^ ERROR mismatched types - //~| HELP introduce a new binding instead } let mut y = Box::new(Some(1)); @@ -29,7 +27,6 @@ fn main() { //~^ ERROR mismatched types None => {} //~^ ERROR mismatched types - //~| HELP introduce a new binding instead } let mut z = Arc::new(Some(1)); @@ -40,7 +37,6 @@ fn main() { //~^ ERROR mismatched types None => {} //~^ ERROR mismatched types - //~| HELP introduce a new binding instead } let z_const: &Arc> = &z; @@ -51,7 +47,6 @@ fn main() { //~^ ERROR mismatched types None => {} //~^ ERROR mismatched types - //~| HELP introduce a new binding instead } // Normal reference because Arc doesn't implement DerefMut. @@ -63,7 +58,6 @@ fn main() { //~^ ERROR mismatched types None => {} //~^ ERROR mismatched types - //~| HELP introduce a new binding instead } // Mutable reference because Box does implement DerefMut. @@ -75,7 +69,6 @@ fn main() { //~^ ERROR mismatched types None => {} //~^ ERROR mismatched types - //~| HELP introduce a new binding instead } // Difficult expression. @@ -87,6 +80,5 @@ fn main() { //~^ ERROR mismatched types None => {} //~^ ERROR mismatched types - //~| HELP introduce a new binding instead } } diff --git a/tests/ui/suggestions/suggest-deref-in-match-issue-132784.stderr b/tests/ui/suggestions/suggest-deref-in-match-issue-132784.stderr index a5ce44b256004..6092272aa8c5a 100644 --- a/tests/ui/suggestions/suggest-deref-in-match-issue-132784.stderr +++ b/tests/ui/suggestions/suggest-deref-in-match-issue-132784.stderr @@ -21,14 +21,7 @@ LL | match x { | - this expression has type `Arc>` ... LL | None => {} - | ^^^^ - | | - | expected `Arc>`, found `Option<_>` - | `None` is interpreted as a unit variant, not a new binding - | - --> $SRC_DIR/core/src/option.rs:LL:COL - | - = note: unit variant defined here + | ^^^^ expected `Arc>`, found `Option<_>` | = note: expected struct `Arc>` found enum `Option<_>` @@ -36,14 +29,9 @@ help: consider dereferencing to access the inner value using the Deref trait | LL | match *x { | + -help: introduce a new binding instead - | -LL - None => {} -LL + other_none => {} - | error[E0308]: mismatched types - --> $DIR/suggest-deref-in-match-issue-132784.rs:17:9 + --> $DIR/suggest-deref-in-match-issue-132784.rs:16:9 | LL | match &x { | -- this expression has type `&Arc>` @@ -59,20 +47,13 @@ LL | match &*x { | + error[E0308]: mismatched types - --> $DIR/suggest-deref-in-match-issue-132784.rs:19:9 + --> $DIR/suggest-deref-in-match-issue-132784.rs:18:9 | LL | match &x { | -- this expression has type `&Arc>` ... LL | None => {} - | ^^^^ - | | - | expected `Arc>`, found `Option<_>` - | `None` is interpreted as a unit variant, not a new binding - | - --> $SRC_DIR/core/src/option.rs:LL:COL - | - = note: unit variant defined here + | ^^^^ expected `Arc>`, found `Option<_>` | = note: expected struct `Arc>` found enum `Option<_>` @@ -80,14 +61,9 @@ help: consider dereferencing to access the inner value using the Deref trait | LL | match &*x { | + -help: introduce a new binding instead - | -LL - None => {} -LL + other_none => {} - | error[E0308]: mismatched types - --> $DIR/suggest-deref-in-match-issue-132784.rs:28:9 + --> $DIR/suggest-deref-in-match-issue-132784.rs:26:9 | LL | match y { | - this expression has type `Box>` @@ -103,20 +79,13 @@ LL | match *y { | + error[E0308]: mismatched types - --> $DIR/suggest-deref-in-match-issue-132784.rs:30:9 + --> $DIR/suggest-deref-in-match-issue-132784.rs:28:9 | LL | match y { | - this expression has type `Box>` ... LL | None => {} - | ^^^^ - | | - | expected `Box>`, found `Option<_>` - | `None` is interpreted as a unit variant, not a new binding - | - --> $SRC_DIR/core/src/option.rs:LL:COL - | - = note: unit variant defined here + | ^^^^ expected `Box>`, found `Option<_>` | = note: expected struct `Box>` found enum `Option<_>` @@ -124,14 +93,9 @@ help: consider dereferencing to access the inner value using the Deref trait | LL | match *y { | + -help: introduce a new binding instead - | -LL - None => {} -LL + other_none => {} - | error[E0308]: mismatched types - --> $DIR/suggest-deref-in-match-issue-132784.rs:39:9 + --> $DIR/suggest-deref-in-match-issue-132784.rs:36:9 | LL | match z as Arc> { | --------------------- this expression has type `Arc>` @@ -148,20 +112,13 @@ LL + match *(z as Arc>) { | error[E0308]: mismatched types - --> $DIR/suggest-deref-in-match-issue-132784.rs:41:9 + --> $DIR/suggest-deref-in-match-issue-132784.rs:38:9 | LL | match z as Arc> { | --------------------- this expression has type `Arc>` ... LL | None => {} - | ^^^^ - | | - | expected `Arc>`, found `Option<_>` - | `None` is interpreted as a unit variant, not a new binding - | - --> $SRC_DIR/core/src/option.rs:LL:COL - | - = note: unit variant defined here + | ^^^^ expected `Arc>`, found `Option<_>` | = note: expected struct `Arc>` found enum `Option<_>` @@ -170,14 +127,9 @@ help: consider dereferencing to access the inner value using the Deref trait LL - match z as Arc> { LL + match *(z as Arc>) { | -help: introduce a new binding instead - | -LL - None => {} -LL + other_none => {} - | error[E0308]: mismatched types - --> $DIR/suggest-deref-in-match-issue-132784.rs:50:9 + --> $DIR/suggest-deref-in-match-issue-132784.rs:46:9 | LL | match z_const { | ------- this expression has type `&Arc>` @@ -193,20 +145,13 @@ LL | match &**z_const { | +++ error[E0308]: mismatched types - --> $DIR/suggest-deref-in-match-issue-132784.rs:52:9 + --> $DIR/suggest-deref-in-match-issue-132784.rs:48:9 | LL | match z_const { | ------- this expression has type `&Arc>` ... LL | None => {} - | ^^^^ - | | - | expected `Arc>`, found `Option<_>` - | `None` is interpreted as a unit variant, not a new binding - | - --> $SRC_DIR/core/src/option.rs:LL:COL - | - = note: unit variant defined here + | ^^^^ expected `Arc>`, found `Option<_>` | = note: expected struct `Arc>` found enum `Option<_>` @@ -214,14 +159,9 @@ help: consider dereferencing to access the inner value using the Deref trait | LL | match &**z_const { | +++ -help: introduce a new binding instead - | -LL - None => {} -LL + other_none => {} - | error[E0308]: mismatched types - --> $DIR/suggest-deref-in-match-issue-132784.rs:62:9 + --> $DIR/suggest-deref-in-match-issue-132784.rs:57:9 | LL | match z_mut { | ----- this expression has type `&mut Arc>` @@ -237,20 +177,13 @@ LL | match &**z_mut { | +++ error[E0308]: mismatched types - --> $DIR/suggest-deref-in-match-issue-132784.rs:64:9 + --> $DIR/suggest-deref-in-match-issue-132784.rs:59:9 | LL | match z_mut { | ----- this expression has type `&mut Arc>` ... LL | None => {} - | ^^^^ - | | - | expected `Arc>`, found `Option<_>` - | `None` is interpreted as a unit variant, not a new binding - | - --> $SRC_DIR/core/src/option.rs:LL:COL - | - = note: unit variant defined here + | ^^^^ expected `Arc>`, found `Option<_>` | = note: expected struct `Arc>` found enum `Option<_>` @@ -258,14 +191,9 @@ help: consider dereferencing to access the inner value using the Deref trait | LL | match &**z_mut { | +++ -help: introduce a new binding instead - | -LL - None => {} -LL + other_none => {} - | error[E0308]: mismatched types - --> $DIR/suggest-deref-in-match-issue-132784.rs:74:9 + --> $DIR/suggest-deref-in-match-issue-132784.rs:68:9 | LL | match y_mut { | ----- this expression has type `&mut Box>` @@ -281,20 +209,13 @@ LL | match &**y_mut { | +++ error[E0308]: mismatched types - --> $DIR/suggest-deref-in-match-issue-132784.rs:76:9 + --> $DIR/suggest-deref-in-match-issue-132784.rs:70:9 | LL | match y_mut { | ----- this expression has type `&mut Box>` ... LL | None => {} - | ^^^^ - | | - | expected `Box>`, found `Option<_>` - | `None` is interpreted as a unit variant, not a new binding - | - --> $SRC_DIR/core/src/option.rs:LL:COL - | - = note: unit variant defined here + | ^^^^ expected `Box>`, found `Option<_>` | = note: expected struct `Box>` found enum `Option<_>` @@ -302,14 +223,9 @@ help: consider dereferencing to access the inner value using the Deref trait | LL | match &**y_mut { | +++ -help: introduce a new binding instead - | -LL - None => {} -LL + other_none => {} - | error[E0308]: mismatched types - --> $DIR/suggest-deref-in-match-issue-132784.rs:86:9 + --> $DIR/suggest-deref-in-match-issue-132784.rs:79:9 | LL | match (& (&difficult) ) { | ------------------ this expression has type `&&Arc>` @@ -326,20 +242,13 @@ LL + match &*difficult { | error[E0308]: mismatched types - --> $DIR/suggest-deref-in-match-issue-132784.rs:88:9 + --> $DIR/suggest-deref-in-match-issue-132784.rs:81:9 | LL | match (& (&difficult) ) { | ------------------ this expression has type `&&Arc>` ... LL | None => {} - | ^^^^ - | | - | expected `Arc>`, found `Option<_>` - | `None` is interpreted as a unit variant, not a new binding - | - --> $SRC_DIR/core/src/option.rs:LL:COL - | - = note: unit variant defined here + | ^^^^ expected `Arc>`, found `Option<_>` | = note: expected struct `Arc>` found enum `Option<_>` @@ -348,11 +257,6 @@ help: consider dereferencing to access the inner value using the Deref trait LL - match (& (&difficult) ) { LL + match &*difficult { | -help: introduce a new binding instead - | -LL - None => {} -LL + other_none => {} - | error: aborting due to 16 previous errors From 4ecc78d637204bc3690ad0cd733671ce7b7e36ea Mon Sep 17 00:00:00 2001 From: arferreira Date: Sun, 15 Mar 2026 12:39:39 -0400 Subject: [PATCH 4/7] Suppress self-referential associated type constraint suggestion --- .../error_reporting/infer/note_and_explain.rs | 7 +++- ...ont-suggest-self-referential-constraint.rs | 20 +++++++++++ ...suggest-self-referential-constraint.stderr | 33 +++++++++++++++++++ 3 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 tests/ui/associated-types/dont-suggest-self-referential-constraint.rs create mode 100644 tests/ui/associated-types/dont-suggest-self-referential-constraint.stderr diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs index 0fde0009debe7..7f53fdbc2c9f8 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs @@ -263,8 +263,13 @@ impl Trait for X { cause.code(), ); } + // Don't suggest constraining a projection to something + // containing itself, e.g. `Item = &::Item`. (_, ty::Alias(ty::Projection | ty::Inherent, proj_ty)) - if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => + if !tcx.is_impl_trait_in_trait(proj_ty.def_id) + && !tcx + .erase_and_anonymize_regions(values.expected) + .contains(tcx.erase_and_anonymize_regions(values.found)) => { let msg = || { format!( diff --git a/tests/ui/associated-types/dont-suggest-self-referential-constraint.rs b/tests/ui/associated-types/dont-suggest-self-referential-constraint.rs new file mode 100644 index 0000000000000..ad999a1c77356 --- /dev/null +++ b/tests/ui/associated-types/dont-suggest-self-referential-constraint.rs @@ -0,0 +1,20 @@ +// Regression test for #112104. +// +// Don't suggest `Item = &::Item` when +// the expected type wraps the found projection. + +fn option_of_ref_assoc(iter: &mut I) { + let _: Option<&I::Item> = iter.next(); + //~^ ERROR mismatched types +} + +// Valid constraint suggestions should still fire. +trait Foo { + type Assoc; +} + +fn assoc_to_concrete(x: T::Assoc) -> u32 { + x //~ ERROR mismatched types +} + +fn main() {} diff --git a/tests/ui/associated-types/dont-suggest-self-referential-constraint.stderr b/tests/ui/associated-types/dont-suggest-self-referential-constraint.stderr new file mode 100644 index 0000000000000..e6e37cdf7e515 --- /dev/null +++ b/tests/ui/associated-types/dont-suggest-self-referential-constraint.stderr @@ -0,0 +1,33 @@ +error[E0308]: mismatched types + --> $DIR/dont-suggest-self-referential-constraint.rs:7:31 + | +LL | let _: Option<&I::Item> = iter.next(); + | ---------------- ^^^^^^^^^^^ expected `Option<&::Item>`, found `Option<::Item>` + | | + | expected due to this + | + = note: expected enum `Option<&_>` + found enum `Option<_>` +help: try using `.as_ref()` to convert `Option<::Item>` to `Option<&::Item>` + | +LL | let _: Option<&I::Item> = iter.next().as_ref(); + | +++++++++ + +error[E0308]: mismatched types + --> $DIR/dont-suggest-self-referential-constraint.rs:17:5 + | +LL | fn assoc_to_concrete(x: T::Assoc) -> u32 { + | --- expected `u32` because of return type +LL | x + | ^ expected `u32`, found associated type + | + = note: expected type `u32` + found associated type `::Assoc` +help: consider constraining the associated type `::Assoc` to `u32` + | +LL | fn assoc_to_concrete>(x: T::Assoc) -> u32 { + | +++++++++++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. From 567f8bd8223b1f1dc9644e99a74f98784115252d Mon Sep 17 00:00:00 2001 From: Daria Sukhonina Date: Mon, 16 Mar 2026 12:29:12 +0300 Subject: [PATCH 5/7] Cleanup from_cycle_error::variances_of. variances_of currently used search_for_cycle_permutation, which can fail and abort when constructed error result value does not match query input. This commit changes variances_of to receive a def_id which means it can compute a value without using search_for_cycle_permutation, avoiding the possible abort. Fixes #127971 --- .../rustc_query_impl/src/from_cycle_error.rs | 30 ++++--------------- 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_query_impl/src/from_cycle_error.rs b/compiler/rustc_query_impl/src/from_cycle_error.rs index fa508419b52f2..4983b01a1f061 100644 --- a/compiler/rustc_query_impl/src/from_cycle_error.rs +++ b/compiler/rustc_query_impl/src/from_cycle_error.rs @@ -8,13 +8,13 @@ use rustc_errors::codes::*; use rustc_errors::{Applicability, Diag, MultiSpan, pluralize, struct_span_code_err}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; +use rustc_middle::bug; use rustc_middle::dep_graph::DepKind; use rustc_middle::queries::{QueryVTables, TaggedQueryKey}; use rustc_middle::query::CycleError; use rustc_middle::query::erase::erase_val; use rustc_middle::ty::layout::LayoutError; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_middle::{bug, span_bug}; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::{ErrorGuaranteed, Span}; @@ -32,9 +32,9 @@ pub(crate) fn specialize_query_vtables<'tcx>(vtables: &mut QueryVTables<'tcx>) { vtables.check_representability_adt_ty.value_from_cycle_error = |tcx, _, cycle, _err| check_representability(tcx, cycle); - vtables.variances_of.value_from_cycle_error = |tcx, _, cycle, err| { + vtables.variances_of.value_from_cycle_error = |tcx, key, _, err| { let _guar = err.delay_as_bug(); - erase_val(variances_of(tcx, cycle)) + erase_val(variances_of(tcx, key)) }; vtables.layout_of.value_from_cycle_error = |tcx, _, cycle, err| { @@ -105,27 +105,9 @@ fn check_representability<'tcx>(tcx: TyCtxt<'tcx>, cycle_error: CycleError<'tcx> guar.raise_fatal() } -fn variances_of<'tcx>(tcx: TyCtxt<'tcx>, cycle_error: CycleError<'tcx>) -> &'tcx [ty::Variance] { - search_for_cycle_permutation( - &cycle_error.cycle, - |cycle| { - if let Some(frame) = cycle.get(0) - && frame.node.dep_kind == DepKind::variances_of - && let Some(def_id) = frame.node.def_id - { - let n = tcx.generics_of(def_id).own_params.len(); - ControlFlow::Break(tcx.arena.alloc_from_iter(iter::repeat_n(ty::Bivariant, n))) - } else { - ControlFlow::Continue(()) - } - }, - || { - span_bug!( - cycle_error.usage.as_ref().unwrap().span, - "only `variances_of` returns `&[ty::Variance]`" - ) - }, - ) +fn variances_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx [ty::Variance] { + let n = tcx.generics_of(def_id).own_params.len(); + tcx.arena.alloc_from_iter(iter::repeat_n(ty::Bivariant, n)) } // Take a cycle of `Q` and try `try_cycle` on every permutation, falling back to `otherwise`. From cd4fd289cd60a56de47372cec0a260939cc93932 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Mon, 16 Mar 2026 17:36:53 +0100 Subject: [PATCH 6/7] suggest valid features when target feature is invalid --- compiler/rustc_codegen_ssa/src/errors.rs | 34 ++++++++++++------- .../rustc_codegen_ssa/src/target_features.rs | 32 +++++++++++------ tests/ui/target-feature/invalid-attribute.rs | 13 ++++--- .../target-feature/invalid-attribute.stderr | 20 ++++++++--- 4 files changed, 68 insertions(+), 31 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 41337fc21a7b7..e0afcd51b7f41 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -8,7 +8,8 @@ use std::process::ExitStatus; use rustc_errors::codes::*; use rustc_errors::{ - Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, Level, msg, + Diag, DiagArgValue, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee, IntoDiagArg, + Level, msg, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_middle::ty::layout::LayoutError; @@ -1249,20 +1250,29 @@ pub(crate) struct FeatureNotValid<'a> { #[label("`{$feature}` is not valid for this target")] pub span: Span, #[subdiagnostic] - pub plus_hint: Option>, + pub hint: FeatureNotValidHint<'a>, } #[derive(Subdiagnostic)] -#[suggestion( - "consider removing the leading `+` in the feature name", - code = "enable = \"{stripped}\"", - applicability = "maybe-incorrect", - style = "verbose" -)] -pub struct RemovePlusFromFeatureName<'a> { - #[primary_span] - pub span: Span, - pub stripped: &'a str, +pub(crate) enum FeatureNotValidHint<'a> { + #[suggestion( + "consider removing the leading `+` in the feature name", + code = "enable = \"{stripped}\"", + applicability = "maybe-incorrect", + style = "verbose" + )] + RemovePlusFromFeatureName { + #[primary_span] + span: Span, + stripped: &'a str, + }, + #[help( + "valid names are: {$possibilities}{$and_more -> + [0] {\"\"} + *[other] {\" \"}and {$and_more} more + }" + )] + ValidFeatureNames { possibilities: DiagSymbolList<&'a str>, and_more: usize }, } #[derive(Diagnostic)] diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 08a02831312c7..8ac3f0555db27 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -9,12 +9,12 @@ use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_session::lint::builtin::AARCH64_SOFTFLOAT_NEON; use rustc_session::parse::feature_err; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{Span, Symbol, edit_distance, sym}; use rustc_target::spec::Arch; use rustc_target::target_features::{RUSTC_SPECIFIC_FEATURES, Stability}; use smallvec::SmallVec; -use crate::errors::{FeatureNotValid, RemovePlusFromFeatureName}; +use crate::errors::{FeatureNotValid, FeatureNotValidHint}; use crate::{errors, target_features}; /// Compute the enabled target features from the `#[target_feature]` function attribute. @@ -32,15 +32,25 @@ pub(crate) fn from_target_feature_attr( for &(feature, feature_span) in features { let feature_str = feature.as_str(); let Some(stability) = rust_target_features.get(feature_str) else { - let plus_hint = feature_str - .strip_prefix('+') - .filter(|stripped| rust_target_features.contains_key(*stripped)) - .map(|stripped| RemovePlusFromFeatureName { span: feature_span, stripped }); - tcx.dcx().emit_err(FeatureNotValid { - feature: feature_str, - span: feature_span, - plus_hint, - }); + let hint = if let Some(stripped) = feature_str.strip_prefix('+') + && rust_target_features.contains_key(stripped) + { + FeatureNotValidHint::RemovePlusFromFeatureName { span: feature_span, stripped } + } else { + // Show the 5 feature names that are most similar to the input. + let mut valid_names: Vec<_> = + rust_target_features.keys().map(|name| name.as_str()).into_sorted_stable_ord(); + valid_names.sort_by_key(|name| { + edit_distance::edit_distance(name, feature.as_str(), 5).unwrap_or(usize::MAX) + }); + valid_names.truncate(5); + + FeatureNotValidHint::ValidFeatureNames { + possibilities: valid_names.into(), + and_more: rust_target_features.len().saturating_sub(5), + } + }; + tcx.dcx().emit_err(FeatureNotValid { feature: feature_str, span: feature_span, hint }); continue; }; diff --git a/tests/ui/target-feature/invalid-attribute.rs b/tests/ui/target-feature/invalid-attribute.rs index 47068fbb25d49..1022929118bd6 100644 --- a/tests/ui/target-feature/invalid-attribute.rs +++ b/tests/ui/target-feature/invalid-attribute.rs @@ -119,7 +119,12 @@ fn main() { //~| NOTE `+sse2` is not valid for this target unsafe fn hey() {} -#[target_feature(enable = "+sse5")] -//~^ ERROR `+sse5` is not valid for this target -//~| NOTE `+sse5` is not valid for this target -unsafe fn typo() {} +#[target_feature(enable = "sse5")] +//~^ ERROR `sse5` is not valid for this target +//~| NOTE `sse5` is not valid for this target +unsafe fn typo_sse() {} + +#[target_feature(enable = "avx512")] +//~^ ERROR `avx512` is not valid for this target +//~| NOTE `avx512` is not valid for this target +unsafe fn typo_avx512() {} diff --git a/tests/ui/target-feature/invalid-attribute.stderr b/tests/ui/target-feature/invalid-attribute.stderr index fbc35cfdc325e..8b91381a32b38 100644 --- a/tests/ui/target-feature/invalid-attribute.stderr +++ b/tests/ui/target-feature/invalid-attribute.stderr @@ -160,6 +160,8 @@ error: the feature named `foo` is not valid for this target | LL | #[target_feature(enable = "foo")] | ^^^^^^^^^^^^^^ `foo` is not valid for this target + | + = help: valid names are: `fma`, `xop`, `adx`, `aes`, and `avx` and 74 more error[E0046]: not all trait items implemented, missing: `foo` --> $DIR/invalid-attribute.rs:81:1 @@ -205,13 +207,23 @@ LL - #[target_feature(enable = "+sse2")] LL + #[target_feature(enable = "sse2")] | -error: the feature named `+sse5` is not valid for this target +error: the feature named `sse5` is not valid for this target --> $DIR/invalid-attribute.rs:122:18 | -LL | #[target_feature(enable = "+sse5")] - | ^^^^^^^^^^^^^^^^ `+sse5` is not valid for this target +LL | #[target_feature(enable = "sse5")] + | ^^^^^^^^^^^^^^^ `sse5` is not valid for this target + | + = help: valid names are: `sse`, `sse2`, `sse3`, `sse4a`, and `ssse3` and 74 more + +error: the feature named `avx512` is not valid for this target + --> $DIR/invalid-attribute.rs:127:18 + | +LL | #[target_feature(enable = "avx512")] + | ^^^^^^^^^^^^^^^^^ `avx512` is not valid for this target + | + = help: valid names are: `avx512f`, `avx2`, `avx512bw`, `avx512cd`, and `avx512dq` and 74 more -error: aborting due to 25 previous errors +error: aborting due to 26 previous errors Some errors have detailed explanations: E0046, E0053, E0539, E0658. For more information about an error, try `rustc --explain E0046`. From f8bce56b3966c8784060ce875a51f65d18ac659b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Wed, 11 Mar 2026 19:39:47 +0100 Subject: [PATCH 7/7] Don't look for non-type-level assoc consts when checking trait object types --- .../src/hir_ty_lowering/dyn_trait.rs | 5 ++- compiler/rustc_middle/src/ty/assoc.rs | 4 +- compiler/rustc_middle/src/ty/sty.rs | 2 +- .../cfi/typeid/itanium_cxx_abi/transform.rs | 2 +- .../associated-const-in-trait.rs | 2 + .../associated-const-in-trait.stderr | 38 +++++++++++++++++-- tests/ui/associated-item/issue-48027.stderr | 4 +- .../associated-consts.stderr | 4 +- tests/ui/type-alias/lack-of-wfcheck.rs | 27 +++++++++++++ tests/ui/wf/issue-87495.stderr | 9 ++++- 10 files changed, 82 insertions(+), 15 deletions(-) create mode 100644 tests/ui/type-alias/lack-of-wfcheck.rs diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs index 7b8e09943df71..515cca6ac1c16 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs @@ -230,8 +230,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ordered_associated_items.extend( tcx.associated_items(pred.trait_ref.def_id) .in_definition_order() - // Only associated types & consts can possibly be constrained via a binding. - .filter(|item| item.is_type() || item.is_const()) + // Only associated types & type consts can possibly be + // constrained in a trait object type via a binding. + .filter(|item| item.is_type() || item.is_type_const()) // Traits with RPITITs are simply not dyn compatible (for now). .filter(|item| !item.is_impl_trait_in_trait()) .map(|item| (item.def_id, trait_ref)), diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs index 4cc255cba6358..cabe8514ae4be 100644 --- a/compiler/rustc_middle/src/ty/assoc.rs +++ b/compiler/rustc_middle/src/ty/assoc.rs @@ -137,8 +137,8 @@ impl AssocItem { self.kind.as_def_kind() } - pub fn is_const(&self) -> bool { - matches!(self.kind, ty::AssocKind::Const { .. }) + pub fn is_type_const(&self) -> bool { + matches!(self.kind, ty::AssocKind::Const { is_type_const: true, .. }) } pub fn is_fn(&self) -> bool { diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index b449b8f1a406c..780b57c470f36 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -753,7 +753,7 @@ impl<'tcx> Ty<'tcx> { .map(|principal| { tcx.associated_items(principal.def_id()) .in_definition_order() - .filter(|item| item.is_type() || item.is_const()) + .filter(|item| item.is_type() || item.is_type_const()) .filter(|item| !item.is_impl_trait_in_trait()) .filter(|item| !tcx.generics_require_sized_self(item.def_id)) .count() diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs index 90b489258360f..5691ed1469276 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs @@ -239,7 +239,7 @@ fn trait_object_ty<'tcx>(tcx: TyCtxt<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tc .flat_map(|super_poly_trait_ref| { tcx.associated_items(super_poly_trait_ref.def_id()) .in_definition_order() - .filter(|item| item.is_type() || item.is_const()) + .filter(|item| item.is_type() || item.is_type_const()) .filter(|item| !tcx.generics_require_sized_self(item.def_id)) .map(move |assoc_item| { super_poly_trait_ref.map_bound(|super_trait_ref| { diff --git a/tests/ui/associated-consts/associated-const-in-trait.rs b/tests/ui/associated-consts/associated-const-in-trait.rs index 6b0b43feb109c..da68a0fa97c82 100644 --- a/tests/ui/associated-consts/associated-const-in-trait.rs +++ b/tests/ui/associated-consts/associated-const-in-trait.rs @@ -7,6 +7,8 @@ trait Trait { impl dyn Trait { //~^ ERROR the trait `Trait` is not dyn compatible [E0038] const fn n() -> usize { Self::N } + //~^ ERROR the trait `Trait` is not dyn compatible [E0038] + //~| ERROR the trait `Trait` is not dyn compatible [E0038] } fn main() {} diff --git a/tests/ui/associated-consts/associated-const-in-trait.stderr b/tests/ui/associated-consts/associated-const-in-trait.stderr index fb4a55110b4e8..4085f8c990785 100644 --- a/tests/ui/associated-consts/associated-const-in-trait.stderr +++ b/tests/ui/associated-consts/associated-const-in-trait.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `Trait` is not dyn compatible - --> $DIR/associated-const-in-trait.rs:7:10 + --> $DIR/associated-const-in-trait.rs:7:6 | LL | impl dyn Trait { - | ^^^^^ `Trait` is not dyn compatible + | ^^^^^^^^^ `Trait` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit @@ -14,6 +14,38 @@ LL | const N: usize; | ^ ...because it contains associated const `N` = help: consider moving `N` to another trait -error: aborting due to 1 previous error +error[E0038]: the trait `Trait` is not dyn compatible + --> $DIR/associated-const-in-trait.rs:9:29 + | +LL | const fn n() -> usize { Self::N } + | ^^^^ `Trait` is not dyn compatible + | +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit + --> $DIR/associated-const-in-trait.rs:4:11 + | +LL | trait Trait { + | ----- this trait is not dyn compatible... +LL | const N: usize; + | ^ ...because it contains associated const `N` + = help: consider moving `N` to another trait + +error[E0038]: the trait `Trait` is not dyn compatible + --> $DIR/associated-const-in-trait.rs:9:29 + | +LL | const fn n() -> usize { Self::N } + | ^^^^^^^ `Trait` is not dyn compatible + | +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit + --> $DIR/associated-const-in-trait.rs:4:11 + | +LL | trait Trait { + | ----- this trait is not dyn compatible... +LL | const N: usize; + | ^ ...because it contains associated const `N` + = help: consider moving `N` to another trait + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/associated-item/issue-48027.stderr b/tests/ui/associated-item/issue-48027.stderr index 7abcabc1c79d8..978c377d438ac 100644 --- a/tests/ui/associated-item/issue-48027.stderr +++ b/tests/ui/associated-item/issue-48027.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `Bar` is not dyn compatible - --> $DIR/issue-48027.rs:6:10 + --> $DIR/issue-48027.rs:6:6 | LL | impl dyn Bar {} - | ^^^ `Bar` is not dyn compatible + | ^^^^^^^ `Bar` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit diff --git a/tests/ui/dyn-compatibility/associated-consts.stderr b/tests/ui/dyn-compatibility/associated-consts.stderr index a92557ea7b8bd..11d02dd2904c8 100644 --- a/tests/ui/dyn-compatibility/associated-consts.stderr +++ b/tests/ui/dyn-compatibility/associated-consts.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `Bar` is not dyn compatible - --> $DIR/associated-consts.rs:8:35 + --> $DIR/associated-consts.rs:8:31 | LL | fn make_bar(t: &T) -> &dyn Bar { - | ^^^ `Bar` is not dyn compatible + | ^^^^^^^ `Bar` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit diff --git a/tests/ui/type-alias/lack-of-wfcheck.rs b/tests/ui/type-alias/lack-of-wfcheck.rs new file mode 100644 index 0000000000000..91fbee8d3f198 --- /dev/null +++ b/tests/ui/type-alias/lack-of-wfcheck.rs @@ -0,0 +1,27 @@ +// Demonstrate that we don't check the definition site of (eager) type aliases for well-formedness. +// +// Listed below are ill-formed type system entities which we don't reject since they appear inside +// the definition of (eager) type aliases. These type aliases are intentionally not referenced from +// anywhere to prevent the eagerly expanded / instantiated aliased types from getting wfchecked +// since that's not what we're testing here. + +//@ check-pass + +type UnsatTraitBound0 = [str]; // `str: Sized` unsatisfied +type UnsatTraitBound1> = T; // `str: Sized` unsatisfied +type UnsatOutlivesBound<'a> = &'static &'a (); // `'a: 'static` unsatisfied + +type Diverging = [(); panic!()]; // `panic!()` diverging + +type DynIncompat0 = dyn Sized; // `Sized` axiomatically dyn incompatible +// issue: +type DynIncompat1 = dyn HasAssocConst; // dyn incompatible due to (non-type-level) assoc const + +// * dyn incompatible due to GAT +// * `'a: 'static`, `String: Copy` and `[u8]: Sized` unsatisfied, `loop {}` diverging +type Several<'a> = dyn HasGenericAssocType = [u8]>; + +trait HasAssocConst { const N: usize; } +trait HasGenericAssocType { type Type<'a: 'static, T: Copy, const N: usize>; } + +fn main() {} diff --git a/tests/ui/wf/issue-87495.stderr b/tests/ui/wf/issue-87495.stderr index 49651e8d6c05c..42e3e2608d732 100644 --- a/tests/ui/wf/issue-87495.stderr +++ b/tests/ui/wf/issue-87495.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `T` is not dyn compatible - --> $DIR/issue-87495.rs:4:29 + --> $DIR/issue-87495.rs:4:25 | LL | const CONST: (bool, dyn T); - | ^ `T` is not dyn compatible + | ^^^^^ `T` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit @@ -13,6 +13,11 @@ LL | trait T { LL | const CONST: (bool, dyn T); | ^^^^^ ...because it contains associated const `CONST` = help: consider moving `CONST` to another trait +help: you might have meant to use `Self` to refer to the implementing type + | +LL - const CONST: (bool, dyn T); +LL + const CONST: (bool, Self); + | error: aborting due to 1 previous error