about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2018-06-07 23:07:46 -0700
committerEsteban Küber <esteban@kuber.com.ar>2018-06-08 15:25:20 -0700
commit82d3a49564aa09229fd9cc43e605b5a44f1108c1 (patch)
tree1eb8bfb02deae69d5df4e2dbca911a078ec8fad0
parent41affd03eb169830773cd1b11efda562ab81fad0 (diff)
downloadrust-82d3a49564aa09229fd9cc43e605b5a44f1108c1.tar.gz
rust-82d3a49564aa09229fd9cc43e605b5a44f1108c1.zip
Suggestion for 'static impl Trait return
When encountering a named or anonymous sup requirement (for example,
`&'a self`) and a `'static` impl Trait return type, suggest adding the
`'_` lifetime constraing to the return type.
-rw-r--r--src/librustc/infer/error_reporting/nice_region_error/mod.rs2
-rw-r--r--src/librustc/infer/error_reporting/nice_region_error/static_impl_trait.rs78
-rw-r--r--src/librustc/infer/error_reporting/nice_region_error/util.rs17
-rw-r--r--src/librustc/middle/mem_categorization.rs2
-rw-r--r--src/librustc/ty/sty.rs7
-rw-r--r--src/test/ui/impl-trait/static-return-lifetime-infered.rs26
-rw-r--r--src/test/ui/impl-trait/static-return-lifetime-infered.stderr44
7 files changed, 175 insertions, 1 deletions
diff --git a/src/librustc/infer/error_reporting/nice_region_error/mod.rs b/src/librustc/infer/error_reporting/nice_region_error/mod.rs
index 59b36a50a2b..f50c23b0aa7 100644
--- a/src/librustc/infer/error_reporting/nice_region_error/mod.rs
+++ b/src/librustc/infer/error_reporting/nice_region_error/mod.rs
@@ -19,6 +19,7 @@ mod different_lifetimes;
 mod find_anon_type;
 mod named_anon_conflict;
 mod outlives_closure;
+mod static_impl_trait;
 mod util;
 
 impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
@@ -67,6 +68,7 @@ impl<'cx, 'gcx, 'tcx> NiceRegionError<'cx, 'gcx, 'tcx> {
         self.try_report_named_anon_conflict()
             .or_else(|| self.try_report_anon_anon_conflict())
             .or_else(|| self.try_report_outlives_closure())
+            .or_else(|| self.try_report_static_impl_trait())
     }
 
     pub fn get_regions(&self) -> (Span, ty::Region<'tcx>, ty::Region<'tcx>) {
diff --git a/src/librustc/infer/error_reporting/nice_region_error/static_impl_trait.rs b/src/librustc/infer/error_reporting/nice_region_error/static_impl_trait.rs
new file mode 100644
index 00000000000..dd25edfa31e
--- /dev/null
+++ b/src/librustc/infer/error_reporting/nice_region_error/static_impl_trait.rs
@@ -0,0 +1,78 @@
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Error Reporting for static impl Traits.
+
+use infer::error_reporting::nice_region_error::NiceRegionError;
+use infer::lexical_region_resolve::RegionResolutionError;
+use ty::RegionKind;
+use util::common::ErrorReported;
+
+impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
+    /// Print the error message for lifetime errors when the return type is a static impl Trait.
+    pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> {
+        if let Some(ref error) = self.error {
+            match error.clone() {
+                RegionResolutionError::SubSupConflict(
+                    var_origin,
+                    sub_origin,
+                    sub_r,
+                    sup_origin,
+                    sup_r,
+                ) => {
+                    let anon_reg_sup = self.is_suitable_region(sup_r)?;
+                    if sub_r == &RegionKind::ReStatic &&
+                        self._is_return_type_impl_trait(anon_reg_sup.def_id)
+                    {
+                        let sp = var_origin.span();
+                        let return_sp = sub_origin.span();
+                        let mut err = self.tcx.sess.struct_span_err(
+                            sp,
+                            "can't infer an appropriate lifetime",
+                        );
+                        err.span_label(sp, "can't infer an appropriate lifetime");
+                        err.span_label(
+                            return_sp,
+                            "this return type evaluates to the `'static` lifetime...",
+                        );
+                        err.span_label(
+                            sup_origin.span(),
+                            "...but this borrow...",
+                        );
+
+                        let (lifetime, lt_sp_opt) = self.tcx.msg_span_from_free_region(sup_r);
+                        if let Some(lifetime_sp) = lt_sp_opt {
+                            err.span_note(
+                                lifetime_sp,
+                                &format!("...can't outlive {}", lifetime),
+                            );
+                        }
+
+                        if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(return_sp) {
+                            err.span_suggestion(
+                                return_sp,
+                                &format!(
+                                    "you can add a constraint to the return type to make it last \
+                                     less than `'static` and match {}",
+                                    lifetime,
+                                ),
+                                format!("{} + '_", snippet),
+                            );
+                        }
+                        err.emit();
+                        return Some(ErrorReported);
+                    }
+                }
+                _ => {}
+            }
+        }
+        None
+    }
+}
diff --git a/src/librustc/infer/error_reporting/nice_region_error/util.rs b/src/librustc/infer/error_reporting/nice_region_error/util.rs
index 8aadec64554..63e036166f8 100644
--- a/src/librustc/infer/error_reporting/nice_region_error/util.rs
+++ b/src/librustc/infer/error_reporting/nice_region_error/util.rs
@@ -167,6 +167,23 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
         }
         None
     }
