]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #44959 - arielb1:generic-errors, r=eddyb
authorbors <bors@rust-lang.org>
Mon, 2 Oct 2017 10:06:32 +0000 (10:06 +0000)
committerbors <bors@rust-lang.org>
Mon, 2 Oct 2017 10:06:32 +0000 (10:06 +0000)
handle nested generics in Generics::type_param/region_param

Fixes #44952.

r? @eddyb

src/librustc/infer/error_reporting/mod.rs
src/librustc/ty/mod.rs
src/librustc/ty/util.rs
src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.rs
src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr

index 3f22950fc773f3d07fdd0ae0a3f6190146100330..895894a0bb2fc5ee1613f0d97ad2f6475ebb82db 100644 (file)
@@ -794,8 +794,8 @@ fn report_generic_bound_failure(&self,
                     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 generics.types.len() > 0 {
-                        let type_param = generics.type_param(param);
+                    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.
index da635ec80fc91081d5405b4a2fa919ce0fc94f28..bc5a056dd3386d396408a10ecc9d7364041c4db1 100644 (file)
@@ -713,6 +713,13 @@ pub fn to_bound_region(&self) -> ty::BoundRegion {
 
 /// 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>,
@@ -729,7 +736,7 @@ pub struct Generics {
     pub has_late_bound_regions: Option<Span>,
 }
 
-impl Generics {
+impl<'a, 'gcx, 'tcx> Generics {
     pub fn parent_count(&self) -> usize {
         self.parent_regions as usize + self.parent_types as usize
     }
@@ -742,14 +749,52 @@ pub fn count(&self) -> usize {
         self.parent_count() + self.own_count()
     }
 
-    pub fn region_param(&self, param: &EarlyBoundRegion) -> &RegionParameterDef {
-        assert_eq!(self.parent_count(), 0);
-        &self.regions[param.index as usize - self.has_self as usize]
-    }
-
-    pub fn type_param(&self, param: &ParamTy) -> &TypeParameterDef {
-        assert_eq!(self.parent_count(), 0);
-        &self.types[param.idx as usize - self.has_self as usize - self.regions.len()]
+    pub fn region_param(&'tcx self,
+                        param: &EarlyBoundRegion,
+                        tcx: TyCtxt<'a, 'gcx, 'tcx>)
+                        -> &'tcx RegionParameterDef
+    {
+        if let Some(index) = param.index.checked_sub(self.parent_count() as u32) {
+            &self.regions[index as usize - self.has_self as usize]
+        } else {
+            tcx.generics_of(self.parent.expect("parent_count>0 but no parent?"))
+                .region_param(param, tcx)
+        }
+    }
+
+    /// Returns the `TypeParameterDef` associated with this `ParamTy`.
+    pub fn type_param(&'tcx self,
+                      param: &ParamTy,
+                      tcx: TyCtxt<'a, 'gcx, 'tcx>)
+                      -> &TypeParameterDef {
+        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"
+            // 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 {
+                assert!(self.has_self && idx == 0);
+                &self.types[0]
+            }
+        } else {
+            tcx.generics_of(self.parent.expect("parent_count>0 but no parent?"))
+                .type_param(param, tcx)
+        }
     }
 }
 
index 27819f551b9b3f47cabcd6fb319eb82395cf8aff..c8037ce081a71e6b5e47ef7e03db742b81069cd4 100644 (file)
@@ -515,11 +515,11 @@ pub fn destructor_constraints(self, def: &'tcx ty::AdtDef)
         let result = item_substs.iter().zip(impl_substs.iter())
             .filter(|&(_, &k)| {
                 if let Some(&ty::RegionKind::ReEarlyBound(ref ebr)) = k.as_region() {
-                    !impl_generics.region_param(ebr).pure_wrt_drop
+                    !impl_generics.region_param(ebr, self).pure_wrt_drop
                 } else if let Some(&ty::TyS {
                     sty: ty::TypeVariants::TyParam(ref pt), ..
                 }) = k.as_type() {
-                    !impl_generics.type_param(pt).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.
index 465b42710352d2665bc56d185d03970a9f06fd1f..242520cdb32c73e027fda9d03bc01451bfbb242b 100644 (file)
@@ -28,4 +28,18 @@ struct Foo<T> {
     foo: &'static 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> {
+    fn generic_in_parent<'a, L: X<&'a Nested<K>>>() {
+    }
+    fn generic_in_child<'a, 'b, L: X<&'a Nested<M>>, M: 'b>() {
+    }
+}
+
 fn main() {}
index e17a660c591709d88961fd7652ed988304524c85..42e4f28260ea2bf202ec85aacf55fd2a17fc806b 100644 (file)
@@ -26,5 +26,65 @@ note: ...so that the reference type `&'static T` does not outlive the data it po
 28 |     foo: &'static T
    |     ^^^^^^^^^^^^^^^
 
-error: aborting due to 2 previous errors
+error[E0309]: the parameter type `K` may not live long enough
+  --> $DIR/lifetime-doesnt-live-long-enough.rs:32:5
+   |
+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`...
+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:39:5
+   |
+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:41:5
+   |
+41 |       fn generic_in_child<'a, 'b, L: X<&'a Nested<M>>, M: 'b>() {
+   |       ^                                                -- help: consider adding an explicit lifetime bound `M: 'a`...
+   |  _____|
+   | |
+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:41:5
+   |
+41 | /     fn generic_in_child<'a, 'b, L: X<&'a Nested<M>>, M: 'b>() {
+42 | |     }
+   | |_____^
+
+error: aborting due to 6 previous errors