Skip to content

Commit 4b93cf5

Browse files
committed
Do not look into scala- or java-defined symbols
This caused errors by forcing evaluation on symbols undefined at the current phase or run.
1 parent bdfb1c1 commit 4b93cf5

File tree

5 files changed

+187
-238
lines changed

5 files changed

+187
-238
lines changed

src/dotty/tools/dotc/Compiler.scala

Lines changed: 27 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -20,29 +20,27 @@ import dotty.tools.backend.jvm.{LabelDefs, GenBCode}
2020
class Compiler {
2121

2222
/** Meta-ordering constraint:
23-
*
24-
* DenotTransformers that change the signature of their denotation's info must go
25-
* after erasure. The reason is that denotations are permanently referred to by
26-
* TermRefs which contain a signature. If the signature of a symbol would change,
27-
* all refs to it would become outdated - they could not be dereferenced in the
28-
* new phase.
29-
*
30-
* After erasure, signature changing denot-transformers are OK because erasure
31-
* will make sure that only term refs with fixed SymDenotations survive beyond it. This
32-
* is possible because:
33-
*
34-
* - splitter has run, so every ident or select refers to a unique symbol
35-
* - after erasure, asSeenFrom is the identity, so every reference has a
36-
* plain SymDenotation, as opposed to a UniqueRefDenotation.
37-
*/
23+
*
24+
* DenotTransformers that change the signature of their denotation's info must go
25+
* after erasure. The reason is that denotations are permanently referred to by
26+
* TermRefs which contain a signature. If the signature of a symbol would change,
27+
* all refs to it would become outdated - they could not be dereferenced in the
28+
* new phase.
29+
*
30+
* After erasure, signature changing denot-transformers are OK because erasure
31+
* will make sure that only term refs with fixed SymDenotations survive beyond it. This
32+
* is possible because:
33+
*
34+
* - splitter has run, so every ident or select refers to a unique symbol
35+
* - after erasure, asSeenFrom is the identity, so every reference has a
36+
* plain SymDenotation, as opposed to a UniqueRefDenotation.
37+
*/
3838
def phases: List[List[Phase]] =
3939
List(
4040
List(new FrontEnd),
41-
List(new InstChecks),
42-
List(new FirstTransform,
43-
new SyntheticMethods),
44-
List(new SuperAccessors),
45-
List(new Pickler), // Pickler needs to come last in a group since it should not pickle trees generated later
41+
List(new PostTyper),
42+
List(new Pickler),
43+
List(new FirstTransform),
4644
List(new PreSpecializer,
4745
new RefChecks,
4846
new ElimRepeated,
@@ -54,9 +52,7 @@ class Compiler {
5452
new ExplicitOuter,
5553
new Splitter),
5654
List(new TypeSpecializer),
57-
List(new LazyVals,
58-
new ElimByName,
59-
new SeqLiterals,
55+
List(new SeqLiterals,
6056
new InterceptedMethods,
6157
new Literalize,
6258
new Getters,
@@ -91,13 +87,13 @@ class Compiler {
9187
}
9288

9389
/** Produces the following contexts, from outermost to innermost
94-
*
95-
* bootStrap: A context with next available runId and a scope consisting of
96-
* the RootPackage _root_
97-
* start A context with RootClass as owner and the necessary initializations
98-
* for type checking.
99-
* imports For each element of RootImports, an import context
100-
*/
90+
*
91+
* bootStrap: A context with next available runId and a scope consisting of
92+
* the RootPackage _root_
93+
* start A context with RootClass as owner and the necessary initializations
94+
* for type checking.
95+
* imports For each element of RootImports, an import context
96+
*/
10197
def rootContext(implicit ctx: Context): Context = {
10298
ctx.definitions.init(ctx)
10399
ctx.setPhasePlan(phases)
@@ -126,4 +122,4 @@ class Compiler {
126122
reset()
127123
new Run(this)(rootContext)
128124
}
129-
}
125+
}

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

Lines changed: 43 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -4,69 +4,24 @@ import dotty.tools.dotc.ast.Trees.{Select, Ident, SeqLiteral, Typed}
44
import dotty.tools.dotc.ast.tpd
55
import dotty.tools.dotc.core.Annotations.Annotation
66
import dotty.tools.dotc.core.Contexts.Context
7-
import dotty.tools.dotc.core.DenotTransformers.InfoTransformer
87
import dotty.tools.dotc.core.StdNames._
9-
import dotty.tools.dotc.core.{Flags, Definitions, Symbols}
8+
import dotty.tools.dotc.core.{Flags, Definitions}
109
import dotty.tools.dotc.core.Symbols.Symbol
11-
import dotty.tools.dotc.core.Types.{TermRef, TypeRef, OrType, Type}
10+
import dotty.tools.dotc.core.Types.Type
1211
import dotty.tools.dotc.transform.TreeTransforms.{TransformerInfo, MiniPhaseTransform}
1312

14-
import scala.collection.mutable
15-
1613
/**
1714
* This phase retrieves all `@specialized` anotations before they are thrown away,
1815
* and stores them for the `TypeSpecializer` phase.
1916
*/
20-
class PreSpecializer extends MiniPhaseTransform with InfoTransformer {
17+
class PreSpecializer extends MiniPhaseTransform {
2118

2219
override def phaseName: String = "prespecialize"
2320

24-
private val specTypes: mutable.HashMap[Symbols.Symbol, List[Type]] = mutable.HashMap.empty
25-
26-
override def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context): Type = {
27-
28-
def getSpecTypes(sym: Symbol)(implicit ctx: Context): List[Type] = {
29-
30-
def allowedToSpecialize(sym: Symbol): Boolean = {
31-
sym.name != nme.asInstanceOf_ &&
32-
sym.name != nme.isInstanceOf_ &&
33-
!(sym is Flags.JavaDefined) &&
34-
!sym.isConstructor//isPrimaryConstructor
35-
}
36-
37-
if (allowedToSpecialize(sym)) {
38-
val annotation = sym.denot.getAnnotation(ctx.definitions.specializedAnnot).getOrElse(Nil)
39-
annotation match {
40-
case annot: Annotation =>
41-
val args = annot.arguments
42-
if (args.isEmpty) primitiveTypes
43-
else args.head match {
44-
case a@Typed(SeqLiteral(types), _) => types.map(t => nameToType(t.tpe)) // Matches the expected `@specialized(...)` annotations
45-
case a@Select(Ident(_), _) => primitiveTypes // Matches `Select(Ident(Specializable), Primitives)` which is used in several instances
46-
case _ => ctx.error("surprising match on specialized annotation"); Nil
47-
}
48-
case nil => Nil
49-
}
50-
} else Nil
51-
}
52-
val st = getSpecTypes(sym)
53-
if (st.nonEmpty) {
54-
specTypes.put(sym.owner, st)
55-
}
56-
tp
57-
}
58-
59-
private final def nameToType(name: Type)(implicit ctx: Context) =
60-
name.asInstanceOf[TermRef].name.toString match {
61-
case s if s.startsWith("Int") => defn.IntType
62-
case s if s.startsWith("Boolean") => defn.BooleanType
63-
case s if s.startsWith("Byte") => defn.ByteType
64-
case s if s.startsWith("Long") => defn.LongType
65-
case s if s.startsWith("Short") => defn.ShortType
66-
case s if s.startsWith("Float") => defn.FloatType
67-
case s if s.startsWith("Unit") => defn.UnitType
68-
case s if s.startsWith("Double") => defn.DoubleType
69-
case s if s.startsWith("Char") => defn.CharType
21+
private final def primitiveCompanionToPrimitive(companion: Type)(implicit ctx: Context) = {
22+
val claz = companion.termSymbol.companionClass
23+
assert(ctx.definitions.ScalaValueClasses.contains(claz))
24+
claz.typeRef
7025
}
7126

7227
def defn(implicit ctx: Context): Definitions = ctx.definitions
@@ -83,9 +38,42 @@ class PreSpecializer extends MiniPhaseTransform with InfoTransformer {
8338
ctx.definitions.UnitType
8439
)
8540

41+
def getSpec(sym: Symbol)(implicit ctx: Context): List[Type] = {
42+
43+
def allowedToSpecialize(sym: Symbol): Boolean = {
44+
sym.name != nme.asInstanceOf_ &&
45+
sym.name != nme.isInstanceOf_ &&
46+
!(sym is Flags.JavaDefined) &&
47+
!sym.isConstructor &&
48+
!sym.name.toString.contains("Function2")
49+
}
50+
51+
if (allowedToSpecialize(sym)) {
52+
val annotation = sym.denot.getAnnotation(ctx.definitions.specializedAnnot).getOrElse(Nil)
53+
annotation match {
54+
case annot: Annotation =>
55+
val args = annot.arguments
56+
if (args.isEmpty) primitiveTypes
57+
else args.head match {
58+
case a@Typed(SeqLiteral(types), _) => types.map(t => primitiveCompanionToPrimitive(t.tpe)) // Matches the expected `@specialized(...)` annotations
59+
case a@Select(Ident(_), _) => primitiveTypes // Matches `Select(Ident(Specializable), Primitives)` which is used in several instances
60+
case _ => ctx.error("surprising match on specialized annotation"); Nil
61+
}
62+
case nil => Nil
63+
}
64+
} else Nil
65+
}
66+
8667
override def transformDefDef(tree: tpd.DefDef)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = {
87-
val st = specTypes.getOrElse(tree.symbol, List())
88-
if (st.nonEmpty) ctx.specializePhase.asInstanceOf[TypeSpecializer].registerSpecializationRequest(tree.symbol)(st)
68+
val tparams = tree.tparams.map(_.symbol)
69+
val st = tparams.map(getSpec)
70+
if (st.nonEmpty) {
71+
st.map{
72+
case (types: List[Type]) if types.nonEmpty =>
73+
ctx.specializePhase.asInstanceOf[TypeSpecializer].registerSpecializationRequest(tree.symbol)(types)
74+
case _ =>
75+
}
76+
}
8977
tree
9078
}
91-
}
79+
}

0 commit comments

Comments
 (0)