+
+    pub(super) fn _is_return_type_impl_trait(
+        &self,
+        scope_def_id: DefId,
+    ) -> bool {
+        let ret_ty = self.tcx.type_of(scope_def_id);
+        match ret_ty.sty {
+            ty::TyFnDef(_, _) => {
+                let sig = ret_ty.fn_sig(self.tcx);
+                let output = self.tcx.erase_late_bound_regions(&sig.output());
+                return output.is_impl_trait();
+            }
+            _ => {}
+        }
+        false
+    }
+
     // Here we check for the case where anonymous region
     // corresponds to self and if yes, we display E0312.
     // FIXME(#42700) - Need to format self properly to
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 959dda69e30..abccad5a148 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -179,7 +179,7 @@ pub enum Note {
 // and how it is located, as well as the mutability of the memory in
 // which the value is stored.
 //
-// *WARNING* The field `cmt.type` is NOT necessarily the same as the
+// *WARNING* The field `cmt.ty` is NOT necessarily the same as the
 // result of `node_id_to_type(cmt.id)`. This is because the `id` is
 // always the `id` of the node producing the type; in an expression
 // like `*x`, the type of this deref node is the deref'd type (`T`),
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index f484fda2ae1..fcdd48d62a3 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -1754,6 +1754,13 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
         }
     }
 
+    pub fn is_impl_trait(&self) -> bool {
+        match self.sty {
+            TyAnon(..) => true,
+            _ => false,
+        }
+    }
+
     pub fn ty_to_def_id(&self) -> Option<DefId> {
         match self.sty {
             TyDynamic(ref tt, ..) => tt.principal().map(|p| p.def_id()),
diff --git a/src/test/ui/impl-trait/static-return-lifetime-infered.rs b/src/test/ui/impl-trait/static-return-lifetime-infered.rs
new file mode 100644
index 00000000000..412950d9671
--- /dev/null
+++ b/src/test/ui/impl-trait/static-return-lifetime-infered.rs
@@ -0,0 +1,26 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct A {
+    x: [(u32, u32); 10]
+}
+
+impl A {
+    fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
+        self.x.iter().map(|a| a.0)
+    }
+    //~^^^ ERROR can't infer an appropriate lifetime
+    fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
+        self.x.iter().map(|a| a.0)
+    }
+    //~^^^ ERROR can't infer an appropriate lifetime
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/static-return-lifetime-infered.stderr b/src/test/ui/impl-trait/static-return-lifetime-infered.stderr
new file mode 100644
index 00000000000..d115e88453b
--- /dev/null
+++ b/src/test/ui/impl-trait/static-return-lifetime-infered.stderr
@@ -0,0 +1,44 @@
+error: can't infer an appropriate lifetime
+  --> $DIR/static-return-lifetime-infered.rs:17:16
+   |
+LL |     fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
+   |                                   ----------------------- this return type evaluates to the `'static` lifetime...
+LL |         self.x.iter().map(|a| a.0)
+   |         ------ ^^^^ can't infer an appropriate lifetime
+   |         |
+   |         ...but this borrow...
+   |
+note: ...can't outlive the anonymous lifetime #1 defined on the method body at 16:5
+  --> $DIR/static-return-lifetime-infered.rs:16:5
+   |
+LL | /     fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
+LL | |         self.x.iter().map(|a| a.0)
+LL | |     }
+   | |_____^
+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 method body at 16:5
+   |
+LL |     fn iter_values_anon(&self) -> impl Iterator<Item=u32> + '_ {
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: can't infer an appropriate lifetime
+  --> $DIR/static-return-lifetime-infered.rs:21:16
+   |
+LL |     fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
+   |                                     ----------------------- this return type evaluates to the `'static` lifetime...
+LL |         self.x.iter().map(|a| a.0)
+   |         ------ ^^^^ can't infer an appropriate lifetime
+   |         |
+   |         ...but this borrow...
+   |
+note: ...can't outlive the lifetime 'a as defined on the method body at 20:5
+  --> $DIR/static-return-lifetime-infered.rs:20:5
+   |
+LL |     fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: you can add a constraint to the return type to make it last less than `'static` and match the lifetime 'a as defined on the method body at 20:5
+   |
+LL |     fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> + '_ {
+   |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+