@@ -20,6 +20,7 @@ use syntax::ast::{self, Ident, Path};
2020use syntax:: util:: lev_distance:: find_best_match_for_name;
2121
2222use crate :: imports:: { ImportDirective , ImportDirectiveSubclass , ImportResolver } ;
23+ use crate :: lifetimes:: { ElisionFailureInfo , LifetimeContext } ;
2324use crate :: path_names_to_string;
2425use crate :: { AmbiguityError , AmbiguityErrorMisc , AmbiguityKind } ;
2526use crate :: { BindingError , CrateLint , HasGenericParams , LegacyScope , Module , ModuleOrUniformRoot } ;
@@ -48,6 +49,40 @@ crate struct ImportSuggestion {
4849 pub path : Path ,
4950}
5051
52+ crate enum MissingLifetimeSpot < ' tcx > {
53+ Generics ( & ' tcx hir:: Generics < ' tcx > ) ,
54+ HigherRanked { span : Span , span_type : ForLifetimeSpanType } ,
55+ }
56+
57+ crate enum ForLifetimeSpanType {
58+ BoundEmpty ,
59+ BoundTail ,
60+ TypeEmpty ,
61+ TypeTail ,
62+ }
63+
64+ impl ForLifetimeSpanType {
65+ crate fn descr ( & self ) -> & ' static str {
66+ match self {
67+ Self :: BoundEmpty | Self :: BoundTail => "bound" ,
68+ Self :: TypeEmpty | Self :: TypeTail => "type" ,
69+ }
70+ }
71+
72+ crate fn suggestion ( & self , sugg : & str ) -> String {
73+ match self {
74+ Self :: BoundEmpty | Self :: TypeEmpty => format ! ( "for<{}> " , sugg) ,
75+ Self :: BoundTail | Self :: TypeTail => format ! ( ", {}" , sugg) ,
76+ }
77+ }
78+ }
79+
80+ impl < ' tcx > Into < MissingLifetimeSpot < ' tcx > > for & ' tcx hir:: Generics < ' tcx > {
81+ fn into ( self ) -> MissingLifetimeSpot < ' tcx > {
82+ MissingLifetimeSpot :: Generics ( self )
83+ }
84+ }
85+
5186/// Adjust the impl span so that just the `impl` keyword is taken by removing
5287/// everything after `<` (`"impl<T> Iterator for A<T> {}" -> "impl"`) and
5388/// everything after the first whitespace (`"impl Iterator for A" -> "impl"`).
@@ -1457,72 +1492,206 @@ crate fn show_candidates(
14571492 }
14581493}
14591494
1460- crate fn report_missing_lifetime_specifiers (
1461- sess : & Session ,
1462- span : Span ,
1463- count : usize ,
1464- ) -> DiagnosticBuilder < ' _ > {
1465- struct_span_err ! ( sess, span, E0106 , "missing lifetime specifier{}" , pluralize!( count) )
1466- }
1495+ impl < ' tcx > LifetimeContext < ' _ , ' tcx > {
1496+ crate fn report_missing_lifetime_specifiers (
1497+ & self ,
1498+ span : Span ,
1499+ count : usize ,
1500+ ) -> DiagnosticBuilder < ' tcx > {
1501+ struct_span_err ! (
1502+ self . tcx. sess,
1503+ span,
1504+ E0106 ,
1505+ "missing lifetime specifier{}" ,
1506+ pluralize!( count)
1507+ )
1508+ }
14671509
1468- crate fn add_missing_lifetime_specifiers_label (
1469- err : & mut DiagnosticBuilder < ' _ > ,
1470- span : Span ,
1471- count : usize ,
1472- lifetime_names : & FxHashSet < ast:: Ident > ,
1473- snippet : Option < & str > ,
1474- missing_named_lifetime_spots : & [ & hir:: Generics < ' _ > ] ,
1475- ) {
1476- if count > 1 {
1477- err. span_label ( span, format ! ( "expected {} lifetime parameters" , count) ) ;
1478- } else {
1479- let suggest_existing = |err : & mut DiagnosticBuilder < ' _ > , sugg| {
1480- err. span_suggestion (
1481- span,
1482- "consider using the named lifetime" ,
1483- sugg,
1484- Applicability :: MaybeIncorrect ,
1485- ) ;
1486- } ;
1487- let suggest_new = |err : & mut DiagnosticBuilder < ' _ > , sugg| {
1488- err. span_label ( span, "expected named lifetime parameter" ) ;
1489-
1490- if let Some ( generics) = missing_named_lifetime_spots. iter ( ) . last ( ) {
1491- let mut introduce_suggestion = vec ! [ ] ;
1492- introduce_suggestion. push ( match & generics. params {
1493- [ ] => ( generics. span , "<'lifetime>" . to_string ( ) ) ,
1494- [ param, ..] => ( param. span . shrink_to_lo ( ) , "'lifetime, " . to_string ( ) ) ,
1495- } ) ;
1496- introduce_suggestion. push ( ( span, sugg) ) ;
1497- err. multipart_suggestion (
1498- "consider introducing a named lifetime parameter" ,
1499- introduce_suggestion,
1500- Applicability :: MaybeIncorrect ,
1501- ) ;
1510+ crate fn emit_undeclared_lifetime_error ( & self , lifetime_ref : & hir:: Lifetime ) {
1511+ let mut err = struct_span_err ! (
1512+ self . tcx. sess,
1513+ lifetime_ref. span,
1514+ E0261 ,
1515+ "use of undeclared lifetime name `{}`" ,
1516+ lifetime_ref
1517+ ) ;
1518+ err. span_label ( lifetime_ref. span , "undeclared lifetime" ) ;
1519+ for missing in & self . missing_named_lifetime_spots {
1520+ match missing {
1521+ MissingLifetimeSpot :: Generics ( generics) => {
1522+ let ( span, sugg) = if let Some ( param) = generics
1523+ . params
1524+ . iter ( )
1525+ . filter ( |p| match p. kind {
1526+ hir:: GenericParamKind :: Type {
1527+ synthetic : Some ( hir:: SyntheticTyParamKind :: ImplTrait ) ,
1528+ ..
1529+ } => false ,
1530+ _ => true ,
1531+ } )
1532+ . next ( )
1533+ {
1534+ ( param. span . shrink_to_lo ( ) , format ! ( "{}, " , lifetime_ref) )
1535+ } else {
1536+ ( generics. span , format ! ( "<{}>" , lifetime_ref) )
1537+ } ;
1538+ err. span_suggestion (
1539+ span,
1540+ & format ! ( "consider introducing lifetime `{}` here" , lifetime_ref) ,
1541+ sugg,
1542+ Applicability :: MaybeIncorrect ,
1543+ ) ;
1544+ }
1545+ MissingLifetimeSpot :: HigherRanked { span, span_type } => {
1546+ err. span_suggestion (
1547+ * span,
1548+ & format ! (
1549+ "consider making the {} lifetime-generic with a new `{}` lifetime" ,
1550+ span_type. descr( ) ,
1551+ lifetime_ref
1552+ ) ,
1553+ span_type. suggestion ( & lifetime_ref. to_string ( ) ) ,
1554+ Applicability :: MaybeIncorrect ,
1555+ ) ;
1556+ err. note (
1557+ "for more information on higher-ranked polymorphism, visit \
1558+ https://doc.rust-lang.org/nomicon/hrtb.html",
1559+ ) ;
1560+ }
15021561 }
1503- } ;
1562+ }
1563+ err. emit ( ) ;
1564+ }
15041565
1505- match ( lifetime_names. len ( ) , lifetime_names. iter ( ) . next ( ) , snippet) {
1506- ( 1 , Some ( name) , Some ( "&" ) ) => {
1507- suggest_existing ( err, format ! ( "&{} " , name) ) ;
1508- }
1509- ( 1 , Some ( name) , Some ( "'_" ) ) => {
1510- suggest_existing ( err, name. to_string ( ) ) ;
1511- }
1512- ( 1 , Some ( name) , Some ( snippet) ) if !snippet. ends_with ( ">" ) => {
1513- suggest_existing ( err, format ! ( "{}<{}>" , snippet, name) ) ;
1514- }
1515- ( 0 , _, Some ( "&" ) ) => {
1516- suggest_new ( err, "&'lifetime " . to_string ( ) ) ;
1517- }
1518- ( 0 , _, Some ( "'_" ) ) => {
1519- suggest_new ( err, "'lifetime" . to_string ( ) ) ;
1520- }
1521- ( 0 , _, Some ( snippet) ) if !snippet. ends_with ( ">" ) => {
1522- suggest_new ( err, format ! ( "{}<'lifetime>" , snippet) ) ;
1566+ crate fn is_trait_ref_fn_scope ( & mut self , trait_ref : & ' tcx hir:: PolyTraitRef < ' tcx > ) -> bool {
1567+ if let def:: Res :: Def ( _, did) = trait_ref. trait_ref . path . res {
1568+ if [
1569+ self . tcx . lang_items ( ) . fn_once_trait ( ) ,
1570+ self . tcx . lang_items ( ) . fn_trait ( ) ,
1571+ self . tcx . lang_items ( ) . fn_mut_trait ( ) ,
1572+ ]
1573+ . contains ( & Some ( did) )
1574+ {
1575+ let ( span, span_type) = match & trait_ref. bound_generic_params {
1576+ [ ] => ( trait_ref. span . shrink_to_lo ( ) , ForLifetimeSpanType :: BoundEmpty ) ,
1577+ [ .., bound] => ( bound. span . shrink_to_hi ( ) , ForLifetimeSpanType :: BoundTail ) ,
1578+ } ;
1579+ self . missing_named_lifetime_spots
1580+ . push ( MissingLifetimeSpot :: HigherRanked { span, span_type } ) ;
1581+ return true ;
15231582 }
1524- _ => {
1525- err. span_label ( span, "expected lifetime parameter" ) ;
1583+ } ;
1584+ false
1585+ }
1586+
1587+ crate fn add_missing_lifetime_specifiers_label (
1588+ & self ,
1589+ err : & mut DiagnosticBuilder < ' _ > ,
1590+ span : Span ,
1591+ count : usize ,
1592+ lifetime_names : & FxHashSet < ast:: Ident > ,
1593+ params : & [ ElisionFailureInfo ] ,
1594+ ) {
1595+ if count > 1 {
1596+ err. span_label ( span, format ! ( "expected {} lifetime parameters" , count) ) ;
1597+ } else {
1598+ let snippet = self . tcx . sess . source_map ( ) . span_to_snippet ( span) . ok ( ) ;
1599+ let suggest_existing = |err : & mut DiagnosticBuilder < ' _ > , sugg| {
1600+ err. span_suggestion (
1601+ span,
1602+ "consider using the named lifetime" ,
1603+ sugg,
1604+ Applicability :: MaybeIncorrect ,
1605+ ) ;
1606+ } ;
1607+ let suggest_new =
1608+ |err : & mut DiagnosticBuilder < ' _ > , sugg : & str | {
1609+ err. span_label ( span, "expected named lifetime parameter" ) ;
1610+
1611+ for missing in self . missing_named_lifetime_spots . iter ( ) . rev ( ) {
1612+ let mut introduce_suggestion = vec ! [ ] ;
1613+ let msg;
1614+ let should_break;
1615+ introduce_suggestion. push ( match missing {
1616+ MissingLifetimeSpot :: Generics ( generics) => {
1617+ msg = "consider introducing a named lifetime parameter" . to_string ( ) ;
1618+ should_break = true ;
1619+ if let Some ( param) = generics. params . iter ( ) . filter ( |p| match p. kind {
1620+ hir:: GenericParamKind :: Type {
1621+ synthetic : Some ( hir:: SyntheticTyParamKind :: ImplTrait ) ,
1622+ ..
1623+ } => false ,
1624+ _ => true ,
1625+ } ) . next ( ) {
1626+ ( param. span . shrink_to_lo ( ) , "'a, " . to_string ( ) )
1627+ } else {
1628+ ( generics. span , "<'a>" . to_string ( ) )
1629+ }
1630+ }
1631+ MissingLifetimeSpot :: HigherRanked { span, span_type } => {
1632+ msg = format ! (
1633+ "consider making the {} lifetime-generic with a new `'a` lifetime" ,
1634+ span_type. descr( ) ,
1635+ ) ;
1636+ should_break = false ;
1637+ err. note (
1638+ "for more information on higher-ranked polymorphism, visit \
1639+ https://doc.rust-lang.org/nomicon/hrtb.html",
1640+ ) ;
1641+ ( * span, span_type. suggestion ( "'a" ) )
1642+ }
1643+ } ) ;
1644+ for param in params {
1645+ if let Ok ( snippet) =
1646+ self . tcx . sess . source_map ( ) . span_to_snippet ( param. span )
1647+ {
1648+ if snippet. starts_with ( "&" ) && !snippet. starts_with ( "&'" ) {
1649+ introduce_suggestion
1650+ . push ( ( param. span , format ! ( "&'a {}" , & snippet[ 1 ..] ) ) ) ;
1651+ } else if snippet. starts_with ( "&'_ " ) {
1652+ introduce_suggestion
1653+ . push ( ( param. span , format ! ( "&'a {}" , & snippet[ 4 ..] ) ) ) ;
1654+ }
1655+ }
1656+ }
1657+ introduce_suggestion. push ( ( span, sugg. to_string ( ) ) ) ;
1658+ err. multipart_suggestion (
1659+ & msg,
1660+ introduce_suggestion,
1661+ Applicability :: MaybeIncorrect ,
1662+ ) ;
1663+ if should_break {
1664+ break ;
1665+ }
1666+ }
1667+ } ;
1668+
1669+ match (
1670+ lifetime_names. len ( ) ,
1671+ lifetime_names. iter ( ) . next ( ) ,
1672+ snippet. as_ref ( ) . map ( |s| s. as_str ( ) ) ,
1673+ ) {
1674+ ( 1 , Some ( name) , Some ( "&" ) ) => {
1675+ suggest_existing ( err, format ! ( "&{} " , name) ) ;
1676+ }
1677+ ( 1 , Some ( name) , Some ( "'_" ) ) => {
1678+ suggest_existing ( err, name. to_string ( ) ) ;
1679+ }
1680+ ( 1 , Some ( name) , Some ( snippet) ) if !snippet. ends_with ( ">" ) => {
1681+ suggest_existing ( err, format ! ( "{}<{}>" , snippet, name) ) ;
1682+ }
1683+ ( 0 , _, Some ( "&" ) ) => {
1684+ suggest_new ( err, "&'a " ) ;
1685+ }
1686+ ( 0 , _, Some ( "'_" ) ) => {
1687+ suggest_new ( err, "'a" ) ;
1688+ }
1689+ ( 0 , _, Some ( snippet) ) if !snippet. ends_with ( ">" ) => {
1690+ suggest_new ( err, & format ! ( "{}<'a>" , snippet) ) ;
1691+ }
1692+ _ => {
1693+ err. span_label ( span, "expected lifetime parameter" ) ;
1694+ }
15261695 }
15271696 }
15281697 }
0 commit comments