提交 0f0f5db4 编写于 作者: B bors

Auto merge of #44959 - arielb1:generic-errors, r=eddyb

handle nested generics in Generics::type_param/region_param

Fixes #44952.

r? @EddyB
......@@ -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.
......
......@@ -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)
}
}
}
......
......@@ -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.
......
......@@ -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() {}
......@@ -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
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册