@@ -15,7 +15,7 @@ use rustc_ast_pretty::pprust::where_bound_predicate_to_string;
15
15
use rustc_data_structures:: fx:: FxHashSet ;
16
16
use rustc_errors:: {
17
17
pluralize, struct_span_err, Applicability , Diagnostic , DiagnosticBuilder , ErrorGuaranteed ,
18
- MultiSpan ,
18
+ MultiSpan , SuggestionStyle ,
19
19
} ;
20
20
use rustc_hir as hir;
21
21
use rustc_hir:: def:: { self , CtorKind , CtorOf , DefKind } ;
@@ -29,6 +29,8 @@ use rustc_span::hygiene::MacroKind;
29
29
use rustc_span:: symbol:: { kw, sym, Ident , Symbol } ;
30
30
use rustc_span:: Span ;
31
31
32
+ use rustc_middle:: ty;
33
+
32
34
use std:: borrow:: Cow ;
33
35
use std:: iter;
34
36
use std:: ops:: Deref ;
@@ -1566,29 +1568,85 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
1566
1568
Some ( Vec :: from ( pattern_spans) )
1567
1569
}
1568
1570
// e.g. `let _ = Enum::TupleVariant(field1, field2);`
1569
- _ if source . is_call ( ) => {
1571
+ PathSource :: Expr ( Some ( Expr { kind : ExprKind :: Call ( _ , ref args ) , .. } ) ) => {
1570
1572
err. set_primary_message (
1571
1573
"cannot initialize a tuple struct which contains private fields" ,
1572
1574
) ;
1573
- if !def_id. is_local ( )
1574
- && self
1575
+ if !def_id. is_local ( ) {
1576
+ // Look at all the associated functions without receivers in the type's
1577
+ // inherent impls to look for builders that return `Self`
1578
+ let mut items = self
1575
1579
. r
1576
1580
. tcx
1577
1581
. inherent_impls ( def_id)
1578
1582
. iter ( )
1579
- . flat_map ( |impl_def_id| {
1580
- self . r . tcx . provided_trait_methods ( * impl_def_id)
1583
+ . flat_map ( |i| self . r . tcx . associated_items ( i) . in_definition_order ( ) )
1584
+ // Only assoc fn with no receivers.
1585
+ . filter ( |item| {
1586
+ matches ! ( item. kind, ty:: AssocKind :: Fn )
1587
+ && !item. fn_has_self_parameter
1581
1588
} )
1582
- . any ( |assoc| !assoc. fn_has_self_parameter && assoc. name == sym:: new)
1583
- {
1584
- // FIXME: look for associated functions with Self return type,
1585
- // instead of relying only on the name and lack of self receiver.
1586
- err. span_suggestion_verbose (
1587
- span. shrink_to_hi ( ) ,
1588
- "you might have meant to use the `new` associated function" ,
1589
- "::new" . to_string ( ) ,
1590
- Applicability :: MaybeIncorrect ,
1591
- ) ;
1589
+ . filter_map ( |item| {
1590
+ // Only assoc fns that return `Self`
1591
+ let fn_sig = self . r . tcx . fn_sig ( item. def_id ) . skip_binder ( ) ;
1592
+ let ret_ty = fn_sig. output ( ) ;
1593
+ let ret_ty = self . r . tcx . erase_late_bound_regions ( ret_ty) ;
1594
+ let ty:: Adt ( def, _args) = ret_ty. kind ( ) else {
1595
+ return None ;
1596
+ } ;
1597
+ // Check for `-> Self`
1598
+ if def. did ( ) == def_id {
1599
+ let order = if item. name . as_str ( ) . starts_with ( "new" )
1600
+ && fn_sig. inputs ( ) . skip_binder ( ) . len ( ) == args. len ( )
1601
+ {
1602
+ 0
1603
+ } else if item. name . as_str ( ) . starts_with ( "new" )
1604
+ || item. name . as_str ( ) . starts_with ( "default" )
1605
+ {
1606
+ // Give higher precedence to functions with a name that
1607
+ // imply construction.
1608
+ 1
1609
+ } else if fn_sig. inputs ( ) . skip_binder ( ) . len ( ) == args. len ( )
1610
+ {
1611
+ 2
1612
+ } else {
1613
+ 3
1614
+ } ;
1615
+ return Some ( ( order, item. name ) ) ;
1616
+ }
1617
+ None
1618
+ } )
1619
+ . collect :: < Vec < _ > > ( ) ;
1620
+ items. sort_by_key ( |( order, _) | * order) ;
1621
+ match & items[ ..] {
1622
+ [ ] => { }
1623
+ [ ( _, name) ] => {
1624
+ err. span_suggestion_verbose (
1625
+ span. shrink_to_hi ( ) ,
1626
+ format ! (
1627
+ "you might have meant to use the `{name}` associated \
1628
+ function",
1629
+ ) ,
1630
+ format ! ( "::{name}" ) ,
1631
+ Applicability :: MaybeIncorrect ,
1632
+ ) ;
1633
+ }
1634
+ _ => {
1635
+ // We use this instead of `span_suggestions` to retain output
1636
+ // sort order.
1637
+ err. span_suggestions_with_style (
1638
+ span. shrink_to_hi ( ) ,
1639
+ "you might have meant to use an associated function to \
1640
+ build this type",
1641
+ items
1642
+ . iter ( )
1643
+ . map ( |( _, name) | format ! ( "::{name}" ) )
1644
+ . collect :: < Vec < String > > ( ) ,
1645
+ Applicability :: MaybeIncorrect ,
1646
+ SuggestionStyle :: ShowAlways ,
1647
+ ) ;
1648
+ }
1649
+ }
1592
1650
}
1593
1651
// Use spans of the tuple struct definition.
1594
1652
self . r . field_def_ids ( def_id) . map ( |field_ids| {
0 commit comments