From fe37adab4b378d68eda8a8893339606d7f381465 Mon Sep 17 00:00:00 2001 From: Zachary S Date: Thu, 30 Jan 2025 16:28:00 -0600 Subject: [PATCH 1/4] Suggest using :: instead of . in more cases. When `Foo.field` or `Foo.method()` exprs are encountered, suggest `Foo::field` or `Foo::method()` when Foo is a type alias, not just a struct, trait, or module. Also rename test for this suggestion from issue-22692.rs to something more meaningful. --- .../rustc_resolve/src/late/diagnostics.rs | 16 +++--- src/tools/tidy/src/issues.txt | 1 - ...tation-type-namespace-suggest-path-sep.rs} | 20 ++++++++ ...on-type-namespace-suggest-path-sep.stderr} | 51 +++++++++++++++---- 4 files changed, 69 insertions(+), 19 deletions(-) rename tests/ui/resolve/{issue-22692.rs => dot-notation-type-namespace-suggest-path-sep.rs} (77%) rename tests/ui/resolve/{issue-22692.stderr => dot-notation-type-namespace-suggest-path-sep.stderr} (68%) diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 0962865e7f190..524915b44e789 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1566,7 +1566,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } }; - let mut bad_struct_syntax_suggestion = |this: &mut Self, def_id: DefId| { + let bad_struct_syntax_suggestion = |this: &mut Self, err: &mut Diag<'_>, def_id: DefId| { let (followed_by_brace, closing_brace) = this.followed_by_brace(span); match source { @@ -1740,12 +1740,10 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } } ( - Res::Def(kind @ (DefKind::Mod | DefKind::Trait), _), + Res::Def(kind @ (DefKind::Mod | DefKind::Trait | DefKind::TyAlias), _), PathSource::Expr(Some(parent)), - ) => { - if !path_sep(self, err, parent, kind) { - return false; - } + ) if path_sep(self, err, parent, kind) => { + return true; } ( Res::Def(DefKind::Enum, def_id), @@ -1777,13 +1775,13 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { let (ctor_def, ctor_vis, fields) = if let Some(struct_ctor) = struct_ctor { if let PathSource::Expr(Some(parent)) = source { if let ExprKind::Field(..) | ExprKind::MethodCall(..) = parent.kind { - bad_struct_syntax_suggestion(self, def_id); + bad_struct_syntax_suggestion(self, err, def_id); return true; } } struct_ctor } else { - bad_struct_syntax_suggestion(self, def_id); + bad_struct_syntax_suggestion(self, err, def_id); return true; }; @@ -1861,7 +1859,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { err.span_label(span, "constructor is not visible here due to private fields"); } (Res::Def(DefKind::Union | DefKind::Variant, def_id), _) if ns == ValueNS => { - bad_struct_syntax_suggestion(self, def_id); + bad_struct_syntax_suggestion(self, err, def_id); } (Res::Def(DefKind::Ctor(_, CtorKind::Const), def_id), _) if ns == ValueNS => { match source { diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 39c9a148e9e56..1cb47353469fa 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -3619,7 +3619,6 @@ ui/resolve/issue-21221-1.rs ui/resolve/issue-21221-2.rs ui/resolve/issue-21221-3.rs ui/resolve/issue-21221-4.rs -ui/resolve/issue-22692.rs ui/resolve/issue-2330.rs ui/resolve/issue-23305.rs ui/resolve/issue-2356.rs diff --git a/tests/ui/resolve/issue-22692.rs b/tests/ui/resolve/dot-notation-type-namespace-suggest-path-sep.rs similarity index 77% rename from tests/ui/resolve/issue-22692.rs rename to tests/ui/resolve/dot-notation-type-namespace-suggest-path-sep.rs index 31a76261408ef..104d11f685cc9 100644 --- a/tests/ui/resolve/issue-22692.rs +++ b/tests/ui/resolve/dot-notation-type-namespace-suggest-path-sep.rs @@ -1,3 +1,11 @@ +// see also https://github.com/rust-lang/rust/issues/22692 + +type Alias = Vec; + +mod foo { + fn bar() {} +} + fn main() { let _ = String.new(); //~^ ERROR expected value, found struct `String` @@ -10,6 +18,18 @@ fn main() { let _ = Vec::<()>.with_capacity(1); //~^ ERROR expected value, found struct `Vec` //~| HELP use the path separator + + let _ = Alias.new(); + //~^ ERROR expected value, found type alias `Alias` + //~| HELP use the path separator + + let _ = Alias.default; + //~^ ERROR expected value, found type alias `Alias` + //~| HELP use the path separator + + let _ = foo.bar; + //~^ ERROR expected value, found module `foo` + //~| HELP use the path separator } macro_rules! Type { diff --git a/tests/ui/resolve/issue-22692.stderr b/tests/ui/resolve/dot-notation-type-namespace-suggest-path-sep.stderr similarity index 68% rename from tests/ui/resolve/issue-22692.stderr rename to tests/ui/resolve/dot-notation-type-namespace-suggest-path-sep.stderr index 546f12b35c156..a5397306b01e4 100644 --- a/tests/ui/resolve/issue-22692.stderr +++ b/tests/ui/resolve/dot-notation-type-namespace-suggest-path-sep.stderr @@ -1,5 +1,5 @@ error[E0423]: expected value, found struct `String` - --> $DIR/issue-22692.rs:2:13 + --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:10:13 | LL | let _ = String.new(); | ^^^^^^ @@ -11,7 +11,7 @@ LL + let _ = String::new(); | error[E0423]: expected value, found struct `String` - --> $DIR/issue-22692.rs:6:13 + --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:14:13 | LL | let _ = String.default; | ^^^^^^ @@ -23,7 +23,7 @@ LL + let _ = String::default; | error[E0423]: expected value, found struct `Vec` - --> $DIR/issue-22692.rs:10:13 + --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:18:13 | LL | let _ = Vec::<()>.with_capacity(1); | ^^^^^^^^^ @@ -34,8 +34,41 @@ LL - let _ = Vec::<()>.with_capacity(1); LL + let _ = Vec::<()>::with_capacity(1); | +error[E0423]: expected value, found type alias `Alias` + --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:22:13 + | +LL | let _ = Alias.new(); + | ^^^^^ + | +help: use the path separator to refer to an item + | +LL | let _ = Alias::new(); + | ~~ + +error[E0423]: expected value, found type alias `Alias` + --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:26:13 + | +LL | let _ = Alias.default; + | ^^^^^ + | +help: use the path separator to refer to an item + | +LL | let _ = Alias::default; + | ~~ + +error[E0423]: expected value, found module `foo` + --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:30:13 + | +LL | let _ = foo.bar; + | ^^^ + | +help: use the path separator to refer to an item + | +LL | let _ = foo::bar; + | ~~ + error[E0423]: expected value, found struct `std::cell::Cell` - --> $DIR/issue-22692.rs:17:9 + --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:37:9 | LL | ::std::cell::Cell | ^^^^^^^^^^^^^^^^^ @@ -51,7 +84,7 @@ LL + ::get(); | error[E0423]: expected value, found struct `std::cell::Cell` - --> $DIR/issue-22692.rs:17:9 + --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:37:9 | LL | ::std::cell::Cell | ^^^^^^^^^^^^^^^^^ @@ -67,7 +100,7 @@ LL + ::get; | error[E0423]: expected value, found struct `Vec` - --> $DIR/issue-22692.rs:26:9 + --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:46:9 | LL | Vec.new() | ^^^ @@ -83,7 +116,7 @@ LL + Vec::new() | error[E0423]: expected value, found struct `Vec` - --> $DIR/issue-22692.rs:31:9 + --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:51:9 | LL | Vec.new | ^^^ @@ -99,7 +132,7 @@ LL + Vec::new | error[E0423]: expected value, found struct `std::cell::Cell` - --> $DIR/issue-22692.rs:17:9 + --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:37:9 | LL | ::std::cell::Cell | ^^^^^^^^^^^^^^^^^ @@ -114,6 +147,6 @@ LL - Type!().new(0) LL + ::new(0) | -error: aborting due to 8 previous errors +error: aborting due to 11 previous errors For more information about this error, try `rustc --explain E0423`. From bfde43c84bfb35fd0d7c7ea46f8cdb0d682ef680 Mon Sep 17 00:00:00 2001 From: Zachary S Date: Thu, 30 Jan 2025 20:45:30 -0600 Subject: [PATCH 2/4] Suggest using :: instead of . for enums in some cases. Suggest replacing `.` with `::` when encountering "expected value, found enum": - in a method-call expression and the method has the same name as a tuple variant - in a field-access expression and the field has the same name as a unit or tuple variant --- .../rustc_resolve/src/late/diagnostics.rs | 70 ++++-- .../enum-expected-value-suggest-variants.rs | 58 +++++ ...num-expected-value-suggest-variants.stderr | 225 ++++++++++++++++++ 3 files changed, 339 insertions(+), 14 deletions(-) create mode 100644 tests/ui/resolve/enum-expected-value-suggest-variants.rs create mode 100644 tests/ui/resolve/enum-expected-value-suggest-variants.stderr diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 524915b44e789..2731efdba48bd 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -8,7 +8,7 @@ use rustc_ast::ptr::P; use rustc_ast::visit::{FnCtxt, FnKind, LifetimeCtxt, Visitor, walk_ty}; use rustc_ast::{ self as ast, AssocItemKind, DUMMY_NODE_ID, Expr, ExprKind, GenericParam, GenericParamKind, - Item, ItemKind, MethodCall, NodeId, Path, Ty, TyKind, + Item, ItemKind, MethodCall, NodeId, Path, PathSegment, Ty, TyKind, }; use rustc_ast_pretty::pprust::where_bound_predicate_to_string; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; @@ -2469,31 +2469,73 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { def_id: DefId, span: Span, ) { - let Some(variants) = self.collect_enum_ctors(def_id) else { + let Some(variant_ctors) = self.collect_enum_ctors(def_id) else { err.note("you might have meant to use one of the enum's variants"); return; }; - let suggest_only_tuple_variants = - matches!(source, PathSource::TupleStruct(..)) || source.is_call(); - if suggest_only_tuple_variants { + // If the expression is a field-access or method-call, try to find a variant with the field/method name + // that could have been intended, and suggest replacing the `.` with `::`. + // Otherwise, suggest adding `::VariantName` after the enum; + // and if the expression is call-like, only suggest tuple variants. + let (suggest_path_sep_dot_span, suggest_only_tuple_variants) = match source { + // `Type(a, b)` in a pattern, only suggest adding a tuple variant after `Type`. + PathSource::TupleStruct(..) => (None, true), + PathSource::Expr(Some(expr)) => match &expr.kind { + // `Type(a, b)`, only suggest adding a tuple variant after `Type`. + ExprKind::Call(..) => (None, true), + // `Type.Foo(a, b)`, suggest replacing `.` -> `::` if variant `Foo` exists and is a tuple variant, + // otherwise suggest adding a variant after `Type`. + ExprKind::MethodCall(box MethodCall { + receiver, + span, + seg: PathSegment { ident, .. }, + .. + }) => { + let dot_span = receiver.span.between(*span); + let found_tuple_variant = variant_ctors.iter().any(|(path, _, ctor_kind)| { + *ctor_kind == CtorKind::Fn + && path.segments.last().is_some_and(|seg| seg.ident == *ident) + }); + (found_tuple_variant.then_some(dot_span), false) + } + // `Type.Foo`, suggest replacing `.` -> `::` if variant `Foo` exists and is a unit or tuple variant, + // otherwise suggest adding a variant after `Type`. + ExprKind::Field(base, ident) => { + let dot_span = base.span.between(ident.span); + let found_tuple_or_unit_variant = variant_ctors.iter().any(|(path, ..)| { + path.segments.last().is_some_and(|seg| seg.ident == *ident) + }); + (found_tuple_or_unit_variant.then_some(dot_span), false) + } + _ => (None, false), + }, + _ => (None, false), + }; + + if let Some(dot_span) = suggest_path_sep_dot_span { + err.span_suggestion_verbose( + dot_span, + "use the path separator to refer to a variant", + "::", + Applicability::MaybeIncorrect, + ); + } else if suggest_only_tuple_variants { // Suggest only tuple variants regardless of whether they have fields and do not // suggest path with added parentheses. - let mut suggestable_variants = variants + let mut suggestable_variants = variant_ctors .iter() .filter(|(.., kind)| *kind == CtorKind::Fn) .map(|(variant, ..)| path_names_to_string(variant)) .collect::>(); suggestable_variants.sort(); - let non_suggestable_variant_count = variants.len() - suggestable_variants.len(); + let non_suggestable_variant_count = variant_ctors.len() - suggestable_variants.len(); - let source_msg = if source.is_call() { - "to construct" - } else if matches!(source, PathSource::TupleStruct(..)) { + let source_msg = if matches!(source, PathSource::TupleStruct(..)) { "to match against" } else { - unreachable!() + "to construct" }; if !suggestable_variants.is_empty() { @@ -2512,7 +2554,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } // If the enum has no tuple variants.. - if non_suggestable_variant_count == variants.len() { + if non_suggestable_variant_count == variant_ctors.len() { err.help(format!("the enum has no tuple variants {source_msg}")); } @@ -2535,7 +2577,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } }; - let mut suggestable_variants = variants + let mut suggestable_variants = variant_ctors .iter() .filter(|(_, def_id, kind)| !needs_placeholder(*def_id, *kind)) .map(|(variant, _, kind)| (path_names_to_string(variant), kind)) @@ -2562,7 +2604,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { ); } - let mut suggestable_variants_with_placeholders = variants + let mut suggestable_variants_with_placeholders = variant_ctors .iter() .filter(|(_, def_id, kind)| needs_placeholder(*def_id, *kind)) .map(|(variant, _, kind)| (path_names_to_string(variant), kind)) diff --git a/tests/ui/resolve/enum-expected-value-suggest-variants.rs b/tests/ui/resolve/enum-expected-value-suggest-variants.rs new file mode 100644 index 0000000000000..9f86a0a1ecc76 --- /dev/null +++ b/tests/ui/resolve/enum-expected-value-suggest-variants.rs @@ -0,0 +1,58 @@ +enum Foo { + //~^ HELP consider importing this tuple variant + A(u32), + B(u32), +} + +enum Bar { + C(u32), + D(u32), + E, + F, +} + +fn main() { + let _: Foo = Foo(0); + //~^ ERROR expected function + //~| HELP try to construct one of the enum's variants + + let _: Foo = Foo.A(0); + //~^ ERROR expected value, found enum `Foo` + //~| HELP use the path separator to refer to a variant + + let _: Foo = Foo.Bad(0); + //~^ ERROR expected value, found enum `Foo` + //~| HELP the following enum variants are available + + let _: Bar = Bar(0); + //~^ ERROR expected function + //~| HELP try to construct one of the enum's variants + //~| HELP you might have meant to construct one of the enum's non-tuple variants + + let _: Bar = Bar.C(0); + //~^ ERROR expected value, found enum `Bar` + //~| HELP use the path separator to refer to a variant + + let _: Bar = Bar.E; + //~^ ERROR expected value, found enum `Bar` + //~| HELP use the path separator to refer to a variant + + let _: Bar = Bar.Bad(0); + //~^ ERROR expected value, found enum `Bar` + //~| HELP you might have meant to use one of the following enum variants + //~| HELP alternatively, the following enum variants are also available + + let _: Bar = Bar.Bad; + //~^ ERROR expected value, found enum `Bar` + //~| HELP you might have meant to use one of the following enum variants + //~| HELP alternatively, the following enum variants are also available + + match Foo::A(42) { + A(..) => {} + //~^ ERROR cannot find tuple struct or tuple variant `A` in this scope + Foo(..) => {} + //~^ ERROR expected tuple struct or tuple variant + //~| HELP try to match against one of the enum's variants + _ => {} + } +} diff --git a/tests/ui/resolve/enum-expected-value-suggest-variants.stderr b/tests/ui/resolve/enum-expected-value-suggest-variants.stderr new file mode 100644 index 0000000000000..0bd6069b27206 --- /dev/null +++ b/tests/ui/resolve/enum-expected-value-suggest-variants.stderr @@ -0,0 +1,225 @@ +error[E0423]: expected value, found enum `Foo` + --> $DIR/enum-expected-value-suggest-variants.rs:19:18 + | +LL | let _: Foo = Foo.A(0); + | ^^^ + | +note: the enum is defined here + --> $DIR/enum-expected-value-suggest-variants.rs:1:1 + | +LL | / enum Foo { +LL | | +LL | | A(u32), +LL | | B(u32), +LL | | } + | |_^ +help: use the path separator to refer to a variant + | +LL | let _: Foo = Foo::A(0); + | ~~ + +error[E0423]: expected value, found enum `Foo` + --> $DIR/enum-expected-value-suggest-variants.rs:23:18 + | +LL | let _: Foo = Foo.Bad(0); + | ^^^ + | +note: the enum is defined here + --> $DIR/enum-expected-value-suggest-variants.rs:1:1 + | +LL | / enum Foo { +LL | | +LL | | A(u32), +LL | | B(u32), +LL | | } + | |_^ +help: the following enum variants are available + | +LL | let _: Foo = (Foo::A(/* fields */)).Bad(0); + | ~~~~~~~~~~~~~~~~~~~~~~ +LL | let _: Foo = (Foo::B(/* fields */)).Bad(0); + | ~~~~~~~~~~~~~~~~~~~~~~ + +error[E0423]: expected value, found enum `Bar` + --> $DIR/enum-expected-value-suggest-variants.rs:32:18 + | +LL | let _: Bar = Bar.C(0); + | ^^^ + | +note: the enum is defined here + --> $DIR/enum-expected-value-suggest-variants.rs:7:1 + | +LL | / enum Bar { +LL | | C(u32), +LL | | D(u32), +LL | | E, +LL | | F, +LL | | } + | |_^ +help: use the path separator to refer to a variant + | +LL | let _: Bar = Bar::C(0); + | ~~ + +error[E0423]: expected value, found enum `Bar` + --> $DIR/enum-expected-value-suggest-variants.rs:36:18 + | +LL | let _: Bar = Bar.E; + | ^^^ + | +note: the enum is defined here + --> $DIR/enum-expected-value-suggest-variants.rs:7:1 + | +LL | / enum Bar { +LL | | C(u32), +LL | | D(u32), +LL | | E, +LL | | F, +LL | | } + | |_^ +help: use the path separator to refer to a variant + | +LL | let _: Bar = Bar::E; + | ~~ + +error[E0423]: expected value, found enum `Bar` + --> $DIR/enum-expected-value-suggest-variants.rs:40:18 + | +LL | let _: Bar = Bar.Bad(0); + | ^^^ + | +note: the enum is defined here + --> $DIR/enum-expected-value-suggest-variants.rs:7:1 + | +LL | / enum Bar { +LL | | C(u32), +LL | | D(u32), +LL | | E, +LL | | F, +LL | | } + | |_^ +help: you might have meant to use one of the following enum variants + | +LL | let _: Bar = Bar::E.Bad(0); + | ~~~~~~ +LL | let _: Bar = Bar::F.Bad(0); + | ~~~~~~ +help: alternatively, the following enum variants are also available + | +LL | let _: Bar = (Bar::C(/* fields */)).Bad(0); + | ~~~~~~~~~~~~~~~~~~~~~~ +LL | let _: Bar = (Bar::D(/* fields */)).Bad(0); + | ~~~~~~~~~~~~~~~~~~~~~~ + +error[E0423]: expected value, found enum `Bar` + --> $DIR/enum-expected-value-suggest-variants.rs:45:18 + | +LL | let _: Bar = Bar.Bad; + | ^^^ + | +note: the enum is defined here + --> $DIR/enum-expected-value-suggest-variants.rs:7:1 + | +LL | / enum Bar { +LL | | C(u32), +LL | | D(u32), +LL | | E, +LL | | F, +LL | | } + | |_^ +help: you might have meant to use one of the following enum variants + | +LL | let _: Bar = Bar::E.Bad; + | ~~~~~~ +LL | let _: Bar = Bar::F.Bad; + | ~~~~~~ +help: alternatively, the following enum variants are also available + | +LL | let _: Bar = (Bar::C(/* fields */)).Bad; + | ~~~~~~~~~~~~~~~~~~~~~~ +LL | let _: Bar = (Bar::D(/* fields */)).Bad; + | ~~~~~~~~~~~~~~~~~~~~~~ + +error[E0531]: cannot find tuple struct or tuple variant `A` in this scope + --> $DIR/enum-expected-value-suggest-variants.rs:51:9 + | +LL | A(..) => {} + | ^ not found in this scope + | +help: consider importing this tuple variant + | +LL + use Foo::A; + | + +error[E0532]: expected tuple struct or tuple variant, found enum `Foo` + --> $DIR/enum-expected-value-suggest-variants.rs:53:9 + | +LL | Foo(..) => {} + | ^^^ + | +note: the enum is defined here + --> $DIR/enum-expected-value-suggest-variants.rs:1:1 + | +LL | / enum Foo { +LL | | +LL | | A(u32), +LL | | B(u32), +LL | | } + | |_^ +help: try to match against one of the enum's variants + | +LL | Foo::A(..) => {} + | ~~~~~~ +LL | Foo::B(..) => {} + | ~~~~~~ + +error[E0423]: expected function, tuple struct or tuple variant, found enum `Foo` + --> $DIR/enum-expected-value-suggest-variants.rs:15:18 + | +LL | let _: Foo = Foo(0); + | ^^^ + | +note: the enum is defined here + --> $DIR/enum-expected-value-suggest-variants.rs:1:1 + | +LL | / enum Foo { +LL | | +LL | | A(u32), +LL | | B(u32), +LL | | } + | |_^ +help: try to construct one of the enum's variants + | +LL | let _: Foo = Foo::A(0); + | ~~~~~~ +LL | let _: Foo = Foo::B(0); + | ~~~~~~ + +error[E0423]: expected function, tuple struct or tuple variant, found enum `Bar` + --> $DIR/enum-expected-value-suggest-variants.rs:27:18 + | +LL | let _: Bar = Bar(0); + | ^^^ + | + = help: you might have meant to construct one of the enum's non-tuple variants +note: the enum is defined here + --> $DIR/enum-expected-value-suggest-variants.rs:7:1 + | +LL | / enum Bar { +LL | | C(u32), +LL | | D(u32), +LL | | E, +LL | | F, +LL | | } + | |_^ +help: try to construct one of the enum's variants + | +LL | let _: Bar = Bar::C(0); + | ~~~~~~ +LL | let _: Bar = Bar::D(0); + | ~~~~~~ + +error: aborting due to 10 previous errors + +Some errors have detailed explanations: E0423, E0531, E0532. +For more information about an error, try `rustc --explain E0423`. From ae7b45a6d4b25f01f5c8b9ed547a980146c0d519 Mon Sep 17 00:00:00 2001 From: Zachary S Date: Fri, 31 Jan 2025 16:28:25 -0600 Subject: [PATCH 3/4] When giving a suggestion to use :: instead of . where the rhs is a macro giving a type, make it also work when the rhs is a type alias, not just a struct. --- .../rustc_resolve/src/late/diagnostics.rs | 2 +- ...otation-type-namespace-suggest-path-sep.rs | 43 +++++++++ ...ion-type-namespace-suggest-path-sep.stderr | 96 ++++++++++++++++++- 3 files changed, 137 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 2731efdba48bd..b37c684a0556a 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1529,7 +1529,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { Applicability::MaybeIncorrect, ); true - } else if kind == DefKind::Struct + } else if matches!(kind, DefKind::Struct | DefKind::TyAlias) && let Some(lhs_source_span) = lhs_span.find_ancestor_inside(expr.span) && let Ok(snippet) = this.r.tcx.sess.source_map().span_to_snippet(lhs_source_span) { diff --git a/tests/ui/resolve/dot-notation-type-namespace-suggest-path-sep.rs b/tests/ui/resolve/dot-notation-type-namespace-suggest-path-sep.rs index 104d11f685cc9..432e3c0b77efc 100644 --- a/tests/ui/resolve/dot-notation-type-namespace-suggest-path-sep.rs +++ b/tests/ui/resolve/dot-notation-type-namespace-suggest-path-sep.rs @@ -39,6 +39,12 @@ macro_rules! Type { //~| ERROR expected value, found struct `std::cell::Cell` //~| ERROR expected value, found struct `std::cell::Cell` }; + (alias) => { + Alias + //~^ ERROR expected value, found type alias `Alias` + //~| ERROR expected value, found type alias `Alias` + //~| ERROR expected value, found type alias `Alias` + }; } macro_rules! create { @@ -56,6 +62,32 @@ macro_rules! create { Type!().new(0) //~^ HELP use the path separator }; + (macro method alias) => { + Type!(alias).new(0) + //~^ HELP use the path separator + }; +} + +macro_rules! check_ty { + ($Ty:ident) => { + $Ty.foo + //~^ ERROR expected value, found type alias `Alias` + //~| HELP use the path separator + }; +} +macro_rules! check_ident { + ($Ident:ident) => { + Alias.$Ident + //~^ ERROR expected value, found type alias `Alias` + //~| HELP use the path separator + }; +} +macro_rules! check_ty_ident { + ($Ty:ident, $Ident:ident) => { + $Ty.$Ident + //~^ ERROR expected value, found type alias `Alias` + //~| HELP use the path separator + }; } fn interaction_with_macros() { @@ -70,6 +102,12 @@ fn interaction_with_macros() { Type! {}.get; //~^ HELP use the path separator + Type!(alias).get(); + //~^ HELP use the path separator + + Type! {alias}.get; + //~^ HELP use the path separator + // // Ensure that the suggestion is shown for expressions inside of macro definitions. // @@ -77,4 +115,9 @@ fn interaction_with_macros() { let _ = create!(type method); let _ = create!(type field); let _ = create!(macro method); + let _ = create!(macro method alias); + + let _ = check_ty!(Alias); + let _ = check_ident!(foo); + let _ = check_ty_ident!(Alias, foo); } diff --git a/tests/ui/resolve/dot-notation-type-namespace-suggest-path-sep.stderr b/tests/ui/resolve/dot-notation-type-namespace-suggest-path-sep.stderr index a5397306b01e4..bb2ae7f2de2d0 100644 --- a/tests/ui/resolve/dot-notation-type-namespace-suggest-path-sep.stderr +++ b/tests/ui/resolve/dot-notation-type-namespace-suggest-path-sep.stderr @@ -99,8 +99,38 @@ LL - Type! {}.get; LL + ::get; | +error[E0423]: expected value, found type alias `Alias` + --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:43:9 + | +LL | Alias + | ^^^^^ +... +LL | Type!(alias).get(); + | ------------ in this macro invocation + | + = note: this error originates in the macro `Type` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use the path separator to refer to an item + | +LL | ::get(); + | ~~~~~~~~~~~~~~~~ + +error[E0423]: expected value, found type alias `Alias` + --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:43:9 + | +LL | Alias + | ^^^^^ +... +LL | Type! {alias}.get; + | ------------- in this macro invocation + | + = note: this error originates in the macro `Type` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use the path separator to refer to an item + | +LL | ::get; + | ~~~~~~~~~~~~~~~~~ + error[E0423]: expected value, found struct `Vec` - --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:46:9 + --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:52:9 | LL | Vec.new() | ^^^ @@ -116,7 +146,7 @@ LL + Vec::new() | error[E0423]: expected value, found struct `Vec` - --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:51:9 + --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:57:9 | LL | Vec.new | ^^^ @@ -147,6 +177,66 @@ LL - Type!().new(0) LL + ::new(0) | -error: aborting due to 11 previous errors +error[E0423]: expected value, found type alias `Alias` + --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:43:9 + | +LL | Alias + | ^^^^^ +... +LL | let _ = create!(macro method alias); + | --------------------------- in this macro invocation + | + = note: this error originates in the macro `Type` which comes from the expansion of the macro `create` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use the path separator to refer to an item + | +LL | ::new(0) + | ~~~~~~~~~~~~~~~~ + +error[E0423]: expected value, found type alias `Alias` + --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:73:9 + | +LL | $Ty.foo + | ^^^ +... +LL | let _ = check_ty!(Alias); + | ---------------- in this macro invocation + | + = note: this error originates in the macro `check_ty` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use the path separator to refer to an item + | +LL | $Ty::foo + | ~~ + +error[E0423]: expected value, found type alias `Alias` + --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:80:9 + | +LL | Alias.$Ident + | ^^^^^ +... +LL | let _ = check_ident!(foo); + | ----------------- in this macro invocation + | + = note: this error originates in the macro `check_ident` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use the path separator to refer to an item + | +LL | ::$Ident + | ~~~~~~~~~ + +error[E0423]: expected value, found type alias `Alias` + --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:87:9 + | +LL | $Ty.$Ident + | ^^^ +... +LL | let _ = check_ty_ident!(Alias, foo); + | --------------------------- in this macro invocation + | + = note: this error originates in the macro `check_ty_ident` (in Nightly builds, run with -Z macro-backtrace for more info) +help: use the path separator to refer to an item + | +LL | <$Ty>::$Ident + | ~~~~~~~ + +error: aborting due to 17 previous errors For more information about this error, try `rustc --explain E0423`. From 2c3725021e1b976ecc30b902f74e0f867c634592 Mon Sep 17 00:00:00 2001 From: Zachary S Date: Tue, 11 Feb 2025 12:49:36 -0600 Subject: [PATCH 4/4] Update `.` -> `::` tests for new diff suggestion format. --- ...ion-type-namespace-suggest-path-sep.stderr | 45 ++++++++----- ...num-expected-value-suggest-variants.stderr | 65 +++++++++++-------- 2 files changed, 64 insertions(+), 46 deletions(-) diff --git a/tests/ui/resolve/dot-notation-type-namespace-suggest-path-sep.stderr b/tests/ui/resolve/dot-notation-type-namespace-suggest-path-sep.stderr index bb2ae7f2de2d0..d74814dd876c2 100644 --- a/tests/ui/resolve/dot-notation-type-namespace-suggest-path-sep.stderr +++ b/tests/ui/resolve/dot-notation-type-namespace-suggest-path-sep.stderr @@ -42,8 +42,9 @@ LL | let _ = Alias.new(); | help: use the path separator to refer to an item | -LL | let _ = Alias::new(); - | ~~ +LL - let _ = Alias.new(); +LL + let _ = Alias::new(); + | error[E0423]: expected value, found type alias `Alias` --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:26:13 @@ -53,8 +54,9 @@ LL | let _ = Alias.default; | help: use the path separator to refer to an item | -LL | let _ = Alias::default; - | ~~ +LL - let _ = Alias.default; +LL + let _ = Alias::default; + | error[E0423]: expected value, found module `foo` --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:30:13 @@ -64,8 +66,9 @@ LL | let _ = foo.bar; | help: use the path separator to refer to an item | -LL | let _ = foo::bar; - | ~~ +LL - let _ = foo.bar; +LL + let _ = foo::bar; + | error[E0423]: expected value, found struct `std::cell::Cell` --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:37:9 @@ -111,8 +114,9 @@ LL | Type!(alias).get(); = note: this error originates in the macro `Type` (in Nightly builds, run with -Z macro-backtrace for more info) help: use the path separator to refer to an item | -LL | ::get(); - | ~~~~~~~~~~~~~~~~ +LL - Type!(alias).get(); +LL + ::get(); + | error[E0423]: expected value, found type alias `Alias` --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:43:9 @@ -126,8 +130,9 @@ LL | Type! {alias}.get; = note: this error originates in the macro `Type` (in Nightly builds, run with -Z macro-backtrace for more info) help: use the path separator to refer to an item | -LL | ::get; - | ~~~~~~~~~~~~~~~~~ +LL - Type! {alias}.get; +LL + ::get; + | error[E0423]: expected value, found struct `Vec` --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:52:9 @@ -189,8 +194,9 @@ LL | let _ = create!(macro method alias); = note: this error originates in the macro `Type` which comes from the expansion of the macro `create` (in Nightly builds, run with -Z macro-backtrace for more info) help: use the path separator to refer to an item | -LL | ::new(0) - | ~~~~~~~~~~~~~~~~ +LL - Type!(alias).new(0) +LL + ::new(0) + | error[E0423]: expected value, found type alias `Alias` --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:73:9 @@ -204,8 +210,9 @@ LL | let _ = check_ty!(Alias); = note: this error originates in the macro `check_ty` (in Nightly builds, run with -Z macro-backtrace for more info) help: use the path separator to refer to an item | -LL | $Ty::foo - | ~~ +LL - $Ty.foo +LL + $Ty::foo + | error[E0423]: expected value, found type alias `Alias` --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:80:9 @@ -219,8 +226,9 @@ LL | let _ = check_ident!(foo); = note: this error originates in the macro `check_ident` (in Nightly builds, run with -Z macro-backtrace for more info) help: use the path separator to refer to an item | -LL | ::$Ident - | ~~~~~~~~~ +LL - Alias.$Ident +LL + ::$Ident + | error[E0423]: expected value, found type alias `Alias` --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:87:9 @@ -234,8 +242,9 @@ LL | let _ = check_ty_ident!(Alias, foo); = note: this error originates in the macro `check_ty_ident` (in Nightly builds, run with -Z macro-backtrace for more info) help: use the path separator to refer to an item | -LL | <$Ty>::$Ident - | ~~~~~~~ +LL - $Ty.$Ident +LL + <$Ty>::$Ident + | error: aborting due to 17 previous errors diff --git a/tests/ui/resolve/enum-expected-value-suggest-variants.stderr b/tests/ui/resolve/enum-expected-value-suggest-variants.stderr index 0bd6069b27206..548a4c0e59320 100644 --- a/tests/ui/resolve/enum-expected-value-suggest-variants.stderr +++ b/tests/ui/resolve/enum-expected-value-suggest-variants.stderr @@ -15,8 +15,9 @@ LL | | } | |_^ help: use the path separator to refer to a variant | -LL | let _: Foo = Foo::A(0); - | ~~ +LL - let _: Foo = Foo.A(0); +LL + let _: Foo = Foo::A(0); + | error[E0423]: expected value, found enum `Foo` --> $DIR/enum-expected-value-suggest-variants.rs:23:18 @@ -35,10 +36,12 @@ LL | | } | |_^ help: the following enum variants are available | -LL | let _: Foo = (Foo::A(/* fields */)).Bad(0); - | ~~~~~~~~~~~~~~~~~~~~~~ -LL | let _: Foo = (Foo::B(/* fields */)).Bad(0); - | ~~~~~~~~~~~~~~~~~~~~~~ +LL - let _: Foo = Foo.Bad(0); +LL + let _: Foo = (Foo::A(/* fields */)).Bad(0); + | +LL - let _: Foo = Foo.Bad(0); +LL + let _: Foo = (Foo::B(/* fields */)).Bad(0); + | error[E0423]: expected value, found enum `Bar` --> $DIR/enum-expected-value-suggest-variants.rs:32:18 @@ -58,8 +61,9 @@ LL | | } | |_^ help: use the path separator to refer to a variant | -LL | let _: Bar = Bar::C(0); - | ~~ +LL - let _: Bar = Bar.C(0); +LL + let _: Bar = Bar::C(0); + | error[E0423]: expected value, found enum `Bar` --> $DIR/enum-expected-value-suggest-variants.rs:36:18 @@ -79,8 +83,9 @@ LL | | } | |_^ help: use the path separator to refer to a variant | -LL | let _: Bar = Bar::E; - | ~~ +LL - let _: Bar = Bar.E; +LL + let _: Bar = Bar::E; + | error[E0423]: expected value, found enum `Bar` --> $DIR/enum-expected-value-suggest-variants.rs:40:18 @@ -101,15 +106,17 @@ LL | | } help: you might have meant to use one of the following enum variants | LL | let _: Bar = Bar::E.Bad(0); - | ~~~~~~ + | +++ LL | let _: Bar = Bar::F.Bad(0); - | ~~~~~~ + | +++ help: alternatively, the following enum variants are also available | -LL | let _: Bar = (Bar::C(/* fields */)).Bad(0); - | ~~~~~~~~~~~~~~~~~~~~~~ -LL | let _: Bar = (Bar::D(/* fields */)).Bad(0); - | ~~~~~~~~~~~~~~~~~~~~~~ +LL - let _: Bar = Bar.Bad(0); +LL + let _: Bar = (Bar::C(/* fields */)).Bad(0); + | +LL - let _: Bar = Bar.Bad(0); +LL + let _: Bar = (Bar::D(/* fields */)).Bad(0); + | error[E0423]: expected value, found enum `Bar` --> $DIR/enum-expected-value-suggest-variants.rs:45:18 @@ -130,15 +137,17 @@ LL | | } help: you might have meant to use one of the following enum variants | LL | let _: Bar = Bar::E.Bad; - | ~~~~~~ + | +++ LL | let _: Bar = Bar::F.Bad; - | ~~~~~~ + | +++ help: alternatively, the following enum variants are also available | -LL | let _: Bar = (Bar::C(/* fields */)).Bad; - | ~~~~~~~~~~~~~~~~~~~~~~ -LL | let _: Bar = (Bar::D(/* fields */)).Bad; - | ~~~~~~~~~~~~~~~~~~~~~~ +LL - let _: Bar = Bar.Bad; +LL + let _: Bar = (Bar::C(/* fields */)).Bad; + | +LL - let _: Bar = Bar.Bad; +LL + let _: Bar = (Bar::D(/* fields */)).Bad; + | error[E0531]: cannot find tuple struct or tuple variant `A` in this scope --> $DIR/enum-expected-value-suggest-variants.rs:51:9 @@ -169,9 +178,9 @@ LL | | } help: try to match against one of the enum's variants | LL | Foo::A(..) => {} - | ~~~~~~ + | +++ LL | Foo::B(..) => {} - | ~~~~~~ + | +++ error[E0423]: expected function, tuple struct or tuple variant, found enum `Foo` --> $DIR/enum-expected-value-suggest-variants.rs:15:18 @@ -191,9 +200,9 @@ LL | | } help: try to construct one of the enum's variants | LL | let _: Foo = Foo::A(0); - | ~~~~~~ + | +++ LL | let _: Foo = Foo::B(0); - | ~~~~~~ + | +++ error[E0423]: expected function, tuple struct or tuple variant, found enum `Bar` --> $DIR/enum-expected-value-suggest-variants.rs:27:18 @@ -215,9 +224,9 @@ LL | | } help: try to construct one of the enum's variants | LL | let _: Bar = Bar::C(0); - | ~~~~~~ + | +++ LL | let _: Bar = Bar::D(0); - | ~~~~~~ + | +++ error: aborting due to 10 previous errors