@@ -783,6 +783,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
783
783
( substs, assoc_bindings, potential_assoc_types)
784
784
}
785
785
786
+ /// On missing type parameters, emit an E0393 error and provide a structured suggestion using
787
+ /// the type parameter's name as a placeholder.
786
788
fn complain_about_missing_type_params (
787
789
& self ,
788
790
missing_type_params : Vec < String > ,
@@ -956,8 +958,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
956
958
trait_def_id : DefId ,
957
959
self_ty : Ty < ' tcx > ,
958
960
trait_segment : & hir:: PathSegment
959
- ) -> ty:: TraitRef < ' tcx >
960
- {
961
+ ) -> ty:: TraitRef < ' tcx > {
961
962
let ( substs, assoc_bindings, _) =
962
963
self . create_substs_for_ast_trait_ref ( span,
963
964
trait_def_id,
@@ -967,15 +968,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
967
968
ty:: TraitRef :: new ( trait_def_id, substs)
968
969
}
969
970
970
- fn create_substs_for_ast_trait_ref < ' a > (
971
+ /// When the code is using the `Fn` traits directly, instead of the `Fn(A) -> B` syntax, emit
972
+ /// an error and attempt to build a reasonable structured suggestion.
973
+ fn complain_about_internal_fn_trait (
971
974
& self ,
972
975
span : Span ,
973
976
trait_def_id : DefId ,
974
- self_ty : Ty < ' tcx > ,
975
977
trait_segment : & ' a hir:: PathSegment ,
976
- ) -> ( SubstsRef < ' tcx > , Vec < ConvertedBinding < ' a , ' tcx > > , Option < Vec < Span > > ) {
977
- debug ! ( "create_substs_for_ast_trait_ref(trait_segment={:?})" , trait_segment) ;
978
-
978
+ ) {
979
979
let trait_def = self . tcx ( ) . trait_def ( trait_def_id) ;
980
980
981
981
if !self . tcx ( ) . features ( ) . unboxed_closures &&
@@ -1020,19 +1020,33 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
1020
1020
}
1021
1021
err. emit ( ) ;
1022
1022
}
1023
+ }
1024
+
1025
+ fn create_substs_for_ast_trait_ref < ' a > (
1026
+ & self ,
1027
+ span : Span ,
1028
+ trait_def_id : DefId ,
1029
+ self_ty : Ty < ' tcx > ,
1030
+ trait_segment : & ' a hir:: PathSegment ,
1031
+ ) -> ( SubstsRef < ' tcx > , Vec < ConvertedBinding < ' a , ' tcx > > , Option < Vec < Span > > ) {
1032
+ debug ! ( "create_substs_for_ast_trait_ref(trait_segment={:?})" , trait_segment) ;
1033
+
1034
+ self . complain_about_internal_fn_trait ( span, trait_def_id, trait_segment) ;
1023
1035
1024
- self . create_substs_for_ast_path ( span,
1025
- trait_def_id,
1026
- trait_segment. generic_args ( ) ,
1027
- trait_segment. infer_args ,
1028
- Some ( self_ty) )
1036
+ self . create_substs_for_ast_path (
1037
+ span,
1038
+ trait_def_id,
1039
+ trait_segment. generic_args ( ) ,
1040
+ trait_segment. infer_args ,
1041
+ Some ( self_ty) ,
1042
+ )
1029
1043
}
1030
1044
1031
- fn trait_defines_associated_type_named ( & self ,
1032
- trait_def_id : DefId ,
1033
- assoc_name : ast :: Ident )
1034
- -> bool
1035
- {
1045
+ fn trait_defines_associated_type_named (
1046
+ & self ,
1047
+ trait_def_id : DefId ,
1048
+ assoc_name : ast :: Ident ,
1049
+ ) -> bool {
1036
1050
self . tcx ( ) . associated_items ( trait_def_id) . any ( |item| {
1037
1051
item. kind == ty:: AssocKind :: Type &&
1038
1052
self . tcx ( ) . hygienic_eq ( assoc_name, item. ident , trait_def_id)
@@ -1400,48 +1414,49 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
1400
1414
. filter ( |( trait_ref, _) | !tcx. trait_is_auto ( trait_ref. def_id ( ) ) ) ;
1401
1415
1402
1416
for ( base_trait_ref, span) in regular_traits_refs_spans {
1403
- debug ! ( "conv_object_ty_poly_trait_ref regular_trait_ref `{:?}`" , base_trait_ref) ;
1404
- let mut new_bounds = vec ! [ ] ;
1405
1417
for trait_ref in traits:: elaborate_trait_ref ( tcx, base_trait_ref) {
1406
- debug ! ( "conv_object_ty_poly_trait_ref: observing object predicate `{:?}`" , trait_ref) ;
1407
- match trait_ref {
1408
- ty:: Predicate :: Trait ( pred) => {
1409
- associated_types. entry ( span) . or_default ( )
1410
- . extend ( tcx. associated_items ( pred. def_id ( ) )
1411
- . filter ( |item| item. kind == ty:: AssocKind :: Type )
1412
- . map ( |item| item. def_id ) ) ;
1413
- }
1414
- ty:: Predicate :: Projection ( pred) => {
1415
- // A `Self` within the original bound will be substituted with a
1416
- // `trait_object_dummy_self`, so check for that.
1417
- let references_self =
1418
- pred. skip_binder ( ) . ty . walk ( ) . any ( |t| t == dummy_self) ;
1419
-
1420
- // If the projection output contains `Self`, force the user to
1421
- // elaborate it explicitly to avoid a lot of complexity.
1422
- //
1423
- // The "classicaly useful" case is the following:
1424
- // ```
1425
- // trait MyTrait: FnMut() -> <Self as MyTrait>::MyOutput {
1426
- // type MyOutput;
1427
- // }
1428
- // ```
1429
- //
1430
- // Here, the user could theoretically write `dyn MyTrait<Output = X>`,
1431
- // but actually supporting that would "expand" to an infinitely-long type
1432
- // `fix $ τ → dyn MyTrait<MyOutput = X, Output = <τ as MyTrait>::MyOutput`.
1433
- //
1434
- // Instead, we force the user to write `dyn MyTrait<MyOutput = X, Output = X>`,
1435
- // which is uglier but works. See the discussion in #56288 for alternatives.
1436
- if !references_self {
1437
- // Include projections defined on supertraits.
1438
- new_bounds. push ( ( pred, span) ) ;
1418
+ debug ! (
1419
+ "conv_object_ty_poly_trait_ref: observing object predicate `{:?}`" ,
1420
+ trait_ref
1421
+ ) ;
1422
+ match trait_ref {
1423
+ ty:: Predicate :: Trait ( pred) => {
1424
+ associated_types. entry ( span) . or_default ( )
1425
+ . extend ( tcx. associated_items ( pred. def_id ( ) )
1426
+ . filter ( |item| item. kind == ty:: AssocKind :: Type )
1427
+ . map ( |item| item. def_id ) ) ;
1428
+ }
1429
+ ty:: Predicate :: Projection ( pred) => {
1430
+ // A `Self` within the original bound will be substituted with a
1431
+ // `trait_object_dummy_self`, so check for that.
1432
+ let references_self =
1433
+ pred. skip_binder ( ) . ty . walk ( ) . any ( |t| t == dummy_self) ;
1434
+
1435
+ // If the projection output contains `Self`, force the user to
1436
+ // elaborate it explicitly to avoid a lot of complexity.
1437
+ //
1438
+ // The "classicaly useful" case is the following:
1439
+ // ```
1440
+ // trait MyTrait: FnMut() -> <Self as MyTrait>::MyOutput {
1441
+ // type MyOutput;
1442
+ // }
1443
+ // ```
1444
+ //
1445
+ // Here, the user could theoretically write `dyn MyTrait<Output = X>`,
1446
+ // but actually supporting that would "expand" to an infinitely-long type
1447
+ // `fix $ τ → dyn MyTrait<MyOutput = X, Output = <τ as MyTrait>::MyOutput`.
1448
+ //
1449
+ // Instead, we force the user to write
1450
+ // `dyn MyTrait<MyOutput = X, Output = X>`, which is uglier but works. See
1451
+ // the discussion in #56288 for alternatives.
1452
+ if !references_self {
1453
+ // Include projections defined on supertraits.
1454
+ bounds. projection_bounds . push ( ( pred, span) ) ;
1455
+ }
1439
1456
}
1457
+ _ => ( )
1440
1458
}
1441
- _ => ( )
1442
- }
1443
1459
}
1444
- bounds. projection_bounds . extend ( new_bounds) ;
1445
1460
}
1446
1461
1447
1462
for ( projection_bound, _) in & bounds. projection_bounds {
@@ -1534,27 +1549,37 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
1534
1549
ty
1535
1550
}
1536
1551
1552
+ /// When there are any missing associated types, emit an E0191 error and attempt to supply a
1553
+ /// reasonable suggestion on how to write it. For the case of multiple associated types in the
1554
+ /// same trait bound have the same name (as they come from different super-traits), we instead
1555
+ /// emit a generic note suggesting using a `where` clause to constraint instead.
1537
1556
fn complain_about_missing_associated_types (
1538
1557
& self ,
1539
- mut associated_types : FxHashMap < Span , BTreeSet < DefId > > ,
1558
+ associated_types : FxHashMap < Span , BTreeSet < DefId > > ,
1540
1559
potential_assoc_types : Vec < Span > ,
1541
1560
trait_bounds : & [ hir:: PolyTraitRef ] ,
1542
1561
) {
1543
1562
if !associated_types. values ( ) . any ( |v| v. len ( ) > 0 ) {
1544
1563
return ;
1545
1564
}
1546
1565
let tcx = self . tcx ( ) ;
1566
+ // FIXME: Marked `mut` so that we can replace the spans further below with a more
1567
+ // appropriate one, but this should be handled earlier in the span assignment.
1568
+ let mut associated_types: FxHashMap < Span , Vec < _ > > = associated_types. into_iter ( )
1569
+ . map ( |( span, def_ids) | (
1570
+ span,
1571
+ def_ids. into_iter ( ) . map ( |did| tcx. associated_item ( did) ) . collect ( ) ,
1572
+ ) ) . collect ( ) ;
1547
1573
let mut names = vec ! [ ] ;
1548
1574
1549
1575
// Account for things like `dyn Foo + 'a`, like in tests `issue-22434.rs` and
1550
1576
// `issue-22560.rs`.
1551
1577
let mut trait_bound_spans: Vec < Span > = vec ! [ ] ;
1552
- for ( span, item_def_ids ) in & associated_types {
1553
- if !item_def_ids . is_empty ( ) {
1578
+ for ( span, items ) in & associated_types {
1579
+ if !items . is_empty ( ) {
1554
1580
trait_bound_spans. push ( * span) ;
1555
1581
}
1556
- for item_def_id in item_def_ids {
1557
- let assoc_item = tcx. associated_item ( * item_def_id) ;
1582
+ for assoc_item in items {
1558
1583
let trait_def_id = assoc_item. container . id ( ) ;
1559
1584
names. push ( format ! (
1560
1585
"`{}` (from trait `{}`)" ,
@@ -1592,7 +1617,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
1592
1617
[ segment] if segment. args . is_none ( ) => {
1593
1618
trait_bound_spans = vec ! [ segment. ident. span] ;
1594
1619
associated_types = associated_types. into_iter ( )
1595
- . map ( |( _, defs ) | ( segment. ident . span , defs ) )
1620
+ . map ( |( _, items ) | ( segment. ident . span , items ) )
1596
1621
. collect ( ) ;
1597
1622
}
1598
1623
_ => { }
@@ -1610,17 +1635,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
1610
1635
let mut suggestions = vec ! [ ] ;
1611
1636
let mut types_count = 0 ;
1612
1637
let mut where_constraints = vec ! [ ] ;
1613
- for ( span, def_ids) in & associated_types {
1614
- let assoc_items: Vec < _ > = def_ids. iter ( )
1615
- . map ( |def_id| tcx. associated_item ( * def_id) )
1616
- . collect ( ) ;
1638
+ for ( span, assoc_items) in & associated_types {
1617
1639
let mut names: FxHashMap < _ , usize > = FxHashMap :: default ( ) ;
1618
- for item in & assoc_items {
1640
+ for item in assoc_items {
1619
1641
types_count += 1 ;
1620
1642
* names. entry ( item. ident . name ) . or_insert ( 0 ) += 1 ;
1621
1643
}
1622
1644
let mut dupes = false ;
1623
- for item in & assoc_items {
1645
+ for item in assoc_items {
1624
1646
let prefix = if names[ & item. ident . name ] > 1 {
1625
1647
let trait_def_id = item. container . id ( ) ;
1626
1648
dupes = true ;
@@ -1681,17 +1703,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
1681
1703
}
1682
1704
if suggestions. len ( ) != 1 {
1683
1705
// We don't need this label if there's an inline suggestion, show otherwise.
1684
- for ( span, def_ids) in & associated_types {
1685
- let assoc_items: Vec < _ > = def_ids. iter ( )
1686
- . map ( |def_id| tcx. associated_item ( * def_id) )
1687
- . collect ( ) ;
1706
+ for ( span, assoc_items) in & associated_types {
1688
1707
let mut names: FxHashMap < _ , usize > = FxHashMap :: default ( ) ;
1689
- for item in & assoc_items {
1708
+ for item in assoc_items {
1690
1709
types_count += 1 ;
1691
1710
* names. entry ( item. ident . name ) . or_insert ( 0 ) += 1 ;
1692
1711
}
1693
1712
let mut label = vec ! [ ] ;
1694
- for item in & assoc_items {
1713
+ for item in assoc_items {
1695
1714
let postfix = if names[ & item. ident . name ] > 1 {
1696
1715
let trait_def_id = item. container . id ( ) ;
1697
1716
format ! ( " (from trait `{}`)" , tcx. def_path_str( trait_def_id) )
0 commit comments