1
1
package dotty .tools .dotc .transform
2
2
3
- import dotty .tools .dotc .ast .TreeTypeMap
4
- import dotty .tools .dotc .ast .Trees .SeqLiteral
3
+ import dotty .tools .dotc .ast .{ tpd , TreeTypeMap }
4
+ import dotty .tools .dotc .ast .Trees .{ TypeApply , SeqLiteral }
5
5
import dotty .tools .dotc .ast .tpd ._
6
6
import dotty .tools .dotc .core .Annotations .Annotation
7
7
import dotty .tools .dotc .core .Contexts .Context
8
8
import dotty .tools .dotc .core .Decorators .StringDecorator
9
9
import dotty .tools .dotc .core .DenotTransformers .InfoTransformer
10
- import dotty .tools .dotc .core .Names .TermName
10
+ import dotty .tools .dotc .core .Names .Name
11
11
import dotty .tools .dotc .core .Symbols .Symbol
12
12
import dotty .tools .dotc .core .{Symbols , Flags }
13
13
import dotty .tools .dotc .core .Types ._
@@ -42,51 +42,82 @@ class TypeSpecializer extends MiniPhaseTransform with InfoTransformer {
42
42
ctx.definitions.CharType -> " $mcC$sp" ,
43
43
ctx.definitions.UnitType -> " $mcV$sp" )
44
44
45
+ private def primitiveTypes (implicit ctx : Context ) =
46
+ List (ctx.definitions.ByteType ,
47
+ ctx.definitions.BooleanType ,
48
+ ctx.definitions.ShortType ,
49
+ ctx.definitions.IntType ,
50
+ ctx.definitions.LongType ,
51
+ ctx.definitions.FloatType ,
52
+ ctx.definitions.DoubleType ,
53
+ ctx.definitions.CharType ,
54
+ ctx.definitions.UnitType
55
+ )
56
+
45
57
private val specializationRequests : mutable.HashMap [Symbols .Symbol , List [List [Type ]]] = mutable.HashMap .empty
46
58
47
- private val newSymbolMap : mutable.HashMap [TermName , ( List [Symbols . TermSymbol ], List [Type ])] = mutable.HashMap .empty // Why does the typechecker require TermSymbol ?
59
+ private val newSymbolMap : mutable.HashMap [Symbol , List [mutable. HashMap [ List [Type ], Symbols . Symbol ]]] = mutable.HashMap .empty
48
60
49
61
override def transformInfo (tp : Type , sym : Symbol )(implicit ctx : Context ): Type = {
62
+ def generateSpecializations (remainingTParams : List [Name ], remainingBounds : List [TypeBounds ])
63
+ (instantiations : List [Type ], names : List [String ], poly : PolyType , decl : Symbol )
64
+ (implicit ctx : Context ): List [Symbol ] = {
65
+ if (remainingTParams.nonEmpty) {
66
+ val bounds = remainingBounds.head
67
+ val specTypes = primitiveTypes.filter{ tpe => bounds.contains(tpe)}
68
+ val specializations = (for (tpe <- specTypes) yield {
69
+ generateSpecializations(remainingTParams.tail, remainingBounds.tail)(tpe :: instantiations, specialisedTypeToSuffix(ctx)(tpe) :: names, poly, decl)
70
+ }).flatten
71
+ specializations
72
+ }
73
+ else {
74
+ generateSpecializedSymbols(instantiations.reverse, names.reverse, poly, decl)
75
+ }
76
+ }
77
+ def generateSpecializedSymbols (instantiations : List [Type ], names : List [String ], poly : PolyType , decl : Symbol )
78
+ (implicit ctx : Context ): List [Symbol ] = {
79
+ val newSym =
80
+ ctx.newSymbol(decl.owner, (decl.name + names.mkString).toTermName,
81
+ decl.flags | Flags .Synthetic , poly.instantiate(instantiations.toList)) // Who should the owner be ? decl.owner ? sym ? sym.owner ? ctx.owner ?
82
+ // TODO I think there might be a bug in the assertion at dotty.tools.dotc.transform.TreeChecker$Checker.dotty$tools$dotc$transform$TreeChecker$Checker$$checkOwner(TreeChecker.scala:244)
83
+ // Shouldn't the owner remain the original one ? In this instance, the assertion always expects the owner to be `class specialization` (the test I run), even for methods that aren't
84
+ // defined by the test itself, such as `instanceOf` (to which my implementation gives owner `class Any`).
85
+ val prevMaps = newSymbolMap.getOrElse(decl, List ()).reverse
86
+ val newMap : mutable.HashMap [List [Type ], Symbols .Symbol ] = mutable.HashMap (instantiations -> newSym)
87
+ newSymbolMap.put(decl, (newMap :: prevMaps.reverse).reverse)
88
+ (newSym :: prevMaps.flatMap(_.values).reverse).reverse // All those reverse are probably useless
89
+ }
50
90
51
- tp.widen match {
52
- case poly : PolyType if ! (sym.isPrimaryConstructor
53
- || (sym is Flags .Label )) =>
54
-
55
- def generateSpecializations (remainingTParams : List [Type ], remainingBounds : List [TypeBounds ])
56
- (instantiations : List [Type ], names : List [String ])(implicit ctx : Context ): Unit = {
57
- if (remainingTParams.nonEmpty) {
58
- val typeToSpecialize = remainingTParams.head
59
- val bounds = remainingBounds.head
60
- val a = shouldSpecializeFor(typeToSpecialize.typeSymbol) // TODO returns Nil because no annotations are found - elucidate
61
- a.flatten
62
- .filter { tpe =>
63
- bounds.contains(tpe)
64
- }.foreach({ tpe =>
65
- val nme = specialisedTypeToSuffix(ctx)(tpe)
66
- generateSpecializations(remainingTParams.tail, remainingBounds.tail)(tpe :: instantiations, nme :: names)
67
- })
68
- }
69
- else {
70
- generateSpecializedSymbols(instantiations.reverse, names.reverse)
91
+ if ((sym ne ctx.definitions.ScalaPredefModule .moduleClass) && ! (sym is Flags .Package ) && ! sym.isAnonymousClass) {
92
+ sym.info match {
93
+ case classInfo : ClassInfo =>
94
+ val newDecls = classInfo.decls.flatMap(decl => {
95
+ if (shouldSpecialize(decl)) {
96
+ decl.info.widen match {
97
+ case poly : PolyType =>
98
+ if (poly.paramNames.length <= maxTparamsToSpecialize && poly.paramNames.length > 0 )
99
+ generateSpecializations(poly.paramNames, poly.paramBounds)(List .empty, List .empty, poly, decl)
100
+ else Nil
101
+ case nil => Nil
102
+ }
103
+ } else Nil
104
+ })
105
+ if (newDecls.nonEmpty) {
106
+ val decls = classInfo.decls.cloneScope
107
+ newDecls.foreach(decls.enter)
108
+ classInfo.derivedClassInfo(decls = decls)
71
109
}
72
- }
73
-
74
- def generateSpecializedSymbols (instantiations : List [Type ], names : List [String ])(implicit ctx : Context ): Unit = {
75
- val newSym = ctx.newSymbol(sym.owner, (sym.name + names.mkString).toTermName, sym.flags | Flags .Synthetic , poly.instantiate(instantiations.toList))
76
- ctx.enter(newSym) // TODO check frozen flag ?
77
- val prev = newSymbolMap.getOrElse(sym.name.toTermName, (Nil , Nil ))
78
- val newSyms = newSym :: prev._1
79
- newSymbolMap.put(sym.name.toTermName, (newSyms, instantiations)) // Could `.put(...)` bring up (mutability) issues ?
80
- }
81
- val origTParams = poly.resType.paramTypess.flatten // Is this really what is needed ?
82
- val bounds = poly.paramBounds
83
- generateSpecializations(origTParams, bounds)(List .empty, List .empty)
84
- tp
85
- case _ =>
86
- tp
87
- }
110
+ case nil =>
111
+ }
112
+ tp
113
+ } else tp
88
114
}
89
115
116
+ def shouldSpecialize (decl : Symbol )(implicit ctx : Context ): Boolean =
117
+ specializationRequests.contains(decl) ||
118
+ (ctx.settings.Yspecialize .value != " " && decl.name.contains(ctx.settings.Yspecialize .value)) ||
119
+ ctx.settings.Yspecialize .value == " all"
120
+
90
121
def registerSpecializationRequest (method : Symbols .Symbol )(arguments : List [Type ])(implicit ctx : Context ) = {
91
122
if (ctx.phaseId > this .treeTransformPhase.id)
92
123
assert(ctx.phaseId <= this .treeTransformPhase.id)
@@ -95,7 +126,7 @@ class TypeSpecializer extends MiniPhaseTransform with InfoTransformer {
95
126
}
96
127
97
128
def specializeForAll (sym : Symbols .Symbol )(implicit ctx : Context ): List [List [Type ]] = {
98
- registerSpecializationRequest(sym)(specialisedTypeToSuffix.keys.toList )
129
+ registerSpecializationRequest(sym)(primitiveTypes )
99
130
println(" Specializing for all primitive types" )
100
131
specializationRequests.getOrElse(sym, Nil )
101
132
}
@@ -106,63 +137,68 @@ class TypeSpecializer extends MiniPhaseTransform with InfoTransformer {
106
137
specializationRequests.getOrElse(sym, Nil )
107
138
}
108
139
109
- def shouldSpecializeFor (sym : Symbols .Symbol )(implicit ctx : Context ): List [List [Type ]] = {
110
- sym.denot.getAnnotation(ctx.definitions.specializedAnnot).getOrElse(Nil ) match {
111
- case annot : Annotation =>
112
- annot.arguments match {
113
- case List (SeqLiteral (types)) =>
114
- specializeForSome(sym)(types.map(tpeTree =>
115
- nameToSpecialisedType(ctx)(tpeTree.tpe.asInstanceOf [TermRef ].name.toString())))
116
- case List () => specializeForAll(sym)
117
- }
118
- case nil =>
119
- if (ctx.settings.Yspecialize .value == " all" ) specializeForAll(sym)
120
- else Nil
121
- }
140
+ def specializeFor (sym : Symbols .Symbol )(implicit ctx : Context ): List [List [Type ]] = {
141
+ sym.denot.getAnnotation(ctx.definitions.specializedAnnot).getOrElse(Nil ) match {
142
+ case annot : Annotation =>
143
+ annot.arguments match {
144
+ case List (SeqLiteral (types)) =>
145
+ specializeForSome(sym)(types.map(tpeTree => // tpeTree.tpe.widen))
146
+ nameToSpecialisedType(ctx)(tpeTree.tpe.asInstanceOf [TermRef ].name.toString()))) // Not sure how to match TermRefs rather than types. comment on line above was an attempt.
147
+ case List () => specializeForAll(sym)
148
+ }
149
+ case nil =>
150
+ if (ctx.settings.Yspecialize .value == " all" ) {println( " Yspecialize set to all " ); specializeForAll(sym) }
151
+ else Nil
152
+ }
122
153
}
123
154
124
155
override def transformDefDef (tree : DefDef )(implicit ctx : Context , info : TransformerInfo ): Tree = {
125
156
126
157
tree.tpe.widen match {
127
158
128
159
case poly : PolyType if ! (tree.symbol.isPrimaryConstructor
129
- || (tree.symbol is Flags .Label )) =>
160
+ || (tree.symbol is Flags .Label )) =>
130
161
val origTParams = tree.tparams.map(_.symbol)
131
162
val origVParams = tree.vparamss.flatten.map(_.symbol)
132
163
println(s " specializing ${tree.symbol} for Tparams: $origTParams" )
133
164
134
- def specialize (instantiations : List [Type ]): List [Tree ] = {
135
- newSymbolMap(tree.name) match {
136
- case newSyms : (List [Symbol ], List [Type ]) =>
137
- newSyms._1.map{newSym =>
138
- polyDefDef(newSym, { tparams => vparams => {
139
- assert(tparams.isEmpty)
140
- new TreeTypeMap (
141
- typeMap = _
142
- .substDealias(origTParams, instantiations.toList)
143
- .subst(origVParams, vparams.flatten.map(_.tpe)),
144
- oldOwners = tree.symbol :: Nil ,
145
- newOwners = newSym :: Nil
146
- ).transform(tree.rhs)
147
- }
148
- })}
149
- case nil =>
150
- List ()
165
+ def specialize (decl : Symbol ): List [Tree ] = {
166
+ val declSpecs = newSymbolMap(decl)
167
+ val newSyms = declSpecs.map(_.values).flatten
168
+ /* for (newSym <- newSyms) {
169
+ println(newSym)
170
+ }*/
171
+ val instantiations = declSpecs.flatMap(_.keys).flatten
172
+ newSyms.map{newSym =>
173
+ polyDefDef(newSym.asTerm, { tparams => vparams => {
174
+ assert(tparams.isEmpty)
175
+ // println(newSym + " ; " + origVParams + " ; " + vparams + " ; " + vparams.flatten + " ; " + vparams.flatten.map(_.tpe))
176
+ new TreeTypeMap ( // TODO Figure out what is happening with newSym. Why do some symbols have unmatching vparams and origVParams ?
177
+ typeMap = _
178
+ .substDealias(origTParams, instantiations)
179
+ .subst(origVParams, vparams.flatten.map(_.tpe)),
180
+ oldOwners = tree.symbol :: Nil ,
181
+ newOwners = newSym :: Nil
182
+ ).transform(tree.rhs)
183
+ }})
151
184
}
152
185
}
153
-
154
- val specializedMethods : List [ Tree ] = ( for (inst <- newSymbolMap.keys) yield specialize(newSymbolMap(inst)._2) ).flatten.toList
186
+ // specializeFor(tree.symbol) -> necessary ? This registers specialization requests, but do they still make sense at this point ? Symbols have already been generated
187
+ val specializedMethods = newSymbolMap.keys.map(specialize ).flatten.toList
155
188
Thicket (tree :: specializedMethods)
156
-
157
189
case _ => tree
158
190
}
159
191
}
160
192
161
- def transformTypeOfTree (tree : Tree ): Tree = {
193
+ override def transformTypeApply (tree : tpd.TypeApply )(implicit ctx : Context , info : TransformerInfo ): Tree = {
194
+ val TypeApply (fun,args) = tree
195
+ val newSymInfo = newSymbolMap(fun.symbol).flatten.toMap
196
+ val specializationType : List [Type ] = args.map(_.tpe.asInstanceOf [TypeVar ].instanceOpt)
197
+ val t = fun.symbol.info.decls
198
+ if (t.nonEmpty) {
199
+ t.cloneScope.lookupEntry(args.head.symbol.name)
200
+ val newSym = newSymInfo(specializationType)
201
+ }
162
202
tree
163
203
}
164
-
165
- override def transformIdent (tree : Ident )(implicit ctx : Context , info : TransformerInfo ): Tree = transformTypeOfTree(tree)
166
- override def transformSelect (tree : Select )(implicit ctx : Context , info : TransformerInfo ): Tree = transformTypeOfTree(tree)
167
-
168
- }
204
+ }
0 commit comments