]> git.lizzy.rs Git - rust.git/commitdiff
Suggest using anonymous lifetime in `impl Trait` return without hacks
authorEsteban Küber <esteban@kuber.com.ar>
Sun, 31 Mar 2019 16:07:56 +0000 (09:07 -0700)
committerEsteban Küber <esteban@kuber.com.ar>
Sun, 31 Mar 2019 16:11:47 +0000 (09:11 -0700)
Fallback to `static_impl_trait` for nice error message by peeking at the
return type and the lifetime type. Point at the return type instead of
the return expr/stmt in NLL mode.

src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs
src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs
src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs
src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr
src/test/ui/nll/ty-outlives/impl-trait-captures.rs
src/test/ui/nll/ty-outlives/impl-trait-captures.stderr

index 8b44aa5e706012ea950903ff8c042ad930aa84ee..7403a5d7dbb09e80219a9441da7b95c3abf2a222 100644 (file)
@@ -1,6 +1,7 @@
 //! Error Reporting for Anonymous Region Lifetime Errors
 //! where one region is named and the other is anonymous.
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
+use crate::hir::{FunctionRetTy, TyKind};
 use crate::ty;
 use errors::{Applicability, DiagnosticBuilder};
 
@@ -11,9 +12,10 @@ pub(super) fn try_report_named_anon_conflict(&self) -> Option<DiagnosticBuilder<
         let (span, sub, sup) = self.get_regions();
 
         debug!(
-            "try_report_named_anon_conflict(sub={:?}, sup={:?})",
+            "try_report_named_anon_conflict(sub={:?}, sup={:?}, error={:?})",
             sub,
-            sup
+            sup,
+            self.error,
         );
 
         // Determine whether the sub and sup consist of one named region ('a)
@@ -84,6 +86,13 @@ pub(super) fn try_report_named_anon_conflict(&self) -> Option<DiagnosticBuilder<
             {
                 return None;
             }
+            if let FunctionRetTy::Return(ty) = &fndecl.output {
+                if let (TyKind::Def(_, _), ty::ReStatic) = (&ty.node, sub) {
+                    // This is an impl Trait return that evaluates de need of 'static.
+                    // We handle this case better in `static_impl_trait`.
+                    return None;
+                }
+            }
         }
 
         let (error_var, span_label_var) = if let Some(simple_ident) = arg.pat.simple_ident() {
@@ -103,40 +112,10 @@ pub(super) fn try_report_named_anon_conflict(&self) -> Option<DiagnosticBuilder<
             error_var
         );
 
-        let many = if let Ok(snippet) = self.tcx().sess.source_map().span_to_snippet(span) {
-            if "'static" == &named.to_string() && snippet.starts_with("impl ") {
-                diag.span_suggestion(
-                    span,
-                    "add explicit unnamed lifetime `'_` to the return type to constrain it",
-                    format!("{} + '_", snippet),
-                    Applicability::Unspecified,
-                );
-                true
-            } else {
-                false
-            }
-        } else {
-            false
-        };
-        if many {
-            diag.span_label(
-                span,
-                "`impl Trait` types can only capture lifetimes that they reference"
-            );
-        } else {
-            diag.span_label(span, format!("lifetime `{}` required", named));
-        }
+        diag.span_label(span, format!("lifetime `{}` required", named));
         diag.span_suggestion(
             new_ty_span,
-            &format!("{}add explicit lifetime `{}` to {}",
-                if many {
-                    "otherwise, "
-                } else {
-                    ""
-                },
-                named,
-                span_label_var,
-            ),
+            &format!("add explicit lifetime `{}` to {}", named, span_label_var),
             new_ty.to_string(),
             Applicability::Unspecified,
         );
index 081c458bfc17a37d821b7f544e8d7316fe85f9f1..3773f1a40c7924545878b83ec8b7dc0c03a4370d 100644 (file)
@@ -132,6 +132,15 @@ fn best_blame_constraint(
             }
         });
         if let Some(i) = best_choice {
+            if let Some(next) = categorized_path.get(i + 1) {
+                if categorized_path[i].0 == ConstraintCategory::Return
+                    && next.0 == ConstraintCategory::OpaqueType
+                {
+                    // The return expression is being influenced by the return type being
+                    // impl Trait, point at the return type and not the return expr.
+                    return *next;
+                }
+            }
             return categorized_path[i];
         }
 
