From 5f04f98c9aaf04e5f670e04dc12d4665489859fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 7 Jan 2025 22:06:58 +0000 Subject: [PATCH 1/3] Ensure that we don't try to access fields on a non-struct pattern type in diagnostic Fix #135209. --- .../rustc_resolve/src/late/diagnostics.rs | 4 ++- ...uct-pattern-on-non-struct-resolve-error.rs | 7 +++++ ...pattern-on-non-struct-resolve-error.stderr | 28 +++++++++++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 tests/ui/pattern/struct-pattern-on-non-struct-resolve-error.rs create mode 100644 tests/ui/pattern/struct-pattern-on-non-struct-resolve-error.stderr diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 6ee02e9f47f15..3957a057fdbce 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1130,7 +1130,9 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { let None = following_seg else { return }; for rib in self.ribs[ValueNS].iter().rev() { for (def_id, spans) in &rib.patterns_with_skipped_bindings { - if let Some(fields) = self.r.field_idents(*def_id) { + if let DefKind::Struct = self.r.tcx.def_kind(*def_id) + && let Some(fields) = self.r.field_idents(*def_id) + { for field in fields { if field.name == segment.ident.name { if spans.iter().all(|(_, had_error)| had_error.is_err()) { diff --git a/tests/ui/pattern/struct-pattern-on-non-struct-resolve-error.rs b/tests/ui/pattern/struct-pattern-on-non-struct-resolve-error.rs new file mode 100644 index 0000000000000..c74c77fea60f4 --- /dev/null +++ b/tests/ui/pattern/struct-pattern-on-non-struct-resolve-error.rs @@ -0,0 +1,7 @@ +// Regression test for #135209. +// We ensure that we don't try to access fields on a non-struct pattern type. +fn main() { + if let Iterator::Item { .. } = 1 { //~ ERROR E0223 + x //~ ERROR E0425 + } +} diff --git a/tests/ui/pattern/struct-pattern-on-non-struct-resolve-error.stderr b/tests/ui/pattern/struct-pattern-on-non-struct-resolve-error.stderr new file mode 100644 index 0000000000000..e31b19ab6bcbf --- /dev/null +++ b/tests/ui/pattern/struct-pattern-on-non-struct-resolve-error.stderr @@ -0,0 +1,28 @@ +error[E0425]: cannot find value `x` in this scope + --> $DIR/struct-pattern-on-non-struct-resolve-error.rs:5:9 + | +LL | x + | ^ not found in this scope + +error[E0223]: ambiguous associated type + --> $DIR/struct-pattern-on-non-struct-resolve-error.rs:4:12 + | +LL | if let Iterator::Item { .. } = 1 { + | ^^^^^^^^^^^^^^ + | +help: use fully-qualified syntax + | +LL | if let as Iterator>::Item { .. } = 1 { + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | if let ::Item { .. } = 1 { + | ~~~~~~~~~~~~~~~~~~~~~~~~ +LL | if let ::Item { .. } = 1 { + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | if let as Iterator>::Item { .. } = 1 { + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + and 71 other candidates + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0223, E0425. +For more information about an error, try `rustc --explain E0223`. From d44f021904e3d5b2870e3c835cbad5e1421e83ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 8 Jan 2025 00:10:16 +0000 Subject: [PATCH 2/3] Add check for missing fields in enum variant pattern --- compiler/rustc_resolve/src/late/diagnostics.rs | 2 +- ...ct-pattern-with-missing-fields-resolve-error.rs | 9 +++++++++ ...attern-with-missing-fields-resolve-error.stderr | 14 +++++++++++--- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 3957a057fdbce..d15eca6927010 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1130,7 +1130,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { let None = following_seg else { return }; for rib in self.ribs[ValueNS].iter().rev() { for (def_id, spans) in &rib.patterns_with_skipped_bindings { - if let DefKind::Struct = self.r.tcx.def_kind(*def_id) + if let DefKind::Struct | DefKind::Variant = self.r.tcx.def_kind(*def_id) && let Some(fields) = self.r.field_idents(*def_id) { for field in fields { diff --git a/tests/ui/pattern/struct-pattern-with-missing-fields-resolve-error.rs b/tests/ui/pattern/struct-pattern-with-missing-fields-resolve-error.rs index 225891e390ff5..39f9f5a2c0208 100644 --- a/tests/ui/pattern/struct-pattern-with-missing-fields-resolve-error.rs +++ b/tests/ui/pattern/struct-pattern-with-missing-fields-resolve-error.rs @@ -3,6 +3,10 @@ struct Website { title: Option, } +enum Foo { + Bar { a: i32 }, +} + fn main() { let website = Website { url: "http://www.example.com".into(), @@ -18,4 +22,9 @@ fn main() { println!("[{}]({})", title, url); //~ ERROR cannot find value `title` in this scope //~^ NOTE not found in this scope } + + let x = Foo::Bar { a: 1 }; + if let Foo::Bar { .. } = x { //~ NOTE this pattern + println!("{a}"); //~ ERROR cannot find value `a` in this scope + } } diff --git a/tests/ui/pattern/struct-pattern-with-missing-fields-resolve-error.stderr b/tests/ui/pattern/struct-pattern-with-missing-fields-resolve-error.stderr index 80fcd714400d6..b985b771754ee 100644 --- a/tests/ui/pattern/struct-pattern-with-missing-fields-resolve-error.stderr +++ b/tests/ui/pattern/struct-pattern-with-missing-fields-resolve-error.stderr @@ -1,5 +1,5 @@ error: expected `,` - --> $DIR/struct-pattern-with-missing-fields-resolve-error.rs:12:31 + --> $DIR/struct-pattern-with-missing-fields-resolve-error.rs:16:31 | LL | if let Website { url, Some(title) } = website { | ------- ^ @@ -7,13 +7,21 @@ LL | if let Website { url, Some(title) } = website { | while parsing the fields for this pattern error[E0425]: cannot find value `title` in this scope - --> $DIR/struct-pattern-with-missing-fields-resolve-error.rs:18:30 + --> $DIR/struct-pattern-with-missing-fields-resolve-error.rs:22:30 | LL | if let Website { url, .. } = website { | ------------------- this pattern doesn't include `title`, which is available in `Website` LL | println!("[{}]({})", title, url); | ^^^^^ not found in this scope -error: aborting due to 2 previous errors +error[E0425]: cannot find value `a` in this scope + --> $DIR/struct-pattern-with-missing-fields-resolve-error.rs:28:20 + | +LL | if let Foo::Bar { .. } = x { + | --------------- this pattern doesn't include `a`, which is available in `Bar` +LL | println!("{a}"); + | ^ help: a local variable with a similar name exists: `x` + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0425`. From 592f2c90da6a6e1b25b3b9c2f13a2e0cfb83dcfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 8 Jan 2025 00:13:43 +0000 Subject: [PATCH 3/3] modify test to side-step platform-dependent stderr output --- ...uct-pattern-on-non-struct-resolve-error.rs | 5 ++- ...pattern-on-non-struct-resolve-error.stderr | 40 +++++++++++-------- 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/tests/ui/pattern/struct-pattern-on-non-struct-resolve-error.rs b/tests/ui/pattern/struct-pattern-on-non-struct-resolve-error.rs index c74c77fea60f4..17a5bad0e6c0f 100644 --- a/tests/ui/pattern/struct-pattern-on-non-struct-resolve-error.rs +++ b/tests/ui/pattern/struct-pattern-on-non-struct-resolve-error.rs @@ -1,7 +1,10 @@ // Regression test for #135209. // We ensure that we don't try to access fields on a non-struct pattern type. fn main() { - if let Iterator::Item { .. } = 1 { //~ ERROR E0223 + if let as Iterator>::Item { .. } = 1 { + //~^ ERROR E0658 + //~| ERROR E0071 + //~| ERROR E0277 x //~ ERROR E0425 } } diff --git a/tests/ui/pattern/struct-pattern-on-non-struct-resolve-error.stderr b/tests/ui/pattern/struct-pattern-on-non-struct-resolve-error.stderr index e31b19ab6bcbf..793c2d1e97fc0 100644 --- a/tests/ui/pattern/struct-pattern-on-non-struct-resolve-error.stderr +++ b/tests/ui/pattern/struct-pattern-on-non-struct-resolve-error.stderr @@ -1,28 +1,34 @@ error[E0425]: cannot find value `x` in this scope - --> $DIR/struct-pattern-on-non-struct-resolve-error.rs:5:9 + --> $DIR/struct-pattern-on-non-struct-resolve-error.rs:8:9 | LL | x | ^ not found in this scope -error[E0223]: ambiguous associated type +error[E0658]: usage of qualified paths in this context is experimental --> $DIR/struct-pattern-on-non-struct-resolve-error.rs:4:12 | -LL | if let Iterator::Item { .. } = 1 { - | ^^^^^^^^^^^^^^ +LL | if let as Iterator>::Item { .. } = 1 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: use fully-qualified syntax + = note: see issue #86935 for more information + = help: add `#![feature(more_qualified_paths)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0071]: expected struct, variant or union type, found inferred type + --> $DIR/struct-pattern-on-non-struct-resolve-error.rs:4:12 + | +LL | if let as Iterator>::Item { .. } = 1 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a struct + +error[E0277]: `Vec<()>` is not an iterator + --> $DIR/struct-pattern-on-non-struct-resolve-error.rs:4:12 + | +LL | if let as Iterator>::Item { .. } = 1 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Vec<()>` is not an iterator | -LL | if let as Iterator>::Item { .. } = 1 { - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -LL | if let ::Item { .. } = 1 { - | ~~~~~~~~~~~~~~~~~~~~~~~~ -LL | if let ::Item { .. } = 1 { - | ~~~~~~~~~~~~~~~~~~~~~~~~~~ -LL | if let as Iterator>::Item { .. } = 1 { - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - and 71 other candidates + = help: the trait `Iterator` is not implemented for `Vec<()>` -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors -Some errors have detailed explanations: E0223, E0425. -For more information about an error, try `rustc --explain E0223`. +Some errors have detailed explanations: E0071, E0277, E0425, E0658. +For more information about an error, try `rustc --explain E0071`.