diff options
| author | Ariel Ben-Yehuda <ariel.byd@gmail.com> | 2017-10-02 10:43:36 +0200 |
|---|---|---|
| committer | Ariel Ben-Yehuda <ariel.byd@gmail.com> | 2017-10-02 10:43:36 +0200 |
| commit | 706e52e2cc1e1ffab4face61f5906164236a0da8 (patch) | |
| tree | ba4a167721aafffa52addcd8e631800458571d7c | |
| parent | ad9986605f5f743ee8cc3da8189a68815313ab07 (diff) | |
| download | rust-706e52e2cc1e1ffab4face61f5906164236a0da8.tar.gz rust-706e52e2cc1e1ffab4face61f5906164236a0da8.zip | |
fix handling of `Self`
| -rw-r--r-- | src/librustc/infer/error_reporting/mod.rs | 3 | ||||
| -rw-r--r-- | src/librustc/ty/mod.rs | 37 | ||||
| -rw-r--r-- | src/librustc/ty/util.rs | 4 | ||||
| -rw-r--r-- | src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.rs | 6 | ||||
| -rw-r--r-- | src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr | 55 |
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 |
