language
language copied to clipboard
Augmenting untyped values with initializers of different type.
This may be covered by the specification, but I'll write it down just to be sure it's what we want.
A program like:
@template
final banana = "foo{x}bar";
augment final banana = (Object x) => augmented.replaceAll('{x}', x.toString());
could possibly be the result of a macro treating the body of the original declaration as a template, and generating a function corresponding to it. Is it valid?
The type of the variable is not declared, so it should be inferred. Inferring the type of a top-level variable is "top-level analysis", but it does analyze the body. In this case, it presumably analyzes each body by itself.
It seems like it should infer the type String for the initial final banana = ... and then there should be an error when the augment final banana inherits that type, and tries to assign a function to it.
It's also possible that the variable doesn't get its type until there is a declaration actually writing a type, or at the end of augmentation, based on the final initializer expression.
That is, final banana = "foo{x}bar"; infers String for the initializer expression, but nothing for the variable yet.
Then augment final banana = (Object) x => augmented.... infers String Function(Object) for its initializer, based on augmented having static type String, and still no type for the variable.
Then, since this was the final augmentation, and the variable not having been given a type yet, the variable is inferred typ have type String Function(Object) from the completely augmented initializer expression.
Either approach can work. Just inferring the type early is more restrictive. Probably also easier to reason about - if you see final banana = "..."; you can deduce that banana has type String, and nothing later can change that.
(So that's probably what we should do, and very likely what we already specify.)
And if the initializer expression has any self-references (to banana, not augmented), inference may run into problems. If we lock the type in as soon as possible, it'll at least only be a problem for that declaration, later self-references have a type.
It seems like it should infer the type
Stringfor the initialfinal banana = ...and then there should be an error when theaugment final bananainherits that type, and tries to assign a function to it.
Yes, this is how it should work (not sure if it is specified explicitly). In the macro spec we do say this "We don't allow augmentations of existing declarations to contribute to inference, so in phase 3 type inference can be performed.". That should be clarified in the augmentations spec as well though, I don't see it there.
That's what I expected.
It does mean that var x; cannot be augmented to have a non-dynamic type by providing an initializer. Which I guess i fine, you should type your var x's that shouldn't be dynamic.
you should type your var x's that shouldn't be dynamic.
Exactly, without a user-visible initializer at the declaration site I think the explicit type is anyways warranted, even if we could infer types based off of a later provided initializer.
I think the remaining work here is clarifying in the augmentations spec? Thanks.
This is already specified:
If the introductory variable declaration does not have a type
annotation, then the variable's declared type is found using only that
declaration, without looking at any further augmenting declarations.
The type can either be inferred from an initializer expression of the
introductory variable declaration, be inherited from a superinterface
for an instance variable, or default to a type of `dynamic` if neither
applies.
This matches what we intend, so I am going to close this