-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
NLL should identify and respect the lifetime annotations that the user wrote #47184
Comments
I'm tagging this with E-hard because @pnkfelix and I established that as the "have to figure out how to do this" convention. That said, I don't know that it's that hard. My rough plan was something like this:
However, it might also be best to have some other way to indicate which types are from user -- for example, maybe instead of a But I sort of prefer to have the "explicit annotations" come from somewhere else, seems easier overall to me. |
cc @Aaron1011 -- btw, since you're on a roll lately, this would be a good one to get done at some point. It'll require a bit of experimentation though. =) Happy to discuss it sometime. |
I'll tackle this one. |
@davidtwco ok, so I think my prior directions were the right path still. It probably makes sense to tackle different kinds of annotations independently. Let's start with the most basic sort of annotation, that placed on local variables: let x: T = ... To handle this, I think we want to add a new form of MIR statement, a type assertion. That would be done by editing the StorageKind enum: Line 1163 in 27a046e
I would call it something like
We would then want to special-case these statements in the renumberer, so that it skips the embedded type within: rust/src/librustc_mir/borrow_check/nll/renumber.rs Lines 121 to 131 in 27a046e
But actually I realize there is a bit more complexity here than I initially considered. For example: let x: &u32 = ...; needs to be distinguished from let x: &'static u32 = ...; The current code doesn't have give you a good way to do that. But let's ignore that complication for a moment -- I have some ideas there for later =). For now, let's just test it with Anyway, once we have this MIR, we also need to generate it. This could presumably mean instrumenting the HAIR, which is the intermediate IR that we use to transition from HIR to MIR. I think we would want to extend the rust/src/librustc_mir/hair/mod.rs Lines 87 to 104 in 27a046e
These are converted to MIR here: rust/src/librustc_mir/build/block.rs Lines 101 to 107 in 27a046e
Hmm. As you can see from the comment, I initially thought we would apply the type to the initializer -- this would probably mean threading the user's type to rust/src/librustc_mir/build/block.rs Line 124 in 27a046e
So it can add the appropriate assertions. But I guess that wouldn't cover a case like
Maybe we want to do things slightly differently. Mostly I wanted to avoid having the need to "match up" the patterns on the LHS (e.g., the |
Oh, I neglected to add that we will want to kill those new statements, presumably through a pass roughly like |
@nikomatsakis I've submitted a PR with what I've got so far: #48482. |
After chatting with @nikomatsakis on Gitter, here's a list of everywhere within function bodies where we annotate types: (Update: @pnkfelix moved the list to the issue description to increase its visibility and make it easier to update it consistently.) |
@davidtwco so the problem in #48482 is (I think) precisely that sometimes user-given types may still include inference variables. The example I gave on gitter is a case of that: fn foo() {
let x = 22;
let y: &u32 = &x;
...
} Specifically, the lifetime in the type of However, what we can use is a So, I think that the thing we want to be keeping in all of these cases (but let's just keep concentrating on the types in rust/src/librustc/infer/canonical.rs Lines 470 to 472 in 8c4ff22
Though we may need to add a pub type CanonicalTy<'gcx> = Canonical<'gcx, Ty<'tcx>>;
impl<'gcx: 'tcx, 'tcx> Canonicalize<'gcx, 'tcx> for Ty<'tcx> {
type Canonicalized = CanonicalTy<'gcx>;
fn intern(
_gcx: TyCtxt<'_, 'gcx, 'gcx>,
value: Canonical<'gcx, Self::Lifted>,
) -> Self::Canonicalized {
value
}
} Anyway, the next challenge is that the "typeck tables" don't have a suitable table: rust/src/librustc/ty/context.rs Lines 338 to 339 in 8c4ff22
We'll have to add a field like this one: rust/src/librustc/ty/context.rs Lines 347 to 350 in 8c4ff22
but it should be called Finally, we have to populate that field. We first convert the user-provided types here: rust/src/librustc_typeck/check/mod.rs Lines 946 to 949 in 8c4ff22
If we canonicalize the type right there, before we go and do anything else it, that should give us the value we want for the table. We can do the store into the table with rust/src/librustc_typeck/check/mod.rs Line 950 in 8c4ff22
|
NLL should identify and respect the lifetime annotations that the user wrote Part of rust-lang#47184. r? @nikomatsakis
NLL should identify and respect the lifetime annotations that the user wrote Part of #47184. r? @nikomatsakis
With #48482 merged, there are some things that were not covered in that PR. rust/src/librustc_mir/build/block.rs Lines 128 to 135 in 4161ae7
Further, this PR also only implements the check for type annotations in the |
…n-ascription, r=pnkfelix support ascription for patterns in NLL This implements the strategy outlined in [this comment](#47184 (comment)): - We first extend the NLL subtyping code so it can handle inference variables and subtyping. - Then we extend HAIR patterns with type ascription. - Then we treat the type `T` in `let pat: T = ...` as an ascription. Before landing, a few things: - [x] Fix the WF rule bug (filed a FIXME #54105) - [x] Fix an ICE I encountered locally around bound regions, or else file a follow-up - [x] More tests probably =) r? @pnkfelix
Spun out to sub-issues. |
Demoting to Rust 2018 release. However, we should go ahead and convert all remaining items to sub-issues, I think, and close this |
…type-take-2, r=nikomatsakis Handle bindings in substructure of patterns with type ascriptions This attempts to follow the outline described by @nikomatsakis [here](#47184 (comment)). Its a bit more complicated than expected for two reasons: 1. In general it handles sets of type ascriptions, because such ascriptions can be nested within patterns 2. It has a separate types in the HAIR, `PatternTypeProjections` and `PatternTypeProjection`, which are analogues to the corresponding types in the MIR. The main reason I added the new HAIR types was because I am worried that the current implementation is inefficent, and asymptotically so: It makes copies of vectors as it descends the patterns, even when those accumulated vectors are never used. Longer term, I would like to used a linked tree structure for the `PatternTypeProjections` and `PatternTypeProjection`, and save the construction of standalone vectors for the MIR types. I didn't want to block landing this on that hypoethetical revision; but I figured I could at least make the future change easier by differentiating between the two types now. Oh, one more thing: This doesn't attempt to handle `ref x` (in terms of ensuring that any necessary types are ascribed to `x` in that scenario as well). We should open an issue to investigate supporting that as well. But I didn't want to block this PR on that future work. Fix #54570
I'm going to close this bug now -- we're down to just a handful of "subbullets", each of which has their own tracking issues. |
We have made some progress on this issue.
Here's a list of everywhere within function bodies where we annotate types, with check boxes on the ones that are currently getting checked by the MIR-borrowck / NLL.
let x: u32 = 3;
let (x, y): (u32, u32) = (33, 54);
patterns.rs
UI test.let _: Foo<'long> = c_is_short_oops;
(support ascription for patterns in NLL #53873)let x: T;
(support ascription for patterns in NLL #53873)let (x, y): (u32, u32);
ref
bindings: e.g.let ref x: u32 = 3;
, broken out into handle user type annotations in NLL forref
bindings #55401"2048".parse::<u32>()
-- MIR: support user-given type annotations on fns, structs, and enums #53225<T as Trait<_>>::method
-- MIR: support user-given type annotations on fns, structs, and enums #53225<_ as Trait<T>>::method
-- MIR: support user-given type annotations on fns, structs, and enums #53225<_ as Trait<_>>::method<T>
-- MIR: support user-given type annotations on fns, structs, and enums #53225Foo::<X>::method
-- broken out into nll should respect lifetime annotations from multi-segment paths #54574let x = foo::<...>;
-- MIR: support user-given type annotations on fns, structs, and enums #53225let x = SomeStruct::<'static> { field: u32 };
-- MIR: support user-given type annotations on fns, structs, and enums #53225<T as Foo>::BAR
? (broken out to nll: respect user type annotations with constants in expressions #54571)<T as Foo>::BAR
? (nll: respect user type annotations with constants in patterns #55511)let A::<'static>(r) = ...
? -- broken out into nll should respect lifetime annotations from patterns #54573Enum::Variant::<...>(...)
-- MIR: support user-given type annotations on fns, structs, and enums #53225None::<&'static u32>
-- MIR: support user-given type annotations on fns, structs, and enums #53225x as T
(broken out into NLL should respect lifetimes inas
expressions #54332)x: &'static u32
(broken out into nll should preserve user types in type ascription #54331)<Type as Trait>::method(args);
-- MIR: support user-given type annotations on fns, structs, and enums #53225yield-subtype.rs
test but that will also need resolved.(We should update this list as we think of more.)
Original bug report follows:
This code compiles with 1.24.0-nightly (2018-01-03 0a3761e):
This is confusing as the
Vec
almost certainly cannot contain a reference of a'static
lifetime. If you uncomment the call toonly_static
, you get the expected error that theString
does not live long enough.@nikomatsakis said:
The text was updated successfully, but these errors were encountered: