Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign up[RFC] Clarify (and improve) rules for projections and well-formedness #1214
Conversation
nikomatsakis
added
the
T-lang
label
Jul 17, 2015
nikomatsakis
self-assigned this
Jul 17, 2015
This comment has been minimized.
This comment has been minimized.
|
cc @arielb1 |
This comment has been minimized.
This comment has been minimized.
Ryman
commented
Jul 17, 2015
|
@nikomatsakis I think the issue referenced for 'unsound' in your description should be rust-lang/rust#24622 which is mentioned in the RFC (also labelled wrong). |
This comment has been minimized.
This comment has been minimized.
|
@Ryman thanks. |
nikomatsakis
added some commits
Jul 17, 2015
Diggsey
reviewed
Jul 18, 2015
| R ⊢ scalar: 'a | ||
|
|
||
| OutlivesNominalType: | ||
| ∀i. Pi: 'a |
This comment has been minimized.
This comment has been minimized.
Gankro
reviewed
Jul 18, 2015
| R ⊢ 'x: 'a | ||
| R ⊢ T: 'a | ||
| -------------------------------------------------- | ||
| R ⊢ &'x T: 'a |
This comment has been minimized.
This comment has been minimized.
Gankro
Jul 18, 2015
Contributor
It seems like T: 'a is redundant, since &'x T is WF only if T: 'x, no?
So T: 'x and 'x: 'a -> T: 'a by transitivity?
Maybe I'm missing a corner case.
This comment has been minimized.
This comment has been minimized.
nikomatsakis
Aug 7, 2015
Author
Contributor
Sorry, I'm not sure if I ever answered this.
It seems like T: 'a is redundant, since &'x T is WF only if T: 'x, no?
This seems true, if harmless.
Gankro
reviewed
Jul 18, 2015
| ∀i. R ⊢ Oi: 'a | ||
| R ⊢ 'x: 'a | ||
| -------------------------------------------------- | ||
| R ⊢ O0..On+'x: 'a |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
arielb1
Jul 18, 2015
Contributor
Shouldn't this be ∀i R, i: 'a ⊢ Oi: 'a (otherwise for<'α> Fn(&'α ()) : 'a would be false).
This comment has been minimized.
This comment has been minimized.
nikomatsakis
Aug 7, 2015
Author
Contributor
Shouldn't this be ∀i R, i: 'a ⊢ Oi: 'a (otherwise for<'α> Fn(&'α ()) : 'a would be false).
No, because the binder is within the Oi.
Gankro
reviewed
Jul 18, 2015
| question was bound within a type or not. In the usual case, we decide | ||
| the relationship between two lifetimes by consulting the environment. | ||
| Lifetimes representing scopes within the current fn have a | ||
| relationship derived from the code itself, lifetime parameters have |
This comment has been minimized.
This comment has been minimized.
Gankro
Jul 18, 2015
Contributor
maybe add a "while" after the comma. Took me a second to parse this correctly.
Gankro
reviewed
Jul 18, 2015
|
|
||
| OutlivesScalar: | ||
| -------------------------------------------------- | ||
| R ⊢ scalar: 'a |
This comment has been minimized.
This comment has been minimized.
Gankro
Jul 18, 2015
Contributor
Note for those of us without a very strong type theory background:
⊢ == "proves"
So this is just saying that any set of bounds proves that a scalar outlives 'a, for any given 'a (Plain Old Data has no external lifetime constraints, so it lives for any lifetime).
(I think)
This comment has been minimized.
This comment has been minimized.
arielb1
Jul 18, 2015
Contributor
Not exactly "proves". this is a sequent-style deduction rule, read "(implicitly) for every environment R, scalar s and lifetime 'a, s outlives 'a given R"
Gankro
reviewed
Jul 18, 2015
| 'x not in R | ||
| ('x: 'a) in Env | ||
| -------------------------------------------------- | ||
| R ⊢ 'x: 'a |
This comment has been minimized.
This comment has been minimized.
Gankro
Jul 18, 2015
Contributor
Env being "the union of all in scope where clauses and implied bounds"? Unclear.
Also unclear what the significance of 'x not in R is? Are saying that R can only use facts from the environment to prove bounds for otherwise unbound lifetimes?
Gankro
reviewed
Jul 18, 2015
|
|
||
| 'x in R | ||
| -------------------------------------------------- | ||
| R ⊢ 'x: 'a |
This comment has been minimized.
This comment has been minimized.
Gankro
Jul 18, 2015
Contributor
Are these supposed to be the same 'a and 'x from the proceeding paragraph?
Gankro
reviewed
Jul 18, 2015
| Projections have the most possibilities. First, we may find | ||
| information in the environment, as with type parameters, but we can | ||
| also consult the trait definition to find bounds (consider an | ||
| associated type declared like `type Foo: 'static`). These rule only |
This comment has been minimized.
This comment has been minimized.
Gankro
Jul 18, 2015
Contributor
It's seems interesting that trait definitions are not considered part of the environment when talking about a type that implements that trait.
Gankro
reviewed
Jul 18, 2015
| reduce `<PROJ>: 'x` to `&'a T: 'x`, which in turn holds if `'a: 'x` | ||
| and `T: 'x` (from the rule `OutlivesReference`). | ||
|
|
||
| But often we are in a situation where we can't normalize the |
This comment has been minimized.
This comment has been minimized.
Gankro
Jul 18, 2015
Contributor
An example would be great. Is it simply any time you're working with a generic I: Iterator?
This comment has been minimized.
This comment has been minimized.
nikomatsakis
Aug 7, 2015
Author
Contributor
An example would be great. Is it simply any time you're working with a generic I: Iterator?
I added an example, but yes that's roughly right (and other analogous cases, of course).
Gankro
reviewed
Jul 18, 2015
| know this is true without ever knowing what `<TYPE>` is -- we just | ||
| need to see that the trait reference `<Foo as Iterator>` doesn't have | ||
| any lifetimes or type parameters in it, and hence the impl cannot | ||
| refer to any lifetime or type parameters. |
This comment has been minimized.
This comment has been minimized.
Gankro
Jul 18, 2015
Contributor
More generally:
Something can only fail to outlive 'x if its type refers to (non-'static) lifetime that doesn't outlive 'x, and the only lifetimes it can possibly refer to have to be declared in the impl declaration. So it's sufficient (though perhaps not always necessary?) to make sure everything referred to in the impl declaration outlives 'x.
This comment has been minimized.
This comment has been minimized.
nikomatsakis
Jul 20, 2015
Author
Contributor
Something can only fail to outlive 'x if its type refers to (non-'static) lifetime that doesn't outlive 'x, and the only lifetimes it can possibly refer to have to be declared in the impl declaration. So it's sufficient (though perhaps not always necessary?) to make sure everything referred to in the impl declaration outlives 'x.
Yes, with a bit of subtlety -- we have to be sure that it not only appears in the impl declaration, but does not appear as part of a projection (as specified below). But this rule already exists.
In other words:
impl<'a> Trait for <i32 as SomeTrait<'a>>::Bar { ... }
wouldn't be good enough for 'a because maybe <i32 as SomeTrait<'a>>::Bar normalized to u32 (and 'a doesn't appear in u32).
This comment has been minimized.
This comment has been minimized.
Gankro
Jul 20, 2015
Contributor
Is that a problem though? We're trying to reason that it outlives 'a, and u32 is 'static.
Gankro
reviewed
Jul 18, 2015
| This complication is unfortunate, but to a large extent already exists | ||
| with where-clauses and trait matching (see e.g. [#21974]). (Moreover, | ||
| it seems to be inherent to the concept of assocated types, since they | ||
| take several inputs (the parameters to the trait) which may or may not |
This comment has been minimized.
This comment has been minimized.
Gankro
reviewed
Jul 18, 2015
|
|
||
| WfParameter: | ||
| -------------------------------------------------- | ||
| R ⊢ X WF |
This comment has been minimized.
This comment has been minimized.
Gankro
reviewed
Jul 18, 2015
|
|
||
| WfProjection: | ||
| ∀i. R ⊢ Pi WF // all components well-formed | ||
| R ⊢ <P0 as Trait<P1..Pn>> // the projection itself is valid |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
nikomatsakis
Jul 20, 2015
Author
Contributor
Should this be P0: Trait<P1..Pn>?
Yeah, I guess. I alternate between those notations somewhat interchangeably. :)
This comment has been minimized.
This comment has been minimized.
|
I think the |
arielb1
reviewed
Jul 18, 2015
| R ⊢ T WF | ||
| R ⊢ T: Sized | ||
| -------------------------------------------------- | ||
| [T] WF |
This comment has been minimized.
This comment has been minimized.
arielb1
Jul 18, 2015
Contributor
There should also be a WfTuple - in fact in the form you use there should be a Wf rule for each type constructor.
This comment has been minimized.
This comment has been minimized.
nikomatsakis
Aug 7, 2015
Author
Contributor
There should also be a WfTuple - in fact in the form you use there should be a Wf rule for each type constructor.
Added.
arielb1
reviewed
Jul 18, 2015
| WfFn: | ||
| ∀i. R, r.. ⊢ Ti | ||
| -------------------------------------------------- | ||
| R ⊢ for<r..> fn(T1..Tn) -> T0 |
This comment has been minimized.
This comment has been minimized.
arielb1
Jul 18, 2015
Contributor
missing WF - should be
∀i. R, r.. ⊢ Ti WF
--------------------------------------------------
R ⊢ for<r..> fn(T1..Tn) -> T0 WF
arielb1
reviewed
Jul 18, 2015
|
|
||
| and a trait object like `Foo+'x`, when we require that `'static: 'x` | ||
| (which is true, clearly, but in some cases the implicit bounds from | ||
| traits are not `'static` but rather some named lifetime). |
This comment has been minimized.
This comment has been minimized.
arielb1
Jul 18, 2015
Contributor
Is there a case where this is relevant? What's an object type vs. object fragment?
This comment has been minimized.
This comment has been minimized.
Perhaps, but the issue is really not whether it's a bug or not, the question is about whether code is affected by the change. That said, I haven't observed any. |
This comment has been minimized.
This comment has been minimized.
|
|
This comment has been minimized.
This comment has been minimized.
|
Could you also clarify which of |
Gustorn
referenced this pull request
Aug 19, 2015
Merged
Added Sized trait bound for traits that requite it #108
crumblingstatue
added a commit
to crumblingstatue/rust-sdl2_image
that referenced
this pull request
Aug 24, 2015
crumblingstatue
referenced this pull request
Aug 24, 2015
Merged
Put Sized bound on LoadSurface trait #48
arielb1
referenced this pull request
Aug 29, 2015
Closed
Inconsistency in type checking where clauses in trait definition #28055
frewsxcv
added a commit
to frewsxcv/rust-block
that referenced
this pull request
Sep 2, 2015
frewsxcv
referenced this pull request
Sep 2, 2015
Merged
Fix nightly warnings related to lifetimes #1
frewsxcv
added a commit
to frewsxcv/webdriver-rust
that referenced
this pull request
Sep 2, 2015
frewsxcv
referenced this pull request
Sep 2, 2015
Merged
Fix nightly warnings related to lifetimes #17
frewsxcv
added a commit
to frewsxcv/rust-offscreen-rendering-context
that referenced
this pull request
Sep 2, 2015
frewsxcv
referenced this pull request
Sep 2, 2015
Merged
Fix nightly warnings related to lifetimes #27
frewsxcv
added a commit
to frewsxcv/rust-chrono
that referenced
this pull request
Sep 5, 2015
frewsxcv
referenced this pull request
Sep 5, 2015
Merged
Fix nightly warnings related to lifetimes #46
This comment has been minimized.
This comment has been minimized.
Zalastra
commented
Sep 22, 2015
|
Ran into this error using an associated const on a trait. On IRC it was suggested that this is likely a compiler bug. pub trait IterableEnum<T> {
const ENUM_VARIANTS: &'static [T];
} |
This comment has been minimized.
This comment has been minimized.
|
Just add |
This comment has been minimized.
This comment has been minimized.
bluss
commented
Sep 22, 2015
|
It outputs two warnings (playpen)
The first one must be a bug. |
This comment has been minimized.
This comment has been minimized.
|
@bluss it's odd because it seems like it doesn't take actual bounds into account - see fixed version (the |
nikomatsakis
referenced this pull request
Sep 30, 2015
Open
Implied bounds on nested references + variance = soundness hole #25860
This comment has been minimized.
This comment has been minimized.
|
I agree that the On Tue, Sep 22, 2015 at 8:14 AM, Eduard-Mihai Burtescu <
|
nikomatsakis commentedJul 17, 2015
RFC has been accepted and merged.
Current text: https://github.com/rust-lang/rfcs/blob/master/text/1214-projections-lifetimes-and-wf.md
Tracking issue: rust-lang/rust#27579
Type system changes to address the outlives relation with respect to projections, and to better enforce that all types are well-formed (meaning that they respect their declared bounds). The current implementation can be both unsound (rust-lang/rust#24622), inconvenient (rust-lang/rust#23442), and surprising (rust-lang/rust#21748, rust-lang/rust#25692). The changes are as follows:
The proposed changes here have been tested and found to cause only a modest number of regressions (about two dozen root regressions were previously found on crates.io; however, that run did not yet include all the provisions from this RFC; updated numbers coming soon). In order to minimize the impact on users, the plan is to first introduce the changes in two stages:
Note that although the changes do cause regressions, they also cause some code (like that in rust-lang/rust#23442) which currently gets errors to compile successfully.
cc @rust-lang/lang
Rendered