diff options
author | Haoyi Li <haoyi@haoyi-mbp.corp.dropbox.com> | 2014-11-26 00:50:50 -0800 |
---|---|---|
committer | Haoyi Li <haoyi@haoyi-mbp.corp.dropbox.com> | 2014-11-26 00:50:50 -0800 |
commit | 88595a41e3ec13c1a516e847fe3d0b279facf3fc (patch) | |
tree | 4f03b902de7b81fa2e32792e84b680038345e761 /examples/scala-js/compiler/src/main/scala/scala/scalajs/compiler/GenJSExports.scala | |
parent | 82773a11c99d260e97ca63356bfb7b417599b1e9 (diff) | |
download | hands-on-scala-js-88595a41e3ec13c1a516e847fe3d0b279facf3fc.tar.gz hands-on-scala-js-88595a41e3ec13c1a516e847fe3d0b279facf3fc.tar.bz2 hands-on-scala-js-88595a41e3ec13c1a516e847fe3d0b279facf3fc.zip |
killed
Diffstat (limited to 'examples/scala-js/compiler/src/main/scala/scala/scalajs/compiler/GenJSExports.scala')
-rw-r--r-- | examples/scala-js/compiler/src/main/scala/scala/scalajs/compiler/GenJSExports.scala | 751 |
1 files changed, 0 insertions, 751 deletions
diff --git a/examples/scala-js/compiler/src/main/scala/scala/scalajs/compiler/GenJSExports.scala b/examples/scala-js/compiler/src/main/scala/scala/scalajs/compiler/GenJSExports.scala deleted file mode 100644 index 92dc26b..0000000 --- a/examples/scala-js/compiler/src/main/scala/scala/scalajs/compiler/GenJSExports.scala +++ /dev/null @@ -1,751 +0,0 @@ -/* Scala.js compiler - * Copyright 2013 LAMP/EPFL - * @author Sébastien Doeraene - */ - -package scala.scalajs.compiler - -import scala.collection.mutable - -import scala.tools.nsc._ -import scala.math.PartialOrdering -import scala.reflect.internal.Flags - -import scala.scalajs.ir -import ir.{Trees => js, Types => jstpe} - -import util.ScopedVar -import ScopedVar.withScopedVars - -/** Generation of exports for JavaScript - * - * @author Sébastien Doeraene - */ -trait GenJSExports extends SubComponent { self: GenJSCode => - import global._ - import jsAddons._ - import definitions._ - import jsDefinitions._ - - trait JSExportsPhase { this: JSCodePhase => - - /** - * Generate exporter methods for a class - * @param classSym symbol of class we export for - * @param decldExports symbols exporter methods that have been encountered in - * the class' tree. This is not the same as classSym.info.delcs since - * inherited concrete methods from traits should be in this param, too - */ - def genMemberExports( - classSym: Symbol, - decldExports: List[Symbol]): List[js.Tree] = { - - val newlyDecldExports = decldExports.filterNot { isOverridingExport _ } - val newlyDecldExportNames = - newlyDecldExports.map(_.name.toTermName).toList.distinct - - newlyDecldExportNames map { genMemberExport(classSym, _) } - } - - def genConstructorExports(classSym: Symbol): List[js.ConstructorExportDef] = { - val constructors = classSym.tpe.member(nme.CONSTRUCTOR).alternatives - - // Generate exports from constructors and their annotations - val ctorExports = for { - ctor <- constructors - exp <- jsInterop.exportsOf(ctor) - } yield (exp, ctor) - - val exports = for { - (jsName, specs) <- ctorExports.groupBy(_._1.jsName) // group by exported name - } yield { - val (namedExports, normalExports) = specs.partition(_._1.isNamed) - - val normalCtors = normalExports.map(s => ExportedSymbol(s._2)) - val namedCtors = for { - (exp, ctor) <- namedExports - } yield { - implicit val pos = exp.pos - ExportedBody(List(JSAnyTpe), - genNamedExporterBody(ctor, genFormalArg(1).ref), - nme.CONSTRUCTOR.toString, pos) - } - - val ctors = normalCtors ++ namedCtors - - implicit val pos = ctors.head.pos - - val js.MethodDef(_, args, _, body) = - withNewLocalNameScope(genExportMethod(ctors, jsName)) - - js.ConstructorExportDef(jsName, args, body) - } - - exports.toList - } - - def genModuleAccessorExports(classSym: Symbol): List[js.ModuleExportDef] = { - for { - exp <- jsInterop.exportsOf(classSym) - } yield { - implicit val pos = exp.pos - - if (exp.isNamed) - reporter.error(pos, "You may not use @JSNamedExport on an object") - - js.ModuleExportDef(exp.jsName) - } - } - - /** Generate the exporter proxy for a named export */ - def genNamedExporterDef(dd: DefDef): js.MethodDef = { - implicit val pos = dd.pos - - val sym = dd.symbol - - val Block(Apply(fun, _) :: Nil, _) = dd.rhs - val trgSym = fun.symbol - - val inArg = - js.ParamDef(js.Ident("namedParams"), jstpe.AnyType, mutable = false) - val inArgRef = inArg.ref - - val methodIdent = encodeMethodSym(sym) - - withScopedVars( - currentMethodInfoBuilder := - currentClassInfoBuilder.addMethod(methodIdent.name) - ) { - js.MethodDef(methodIdent, List(inArg), toIRType(sym.tpe.resultType), - genNamedExporterBody(trgSym, inArg.ref))(None) - } - } - - private def genNamedExporterBody(trgSym: Symbol, inArg: js.Tree)( - implicit pos: Position) = { - - if (hasRepeatedParam(trgSym)) { - reporter.error(pos, - "You may not name-export a method with a *-parameter") - } - - val jsArgs = for { - (pSym, index) <- trgSym.info.params.zipWithIndex - } yield { - val rhs = js.JSBracketSelect(inArg, - js.StringLiteral(pSym.name.decoded)) - js.VarDef(js.Ident("namedArg$" + index), jstpe.AnyType, - mutable = false, rhs = rhs) - } - - val jsArgRefs = jsArgs.map(_.ref) - - // Generate JS code to prepare arguments (default getters and unboxes) - val jsArgPrep = genPrepareArgs(jsArgRefs, trgSym) - val jsResult = genResult(trgSym, jsArgPrep.map(_.ref)) - - js.Block(jsArgs ++ jsArgPrep :+ jsResult) - } - - private def genMemberExport(classSym: Symbol, name: TermName): js.Tree = { - val alts = classSym.info.member(name).alternatives - - assert(!alts.isEmpty, - s"Ended up with no alternatives for ${classSym.fullName}::$name. " + - s"Original set was ${alts} with types ${alts.map(_.tpe)}") - - val (jsName, isProp) = jsInterop.jsExportInfo(name) - - // Check if we have a conflicting export of the other kind - val conflicting = - classSym.info.member(jsInterop.scalaExportName(jsName, !isProp)) - - if (conflicting != NoSymbol) { - val kind = if (isProp) "property" else "method" - val alts = conflicting.alternatives - - reporter.error(alts.head.pos, - s"Exported $kind $jsName conflicts with ${alts.head.fullName}") - } - - withNewLocalNameScope { - if (isProp) - genExportProperty(alts, jsName) - else - genExportMethod(alts.map(ExportedSymbol), jsName) - } - } - - private def genExportProperty(alts: List[Symbol], jsName: String) = { - assert(!alts.isEmpty) - implicit val pos = alts.head.pos - - // Separate getters and setters. Somehow isJSGetter doesn't work here. Hence - // we just check the parameter list length. - val (getter, setters) = alts.partition(_.tpe.params.isEmpty) - - // if we have more than one getter, something went horribly wrong - assert(getter.size <= 1, - s"Found more than one getter to export for name ${jsName}.") - - val getTree = - if (getter.isEmpty) js.EmptyTree - else genApplyForSym(getter.head) - - val setTree = - if (setters.isEmpty) js.EmptyTree - else genExportSameArgc(setters.map(ExportedSymbol), 0) // we only have 1 argument - - js.PropertyDef(js.StringLiteral(jsName), getTree, genFormalArg(1), setTree) - } - - /** generates the exporter function (i.e. exporter for non-properties) for - * a given name */ - private def genExportMethod(alts0: List[Exported], jsName: String) = { - assert(alts0.nonEmpty, - "need at least one alternative to generate exporter method") - - implicit val pos = alts0.head.pos - - val alts = { - // toString() is always exported. We might need to add it here - // to get correct overloading. - if (jsName == "toString" && alts0.forall(_.params.nonEmpty)) - ExportedSymbol(Object_toString) :: alts0 - else - alts0 - } - - // Factor out methods with variable argument lists. Note that they can - // only be at the end of the lists as enforced by PrepJSExports - val (varArgMeths, normalMeths) = alts.partition(_.hasRepeatedParam) - - // Highest non-repeated argument count - val maxArgc = ( - // We have argc - 1, since a repeated parameter list may also be empty - // (unlike a normal parameter) - varArgMeths.map(_.params.size - 1) ++ - normalMeths.map(_.params.size) - ).max - - val formalArgs = genFormalArgs(maxArgc) - - // Calculates possible arg counts for normal method - def argCounts(ex: Exported) = ex match { - case ExportedSymbol(sym) => - val params = sym.tpe.params - // Find default param - val dParam = params.indexWhere { _.hasFlag(Flags.DEFAULTPARAM) } - if (dParam == -1) Seq(params.size) - else dParam to params.size - case ex: ExportedBody => - List(ex.params.size) - } - - // Generate tuples (argc, method) - val methodArgCounts = { - // Normal methods - for { - method <- normalMeths - argc <- argCounts(method) - } yield (argc, method) - } ++ { - // Repeated parameter methods - for { - method <- varArgMeths - argc <- method.params.size - 1 to maxArgc - } yield (argc, method) - } - - // Create a map: argCount -> methods (methods may appear multiple times) - val methodByArgCount = - methodArgCounts.groupBy(_._1).mapValues(_.map(_._2).toSet) - - // Create tuples: (methods, argCounts). This will be the cases we generate - val caseDefinitions = - methodByArgCount.groupBy(_._2).mapValues(_.keySet) - - // Verify stuff about caseDefinitions - assert({ - val argcs = caseDefinitions.values.flatten.toList - argcs == argcs.distinct && - argcs.forall(_ <= maxArgc) - }, "every argc should appear only once and be lower than max") - - // Generate a case block for each (methods, argCounts) tuple - val cases = for { - (methods, argcs) <- caseDefinitions - if methods.nonEmpty && argcs.nonEmpty - - // exclude default case we're generating anyways for varargs - if methods != varArgMeths.toSet - - // body of case to disambiguates methods with current count - caseBody = - genExportSameArgc(methods.toList, 0, Some(argcs.min)) - - // argc in reverse order - argcList = argcs.toList.sortBy(- _) - } yield (argcList.map(js.IntLiteral(_)), caseBody) - - val hasVarArg = varArgMeths.nonEmpty - - def defaultCase = { - if (!hasVarArg) - genThrowTypeError() - else - genExportSameArgc(varArgMeths, 0) - } - - val body = { - if (cases.isEmpty) - defaultCase - else if (cases.size == 1 && !hasVarArg) - cases.head._2 - else { - js.Match( - js.Unbox(js.JSBracketSelect( - js.VarRef(js.Ident("arguments"), false)(jstpe.AnyType), - js.StringLiteral("length")), - 'I'), - cases.toList, defaultCase)(jstpe.AnyType) - } - } - - js.MethodDef(js.StringLiteral(jsName), formalArgs, jstpe.AnyType, body)(None) - } - - /** - * Resolve method calls to [[alts]] while assuming they have the same - * parameter count. - * @param alts Alternative methods - * @param paramIndex Index where to start disambiguation - * @param maxArgc only use that many arguments - */ - private def genExportSameArgc(alts: List[Exported], - paramIndex: Int, maxArgc: Option[Int] = None): js.Tree = { - - implicit val pos = alts.head.pos - - if (alts.size == 1) - alts.head.body - else if (maxArgc.exists(_ <= paramIndex) || - !alts.exists(_.params.size > paramIndex)) { - // We reach here in three cases: - // 1. The parameter list has been exhausted - // 2. The optional argument count restriction has triggered - // 3. We only have (more than once) repeated parameters left - // Therefore, we should fail - reporter.error(pos, - s"""Cannot disambiguate overloads for exported method ${alts.head.name} with types - | ${alts.map(_.typeInfo).mkString("\n ")}""".stripMargin) - js.Undefined() - } else { - - val altsByTypeTest = groupByWithoutHashCode(alts) { - case ExportedSymbol(alt) => - // get parameter type while resolving repeated params - val tpe = enteringPhase(currentRun.uncurryPhase) { - val ps = alt.paramss.flatten - if (ps.size <= paramIndex || isRepeated(ps(paramIndex))) { - assert(isRepeated(ps.last)) - repeatedToSingle(ps.last.tpe) - } else { - enteringPhase(currentRun.posterasurePhase) { - ps(paramIndex).tpe - } - } - } - - typeTestForTpe(tpe) - - case ex: ExportedBody => - typeTestForTpe(ex.params(paramIndex)) - } - - if (altsByTypeTest.size == 1) { - // Testing this parameter is not doing any us good - genExportSameArgc(alts, paramIndex+1, maxArgc) - } else { - // Sort them so that, e.g., isInstanceOf[String] - // comes before isInstanceOf[Object] - val sortedAltsByTypeTest = topoSortDistinctsBy( - altsByTypeTest)(_._1)(RTTypeTest.Ordering) - - val defaultCase = genThrowTypeError() - - sortedAltsByTypeTest.foldRight[js.Tree](defaultCase) { (elem, elsep) => - val (typeTest, subAlts) = elem - implicit val pos = subAlts.head.pos - - val param = genFormalArg(paramIndex+1) - val genSubAlts = genExportSameArgc(subAlts, paramIndex+1, maxArgc) - - def hasDefaultParam = subAlts.exists { - case ExportedSymbol(p) => - val params = p.tpe.params - params.size > paramIndex && - params(paramIndex).hasFlag(Flags.DEFAULTPARAM) - case _: ExportedBody => false - } - - val optCond = typeTest match { - case HijackedTypeTest(boxedClassName, _) => - Some(js.IsInstanceOf(param.ref, jstpe.ClassType(boxedClassName))) - - case InstanceOfTypeTest(tpe) => - Some(genIsInstanceOf(param.ref, tpe)) - - case NoTypeTest => - None - } - - optCond.fold[js.Tree] { - genSubAlts // note: elsep is discarded, obviously - } { cond => - val condOrUndef = if (!hasDefaultParam) cond else { - js.If(cond, js.BooleanLiteral(true), - js.BinaryOp(js.BinaryOp.===, param.ref, js.Undefined()))( - jstpe.BooleanType) - } - js.If(condOrUndef, genSubAlts, elsep)(jstpe.AnyType) - } - } - } - } - } - - /** - * Generate a call to the method [[sym]] while using the formalArguments - * and potentially the argument array. Also inserts default parameters if - * required. - */ - private def genApplyForSym(sym: Symbol): js.Tree = { - implicit val pos = sym.pos - - // the (single) type of the repeated parameter if any - val repeatedTpe = enteringPhase(currentRun.uncurryPhase) { - for { - param <- sym.paramss.flatten.lastOption - if isRepeated(param) - } yield repeatedToSingle(param.tpe) - } - - val normalArgc = sym.tpe.params.size - - (if (repeatedTpe.isDefined) 1 else 0) - - // optional repeated parameter list - val jsVarArg = repeatedTpe map { tpe => - // Copy arguments that go to vararg into an array, put it in a wrapper - - val countIdent = freshLocalIdent("count") - val count = js.VarRef(countIdent, mutable = false)(jstpe.IntType) - - val counterIdent = freshLocalIdent("i") - val counter = js.VarRef(counterIdent, mutable = true)(jstpe.IntType) - - val arrayIdent = freshLocalIdent("varargs") - val array = js.VarRef(arrayIdent, mutable = false)(jstpe.AnyType) - - val arguments = js.VarRef(js.Ident("arguments"), - mutable = false)(jstpe.AnyType) - val argLen = js.Unbox( - js.JSBracketSelect(arguments, js.StringLiteral("length")), 'I') - val argOffset = js.IntLiteral(normalArgc) - - val jsArrayCtor = - js.JSBracketSelect( - js.JSBracketSelect(js.JSEnvInfo(), js.StringLiteral("global")), - js.StringLiteral("Array")) - - js.Block( - // var i = 0 - js.VarDef(counterIdent, jstpe.IntType, mutable = true, - rhs = js.IntLiteral(0)), - // val count = arguments.length - <normalArgc> - js.VarDef(countIdent, jstpe.IntType, mutable = false, - rhs = js.BinaryOp(js.BinaryOp.Int_-, argLen, argOffset)), - // val varargs = new Array(count) - js.VarDef(arrayIdent, jstpe.AnyType, mutable = false, - rhs = js.JSNew(jsArrayCtor, List(count))), - // while (i < count) - js.While(js.BinaryOp(js.BinaryOp.Num_<, counter, count), js.Block( - // varargs[i] = arguments[<normalArgc> + i]; - js.Assign( - js.JSBracketSelect(array, counter), - js.JSBracketSelect(arguments, - js.BinaryOp(js.BinaryOp.Int_+, argOffset, counter))), - // i = i + 1 (++i won't work, desugar eliminates it) - js.Assign(counter, js.BinaryOp(js.BinaryOp.Int_+, - counter, js.IntLiteral(1))) - )), - // new WrappedArray(varargs) - genNew(WrappedArrayClass, WrappedArray_ctor, List(array)) - ) - } - - // normal arguments - val jsArgs = genFormalArgs(normalArgc) - val jsArgRefs = jsArgs.map(_.ref) - - // Generate JS code to prepare arguments (default getters and unboxes) - val jsArgPrep = genPrepareArgs(jsArgRefs, sym) - val jsResult = genResult(sym, jsArgPrep.map(_.ref) ++ jsVarArg) - - js.Block(jsArgPrep :+ jsResult) - } - - /** Generate the necessary JavaScript code to prepare the arguments of an - * exported method (unboxing and default parameter handling) - */ - private def genPrepareArgs(jsArgs: List[js.VarRef], sym: Symbol)( - implicit pos: Position): List[js.VarDef] = { - - val result = new mutable.ListBuffer[js.VarDef] - - val funTpe = enteringPhase(currentRun.posterasurePhase)(sym.tpe) - for { - (jsArg, (param, i)) <- jsArgs zip funTpe.params.zipWithIndex - } yield { - // Code to verify the type of the argument (if it is defined) - val verifiedArg = { - val tpePosterasure = - enteringPhase(currentRun.posterasurePhase)(param.tpe) - tpePosterasure match { - case tpe if isPrimitiveValueType(tpe) => - val unboxed = makePrimitiveUnbox(jsArg, tpe) - // Ensure we don't convert null to a primitive value type - js.If(js.BinaryOp(js.BinaryOp.===, jsArg, js.Null()), - genThrowTypeError(s"Found null, expected $tpe"), - unboxed)(unboxed.tpe) - case tpe: ErasedValueType => - val boxedClass = tpe.valueClazz - val unboxMethod = boxedClass.derivedValueClassUnbox - genApplyMethod( - genAsInstanceOf(jsArg, tpe), - boxedClass, unboxMethod, Nil) - case tpe => - genAsInstanceOf(jsArg, tpe) - } - } - - // If argument is undefined and there is a default getter, call it - val verifiedOrDefault = if (param.hasFlag(Flags.DEFAULTPARAM)) { - js.If(js.BinaryOp(js.BinaryOp.===, jsArg, js.Undefined()), { - val trgSym = { - if (sym.isClassConstructor) sym.owner.companionModule.moduleClass - else sym.owner - } - val defaultGetter = trgSym.tpe.member( - nme.defaultGetterName(sym.name, i+1)) - - assert(defaultGetter.exists, - s"need default getter for method ${sym.fullName}") - assert(!defaultGetter.isOverloaded) - - val trgTree = { - if (sym.isClassConstructor) genLoadModule(trgSym) - else js.This()(encodeClassType(trgSym)) - } - - // Pass previous arguments to defaultGetter - genApplyMethod(trgTree, trgSym, defaultGetter, - result.take(defaultGetter.tpe.params.size).toList.map(_.ref)) - }, { - // Otherwise, unbox the argument - verifiedArg - })(verifiedArg.tpe) - } else { - // Otherwise, it is always the unboxed argument - verifiedArg - } - - result += - js.VarDef(js.Ident("prep"+jsArg.ident.name, jsArg.ident.originalName), - verifiedOrDefault.tpe, mutable = false, verifiedOrDefault) - } - - result.toList - } - - /** Generate the final forwarding call to the exported method. - * Attention: This method casts the arguments to the right type. The IR - * checker will not detect if you pass in a wrongly typed argument. - */ - private def genResult(sym: Symbol, - args: List[js.Tree])(implicit pos: Position) = { - val thisType = - if (sym.owner == ObjectClass) jstpe.ClassType(ir.Definitions.ObjectClass) - else encodeClassType(sym.owner) - val call = genApplyMethod(js.This()(thisType), sym.owner, sym, args) - ensureBoxed(call, - enteringPhase(currentRun.posterasurePhase)(sym.tpe.resultType)) - } - - private sealed abstract class Exported { - def pos: Position - def params: List[Type] - def body: js.Tree - def name: String - def typeInfo: String - def hasRepeatedParam: Boolean - } - - private case class ExportedSymbol(sym: Symbol) extends Exported { - def pos: Position = sym.pos - def params: List[Type] = sym.tpe.params.map(_.tpe) - def body: js.Tree = genApplyForSym(sym) - def name: String = sym.name.toString - def typeInfo: String = sym.tpe.toString - def hasRepeatedParam: Boolean = GenJSExports.this.hasRepeatedParam(sym) - } - - private case class ExportedBody(params: List[Type], body: js.Tree, - name: String, pos: Position) extends Exported { - def typeInfo: String = params.mkString("(", ", ", ")") - val hasRepeatedParam: Boolean = false - } - } - - private def isOverridingExport(sym: Symbol): Boolean = { - lazy val osym = sym.nextOverriddenSymbol - sym.isOverridingSymbol && !osym.owner.isInterface - } - - private sealed abstract class RTTypeTest - - private final case class HijackedTypeTest( - boxedClassName: String, rank: Int) extends RTTypeTest - - private final case class InstanceOfTypeTest(tpe: Type) extends RTTypeTest { - override def equals(that: Any): Boolean = { - that match { - case InstanceOfTypeTest(thatTpe) => tpe =:= thatTpe - case _ => false - } - } - } - - private case object NoTypeTest extends RTTypeTest - - private object RTTypeTest { - implicit object Ordering extends PartialOrdering[RTTypeTest] { - override def tryCompare(lhs: RTTypeTest, rhs: RTTypeTest): Option[Int] = { - if (lteq(lhs, rhs)) if (lteq(rhs, lhs)) Some(0) else Some(-1) - else if (lteq(rhs, lhs)) Some(1) else None - } - - override def lteq(lhs: RTTypeTest, rhs: RTTypeTest): Boolean = { - (lhs, rhs) match { - // NoTypeTest is always last - case (_, NoTypeTest) => true - case (NoTypeTest, _) => false - - case (HijackedTypeTest(_, rank1), HijackedTypeTest(_, rank2)) => - rank1 <= rank2 - - case (InstanceOfTypeTest(t1), InstanceOfTypeTest(t2)) => - t1 <:< t2 - - case (_:HijackedTypeTest, _:InstanceOfTypeTest) => true - case (_:InstanceOfTypeTest, _:HijackedTypeTest) => false - } - } - - override def equiv(lhs: RTTypeTest, rhs: RTTypeTest): Boolean = { - lhs == rhs - } - } - } - - // Very simple O(n²) topological sort for elements assumed to be distinct - private def topoSortDistinctsBy[A <: AnyRef, B](coll: List[A])(f: A => B)( - implicit ord: PartialOrdering[B]): List[A] = { - - @scala.annotation.tailrec - def loop(coll: List[A], acc: List[A]): List[A] = { - if (coll.isEmpty) acc - else if (coll.tail.isEmpty) coll.head :: acc - else { - val (lhs, rhs) = coll.span(x => !coll.forall( - y => (x eq y) || !ord.lteq(f(x), f(y)))) - assert(!rhs.isEmpty, s"cycle while ordering $coll") - loop(lhs ::: rhs.tail, rhs.head :: acc) - } - } - - loop(coll, Nil) - } - - private def typeTestForTpe(tpe: Type): RTTypeTest = { - tpe match { - case tpe: ErasedValueType => - InstanceOfTypeTest(tpe.valueClazz.typeConstructor) - - case _ => - import ir.{Definitions => Defs} - (toTypeKind(tpe): @unchecked) match { - case VoidKind => HijackedTypeTest(Defs.BoxedUnitClass, 0) - case BooleanKind => HijackedTypeTest(Defs.BoxedBooleanClass, 1) - case ByteKind => HijackedTypeTest(Defs.BoxedByteClass, 2) - case ShortKind => HijackedTypeTest(Defs.BoxedShortClass, 3) - case IntKind => HijackedTypeTest(Defs.BoxedIntegerClass, 4) - case FloatKind => HijackedTypeTest(Defs.BoxedFloatClass, 5) - case DoubleKind => HijackedTypeTest(Defs.BoxedDoubleClass, 6) - - case CharKind => InstanceOfTypeTest(boxedClass(CharClass).tpe) - case LongKind => InstanceOfTypeTest(boxedClass(LongClass).tpe) - - case REFERENCE(cls) => - if (cls == StringClass) HijackedTypeTest(Defs.StringClass, 7) - else if (cls == ObjectClass) NoTypeTest - else if (isRawJSType(tpe)) { - cls match { - case JSUndefinedClass => HijackedTypeTest(Defs.BoxedUnitClass, 0) - case JSBooleanClass => HijackedTypeTest(Defs.BoxedBooleanClass, 1) - case JSNumberClass => HijackedTypeTest(Defs.BoxedDoubleClass, 6) - case JSStringClass => HijackedTypeTest(Defs.StringClass, 7) - case _ => NoTypeTest - } - } else InstanceOfTypeTest(tpe) - - case ARRAY(_) => InstanceOfTypeTest(tpe) - } - } - } - - // Group-by that does not rely on hashCode(), only equals() - O(n²) - private def groupByWithoutHashCode[A, B]( - coll: List[A])(f: A => B): List[(B, List[A])] = { - - import scala.collection.mutable.ArrayBuffer - val m = new ArrayBuffer[(B, List[A])] - m.sizeHint(coll.length) - - for (elem <- coll) { - val key = f(elem) - val index = m.indexWhere(_._1 == key) - if (index < 0) m += ((key, List(elem))) - else m(index) = (key, elem :: m(index)._2) - } - - m.toList - } - - private def genThrowTypeError(msg: String = "No matching overload")( - implicit pos: Position): js.Tree = { - js.Throw(js.StringLiteral(msg)) - } - - private def genFormalArgs(count: Int)(implicit pos: Position): List[js.ParamDef] = - (1 to count map genFormalArg).toList - - private def genFormalArg(index: Int)(implicit pos: Position): js.ParamDef = - js.ParamDef(js.Ident("arg$" + index), jstpe.AnyType, mutable = false) - - private def hasRepeatedParam(sym: Symbol) = - enteringPhase(currentRun.uncurryPhase) { - sym.paramss.flatten.lastOption.exists(isRepeated _) - } - -} |