-
Notifications
You must be signed in to change notification settings - Fork 13.4k
Implementation of GATs outlives lint #89970
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+694
−61
Merged
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
0bc340f
Error initial pass
jackh726 a8c44d3
Some cleanup
jackh726 82148cd
Change outlives clause checking algorithm
jackh726 e391796
Better error
jackh726 c2da210
Edit GATs tests to apply lint
jackh726 f9e14af
Don't just check params
jackh726 b84044a
Review comments and more tests
jackh726 18421b1
Add lint for region pairs too
jackh726 ef5e31a
Move outlives checking to separate functions
jackh726 b6edcbd
Review comments
jackh726 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,32 +1,10 @@ | ||
error: `impl` associated type signature for `TRef` doesn't match `trait` associated type signature | ||
--> $DIR/issue-86787.rs:23:5 | ||
error: Missing required bounds on TRef | ||
--> $DIR/issue-86787.rs:11:5 | ||
| | ||
LL | type TRef<'a>; | ||
| -------------- expected | ||
... | ||
LL | / type TRef<'a> | ||
LL | | | ||
LL | | | ||
LL | | where | ||
LL | | <Left as HasChildrenOf>::T: 'a, | ||
LL | | <Right as HasChildrenOf>::T: 'a | ||
LL | | = Either<&'a Left::T, &'a Right::T>; | ||
| |________________________________________^ found | ||
LL | type TRef<'a>; | ||
| ^^^^^^^^^^^^^- | ||
| | | ||
| help: add the required where clauses: `where Self: 'a` | ||
|
||
error: `impl` associated type signature for `TRef` doesn't match `trait` associated type signature | ||
--> $DIR/issue-86787.rs:23:5 | ||
| | ||
LL | type TRef<'a>; | ||
| -------------- expected | ||
... | ||
LL | / type TRef<'a> | ||
LL | | | ||
LL | | | ||
LL | | where | ||
LL | | <Left as HasChildrenOf>::T: 'a, | ||
LL | | <Right as HasChildrenOf>::T: 'a | ||
LL | | = Either<&'a Left::T, &'a Right::T>; | ||
| |________________________________________^ found | ||
|
||
error: aborting due to 2 previous errors | ||
error: aborting due to previous error | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.rs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
173 changes: 173 additions & 0 deletions
173
src/test/ui/generic-associated-types/self-outlives-lint.rs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
#![feature(generic_associated_types)] | ||
jackh726 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// check-fail | ||
|
||
use std::fmt::Debug; | ||
|
||
// We have a `&'a self`, so we need a `Self: 'a` | ||
trait Iterable { | ||
type Item<'x>; | ||
//~^ Missing required bounds | ||
fn iter<'a>(&'a self) -> Self::Item<'a>; | ||
} | ||
|
||
/* | ||
impl<T> Iterable for T { | ||
type Item<'a> = &'a T; | ||
fn iter<'a>(&'a self) -> Self::Item<'a> { | ||
self | ||
} | ||
} | ||
*/ | ||
|
||
// We have a `&'a T`, so we need a `T: 'x` | ||
trait Deserializer<T> { | ||
type Out<'x>; | ||
//~^ Missing required bounds | ||
fn deserialize<'a>(&self, input: &'a T) -> Self::Out<'a>; | ||
} | ||
|
||
/* | ||
impl<T> Deserializer<T> for () { | ||
type Out<'a> = &'a T; | ||
fn deserialize<'a>(&self, input: &'a T) -> Self::Out<'a> { input } | ||
} | ||
*/ | ||
|
||
// We have a `&'b T` and a `'b: 'a`, so it is implied that `T: 'a`. Therefore, we need a `T: 'x` | ||
trait Deserializer2<T> { | ||
type Out<'x>; | ||
//~^ Missing required bounds | ||
fn deserialize2<'a, 'b: 'a>(&self, input1: &'b T) -> Self::Out<'a>; | ||
} | ||
|
||
// We have a `&'a T` and a `&'b U`, so we need a `T: 'x` and a `U: 'y` | ||
trait Deserializer3<T, U> { | ||
type Out<'x, 'y>; | ||
//~^ Missing required bounds | ||
fn deserialize2<'a, 'b>(&self, input: &'a T, input2: &'b U) -> Self::Out<'a, 'b>; | ||
} | ||
|
||
// `T` is a param on the function, so it can't be named by the associated type | ||
trait Deserializer4 { | ||
type Out<'x>; | ||
fn deserialize<'a, T>(&self, input: &'a T) -> Self::Out<'a>; | ||
} | ||
|
||
struct Wrap<T>(T); | ||
|
||
// We pass `Wrap<T>` and we see `&'z Wrap<T>`, so we require `D: 'x` | ||
trait Des { | ||
type Out<'x, D>; | ||
//~^ Missing required bounds | ||
fn des<'z, T>(&self, data: &'z Wrap<T>) -> Self::Out<'z, Wrap<T>>; | ||
} | ||
/* | ||
impl Des for () { | ||
type Out<'x, D> = &'x D; // Not okay | ||
fn des<'a, T>(&self, data: &'a Wrap<T>) -> Self::Out<'a, Wrap<T>> { | ||
data | ||
} | ||
} | ||
*/ | ||
|
||
// We have `T` and `'z` as GAT substs. Because of `&'z Wrap<T>`, there is an | ||
// implied bound that `T: 'z`, so we require `D: 'x` | ||
trait Des2 { | ||
type Out<'x, D>; | ||
//~^ Missing required bounds | ||
fn des<'z, T>(&self, data: &'z Wrap<T>) -> Self::Out<'z, T>; | ||
} | ||
/* | ||
impl Des2 for () { | ||
type Out<'x, D> = &'x D; | ||
fn des<'a, T>(&self, data: &'a Wrap<T>) -> Self::Out<'a, T> { | ||
&data.0 | ||
} | ||
} | ||
*/ | ||
|
||
// We see `&'z T`, so we require `D: 'x` | ||
trait Des3 { | ||
type Out<'x, D>; | ||
//~^ Missing required bounds | ||
fn des<'z, T>(&self, data: &'z T) -> Self::Out<'z, T>; | ||
} | ||
/* | ||
impl Des3 for () { | ||
type Out<'x, D> = &'x D; | ||
fn des<'a, T>(&self, data: &'a T) -> Self::Out<'a, T> { | ||
data | ||
} | ||
} | ||
*/ | ||
|
||
// Similar case to before, except with GAT. | ||
trait NoGat<'a> { | ||
type Bar; | ||
fn method(&'a self) -> Self::Bar; | ||
} | ||
|
||
// Lifetime is not on function; except `Self: 'a` | ||
// FIXME: we require two bounds (`where Self: 'a, Self: 'b`) when we should only require one | ||
trait TraitLifetime<'a> { | ||
type Bar<'b>; | ||
//~^ Missing required bounds | ||
fn method(&'a self) -> Self::Bar<'a>; | ||
} | ||
|
||
// Like above, but we have a where clause that can prove what we want | ||
// FIXME: we require two bounds (`where Self: 'a, Self: 'b`) when we should only require one | ||
trait TraitLifetimeWhere<'a> where Self: 'a { | ||
type Bar<'b>; | ||
//~^ Missing required bounds | ||
fn method(&'a self) -> Self::Bar<'a>; | ||
} | ||
|
||
// Explicit bound instead of implicit; we want to still error | ||
trait ExplicitBound { | ||
type Bar<'b>; | ||
//~^ Missing required bounds | ||
fn method<'b>(&self, token: &'b ()) -> Self::Bar<'b> where Self: 'b; | ||
} | ||
|
||
// The use of the GAT here is not in the return, we don't want to error | ||
trait NotInReturn { | ||
type Bar<'b>; | ||
fn method<'b>(&'b self) where Self::Bar<'b>: Debug; | ||
} | ||
|
||
// We obviously error for `Iterator`, but we should also error for `Item` | ||
trait IterableTwo { | ||
type Item<'a>; | ||
type Iterator<'a>: Iterator<Item = Self::Item<'a>>; | ||
//~^ Missing required bounds | ||
fn iter<'a>(&'a self) -> Self::Iterator<'a>; | ||
} | ||
|
||
// We also should report region outlives clauses | ||
trait RegionOutlives { | ||
type Bar<'a, 'b>; | ||
//~^ Missing required bounds | ||
fn foo<'x, 'y>(&self, input: &'x &'y ()) -> Self::Bar<'x, 'y>; | ||
} | ||
|
||
/* | ||
impl Foo for () { | ||
type Bar<'a, 'b> = &'a &'b (); | ||
fn foo<'x, 'y>(&self, input: &'x &'y ()) -> Self::Bar<'x, 'y> { | ||
input | ||
} | ||
} | ||
*/ | ||
|
||
// If there are multiple methods that return the GAT, require a set of clauses | ||
// that can be satisfied by *all* methods | ||
trait MultipleMethods { | ||
type Bar<'me>; | ||
|
||
fn gimme<'a>(&'a self) -> Self::Bar<'a>; | ||
fn gimme_default(&self) -> Self::Bar<'static>; | ||
} | ||
|
||
fn main() {} |
98 changes: 98 additions & 0 deletions
98
src/test/ui/generic-associated-types/self-outlives-lint.stderr
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
error: Missing required bounds on Item | ||
--> $DIR/self-outlives-lint.rs:9:5 | ||
| | ||
LL | type Item<'x>; | ||
| ^^^^^^^^^^^^^- | ||
| | | ||
| help: add the required where clauses: `where Self: 'x` | ||
|
||
error: Missing required bounds on Out | ||
--> $DIR/self-outlives-lint.rs:25:5 | ||
| | ||
LL | type Out<'x>; | ||
| ^^^^^^^^^^^^- | ||
| | | ||
| help: add the required where clauses: `where T: 'x` | ||
|
||
error: Missing required bounds on Out | ||
--> $DIR/self-outlives-lint.rs:39:5 | ||
| | ||
LL | type Out<'x>; | ||
| ^^^^^^^^^^^^- | ||
| | | ||
| help: add the required where clauses: `where T: 'x` | ||
|
||
error: Missing required bounds on Out | ||
--> $DIR/self-outlives-lint.rs:46:5 | ||
| | ||
LL | type Out<'x, 'y>; | ||
| ^^^^^^^^^^^^^^^^- | ||
| | | ||
| help: add the required where clauses: `where T: 'x, U: 'y` | ||
|
||
error: Missing required bounds on Out | ||
--> $DIR/self-outlives-lint.rs:61:5 | ||
| | ||
LL | type Out<'x, D>; | ||
| ^^^^^^^^^^^^^^^- | ||
| | | ||
| help: add the required where clauses: `where D: 'x` | ||
|
||
error: Missing required bounds on Out | ||
--> $DIR/self-outlives-lint.rs:77:5 | ||
| | ||
LL | type Out<'x, D>; | ||
| ^^^^^^^^^^^^^^^- | ||
| | | ||
| help: add the required where clauses: `where D: 'x` | ||
|
||
error: Missing required bounds on Out | ||
--> $DIR/self-outlives-lint.rs:92:5 | ||
| | ||
LL | type Out<'x, D>; | ||
| ^^^^^^^^^^^^^^^- | ||
| | | ||
| help: add the required where clauses: `where D: 'x` | ||
|
||
error: Missing required bounds on Bar | ||
--> $DIR/self-outlives-lint.rs:114:5 | ||
| | ||
LL | type Bar<'b>; | ||
| ^^^^^^^^^^^^- | ||
| | | ||
| help: add the required where clauses: `where Self: 'a, Self: 'b` | ||
|
||
error: Missing required bounds on Bar | ||
--> $DIR/self-outlives-lint.rs:122:5 | ||
| | ||
LL | type Bar<'b>; | ||
| ^^^^^^^^^^^^- | ||
| | | ||
| help: add the required where clauses: `where Self: 'a, Self: 'b` | ||
|
||
error: Missing required bounds on Bar | ||
--> $DIR/self-outlives-lint.rs:129:5 | ||
| | ||
LL | type Bar<'b>; | ||
| ^^^^^^^^^^^^- | ||
| | | ||
| help: add the required where clauses: `where Self: 'b` | ||
|
||
error: Missing required bounds on Iterator | ||
--> $DIR/self-outlives-lint.rs:143:5 | ||
| | ||
LL | type Iterator<'a>: Iterator<Item = Self::Item<'a>>; | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | ||
| | | ||
| help: add the required where clauses: `where Self: 'a` | ||
|
||
error: Missing required bounds on Bar | ||
--> $DIR/self-outlives-lint.rs:150:5 | ||
| | ||
LL | type Bar<'a, 'b>; | ||
| ^^^^^^^^^^^^^^^^- | ||
| | | ||
| help: add the required where clauses: `where 'a: 'b` | ||
|
||
error: aborting due to 12 previous errors | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: lowercase letter
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can do more to give an intuitive understanding here. I'd like the message to be something like this...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Obviously these spans are not as precise as they could be, and the wording can probably be improved. I was trying to give what seemed like a realistic message based on the content we currently have available