Open stereotype441 opened 3 years ago
This suggests that the analyzer is interpreting it as a call to
f
with one argument, and that argument is an invocation ofsuper.call
with type arguments<int, int>
and argument0
.
That is correct. You can validate the AST structure being produced by
Guess before I get spoiled: No, but only because we forgot it in the grammar or semantics. (That seems to be the usual answer around super
.)
The super
+something rules are all special cases. It's not an object invocation, so if we didn't write the special-case rule, it doesn't work.
My opinion is that it should work for every invocation you can do on this
, as long as the superclass has a non-abstract implementation of the corresponding member. If you can do foo(this<a,b>(0))
, you should be able to do foo(super<a,b>(0))
. Anything else is just confusion to users.
We're approaching an old goal: Execute an email! We just need to define a bunch of operators and extension methods, and then anything will mean something! ;-)
I agree with @lrhn that we must have omitted that case from the set of super
constructs by accident, and it would improve on the syntactic consistency if we add that case. However, it's not a practical problem, because we can use .call
today in order to get the behavior of the potential new syntax.
The spec parser does not bring up any parsing problems if we add a new alternative to <primary>
:
<primary> ::= <thisExpression>
| 'super' <unconditionalAssignableSelector>
| 'super' <argumentPart>
| ... ;
Ok, it sounds like we have a soft consensus for changing the front end so that expressions of the form super(arguments)
and super<typeArguments>(arguments)
are allowed when there is an appropriate call
method in the superclass. I suspect this would be a fairly low impact change because these expressions would essentially desugar to super.call(arguments)
and super.call<typeArguments>(arguments)
(which are already supported). @johnniwinther, does that seem right to you? What do you think of the idea?
Here is a proposal for the corresponding language specification update.
LGTM, assuming that there aren't unexpected CFE/backend costs to supporting this.
Support for this (at least for the example code) seems to require 4 lines of code so it should be ok from the CFE perspective.
Did you impose a constraint on the line length? :grin:
Ok, after discussion in the language team meeting, we're going to move forward with this. @eernstg has already updated the spec (https://github.com/dart-lang/language/pull/1636) so all that remains is to write tests, and make the CFE behavior consistent with the analyzer. I'll write some language tests and then turn this over to the front_end team.
Here's a brain teaser for my fellow parsing nerds (I suspect @eernstg and @lrhn will particularly want to weigh in).
Is the following code valid? If so, what do we expect its output to be?
Stop reading now if you want to guess before I spoil it for you.
AFAICT, the answer depends who you ask:
super
followed by <argumentPart>, sof(super<int, int>(0))
should unambiguously parse as a call tof
with two arguments:super < int
andint > (0)
. Thanks to the definitions of operators<
and>
I've provided, this is valid. So I believe according to the spec, the program should printf(x=(C() < int), y=(int > 0))
.f(super<int, int>(0))
as a call tof
with two arguments. If you comment out the definition ofB.call
, the analyzer gives an error; if you comment out the definition ofB.operator<
, it doesn't. This suggests that the analyzer is interpreting it as a call tof
with one argument, and that argument is an invocation ofsuper.call
with type arguments<int, int>
and argument0
.print(f(super(0)));
, you get the exact same message. If instead you change (1) toprint(f(super<int, int>0));
, then the output isf(x=(C() < int), y=(int > 0))
. If you change (1) toprint(f(super.call<int, int>(0)));
, then the output isf(x=C().call<int, int>(0), y=null)
. This suggests that the CFE is parsingf(super<int, int>(0))
the same way as the analyzer (not really surprising, since the parser implementation is shared), but it has an extra rule that "super" isn't callable unless the.call
is explicit.It seems like we ought to fix this disparity. Anyone have an opinion about which interpretation we should pick as the "correct" one? We aren't in danger of breaking anyone because the CFE rejects the code today.
Personally I favor the analyzer's interpretation, partly because it just feels right to me, and partly because I suspect it will be an easy fix to the CFE (leave the shared parser as is, and remove whatever CFE logic is preventing
super
from being callable).