Also an interesting case:
var yield = 5;
var res = switch(yield) { default -> yield + yield; } // are we
returning result of binary plus (10) or yielding result of unary plus
(5)? Seems the first one, yet confusing.
Tagir.
On Fri, May 24, 2019 at 4:30 AM Dan Smith <[email protected]> wrote:
>
> > On May 22, 2019, at 9:45 AM, Brian Goetz <[email protected]> wrote:
> >
> > The “compromise” strategy is like the smart strategy, except that it trades
> > fixed lookahead for missing a few more method invocation cases. Here, we
> > look at the tokens that follow the identifier yield, and use those to
> > determine whether to classify yield as a keyword or identifier. (We’d
> > choose identifier if it is an assignment op (=, +=, etc), left-bracket,
> > dot, and a few others, plus a few two-token sequences (e.g., ++ and then
> > semicolon), which is lookahead(2).
>
> > The compromise strategy misses some cases we could parse unambiguously, but
> > also offers a simpler user model: always qualify invocations of methods
> > called yield when used as expression statements. And it offers the better
> > lookup behavior, which will make life easier for IDEs.
>
> There's still some space for different design choices within the compromise
> strategy: what happens to names in contexts *other than* the start of a
> statement?
>
> I think it's really helpful to split the question into three parts: variable
> names, type names, and method names.
>
> 1) Variable names: we've established that, with a fixed lookahead, every
> legal use of the variable name 'yield' can be properly interpreted. Great.
>
> 2) Type names: 'yield' might be used as the name of a class, type of a method
> parameter, type of a field, array component type, type of a 'final' local
> variable etc. Or we can prohibit it entirely as a type name.
>
> We went through this when designing 'var', and settled on the more
> restrictive position: you can't declare classes/interfaces/type vars or make
> reference to types with name 'var', regardless of context. That way, there's
> no risk of confusion between subtly different programs—wherever you see 'var'
> used as a type, you know it can only mean the keyword.
>
> I think it's best to treat 'yield' like 'var' in this case.
>
> 3) Method names: 'yield(' at the start of a statement means YieldStatement,
> but what about other contexts in which method invocations can appear?
>
> Example:
> var v = switch (x) {
> case 1 -> yield(x); // method call?
> default -> { yield(x); } // no-op, produces x (oops!)
> };
>
> Fortunately, the different normal-completion behavior of a method call and a
> yield statement will probably catch most errors of this form—when I type the
> braces above, I'll probably also try adding a statement after the attempted
> 'yield' call, and the compiler will complain that the statement is
> unreachable. But it's all very subtle (not to mention painful for IDEs).
>
> Taking inspiration from the treatment of type names, my preference here is to
> make a blanket restriction that's easy to visualize: an *unqualified* method
> invocation must not use the name 'yield'. Context is irrelevant. The
> workaround is always to add a qualifier.
>
> (If, in the future, we introduce local methods or something similar that
> can't be qualified, we should not allow such methods to be named 'yield'.)
>
> ---
>
> Are people generally good with my preferred restrictions, or do you think
> it's better to be more permissive?
>