|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
One step towards teasing apart the mixin phase, making
each phase that adds members to traits responsible for
mixing in those members into subclasses of said traits.
Another design tenet is to not emit symbols or trees
only to later remove them. Therefore, we model a
val in a trait as its accessor. The underlying field
is an implementation detail. It must be mixed into
subclasses, but has no business in a trait (an interface).
Also trying to reduce tree creation by changing less in subtrees
during tree transforms.
A lot of nice fixes fall out from this rework:
- Correct bridges and more precise generic signatures for
mixed in accessors, since they are now created before erasure.
- Correct enclosing method attribute for classes nested in trait fields.
Trait fields are now created as MethodSymbol (no longer TermSymbol).
This symbol shows up in the `originalOwner` chain of a class declared
within the field initializer. This promoted the field getter to
being the enclosing method of the nested class, which it is not
(the EnclosingMethod attribute is a source-level property).
- Signature inference is now more similar between vals and defs
- No more field for constant-typed vals, or mixed in accessors
for subclasses. A constant val can be fully implemented in a trait.
TODO:
- give same treatment to trait lazy vals (only accessors, no fields)
- remove support for presuper vals in traits
(they don't have the right init semantics in traits anyway)
- lambdalift should emit accessors for captured vals in traits,
not a field
Assorted notes from the full git history before squashing below.
Unit-typed vals: don't suppress field
it affects the memory model -- even a write of unit to a field is relevant...
unit-typed lazy vals should never receive a field
this need was unmasked by test/files/run/t7843-jsr223-service.scala,
which no longer printed the output expected from the `0 to 10 foreach`
Use getter.referenced to track traitsetter
reify's toolbox compiler changes the name of the trait
that owns the accessor between fields and constructors (`$` suffix),
so that the trait setter cannot be found when doing mkAssign in constructors
this could be solved by creating the mkAssign tree immediately during fields
anyway, first experiment: use `referenced` now that fields runs closer
to the constructors phase (I tried this before and something broke)
Infer result type for `val`s, like we do for `def`s
The lack of result type inference caused pos/t6780 to fail
in the new field encoding for traits, as there is no separate accessor,
and method synthesis computes the type signature based on the ValDef tree.
This caused a cyclic error in implicit search, because now the
implicit val's result type was not inferred from the super member,
and inferring it from the RHS would cause implicit search to consider
the member in question, so that a cycle is detected and type checking fails...
Regardless of the new encoding, we should consistently infer result types
for `def`s and `val`s.
Removed test/files/run/t4287inferredMethodTypes.scala and test/files/presentation/t4287c,
since they were relying on inferring argument types from "overridden" constructors
in a test for range positions of default arguments. Constructors don't override,
so that was a mis-feature of -Yinfer-argument-types.
Had to slightly refactor test/files/presentation/doc, as it was relying
on scalac inferring a big intersection type to approximate the anonymous
class that's instantiated for `override lazy val analyzer`.
Now that we infer `Global` as the expected type based on the overridden val,
we make `getComment` private in navigating between good old Skylla and Charybdis.
I'm not sure why we need this restriction for anonymous classes though;
only structural calls are restricted in the way that we're trying to avoid.
The old behavior is maintained nder -Xsource:2.11.
Tests:
- test/files/{pos,neg}/val_infer.scala
- test/files/neg/val_sig_infer_match.scala
- test/files/neg/val_sig_infer_struct.scala
need NMT when inferring sig for accessor
Q: why are we calling valDefSig and not methodSig?
A: traits use defs for vals, but still use valDefSig...
keep accessor and field info in synch
|
|
* Default arguments are always retained on the <init> method (i.e.,
the class' constructor). Therefore, when the <init> parameters are
created, we need to use `duplicateAndKeepPositions` to make sure that
if a default argument is present, its opaque position is retained as
well. This is necessary because when parameter accessors (i.e.,
`fieldDefs`) are created, all default arguments are discared ( as you
can see in the code, the right-hand-side of a `field` is always an
`EmptyTree`) - see changes in TreeGen.scala
* When constructing the `fieldDefs`, it is important to adapt their
range position to avoid overlappings with the positions of default
arguments. It is worth noting that updating the field's end position
to `vd.rhs.pos.start` would be incorrect, because `askTypeAt(pos)`
could return the incorrect tree when the position is equal to
`vd.rhs.pos.start` (because two nodes including that point position
would exist in the tree, and `CompilerControl.locateTree(pos)` would
return the first tree that includes the passed `pos`). This is why
`1` is subtracted to `vd.rhs.pos.start`. Alternatively, we could have
used `vd.tpt.pos.end` with similar results. However the logic would
have become slightly more complex as we would need to handle the case
where `vd.tpt` doesn't have a range position (for instance, this can
happen if `-Yinfer-argument-types` is enabled). Therefore, subtracting
`1` from `vd.rhs.pos.start` seemed the cleanest solution at the
moment. - see changes in TreeGen.scala.
* If the synthetic constructor contains trees with an opaque range
position (see point above), it must have a transparent position.
This can only happen if the constructor's parameters' positions are
considered, which is why we are now passing `vparamss1` to
`wrappingPos` - see changes in TreeGen.scala.
* The derived primary constructor should have a transparent position
as it may contain trees with an opaque range position. Hence, the
`primaryCtor` position is considered for computing the position of the
derived constructor - see change in Typers.scala.
Finally, below follows the printing of the tree for test t4287, which
you should compare with the one attached with the previous commit
message:
```
[[syntax trees at end of typer]] // Foo.scala
[0:63]package [0:0]<empty> {
[0:37]class Baz extends [9:37][39]scala.AnyRef {
[10:20]<paramaccessor> private[this] val f: [14]Int = _;
[14]<stable> <accessor> <paramaccessor> def f: [14]Int = [14][14]Baz.this.f;
<10:31>def <init>(<10:31>f: [17]<type: [17]scala.Int> = [23:31]B.a): [9]Baz = <10:31>{
<10:31><10:31><10:31>Baz.super.<init>();
<10:31>()
}
};
[6]<synthetic> object Baz extends [6][6]AnyRef {
[6]def <init>(): [9]Baz.type = [6]{
[6][6][6]Baz.super.<init>();
[9]()
};
[14]<synthetic> def <init>$default$1: [14]Int = [30]B.a
};
[39:63]object B extends [48:63][63]scala.AnyRef {
[63]def <init>(): [48]B.type = [63]{
[63][63][63]B.super.<init>();
[48]()
};
[52:61]private[this] val a: [56]Int = [60:61]2;
[56]<stable> <accessor> def a: [56]Int = [56][56]B.this.a
}
}
```
You should notice that the default arg of `Baz` constructor now has a
range position. And that explains why the associated test now returns
the right tree when asking hyperlinking at the location of the default
argument.
|