about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAriel Ben-Yehuda <ariel.byd@gmail.com>2017-10-02 10:43:36 +0200
committerAriel Ben-Yehuda <ariel.byd@gmail.com>2017-10-02 10:43:36 +0200
commit706e52e2cc1e1ffab4face61f5906164236a0da8 (patch)
treeba4a167721aafffa52addcd8e631800458571d7c
parentad9986605f5f743ee8cc3da8189a68815313ab07 (diff)
downloadrust-706e52e2cc1e1ffab4face61f5906164236a0da8.tar.gz
rust-706e52e2cc1e1ffab4face61f5906164236a0da8.zip
fix handling of `Self`
-rw-r--r--src/librustc/infer/error_reporting/mod.rs3
-rw-r--r--src/librustc/ty/mod.rs37
-rw-r--r--src/librustc/ty/util.rs4
-rw-r--r--src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.rs6
-rw-r--r--src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr55
5 files changed, 79 insertions, 26 deletions
diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs
index 3c3c5395011..895894a0bb2 100644
--- a/src/librustc/infer/error_reporting/mod.rs
+++ b/src/librustc/infer/error_reporting/mod.rs
@@ -794,7 +794,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                     let generics = self.tcx.generics_of(did);
                     // Account for the case where `did` corresponds to `Self`, which doesn't have
                     // the expected type argument.
