Point to where clause for GATs
This commit is contained in:
parent
2fc3c69e54
commit
22fc7d6e5a
7 changed files with 200 additions and 8 deletions
|
@ -2259,9 +2259,99 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut err = match *sub {
|
#[derive(Debug)]
|
||||||
ty::ReEarlyBound(ty::EarlyBoundRegion { name, .. })
|
enum SubOrigin<'hir> {
|
||||||
| ty::ReFree(ty::FreeRegion { bound_region: ty::BrNamed(_, name), .. }) => {
|
GAT(&'hir hir::Generics<'hir>),
|
||||||
|
Impl(&'hir hir::Generics<'hir>),
|
||||||
|
Trait(&'hir hir::Generics<'hir>),
|
||||||
|
Fn(&'hir hir::Generics<'hir>),
|
||||||
|
Unknown,
|
||||||
|
}
|
||||||
|
let sub_origin = 'origin: {
|
||||||
|
match *sub {
|
||||||
|
ty::ReEarlyBound(ty::EarlyBoundRegion { def_id, .. }) => {
|
||||||
|
let node = self.tcx.hir().get_if_local(def_id).unwrap();
|
||||||
|
match node {
|
||||||
|
Node::GenericParam(param) => {
|
||||||
|
for h in self.tcx.hir().parent_iter(param.hir_id) {
|
||||||
|
break 'origin match h.1 {
|
||||||
|
Node::ImplItem(hir::ImplItem {
|
||||||
|
kind: hir::ImplItemKind::TyAlias(..),
|
||||||
|
generics,
|
||||||
|
..
|
||||||
|
}) => SubOrigin::GAT(generics),
|
||||||
|
Node::ImplItem(hir::ImplItem {
|
||||||
|
kind: hir::ImplItemKind::Fn(..),
|
||||||
|
generics,
|
||||||
|
..
|
||||||
|
}) => SubOrigin::Fn(generics),
|
||||||
|
Node::TraitItem(hir::TraitItem {
|
||||||
|
kind: hir::TraitItemKind::Type(..),
|
||||||
|
generics,
|
||||||
|
..
|
||||||
|
}) => SubOrigin::GAT(generics),
|
||||||
|
Node::TraitItem(hir::TraitItem {
|
||||||
|
kind: hir::TraitItemKind::Fn(..),
|
||||||
|
generics,
|
||||||
|
..
|
||||||
|
}) => SubOrigin::Fn(generics),
|
||||||
|
Node::Item(hir::Item {
|
||||||
|
kind: hir::ItemKind::Trait(_, _, generics, _, _),
|
||||||
|
..
|
||||||
|
}) => SubOrigin::Trait(generics),
|
||||||
|
Node::Item(hir::Item {
|
||||||
|
kind: hir::ItemKind::Impl(hir::Impl { generics, .. }),
|
||||||
|
..
|
||||||
|
}) => SubOrigin::Impl(generics),
|
||||||
|
Node::Item(hir::Item {
|
||||||
|
kind: hir::ItemKind::Fn(_, generics, _),
|
||||||
|
..
|
||||||
|
}) => SubOrigin::Fn(generics),
|
||||||
|
_ => continue,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
SubOrigin::Unknown
|
||||||
|
};
|
||||||
|
debug!(?sub_origin);
|
||||||
|
|
||||||
|
let mut err = match (*sub, sub_origin) {
|
||||||
|
// In the case of GATs, we have to be careful. If we a type parameter `T` on an impl,
|
||||||
|
// but a lifetime `'a` on an associated type, then we might need to suggest adding
|
||||||
|
// `where T: 'a`. Importantly, this is on the GAT span, not on the `T` declaration.
|
||||||
|
(ty::ReEarlyBound(ty::EarlyBoundRegion { name: _, .. }), SubOrigin::GAT(generics)) => {
|
||||||
|
// Does the required lifetime have a nice name we can print?
|
||||||
|
let mut err = struct_span_err!(
|
||||||
|
self.tcx.sess,
|
||||||
|
span,
|
||||||
|
E0309,
|
||||||
|
"{} may not live long enough",
|
||||||
|
labeled_user_string
|
||||||
|
);
|
||||||
|
let pred = format!("{}: {}", bound_kind, sub);
|
||||||
|
let suggestion = format!(
|
||||||
|
"{} {}",
|
||||||
|
if !generics.where_clause.predicates.is_empty() { "," } else { " where" },
|
||||||
|
pred,
|
||||||
|
);
|
||||||
|
err.span_suggestion(
|
||||||
|
generics.where_clause.tail_span_for_suggestion(),
|
||||||
|
"consider adding a where clause".into(),
|
||||||
|
suggestion,
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
err
|
||||||
|
}
|
||||||
|
(
|
||||||
|
ty::ReEarlyBound(ty::EarlyBoundRegion { name, .. })
|
||||||
|
| ty::ReFree(ty::FreeRegion { bound_region: ty::BrNamed(_, name), .. }),
|
||||||
|
_,
|
||||||
|
) => {
|
||||||
// Does the required lifetime have a nice name we can print?
|
// Does the required lifetime have a nice name we can print?
|
||||||
let mut err = struct_span_err!(
|
let mut err = struct_span_err!(
|
||||||
self.tcx.sess,
|
self.tcx.sess,
|
||||||
|
@ -2278,7 +2368,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
err
|
err
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::ReStatic => {
|
(ty::ReStatic, _) => {
|
||||||
// Does the required lifetime have a nice name we can print?
|
// Does the required lifetime have a nice name we can print?
|
||||||
let mut err = struct_span_err!(
|
let mut err = struct_span_err!(
|
||||||
self.tcx.sess,
|
self.tcx.sess,
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#![feature(in_band_lifetimes)]
|
#![feature(in_band_lifetimes)]
|
||||||
#![feature(control_flow_enum)]
|
#![feature(control_flow_enum)]
|
||||||
#![feature(min_specialization)]
|
#![feature(min_specialization)]
|
||||||
|
#![feature(label_break_value)]
|
||||||
#![recursion_limit = "512"] // For rustdoc
|
#![recursion_limit = "512"] // For rustdoc
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
|
22
src/test/ui/generic-associated-types/issue-84931.rs
Normal file
22
src/test/ui/generic-associated-types/issue-84931.rs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#![feature(generic_associated_types)]
|
||||||
|
// check-fail
|
||||||
|
|
||||||
|
trait StreamingIter {
|
||||||
|
type Item<'a> where Self: 'a;
|
||||||
|
fn next<'a>(&'a mut self) -> Option<Self::Item::<'a>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct StreamingSliceIter<'a, T> {
|
||||||
|
idx: usize,
|
||||||
|
data: &'a mut [T],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'b, T: 'b> StreamingIter for StreamingSliceIter<'b, T> {
|
||||||
|
type Item<'a> = &'a mut T;
|
||||||
|
//~^ the parameter type
|
||||||
|
fn next(&mut self) -> Option<&mut T> {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
11
src/test/ui/generic-associated-types/issue-84931.stderr
Normal file
11
src/test/ui/generic-associated-types/issue-84931.stderr
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
error[E0309]: the parameter type `T` may not live long enough
|
||||||
|
--> $DIR/issue-84931.rs:15:21
|
||||||
|
|
|
||||||
|
LL | type Item<'a> = &'a mut T;
|
||||||
|
| - ^^^^^^^^^ ...so that the reference type `&'a mut T` does not outlive the data it points at
|
||||||
|
| |
|
||||||
|
| help: consider adding a where clause: `where T: 'a`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0309`.
|
|
@ -37,11 +37,10 @@ LL | for<'a> T: 'a,
|
||||||
error[E0309]: the parameter type `T` may not live long enough
|
error[E0309]: the parameter type `T` may not live long enough
|
||||||
--> $DIR/issue-86483.rs:9:32
|
--> $DIR/issue-86483.rs:9:32
|
||||||
|
|
|
|
||||||
LL | pub trait IceIce<T>
|
|
||||||
| - help: consider adding an explicit lifetime bound...: `T: 'v`
|
|
||||||
...
|
|
||||||
LL | type Ice<'v>: IntoIterator<Item = &'v T>;
|
LL | type Ice<'v>: IntoIterator<Item = &'v T>;
|
||||||
| ^^^^^^^^^^^^ ...so that the reference type `&'v T` does not outlive the data it points at
|
| ^^^^^^^^^^^^ - help: consider adding a where clause: `where T: 'v`
|
||||||
|
| |
|
||||||
|
| ...so that the reference type `&'v T` does not outlive the data it points at
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
|
40
src/test/ui/generic-associated-types/issue-86787.rs
Normal file
40
src/test/ui/generic-associated-types/issue-86787.rs
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
#![feature(generic_associated_types)]
|
||||||
|
// check-fail
|
||||||
|
|
||||||
|
enum Either<L, R> {
|
||||||
|
Left(L),
|
||||||
|
Right(R),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait HasChildrenOf {
|
||||||
|
type T;
|
||||||
|
type TRef<'a>;
|
||||||
|
|
||||||
|
fn ref_children<'a>(&'a self) -> Vec<Self::TRef<'a>>;
|
||||||
|
fn take_children(self) -> Vec<Self::T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Left, Right> HasChildrenOf for Either<Left, Right>
|
||||||
|
where
|
||||||
|
Left: HasChildrenOf,
|
||||||
|
Right: HasChildrenOf,
|
||||||
|
{
|
||||||
|
type T = Either<Left::T, Right::T>;
|
||||||
|
type TRef<'a>
|
||||||
|
//~^ the associated type
|
||||||
|
//~^^ the associated type
|
||||||
|
where
|
||||||
|
<Left as HasChildrenOf>::T: 'a,
|
||||||
|
<Right as HasChildrenOf>::T: 'a
|
||||||
|
= Either<&'a Left::T, &'a Right::T>;
|
||||||
|
|
||||||
|
fn ref_children<'a>(&'a self) -> Vec<Self::TRef<'a>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn take_children(self) -> Vec<Self::T> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
29
src/test/ui/generic-associated-types/issue-86787.stderr
Normal file
29
src/test/ui/generic-associated-types/issue-86787.stderr
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
error[E0309]: the associated type `<Left as HasChildrenOf>::T` may not live long enough
|
||||||
|
--> $DIR/issue-86787.rs:23:5
|
||||||
|
|
|
||||||
|
LL | / type TRef<'a>
|
||||||
|
LL | |
|
||||||
|
LL | |
|
||||||
|
LL | | where
|
||||||
|
LL | | <Left as HasChildrenOf>::T: 'a,
|
||||||
|
LL | | <Right as HasChildrenOf>::T: 'a
|
||||||
|
| | - help: consider adding a where clause: `, <Left as HasChildrenOf>::T: 'a`
|
||||||
|
LL | | = Either<&'a Left::T, &'a Right::T>;
|
||||||
|
| |________________________________________^ ...so that the type `<Left as HasChildrenOf>::T` will meet its required lifetime bounds
|
||||||
|
|
||||||
|
error[E0309]: the associated type `<Right as HasChildrenOf>::T` may not live long enough
|
||||||
|
--> $DIR/issue-86787.rs:23:5
|
||||||
|
|
|
||||||
|
LL | / type TRef<'a>
|
||||||
|
LL | |
|
||||||
|
LL | |
|
||||||
|
LL | | where
|
||||||
|
LL | | <Left as HasChildrenOf>::T: 'a,
|
||||||
|
LL | | <Right as HasChildrenOf>::T: 'a
|
||||||
|
| | - help: consider adding a where clause: `, <Right as HasChildrenOf>::T: 'a`
|
||||||
|
LL | | = Either<&'a Left::T, &'a Right::T>;
|
||||||
|
| |________________________________________^ ...so that the type `<Right as HasChildrenOf>::T` will meet its required lifetime bounds
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0309`.
|
Loading…
Add table
Add a link
Reference in a new issue