|
| 1 | +package dotty.tools.dotc |
| 2 | +package transform |
| 3 | + |
| 4 | +import TreeTransforms.{ MiniPhaseTransform, TransformerInfo } |
| 5 | +import ast.Trees._, ast.tpd, core._ |
| 6 | +import Contexts.Context, Types._, Decorators._, Symbols._, DenotTransformers._ |
| 7 | +import SymDenotations._, Scopes._, StdNames._, NameOps._, Names._ |
| 8 | + |
| 9 | +import scala.collection.mutable |
| 10 | + |
| 11 | +/** Specializes classes that inherit from `FunctionN` where there exists a |
| 12 | + * specialized form. |
| 13 | + */ |
| 14 | +class SpecializeFunctions extends MiniPhaseTransform with InfoTransformer { |
| 15 | + import ast.tpd._ |
| 16 | + val phaseName = "specializeFunctions" |
| 17 | + |
| 18 | + private[this] var _blacklistedSymbols: List[Symbol] = _ |
| 19 | + |
| 20 | + private def blacklistedSymbols(implicit ctx: Context): List[Symbol] = { |
| 21 | + if (_blacklistedSymbols eq null) _blacklistedSymbols = List( |
| 22 | + ctx.getClassIfDefined("scala.math.Ordering").asClass.membersNamed("Ops".toTypeName).first.symbol |
| 23 | + ) |
| 24 | + |
| 25 | + _blacklistedSymbols |
| 26 | + } |
| 27 | + |
| 28 | + /** Transforms the type to include decls for specialized applys and replace |
| 29 | + * the class parents with specialized versions. |
| 30 | + */ |
| 31 | + def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context) = tp match { |
| 32 | + case tp: ClassInfo if !sym.is(Flags.Package) && (tp.decls ne EmptyScope) => { |
| 33 | + var newApplys = Map.empty[Name, Symbol] |
| 34 | + |
| 35 | + val newParents = tp.parents.mapConserve { parent => |
| 36 | + List(0, 1, 2, 3).flatMap { arity => |
| 37 | + val func = defn.FunctionClass(arity) |
| 38 | + if (!parent.derivesFrom(func)) Nil |
| 39 | + else { |
| 40 | + val typeParams = tp.typeRef.baseArgInfos(func) |
| 41 | + val interface = specInterface(typeParams) |
| 42 | + |
| 43 | + if (interface.exists) { |
| 44 | + if (tp.decls.lookup(nme.apply).exists) { |
| 45 | + val specializedMethodName = nme.apply.specializedFunction(typeParams.last, typeParams.init) |
| 46 | + newApplys = newApplys + (specializedMethodName -> interface) |
| 47 | + } |
| 48 | + |
| 49 | + if (parent.isRef(func)) List(interface.typeRef) |
| 50 | + else Nil |
| 51 | + } |
| 52 | + else Nil |
| 53 | + } |
| 54 | + } |
| 55 | + .headOption |
| 56 | + .getOrElse(parent) |
| 57 | + } |
| 58 | + |
| 59 | + def newDecls = |
| 60 | + if (newApplys.isEmpty) tp.decls |
| 61 | + else |
| 62 | + newApplys.toList.map { case (name, interface) => |
| 63 | + ctx.newSymbol( |
| 64 | + sym, |
| 65 | + name, |
| 66 | + Flags.Override | Flags.Method, |
| 67 | + interface.info.decls.lookup(name).info |
| 68 | + ) |
| 69 | + } |
| 70 | + .foldLeft(tp.decls.cloneScope) { |
| 71 | + (scope, sym) => scope.enter(sym); scope |
| 72 | + } |
| 73 | + |
| 74 | + tp.derivedClassInfo( |
| 75 | + classParents = newParents, |
| 76 | + decls = newDecls |
| 77 | + ) |
| 78 | + } |
| 79 | + |
| 80 | + case _ => tp |
| 81 | + } |
| 82 | + |
| 83 | + /** Transforms the `Template` of the classes to contain forwarders from the |
| 84 | + * generic applys to the specialized ones. Also replaces parents of the |
| 85 | + * class on the tree level and inserts the specialized applys in the |
| 86 | + * template body. |
| 87 | + */ |
| 88 | + override def transformTemplate(tree: Template)(implicit ctx: Context, info: TransformerInfo) = { |
| 89 | + val applyBuf = new mutable.ListBuffer[Tree] |
| 90 | + val newBody = tree.body.mapConserve { |
| 91 | + case dt: DefDef if dt.name == nme.apply && dt.vparamss.length == 1 => { |
| 92 | + val specName = nme.apply.specializedFunction( |
| 93 | + dt.tpe.widen.finalResultType, |
| 94 | + dt.vparamss.head.map(_.symbol.info) |
| 95 | + ) |
| 96 | + |
| 97 | + val specializedApply = tree.symbol.enclosingClass.info.decls.lookup(specName)//member(specName).symbol |
| 98 | + //val specializedApply = tree.symbol.enclosingClass.info.member(specName).symbol |
| 99 | + |
| 100 | + if (false) { |
| 101 | + println(tree.symbol.enclosingClass.show) |
| 102 | + println("'" + specName.show + "'") |
| 103 | + println(specializedApply) |
| 104 | + println(specializedApply.exists) |
| 105 | + } |
| 106 | + |
| 107 | + |
| 108 | + if (specializedApply.exists) { |
| 109 | + val apply = specializedApply.asTerm |
| 110 | + val specializedDecl = |
| 111 | + polyDefDef(apply, trefs => vrefss => { |
| 112 | + dt.rhs |
| 113 | + .changeOwner(dt.symbol, apply) |
| 114 | + .subst(dt.vparamss.flatten.map(_.symbol), vrefss.flatten.map(_.symbol)) |
| 115 | + }) |
| 116 | + applyBuf += specializedDecl |
| 117 | + |
| 118 | + // create a forwarding to the specialized apply |
| 119 | + cpy.DefDef(dt)(rhs = { |
| 120 | + tpd |
| 121 | + .ref(apply) |
| 122 | + .appliedToArgs(dt.vparamss.head.map(vparam => ref(vparam.symbol))) |
| 123 | + }) |
| 124 | + } else dt |
| 125 | + } |
| 126 | + case x => x |
| 127 | + } |
| 128 | + |
| 129 | + val missing: List[TypeTree] = List(0, 1, 2, 3).flatMap { arity => |
| 130 | + val func = defn.FunctionClass(arity) |
| 131 | + val tr = tree.symbol.enclosingClass.typeRef |
| 132 | + |
| 133 | + if (!tr.parents.exists(_.isRef(func))) Nil |
| 134 | + else { |
| 135 | + val typeParams = tr.baseArgInfos(func) |
| 136 | + val interface = specInterface(typeParams) |
| 137 | + |
| 138 | + if (interface.exists) List(interface.info) |
| 139 | + else Nil |
| 140 | + } |
| 141 | + }.map(TypeTree) |
| 142 | + |
| 143 | + cpy.Template(tree)( |
| 144 | + parents = tree.parents ++ missing, |
| 145 | + body = applyBuf.toList ++ newBody |
| 146 | + ) |
| 147 | + } |
| 148 | + |
| 149 | + /** Dispatch to specialized `apply`s in user code when available */ |
| 150 | + override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo) = |
| 151 | + tree match { |
| 152 | + case app @ Apply(fun, args) |
| 153 | + if fun.symbol.name == nme.apply && |
| 154 | + fun.symbol.owner.derivesFrom(defn.FunctionClass(args.length)) |
| 155 | + => { |
| 156 | + val params = (fun.tpe.widen.firstParamTypes :+ tree.tpe).map(_.widenSingleton.dealias) |
| 157 | + val specializedApply = specializedName(nme.apply, params) |
| 158 | + |
| 159 | + if (!params.exists(_.isInstanceOf[ExprType]) && fun.symbol.owner.info.decls.lookup(specializedApply).exists) { |
| 160 | + val newSel = fun match { |
| 161 | + case Select(qual, _) => |
| 162 | + qual.select(specializedApply) |
| 163 | + case _ => { |
| 164 | + (fun.tpe: @unchecked) match { |
| 165 | + case TermRef(prefix: ThisType, name) => |
| 166 | + tpd.This(prefix.cls).select(specializedApply) |
| 167 | + case TermRef(prefix: NamedType, name) => |
| 168 | + tpd.ref(prefix).select(specializedApply) |
| 169 | + } |
| 170 | + } |
| 171 | + } |
| 172 | + |
| 173 | + newSel.appliedToArgs(args) |
| 174 | + } |
| 175 | + else tree |
| 176 | + } |
| 177 | + case _ => tree |
| 178 | + } |
| 179 | + |
| 180 | + @inline private def specializedName(name: Name, args: List[Type])(implicit ctx: Context) = |
| 181 | + name.specializedFor(args, args.map(_.typeSymbol.name), Nil, Nil) |
| 182 | + |
| 183 | + @inline private def specInterface(typeParams: List[Type])(implicit ctx: Context) = { |
| 184 | + val specName = |
| 185 | + ("JFunction" + (typeParams.length - 1)).toTermName |
| 186 | + .specializedFunction(typeParams.last, typeParams.init) |
| 187 | + |
| 188 | + ctx.getClassIfDefined("scala.compat.java8.".toTermName ++ specName) |
| 189 | + } |
| 190 | +} |
0 commit comments