about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAriel Ben-Yehuda <ariel.byd@gmail.com>2017-12-13 23:06:54 -0600
committerAriel Ben-Yehuda <ariel.byd@gmail.com>2017-12-13 23:06:54 -0600
commit2679944653bb7ef1690840cc177da9896daa2963 (patch)
treeb55b0b5f78079506157037f29fb50a68ac597637
parente798cb0e52e505ed759f8af01e90a758858b115d (diff)
downloadrust-2679944653bb7ef1690840cc177da9896daa2963.tar.gz
rust-2679944653bb7ef1690840cc177da9896daa2963.zip
fix broken assertion in type_param
Nested generics (aka method generics) in trait methods don't have an
*additional* Self parameter in their own type parameter list (they have
a Self parameter in the parent generics), so don't try to check we're
correctly adjusting for it.

Fixes #46568.
-rw-r--r--src/librustc/ty/mod.rs28
-rw-r--r--src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.rs8
-rw-r--r--src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr63
3 files changed, 71 insertions, 28 deletions
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index afe999cede7..92bf9b05cda 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -778,10 +778,20 @@ impl<'a, 'gcx, 'tcx> Generics {
         if let Some(idx) = param.idx.checked_sub(self.parent_count() as u32) {
             // 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"
+            // but even in the presence of a `Self` we just have to "compensate"
             // for the regions:
             //
-            // For example, for `trait Foo<'a, 'b, T1, T2>`, the
+            // Without a `Self` (or in a nested generics that doesn't have
+            // a `Self` in itself, even through it parent does), for example
+            // for `fn foo<'a, T1, T2>()`, the situation is:
+            //     Substs:
+            //         0  1  2
+            //         'a T1 T2
+            //     generics.types:
+            //         0  1
+            //         T1 T2
+            //
+            // And with a `Self`, for example for `trait Foo<'a, 'b, T1, T2>`, the
             // situation is:
             //     Substs:
             //         0   1  2  3  4
@@ -789,14 +799,20 @@ impl<'a, 'gcx, 'tcx> Generics {
             //     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.
+            //
+            // And it can be seen that in both cases, 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();
+
+            let has_self = self.has_self && self.parent.is_none();
+            let is_separated_self = type_param_offset != 0 && idx == 0 && has_self;
+
             if let Some(idx) = (idx as usize).checked_sub(type_param_offset) {
-                assert!(!(self.has_self && idx == 0));
+                assert!(!is_separated_self, "found a Self after type_param_offset");
                 &self.types[idx]
             } else {
-                assert!(self.has_self && idx == 0);
+                assert!(is_separated_self, "non-Self param before type_param_offset");
                 &self.types[0]
             }
         } else {
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 58c33af0ddd..0099a8bc10f 100644
--- a/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.rs
+++ b/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.rs
@@ -33,11 +33,19 @@ struct Foo<T> {
 trait X<K>: Sized {
     fn foo<'a, L: X<&'a Nested<K>>>();
     //~^ ERROR may not live long enough
+
     // check that we give a sane error for `Self`
     fn bar<'a, L: X<&'a Nested<Self>>>();
     //~^ ERROR may not live long enough
+
+    // check that we give a sane error for nested generics
+    fn baz<'a, L, M: X<&'a Nested<L>>>() {
+        //~^ ERROR may not live long enough
+    }
 }
 
+trait TraitB {}
+
 struct Nested<K>(K);
 impl<K> Nested<K> {
     fn generic_in_parent<'a, L: X<&'a 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 342c6ab8f16..05908606da7 100644
--- a/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr
+++ b/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr
@@ -41,54 +41,73 @@ note: ...so that the reference type `&'a Nested<K>` does not outlive the data it
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0309]: the parameter type `Self` may not live long enough
-  --> $DIR/lifetime-doesnt-live-long-enough.rs:37:5
+  --> $DIR/lifetime-doesnt-live-long-enough.rs:38:5
    |
-37 |     fn bar<'a, L: X<&'a Nested<Self>>>();
+38 |     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:37:5
+  --> $DIR/lifetime-doesnt-live-long-enough.rs:38:5
    |
-37 |     fn bar<'a, L: X<&'a Nested<Self>>>();
+38 |     fn bar<'a, L: X<&'a Nested<Self>>>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+error[E0309]: the parameter type `L` may not live long enough
+  --> $DIR/lifetime-doesnt-live-long-enough.rs:42:5
+   |
+42 |       fn baz<'a, L, M: X<&'a Nested<L>>>() {
+   |       ^          - help: consider adding an explicit lifetime bound `L: 'a`...
+   |  _____|
+   | |
+43 | |         //~^ ERROR may not live long enough
+44 | |     }
+   | |_____^
+   |
+note: ...so that the reference type `&'a Nested<L>` does not outlive the data it points at
+  --> $DIR/lifetime-doesnt-live-long-enough.rs:42:5
+   |
+42 | /     fn baz<'a, L, M: X<&'a Nested<L>>>() {
+43 | |         //~^ ERROR may not live long enough
+44 | |     }
+   | |_____^
+
 error[E0309]: the parameter type `K` may not live long enough
-  --> $DIR/lifetime-doesnt-live-long-enough.rs:43:5
+  --> $DIR/lifetime-doesnt-live-long-enough.rs:51:5
    |
-42 |   impl<K> Nested<K> {
+50 |   impl<K> Nested<K> {
    |        - help: consider adding an explicit lifetime bound `K: 'a`...
-43 | /     fn generic_in_parent<'a, L: X<&'a Nested<K>>>() {
-44 | |         //~^ ERROR may not live long enough
-45 | |     }
+51 | /     fn generic_in_parent<'a, L: X<&'a Nested<K>>>() {
+52 | |         //~^ ERROR may not live long enough
+53 | |     }
    | |_____^
    |
 note: ...so that the reference type `&'a Nested<K>` does not outlive the data it points at
-  --> $DIR/lifetime-doesnt-live-long-enough.rs:43:5
+  --> $DIR/lifetime-doesnt-live-long-enough.rs:51:5
    |
-43 | /     fn generic_in_parent<'a, L: X<&'a Nested<K>>>() {
-44 | |         //~^ ERROR may not live long enough
-45 | |     }
+51 | /     fn generic_in_parent<'a, L: X<&'a Nested<K>>>() {
+52 | |         //~^ ERROR may not live long enough
+53 | |     }
    | |_____^
 
 error[E0309]: the parameter type `M` may not live long enough
-  --> $DIR/lifetime-doesnt-live-long-enough.rs:46:5
+  --> $DIR/lifetime-doesnt-live-long-enough.rs:54:5
    |
-46 |       fn generic_in_child<'a, 'b, L: X<&'a Nested<M>>, M: 'b>() {
+54 |       fn generic_in_child<'a, 'b, L: X<&'a Nested<M>>, M: 'b>() {
    |       ^                                                -- help: consider adding an explicit lifetime bound `M: 'a`...
    |  _____|
    | |
-47 | |         //~^ ERROR may not live long enough
-48 | |     }
+55 | |         //~^ ERROR may not live long enough
+56 | |     }
    | |_____^
    |
 note: ...so that the reference type `&'a Nested<M>` does not outlive the data it points at
-  --> $DIR/lifetime-doesnt-live-long-enough.rs:46:5
+  --> $DIR/lifetime-doesnt-live-long-enough.rs:54:5
    |
-46 | /     fn generic_in_child<'a, 'b, L: X<&'a Nested<M>>, M: 'b>() {
-47 | |         //~^ ERROR may not live long enough
-48 | |     }
+54 | /     fn generic_in_child<'a, 'b, L: X<&'a Nested<M>>, M: 'b>() {
+55 | |         //~^ ERROR may not live long enough
+56 | |     }
    | |_____^
 
-error: aborting due to 6 previous errors
+error: aborting due to 7 previous errors