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 upImplement underscore lifetimes #44691
Conversation
rust-highfive
assigned
nikomatsakis
Sep 19, 2017
This comment has been minimized.
This comment has been minimized.
|
(rust_highfive has picked a reviewer for you, use r? to override) |
cramertj
reviewed
Sep 19, 2017
| self.err_handler() | ||
| .span_err(lt_def.lifetime.span, | ||
| &format!("invalid lifetime name `{}`", lt_def.lifetime.ident)); | ||
| } |
This comment has been minimized.
This comment has been minimized.
cramertj
Sep 19, 2017
Author
Member
Feel free to bikeshed this error message (it shows up in code that tries to explicitly bind '_ in the generics of an item declaration).
This comment has been minimized.
This comment has been minimized.
petrochenkov
Sep 19, 2017
Contributor
An equivalent error is already issued for 'static, so the wording can be reused:
invalid lifetime parameter name: `'static`
This comment has been minimized.
This comment has been minimized.
|
r? @eddyb |
kennytm
reviewed
Sep 19, 2017
| @@ -383,6 +383,9 @@ declare_features! ( | |||
|
|
|||
| // allow '|' at beginning of match arms (RFC 1925) | |||
| (active, match_beginning_vert, "1.21.0", Some(44101)), | |||
|
|
|||
| // allow `'_` placeholder lifetimes | |||
| (active, underscore_lifetimes, "1.21.0", Some(44524)), | |||
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
r=me with build & nit fixed |
petrochenkov
reviewed
Sep 19, 2017
| @@ -318,6 +310,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> { | |||
|
|
|||
| fn visit_generics(&mut self, g: &'a Generics) { | |||
| let mut seen_default = None; | |||
| for lt_def in &g.lifetimes { | |||
This comment has been minimized.
This comment has been minimized.
petrochenkov
Sep 19, 2017
Contributor
Lifetime definitions can happen in for<'a, 'b, 'c> in fn pointers, trait objects, etc.
It's better to place the error in fn visit_lifetime_def.
This comment has been minimized.
This comment has been minimized.
|
@cramertj |
cramertj
force-pushed the
cramertj:underscore-lifetimes
branch
2 times, most recently
from
0c3b9ef
to
942a85c
Sep 19, 2017
nikomatsakis
requested changes
Sep 19, 2017
| @@ -159,7 +159,8 @@ impl fmt::Debug for Lifetime { | |||
|
|
|||
| impl Lifetime { | |||
| pub fn is_elided(&self) -> bool { | |||
| self.name == keywords::Invalid.name() | |||
| self.name == keywords::Invalid.name() || | |||
| self.name == "'_" | |||
This comment has been minimized.
This comment has been minimized.
nikomatsakis
Sep 19, 2017
Contributor
So I've never been crazy about using a "sentinel value" here rather than an enum -- now that we've got more than one sentinel, I feel even less good. Can't we change this to something like
enum LifetimeName {
Elided,
Underscore,
Static,
Name(Token) // or whatever this is
}
This comment has been minimized.
This comment has been minimized.
| @@ -1422,7 +1422,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { | |||
| let lifetime_i = &lifetimes[i]; | |||
|
|
|||
| for lifetime in lifetimes { | |||
| if lifetime.lifetime.is_static() { | |||
| if lifetime.lifetime.is_static() || lifetime.lifetime.name == "'_" { | |||
This comment has been minimized.
This comment has been minimized.
nikomatsakis
Sep 19, 2017
Contributor
...if we were using an enum, this code would be rather cleaner
|
|
||
| struct Foo<'a>(&'a u8); | ||
|
|
||
| fn foo(x: &u8) -> Foo<'_> { |
This comment has been minimized.
This comment has been minimized.
nikomatsakis
Sep 19, 2017
Contributor
can we have some tests that use multiple lifetime parameters in one function? For example:
fn foo(x: &'_ u8, y: &'_ u8) -> &'_ u8 { } // ERROR from elision
fn foo(x: &mut Vec<&'_ u8>, y: &'_ u8) { x.push(y); // ERROR }
struct Foo<'a, 'b> { a: &'a u32, b: &'b u32 }
fn foo_a<'b>(foo: Foo<'_, 'b>) -> &'b u32 { &foo.a } // ERROR
fn foo_b<'b>(foo: Foo<'_, 'b>) -> &'b u32 { &foo.b } // OK
This comment has been minimized.
This comment has been minimized.
|
@cramertj thanks for jumping on this btw -- so excited to see it land =) |
arielb1
added
the
S-waiting-on-author
label
Sep 19, 2017
cramertj
force-pushed the
cramertj:underscore-lifetimes
branch
from
ac16bad
to
c91a1a7
Sep 19, 2017
petrochenkov
reviewed
Sep 19, 2017
| Elided => keywords::Invalid.name(), | ||
| Underscore => Symbol::intern("'_"), | ||
| Static => Symbol::intern("'static"), | ||
| Name(name) => name, |
This comment has been minimized.
This comment has been minimized.
petrochenkov
Sep 19, 2017
Contributor
Nooooo.
This LifetimeName over Name is pure over-engineering, N extra lines of boilerplate just to avoid one string comparison.
This comment has been minimized.
This comment has been minimized.
cramertj
Sep 19, 2017
•
Author
Member
Heh. I don't have any strong opinion here. Take it up with @nikomatsakis
I left it as its own commit so it's easy to pull out if that's the decision.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
nikomatsakis
Sep 20, 2017
Contributor
I disagree. Sentinel values mean you wind up with if-else-if chains like if foo.is_elided() { ... } which are easily forgotten. Having an enum means we can use exhaustive matching, so that when we add variants in the future, the compiler helps us catch cases that are missing etc.
Plus, there isn't a lot of boilerplate here.
This comment has been minimized.
This comment has been minimized.
petrochenkov
Sep 20, 2017
Contributor
@nikomatsakis
Ok, not a big deal.
(I'll revert this when you are on vacation, ha-ha.)
This comment has been minimized.
This comment has been minimized.
|
Gah! I didn't try building rustdoc and the others... |
This comment has been minimized.
This comment has been minimized.
|
cc @Mark-Simulacrum this is why I have |
cramertj
force-pushed the
cramertj:underscore-lifetimes
branch
from
c91a1a7
to
051b5cf
Sep 20, 2017
petrochenkov
reviewed
Sep 20, 2017
| match *self { | ||
| Elided => keywords::Invalid.name(), | ||
| Underscore => Symbol::intern("'_"), | ||
| Static => Symbol::intern("'static"), |
This comment has been minimized.
This comment has been minimized.
cramertj
force-pushed the
cramertj:underscore-lifetimes
branch
from
051b5cf
to
71c8ad4
Sep 20, 2017
This comment has been minimized.
This comment has been minimized.
|
@cramertj |
This comment has been minimized.
This comment has been minimized.
|
|
cramertj
force-pushed the
cramertj:underscore-lifetimes
branch
from
8f5f35c
to
31fd099
Sep 21, 2017
petrochenkov
reviewed
Sep 21, 2017
| Underscore, | ||
| Static, | ||
| Name(Name), | ||
| } |
This comment has been minimized.
This comment has been minimized.
petrochenkov
Sep 21, 2017
•
Contributor
@cramertj
Actually, can you tweak the naming slightly.
enum LifetimeKind { // This is not a name
Implicit, // `Elided` is not correct, because implicit can be both elided and inferred, but we don't discern between them yet when lowering into HIR
Underscore,
Static,
Named(Name), // Named lifetime
}
This comment has been minimized.
This comment has been minimized.
petrochenkov
Sep 21, 2017
Contributor
(The variants are going to change anyway when lifetimes are first resolved, then lowered into HIR.)
This comment has been minimized.
This comment has been minimized.
eddyb
Sep 21, 2017
Member
I think what we want is name resolution to give us a Def, and the existing resolve_lifetimes pass to do elision and compute the semantic representation from Def::Lifetime(DefId).
This comment has been minimized.
This comment has been minimized.
nikomatsakis
Sep 21, 2017
Contributor
@petrochenkov I don't object to calling "Implicit" for sure, but I'm curious: what does "elided" mean to you? To me, it means "not written". I would then say that the behavior around elided lifetimes depends on context: in function signatures, we use defaulting rules (as specified by the lifetime elision RFCs plus the object-lifetime RFCs), and in function bodies, we use inference.
This comment has been minimized.
This comment has been minimized.
eddyb
Sep 21, 2017
Member
Using "elided" to mean literally "not written" may be correct wrt the English language but then "elision rules" doesn't mean much anymore and we have to say "default lifetime rules" I guess? And "lifetime defaulting" for the process of picking a lifetime.
This comment has been minimized.
This comment has been minimized.
nikomatsakis
Sep 21, 2017
Contributor
So personally, when I explain to people, I say something like "sometimes you can elide lifetimes. The meaning of this depends on context. In a function signature, we use the following system of defaults. etc". In other words, I think I do use the terms the way you described. =) But also I rely on context. That is, I might say "elision rules" when it's clear we're talking about function signatures, in which case it just means "defaulting rules" (but including, naturally, the object defaults).
In any case, it seems clear that calling things elided is ripe for confusion. I prefer either "implicit", "not written", or "not present", all of which seem reasonably clear.
This comment has been minimized.
This comment has been minimized.
petrochenkov
Sep 21, 2017
•
Contributor
@nikomatsakis
Well, I usually associate "elided" with "lifetime elision RFCs", i.e. "defaulting", not inference.
It's useful to have some separate words for "not-written-in-signature" and "not-written-in-body", and "elided" and "inferred" already kinda serve this purpose given that "lifetime elision" is commonly used to describe what happens in signatures.
This comment has been minimized.
This comment has been minimized.
nikomatsakis
Sep 21, 2017
Contributor
That makes some sense. I guess I prefer to have words that match their English meanings to the extent possible, though, and to me "elided" just means "not written" (whereas "defaulted" seems more specific -- we assigned it a default value). I admit that the distinction between defaulted (based on some simple rules) and inferred (based on complex analysis) is a subtle one as well. =)
This comment has been minimized.
This comment has been minimized.
nikomatsakis
Sep 21, 2017
Contributor
Regardless, the question at hand is whether to use elided here with the broader meaning, right? In which case, "Implicit" or "Not written" seems fine.
nikomatsakis
approved these changes
Sep 21, 2017
cramertj
added some commits
Sep 19, 2017
cramertj
force-pushed the
cramertj:underscore-lifetimes
branch
from
31fd099
to
f5505d1
Sep 21, 2017
This comment has been minimized.
This comment has been minimized.
|
@bors r+ |
This comment has been minimized.
This comment has been minimized.
|
|
This was referenced Sep 21, 2017
nikomatsakis
added
S-waiting-on-bors
and removed
S-waiting-on-author
labels
Sep 21, 2017
This comment has been minimized.
This comment has been minimized.
bors
added a commit
that referenced
this pull request
Sep 22, 2017
This comment has been minimized.
This comment has been minimized.
|
|
cramertj commentedSep 19, 2017
Part of #44524