@@ -8,7 +8,7 @@ use rustc_ast::ptr::P;
8
8
use rustc_ast:: visit:: { FnCtxt , FnKind , LifetimeCtxt , Visitor , walk_ty} ;
9
9
use rustc_ast:: {
10
10
self as ast, AssocItemKind , DUMMY_NODE_ID , Expr , ExprKind , GenericParam , GenericParamKind ,
11
- Item , ItemKind , MethodCall , NodeId , Path , Ty , TyKind ,
11
+ Item , ItemKind , MethodCall , NodeId , Path , PathSegment , Ty , TyKind ,
12
12
} ;
13
13
use rustc_ast_pretty:: pprust:: where_bound_predicate_to_string;
14
14
use rustc_data_structures:: fx:: { FxHashSet , FxIndexSet } ;
@@ -1529,7 +1529,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
1529
1529
Applicability :: MaybeIncorrect ,
1530
1530
) ;
1531
1531
true
1532
- } else if kind == DefKind :: Struct
1532
+ } else if matches ! ( kind, DefKind :: Struct | DefKind :: TyAlias )
1533
1533
&& let Some ( lhs_source_span) = lhs_span. find_ancestor_inside ( expr. span )
1534
1534
&& let Ok ( snippet) = this. r . tcx . sess . source_map ( ) . span_to_snippet ( lhs_source_span)
1535
1535
{
@@ -1566,7 +1566,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
1566
1566
}
1567
1567
} ;
1568
1568
1569
- let mut bad_struct_syntax_suggestion = |this : & mut Self , def_id : DefId | {
1569
+ let bad_struct_syntax_suggestion = |this : & mut Self , err : & mut Diag < ' _ > , def_id : DefId | {
1570
1570
let ( followed_by_brace, closing_brace) = this. followed_by_brace ( span) ;
1571
1571
1572
1572
match source {
@@ -1740,12 +1740,10 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
1740
1740
}
1741
1741
}
1742
1742
(
1743
- Res :: Def ( kind @ ( DefKind :: Mod | DefKind :: Trait ) , _) ,
1743
+ Res :: Def ( kind @ ( DefKind :: Mod | DefKind :: Trait | DefKind :: TyAlias ) , _) ,
1744
1744
PathSource :: Expr ( Some ( parent) ) ,
1745
- ) => {
1746
- if !path_sep ( self , err, parent, kind) {
1747
- return false ;
1748
- }
1745
+ ) if path_sep ( self , err, parent, kind) => {
1746
+ return true ;
1749
1747
}
1750
1748
(
1751
1749
Res :: Def ( DefKind :: Enum , def_id) ,
@@ -1777,13 +1775,13 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
1777
1775
let ( ctor_def, ctor_vis, fields) = if let Some ( struct_ctor) = struct_ctor {
1778
1776
if let PathSource :: Expr ( Some ( parent) ) = source {
1779
1777
if let ExprKind :: Field ( ..) | ExprKind :: MethodCall ( ..) = parent. kind {
1780
- bad_struct_syntax_suggestion ( self , def_id) ;
1778
+ bad_struct_syntax_suggestion ( self , err , def_id) ;
1781
1779
return true ;
1782
1780
}
1783
1781
}
1784
1782
struct_ctor
1785
1783
} else {
1786
- bad_struct_syntax_suggestion ( self , def_id) ;
1784
+ bad_struct_syntax_suggestion ( self , err , def_id) ;
1787
1785
return true ;
1788
1786
} ;
1789
1787
@@ -1861,7 +1859,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
1861
1859
err. span_label ( span, "constructor is not visible here due to private fields" ) ;
1862
1860
}
1863
1861
( Res :: Def ( DefKind :: Union | DefKind :: Variant , def_id) , _) if ns == ValueNS => {
1864
- bad_struct_syntax_suggestion ( self , def_id) ;
1862
+ bad_struct_syntax_suggestion ( self , err , def_id) ;
1865
1863
}
1866
1864
( Res :: Def ( DefKind :: Ctor ( _, CtorKind :: Const ) , def_id) , _) if ns == ValueNS => {
1867
1865
match source {
@@ -2471,31 +2469,73 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
2471
2469
def_id : DefId ,
2472
2470
span : Span ,
2473
2471
) {
2474
- let Some ( variants ) = self . collect_enum_ctors ( def_id) else {
2472
+ let Some ( variant_ctors ) = self . collect_enum_ctors ( def_id) else {
2475
2473
err. note ( "you might have meant to use one of the enum's variants" ) ;
2476
2474
return ;
2477
2475
} ;
2478
2476
2479
- let suggest_only_tuple_variants =
2480
- matches ! ( source, PathSource :: TupleStruct ( ..) ) || source. is_call ( ) ;
2481
- if suggest_only_tuple_variants {
2477
+ // If the expression is a field-access or method-call, try to find a variant with the field/method name
2478
+ // that could have been intended, and suggest replacing the `.` with `::`.
2479
+ // Otherwise, suggest adding `::VariantName` after the enum;
2480
+ // and if the expression is call-like, only suggest tuple variants.
2481
+ let ( suggest_path_sep_dot_span, suggest_only_tuple_variants) = match source {
2482
+ // `Type(a, b)` in a pattern, only suggest adding a tuple variant after `Type`.
2483
+ PathSource :: TupleStruct ( ..) => ( None , true ) ,
2484
+ PathSource :: Expr ( Some ( expr) ) => match & expr. kind {
2485
+ // `Type(a, b)`, only suggest adding a tuple variant after `Type`.
2486
+ ExprKind :: Call ( ..) => ( None , true ) ,
2487
+ // `Type.Foo(a, b)`, suggest replacing `.` -> `::` if variant `Foo` exists and is a tuple variant,
2488
+ // otherwise suggest adding a variant after `Type`.
2489
+ ExprKind :: MethodCall ( box MethodCall {
2490
+ receiver,
2491
+ span,
2492
+ seg : PathSegment { ident, .. } ,
2493
+ ..
2494
+ } ) => {
2495
+ let dot_span = receiver. span . between ( * span) ;
2496
+ let found_tuple_variant = variant_ctors. iter ( ) . any ( |( path, _, ctor_kind) | {
2497
+ * ctor_kind == CtorKind :: Fn
2498
+ && path. segments . last ( ) . is_some_and ( |seg| seg. ident == * ident)
2499
+ } ) ;
2500
+ ( found_tuple_variant. then_some ( dot_span) , false )
2501
+ }
2502
+ // `Type.Foo`, suggest replacing `.` -> `::` if variant `Foo` exists and is a unit or tuple variant,
2503
+ // otherwise suggest adding a variant after `Type`.
2504
+ ExprKind :: Field ( base, ident) => {
2505
+ let dot_span = base. span . between ( ident. span ) ;
2506
+ let found_tuple_or_unit_variant = variant_ctors. iter ( ) . any ( |( path, ..) | {
2507
+ path. segments . last ( ) . is_some_and ( |seg| seg. ident == * ident)
2508
+ } ) ;
2509
+ ( found_tuple_or_unit_variant. then_some ( dot_span) , false )
2510
+ }
2511
+ _ => ( None , false ) ,
2512
+ } ,
2513
+ _ => ( None , false ) ,
2514
+ } ;
2515
+
2516
+ if let Some ( dot_span) = suggest_path_sep_dot_span {
2517
+ err. span_suggestion_verbose (
2518
+ dot_span,
2519
+ "use the path separator to refer to a variant" ,
2520
+ "::" ,
2521
+ Applicability :: MaybeIncorrect ,
2522
+ ) ;
2523
+ } else if suggest_only_tuple_variants {
2482
2524
// Suggest only tuple variants regardless of whether they have fields and do not
2483
2525
// suggest path with added parentheses.
2484
- let mut suggestable_variants = variants
2526
+ let mut suggestable_variants = variant_ctors
2485
2527
. iter ( )
2486
2528
. filter ( |( .., kind) | * kind == CtorKind :: Fn )
2487
2529
. map ( |( variant, ..) | path_names_to_string ( variant) )
2488
2530
. collect :: < Vec < _ > > ( ) ;
2489
2531
suggestable_variants. sort ( ) ;
2490
2532
2491
- let non_suggestable_variant_count = variants . len ( ) - suggestable_variants. len ( ) ;
2533
+ let non_suggestable_variant_count = variant_ctors . len ( ) - suggestable_variants. len ( ) ;
2492
2534
2493
- let source_msg = if source. is_call ( ) {
2494
- "to construct"
2495
- } else if matches ! ( source, PathSource :: TupleStruct ( ..) ) {
2535
+ let source_msg = if matches ! ( source, PathSource :: TupleStruct ( ..) ) {
2496
2536
"to match against"
2497
2537
} else {
2498
- unreachable ! ( )
2538
+ "to construct"
2499
2539
} ;
2500
2540
2501
2541
if !suggestable_variants. is_empty ( ) {
@@ -2514,7 +2554,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
2514
2554
}
2515
2555
2516
2556
// If the enum has no tuple variants..
2517
- if non_suggestable_variant_count == variants . len ( ) {
2557
+ if non_suggestable_variant_count == variant_ctors . len ( ) {
2518
2558
err. help ( format ! ( "the enum has no tuple variants {source_msg}" ) ) ;
2519
2559
}
2520
2560
@@ -2537,7 +2577,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
2537
2577
}
2538
2578
} ;
2539
2579
2540
- let mut suggestable_variants = variants
2580
+ let mut suggestable_variants = variant_ctors
2541
2581
. iter ( )
2542
2582
. filter ( |( _, def_id, kind) | !needs_placeholder ( * def_id, * kind) )
2543
2583
. map ( |( variant, _, kind) | ( path_names_to_string ( variant) , kind) )
@@ -2564,7 +2604,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
2564
2604
) ;
2565
2605
}
2566
2606
2567
- let mut suggestable_variants_with_placeholders = variants
2607
+ let mut suggestable_variants_with_placeholders = variant_ctors
2568
2608
. iter ( )
2569
2609
. filter ( |( _, def_id, kind) | needs_placeholder ( * def_id, * kind) )
2570
2610
. map ( |( variant, _, kind) | ( path_names_to_string ( variant) , kind) )
0 commit comments