Skip to content

Commit cf57534

Browse files
committed
Add PrimitiveForwarders and fix forwarding on value classes.
1 parent 9f505a4 commit cf57534

File tree

8 files changed

+102
-15
lines changed

8 files changed

+102
-15
lines changed

compiler/src/dotty/tools/dotc/Compiler.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ class Compiler {
7272
new ElimByName, // Expand by-name parameters and arguments
7373
new AugmentScala2Traits, // Expand traits defined in Scala 2.11 to simulate old-style rewritings
7474
new ResolveSuper, // Implement super accessors and add forwarders to trait methods
75+
new PrimitiveForwarders, // Add forwarders to trait methods that have a mismatch between generic and primitives
7576
new ArrayConstructors), // Intercept creation of (non-generic) arrays and intrinsify.
7677
List(new Erasure), // Rewrite types to JVM model, erasing all type parameters, abstract types and refinements.
7778
List(new ElimErasedValueType, // Expand erased value types to their underlying implmementation types

compiler/src/dotty/tools/dotc/transform/MixinOps.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ class MixinOps(cls: ClassSymbol, thisTransform: DenotTransformer)(implicit ctx:
6868
hasPrimitiveMissMatch(tp1.resultType, tp2.resultType) ||
6969
tp1.paramTypess.flatten.zip(tp1.paramTypess.flatten).exists(args => hasPrimitiveMissMatch(args._1, args._2))
7070
case _ =>
71-
tp1.typeSymbol.isPrimitiveValueClass ^ tp2.typeSymbol.isPrimitiveValueClass
71+
def isPrimitiveOrValueClass(sym: Symbol): Boolean = sym.isPrimitiveValueClass || sym.isValueClass
72+
isPrimitiveOrValueClass(tp1.typeSymbol) ^ isPrimitiveOrValueClass(tp2.typeSymbol)
7273
}
7374

7475
def needsPrimitiveForwarder(m: Symbol): Boolean =
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package dotty.tools.dotc
2+
package transform
3+
4+
import core._
5+
import TreeTransforms._
6+
import Contexts.Context
7+
import Flags._
8+
import SymUtils._
9+
import Symbols._
10+
import SymDenotations._
11+
import Types._
12+
import Decorators._
13+
import DenotTransformers._
14+
import StdNames._
15+
import NameOps._
16+
import ast.Trees._
17+
import util.Positions._
18+
import Names._
19+
import collection.mutable
20+
import ResolveSuper._
21+
22+
/** This phase adds forwarder where mixedin generic and primitive typed methods have a missmatch.
23+
* In particular for every method that is declared both as generic with a primitive type and with a primitive type
24+
* `<mods> def f[Ts](ps1)...(psN): U` in trait M` and
25+
* `<mods> def f[Ts](ps1)...(psN): V = ...` in implemented in N`
26+
* where U is a primitive and V a polymorphic type (or vice versa) needs:
27+
*
28+
* <mods> def f[Ts](ps1)...(psN): U = super[N].f[Ts](ps1)...(psN)
29+
*
30+
* IMPORTANT: When\If Valhalla happens, we'll need to move mixin before erasure and than this code will need to be rewritten
31+
* as it will instead change super-class.
32+
*/
33+
class PrimitiveForwarders extends MiniPhaseTransform with IdentityDenotTransformer { thisTransform =>
34+
import ast.tpd._
35+
36+
override def phaseName: String = "primitiveForwarders"
37+
38+
override def runsAfter = Set(classOf[ResolveSuper])
39+
40+
override def transformTemplate(impl: Template)(implicit ctx: Context, info: TransformerInfo) = {
41+
val cls = impl.symbol.owner.asClass
42+
val ops = new MixinOps(cls, thisTransform)
43+
import ops._
44+
45+
def methodPrimitiveForwarders: List[Tree] =
46+
for (meth <- mixins.flatMap(_.info.decls.flatMap(needsPrimitiveForwarderTo)).distinct)
47+
yield polyDefDef(implementation(meth.asTerm), forwarder(meth))
48+
49+
cpy.Template(impl)(body = methodPrimitiveForwarders ::: impl.body)
50+
}
51+
}

compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,6 @@ import ResolveSuper._
3838
*
3939
* <mods> def f[Ts](ps1)...(psN): U = super[M].f[Ts](ps1)...(psN)
4040
*
41-
* 3.3 (done in `methodPrimitiveForwarders`) For every method that is declared both
42-
* as generic with a primitive type and with a primitive type
43-
* `<mods> def f[Ts](ps1)...(psN): U` in trait M` and
44-
* `<mods> def f[Ts](ps1)...(psN): V = ...` in implemented in N`
45-
* where U is a primitive and V a polymorphic type (or vice versa) needs:
46-
*
47-
* <mods> def f[Ts](ps1)...(psN): U = super[N].f[Ts](ps1)...(psN)
48-
*
4941
* A method in M needs to be disambiguated if it is concrete, not overridden in C,
5042
* and if it overrides another concrete method.
5143
*
@@ -73,11 +65,7 @@ class ResolveSuper extends MiniPhaseTransform with IdentityDenotTransformer { th
7365
for (meth <- mixin.info.decls.toList if needsForwarder(meth))
7466
yield polyDefDef(implementation(meth.asTerm), forwarder(meth))
7567

76-
def methodPrimitiveForwarders: List[Tree] =
77-
for (meth <- mixins.flatMap(_.info.decls.flatMap(needsPrimitiveForwarderTo)).distinct)
78-
yield polyDefDef(implementation(meth.asTerm), forwarder(meth))
79-
80-
val overrides = mixins.flatMap(mixin => superAccessors(mixin) ::: methodOverrides(mixin)) ::: methodPrimitiveForwarders
68+
val overrides = mixins.flatMap(mixin => superAccessors(mixin) ::: methodOverrides(mixin))
8169

8270
cpy.Template(impl)(body = overrides ::: impl.body)
8371
}
@@ -97,7 +85,7 @@ class ResolveSuper extends MiniPhaseTransform with IdentityDenotTransformer { th
9785
private val PrivateOrAccessorOrDeferred = Private | Accessor | Deferred
9886
}
9987

100-
object ResolveSuper{
88+
object ResolveSuper {
10189
/** Returns the symbol that is accessed by a super-accessor in a mixin composition.
10290
*
10391
* @param base The class in which everything is mixed together
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
true
2+
true
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
2+
object Test {
3+
def main(args: Array[String]): Unit = {
4+
println((new Foo: Baz).value1.v)
5+
println((new Foo: Baz).value2.v)
6+
}
7+
}
8+
9+
class Foo extends Bar[VBoolean](new VBoolean(true)) with Baz
10+
11+
class Bar[T](x: T) {
12+
def value1: T = x
13+
def value2(): T = x
14+
}
15+
16+
trait Baz {
17+
def value1: VBoolean
18+
def value2(): VBoolean
19+
}
20+
21+
class VBoolean(val v: Boolean) extends AnyVal
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
true
2+
true
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
2+
object Test {
3+
def main(args: Array[String]): Unit = {
4+
println((new Foo: Bar[VBoolean]).value1.v)
5+
println((new Foo: Bar[VBoolean]).value2.v)
6+
}
7+
}
8+
9+
class Foo extends Baz with Bar[VBoolean]
10+
11+
trait Bar[T] {
12+
def value1: T
13+
def value2(): T
14+
}
15+
16+
class Baz {
17+
def value1: VBoolean = new VBoolean(true)
18+
def value2(): VBoolean = new VBoolean(true)
19+
}
20+
21+
class VBoolean(val v: Boolean) extends AnyVal

0 commit comments

Comments
 (0)