diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 3f22950fc773f..895894a0bb2fc 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -794,8 +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 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. diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index da635ec80fc91..bc5a056dd3386 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, @@ -729,7 +736,7 @@ pub struct Generics { pub has_late_bound_regions: Option, } -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 @@ impl Generics { 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) + } } } diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 27819f551b9b3..c8037ce081a71 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -515,11 +515,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { 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. 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 465b42710352d..242520cdb32c7 100644 --- a/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.rs +++ b/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.rs @@ -28,4 +28,18 @@ struct Foo { foo: &'static T } +trait X: Sized { + fn foo<'a, L: X<&'a Nested>>(); + // check that we give a sane error for `Self` + fn bar<'a, L: X<&'a Nested>>(); +} + +struct Nested(K); +impl Nested { + fn generic_in_parent<'a, L: X<&'a Nested>>() { + } + fn generic_in_child<'a, 'b, L: X<&'a Nested>, M: 'b>() { + } +} + fn main() {} 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 e17a660c59170..42e4f28260ea2 100644 --- a/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr +++ b/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr @@ -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: Sized { + | - help: consider adding an explicit lifetime bound `K: 'a`... +32 | fn foo<'a, L: X<&'a Nested>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: ...so that the reference type `&'a Nested` 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>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +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>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider adding an explicit lifetime bound `Self: 'a`... +note: ...so that the reference type `&'a Nested` 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>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0309]: the parameter type `K` may not live long enough + --> $DIR/lifetime-doesnt-live-long-enough.rs:39:5 + | +38 | impl Nested { + | - help: consider adding an explicit lifetime bound `K: 'a`... +39 | / fn generic_in_parent<'a, L: X<&'a Nested>>() { +40 | | } + | |_____^ + | +note: ...so that the reference type `&'a Nested` 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>>() { +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: 'b>() { + | ^ -- help: consider adding an explicit lifetime bound `M: 'a`... + | _____| + | | +42 | | } + | |_____^ + | +note: ...so that the reference type `&'a Nested` 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: 'b>() { +42 | | } + | |_____^ + +error: aborting due to 6 previous errors