-                    if let Some(type_param) = generics.type_param(param, self.tcx) {
+                    if !param.is_self() {
+                        let type_param = generics.type_param(param, self.tcx);
                         let hir = &self.tcx.hir;
                         hir.as_local_node_id(type_param.def_id).map(|id| {
                             // Get the `hir::TyParam` to verify wether it already has any bounds.
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 46d2f65f34e..bc5a056dd33 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -713,6 +713,13 @@ impl ty::EarlyBoundRegion {
 
 /// Information about the formal type/lifetime parameters associated
 /// with an item or method. Analogous to hir::Generics.
+///
+/// Note that in the presence of a `Self` parameter, the ordering here
+/// is different from the ordering in a Substs. Substs are ordered as
+///     Self, *Regions, *Other Type Params, (...child generics)
+/// while this struct is ordered as
+///     regions = Regions
+///     types = [Self, *Other Type Params]
 #[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
 pub struct Generics {
     pub parent: Option<DefId>,
@@ -755,18 +762,34 @@ impl<'a, 'gcx, 'tcx> Generics {
         }
     }
 
-    /// Returns the `TypeParameterDef` associated with this `ParamTy`, or `None`
-    /// if `param` is `self`.
+    /// Returns the `TypeParameterDef` associated with this `ParamTy`.
     pub fn type_param(&'tcx self,
                       param: &ParamTy,
                       tcx: TyCtxt<'a, 'gcx, 'tcx>)
-                      -> Option<&TypeParameterDef> {
+                      -> &TypeParameterDef {
         if let Some(idx) = param.idx.checked_sub(self.parent_count() as u32) {
-            let type_param_start = (self.has_self as usize) + self.regions.len();
-            if let Some(idx) = (idx as usize).checked_sub(type_param_start) {
-                Some(&self.types[idx])
+            // non-Self type parameters are always offset by exactly
+            // `self.regions.len()`. In the absence of a Self, this is obvious,
+            // but even in the absence of a `Self` we just have to "compensate"
+            // for the regions:
+            //
+            // For example, for `trait Foo<'a, 'b, T1, T2>`, the
+            // situation is:
+            //     Substs:
+            //         0   1  2  3  4
+            //       Self 'a 'b  T1 T2
+            //     generics.types:
+            //         0  1  2
+            //       Self T1 T2
+            // And it can be seen that to move from a substs offset to a
+            // generics offset you just have to offset by the number of regions.
+            let type_param_offset = self.regions.len();
+            if let Some(idx) = (idx as usize).checked_sub(type_param_offset) {
+                assert!(!(self.has_self && idx == 0));
+                &self.types[idx]
             } else {
-                None
+                assert!(self.has_self && idx == 0);
+                &self.types[0]
             }
         } else {
             tcx.generics_of(self.parent.expect("parent_count>0 but no parent?"))
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index e4abe5ee615..c8037ce081a 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -519,9 +519,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                 } else if let Some(&ty::TyS {
                     sty: ty::TypeVariants::TyParam(ref pt), ..
                 }) = k.as_type() {
-                    !impl_generics.type_param(pt, self)
-                        .expect("drop impl param doesn't have a ParameterDef?")
-                        .pure_wrt_drop
+                    !impl_generics.type_param(pt, self).pure_wrt_drop
                 } else {
                     // not a type or region param - this should be reported
                     // as an error.
diff --git a/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.rs b/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.rs
index a41d8b0e342..242520cdb32 100644
--- a/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.rs
+++ b/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.rs
@@ -28,7 +28,11 @@ struct Foo<T> {
     foo: &'static T
 }
 
-trait X<T> {}
+trait X<K>: Sized {
+    fn foo<'a, L: X<&'a Nested<K>>>();
+    // check that we give a sane error for `Self`
+    fn bar<'a, L: X<&'a Nested<Self>>>();
+}
 
 struct Nested<K>(K);
 impl<K> Nested<K> {
diff --git a/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr b/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr
index c74302fe9b3..42e4f28260e 100644
--- a/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr
+++ b/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr
@@ -27,37 +27,64 @@ note: ...so that the reference type `&'static T` does not outlive the data it po
    |     ^^^^^^^^^^^^^^^
 
 error[E0309]: the parameter type `K` may not live long enough
-  --> $DIR/lifetime-doesnt-live-long-enough.rs:35:5
+  --> $DIR/lifetime-doesnt-live-long-enough.rs:32:5
    |
-34 |   impl<K> Nested<K> {
+31 | trait X<K>: Sized {
+   |         - help: consider adding an explicit lifetime bound `K: 'a`...
+32 |     fn foo<'a, L: X<&'a Nested<K>>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: ...so that the reference type `&'a Nested<K>` does not outlive the data it points at
+  --> $DIR/lifetime-doesnt-live-long-enough.rs:32:5
+   |
+32 |     fn foo<'a, L: X<&'a Nested<K>>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0309]: the parameter type `Self` may not live long enough
+  --> $DIR/lifetime-doesnt-live-long-enough.rs:34:5
+   |
+34 |     fn bar<'a, L: X<&'a Nested<Self>>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider adding an explicit lifetime bound `Self: 'a`...
+note: ...so that the reference type `&'a Nested<Self>` does not outlive the data it points at
+  --> $DIR/lifetime-doesnt-live-long-enough.rs:34:5
+   |
+34 |     fn bar<'a, L: X<&'a Nested<Self>>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0309]: the parameter type `K` may not live long enough
+  --> $DIR/lifetime-doesnt-live-long-enough.rs:39:5
+   |
+38 |   impl<K> Nested<K> {
    |        - help: consider adding an explicit lifetime bound `K: 'a`...
-35 | /     fn generic_in_parent<'a, L: X<&'a Nested<K>>>() {
-36 | |     }
+39 | /     fn generic_in_parent<'a, L: X<&'a Nested<K>>>() {
+40 | |     }
    | |_____^
    |
 note: ...so that the reference type `&'a Nested<K>` does not outlive the data it points at
-  --> $DIR/lifetime-doesnt-live-long-enough.rs:35:5
+  --> $DIR/lifetime-doesnt-live-long-enough.rs:39:5
    |
-35 | /     fn generic_in_parent<'a, L: X<&'a Nested<K>>>() {
-36 | |     }
+39 | /     fn generic_in_parent<'a, L: X<&'a Nested<K>>>() {
+40 | |     }
    | |_____^
 
 error[E0309]: the parameter type `M` may not live long enough
-  --> $DIR/lifetime-doesnt-live-long-enough.rs:37:5
+  --> $DIR/lifetime-doesnt-live-long-enough.rs:41:5
    |
-37 |       fn generic_in_child<'a, 'b, L: X<&'a Nested<M>>, M: 'b>() {
+41 |       fn generic_in_child<'a, 'b, L: X<&'a Nested<M>>, M: 'b>() {
    |       ^                                                -- help: consider adding an explicit lifetime bound `M: 'a`...
    |  _____|
    | |
-38 | |     }
+42 | |     }
    | |_____^
    |
 note: ...so that the reference type `&'a Nested<M>` does not outlive the data it points at
-  --> $DIR/lifetime-doesnt-live-long-enough.rs:37:5
+  --> $DIR/lifetime-doesnt-live-long-enough.rs:41:5
    |
-37 | /     fn generic_in_child<'a, 'b, L: X<&'a Nested<M>>, M: 'b>() {
-38 | |     }
+41 | /     fn generic_in_child<'a, 'b, L: X<&'a Nested<M>>, M: 'b>() {
+42 | |     }
    | |_____^
 
-error: aborting due to 4 previous errors
+error: aborting due to 6 previous errors