aboutsummaryrefslogtreecommitdiff
path: root/src/dotty
diff options
context:
space:
mode:
Diffstat (limited to 'src/dotty')
-rw-r--r--src/dotty/tools/dotc/TypeErasure.scala3
-rw-r--r--src/dotty/tools/dotc/ast/Desugar.scala7
-rw-r--r--src/dotty/tools/dotc/ast/tpd.scala49
-rw-r--r--src/dotty/tools/dotc/config/ScalaSettings.scala1
-rw-r--r--src/dotty/tools/dotc/core/Annotations.scala15
-rw-r--r--src/dotty/tools/dotc/core/Flags.scala11
-rw-r--r--src/dotty/tools/dotc/core/TypeApplications.scala5
-rw-r--r--src/dotty/tools/dotc/core/Types.scala17
-rw-r--r--src/dotty/tools/dotc/core/pickling/ClassfileParser.scala44
-rw-r--r--src/dotty/tools/dotc/core/pickling/PickleBuffer.scala3
-rw-r--r--src/dotty/tools/dotc/core/pickling/UnPickler.scala32
-rw-r--r--src/dotty/tools/dotc/parsing/JavaParsers.scala892
-rw-r--r--src/dotty/tools/dotc/parsing/JavaScanners.scala537
-rw-r--r--src/dotty/tools/dotc/parsing/JavaTokens.scala92
-rw-r--r--src/dotty/tools/dotc/parsing/Parsers.scala90
-rw-r--r--src/dotty/tools/dotc/parsing/Scanners.scala233
-rw-r--r--src/dotty/tools/dotc/parsing/Tokens.scala143
-rw-r--r--src/dotty/tools/dotc/transform/ElimRepeated.scala20
-rw-r--r--src/dotty/tools/dotc/transform/FirstTransform.scala21
-rw-r--r--src/dotty/tools/dotc/transform/GettersSetters.scala2
-rw-r--r--src/dotty/tools/dotc/transform/Memoize.scala2
-rw-r--r--src/dotty/tools/dotc/transform/TreeChecker.scala38
-rw-r--r--src/dotty/tools/dotc/transform/TreeTransform.scala24
-rw-r--r--src/dotty/tools/dotc/typer/Applications.scala21
-rw-r--r--src/dotty/tools/dotc/typer/Checking.scala4
-rw-r--r--src/dotty/tools/dotc/typer/FrontEnd.scala5
-rw-r--r--src/dotty/tools/dotc/typer/Namer.scala5
-rw-r--r--src/dotty/tools/dotc/typer/ProtoTypes.scala12
-rw-r--r--src/dotty/tools/dotc/typer/TypeAssigner.scala13
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala41
30 files changed, 2116 insertions, 266 deletions
diff --git a/src/dotty/tools/dotc/TypeErasure.scala b/src/dotty/tools/dotc/TypeErasure.scala
index 4a492560f..1786e2e29 100644
--- a/src/dotty/tools/dotc/TypeErasure.scala
+++ b/src/dotty/tools/dotc/TypeErasure.scala
@@ -95,8 +95,9 @@ object TypeErasure {
def erasure(tp: Type)(implicit ctx: Context): Type = scalaErasureFn(tp)(erasureCtx)
def semiErasure(tp: Type)(implicit ctx: Context): Type = semiErasureFn(tp)(erasureCtx)
def sigName(tp: Type, isJava: Boolean)(implicit ctx: Context): TypeName = {
+ val seqClass = if(isJava) defn.ArrayClass else defn.SeqClass
val normTp =
- if (tp.isRepeatedParam) tp.translateParameterized(defn.RepeatedParamClass, defn.SeqClass)
+ if (tp.isRepeatedParam) tp.translateParameterized(defn.RepeatedParamClass, seqClass)
else tp
(if (isJava) javaSigFn else scalaSigFn).sigName(normTp)(erasureCtx)
}
diff --git a/src/dotty/tools/dotc/ast/Desugar.scala b/src/dotty/tools/dotc/ast/Desugar.scala
index b7786e00c..1aab16469 100644
--- a/src/dotty/tools/dotc/ast/Desugar.scala
+++ b/src/dotty/tools/dotc/ast/Desugar.scala
@@ -771,11 +771,12 @@ object desugar {
else // l.op(r), or val x = r; l.op(x), plus handle named args specially
makeBinop(l, op, r)
case PostfixOp(t, op) =>
- if ((ctx.mode is Mode.Type) && op == nme.raw.STAR)
+ if ((ctx.mode is Mode.Type) && op == nme.raw.STAR) {
+ val seqClass = if (ctx.compilationUnit.isJava) defn.ArrayClass else defn.SeqClass
Annotated(
New(ref(defn.RepeatedAnnot.typeRef), Nil :: Nil),
- AppliedTypeTree(ref(defn.SeqClass.typeRef), t))
- else {
+ AppliedTypeTree(ref(seqClass.typeRef), t))
+ } else {
assert(ctx.mode.isExpr, ctx.mode)
Select(t, op)
}
diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala
index 12d4ac5e4..98609f9f1 100644
--- a/src/dotty/tools/dotc/ast/tpd.scala
+++ b/src/dotty/tools/dotc/ast/tpd.scala
@@ -2,6 +2,7 @@ package dotty.tools
package dotc
package ast
+import dotty.tools.dotc.typer.ProtoTypes.FunProtoTyped
import transform.SymUtils._
import core._
import util.Positions._, Types._, Contexts._, Constants._, Names._, Flags._
@@ -126,8 +127,8 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
if (tpe derivesFrom defn.SeqClass) SeqLiteral(elems) else JavaSeqLiteral(elems)
def JavaSeqLiteral(elems: List[Tree])(implicit ctx: Context): SeqLiteral =
- new untpd.JavaSeqLiteral(elems)
- .withType(defn.ArrayClass.typeRef.appliedTo(ctx.typeComparer.lub(elems.tpes)))
+ ta.assignType(new untpd.JavaSeqLiteral(elems), elems)
+
def TypeTree(original: Tree)(implicit ctx: Context): TypeTree =
TypeTree(original.tpe, original)
@@ -677,6 +678,50 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
Throw(New(defn.ClassCastExceptionClass.typeRef, Nil)) withPos tree.pos
}
}
+
+ def applyOverloaded(receiver: Tree, method: TermName, args: List[Tree], targs: List[Type], expectedType: Type, isAnnotConstructor: Boolean = false)(implicit ctx: Context): Tree = {
+ val typer = ctx.typer
+ val proto = new FunProtoTyped(args, expectedType, typer)
+ val alts = receiver.tpe.member(method).alternatives.map(_.termRef)
+
+ val alternatives = ctx.typer.resolveOverloaded(alts, proto, Nil)
+ assert(alternatives.size == 1) // this is parsed from bytecode tree. there's nothing user can do about it
+
+ val selected = alternatives.head
+ val fun = receiver
+ .select(TermRef.withSig(receiver.tpe.normalizedPrefix, selected.termSymbol.asTerm))
+ .appliedToTypes(targs)
+
+ def adaptLastArg(lastParam: Tree, expectedType: Type) = {
+ if (isAnnotConstructor && !(lastParam.tpe <:< expectedType)) {
+ val defn = ctx.definitions
+ val prefix = args.take(selected.widen.paramTypess.head.size - 1)
+ expectedType match {
+ case defn.ArrayType(el) =>
+ lastParam.tpe match {
+ case defn.ArrayType(el2) if (el2 <:< el) =>
+ // we have a JavaSeqLiteral with a more precise type
+ // we cannot construct a tree as JavaSeqLiteral infered to precise type
+ // if we add typed than it would be both type-correct and
+ // will pass Ycheck
+ prefix ::: List(tpd.Typed(lastParam, TypeTree(defn.ArrayType(el))))
+ case _ =>
+ ???
+ }
+ case _ => args
+ }
+ } else args
+ }
+
+ val callArgs: List[Tree] = if(args.isEmpty) Nil else {
+ val expectedType = selected.widen.paramTypess.head.last
+ val lastParam = args.last
+ adaptLastArg(lastParam, expectedType)
+ }
+
+ val apply = untpd.Apply(fun, callArgs)
+ new typer.ApplyToTyped(apply, fun, selected, callArgs, expectedType).result.asInstanceOf[Tree] // needed to handle varargs
+ }
@tailrec
def sameTypes(trees: List[tpd.Tree], trees1: List[tpd.Tree]): Boolean = {
diff --git a/src/dotty/tools/dotc/config/ScalaSettings.scala b/src/dotty/tools/dotc/config/ScalaSettings.scala
index abde6cb53..05b936136 100644
--- a/src/dotty/tools/dotc/config/ScalaSettings.scala
+++ b/src/dotty/tools/dotc/config/ScalaSettings.scala
@@ -99,6 +99,7 @@ class ScalaSettings extends Settings.SettingGroup {
val Yhelp = BooleanSetting("-Y", "Print a synopsis of private options.")
val browse = PhasesSetting("-Ybrowse", "Browse the abstract syntax tree after")
val Ycheck = PhasesSetting("-Ycheck", "Check the tree at the end of")
+ val YcheckMods = BooleanSetting("-Ycheck-mods", "Check that symbols and their defining trees have modifiers in sync")
val YcheckTypedTrees = BooleanSetting("-YcheckTypedTrees", "Check all constructured typed trees for type correctness")
val Yshow = PhasesSetting("-Yshow", "(Requires -Xshow-class or -Xshow-object) Show after")
val Xcloselim = BooleanSetting("-Yclosure-elim", "Perform closure elimination.")
diff --git a/src/dotty/tools/dotc/core/Annotations.scala b/src/dotty/tools/dotc/core/Annotations.scala
index 92b28a193..79aa058ef 100644
--- a/src/dotty/tools/dotc/core/Annotations.scala
+++ b/src/dotty/tools/dotc/core/Annotations.scala
@@ -3,6 +3,9 @@ package core
import Symbols._, Types._, util.Positions._, Contexts._, Constants._, ast.tpd._
import config.ScalaVersion
+import StdNames._
+import dotty.tools.dotc.ast.{tpd, untpd}
+import dotty.tools.dotc.typer.ProtoTypes.FunProtoTyped
object Annotations {
@@ -61,12 +64,24 @@ object Annotations {
def apply(atp: Type, args: List[Tree])(implicit ctx: Context): Annotation =
apply(New(atp, args))
+ private def resolveConstructor(atp: Type, args:List[Tree])(implicit ctx: Context): Tree = {
+ val targs = atp.argTypes
+ tpd.applyOverloaded(New(atp withoutArgs targs), nme.CONSTRUCTOR, args, targs, atp, isAnnotConstructor = true)
+ }
+
+ def applyResolve(atp: Type, args: List[Tree])(implicit ctx: Context): Annotation = {
+ apply(resolveConstructor(atp, args))
+ }
+
def deferred(sym: Symbol, treeFn: Context => Tree)(implicit ctx: Context): Annotation =
new LazyAnnotation(sym)(treeFn)
def deferred(atp: Type, args: List[Tree])(implicit ctx: Context): Annotation =
deferred(atp.classSymbol, implicit ctx => New(atp, args))
+ def deferredResolve(atp: Type, args: List[Tree])(implicit ctx: Context): Annotation =
+ deferred(atp.classSymbol, implicit ctx => resolveConstructor(atp, args))
+
def makeAlias(sym: TermSymbol)(implicit ctx: Context) =
apply(defn.AliasAnnot, List(
ref(TermRef.withSigAndDenot(sym.owner.thisType, sym.name, sym.signature, sym))))
diff --git a/src/dotty/tools/dotc/core/Flags.scala b/src/dotty/tools/dotc/core/Flags.scala
index db969767b..0e86a2936 100644
--- a/src/dotty/tools/dotc/core/Flags.scala
+++ b/src/dotty/tools/dotc/core/Flags.scala
@@ -318,7 +318,7 @@ object Flags {
/** An unpickled Scala 2.x class */
final val Scala2x = typeFlag(26, "<scala-2.x>")
- /** A method that has default params */ // TODO: drop
+ /** A method that has default params */
final val DefaultParameterized = termFlag(27, "<defaultparam>")
/** Symbol is initialized to the default value, e.g. var x: T = _ */
@@ -356,6 +356,12 @@ object Flags {
/** Symbol is a Java-style varargs method */
final val JavaVarargs = termFlag(37, "<varargs>")
+ /** Symbol is a Java default method */
+ final val DefaultMethod = termFlag(38, "<defaultmethod>")
+
+ /** Symbol is a Java enum */
+ final val Enum = commonFlag(40, "<enum>")
+
// Flags following this one are not pickled
/** Symbol always defines a fresh named type */
@@ -547,6 +553,9 @@ object Flags {
/** A Java interface, potentially with default methods */
final val JavaTrait = allOf(JavaDefined, Trait, NoInits)
+
+ /** A Java interface */
+ final val JavaInterface = allOf(JavaDefined, Trait)
/** A Java companion object */
final val JavaModule = allOf(JavaDefined, Module)
diff --git a/src/dotty/tools/dotc/core/TypeApplications.scala b/src/dotty/tools/dotc/core/TypeApplications.scala
index bf756facf..3beb680d9 100644
--- a/src/dotty/tools/dotc/core/TypeApplications.scala
+++ b/src/dotty/tools/dotc/core/TypeApplications.scala
@@ -284,7 +284,10 @@ class TypeApplications(val self: Type) extends AnyVal {
* or, if isJava is true, Array type, else the type itself.
*/
def underlyingIfRepeated(isJava: Boolean)(implicit ctx: Context): Type =
- if (self.isRepeatedParam) translateParameterized(defn.RepeatedParamClass, defn.SeqClass)
+ if (self.isRepeatedParam) {
+ val seqClass = if(isJava) defn.ArrayClass else defn.SeqClass
+ translateParameterized(defn.RepeatedParamClass, seqClass)
+ }
else self
/** If this is an encoding of a (partially) applied type, return its arguments,
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index aa8036fc5..2997e9e77 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -35,6 +35,8 @@ object Types {
private var recCount = 0 // used temporarily for debugging. TODO: remove
+ private var nextId = 0
+
/** The class of types.
* The principal subclasses and sub-objects are as follows:
*
@@ -70,6 +72,13 @@ object Types {
// ----- Tests -----------------------------------------------------
+ val uniqId = {
+ nextId = nextId + 1
+// if(nextId == 19555)
+// println("foo")
+ nextId
+ }
+
/** Is this type different from NoType? */
def exists: Boolean = true
@@ -1965,7 +1974,9 @@ object Types {
def fromSymbols(params: List[Symbol], resultType: Type)(implicit ctx: Context) = {
def paramInfo(param: Symbol): Type = param.info match {
case AnnotatedType(annot, tp) if annot matches defn.RepeatedAnnot =>
- tp.translateParameterized(defn.SeqClass, defn.RepeatedParamClass)
+ val typeSym = param.info.typeSymbol.asClass
+ assert(typeSym == defn.SeqClass || typeSym == defn.ArrayClass)
+ tp.translateParameterized(typeSym, defn.RepeatedParamClass)
case tp =>
tp
}
@@ -2024,9 +2035,9 @@ object Types {
def derivedPolyType(paramNames: List[TypeName], paramBounds: List[TypeBounds], restpe: Type)(implicit ctx: Context) =
if ((paramNames eq this.paramNames) && (paramBounds eq this.paramBounds) && (restpe eq this.resultType)) this
- else copy(paramNames, paramBounds, restpe)
+ else duplicate(paramNames, paramBounds, restpe)
- def copy(paramNames: List[TypeName], paramBounds: List[TypeBounds], restpe: Type)(implicit ctx: Context) =
+ def duplicate(paramNames: List[TypeName] = this.paramNames, paramBounds: List[TypeBounds] = this.paramBounds, restpe: Type)(implicit ctx: Context) =
PolyType(paramNames)(
x => paramBounds mapConserve (_.subst(this, x).bounds),
x => restpe.subst(this, x))
diff --git a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala
index 8dd9314ee..f92573d22 100644
--- a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala
+++ b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala
@@ -128,6 +128,7 @@ class ClassfileParser(
for (i <- 0 until in.nextChar) parseMember(method = false)
for (i <- 0 until in.nextChar) parseMember(method = true)
classInfo = parseAttributes(classRoot.symbol, classInfo)
+ if (isAnnotation) addAnnotationConstructor(classInfo)
setClassInfo(classRoot, classInfo)
setClassInfo(moduleRoot, staticInfo)
}
@@ -421,7 +422,7 @@ class ClassfileParser(
case None => hasError = true
}
if (hasError) None
- else if (skip) None else Some(SeqLiteral(arr.toList))
+ else if (skip) None else Some(JavaSeqLiteral(arr.toList))
case ANNOTATION_TAG =>
parseAnnotation(index, skip) map (_.tree)
}
@@ -443,7 +444,7 @@ class ClassfileParser(
}
}
if (hasError || skip) None
- else Some(Annotation.deferred(attrType, argbuf.toList))
+ else Some(Annotation.deferredResolve(attrType, argbuf.toList))
} catch {
case f: FatalError => throw f // don't eat fatal errors, they mean a class was not found
case ex: Throwable =>
@@ -551,6 +552,45 @@ class ClassfileParser(
newType
}
+ /** Add a synthetic constructor and potentially also default getters which
+ * reflects the fields of the annotation with given `classInfo`.
+ * Annotations in Scala are assumed to get all their arguments as constructor
+ * parameters. For Java annotations we need to fake it by making up the constructor.
+ * Note that default getters have type Nothing. That's OK because we need
+ * them only to signal that the corresponding parameter is optional.
+ */
+ def addAnnotationConstructor(classInfo: Type, tparams: List[Symbol] = Nil)(implicit ctx: Context): Unit = {
+ def addDefaultGetter(attr: Symbol, n: Int) =
+ ctx.newSymbol(
+ owner = moduleRoot.symbol,
+ name = nme.CONSTRUCTOR.defaultGetterName(n),
+ flags = attr.flags & Flags.AccessFlags,
+ info = defn.NothingType).entered
+
+ classInfo match {
+ case classInfo @ TempPolyType(tparams, restpe) if tparams.isEmpty =>
+ addAnnotationConstructor(restpe, tparams)
+ case classInfo: TempClassInfoType =>
+ val attrs = classInfo.decls.toList.filter(_.isTerm)
+ val targs = tparams.map(_.typeRef)
+ val methType = MethodType(
+ attrs.map(_.name.asTermName),
+ attrs.map(_.info.resultType),
+ classRoot.typeRef.appliedTo(targs))
+ val constr = ctx.newSymbol(
+ owner = classRoot.symbol,
+ name = nme.CONSTRUCTOR,
+ flags = Flags.Synthetic,
+ info = if (tparams.isEmpty) methType else TempPolyType(tparams, methType)
+ ).entered
+ for ((attr, i) <- attrs.zipWithIndex)
+ if (attr.hasAnnotation(defn.AnnotationDefaultAnnot)) {
+ constr.setFlag(Flags.HasDefaultParams)
+ addDefaultGetter(attr, i)
+ }
+ }
+ }
+
/** Enter own inner classes in the right scope. It needs the scopes to be set up,
* and implicitly current class' superclasses.
*/
diff --git a/src/dotty/tools/dotc/core/pickling/PickleBuffer.scala b/src/dotty/tools/dotc/core/pickling/PickleBuffer.scala
index 9f8d4fc2d..c16b794b7 100644
--- a/src/dotty/tools/dotc/core/pickling/PickleBuffer.scala
+++ b/src/dotty/tools/dotc/core/pickling/PickleBuffer.scala
@@ -251,7 +251,8 @@ object PickleBuffer {
SPECIALIZED -> Specialized,
DEFAULTINIT -> DefaultInit,
VBRIDGE -> VBridge,
- VARARGS -> JavaVarargs)
+ VARARGS -> JavaVarargs,
+ ENUM -> Enum)
// generate initial maps from Scala flags to Dotty flags
val termMap, typeMap = new Array[Long](64)
diff --git a/src/dotty/tools/dotc/core/pickling/UnPickler.scala b/src/dotty/tools/dotc/core/pickling/UnPickler.scala
index 60000441c..728048700 100644
--- a/src/dotty/tools/dotc/core/pickling/UnPickler.scala
+++ b/src/dotty/tools/dotc/core/pickling/UnPickler.scala
@@ -9,8 +9,9 @@ import java.lang.Double.longBitsToDouble
import Contexts._, Symbols._, Types._, Scopes._, SymDenotations._, Names._, NameOps._
import StdNames._, Denotations._, NameOps._, Flags._, Constants._, Annotations._
+import dotty.tools.dotc.typer.ProtoTypes.{FunProtoTyped, FunProto}
import util.Positions._
-import ast.Trees, ast.tpd._, ast.untpd
+import dotty.tools.dotc.ast.{tpd, Trees, untpd}, ast.tpd._
import printing.Texts._
import printing.Printer
import io.AbstractFile
@@ -815,19 +816,26 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot:
*/
protected def readAnnotationContents(end: Int)(implicit ctx: Context): Tree = {
val atp = readTypeRef()
- val args = new ListBuffer[Tree]
- while (readIndex != end) {
- val argref = readNat()
- args += {
- if (isNameEntry(argref)) {
- val name = at(argref, readName)
- val arg = readClassfileAnnotArg(readNat())
- NamedArg(name.asTermName, arg)
- } else readAnnotArg(argref)
+ val args = {
+ val t = new ListBuffer[Tree]
+
+ while (readIndex != end) {
+ val argref = readNat()
+ t += {
+ if (isNameEntry(argref)) {
+ val name = at(argref, readName)
+ val arg = readClassfileAnnotArg(readNat())
+ NamedArg(name.asTermName, arg)
+ } else readAnnotArg(argref)
+ }
}
+ t.toList
}
- New(atp, args.toList)
- }
+ // println(atp)
+ val targs = atp.argTypes
+
+ tpd.applyOverloaded(tpd.New(atp withoutArgs targs), nme.CONSTRUCTOR, args, targs, atp)
+}
/** Read an annotation and as a side effect store it into
* the symbol it requests. Called at top-level, for all
diff --git a/src/dotty/tools/dotc/parsing/JavaParsers.scala b/src/dotty/tools/dotc/parsing/JavaParsers.scala
new file mode 100644
index 000000000..ab805f261
--- /dev/null
+++ b/src/dotty/tools/dotc/parsing/JavaParsers.scala
@@ -0,0 +1,892 @@
+package dotty.tools
+package dotc
+package parsing
+
+import dotty.tools.dotc.core.Constants.Constant
+import dotty.tools.dotc.core.Flags
+import dotty.tools.dotc.core.Flags.FlagSet
+
+import scala.language.implicitConversions
+
+import JavaTokens._
+import JavaScanners._
+import Parsers._
+import core._
+import Contexts._
+import Names._
+import NameOps._
+import Types._
+import Symbols._
+import ast.Trees._
+import Decorators._
+import StdNames._
+import dotty.tools.dotc.util.SourceFile
+import util.Positions._
+import annotation.switch
+import scala.collection.mutable.ListBuffer
+import scala.reflect.internal.util.Collections._
+
+object JavaParsers {
+
+ import ast.untpd._
+
+ class JavaParser(source: SourceFile)(implicit ctx: Context) extends ParserCommon(source) {
+
+ val definitions = ctx.definitions
+ import definitions._
+
+ val in: JavaScanner = new JavaScanner(source)
+
+ /** The simple name of the package of the currently parsed file */
+ private var thisPackageName: TypeName = tpnme.EMPTY
+
+ /** This is the general parse entry point.
+ * Overridden by ScriptParser
+ */
+ def parse(): Tree = {
+ val t = compilationUnit()
+ accept(EOF)
+ t
+ }
+
+ // -------- error handling ---------------------------------------
+
+ protected def skip(): Unit = {
+ var nparens = 0
+ var nbraces = 0
+ while (true) {
+ in.token match {
+ case EOF =>
+ return
+ case SEMI =>
+ if (nparens == 0 && nbraces == 0) return
+ case RPAREN =>
+ nparens -= 1
+ case RBRACE =>
+ if (nbraces == 0) return
+ nbraces -= 1
+ case LPAREN =>
+ nparens += 1
+ case LBRACE =>
+ nbraces += 1
+ case _ =>
+ }
+ in.nextToken()
+ }
+ }
+
+ def syntaxError(msg: String, skipIt: Boolean): Unit = {
+ syntaxError(in.offset, msg, skipIt)
+ }
+
+ def syntaxError(pos: Int, msg: String, skipIt: Boolean): Unit = {
+ if (pos > lastErrorOffset) {
+ syntaxError(msg, pos)
+ // no more errors on this token.
+ lastErrorOffset = in.offset
+ }
+ if (skipIt)
+ skip()
+ }
+ def errorTypeTree = TypeTree().withType(ErrorType) withPos Position(in.offset)
+
+ // --------- tree building -----------------------------
+
+ def rootId(name: Name) = Select(Ident(nme.ROOTPKG), name)
+ def scalaDot(name: Name) = Select(Ident(nme.scala_), name)
+ def scalaAnnotationDot(name: Name) = Select(scalaDot(nme.annotation), name)
+
+ def javaDot(name: Name): Tree =
+ Select(rootId(nme.java), name)
+
+ def javaLangDot(name: Name): Tree =
+ Select(javaDot(nme.lang), name)
+
+ def javaLangObject(): Tree = javaLangDot(tpnme.Object)
+
+ def arrayOf(tpt: Tree) =
+ AppliedTypeTree(Ident(nme.Array.toTypeName), List(tpt))
+
+ def unimplementedExpr = Ident("???".toTermName)
+
+ def makePackaging(pkg: RefTree, stats: List[Tree]): PackageDef =
+ atPos(pkg.pos) { PackageDef(pkg, stats) }
+
+ def makeTemplate(parents: List[Tree], stats: List[Tree], tparams: List[TypeDef], needsDummyConstr: Boolean) = {
+ def pullOutFirstConstr(stats: List[Tree]): (Tree, List[Tree]) = stats match {
+ case (meth: DefDef) :: rest if meth.name.isConstructorName => (meth, rest)
+ case first :: rest =>
+ val (constr, tail) = pullOutFirstConstr(rest)
+ (constr, first :: tail)
+ case nil => (EmptyTree, nil)
+ }
+ var (constr1, stats1) = pullOutFirstConstr(stats)
+ if(constr1 == EmptyTree) constr1 = makeConstructor(List(), tparams)
+ // A dummy first constructor is needed for Java classes so that the real constructors see the
+ // import of the companion object. The constructor has parameter of type Unit so no Java code
+ // can call it.
+ if(needsDummyConstr) {
+ stats1 = constr1 :: stats1
+ constr1 = makeConstructor(List(scalaDot(tpnme.Unit)), tparams, Flags.JavaDefined | Flags.PrivateLocal)
+ }
+ Template(constr1.asInstanceOf[DefDef], parents, EmptyValDef, stats1)
+ }
+
+ def makeSyntheticParam(count: Int, tpt: Tree): ValDef =
+ makeParam(nme.syntheticParamName(count), tpt)
+ def makeParam(name: TermName, tpt: Tree): ValDef =
+ ValDef(name, tpt, EmptyTree).withMods(Modifiers(Flags.JavaDefined | Flags.PrivateLocalParamAccessor))
+
+ def makeConstructor(formals: List[Tree], tparams: List[TypeDef], flags: FlagSet = Flags.JavaDefined) = {
+ val vparams = mapWithIndex(formals)((p, i) => makeSyntheticParam(i + 1, p))
+ DefDef(nme.CONSTRUCTOR, tparams, List(vparams), TypeTree(), EmptyTree).withMods(Modifiers(flags))
+ }
+
+ // ------------- general parsing ---------------------------
+
+ /** skip parent or brace enclosed sequence of things */
+ def skipAhead(): Unit = {
+ var nparens = 0
+ var nbraces = 0
+ do {
+ in.token match {
+ case LPAREN =>
+ nparens += 1
+ case LBRACE =>
+ nbraces += 1
+ case _ =>
+ }
+ in.nextToken()
+ in.token match {
+ case RPAREN =>
+ nparens -= 1
+ case RBRACE =>
+ nbraces -= 1
+ case _ =>
+ }
+ } while (in.token != EOF && (nparens > 0 || nbraces > 0))
+ }
+
+ def skipTo(tokens: Int*): Unit = {
+ while (!(tokens contains in.token) && in.token != EOF) {
+ if (in.token == LBRACE) { skipAhead(); accept(RBRACE) }
+ else if (in.token == LPAREN) { skipAhead(); accept(RPAREN) }
+ else in.nextToken()
+ }
+ }
+
+ /** Consume one token of the specified type, or
+ * signal an error if it is not there.
+ */
+ def accept(token: Int): Int = {
+ val offset = in.offset
+ if (in.token != token) {
+ val offsetToReport = in.offset
+ val msg =
+ tokenString(token) + " expected but " +
+ tokenString(in.token) + " found."
+
+ syntaxError(offsetToReport, msg, skipIt = true)
+ }
+ if (in.token == token) in.nextToken()
+ offset
+ }
+
+ def acceptClosingAngle(): Unit = {
+ val closers: PartialFunction[Int, Int] = {
+ case GTGTGTEQ => GTGTEQ
+ case GTGTGT => GTGT
+ case GTGTEQ => GTEQ
+ case GTGT => GT
+ case GTEQ => EQUALS
+ }
+ if (closers isDefinedAt in.token) in.token = closers(in.token)
+ else accept(GT)
+ }
+
+ def identForType(): TypeName = ident().toTypeName
+ def ident(): Name =
+ if (in.token == IDENTIFIER) {
+ val name = in.name
+ in.nextToken()
+ name
+ } else {
+ accept(IDENTIFIER)
+ nme.ERROR
+ }
+
+ def repsep[T <: Tree](p: () => T, sep: Int): List[T] = {
+ val buf = ListBuffer[T](p())
+ while (in.token == sep) {
+ in.nextToken()
+ buf += p()
+ }
+ buf.toList
+ }
+
+ /** Convert (qual)ident to type identifier
+ */
+ def convertToTypeId(tree: Tree): Tree = convertToTypeName(tree) match {
+ case Some(t) => t withPos tree.pos
+ case _ => tree match {
+ case AppliedTypeTree(_, _) | SelectFromTypeTree(_, _) =>
+ tree
+ case _ =>
+ syntaxError("identifier expected", tree.pos)
+ errorTypeTree
+ }
+ }
+
+ /** Translate names in Select/Ident nodes to type names.
+ */
+ def convertToTypeName(tree: Tree): Option[RefTree] = tree match {
+ case Select(qual, name) => Some(Select(qual, name.toTypeName))
+ case Ident(name) => Some(Ident(name.toTypeName))
+ case _ => None
+ }
+ // -------------------- specific parsing routines ------------------
+
+ def qualId(): RefTree = {
+ var t: RefTree = atPos(in.offset) { Ident(ident()) }
+ while (in.token == DOT) {
+ in.nextToken()
+ t = atPos(in.offset) { Select(t, ident()) }
+ }
+ t
+ }
+
+ def optArrayBrackets(tpt: Tree): Tree =
+ if (in.token == LBRACKET) {
+ val tpt1 = atPos(in.offset) { arrayOf(tpt) }
+ in.nextToken()
+ accept(RBRACKET)
+ optArrayBrackets(tpt1)
+ } else tpt
+
+ def basicType(): Tree =
+ atPos(in.offset) {
+ in.token match {
+ case BYTE => in.nextToken(); TypeTree(ByteType)
+ case SHORT => in.nextToken(); TypeTree(ShortType)
+ case CHAR => in.nextToken(); TypeTree(CharType)
+ case INT => in.nextToken(); TypeTree(IntType)
+ case LONG => in.nextToken(); TypeTree(LongType)
+ case FLOAT => in.nextToken(); TypeTree(FloatType)
+ case DOUBLE => in.nextToken(); TypeTree(DoubleType)
+ case BOOLEAN => in.nextToken(); TypeTree(BooleanType)
+ case _ => syntaxError("illegal start of type", skipIt = true); errorTypeTree
+ }
+ }
+
+ def typ(): Tree =
+ optArrayBrackets {
+ if (in.token == FINAL) in.nextToken()
+ if (in.token == IDENTIFIER) {
+ var t = typeArgs(atPos(in.offset)(Ident(ident())))
+ // typeSelect generates Select nodes is the lhs is an Ident or Select,
+ // SelectFromTypeTree otherwise. See #3567.
+ // Select nodes can be later
+ // converted in the typechecker to SelectFromTypeTree if the class
+ // turns out to be an instance ionner class instead of a static inner class.
+ def typeSelect(t: Tree, name: Name) = t match {
+ case Ident(_) | Select(_, _) => Select(t, name)
+ case _ => SelectFromTypeTree(t, name.toTypeName)
+ }
+ while (in.token == DOT) {
+ in.nextToken()
+ t = typeArgs(atPos(in.offset)(typeSelect(t, ident())))
+ }
+ convertToTypeId(t)
+ } else {
+ basicType()
+ }
+ }
+
+ def typeArgs(t: Tree): Tree = {
+ var wildnum = 0
+ def typeArg(): Tree =
+ if (in.token == QMARK) {
+ val offset = in.offset
+ in.nextToken()
+ val hi = if (in.token == EXTENDS) { in.nextToken() ; typ() } else EmptyTree
+ val lo = if (in.token == SUPER) { in.nextToken() ; typ() } else EmptyTree
+ atPos(offset) {
+ /*
+ TypeDef(
+ Modifiers(Flags.JavaDefined | Flags.Deferred),
+ typeName("_$"+(wildnum += 1)),
+ List(),
+ TypeBoundsTree(lo, hi))
+ */
+ TypeBoundsTree(lo, hi)
+ }
+ } else {
+ typ()
+ }
+ if (in.token == LT) {
+ in.nextToken()
+ val t1 = convertToTypeId(t)
+ val args = repsep(typeArg, COMMA)
+ acceptClosingAngle()
+ atPos(t1.pos) {
+ AppliedTypeTree(t1, args)
+ }
+ } else t
+ }
+
+ def annotations(): List[Tree] = {
+ //var annots = new ListBuffer[Tree]
+ while (in.token == AT) {
+ in.nextToken()
+ annotation()
+ }
+ List() // don't pass on annotations for now
+ }
+
+ /** Annotation ::= TypeName [`(` AnnotationArgument {`,` AnnotationArgument} `)`]
+ */
+ def annotation(): Unit = {
+ qualId()
+ if (in.token == LPAREN) { skipAhead(); accept(RPAREN) }
+ else if (in.token == LBRACE) { skipAhead(); accept(RBRACE) }
+ }
+
+ def modifiers(inInterface: Boolean): Modifiers = {
+ var flags = Flags.JavaDefined
+ // assumed true unless we see public/private/protected
+ var isPackageAccess = true
+ var annots: List[Tree] = Nil
+ def addAnnot(sym: ClassSymbol) = annots :+= New(TypeTree(sym.typeRef))
+
+ while (true) {
+ in.token match {
+ case AT if (in.lookaheadToken != INTERFACE) =>
+ in.nextToken()
+ annotation()
+ case PUBLIC =>
+ isPackageAccess = false
+ in.nextToken()
+ case PROTECTED =>
+ flags |= Flags.Protected
+ in.nextToken()
+ case PRIVATE =>
+ isPackageAccess = false
+ flags |= Flags.Private
+ in.nextToken()
+ case STATIC =>
+ flags |= Flags.JavaStatic
+ in.nextToken()
+ case ABSTRACT =>
+ flags |= Flags.Abstract
+ in.nextToken()
+ case FINAL =>
+ flags |= Flags.Final
+ in.nextToken()
+ case DEFAULT =>
+ flags |= Flags.DefaultMethod
+ in.nextToken()
+ case NATIVE =>
+ addAnnot(NativeAnnot)
+ in.nextToken()
+ case TRANSIENT =>
+ addAnnot(TransientAnnot)
+ in.nextToken()
+ case VOLATILE =>
+ addAnnot(VolatileAnnot)
+ in.nextToken()
+ case SYNCHRONIZED | STRICTFP =>
+ in.nextToken()
+ case _ =>
+ val privateWithin: TypeName =
+ if (isPackageAccess && !inInterface) thisPackageName
+ else tpnme.EMPTY
+
+ return Modifiers(flags, privateWithin) withAnnotations annots
+ }
+ }
+ assert(false, "should not be here")
+ throw new RuntimeException
+ }
+
+ def typeParams(flags: FlagSet = Flags.JavaDefined | Flags.PrivateLocal | Flags.Param): List[TypeDef] =
+ if (in.token == LT) {
+ in.nextToken()
+ val tparams = repsep(() => typeParam(flags), COMMA)
+ acceptClosingAngle()
+ tparams
+ } else List()
+
+ def typeParam(flags: FlagSet): TypeDef =
+ atPos(in.offset) {
+ val name = identForType()
+ val hi = if (in.token == EXTENDS) { in.nextToken() ; bound() } else EmptyTree
+ TypeDef(name, Nil, TypeBoundsTree(EmptyTree, hi)).withMods(Modifiers(flags))
+ }
+
+ def bound(): Tree =
+ atPos(in.offset) {
+ val buf = ListBuffer[Tree](typ())
+ while (in.token == AMP) {
+ in.nextToken()
+ buf += typ()
+ }
+ val ts = buf.toList
+ if (ts.tail.isEmpty) ts.head
+ else ts.reduce(AndTypeTree(_,_))
+ }
+
+ def formalParams(): List[ValDef] = {
+ accept(LPAREN)
+ val vparams = if (in.token == RPAREN) List() else repsep(formalParam, COMMA)
+ accept(RPAREN)
+ vparams
+ }
+
+ def formalParam(): ValDef = {
+ if (in.token == FINAL) in.nextToken()
+ annotations()
+ var t = typ()
+ if (in.token == DOTDOTDOT) {
+ in.nextToken()
+ t = atPos(t.pos) {
+ PostfixOp(t, nme.raw.STAR)
+ }
+ }
+ varDecl(Position(in.offset), Modifiers(Flags.JavaDefined | Flags.Param), t, ident().toTermName)
+ }
+
+ def optThrows(): Unit = {
+ if (in.token == THROWS) {
+ in.nextToken()
+ repsep(typ, COMMA)
+ }
+ }
+
+ def methodBody(): Tree = {
+ skipAhead()
+ accept(RBRACE) // skip block
+ unimplementedExpr
+ }
+
+ def definesInterface(token: Int) = token == INTERFACE || token == AT
+
+ def termDecl(mods: Modifiers, parentToken: Int, parentTParams: List[TypeDef]): List[Tree] = {
+ val inInterface = definesInterface(parentToken)
+ val tparams = if (in.token == LT) typeParams(Flags.JavaDefined | Flags.Param) else List()
+ val isVoid = in.token == VOID
+ var rtpt =
+ if (isVoid) {
+ in.nextToken()
+ TypeTree(UnitType) withPos Position(in.offset)
+ } else typ()
+ var offset = in.offset
+ val rtptName = rtpt match {
+ case Ident(name) => name
+ case _ => nme.EMPTY
+ }
+ if (in.token == LPAREN && rtptName != nme.EMPTY && !inInterface) {
+ // constructor declaration
+ val vparams = formalParams()
+ optThrows()
+ List {
+ atPos(offset) {
+ DefDef(nme.CONSTRUCTOR, parentTParams, List(vparams), TypeTree(), methodBody()).withMods(mods)
+ }
+ }
+ } else {
+ var mods1 = mods
+ if (mods is Flags.Abstract) mods1 = mods &~ Flags.Abstract
+ offset = in.offset
+ val name = ident()
+ if (in.token == LPAREN) {
+ // method declaration
+ val vparams = formalParams()
+ if (!isVoid) rtpt = optArrayBrackets(rtpt)
+ optThrows()
+ val bodyOk = !inInterface || (mods is Flags.DefaultMethod)
+ val body =
+ if (bodyOk && in.token == LBRACE) {
+ methodBody()
+ } else {
+ if (parentToken == AT && in.token == DEFAULT) {
+ val annot =
+ atPos(offset) {
+ New(Select(scalaDot(nme.runtime), tpnme.AnnotationDefaultATTR), Nil)
+ }
+ mods1 = mods1 withAnnotations annot :: Nil
+ skipTo(SEMI)
+ accept(SEMI)
+ unimplementedExpr
+ } else {
+ accept(SEMI)
+ EmptyTree
+ }
+ }
+ //if (inInterface) mods1 |= Flags.Deferred
+ List {
+ atPos(offset) {
+ DefDef(name.toTermName, tparams, List(vparams), rtpt, body).withMods(mods1 | Flags.Method)
+ }
+ }
+ } else {
+ if (inInterface) mods1 |= Flags.Final | Flags.JavaStatic
+ val result = fieldDecls(Position(offset), mods1, rtpt, name)
+ accept(SEMI)
+ result
+ }
+ }
+ }
+
+ /** Parse a sequence of field declarations, separated by commas.
+ * This one is tricky because a comma might also appear in an
+ * initializer. Since we don't parse initializers we don't know
+ * what the comma signifies.
+ * We solve this with a second list buffer `maybe` which contains
+ * potential variable definitions.
+ * Once we have reached the end of the statement, we know whether
+ * these potential definitions are real or not.
+ */
+ def fieldDecls(pos: Position, mods: Modifiers, tpt: Tree, name: Name): List[Tree] = {
+ val buf = ListBuffer[Tree](varDecl(pos, mods, tpt, name.toTermName))
+ val maybe = new ListBuffer[Tree] // potential variable definitions.
+ while (in.token == COMMA) {
+ in.nextToken()
+ if (in.token == IDENTIFIER) { // if there's an ident after the comma ...
+ val name = ident()
+ if (in.token == EQUALS || in.token == SEMI) { // ... followed by a `=` or `;`, we know it's a real variable definition
+ buf ++= maybe
+ buf += varDecl(Position(in.offset), mods, tpt, name.toTermName)
+ maybe.clear()
+ } else if (in.token == COMMA) { // ... if there's a comma after the ident, it could be a real vardef or not.
+ maybe += varDecl(Position(in.offset), mods, tpt, name.toTermName)
+ } else { // ... if there's something else we were still in the initializer of the
+ // previous var def; skip to next comma or semicolon.
+ skipTo(COMMA, SEMI)
+ maybe.clear()
+ }
+ } else { // ... if there's no ident following the comma we were still in the initializer of the
+ // previous var def; skip to next comma or semicolon.
+ skipTo(COMMA, SEMI)
+ maybe.clear()
+ }
+ }
+ if (in.token == SEMI) {
+ buf ++= maybe // every potential vardef that survived until here is real.
+ }
+ buf.toList
+ }
+
+ def varDecl(pos: Position, mods: Modifiers, tpt: Tree, name: TermName): ValDef = {
+ val tpt1 = optArrayBrackets(tpt)
+ if (in.token == EQUALS && !(mods is Flags.Param)) skipTo(COMMA, SEMI)
+ val mods1 = if(mods is Flags.Final) mods else mods | Flags.Mutable
+ atPos(pos) {
+ ValDef(name, tpt1, if(mods is Flags.Param) EmptyTree else unimplementedExpr).withMods(mods1)
+ }
+ }
+
+ def memberDecl(mods: Modifiers, parentToken: Int, parentTParams: List[TypeDef]): List[Tree] = in.token match {
+ case CLASS | ENUM | INTERFACE | AT =>
+ typeDecl(if (definesInterface(parentToken)) mods | Flags.JavaStatic else mods)
+ case _ =>
+ termDecl(mods, parentToken, parentTParams)
+ }
+
+ def makeCompanionObject(cdef: TypeDef, statics: List[Tree]): Tree =
+ atPos(cdef.pos) {
+ ModuleDef(cdef.name.toTermName,
+ makeTemplate(List(), statics, List(), false)).withMods((cdef.mods & (Flags.AccessFlags | Flags.JavaDefined)).toTermFlags)
+ }
+
+ private val wild = Ident(nme.WILDCARD) withPos Position(-1)
+ private val wildList = List(wild) // OPT This list is shared for performance.
+
+ def importCompanionObject(cdef: TypeDef): Tree =
+ atPos(cdef.pos) {
+ Import(Ident(cdef.name.toTermName), wildList)
+ }
+
+ // Importing the companion object members cannot be done uncritically: see
+ // ticket #2377 wherein a class contains two static inner classes, each of which
+ // has a static inner class called "Builder" - this results in an ambiguity error
+ // when each performs the import in the enclosing class's scope.
+ //
+ // To address this I moved the import Companion._ inside the class, as the first
+ // statement. This should work without compromising the enclosing scope, but may (?)
+ // end up suffering from the same issues it does in scala - specifically that this
+ // leaves auxiliary constructors unable to access members of the companion object
+ // as unqualified identifiers.
+ def addCompanionObject(statics: List[Tree], cdef: TypeDef): List[Tree] = {
+ // if there are no statics we can use the original cdef, but we always
+ // create the companion so import A._ is not an error (see ticket #1700)
+ val cdefNew =
+ if (statics.isEmpty) cdef
+ else {
+ val template = cdef.rhs.asInstanceOf[Template]
+ cpy.TypeDef(cdef)(cdef.name,
+ cpy.Template(template)(template.constr, template.parents, template.self,
+ importCompanionObject(cdef) :: template.body),
+ cdef.tparams).withMods(cdef.mods)
+ }
+
+ List(makeCompanionObject(cdefNew, statics), cdefNew)
+ }
+
+ def importDecl(): List[Tree] = {
+ accept(IMPORT)
+ val offset = in.offset
+ val buf = new ListBuffer[Name]
+ def collectIdents() : Int = {
+ if (in.token == ASTERISK) {
+ val starOffset = in.offset
+ in.nextToken()
+ buf += nme.WILDCARD
+ starOffset
+ } else {
+ val nameOffset = in.offset
+ buf += ident()
+ if (in.token == DOT) {
+ in.nextToken()
+ collectIdents()
+ } else nameOffset
+ }
+ }
+ if (in.token == STATIC) in.nextToken()
+ else buf += nme.ROOTPKG
+ val lastnameOffset = collectIdents()
+ accept(SEMI)
+ val names = buf.toList
+ if (names.length < 2) {
+ syntaxError(offset, "illegal import", skipIt = false)
+ List()
+ } else {
+ val qual = ((Ident(names.head): Tree) /: names.tail.init) (Select(_, _))
+ val lastname = names.last
+ val ident = Ident(lastname) withPos Position(lastnameOffset)
+// val selector = lastname match {
+// case nme.WILDCARD => Pair(ident, Ident(null) withPos Position(-1))
+// case _ => Pair(ident, ident)
+// }
+ List(atPos(offset)(Import(qual, List(ident))))
+ }
+ }
+
+ def interfacesOpt() =
+ if (in.token == IMPLEMENTS) {
+ in.nextToken()
+ repsep(typ, COMMA)
+ } else {
+ List()
+ }
+
+ def classDecl(mods: Modifiers): List[Tree] = {
+ accept(CLASS)
+ val offset = in.offset
+ val name = identForType()
+ val tparams = typeParams()
+ val superclass =
+ if (in.token == EXTENDS) {
+ in.nextToken()
+ typ()
+ } else {
+ javaLangObject()
+ }
+ val interfaces = interfacesOpt()
+ val (statics, body) = typeBody(CLASS, name, tparams)
+ addCompanionObject(statics, atPos(offset) {
+ TypeDef(name, makeTemplate(superclass :: interfaces, body, tparams, true)).withMods(mods)
+ })
+ }
+
+ def interfaceDecl(mods: Modifiers): List[Tree] = {
+ accept(INTERFACE)
+ val offset = in.offset
+ val name = identForType()
+ val tparams = typeParams()
+ val parents =
+ if (in.token == EXTENDS) {
+ in.nextToken()
+ repsep(typ, COMMA)
+ } else {
+ List(javaLangObject())
+ }
+ val (statics, body) = typeBody(INTERFACE, name, tparams)
+ addCompanionObject(statics, atPos(offset) {
+ TypeDef(
+ name, tparams,
+ makeTemplate(parents, body, tparams, false)).withMods(mods | Flags.Trait | Flags.JavaInterface | Flags.Abstract)
+ })
+ }
+
+ def typeBody(leadingToken: Int, parentName: Name, parentTParams: List[TypeDef]): (List[Tree], List[Tree]) = {
+ accept(LBRACE)
+ val defs = typeBodyDecls(leadingToken, parentName, parentTParams)
+ accept(RBRACE)
+ defs
+ }
+
+ def typeBodyDecls(parentToken: Int, parentName: Name, parentTParams: List[TypeDef]): (List[Tree], List[Tree]) = {
+ val inInterface = definesInterface(parentToken)
+ val statics = new ListBuffer[Tree]
+ val members = new ListBuffer[Tree]
+ while (in.token != RBRACE && in.token != EOF) {
+ var mods = modifiers(inInterface)
+ if (in.token == LBRACE) {
+ skipAhead() // skip init block, we just assume we have seen only static
+ accept(RBRACE)
+ } else if (in.token == SEMI) {
+ in.nextToken()
+ } else {
+ if (in.token == ENUM || definesInterface(in.token)) mods |= Flags.JavaStatic
+ val decls = memberDecl(mods, parentToken, parentTParams)
+ (if ((mods is Flags.JavaStatic) || inInterface && !(decls exists (_.isInstanceOf[DefDef])))
+ statics
+ else
+ members) ++= decls
+ }
+ }
+ def forwarders(sdef: Tree): List[Tree] = sdef match {
+ case TypeDef(name, _) if (parentToken == INTERFACE) =>
+ var rhs: Tree = Select(Ident(parentName.toTermName), name)
+ List(TypeDef(name, rhs).withMods(Modifiers(Flags.Protected)))
+ case _ =>
+ List()
+ }
+ val sdefs = statics.toList
+ val idefs = members.toList ::: (sdefs flatMap forwarders)
+ (sdefs, idefs)
+ }
+ def annotationParents = List(
+ scalaAnnotationDot(tpnme.Annotation),
+ Select(javaLangDot(nme.annotation), tpnme.Annotation),
+ scalaAnnotationDot(tpnme.ClassfileAnnotation)
+ )
+ def annotationDecl(mods: Modifiers): List[Tree] = {
+ accept(AT)
+ accept(INTERFACE)
+ val offset = in.offset
+ val name = identForType()
+ val (statics, body) = typeBody(AT, name, List())
+ val constructorParams = body.collect {
+ case dd: DefDef => makeParam(dd.name, dd.tpt)
+ }
+ val constr = DefDef(nme.CONSTRUCTOR,
+ List(), List(constructorParams), TypeTree(), EmptyTree).withMods(Modifiers(Flags.JavaDefined))
+ val body1 = body.filterNot(_.isInstanceOf[DefDef])
+ val templ = makeTemplate(annotationParents, constr :: body1, List(), false)
+ addCompanionObject(statics, atPos(offset) {
+ TypeDef(name, templ).withMods(mods | Flags.Abstract)
+ })
+ }
+
+ def enumDecl(mods: Modifiers): List[Tree] = {
+ accept(ENUM)
+ val offset = in.offset
+ val name = identForType()
+ def enumType = Ident(name)
+ val interfaces = interfacesOpt()
+ accept(LBRACE)
+ val buf = new ListBuffer[Tree]
+ def parseEnumConsts(): Unit = {
+ if (in.token != RBRACE && in.token != SEMI && in.token != EOF) {
+ buf += enumConst(enumType)
+ if (in.token == COMMA) {
+ in.nextToken()
+ parseEnumConsts()
+ }
+ }
+ }
+ parseEnumConsts()
+ val consts = buf.toList
+ val (statics, body) =
+ if (in.token == SEMI) {
+ in.nextToken()
+ typeBodyDecls(ENUM, name, List())
+ } else {
+ (List(), List())
+ }
+ val predefs = List(
+ DefDef(
+ nme.values, List(),
+ ListOfNil,
+ arrayOf(enumType),
+ unimplementedExpr).withMods(Modifiers(Flags.JavaDefined | Flags.JavaStatic | Flags.Method)),
+ DefDef(
+ nme.valueOf, List(),
+ List(List(makeParam("x".toTermName, TypeTree(StringType)))),
+ enumType,
+ unimplementedExpr).withMods(Modifiers(Flags.JavaDefined | Flags.JavaStatic | Flags.Method)))
+ accept(RBRACE)
+ /*
+ val superclazz =
+ AppliedTypeTree(javaLangDot(tpnme.Enum), List(enumType))
+ */
+ val superclazz = Apply(TypeApply(
+ Select(New(javaLangDot(tpnme.Enum)), nme.CONSTRUCTOR), List(enumType)),
+ List(Literal(Constant(null)),Literal(Constant(0))))
+ addCompanionObject(consts ::: statics ::: predefs, atPos(offset) {
+ TypeDef(name, List(),
+ makeTemplate(superclazz :: interfaces, body, List(), true)).withMods(mods | Flags.Enum)
+ })
+ }
+
+ def enumConst(enumType: Tree) = {
+ annotations()
+ atPos(in.offset) {
+ val name = ident()
+ if (in.token == LPAREN) {
+ // skip arguments
+ skipAhead()
+ accept(RPAREN)
+ }
+ if (in.token == LBRACE) {
+ // skip classbody
+ skipAhead()
+ accept(RBRACE)
+ }
+ ValDef(name.toTermName, enumType, unimplementedExpr).withMods(Modifiers(Flags.Enum | Flags.Stable | Flags.JavaDefined | Flags.JavaStatic))
+ }
+ }
+
+ def typeDecl(mods: Modifiers): List[Tree] = in.token match {
+ case ENUM => enumDecl(mods)
+ case INTERFACE => interfaceDecl(mods)
+ case AT => annotationDecl(mods)
+ case CLASS => classDecl(mods)
+ case _ => in.nextToken(); syntaxError("illegal start of type declaration", skipIt = true); List(errorTypeTree)
+ }
+
+ /** CompilationUnit ::= [package QualId semi] TopStatSeq
+ */
+ def compilationUnit(): Tree = {
+ var offset = in.offset
+ val pkg: RefTree =
+ if (in.token == AT || in.token == PACKAGE) {
+ annotations()
+ offset = in.offset
+ accept(PACKAGE)
+ val pkg = qualId()
+ accept(SEMI)
+ pkg
+ } else {
+ Ident(nme.EMPTY_PACKAGE)
+ }
+ thisPackageName = convertToTypeName(pkg) match {
+ case Some(t) => t.name.toTypeName
+ case _ => tpnme.EMPTY
+ }
+ val buf = new ListBuffer[Tree]
+ while (in.token == IMPORT)
+ buf ++= importDecl()
+ while (in.token != EOF && in.token != RBRACE) {
+ while (in.token == SEMI) in.nextToken()
+ if (in.token != EOF)
+ buf ++= typeDecl(modifiers(inInterface = false))
+ }
+ accept(EOF)
+ atPos(offset) {
+ makePackaging(pkg, buf.toList)
+ }
+ }
+ }
+}
diff --git a/src/dotty/tools/dotc/parsing/JavaScanners.scala b/src/dotty/tools/dotc/parsing/JavaScanners.scala
new file mode 100644
index 000000000..faac8e163
--- /dev/null
+++ b/src/dotty/tools/dotc/parsing/JavaScanners.scala
@@ -0,0 +1,537 @@
+package dotty.tools
+package dotc
+package parsing
+
+import core.Names._, core.Contexts._, core.Decorators._, util.Positions._
+import Scanners._
+import util.SourceFile
+import JavaTokens._
+import scala.annotation.{ switch, tailrec }
+import scala.reflect.internal.Chars._
+
+object JavaScanners {
+
+ class JavaScanner(source: SourceFile, override val startFrom: Offset = 0)(implicit ctx: Context) extends ScannerCommon(source)(ctx) {
+
+ def toToken(idx: Int): Token =
+ if (idx >= 0 && idx <= lastKeywordStart) kwArray(idx) else IDENTIFIER
+
+ private class JavaTokenData0 extends TokenData
+
+ /** we need one token lookahead
+ */
+ val next : TokenData = new JavaTokenData0
+ val prev : TokenData = new JavaTokenData0
+
+ // Get next token ------------------------------------------------------------
+
+ def nextToken(): Unit = {
+ if (next.token == EMPTY) {
+ fetchToken()
+ }
+ else {
+ this copyFrom next
+ next.token = EMPTY
+ }
+ }
+
+ def lookaheadToken: Int = {
+ prev copyFrom this
+ nextToken()
+ val t = token
+ next copyFrom this
+ this copyFrom prev
+ t
+ }
+
+ /** read next token
+ */
+ private def fetchToken(): Unit = {
+ offset = charOffset - 1
+ ch match {
+ case ' ' | '\t' | CR | LF | FF =>
+ nextChar()
+ fetchToken()
+ case _ =>
+ (ch: @switch) match {
+ case 'A' | 'B' | 'C' | 'D' | 'E' |
+ 'F' | 'G' | 'H' | 'I' | 'J' |
+ 'K' | 'L' | 'M' | 'N' | 'O' |
+ 'P' | 'Q' | 'R' | 'S' | 'T' |
+ 'U' | 'V' | 'W' | 'X' | 'Y' |
+ 'Z' | '$' | '_' |
+ 'a' | 'b' | 'c' | 'd' | 'e' |
+ 'f' | 'g' | 'h' | 'i' | 'j' |
+ 'k' | 'l' | 'm' | 'n' | 'o' |
+ 'p' | 'q' | 'r' | 's' | 't' |
+ 'u' | 'v' | 'w' | 'x' | 'y' |
+ 'z' =>
+ putChar(ch)
+ nextChar()
+ getIdentRest()
+
+ case '0' =>
+ putChar(ch)
+ nextChar()
+ if (ch == 'x' || ch == 'X') {
+ nextChar()
+ base = 16
+ } else {
+ base = 8
+ }
+ getNumber()
+
+ case '1' | '2' | '3' | '4' |
+ '5' | '6' | '7' | '8' | '9' =>
+ base = 10
+ getNumber()
+
+ case '\"' =>
+ nextChar()
+ while (ch != '\"' && (isUnicodeEscape || ch != CR && ch != LF && ch != SU)) {
+ getlitch()
+ }
+ if (ch == '\"') {
+ token = STRINGLIT
+ setStrVal()
+ nextChar()
+ } else {
+ error("unclosed string literal")
+ }
+
+ case '\'' =>
+ nextChar()
+ getlitch()
+ if (ch == '\'') {
+ nextChar()
+ token = CHARLIT
+ setStrVal()
+ } else {
+ error("unclosed character literal")
+ }
+
+ case '=' =>
+ token = EQUALS
+ nextChar()
+ if (ch == '=') {
+ token = EQEQ
+ nextChar()
+ }
+
+ case '>' =>
+ token = GT
+ nextChar()
+ if (ch == '=') {
+ token = GTEQ
+ nextChar()
+ } else if (ch == '>') {
+ token = GTGT
+ nextChar()
+ if (ch == '=') {
+ token = GTGTEQ
+ nextChar()
+ } else if (ch == '>') {
+ token = GTGTGT
+ nextChar()
+ if (ch == '=') {
+ token = GTGTGTEQ
+ nextChar()
+ }
+ }
+ }
+
+ case '<' =>
+ token = LT
+ nextChar()
+ if (ch == '=') {
+ token = LTEQ
+ nextChar()
+ } else if (ch == '<') {
+ token = LTLT
+ nextChar()
+ if (ch == '=') {
+ token = LTLTEQ
+ nextChar()
+ }
+ }
+
+ case '!' =>
+ token = BANG
+ nextChar()
+ if (ch == '=') {
+ token = BANGEQ
+ nextChar()
+ }
+
+ case '~' =>
+ token = TILDE
+ nextChar()
+
+ case '?' =>
+ token = QMARK
+ nextChar()
+
+ case ':' =>
+ token = COLON
+ nextChar()
+
+ case '@' =>
+ token = AT
+ nextChar()
+
+ case '&' =>
+ token = AMP
+ nextChar()
+ if (ch == '&') {
+ token = AMPAMP
+ nextChar()
+ } else if (ch == '=') {
+ token = AMPEQ
+ nextChar()
+ }
+
+ case '|' =>
+ token = BAR
+ nextChar()
+ if (ch == '|') {
+ token = BARBAR
+ nextChar()
+ } else if (ch == '=') {
+ token = BAREQ
+ nextChar()
+ }
+
+ case '+' =>
+ token = PLUS
+ nextChar()
+ if (ch == '+') {
+ token = PLUSPLUS
+ nextChar()
+ } else if (ch == '=') {
+ token = PLUSEQ
+ nextChar()
+ }
+
+ case '-' =>
+ token = MINUS
+ nextChar()
+ if (ch == '-') {
+ token = MINUSMINUS
+ nextChar()
+ } else if (ch == '=') {
+ token = MINUSEQ
+ nextChar()
+ }
+
+ case '*' =>
+ token = ASTERISK
+ nextChar()
+ if (ch == '=') {
+ token = ASTERISKEQ
+ nextChar()
+ }
+
+ case '/' =>
+ nextChar()
+ if (!skipComment()) {
+ token = SLASH
+ nextChar()
+ if (ch == '=') {
+ token = SLASHEQ
+ nextChar()
+ }
+ } else fetchToken()
+
+ case '^' =>
+ token = HAT
+ nextChar()
+ if (ch == '=') {
+ token = HATEQ
+ nextChar()
+ }
+
+ case '%' =>
+ token = PERCENT
+ nextChar()
+ if (ch == '=') {
+ token = PERCENTEQ
+ nextChar()
+ }
+
+ case '.' =>
+ token = DOT
+ nextChar()
+ if ('0' <= ch && ch <= '9') {
+ putChar('.');
+ getFraction()
+ } else if (ch == '.') {
+ nextChar()
+ if (ch == '.') {
+ nextChar()
+ token = DOTDOTDOT
+ } else error("`.' character expected")
+ }
+
+ case ';' =>
+ token = SEMI
+ nextChar()
+
+ case ',' =>
+ token = COMMA
+ nextChar()
+
+ case '(' =>
+ token = LPAREN
+ nextChar()
+
+ case '{' =>
+ token = LBRACE
+ nextChar()
+
+ case ')' =>
+ token = RPAREN
+ nextChar()
+
+ case '}' =>
+ token = RBRACE
+ nextChar()
+
+ case '[' =>
+ token = LBRACKET
+ nextChar()
+
+ case ']' =>
+ token = RBRACKET
+ nextChar()
+
+ case SU =>
+ if (isAtEnd) token = EOF
+ else {
+ error("illegal character")
+ nextChar()
+ }
+
+ case _ =>
+ if (Character.isUnicodeIdentifierStart(ch)) {
+ putChar(ch)
+ nextChar()
+ getIdentRest()
+ } else {
+ error("illegal character: " + ch.toInt)
+ nextChar()
+ }
+ }
+ }
+ }
+
+ protected def skipComment(): Boolean = {
+ @tailrec def skipLineComment(): Unit = ch match {
+ case CR | LF | SU =>
+ case _ => nextChar(); skipLineComment()
+ }
+ @tailrec def skipJavaComment(): Unit = ch match {
+ case SU => incompleteInputError("unclosed comment")
+ case '*' => nextChar(); if (ch == '/') nextChar() else skipJavaComment()
+ case _ => nextChar(); skipJavaComment()
+ }
+ ch match {
+ case '/' => nextChar(); skipLineComment(); true
+ case '*' => nextChar(); skipJavaComment(); true
+ case _ => false
+ }
+ }
+
+ // Identifiers ---------------------------------------------------------------
+
+ private def getIdentRest(): Unit = {
+ while (true) {
+ (ch: @switch) match {
+ case 'A' | 'B' | 'C' | 'D' | 'E' |
+ 'F' | 'G' | 'H' | 'I' | 'J' |
+ 'K' | 'L' | 'M' | 'N' | 'O' |
+ 'P' | 'Q' | 'R' | 'S' | 'T' |
+ 'U' | 'V' | 'W' | 'X' | 'Y' |
+ 'Z' | '$' |
+ 'a' | 'b' | 'c' | 'd' | 'e' |
+ 'f' | 'g' | 'h' | 'i' | 'j' |
+ 'k' | 'l' | 'm' | 'n' | 'o' |
+ 'p' | 'q' | 'r' | 's' | 't' |
+ 'u' | 'v' | 'w' | 'x' | 'y' |
+ 'z' |
+ '0' | '1' | '2' | '3' | '4' |
+ '5' | '6' | '7' | '8' | '9' =>
+ putChar(ch)
+ nextChar()
+
+ case '_' =>
+ putChar(ch)
+ nextChar()
+ getIdentRest()
+ return
+ case SU =>
+ finishNamed()
+ return
+ case _ =>
+ if (Character.isUnicodeIdentifierPart(ch)) {
+ putChar(ch)
+ nextChar()
+ } else {
+ finishNamed()
+ return
+ }
+ }
+ }
+ }
+
+ // Literals -----------------------------------------------------------------
+
+ /** read next character in character or string literal:
+ */
+ protected def getlitch() =
+ if (ch == '\\') {
+ nextChar()
+ if ('0' <= ch && ch <= '7') {
+ val leadch: Char = ch
+ var oct: Int = digit2int(ch, 8)
+ nextChar()
+ if ('0' <= ch && ch <= '7') {
+ oct = oct * 8 + digit2int(ch, 8)
+ nextChar()
+ if (leadch <= '3' && '0' <= ch && ch <= '7') {
+ oct = oct * 8 + digit2int(ch, 8)
+ nextChar()
+ }
+ }
+ putChar(oct.asInstanceOf[Char])
+ } else {
+ ch match {
+ case 'b' => putChar('\b')
+ case 't' => putChar('\t')
+ case 'n' => putChar('\n')
+ case 'f' => putChar('\f')
+ case 'r' => putChar('\r')
+ case '\"' => putChar('\"')
+ case '\'' => putChar('\'')
+ case '\\' => putChar('\\')
+ case _ =>
+ error("invalid escape character", charOffset - 1)
+ putChar(ch)
+ }
+ nextChar()
+ }
+ } else {
+ putChar(ch)
+ nextChar()
+ }
+
+ /** read fractional part and exponent of floating point number
+ * if one is present.
+ */
+ protected def getFraction(): Unit = {
+ token = DOUBLELIT
+ while ('0' <= ch && ch <= '9') {
+ putChar(ch)
+ nextChar()
+ }
+ if (ch == 'e' || ch == 'E') {
+ val lookahead = lookaheadReader
+ lookahead.nextChar()
+ if (lookahead.ch == '+' || lookahead.ch == '-') {
+ lookahead.nextChar()
+ }
+ if ('0' <= lookahead.ch && lookahead.ch <= '9') {
+ putChar(ch)
+ nextChar()
+ if (ch == '+' || ch == '-') {
+ putChar(ch)
+ nextChar()
+ }
+ while ('0' <= ch && ch <= '9') {
+ putChar(ch)
+ nextChar()
+ }
+ }
+ token = DOUBLELIT
+ }
+ if (ch == 'd' || ch == 'D') {
+ putChar(ch)
+ nextChar()
+ token = DOUBLELIT
+ } else if (ch == 'f' || ch == 'F') {
+ putChar(ch)
+ nextChar()
+ token = FLOATLIT
+ }
+ setStrVal()
+ }
+
+ /** read a number into name and set base
+ */
+ protected def getNumber(): Unit = {
+ while (digit2int(ch, if (base < 10) 10 else base) >= 0) {
+ putChar(ch)
+ nextChar()
+ }
+ token = INTLIT
+ if (base <= 10 && ch == '.') {
+ val lookahead = lookaheadReader
+ lookahead.nextChar()
+ lookahead.ch match {
+ case '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' |
+ '8' | '9' | 'd' | 'D' | 'e' | 'E' | 'f' | 'F' =>
+ putChar(ch)
+ nextChar()
+ return getFraction()
+ case _ =>
+ if (!isIdentifierStart(lookahead.ch)) {
+ putChar(ch)
+ nextChar()
+ return getFraction()
+ }
+ }
+ }
+ if (base <= 10 &&
+ (ch == 'e' || ch == 'E' ||
+ ch == 'f' || ch == 'F' ||
+ ch == 'd' || ch == 'D')) {
+ return getFraction()
+ }
+ setStrVal()
+ if (ch == 'l' || ch == 'L') {
+ nextChar()
+ token = LONGLIT
+ }
+ }
+
+ // Errors -----------------------------------------------------------------
+
+ override def toString() = token match {
+ case IDENTIFIER =>
+ "id(" + name + ")"
+ case CHARLIT =>
+ "char(" + intVal + ")"
+ case INTLIT =>
+ "int(" + intVal + ")"
+ case LONGLIT =>
+ "long(" + intVal + ")"
+ case FLOATLIT =>
+ "float(" + floatVal + ")"
+ case DOUBLELIT =>
+ "double(" + floatVal + ")"
+ case STRINGLIT =>
+ "string(" + name + ")"
+ case SEMI =>
+ ";"
+ case COMMA =>
+ ","
+ case _ =>
+ tokenString(token)
+ }
+
+ /* Initialization: read first char, then first token */
+ nextChar()
+ nextToken()
+ }
+
+ val (lastKeywordStart, kwArray) = buildKeywordArray(keywords)
+}
diff --git a/src/dotty/tools/dotc/parsing/JavaTokens.scala b/src/dotty/tools/dotc/parsing/JavaTokens.scala
new file mode 100644
index 000000000..9530e0516
--- /dev/null
+++ b/src/dotty/tools/dotc/parsing/JavaTokens.scala
@@ -0,0 +1,92 @@
+package dotty.tools
+package dotc
+package parsing
+
+import collection.immutable.BitSet
+
+object JavaTokens extends TokensCommon {
+ final val minToken = EMPTY
+ final val maxToken = DOUBLE
+
+ final val javaOnlyKeywords = tokenRange(INSTANCEOF, ASSERT)
+ final val sharedKeywords = BitSet( IF, FOR, ELSE, THIS, NULL, NEW, SUPER, ABSTRACT, FINAL, PRIVATE, PROTECTED,
+ OVERRIDE, EXTENDS, TRUE, FALSE, CLASS, IMPORT, PACKAGE, DO, THROW, TRY, CATCH, FINALLY, WHILE, RETURN )
+ final val primTypes = tokenRange(VOID, DOUBLE)
+ final val keywords = sharedKeywords | javaOnlyKeywords | primTypes
+
+ /** keywords */
+ final val INSTANCEOF = 101; enter(INSTANCEOF, "instanceof")
+ final val CONST = 102; enter(CONST, "const")
+
+ /** templates */
+ final val INTERFACE = 105; enter(INTERFACE, "interface")
+ final val ENUM = 106; enter(ENUM, "enum")
+ final val IMPLEMENTS = 107; enter(IMPLEMENTS, "implements")
+
+ /** modifiers */
+ final val PUBLIC = 110; enter(PUBLIC, "public")
+ final val DEFAULT = 111; enter(DEFAULT, "default")
+ final val STATIC = 112; enter(STATIC, "static")
+ final val TRANSIENT = 113; enter(TRANSIENT, "transient")
+ final val VOLATILE = 114; enter(VOLATILE, "volatile")
+ final val SYNCHRONIZED = 115; enter(SYNCHRONIZED, "synchronized")
+ final val NATIVE = 116; enter(NATIVE, "native")
+ final val STRICTFP = 117; enter(STRICTFP, "strictfp")
+ final val THROWS = 118; enter(THROWS, "throws")
+
+ /** control structures */
+ final val BREAK = 130; enter(BREAK, "break")
+ final val CONTINUE = 131; enter(CONTINUE, "continue")
+ final val GOTO = 132; enter(GOTO, "goto")
+ final val SWITCH = 133; enter(SWITCH, "switch")
+ final val ASSERT = 134; enter(ASSERT, "assert")
+
+ /** special symbols */
+ final val EQEQ = 140
+ final val BANGEQ = 141
+ final val LT = 142
+ final val GT = 143
+ final val LTEQ = 144
+ final val GTEQ = 145
+ final val BANG = 146
+ final val QMARK = 147
+ final val AMP = 148
+ final val BAR = 149
+ final val PLUS = 150
+ final val MINUS = 151
+ final val ASTERISK = 152
+ final val SLASH = 153
+ final val PERCENT = 154
+ final val HAT = 155
+ final val LTLT = 156
+ final val GTGT = 157
+ final val GTGTGT = 158
+ final val AMPAMP = 159
+ final val BARBAR = 160
+ final val PLUSPLUS = 161
+ final val MINUSMINUS = 162
+ final val TILDE = 163
+ final val DOTDOTDOT = 164
+ final val AMPEQ = 165
+ final val BAREQ = 166
+ final val PLUSEQ = 167
+ final val MINUSEQ = 168
+ final val ASTERISKEQ = 169
+ final val SLASHEQ = 170
+ final val PERCENTEQ = 171
+ final val HATEQ = 172
+ final val LTLTEQ = 173
+ final val GTGTEQ = 174
+ final val GTGTGTEQ = 175
+
+ /** primitive types */
+ final val VOID = 180; enter(VOID, "void")
+ final val BOOLEAN = 181; enter(BOOLEAN, "boolean")
+ final val BYTE = 182; enter(BYTE, "byte")
+ final val SHORT = 183; enter(SHORT, "short")
+ final val CHAR = 184; enter(CHAR, "char")
+ final val INT = 185; enter(INT, "int")
+ final val LONG = 186; enter(LONG, "long")
+ final val FLOAT = 187; enter(FLOAT, "float")
+ final val DOUBLE = 188; enter(DOUBLE, "double")
+}
diff --git a/src/dotty/tools/dotc/parsing/Parsers.scala b/src/dotty/tools/dotc/parsing/Parsers.scala
index 1b08b7400..e8a6fd815 100644
--- a/src/dotty/tools/dotc/parsing/Parsers.scala
+++ b/src/dotty/tools/dotc/parsing/Parsers.scala
@@ -51,9 +51,56 @@ object Parsers {
if (source.isSelfContained) new ScriptParser(source)
else new Parser(source)
- class Parser(val source: SourceFile)(implicit ctx: Context) extends DotClass {
+ abstract class ParserCommon(val source: SourceFile)(implicit ctx: Context) extends DotClass {
- val in = new Scanner(source)
+ val in: ScannerCommon
+
+ /* ------------- POSITIONS ------------------------------------------- */
+
+ def atPos[T <: Positioned](start: Offset, point: Offset, end: Offset)(t: T): T =
+ atPos(Position(start, end, point))(t)
+
+ def atPos[T <: Positioned](start: Offset, point: Offset)(t: T): T =
+ atPos(start, point, in.lastOffset)(t)
+
+ def atPos[T <: Positioned](start: Offset)(t: T): T =
+ atPos(start, start)(t)
+
+ def atPos[T <: Positioned](pos: Position)(t: T): T =
+ if (t.pos.isSourceDerived) t else t.withPos(pos)
+
+ def tokenRange = Position(in.offset, in.lastCharOffset, in.offset)
+
+ def sourcePos(off: Int = in.offset): SourcePosition =
+ source atPos Position(off)
+
+
+ /* ------------- ERROR HANDLING ------------------------------------------- */
+ /** The offset where the last syntax error was reported, or if a skip to a
+ * safepoint occurred afterwards, the offset of the safe point.
+ */
+ protected var lastErrorOffset : Int = -1
+
+ /** Issue an error at given offset if beyond last error offset
+ * and update lastErrorOffset.
+ */
+ def syntaxError(msg: String, offset: Int = in.offset): Unit =
+ if (offset > lastErrorOffset) {
+ syntaxError(msg, Position(offset))
+ lastErrorOffset = in.offset
+ }
+
+ /** Unconditionally issue an error at given position, without
+ * updating lastErrorOffset.
+ */
+ def syntaxError(msg: String, pos: Position): Unit =
+ ctx.error(msg, source atPos pos)
+
+ }
+
+ class Parser(source: SourceFile)(implicit ctx: Context) extends ParserCommon(source) {
+
+ val in: Scanner = new Scanner(source)
val openParens = new ParensCounters
@@ -85,25 +132,6 @@ object Parsers {
def isStatSep: Boolean =
in.token == NEWLINE || in.token == NEWLINES || in.token == SEMI
-/* ------------- POSITIONS ------------------------------------------- */
-
- def atPos[T <: Positioned](start: Offset, point: Offset, end: Offset)(t: T): T =
- atPos(Position(start, end, point))(t)
-
- def atPos[T <: Positioned](start: Offset, point: Offset)(t: T): T =
- atPos(start, point, in.lastOffset)(t)
-
- def atPos[T <: Positioned](start: Offset)(t: T): T =
- atPos(start, start)(t)
-
- def atPos[T <: Positioned](pos: Position)(t: T): T =
- if (t.pos.isSourceDerived) t else t.withPos(pos)
-
- def tokenRange = Position(in.offset, in.lastCharOffset, in.offset)
-
- def sourcePos(off: Int = in.offset): SourcePosition =
- source atPos Position(off)
-
/* ------------- ERROR HANDLING ------------------------------------------- */
/** The offset of the last time when a statement on a new line was definitely
@@ -177,26 +205,6 @@ object Parsers {
def deprecationWarning(msg: String, offset: Int = in.offset) =
ctx.deprecationWarning(msg, source atPos Position(offset))
- /** The offset where the last syntax error was reported, or if a skip to a
- * safepoint occurred afterwards, the offset of the safe point.
- */
- private var lastErrorOffset : Int = -1
-
- /** Issue an error at given offset if beyond last error offset
- * and update lastErrorOffset.
- */
- def syntaxError(msg: String, offset: Int = in.offset): Unit =
- if (offset > lastErrorOffset) {
- syntaxError(msg, Position(offset))
- lastErrorOffset = in.offset
- }
-
- /** Unconditionally issue an error at given position, without
- * updating lastErrorOffset.
- */
- def syntaxError(msg: String, pos: Position): Unit =
- ctx.error(msg, source atPos pos)
-
/** Issue an error at current offset taht input is incomplete */
def incompleteInputError(msg: String) =
ctx.incompleteInputError(msg, source atPos Position(in.offset))
diff --git a/src/dotty/tools/dotc/parsing/Scanners.scala b/src/dotty/tools/dotc/parsing/Scanners.scala
index 4d8fdd10d..5eb8357a4 100644
--- a/src/dotty/tools/dotc/parsing/Scanners.scala
+++ b/src/dotty/tools/dotc/parsing/Scanners.scala
@@ -58,36 +58,136 @@ object Scanners {
}
}
- class Scanner(source: SourceFile, override val startFrom: Offset = 0)(implicit ctx: Context) extends CharArrayReader with TokenData {
-
+ abstract class ScannerCommon(source: SourceFile)(implicit ctx: Context) extends CharArrayReader with TokenData {
val buf = source.content
- var keepComments = false
-
- /** All comments in the reverse order of their position in the source.
- * set only when `keepComments` is true.
- */
- var revComments: List[Comment] = Nil
+ // Errors -----------------------------------------------------------------
/** the last error offset
- */
+ */
var errOffset: Offset = NoOffset
- /** A buffer for comments */
- val commentBuf = new StringBuilder
+
+ /** Generate an error at the given offset */
+ def error(msg: String, off: Offset = offset) = {
+ ctx.error(msg, source atPos Position(off))
+ token = ERROR
+ errOffset = off
+ }
+
+ /** signal an error where the input ended in the middle of a token */
+ def incompleteInputError(msg: String): Unit = {
+ ctx.incompleteInputError(msg, source atPos Position(offset))
+ token = EOF
+ errOffset = offset
+ }
+
+ // Setting token data ----------------------------------------------------
/** A character buffer for literals
- */
+ */
val litBuf = new StringBuilder
/** append Unicode character to "litBuf" buffer
- */
+ */
protected def putChar(c: Char): Unit = litBuf.append(c)
+ /** Return buffer contents and clear */
+ def flushBuf(buf: StringBuilder): String = {
+ val str = buf.toString
+ buf.clear()
+ str
+ }
+
+ /** Clear buffer and set name and token */
+ def finishNamed(idtoken: Token = IDENTIFIER, target: TokenData = this): Unit = {
+ target.name = flushBuf(litBuf).toTermName
+ target.token = idtoken
+ if (idtoken == IDENTIFIER) {
+ val idx = target.name.start
+ target.token = toToken(idx)
+ }
+ }
+ def toToken(idx: Int): Token
+
/** Clear buffer and set string */
- private def setStrVal() =
+ def setStrVal() =
strVal = flushBuf(litBuf)
+ /** Convert current strVal to char value
+ */
+ def charVal: Char = if (strVal.length > 0) strVal.charAt(0) else 0
+
+ /** Convert current strVal, base to long value
+ * This is tricky because of max negative value.
+ */
+ def intVal(negated: Boolean): Long = {
+ if (token == CHARLIT && !negated) {
+ charVal
+ } else {
+ var value: Long = 0
+ val divider = if (base == 10) 1 else 2
+ val limit: Long =
+ if (token == LONGLIT) Long.MaxValue else Int.MaxValue
+ var i = 0
+ val len = strVal.length
+ while (i < len) {
+ val d = digit2int(strVal charAt i, base)
+ if (d < 0) {
+ error("malformed integer number")
+ return 0
+ }
+ if (value < 0 ||
+ limit / (base / divider) < value ||
+ limit - (d / divider) < value * (base / divider) &&
+ !(negated && limit == value * base - 1 + d)) {
+ error("integer number too large")
+ return 0
+ }
+ value = value * base + d
+ i += 1
+ }
+ if (negated) -value else value
+ }
+ }
+
+ def intVal: Long = intVal(false)
+
+ /** Convert current strVal, base to double value
+ */
+ def floatVal(negated: Boolean): Double = {
+ val limit: Double =
+ if (token == DOUBLELIT) Double.MaxValue else Float.MaxValue
+ try {
+ val value: Double = java.lang.Double.valueOf(strVal).doubleValue()
+ if (value > limit)
+ error("floating point number too large")
+ if (negated) -value else value
+ } catch {
+ case _: NumberFormatException =>
+ error("malformed floating point number")
+ 0.0
+ }
+ }
+
+ def floatVal: Double = floatVal(false)
+
+ }
+
+ class Scanner(source: SourceFile, override val startFrom: Offset = 0)(implicit ctx: Context) extends ScannerCommon(source)(ctx) {
+ var keepComments = false
+
+ /** All comments in the reverse order of their position in the source.
+ * set only when `keepComments` is true.
+ */
+ var revComments: List[Comment] = Nil
+
+ /** A buffer for comments */
+ val commentBuf = new StringBuilder
+
+ def toToken(idx: Int): Token =
+ if (idx >= 0 && idx <= lastKeywordStart) kwArray(idx) else IDENTIFIER
+
private class TokenData0 extends TokenData
/** we need one token lookahead and one token history
@@ -818,84 +918,6 @@ object Scanners {
strVal = name.toString
}
}
-
-// Setting token data ----------------------------------------------------
-
- /** Clear buffer and set name and token */
- def finishNamed(idtoken: Token = IDENTIFIER, target: TokenData = this): Unit = {
- target.name = flushBuf(litBuf).toTermName
- target.token = idtoken
- if (idtoken == IDENTIFIER) {
- val idx = target.name.start
- if (idx >= 0 && idx <= lastKeywordStart) target.token = kwArray(idx)
- }
- }
-
- /** Return buffer contents and clear */
- def flushBuf(buf: StringBuilder): String = {
- val str = buf.toString
- buf.clear()
- str
- }
-
- /** Convert current strVal to char value
- */
- def charVal: Char = if (strVal.length > 0) strVal.charAt(0) else 0
-
- /** Convert current strVal, base to long value
- * This is tricky because of max negative value.
- */
- def intVal(negated: Boolean): Long = {
- if (token == CHARLIT && !negated) {
- charVal
- } else {
- var value: Long = 0
- val divider = if (base == 10) 1 else 2
- val limit: Long =
- if (token == LONGLIT) Long.MaxValue else Int.MaxValue
- var i = 0
- val len = strVal.length
- while (i < len) {
- val d = digit2int(strVal charAt i, base)
- if (d < 0) {
- error("malformed integer number")
- return 0
- }
- if (value < 0 ||
- limit / (base / divider) < value ||
- limit - (d / divider) < value * (base / divider) &&
- !(negated && limit == value * base - 1 + d)) {
- error("integer number too large")
- return 0
- }
- value = value * base + d
- i += 1
- }
- if (negated) -value else value
- }
- }
-
- def intVal: Long = intVal(false)
-
- /** Convert current strVal, base to double value
- */
- def floatVal(negated: Boolean): Double = {
- val limit: Double =
- if (token == DOUBLELIT) Double.MaxValue else Float.MaxValue
- try {
- val value: Double = java.lang.Double.valueOf(strVal).doubleValue()
- if (value > limit)
- error("floating point number too large")
- if (negated) -value else value
- } catch {
- case _: NumberFormatException =>
- error("malformed floating point number")
- 0.0
- }
- }
-
- def floatVal: Double = floatVal(false)
-
override def toString =
showTokenDetailed(token) + {
if ((identifierTokens contains token) || (literalTokens contains token)) " " + name
@@ -930,22 +952,6 @@ object Scanners {
nextToken()
}
-// Errors -----------------------------------------------------------------
-
- /** Generate an error at the given offset */
- def error(msg: String, off: Offset = offset) = {
- ctx.error(msg, source atPos Position(off))
- token = ERROR
- errOffset = off
- }
-
- /** signal an error where the input ended in the middle of a token */
- def incompleteInputError(msg: String): Unit = {
- ctx.incompleteInputError(msg, source atPos Position(offset))
- token = EOF
- errOffset = offset
- }
-
/* Initialization: read first char, then first token */
nextChar()
nextToken()
@@ -953,14 +959,5 @@ object Scanners {
// ------------- keyword configuration -----------------------------------
- private def start(tok: Token) = tokenString(tok).toTermName.start
- private def sourceKeywords = keywords.toList.filterNot(kw => tokenString(kw) contains ' ')
-
- private val lastKeywordStart = sourceKeywords.map(start).max
-
- private val kwArray: Array[Token] = {
- val arr = Array.fill(lastKeywordStart + 1)(IDENTIFIER)
- for (kw <- sourceKeywords) arr(start(kw)) = kw
- arr
- }
+ val (lastKeywordStart, kwArray) = buildKeywordArray(keywords)
}
diff --git a/src/dotty/tools/dotc/parsing/Tokens.scala b/src/dotty/tools/dotc/parsing/Tokens.scala
index 09124d0d1..226a3710d 100644
--- a/src/dotty/tools/dotc/parsing/Tokens.scala
+++ b/src/dotty/tools/dotc/parsing/Tokens.scala
@@ -3,11 +3,10 @@ package dotc
package parsing
import collection.immutable.BitSet
+import core.Decorators._
-object Tokens {
-
- final val minToken = EMPTY
- final val maxToken = XMLSTART
+abstract class TokensCommon {
+ val maxToken: Int
type Token = Int
type TokenSet = BitSet
@@ -24,6 +23,7 @@ object Tokens {
val tokenString, debugString = new Array[String](maxToken + 1)
def enter(token: Int, str: String, debugStr: String = ""): Unit = {
+ assert(tokenString(token) == null)
tokenString(token) = str
debugString(token) = if (debugStr.isEmpty) str else debugStr
}
@@ -41,17 +41,12 @@ object Tokens {
final val DOUBLELIT = 7; enter(DOUBLELIT, "double literal")
final val STRINGLIT = 8; enter(STRINGLIT, "string literal")
final val STRINGPART = 9; enter(STRINGPART, "string literal", "string literal part")
- final val INTERPOLATIONID = 10; enter(INTERPOLATIONID, "string interpolator")
- final val SYMBOLLIT = 11; enter(SYMBOLLIT, "symbol literal") // TODO: deprecate
+ //final val INTERPOLATIONID = 10; enter(INTERPOLATIONID, "string interpolator")
+ //final val SYMBOLLIT = 11; enter(SYMBOLLIT, "symbol literal") // TODO: deprecate
/** identifiers */
final val IDENTIFIER = 12; enter(IDENTIFIER, "identifier")
- final val BACKQUOTED_IDENT = 13; enter(BACKQUOTED_IDENT, "identifier", "backquoted ident")
-
- final val identifierTokens = BitSet(IDENTIFIER, BACKQUOTED_IDENT)
-
- def isIdentifier(token : Int) =
- token >= IDENTIFIER && token <= BACKQUOTED_IDENT
+ //final val BACKQUOTED_IDENT = 13; enter(BACKQUOTED_IDENT, "identifier", "backquoted ident")
/** alphabetic keywords */
final val IF = 20; enter(IF, "if")
@@ -60,67 +55,63 @@ object Tokens {
final val THIS = 23; enter(THIS, "this")
final val NULL = 24; enter(NULL, "null")
final val NEW = 25; enter(NEW, "new")
- final val WITH = 26; enter(WITH, "with")
+ //final val WITH = 26; enter(WITH, "with")
final val SUPER = 27; enter(SUPER, "super")
- final val CASE = 28; enter(CASE, "case")
- final val CASECLASS = 29; enter(CASECLASS, "case class")
- final val CASEOBJECT = 30; enter(CASEOBJECT, "case object")
- final val VAL = 31; enter(VAL, "val")
+ //final val CASE = 28; enter(CASE, "case")
+ //final val CASECLASS = 29; enter(CASECLASS, "case class")
+ //final val CASEOBJECT = 30; enter(CASEOBJECT, "case object")
+ //final val VAL = 31; enter(VAL, "val")
final val ABSTRACT = 32; enter(ABSTRACT, "abstract")
final val FINAL = 33; enter(FINAL, "final")
final val PRIVATE = 34; enter(PRIVATE, "private")
final val PROTECTED = 35; enter(PROTECTED, "protected")
final val OVERRIDE = 36; enter(OVERRIDE, "override")
- final val IMPLICIT = 37; enter(IMPLICIT, "implicit")
- final val VAR = 38; enter(VAR, "var")
- final val DEF = 39; enter(DEF, "def")
- final val TYPE = 40; enter(TYPE, "type")
+ //final val IMPLICIT = 37; enter(IMPLICIT, "implicit")
+ //final val VAR = 38; enter(VAR, "var")
+ //final val DEF = 39; enter(DEF, "def")
+ //final val TYPE = 40; enter(TYPE, "type")
final val EXTENDS = 41; enter(EXTENDS, "extends")
final val TRUE = 42; enter(TRUE, "true")
final val FALSE = 43; enter(FALSE, "false")
- final val OBJECT = 44; enter(OBJECT, "object")
+ //final val OBJECT = 44; enter(OBJECT, "object")
final val CLASS = 45; enter(CLASS, "class")
final val IMPORT = 46; enter(IMPORT, "import")
final val PACKAGE = 47; enter(PACKAGE, "package")
- final val YIELD = 48; enter(YIELD, "yield")
+ //final val YIELD = 48; enter(YIELD, "yield")
final val DO = 49; enter(DO, "do")
- final val TRAIT = 50; enter(TRAIT, "trait")
- final val SEALED = 51; enter(SEALED, "sealed")
+ //final val TRAIT = 50; enter(TRAIT, "trait")
+ //final val SEALED = 51; enter(SEALED, "sealed")
final val THROW = 52; enter(THROW, "throw")
final val TRY = 53; enter(TRY, "try")
final val CATCH = 54; enter(CATCH, "catch")
final val FINALLY = 55; enter(FINALLY, "finally")
final val WHILE = 56; enter(WHILE, "while")
final val RETURN = 57; enter(RETURN, "return")
- final val MATCH = 58; enter(MATCH, "match")
- final val LAZY = 59; enter(LAZY, "lazy")
- final val THEN = 60; enter(THEN, "then")
- final val FORSOME = 61; enter(FORSOME, "forSome") // TODO: deprecate
-
- final val alphaKeywords = tokenRange(IF, FORSOME)
+ //final val MATCH = 58; enter(MATCH, "match")
+ //final val LAZY = 59; enter(LAZY, "lazy")
+ //final val THEN = 60; enter(THEN, "then")
+ //final val FORSOME = 61; enter(FORSOME, "forSome") // TODO: deprecate
/** special symbols */
final val COMMA = 70; enter(COMMA, "','")
final val SEMI = 71; enter(DOT, "'.'")
final val DOT = 72; enter(SEMI, "';'")
- final val NEWLINE = 78; enter(NEWLINE, "end of statement", "new line")
- final val NEWLINES = 79; enter(NEWLINES, "end of statement", "new lines")
+ //final val NEWLINE = 78; enter(NEWLINE, "end of statement", "new line")
+ //final val NEWLINES = 79; enter(NEWLINES, "end of statement", "new lines")
/** special keywords */
- final val USCORE = 73; enter(USCORE, "_")
+ //final val USCORE = 73; enter(USCORE, "_")
final val COLON = 74; enter(COLON, ":")
final val EQUALS = 75; enter(EQUALS, "=")
- final val LARROW = 76; enter(LARROW, "<-")
- final val ARROW = 77; enter(ARROW, "=>")
- final val SUBTYPE = 80; enter(SUBTYPE, "<:")
- final val SUPERTYPE = 81; enter(SUPERTYPE, ">:")
- final val HASH = 82; enter(HASH, "#")
+ //final val LARROW = 76; enter(LARROW, "<-")
+ //final val ARROW = 77; enter(ARROW, "=>")
+ //final val SUBTYPE = 80; enter(SUBTYPE, "<:")
+ //final val SUPERTYPE = 81; enter(SUPERTYPE, ">:")
+ //final val HASH = 82; enter(HASH, "#")
final val AT = 83; enter(AT, "@")
- final val VIEWBOUND = 84; enter(VIEWBOUND, "<%") // TODO: deprecate
+ //final val VIEWBOUND = 84; enter(VIEWBOUND, "<%") // TODO: deprecate
- final val symbolicKeywords = tokenRange(USCORE, VIEWBOUND)
- final val symbolicTokens = tokenRange(COMMA, VIEWBOUND)
- final val keywords = alphaKeywords | symbolicKeywords
+ val keywords: TokenSet
/** parentheses */
final val LPAREN = 90; enter(LPAREN, "'('")
@@ -133,9 +124,75 @@ object Tokens {
final val firstParen = LPAREN
final val lastParen = RBRACE
+ def buildKeywordArray(keywords: TokenSet) = {
+ def start(tok: Token) = tokenString(tok).toTermName.start
+ def sourceKeywords = keywords.toList.filter { (kw: Token) =>
+ val ts = tokenString(kw)
+ (ts != null) && !ts.contains(' ')
+ }
+
+ val lastKeywordStart = sourceKeywords.map(start).max
+
+ val arr = Array.fill(lastKeywordStart + 1)(IDENTIFIER)
+ for (kw <- sourceKeywords) arr(start(kw)) = kw
+ (lastKeywordStart, arr)
+ }
+}
+
+object Tokens extends TokensCommon {
+ final val minToken = EMPTY
+ final val maxToken = XMLSTART
+
+ final val INTERPOLATIONID = 10; enter(INTERPOLATIONID, "string interpolator")
+ final val SYMBOLLIT = 11; enter(SYMBOLLIT, "symbol literal") // TODO: deprecate
+
+ final val BACKQUOTED_IDENT = 13; enter(BACKQUOTED_IDENT, "identifier", "backquoted ident")
+
+ final val identifierTokens = BitSet(IDENTIFIER, BACKQUOTED_IDENT)
+
+ def isIdentifier(token : Int) =
+ token >= IDENTIFIER && token <= BACKQUOTED_IDENT
+
+ /** alphabetic keywords */
+ final val WITH = 26; enter(WITH, "with")
+ final val CASE = 28; enter(CASE, "case")
+ final val CASECLASS = 29; enter(CASECLASS, "case class")
+ final val CASEOBJECT = 30; enter(CASEOBJECT, "case object")
+ final val VAL = 31; enter(VAL, "val")
+ final val IMPLICIT = 37; enter(IMPLICIT, "implicit")
+ final val VAR = 38; enter(VAR, "var")
+ final val DEF = 39; enter(DEF, "def")
+ final val TYPE = 40; enter(TYPE, "type")
+ final val OBJECT = 44; enter(OBJECT, "object")
+ final val YIELD = 48; enter(YIELD, "yield")
+ final val TRAIT = 50; enter(TRAIT, "trait")
+ final val SEALED = 51; enter(SEALED, "sealed")
+ final val MATCH = 58; enter(MATCH, "match")
+ final val LAZY = 59; enter(LAZY, "lazy")
+ final val THEN = 60; enter(THEN, "then")
+ final val FORSOME = 61; enter(FORSOME, "forSome") // TODO: deprecate
+
+ /** special symbols */
+ final val NEWLINE = 78; enter(NEWLINE, "end of statement", "new line")
+ final val NEWLINES = 79; enter(NEWLINES, "end of statement", "new lines")
+
+ /** special keywords */
+ final val USCORE = 73; enter(USCORE, "_")
+ final val LARROW = 76; enter(LARROW, "<-")
+ final val ARROW = 77; enter(ARROW, "=>")
+ final val SUBTYPE = 80; enter(SUBTYPE, "<:")
+ final val SUPERTYPE = 81; enter(SUPERTYPE, ">:")
+ final val HASH = 82; enter(HASH, "#")
+ final val VIEWBOUND = 84; enter(VIEWBOUND, "<%") // TODO: deprecate
+
/** XML mode */
final val XMLSTART = 96; enter(XMLSTART, "$XMLSTART$<") // TODO: deprecate
+ final val alphaKeywords = tokenRange(IF, FORSOME)
+ final val symbolicKeywords = tokenRange(USCORE, VIEWBOUND)
+ final val symbolicTokens = tokenRange(COMMA, VIEWBOUND)
+ final val keywords = alphaKeywords | symbolicKeywords
+
final val allTokens = tokenRange(minToken, maxToken)
final val literalTokens = tokenRange(CHARLIT, SYMBOLLIT) | BitSet(TRUE, FALSE, NULL)
diff --git a/src/dotty/tools/dotc/transform/ElimRepeated.scala b/src/dotty/tools/dotc/transform/ElimRepeated.scala
index 03fd28a26..ff56ae872 100644
--- a/src/dotty/tools/dotc/transform/ElimRepeated.scala
+++ b/src/dotty/tools/dotc/transform/ElimRepeated.scala
@@ -4,13 +4,15 @@ package transform
import core._
import Names._
import Types._
-import TreeTransforms.{TransformerInfo, MiniPhaseTransform, TreeTransformer}
+import dotty.tools.dotc.transform.TreeTransforms.{AnnotationTransformer, TransformerInfo, MiniPhaseTransform, TreeTransformer}
import ast.Trees.flatten
import Flags._
import Contexts.Context
import Symbols._
import Denotations._, SymDenotations._
import Decorators.StringInterpolators
+import dotty.tools.dotc.ast.tpd
+import dotty.tools.dotc.core.Annotations.ConcreteAnnotation
import scala.collection.mutable
import DenotTransformers._
import Names.Name
@@ -20,7 +22,7 @@ import TypeUtils._
/** A transformer that removes repeated parameters (T*) from all types, replacing
* them with Seq types.
*/
-class ElimRepeated extends MiniPhaseTransform with InfoTransformer { thisTransformer =>
+class ElimRepeated extends MiniPhaseTransform with InfoTransformer with AnnotationTransformer { thisTransformer =>
import ast.tpd._
override def phaseName = "elimRepeated"
@@ -34,9 +36,10 @@ class ElimRepeated extends MiniPhaseTransform with InfoTransformer { thisTransfo
case tp @ MethodType(paramNames, paramTypes) =>
val resultType1 = elimRepeated(tp.resultType)
val paramTypes1 =
- if (paramTypes.nonEmpty && paramTypes.last.isRepeatedParam)
- paramTypes.init :+ paramTypes.last.underlyingIfRepeated(tp.isJava)
- else paramTypes
+ if (paramTypes.nonEmpty && paramTypes.last.isRepeatedParam) {
+ val last = paramTypes.last.underlyingIfRepeated(tp.isJava)
+ paramTypes.init :+ last
+ } else paramTypes
tp.derivedMethodType(paramNames, paramTypes1, resultType1)
case tp: PolyType =>
tp.derivedPolyType(tp.paramNames, tp.paramBounds, elimRepeated(tp.resultType))
@@ -54,19 +57,20 @@ class ElimRepeated extends MiniPhaseTransform with InfoTransformer { thisTransfo
transformTypeOfTree(tree)
override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo): Tree =
- transformTypeOfTree(tree)
+ transformTypeOfTree(tree) // should also transform the tree if argument needs adaptation
override def transformTypeApply(tree: TypeApply)(implicit ctx: Context, info: TransformerInfo): Tree =
transformTypeOfTree(tree)
/** If method overrides a Java varargs method, add a varargs bridge.
+ * Also transform trees inside method annotation
*/
override def transformDefDef(tree: DefDef)(implicit ctx: Context, info: TransformerInfo): Tree = {
assert(ctx.phase == thisTransformer)
def overridesJava = tree.symbol.allOverriddenSymbols.exists(_ is JavaDefined)
if (tree.symbol.info.isVarArgsMethod && overridesJava)
- addVarArgsBridge(tree)(ctx.withPhase(thisTransformer.next))
- else
+ addVarArgsBridge(tree)(ctx.withPhase(thisTransformer.next))
+ else
tree
}
diff --git a/src/dotty/tools/dotc/transform/FirstTransform.scala b/src/dotty/tools/dotc/transform/FirstTransform.scala
index 7687be457..29cef09fe 100644
--- a/src/dotty/tools/dotc/transform/FirstTransform.scala
+++ b/src/dotty/tools/dotc/transform/FirstTransform.scala
@@ -3,7 +3,7 @@ package transform
import core._
import Names._
-import TreeTransforms.{TransformerInfo, MiniPhaseTransform, TreeTransformer}
+import dotty.tools.dotc.transform.TreeTransforms.{AnnotationTransformer, TransformerInfo, MiniPhaseTransform, TreeTransformer}
import ast.Trees._
import Flags._
import Types._
@@ -12,6 +12,8 @@ import Contexts.Context
import Symbols._
import SymDenotations._
import Decorators._
+import dotty.tools.dotc.core.Annotations.ConcreteAnnotation
+import dotty.tools.dotc.core.Denotations.SingleDenotation
import scala.collection.mutable
import DenotTransformers._
import typer.Checking
@@ -26,12 +28,16 @@ import NameOps._
* - inserts `.package` for selections of package object members
* - checks the bounds of AppliedTypeTrees
* - stubs out native methods
+ * - removes java-defined ASTs
*/
-class FirstTransform extends MiniPhaseTransform with IdentityDenotTransformer { thisTransformer =>
+class FirstTransform extends MiniPhaseTransform with IdentityDenotTransformer with AnnotationTransformer { thisTransformer =>
import ast.tpd._
override def phaseName = "firstTransform"
+
+ def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context): Type = tp
+
override def checkPostCondition(tree: Tree)(implicit ctx: Context): Unit = tree match {
case Select(qual, _) if tree.symbol.exists =>
assert(qual.tpe derivesFrom tree.symbol.owner, i"non member selection of ${tree.symbol.showLocated} from ${qual.tpe}")
@@ -79,16 +85,21 @@ class FirstTransform extends MiniPhaseTransform with IdentityDenotTransformer {
Thicket(stat :: newCompanion(stat.name.toTermName).trees)
case stat => stat
}
- addMissingCompanions(reorder(stats))
+
+ def skipJava(stats: List[Tree]): List[Tree] = // packages get a JavaDefined flag. Dont skip them
+ stats.filter(t => !(t.symbol is(Flags.JavaDefined, Flags.Package)))
+
+ addMissingCompanions(reorder(skipJava(stats)))
}
- override def transformDefDef(ddef: DefDef)(implicit ctx: Context, info: TransformerInfo) =
+ override def transformDefDef(ddef: DefDef)(implicit ctx: Context, info: TransformerInfo) = {
if (ddef.symbol.hasAnnotation(defn.NativeAnnot)) {
ddef.symbol.resetFlag(Deferred)
DefDef(ddef.symbol.asTerm,
_ => ref(defn.Sys_error).withPos(ddef.pos)
.appliedTo(Literal(Constant("native method stub"))))
} else ddef
+ }
override def transformStats(trees: List[Tree])(implicit ctx: Context, info: TransformerInfo): List[Tree] =
ast.Trees.flatten(reorderAndComplete(trees)(ctx.withPhase(thisTransformer.next)))
@@ -107,6 +118,8 @@ class FirstTransform extends MiniPhaseTransform with IdentityDenotTransformer {
case _ => normalizeType(tree)
}
+
+
override def transformSelect(tree: Select)(implicit ctx: Context, info: TransformerInfo) =
normalizeType {
val qual = tree.qualifier
diff --git a/src/dotty/tools/dotc/transform/GettersSetters.scala b/src/dotty/tools/dotc/transform/GettersSetters.scala
index e1b4b59a0..bbe5740ff 100644
--- a/src/dotty/tools/dotc/transform/GettersSetters.scala
+++ b/src/dotty/tools/dotc/transform/GettersSetters.scala
@@ -102,7 +102,7 @@ import Decorators._
}
override def transformDefDef(tree: DefDef)(implicit ctx: Context, info: TransformerInfo): Tree =
- if (tree.symbol.isSetter && !tree.symbol.is(Deferred | ParamAccessor)) {
+ if (tree.symbol.isSetter && !tree.symbol.is(Deferred | ParamAccessor | JavaDefined)) {
val Literal(Constant(())) = tree.rhs
assert(tree.symbol.field.exists, i"no field for ${tree.symbol.showLocated}")
val initializer = Assign(ref(tree.symbol.field), ref(tree.vparamss.head.head.symbol))
diff --git a/src/dotty/tools/dotc/transform/Memoize.scala b/src/dotty/tools/dotc/transform/Memoize.scala
index ef70b9ecf..f4b00d6a5 100644
--- a/src/dotty/tools/dotc/transform/Memoize.scala
+++ b/src/dotty/tools/dotc/transform/Memoize.scala
@@ -82,5 +82,5 @@ import Decorators._
// neither getters nor setters
else tree
}
- private val NoFieldNeeded = Lazy | Deferred | ParamAccessor
+ private val NoFieldNeeded = Lazy | Deferred | ParamAccessor | JavaDefined
} \ No newline at end of file
diff --git a/src/dotty/tools/dotc/transform/TreeChecker.scala b/src/dotty/tools/dotc/transform/TreeChecker.scala
index dd84cd53a..5c45f4fc5 100644
--- a/src/dotty/tools/dotc/transform/TreeChecker.scala
+++ b/src/dotty/tools/dotc/transform/TreeChecker.scala
@@ -67,19 +67,39 @@ class TreeChecker {
class Checker(phasesToCheck: Seq[Phase]) extends ReTyper {
- val definedSyms = new mutable.HashSet[Symbol]
+ val nowDefinedSyms = new mutable.HashSet[Symbol]
+ val everDefinedSyms = new mutable.HashMap[Symbol, Tree]
+
+ def withDefinedSym[T](tree: untpd.Tree)(op: => T)(implicit ctx: Context): T = tree match {
+ case tree: DefTree =>
+ val sym = tree.symbol
+ everDefinedSyms.get(sym) match {
+ case Some(t) =>
+ if(t ne tree)
+ ctx.warning(i"symbol ${sym.fullName} is defined at least twice in different parts of AST")
+ // should become an error
+ case None =>
+ everDefinedSyms(sym) = tree
+ }
+ assert(!nowDefinedSyms.contains(sym), i"doubly defined symbol: ${sym.fullName} in $tree")
+
+ if(ctx.settings.YcheckMods.value) {
+ tree match {
+ case t: MemberDef =>
+ if (t.name ne sym.name) ctx.warning(s"symbol ${sym.fullName} name doesn't correspond to AST: ${t}")
+ if (sym.flags != t.mods.flags) ctx.warning(s"symbol ${sym.fullName} flags ${sym.flags} doesn't match AST definition flags ${t.mods.flags}")
+ // todo: compare trees inside annotations
+ case _ =>
+ }
+ }
- def withDefinedSym[T](tree: untpd.Tree)(op: => T)(implicit ctx: Context): T = {
- if (tree.isDef) {
- assert(!definedSyms.contains(tree.symbol), i"doubly defined symbol: ${tree.symbol}in $tree")
- definedSyms += tree.symbol
+ nowDefinedSyms += tree.symbol
//println(i"defined: ${tree.symbol}")
val res = op
- definedSyms -= tree.symbol
+ nowDefinedSyms -= tree.symbol
//println(i"undefined: ${tree.symbol}")
res
- }
- else op
+ case _ => op
}
def withDefinedSyms[T](trees: List[untpd.Tree])(op: => T)(implicit ctx: Context) =
@@ -90,7 +110,7 @@ class TreeChecker {
def assertDefined(tree: untpd.Tree)(implicit ctx: Context) =
if (tree.symbol.maybeOwner.isTerm)
- assert(definedSyms contains tree.symbol, i"undefined symbol ${tree.symbol}")
+ assert(nowDefinedSyms contains tree.symbol, i"undefined symbol ${tree.symbol}")
override def typedUnadapted(tree: untpd.Tree, pt: Type)(implicit ctx: Context): tpd.Tree = {
val res = tree match {
diff --git a/src/dotty/tools/dotc/transform/TreeTransform.scala b/src/dotty/tools/dotc/transform/TreeTransform.scala
index d3d8a183b..3869adf6c 100644
--- a/src/dotty/tools/dotc/transform/TreeTransform.scala
+++ b/src/dotty/tools/dotc/transform/TreeTransform.scala
@@ -2,8 +2,12 @@ package dotty.tools.dotc
package transform
import dotty.tools.dotc.ast.tpd
+import dotty.tools.dotc.core.Annotations.ConcreteAnnotation
import dotty.tools.dotc.core.Contexts.Context
+import dotty.tools.dotc.core.DenotTransformers.{InfoTransformer, DenotTransformer}
+import dotty.tools.dotc.core.Denotations.SingleDenotation
import dotty.tools.dotc.core.Phases.Phase
+import dotty.tools.dotc.core.SymDenotations.SymDenotation
import dotty.tools.dotc.core.Symbols.Symbol
import dotty.tools.dotc.core.Flags.PackageVal
import dotty.tools.dotc.typer.Mode
@@ -169,6 +173,26 @@ object TreeTransforms {
def phase = this
}
+ /** A helper trait to transform annotations on MemberDefs */
+ trait AnnotationTransformer extends MiniPhaseTransform with InfoTransformer {
+
+ val annotationTransformer = mkTreeTransformer
+
+ override def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation = {
+ val info1 = transformInfo(ref.info, ref.symbol)
+
+ ref match {
+ case ref: SymDenotation =>
+ val annotTrees = ref.annotations.map(_.tree)
+ val annotTrees1 = annotTrees.mapConserve(annotationTransformer.macroTransform)
+ val annots1 = if(annotTrees eq annotTrees1) ref.annotations else annotTrees1.map(new ConcreteAnnotation(_))
+ if ((info1 eq ref.info) && (annots1 eq ref.annotations)) ref
+ else ref.copySymDenotation(info = info1, annotations = annots1)
+ case _ => if (info1 eq ref.info) ref else ref.derivedSingleDenotation(ref.symbol, info1)
+ }
+ }
+ }
+
val NoTransform = new TreeTransform {
def phase = unsupported("phase")
idx = -1
diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala
index 931acb4b5..9b2e64f35 100644
--- a/src/dotty/tools/dotc/typer/Applications.scala
+++ b/src/dotty/tools/dotc/typer/Applications.scala
@@ -388,6 +388,14 @@ trait Applications extends Compatibility { self: Typer =>
def isVarArg(arg: Tree): Boolean = tpd.isWildcardStarArg(arg)
}
+ /** Subclass of Application for applicability tests with type arguments and value
+ * argument trees.
+ */
+ class ApplicableToTreesDirectly(methRef: TermRef, targs: List[Type], args: List[Tree], resultType: Type)(implicit ctx: Context) extends ApplicableToTrees(methRef, targs, args, resultType)(ctx) {
+ override def addArg(arg: TypedArg, formal: Type) =
+ ok = ok & (argType(arg, formal) <:< formal)
+ }
+
/** Subclass of Application for applicability tests with value argument types. */
class ApplicableToTypes(methRef: TermRef, args: List[Type], resultType: Type)(implicit ctx: Context)
extends TestApplication(methRef, methRef, args, resultType) {
@@ -754,6 +762,14 @@ trait Applications extends Compatibility { self: Typer =>
new ApplicableToTrees(methRef, targs, args, resultType)(nestedContext).success
}
+ /** Is given method reference applicable to type arguments `targs` and argument trees `args` without invfering views?
+ * @param resultType The expected result type of the application
+ */
+ def isDirectlyApplicable(methRef: TermRef, targs: List[Type], args: List[Tree], resultType: Type)(implicit ctx: Context): Boolean = {
+ val nestedContext = ctx.fresh.setExploreTyperState
+ new ApplicableToTreesDirectly(methRef, targs, args, resultType)(nestedContext).success
+ }
+
/** Is given method reference applicable to argument types `args`?
* @param resultType The expected result type of the application
*/
@@ -948,7 +964,10 @@ trait Applications extends Compatibility { self: Typer =>
}
def narrowByTrees(alts: List[TermRef], args: List[Tree], resultType: Type): List[TermRef] =
- alts filter (isApplicable(_, targs, args, resultType))
+ alts filter ( alt =>
+ if (!ctx.isAfterTyper) isApplicable(alt, targs, args, resultType)
+ else isDirectlyApplicable(alt, targs, args, resultType)
+ )
val alts1 = narrowBySize(alts)
//ctx.log(i"narrowed by size: ${alts1.map(_.symbol.showDcl)}%, %")
diff --git a/src/dotty/tools/dotc/typer/Checking.scala b/src/dotty/tools/dotc/typer/Checking.scala
index 4466e05ed..982b97f7e 100644
--- a/src/dotty/tools/dotc/typer/Checking.scala
+++ b/src/dotty/tools/dotc/typer/Checking.scala
@@ -182,7 +182,9 @@ trait Checking {
def checkValue(tree: Tree, proto: Type)(implicit ctx: Context): tree.type = {
if (!proto.isInstanceOf[SelectionProto]) {
val sym = tree.tpe.termSymbol
- if ((sym is Package) || (sym is JavaModule)) ctx.error(d"$sym is not a value", tree.pos)
+ // The check is avoided inside Java compilation units because it always fails
+ // on the singleton type Module.type.
+ if ((sym is Package) || ((sym is JavaModule) && !ctx.compilationUnit.isJava)) ctx.error(d"$sym is not a value", tree.pos)
}
tree
}
diff --git a/src/dotty/tools/dotc/typer/FrontEnd.scala b/src/dotty/tools/dotc/typer/FrontEnd.scala
index 4f3b03fa1..d276792e7 100644
--- a/src/dotty/tools/dotc/typer/FrontEnd.scala
+++ b/src/dotty/tools/dotc/typer/FrontEnd.scala
@@ -4,6 +4,7 @@ package typer
import core._
import Phases._
import Contexts._
+import dotty.tools.dotc.parsing.JavaParsers.JavaParser
import parsing.Parsers.Parser
import config.Printers._
import util.Stats._
@@ -22,7 +23,9 @@ class FrontEnd extends Phase {
def parse(implicit ctx: Context) = monitor("parsing") {
val unit = ctx.compilationUnit
- unit.untpdTree = new Parser(unit.source).parse()
+ unit.untpdTree =
+ if(unit.isJava) new JavaParser(unit.source).parse()
+ else new Parser(unit.source).parse()
typr.println("parsed:\n"+unit.untpdTree.show)
}
diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala
index 0ca681d32..bc64e10fc 100644
--- a/src/dotty/tools/dotc/typer/Namer.scala
+++ b/src/dotty/tools/dotc/typer/Namer.scala
@@ -243,7 +243,10 @@ class Namer { typer: Typer =>
// different: The former must have the class as owner (because the
// constructor is owned by the class), the latter must not (because
// constructor parameters are interpreted as if they are outside the class).
- val cctx = if (tree.name == nme.CONSTRUCTOR) ctx.outer else ctx
+ // Don't do this for Java constructors because they need to see the import
+ // of the companion object, and it is not necessary for them because they
+ // have no implementation.
+ val cctx = if (tree.name == nme.CONSTRUCTOR && !(tree.mods is JavaDefined)) ctx.outer else ctx
record(ctx.newSymbol(
ctx.owner, name, tree.mods.flags | deferred | method | higherKinded | inSuperCall1,
diff --git a/src/dotty/tools/dotc/typer/ProtoTypes.scala b/src/dotty/tools/dotc/typer/ProtoTypes.scala
index 0aa0aa538..8d29916fa 100644
--- a/src/dotty/tools/dotc/typer/ProtoTypes.scala
+++ b/src/dotty/tools/dotc/typer/ProtoTypes.scala
@@ -227,6 +227,16 @@ object ProtoTypes {
override def deepenProto(implicit ctx: Context) = derivedFunProto(args, resultType.deepenProto, typer)
}
+
+ /** A prototype for expressions that appear in function position
+ *
+ * [](args): resultType, where args are known to be typed
+ */
+ class FunProtoTyped(args: List[tpd.Tree], resultType: Type, typer: Typer)(implicit ctx: Context) extends FunProto(args, resultType, typer)(ctx) {
+ override def typedArgs = args
+ override def argsAreTyped = true
+ }
+
/** A prototype for implicitly inferred views:
*
* []: argType => resultType
@@ -311,7 +321,7 @@ object ProtoTypes {
yield new TypeVar(PolyParam(pt, n), state, owningTree)
val added =
- if (state.constraint contains pt) pt.copy(pt.paramNames, pt.paramBounds, pt.resultType)
+ if (state.constraint contains pt) pt.duplicate(pt.paramNames, pt.paramBounds, pt.resultType)
else pt
val tvars = if (owningTree.isEmpty) Nil else newTypeVars(added)
state.constraint = state.constraint.add(added, tvars)
diff --git a/src/dotty/tools/dotc/typer/TypeAssigner.scala b/src/dotty/tools/dotc/typer/TypeAssigner.scala
index 765c6bea7..6c5e48edb 100644
--- a/src/dotty/tools/dotc/typer/TypeAssigner.scala
+++ b/src/dotty/tools/dotc/typer/TypeAssigner.scala
@@ -323,11 +323,14 @@ trait TypeAssigner {
def assignType(tree: untpd.Throw)(implicit ctx: Context) =
tree.withType(defn.NothingType)
- def assignType(tree: untpd.SeqLiteral, elems: List[Tree])(implicit ctx: Context) = {
- val ownType =
- if (ctx.erasedTypes) defn.SeqType
- else defn.SeqType.appliedTo(ctx.typeComparer.lub(elems.tpes).widen)
- tree.withType(ownType)
+ def assignType(tree: untpd.SeqLiteral, elems: List[Tree])(implicit ctx: Context) = tree match {
+ case tree: JavaSeqLiteral =>
+ tree.withType(defn.ArrayClass.typeRef.appliedTo(ctx.typeComparer.lub(elems.tpes)))
+ case _ =>
+ val ownType =
+ if (ctx.erasedTypes) defn.SeqType
+ else defn.SeqType.appliedTo(ctx.typeComparer.lub(elems.tpes).widen)
+ tree.withType(ownType)
}
def assignType(tree: untpd.SingletonTypeTree, ref: Tree)(implicit ctx: Context) =
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index 93a8dff7d..4bb6e172b 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -169,9 +169,11 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
selectors match {
case Pair(Ident(from), Ident(Name)) :: rest =>
val selName = if (name.isTypeName) from.toTypeName else from
- checkUnambiguous(selectionType(site, selName, tree.pos))
+ // Pass refctx so that any errors are reported in the context of the
+ // reference instead of the context of the import.
+ checkUnambiguous(selectionType(site, selName, tree.pos)(refctx))
case Ident(Name) :: rest =>
- checkUnambiguous(selectionType(site, name, tree.pos))
+ checkUnambiguous(selectionType(site, name, tree.pos)(refctx))
case _ :: rest =>
namedImportRef(site, rest)
case nil =>
@@ -279,9 +281,38 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
}
def typedSelect(tree: untpd.Select, pt: Type)(implicit ctx: Context): Tree = track("typedSelect") {
- val qual1 = typedExpr(tree.qualifier, selectionProto(tree.name, pt, this))
- if (tree.name.isTypeName) checkStable(qual1.tpe, qual1.pos)
- checkValue(assignType(cpy.Select(tree)(qual1, tree.name), qual1), pt)
+ def asSelect(implicit ctx: Context): Tree = {
+ val qual1 = typedExpr(tree.qualifier, selectionProto(tree.name, pt, this))
+ if (tree.name.isTypeName) checkStable(qual1.tpe, qual1.pos)
+ checkValue(assignType(cpy.Select(tree)(qual1, tree.name), qual1), pt)
+ }
+
+ def asJavaSelectFromTypeTree(implicit ctx: Context): Tree = {
+ // Translate names in Select/Ident nodes to type names.
+ def convertToTypeName(tree: untpd.Tree): Option[untpd.Tree] = tree match {
+ case Select(qual, name) => Some(untpd.Select(qual, name.toTypeName))
+ case Ident(name) => Some(untpd.Ident(name.toTypeName))
+ case _ => None
+ }
+
+ // Try to convert Select(qual, name) to a SelectFromTypeTree.
+ def convertToSelectFromType(qual: untpd.Tree, origName: Name): Option[untpd.SelectFromTypeTree] =
+ convertToTypeName(qual) match {
+ case Some(qual1) => Some(untpd.SelectFromTypeTree(qual1 withPos qual.pos, origName.toTypeName))
+ case _ => None
+ }
+
+ convertToSelectFromType(tree.qualifier, tree.name) match {
+ case Some(sftt) => typedSelectFromTypeTree(sftt, pt)
+ case _ => ctx.error(d"Could not convert $tree to a SelectFromTypeTree"); EmptyTree
+ }
+ }
+
+ if(ctx.compilationUnit.isJava && tree.name.isTypeName) {
+ // SI-3120 Java uses the same syntax, A.B, to express selection from the
+ // value A and from the type A. We have to try both.
+ tryEither(tryCtx => asSelect(tryCtx))((_,_) => asJavaSelectFromTypeTree(ctx))
+ } else asSelect(ctx)
}
def typedSelectFromTypeTree(tree: untpd.SelectFromTypeTree, pt: Type)(implicit ctx: Context): Tree = track("typedSelectFromTypeTree") {