@@ -743,57 +743,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
743
743
}
744
744
} ,
745
745
) ;
746
- if !missing_type_params. is_empty ( ) {
747
- let display = missing_type_params. iter ( )
748
- . map ( |n| format ! ( "`{}`" , n) )
749
- . collect :: < Vec < _ > > ( ) . join ( ", " ) ;
750
- let mut err = struct_span_err ! ( tcx. sess, span, E0393 ,
751
- "the type parameter{} {} must be explicitly specified" ,
752
- pluralize!( missing_type_params. len( ) ) ,
753
- display,
754
- ) ;
755
- err. span_label ( self . tcx ( ) . def_span ( def_id) , & format ! (
756
- "type parameter{} {} must be specified for this" ,
757
- pluralize!( missing_type_params. len( ) ) ,
758
- display,
759
- ) ) ;
760
- let mut suggested = false ;
761
- if let ( Ok ( snippet) , true ) = (
762
- tcx. sess . source_map ( ) . span_to_snippet ( span) ,
763
- // Don't suggest setting the type params if there are some already: the order is
764
- // tricky to get right and the user will already know what the syntax is.
765
- generic_args. args . is_empty ( ) ,
766
- ) {
767
- if snippet. ends_with ( '>' ) {
768
- // The user wrote `Trait<'a, T>` or similar. To provide an accurate suggestion
769
- // we would have to preserve the right order. For now, as clearly the user is
770
- // aware of the syntax, we do nothing.
771
- } else {
772
- // The user wrote `Iterator`, so we don't have a type we can suggest, but at
773
- // least we can clue them to the correct syntax `Iterator<Type>`.
774
- err. span_suggestion (
775
- span,
776
- & format ! (
777
- "set the type parameter{plural} to the desired type{plural}" ,
778
- plural=pluralize!( missing_type_params. len( ) ) ,
779
- ) ,
780
- format ! ( "{}<{}>" , snippet, missing_type_params. join( ", " ) ) ,
781
- Applicability :: HasPlaceholders ,
782
- ) ;
783
- suggested = true ;
784
- }
785
- }
786
- if !suggested {
787
- err. span_label ( span, format ! (
788
- "missing reference{} to {}" ,
789
- pluralize!( missing_type_params. len( ) ) ,
790
- display,
791
- ) ) ;
792
- }
793
- err. note ( & format ! ( "because of the default `Self` reference, type parameters must be \
794
- specified on object types") ) ;
795
- err. emit ( ) ;
796
- }
746
+
747
+ self . complain_about_missing_type_params (
748
+ missing_type_params,
749
+ def_id,
750
+ span,
751
+ generic_args. args . is_empty ( ) ,
752
+ ) ;
797
753
798
754
// Convert associated-type bindings or constraints into a separate vector.
799
755
// Example: Given this:
@@ -826,6 +782,67 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
826
782
( substs, assoc_bindings, potential_assoc_types)
827
783
}
828
784
785
+ fn complain_about_missing_type_params (
786
+ & self ,
787
+ missing_type_params : Vec < String > ,
788
+ def_id : DefId ,
789
+ span : Span ,
790
+ empty_generic_args : bool ,
791
+ ) {
792
+ if missing_type_params. is_empty ( ) {
793
+ return ;
794
+ }
795
+ let display = missing_type_params. iter ( )
796
+ . map ( |n| format ! ( "`{}`" , n) )
797
+ . collect :: < Vec < _ > > ( ) . join ( ", " ) ;
798
+ let mut err = struct_span_err ! ( self . tcx( ) . sess, span, E0393 ,
799
+ "the type parameter{} {} must be explicitly specified" ,
800
+ pluralize!( missing_type_params. len( ) ) ,
801
+ display,
802
+ ) ;
803
+ err. span_label ( self . tcx ( ) . def_span ( def_id) , & format ! (
804
+ "type parameter{} {} must be specified for this" ,
805
+ pluralize!( missing_type_params. len( ) ) ,
806
+ display,
807
+ ) ) ;
808
+ let mut suggested = false ;
809
+ if let ( Ok ( snippet) , true ) = (
810
+ self . tcx ( ) . sess . source_map ( ) . span_to_snippet ( span) ,
811
+ // Don't suggest setting the type params if there are some already: the order is
812
+ // tricky to get right and the user will already know what the syntax is.
813
+ empty_generic_args,
814
+ ) {
815
+ if snippet. ends_with ( '>' ) {
816
+ // The user wrote `Trait<'a, T>` or similar. To provide an accurate suggestion
817
+ // we would have to preserve the right order. For now, as clearly the user is
818
+ // aware of the syntax, we do nothing.
819
+ } else {
820
+ // The user wrote `Iterator`, so we don't have a type we can suggest, but at
821
+ // least we can clue them to the correct syntax `Iterator<Type>`.
822
+ err. span_suggestion (
823
+ span,
824
+ & format ! (
825
+ "set the type parameter{plural} to the desired type{plural}" ,
826
+ plural=pluralize!( missing_type_params. len( ) ) ,
827
+ ) ,
828
+ format ! ( "{}<{}>" , snippet, missing_type_params. join( ", " ) ) ,
829
+ Applicability :: HasPlaceholders ,
830
+ ) ;
831
+ suggested = true ;
832
+ }
833
+ }
834
+ if !suggested {
835
+ err. span_label ( span, format ! (
836
+ "missing reference{} to {}" ,
837
+ pluralize!( missing_type_params. len( ) ) ,
838
+ display,
839
+ ) ) ;
840
+ }
841
+ err. note ( & format ! ( "because of the default `Self` reference, type parameters must be \
842
+ specified on object types") ) ;
843
+ err. emit ( ) ;
844
+ }
845
+
829
846
/// Instantiates the path for the given trait reference, assuming that it's
830
847
/// bound to a valid trait type. Returns the `DefId` of the defining trait.
831
848
/// The type _cannot_ be a type other than a trait type.
@@ -859,13 +876,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
859
876
860
877
self . prohibit_generics ( trait_ref. path . segments . split_last ( ) . unwrap ( ) . 1 ) ;
861
878
862
- let path_span = if trait_ref. path . segments . len ( ) == 1 {
879
+ let path_span = if let [ segment ] = & trait_ref. path . segments [ .. ] {
863
880
// FIXME: `trait_ref.path.span` can point to a full path with multiple
864
881
// segments, even though `trait_ref.path.segments` is of length `1`. Work
865
882
// around that bug here, even though it should be fixed elsewhere.
866
883
// This would otherwise cause an invalid suggestion. For an example, look at
867
884
// `src/test/ui/issues/issue-28344.rs`.
868
- trait_ref . path . segments [ 0 ] . ident . span
885
+ segment . ident . span
869
886
} else {
870
887
trait_ref. path . span
871
888
} ;
@@ -1397,115 +1414,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
1397
1414
associated_types. remove ( & projection_bound. projection_def_id ( ) ) ;
1398
1415
}
1399
1416
1400
- if !associated_types. is_empty ( ) {
1401
- // Account for things like `dyn Foo + 'a` by pointing at the `TraitRef.path`
1402
- // `Span` instead of the `PolyTraitRef` `Span`. That way the suggestion will
1403
- // be valid, otherwise we would suggest `dyn Foo + 'a<A = Type>`. See tests
1404
- // `issue-22434.rs` and `issue-22560.rs` for examples.
1405
- let sugg_span = if potential_assoc_types. is_empty ( ) && trait_bounds. len ( ) == 1 {
1406
- if trait_bounds[ 0 ] . trait_ref . path . segments . len ( ) == 1 &&
1407
- trait_bounds[ 0 ] . trait_ref . path . segments [ 0 ] . args . is_none ( )
1408
- {
1409
- // FIXME: `trait_ref.path.span` can point to a full path with multiple
1410
- // segments, even though `trait_ref.path.segments` is of length `1`. Work
1411
- // around that bug here, even though it should be fixed elsewhere.
1412
- // This would otherwise cause an invalid suggestion. For an example, look at
1413
- // `src/test/ui/issues/issue-28344.rs`.
1414
- trait_bounds[ 0 ] . trait_ref . path . segments [ 0 ] . ident . span
1415
- } else {
1416
- trait_bounds[ 0 ] . trait_ref . path . span
1417
- }
1418
- } else {
1419
- span
1420
- } ;
1421
- let names = associated_types. iter ( ) . map ( |item_def_id| {
1422
- let assoc_item = tcx. associated_item ( * item_def_id) ;
1423
- let trait_def_id = assoc_item. container . id ( ) ;
1424
- format ! ( "`{}` (from trait `{}`)" , assoc_item. ident, tcx. def_path_str( trait_def_id) )
1425
- } ) . collect :: < Vec < _ > > ( ) . join ( ", " ) ;
1426
- let mut err = struct_span_err ! (
1427
- tcx. sess,
1428
- sugg_span,
1429
- E0191 ,
1430
- "the value of the associated type{} {} must be specified" ,
1431
- pluralize!( associated_types. len( ) ) ,
1432
- names,
1433
- ) ;
1434
- let mut suggestions = Vec :: new ( ) ;
1435
- let mut applicability = Applicability :: MaybeIncorrect ;
1436
- for ( i, item_def_id) in associated_types. iter ( ) . enumerate ( ) {
1437
- let assoc_item = tcx. associated_item ( * item_def_id) ;
1438
- if let Some ( sp) = tcx. hir ( ) . span_if_local ( * item_def_id) {
1439
- err. span_label ( sp, format ! ( "`{}` defined here" , assoc_item. ident) ) ;
1440
- }
1441
- if potential_assoc_types. len ( ) == associated_types. len ( ) {
1442
- // Only suggest when the amount of missing associated types equals the number of
1443
- // extra type arguments present, as that gives us a relatively high confidence
1444
- // that the user forgot to give the associtated type's name. The canonical
1445
- // example would be trying to use `Iterator<isize>` instead of
1446
- // `Iterator<Item = isize>`.
1447
- if let Ok ( snippet) = tcx. sess . source_map ( ) . span_to_snippet (
1448
- potential_assoc_types[ i] ,
1449
- ) {
1450
- suggestions. push ( (
1451
- potential_assoc_types[ i] ,
1452
- format ! ( "{} = {}" , assoc_item. ident, snippet) ,
1453
- ) ) ;
1454
- }
1455
- }
1456
- }
1457
- let mut suggestions_len = suggestions. len ( ) ;
1458
- if let Ok ( snippet) = tcx. sess . source_map ( ) . span_to_snippet ( sugg_span) {
1459
- if potential_assoc_types. is_empty ( ) && trait_bounds. len ( ) == 1 &&
1460
- // Do not attempt to suggest when we don't know which path segment needs the
1461
- // type parameter set.
1462
- trait_bounds[ 0 ] . trait_ref . path . segments . len ( ) == 1
1463
- {
1464
- debug ! ( "path segments {:?}" , trait_bounds[ 0 ] . trait_ref. path. segments) ;
1465
- applicability = Applicability :: HasPlaceholders ;
1466
- let assoc_types: Vec < String > = associated_types. iter ( )
1467
- . map ( |item_def_id| {
1468
- let assoc_item = tcx. associated_item ( * item_def_id) ;
1469
- format ! ( "{} = Type" , assoc_item. ident)
1470
- } )
1471
- . collect ( ) ;
1472
- let sugg = assoc_types. join ( ", " ) ;
1473
- if snippet. ends_with ( '>' ) {
1474
- // The user wrote `Trait<'a>` or similar and we don't have a type we can
1475
- // suggest, but at least we can clue them to the correct syntax
1476
- // `Trait<'a, Item = Type>` while accounting for the `<'a>` in the
1477
- // suggestion.
1478
- suggestions. push ( ( sugg_span, format ! (
1479
- "{}, {}>" ,
1480
- & snippet[ ..snippet. len( ) -1 ] ,
1481
- sugg,
1482
- ) ) ) ;
1483
- } else {
1484
- // The user wrote `Iterator`, so we don't have a type we can suggest, but at
1485
- // least we can clue them to the correct syntax `Iterator<Item = Type>`.
1486
- suggestions. push ( ( sugg_span, format ! ( "{}<{}>" , snippet, sugg) ) ) ;
1487
- }
1488
- suggestions_len = assoc_types. len ( ) ;
1489
- }
1490
- }
1491
- if suggestions. len ( ) != 1 {
1492
- // We don't need this label if there's an inline suggestion, show otherwise.
1493
- let names = associated_types. iter ( )
1494
- . map ( |t| format ! ( "`{}`" , tcx. associated_item( * t) . ident) )
1495
- . collect :: < Vec < _ > > ( )
1496
- . join ( ", " ) ;
1497
- err. span_label ( span, format ! (
1498
- "associated type{} {} must be specified" ,
1499
- pluralize!( associated_types. len( ) ) ,
1500
- names,
1501
- ) ) ;
1502
- }
1503
- if !suggestions. is_empty ( ) {
1504
- let msg = format ! ( "specify the associated type{}" , pluralize!( suggestions_len) ) ;
1505
- err. multipart_suggestion ( & msg, suggestions, applicability) ;
1506
- }
1507
- err. emit ( ) ;
1508
- }
1417
+ self . complain_about_missing_associated_types (
1418
+ span,
1419
+ associated_types,
1420
+ potential_assoc_types,
1421
+ trait_bounds,
1422
+ ) ;
1509
1423
1510
1424
// De-duplicate auto traits so that, e.g., `dyn Trait + Send + Send` is the same as
1511
1425
// `dyn Trait + Send`.
@@ -1585,6 +1499,122 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
1585
1499
ty
1586
1500
}
1587
1501
1502
+ fn complain_about_missing_associated_types (
1503
+ & self ,
1504
+ span : Span ,
1505
+ associated_types : BTreeSet < DefId > ,
1506
+ potential_assoc_types : Vec < Span > ,
1507
+ trait_bounds : & [ hir:: PolyTraitRef ] ,
1508
+ ) {
1509
+ if associated_types. is_empty ( ) {
1510
+ return ;
1511
+ }
1512
+ // Account for things like `dyn Foo + 'a` by pointing at the `TraitRef.path`
1513
+ // `Span` instead of the `PolyTraitRef` `Span`. That way the suggestion will
1514
+ // be valid, otherwise we would suggest `dyn Foo + 'a<A = Type>`. See tests
1515
+ // `issue-22434.rs` and `issue-22560.rs` for examples.
1516
+ let sugg_span = match ( & potential_assoc_types[ ..] , & trait_bounds) {
1517
+ ( [ ] , [ bound] ) => match & bound. trait_ref . path . segments [ ..] {
1518
+ // FIXME: `trait_ref.path.span` can point to a full path with multiple
1519
+ // segments, even though `trait_ref.path.segments` is of length `1`. Work
1520
+ // around that bug here, even though it should be fixed elsewhere.
1521
+ // This would otherwise cause an invalid suggestion. For an example, look at
1522
+ // `src/test/ui/issues/issue-28344.rs`.
1523
+ [ segment] if segment. args . is_none ( ) => segment. ident . span ,
1524
+ _ => bound. trait_ref . path . span ,
1525
+ } ,
1526
+ _ => span,
1527
+ } ;
1528
+ let tcx = self . tcx ( ) ;
1529
+ let names = associated_types. iter ( ) . map ( |item_def_id| {
1530
+ let assoc_item = tcx. associated_item ( * item_def_id) ;
1531
+ let trait_def_id = assoc_item. container . id ( ) ;
1532
+ format ! ( "`{}` (from trait `{}`)" , assoc_item. ident, tcx. def_path_str( trait_def_id) )
1533
+ } ) . collect :: < Vec < _ > > ( ) . join ( ", " ) ;
1534
+ let mut err = struct_span_err ! (
1535
+ tcx. sess,
1536
+ sugg_span,
1537
+ E0191 ,
1538
+ "the value of the associated type{} {} must be specified" ,
1539
+ pluralize!( associated_types. len( ) ) ,
1540
+ names,
1541
+ ) ;
1542
+ let mut suggestions = Vec :: new ( ) ;
1543
+ let mut applicability = Applicability :: MaybeIncorrect ;
1544
+ for ( i, item_def_id) in associated_types. iter ( ) . enumerate ( ) {
1545
+ let assoc_item = tcx. associated_item ( * item_def_id) ;
1546
+ if let Some ( sp) = tcx. hir ( ) . span_if_local ( * item_def_id) {
1547
+ err. span_label ( sp, format ! ( "`{}` defined here" , assoc_item. ident) ) ;
1548
+ }
1549
+ if potential_assoc_types. len ( ) == associated_types. len ( ) {
1550
+ // Only suggest when the amount of missing associated types equals the number of
1551
+ // extra type arguments present, as that gives us a relatively high confidence
1552
+ // that the user forgot to give the associtated type's name. The canonical
1553
+ // example would be trying to use `Iterator<isize>` instead of
1554
+ // `Iterator<Item = isize>`.
1555
+ if let Ok ( snippet) = tcx. sess . source_map ( ) . span_to_snippet (
1556
+ potential_assoc_types[ i] ,
1557
+ ) {
1558
+ suggestions. push ( (
1559
+ potential_assoc_types[ i] ,
1560
+ format ! ( "{} = {}" , assoc_item. ident, snippet) ,
1561
+ ) ) ;
1562
+ }
1563
+ }
1564
+ }
1565
+ let mut suggestions_len = suggestions. len ( ) ;
1566
+ if let Ok ( snippet) = tcx. sess . source_map ( ) . span_to_snippet ( sugg_span) {
1567
+ if potential_assoc_types. is_empty ( ) && trait_bounds. len ( ) == 1 &&
1568
+ // Do not attempt to suggest when we don't know which path segment needs the
1569
+ // type parameter set.
1570
+ trait_bounds[ 0 ] . trait_ref . path . segments . len ( ) == 1
1571
+ {
1572
+ debug ! ( "path segments {:?}" , trait_bounds[ 0 ] . trait_ref. path. segments) ;
1573
+ applicability = Applicability :: HasPlaceholders ;
1574
+ let assoc_types: Vec < String > = associated_types. iter ( )
1575
+ . map ( |item_def_id| {
1576
+ let assoc_item = tcx. associated_item ( * item_def_id) ;
1577
+ format ! ( "{} = Type" , assoc_item. ident)
1578
+ } )
1579
+ . collect ( ) ;
1580
+ let sugg = assoc_types. join ( ", " ) ;
1581
+ if snippet. ends_with ( '>' ) {
1582
+ // The user wrote `Trait<'a>` or similar and we don't have a type we can
1583
+ // suggest, but at least we can clue them to the correct syntax
1584
+ // `Trait<'a, Item = Type>` while accounting for the `<'a>` in the
1585
+ // suggestion.
1586
+ suggestions. push ( ( sugg_span, format ! (
1587
+ "{}, {}>" ,
1588
+ & snippet[ ..snippet. len( ) -1 ] ,
1589
+ sugg,
1590
+ ) ) ) ;
1591
+ } else {
1592
+ // The user wrote `Iterator`, so we don't have a type we can suggest, but at
1593
+ // least we can clue them to the correct syntax `Iterator<Item = Type>`.
1594
+ suggestions. push ( ( sugg_span, format ! ( "{}<{}>" , snippet, sugg) ) ) ;
1595
+ }
1596
+ suggestions_len = assoc_types. len ( ) ;
1597
+ }
1598
+ }
1599
+ if suggestions. len ( ) != 1 {
1600
+ // We don't need this label if there's an inline suggestion, show otherwise.
1601
+ let names = associated_types. iter ( )
1602
+ . map ( |t| format ! ( "`{}`" , tcx. associated_item( * t) . ident) )
1603
+ . collect :: < Vec < _ > > ( )
1604
+ . join ( ", " ) ;
1605
+ err. span_label ( span, format ! (
1606
+ "associated type{} {} must be specified" ,
1607
+ pluralize!( associated_types. len( ) ) ,
1608
+ names,
1609
+ ) ) ;
1610
+ }
1611
+ if !suggestions. is_empty ( ) {
1612
+ let msg = format ! ( "specify the associated type{}" , pluralize!( suggestions_len) ) ;
1613
+ err. multipart_suggestion ( & msg, suggestions, applicability) ;
1614
+ }
1615
+ err. emit ( ) ;
1616
+ }
1617
+
1588
1618
fn report_ambiguous_associated_type (
1589
1619
& self ,
1590
1620
span : Span ,
0 commit comments