summaryrefslogtreecommitdiff
path: root/examples/scala-js/compiler/src/main/scala/scala/scalajs/compiler/GenJSExports.scala
diff options
context:
space:
mode:
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.scala751
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 _)
- }
-
-}