Commit 471fcd9
committed
Fix #9970: Reconcile how Scala 3 and 2 decide whether a trait has $init$.
Scala 2 uses a very simple mechanism to detect traits that have or
don't have a `$init$` method:
* At parsing time, a `$init$` method is created if and only if
there at least one member in the body that "requires" it.
* `$init$` are otherwise never created nor removed.
* A call to `T.$init$` in a subclass `C` is generated if and only
if `T.$init$` exists.
Scala 3 has a flags-based approach to the above:
* At parsing time, a `<init>` method is always created for traits.
* The `NoInits` flag is added if the body does not contain any
member that "requires" an initialization.
* In addition, the constructor receives the `StableRealizable` flag
if the trait *and all its base classes/traits* have the `NoInits`
flag. This is then used for purity analysis in the inliner.
* The `Constructors` phase creates a `$init$` method for traits
that do not have the `NoInits` flag, and generates calls based on
the same criteria.
Now, one might think that this is all fine, except it isn't when we
mix Scala 2 and 3, and in particular when a Scala 2 class extend a
Scala 3 trait.
Indeed, since Scala 3 *always* defines a `<init>` method in traits,
which Scala 2 translates as `$init$`, Scala 2 would think that it
always needs to emit a call to `$init$` (even for traits where
Scala 3 does not, in fact, emit a `$init$` method in the end).
This was mitigated in the TASTy reader of Scala 2 by removing
`$init$` if it has the `STABLE` flag (coming from
`StableRealizable`).
This would have been fine if `StableRealizable` was present if and
only if the owner trait has `NoInits`. But until this commit, that
was not the case: a trait without initialization in itself, but
extending a trait with initialization code, would have the flag
`NoInits` but its constructor would not have the `StableRealizable`
flag.
Therefore, this commit basically reconciles the `NoInits` and
`StableRealizable` flags, so that Scala 2 understands whether or
not a Scala 3 trait has a `$init$` method. We also align those
flags when reading from Scala 2 traits, so that Scala 3 also
understands whether or not a Scala 2 trait has a `$init$` trait.
This solves the compatibility issue between Scala 2 and Scala 3.
One detail remains. The attentive reader may have noticed the
quotes in 'an element of the body that "requires" initialization'.
Scala 2 and Scala 3 do not agree on what requires initialization:
notably, Scala 2 thinks that a concrete `def` requires
initialization, whereas Scala 3 knows that this is not the case.
This is not an issue for synchronous interoperability between Scala
2 and 3, since each decides on its own which of its traits has a
`$init$` method, and communicates that fact to the other version.
However, this still poses an issue for "diachronic" compatibility:
if a library defines a trait with a concrete `def` and is compiled
by Scala 2 in version v1, that trait will have a `$init$`. When the
library upgrades to Scala 3 in version v2, the trait will *lose*
the `$init$`, which can break third-party subclasses.
This commit does not address this issue. There are two ways we
could do so:
* Precisely align the detection of whether a trait should have a
`$init$` method with Scala 2 (notably, adding one when there is a
concrete `def`), or
* *Always* emit an empty static `$init$` method, even for traits
that have the `NoInits` flag (but do not generate calls to them,
nor have that affect whether or not subclasses are considered
pure).1 parent f334e3f commit 471fcd9
File tree
8 files changed
+128
-23
lines changed- compiler/src/dotty/tools/dotc
- ast
- core
- unpickleScala2
- typer
- tests/run-custom-args/tasty-inspector
8 files changed
+128
-23
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
316 | 316 | | |
317 | 317 | | |
318 | 318 | | |
319 | | - | |
| 319 | + | |
320 | 320 | | |
321 | 321 | | |
322 | 322 | | |
| |||
402 | 402 | | |
403 | 403 | | |
404 | 404 | | |
405 | | - | |
406 | | - | |
| 405 | + | |
407 | 406 | | |
408 | 407 | | |
409 | 408 | | |
| |||
459 | 458 | | |
460 | 459 | | |
461 | 460 | | |
462 | | - | |
| 461 | + | |
463 | 462 | | |
464 | 463 | | |
465 | 464 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
181 | 181 | | |
182 | 182 | | |
183 | 183 | | |
184 | | - | |
| 184 | + | |
185 | 185 | | |
186 | 186 | | |
187 | 187 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
293 | 293 | | |
294 | 294 | | |
295 | 295 | | |
296 | | - | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
297 | 304 | | |
298 | 305 | | |
299 | 306 | | |
| |||
319 | 326 | | |
320 | 327 | | |
321 | 328 | | |
322 | | - | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
323 | 332 | | |
324 | 333 | | |
325 | 334 | | |
| |||
536 | 545 | | |
537 | 546 | | |
538 | 547 | | |
539 | | - | |
540 | 548 | | |
541 | 549 | | |
542 | 550 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
725 | 725 | | |
726 | 726 | | |
727 | 727 | | |
728 | | - | |
| 728 | + | |
729 | 729 | | |
730 | 730 | | |
731 | | - | |
732 | | - | |
| 731 | + | |
| 732 | + | |
733 | 733 | | |
734 | 734 | | |
735 | 735 | | |
| |||
Lines changed: 14 additions & 7 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
59 | 59 | | |
60 | 60 | | |
61 | 61 | | |
62 | | - | |
| 62 | + | |
63 | 63 | | |
64 | 64 | | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
65 | 70 | | |
66 | 71 | | |
67 | 72 | | |
| |||
95 | 100 | | |
96 | 101 | | |
97 | 102 | | |
98 | | - | |
| 103 | + | |
99 | 104 | | |
100 | 105 | | |
101 | 106 | | |
| |||
465 | 470 | | |
466 | 471 | | |
467 | 472 | | |
468 | | - | |
469 | | - | |
470 | | - | |
471 | | - | |
472 | | - | |
| 473 | + | |
| 474 | + | |
| 475 | + | |
| 476 | + | |
| 477 | + | |
| 478 | + | |
| 479 | + | |
473 | 480 | | |
474 | 481 | | |
475 | 482 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
555 | 555 | | |
556 | 556 | | |
557 | 557 | | |
558 | | - | |
| 558 | + | |
559 | 559 | | |
560 | 560 | | |
561 | | - | |
562 | | - | |
| 561 | + | |
563 | 562 | | |
564 | 563 | | |
565 | 564 | | |
| |||
864 | 863 | | |
865 | 864 | | |
866 | 865 | | |
867 | | - | |
| 866 | + | |
868 | 867 | | |
869 | 868 | | |
870 | 869 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1197 | 1197 | | |
1198 | 1198 | | |
1199 | 1199 | | |
1200 | | - | |
| 1200 | + | |
| 1201 | + | |
| 1202 | + | |
| 1203 | + | |
1201 | 1204 | | |
1202 | 1205 | | |
1203 | 1206 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
0 commit comments