@@ -240,6 +249,7 @@ pub(super) fn report_error(
             self.provides_universal_region(r, fr, outlived_fr)
         });
 
+        debug!("report_error: category={:?} {:?}", category, span);
         // Check if we can use one of the "nice region errors".
         if let (Some(f), Some(o)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) {
             let tables = infcx.tcx.typeck_tables_of(mir_def_id);
index ef1b976ae333f304fcfb9ebac9d30ac554ccd49a..1c3b5ac76138f2eb56f25c2effda0fb28a494d14 100644 (file)
@@ -1,7 +1,7 @@
 use std::fmt::Debug;
 
 fn elided(x: &i32) -> impl Copy { x }
-//~^ ERROR explicit lifetime required in the type of `x` [E0621]
+//~^ ERROR cannot infer an appropriate lifetime
 
 fn explicit<'a>(x: &'a i32) -> impl Copy { x }
 //~^ ERROR cannot infer an appropriate lifetime
index 8a155d1c1b21572560caa17fb953e17cfb8d495c..9339a83b09a9df8388a63cfc8e7a33bf3bb5227f 100644 (file)
@@ -1,16 +1,20 @@
-error[E0621]: explicit lifetime required in the type of `x`
-  --> $DIR/must_outlive_least_region_or_bound.rs:3:23
+error: cannot infer an appropriate lifetime
+  --> $DIR/must_outlive_least_region_or_bound.rs:3:35
    |
 LL | fn elided(x: &i32) -> impl Copy { x }
-   |                       ^^^^^^^^^ `impl Trait` types can only capture lifetimes that they reference
-help: add explicit unnamed lifetime `'_` to the return type to constrain it
+   |                       ---------   ^ ...but this borrow...
+   |                       |
+   |                       this return type evaluates to the `'static` lifetime...
+   |
+note: ...can't outlive the anonymous lifetime #1 defined on the function body at 3:1
+  --> $DIR/must_outlive_least_region_or_bound.rs:3:1
+   |
+LL | fn elided(x: &i32) -> impl Copy { x }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: you can add a constraint to the return type to make it last less than `'static` and match the anonymous lifetime #1 defined on the function body at 3:1
    |
 LL | fn elided(x: &i32) -> impl Copy + '_ { x }
    |                       ^^^^^^^^^^^^^^
-help: otherwise, add explicit lifetime `'static` to the type of `x`
-   |
-LL | fn elided(x: &'static i32) -> impl Copy { x }
-   |              ^^^^^^^^^^^^
 
 error: cannot infer an appropriate lifetime
   --> $DIR/must_outlive_least_region_or_bound.rs:6:44
@@ -73,5 +77,5 @@ LL | fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
 
 error: aborting due to 5 previous errors
 
-Some errors occurred: E0310, E0621, E0623.
+Some errors occurred: E0310, E0623.
 For more information about an error, try `rustc --explain E0310`.
index 7405505d5d6f8da237fe8089f0a4cb3af6c285ad..bcdf643c0b9d1136001d98643105630f55fe0231 100644 (file)
@@ -8,8 +8,8 @@ trait Foo<'a> {
 impl<'a, T> Foo<'a> for T { }
 
 fn foo<'a, T>(x: &T) -> impl Foo<'a> {
+//~^ ERROR explicit lifetime required in the type of `x` [E0621]
     x
-        //~^ ERROR explicit lifetime required in the type of `x` [E0621]
 }
 
 fn main() {}
index d9481b6156ca03bd6a6994096f88625366c88edc..3a1e3ce3ad1a0d3a539b60618d939688e2a6b65e 100644 (file)
@@ -1,8 +1,8 @@
 error[E0621]: explicit lifetime required in the type of `x`
-  --> $DIR/impl-trait-captures.rs:11:5
+  --> $DIR/impl-trait-captures.rs:10:25
    |
-LL |     x
-   |     ^ lifetime `ReEarlyBound(0, 'a)` required
+LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> {
+   |                         ^^^^^^^^^^^^ lifetime `ReEarlyBound(0, 'a)` required
 help: add explicit lifetime `ReEarlyBound(0, 'a)` to the type of `x`
    |
 LL | fn foo<'a, T>(x: &ReEarlyBound(0, 'a) T) -> impl Foo<'a> {