Skip to content

Commit 0679784

Browse files
committed
Merge pull request #563 from dotty-staging/classtags
ClassTags: New phase which synthesises class tags.
2 parents d2b6f3c + 736682e commit 0679784

File tree

5 files changed

+106
-17
lines changed

5 files changed

+106
-17
lines changed

src/dotty/tools/dotc/Compiler.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ class Compiler {
5454
new InterceptedMethods,
5555
new Literalize,
5656
new Getters,
57+
new ClassTags,
5758
new ElimByName,
5859
new ResolveSuper),
5960
List(new Erasure),

src/dotty/tools/dotc/core/StdNames.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,10 @@ object StdNames {
149149
final val Seq: N = "Seq"
150150
final val Symbol: N = "Symbol"
151151
final val ClassTag: N = "ClassTag"
152+
final val classTag: N = "classTag"
152153
final val WeakTypeTag: N = "WeakTypeTag"
153154
final val TypeTag : N = "TypeTag"
155+
final val typeTag: N = "typeTag"
154156
final val Expr: N = "Expr"
155157
final val String: N = "String"
156158
final val Annotation: N = "Annotation"

src/dotty/tools/dotc/core/SymDenotations.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1350,7 +1350,7 @@ object SymDenotations {
13501350
// than this is a scope that will eventually become decls of this symbol.
13511351
// And this should only happen if this is first time the scope of symbol
13521352
// is computed, ie symbol yet has no future.
1353-
assert(this.nextInRun == this)
1353+
assert(this.nextInRun.validFor.code <= this.validFor.code)
13541354
scope
13551355
case _ => unforcedDecls.openForMutations
13561356
}
@@ -1371,7 +1371,7 @@ object SymDenotations {
13711371

13721372
/** Enter a symbol in given `scope` without potentially replacing the old copy. */
13731373
def enterNoReplace(sym: Symbol, scope: MutableScope)(implicit ctx: Context): Unit = {
1374-
require((sym.denot.flagsUNSAFE is Private) || !(this is Frozen))
1374+
require((sym.denot.flagsUNSAFE is Private) || !(this is Frozen) || (scope ne this.unforcedDecls))
13751375
scope.enter(sym)
13761376

13771377
if (myMemberFingerPrint != FingerPrint.unknown)
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
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 dotty.tools.dotc.ast.tpd
18+
import dotty.tools.dotc.core.Constants.Constant
19+
import util.Positions._
20+
import Names._
21+
import collection.mutable
22+
23+
/** This phase replaces calls to DottyPredef.classTag by code that synthesizes appropriate ClassTag
24+
*/
25+
class ClassTags extends MiniPhaseTransform with IdentityDenotTransformer { thisTransform =>
26+
import ast.tpd._
27+
28+
private var classTagCache: Symbol = null
29+
private var typeTagCache: Symbol = null
30+
private var scala2ClassTagModule: Symbol = null
31+
32+
33+
override def prepareForUnit(tree: tpd.Tree)(implicit ctx: Context): TreeTransform = {
34+
val predefClass = defn.DottyPredefModule.moduleClass.asClass
35+
classTagCache = ctx.requiredMethod(predefClass, nme.classTag)
36+
typeTagCache = ctx.requiredMethod(predefClass, nme.typeTag)
37+
scala2ClassTagModule = ctx.requiredModule("scala.reflect.ClassTag")
38+
this
39+
}
40+
41+
override def phaseName: String = "classTags"
42+
43+
override def transformTypeApply(tree: tpd.TypeApply)(implicit ctx: Context, info: TransformerInfo): tpd.Tree =
44+
if (tree.fun.symbol eq classTagCache) {
45+
val tp = tree.args.head.tpe
46+
val defn = ctx.definitions
47+
val (elemType, ndims) = tp match {
48+
case defn.MultiArrayType(elem, ndims) => (elem, ndims)
49+
case _ => (tp, 0)
50+
}
51+
52+
val claz = tp.classSymbol
53+
val elemClaz = elemType.classSymbol
54+
assert(!claz.isPrimitiveValueClass) // should be inserted by typer
55+
val elemTag = if (defn.ScalaValueClasses.contains(elemClaz) || elemClaz == defn.NothingClass || elemClaz == defn.NullClass)
56+
ref(defn.DottyPredefModule).select(s"${elemClaz.name}ClassTag".toTermName)
57+
else if (ValueClasses.isDerivedValueClass(elemClaz)) ref(claz.companionModule)
58+
else if (elemClaz eq defn.AnyClass) ref(scala2ClassTagModule).select(nme.Any)
59+
else {
60+
val erazedTp = TypeErasure.erasure(elemType).classSymbol.typeRef
61+
ref(scala2ClassTagModule).select(nme.apply).appliedToType(erazedTp).appliedTo(Literal(Constant(erazedTp)))
62+
}
63+
(1 to ndims).foldLeft(elemTag)((arr, level) => Select(arr, nme.wrap).ensureApplied).ensureConforms(tree.tpe)
64+
} else tree
65+
}

src/dotty/tools/dotc/transform/ExtensionMethods.scala

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -46,35 +46,56 @@ class ExtensionMethods extends MiniPhaseTransform with DenotTransformer with Ful
4646
override def runsAfterGroupsOf = Set(classOf[FirstTransform]) // need companion objects to exist
4747

4848
override def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation = ref match {
49-
case ref: ClassDenotation if ref is ModuleClass =>
50-
ref.linkedClass match {
51-
case origClass: ClassSymbol if isDerivedValueClass(origClass) =>
52-
val cinfo = ref.classInfo
49+
case moduleClassSym: ClassDenotation if moduleClassSym is ModuleClass =>
50+
moduleClassSym.linkedClass match {
51+
case valueClass: ClassSymbol if isDerivedValueClass(valueClass) =>
52+
val cinfo = moduleClassSym.classInfo
5353
val decls1 = cinfo.decls.cloneScope
54+
val moduleSym = moduleClassSym.symbol.asClass
55+
56+
var newSuperClass: Type = null
57+
5458
ctx.atPhase(thisTransformer.next) { implicit ctx =>
5559
// In Scala 2, extension methods are added before pickling so we should
5660
// not generate them again.
57-
if (!(origClass is Scala2x)) ctx.atPhase(thisTransformer) { implicit ctx =>
58-
for (decl <- origClass.classInfo.decls) {
61+
if (!(valueClass is Scala2x)) ctx.atPhase(thisTransformer) { implicit ctx =>
62+
for (decl <- valueClass.classInfo.decls) {
5963
if (isMethodWithExtension(decl))
60-
decls1.enter(createExtensionMethod(decl, ref.symbol))
64+
decls1.enter(createExtensionMethod(decl, moduleClassSym.symbol))
6165
}
6266
}
6367

64-
val sym = ref.symbol
65-
val underlying = erasure(underlyingOfValueClass(origClass))
66-
val evt = ErasedValueType(origClass, underlying)
67-
val u2evtSym = ctx.newSymbol(sym, nme.U2EVT, Synthetic | Method,
68+
val underlying = erasure(underlyingOfValueClass(valueClass))
69+
val evt = ErasedValueType(valueClass, underlying)
70+
val u2evtSym = ctx.newSymbol(moduleSym, nme.U2EVT, Synthetic | Method,
6871
MethodType(List(nme.x_0), List(underlying), evt))
69-
val evt2uSym = ctx.newSymbol(sym, nme.EVT2U, Synthetic | Method,
72+
val evt2uSym = ctx.newSymbol(moduleSym, nme.EVT2U, Synthetic | Method,
7073
MethodType(List(nme.x_0), List(evt), underlying))
74+
75+
val defn = ctx.definitions
76+
77+
val underlyingCls = underlying.classSymbol
78+
val underlyingClsName =
79+
if (defn.ScalaNumericValueClasses.contains(underlyingCls) ||
80+
underlyingCls == defn.BooleanClass) underlyingCls.name else nme.Object
81+
82+
83+
val syp = ctx.requiredClass(s"dotty.runtime.vc.VC${underlyingClsName}Companion").asClass
84+
85+
newSuperClass = tpd.ref(syp).select(nme.CONSTRUCTOR).appliedToType(valueClass.typeRef).tpe.resultType
86+
7187
decls1.enter(u2evtSym)
7288
decls1.enter(evt2uSym)
7389
}
74-
if (decls1.isEmpty) ref
75-
else ref.copySymDenotation(info = cinfo.derivedClassInfo(decls = decls1))
90+
91+
// add a VCXXXCompanion superclass
92+
93+
moduleClassSym.copySymDenotation(info =
94+
cinfo.derivedClassInfo(
95+
classParents = ctx.normalizeToClassRefs(List(newSuperClass), moduleSym, decls1),
96+
decls = decls1))
7697
case _ =>
77-
ref
98+
moduleClassSym
7899
}
79100
case ref: SymDenotation
80101
if isMethodWithExtension(ref) && ref.hasAnnotation(defn.TailrecAnnotationClass) =>

0 commit comments

Comments
 (0)