From 1e1f260577d8522a5c99052cea5b3ebe64a12830 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 10 Oct 2014 16:25:26 +0200 Subject: [PATCH 01/46] Add the right constructor to Java annotations --- src/dotty/tools/dotc/core/Flags.scala | 2 +- src/dotty/tools/dotc/core/Types.scala | 2 +- .../dotc/core/pickling/ClassfileParser.scala | 40 +++++++++++++++++++ tests/pos/annot.scala | 11 +++++ 4 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 tests/pos/annot.scala diff --git a/src/dotty/tools/dotc/core/Flags.scala b/src/dotty/tools/dotc/core/Flags.scala index db969767b8c4..c966f0d61e81 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, "") - /** A method that has default params */ // TODO: drop + /** A method that has default params */ final val DefaultParameterized = termFlag(27, "") /** Symbol is initialized to the default value, e.g. var x: T = _ */ diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index aa8036fc5972..7dba8c0269b2 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -2026,7 +2026,7 @@ object Types { if ((paramNames eq this.paramNames) && (paramBounds eq this.paramBounds) && (restpe eq this.resultType)) this else copy(paramNames, paramBounds, restpe) - def copy(paramNames: List[TypeName], paramBounds: List[TypeBounds], restpe: Type)(implicit ctx: Context) = + def copy(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 8dd9314ee5cc..fb5a6309b30c 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) } @@ -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/tests/pos/annot.scala b/tests/pos/annot.scala new file mode 100644 index 000000000000..cda24e05daaf --- /dev/null +++ b/tests/pos/annot.scala @@ -0,0 +1,11 @@ +import java.beans.Transient + +class Test { + + @SuppressWarnings(Array("hi")) def foo() = ??? + + @Transient(false) def bar = ??? + + @Transient() def baz = ??? +} + From 9760fb7bbb5ceaeba98b6625470bd9f03755a31d Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Sat, 11 Oct 2014 12:10:37 +0200 Subject: [PATCH 02/46] Testcase that shows bug in ElimRepeated. --- tests/pos/repeatedArgs.scala | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 tests/pos/repeatedArgs.scala diff --git a/tests/pos/repeatedArgs.scala b/tests/pos/repeatedArgs.scala new file mode 100644 index 000000000000..f9abb4aee70e --- /dev/null +++ b/tests/pos/repeatedArgs.scala @@ -0,0 +1,3 @@ +object testRepeated { + def foo = java.lang.System.out.format("%4$2s %3$2s %2$2s %1$2s", "a", "b", "c", "d") +} From cda5addb0e4fca124e0cedcb80237dd7f39ac0b7 Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Sat, 11 Oct 2014 12:21:12 +0200 Subject: [PATCH 03/46] Fix elimRepeated not transforming annotations. --- .../tools/dotc/transform/ElimRepeated.scala | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/dotty/tools/dotc/transform/ElimRepeated.scala b/src/dotty/tools/dotc/transform/ElimRepeated.scala index 03fd28a2602c..7f2492d3cd03 100644 --- a/src/dotty/tools/dotc/transform/ElimRepeated.scala +++ b/src/dotty/tools/dotc/transform/ElimRepeated.scala @@ -11,6 +11,7 @@ import Contexts.Context import Symbols._ import Denotations._, SymDenotations._ import Decorators.StringInterpolators +import dotty.tools.dotc.core.Annotations.ConcreteAnnotation import scala.collection.mutable import DenotTransformers._ import Names.Name @@ -25,6 +26,34 @@ class ElimRepeated extends MiniPhaseTransform with InfoTransformer { thisTransfo override def phaseName = "elimRepeated" + object annotTransformer extends TreeMap { + override def transform(tree: Tree)(implicit ctx: Context): Tree = super.transform(tree) match { + case x @(_: Ident|_ :Select|_: Apply| _: TypeApply| _: DefDef) => transformTypeOfTree(x) + case x => x + } + } + + /** + * Overriden to solve a particular problem with not being eliminated inside annotation trees + * Dmitry: this should solve problem for now, + * following YAGNI principle I am convinced that we shouldn't make a solution + * for a generalized problem(transforming annotations trees) + * that manifests itself only here. + */ + 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(annotTransformer.transform) + 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) + } + } + def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context): Type = elimRepeated(tp) From 7e7b2f2927aac6b17883e69b85ccccf2dfcab51a Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Wed, 29 Oct 2014 17:22:17 +0100 Subject: [PATCH 04/46] Add Id's to types. Helps to track where erroneous type was created. --- src/dotty/tools/dotc/core/Types.scala | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index 7dba8c0269b2..b4603a34a014 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 From 3c14254d9e8ef9ee1e586ee5f86e3b27771d7dd4 Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Wed, 29 Oct 2014 17:23:01 +0100 Subject: [PATCH 05/46] Fix typeAssigner ignoring existence of JavaSeqLiteral --- src/dotty/tools/dotc/ast/tpd.scala | 4 ++-- src/dotty/tools/dotc/typer/TypeAssigner.scala | 13 ++++++++----- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala index 12d4ac5e4a07..c735f079c0e7 100644 --- a/src/dotty/tools/dotc/ast/tpd.scala +++ b/src/dotty/tools/dotc/ast/tpd.scala @@ -126,8 +126,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) diff --git a/src/dotty/tools/dotc/typer/TypeAssigner.scala b/src/dotty/tools/dotc/typer/TypeAssigner.scala index 765c6bea7f41..6c5e48edba75 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) = From 9bcb3a0bf17352efa22bd50c5d8738b79eeae72c Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Wed, 29 Oct 2014 17:25:28 +0100 Subject: [PATCH 06/46] Fix TypeErasure.sigName erasing java repeated params to Seq --- src/dotty/tools/dotc/TypeErasure.scala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/dotty/tools/dotc/TypeErasure.scala b/src/dotty/tools/dotc/TypeErasure.scala index 4a492560f581..81369f28d8e3 100644 --- a/src/dotty/tools/dotc/TypeErasure.scala +++ b/src/dotty/tools/dotc/TypeErasure.scala @@ -96,7 +96,9 @@ object TypeErasure { def semiErasure(tp: Type)(implicit ctx: Context): Type = semiErasureFn(tp)(erasureCtx) def sigName(tp: Type, isJava: Boolean)(implicit ctx: Context): TypeName = { val normTp = - if (tp.isRepeatedParam) tp.translateParameterized(defn.RepeatedParamClass, defn.SeqClass) + if (tp.isRepeatedParam) + if (isJava) tp.translateParameterized(defn.RepeatedParamClass, defn.ArrayClass) + else tp.translateParameterized(defn.RepeatedParamClass, defn.SeqClass) else tp (if (isJava) javaSigFn else scalaSigFn).sigName(normTp)(erasureCtx) } From cbe4f0a44739a26cfddc45bea33fee6246a240f5 Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Wed, 29 Oct 2014 17:26:13 +0100 Subject: [PATCH 07/46] Fix underlyingIfRepeated always assuming Scala repeated. --- src/dotty/tools/dotc/core/TypeApplications.scala | 7 +++++-- src/dotty/tools/dotc/transform/ElimRepeated.scala | 7 ++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/dotty/tools/dotc/core/TypeApplications.scala b/src/dotty/tools/dotc/core/TypeApplications.scala index bf756facfa28..3808cb17c55c 100644 --- a/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/src/dotty/tools/dotc/core/TypeApplications.scala @@ -283,9 +283,12 @@ class TypeApplications(val self: Type) extends AnyVal { /** If this is repeated parameter type, its underlying Seq type, * 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) + def underlyingIfRepeated(isJava: Boolean)(implicit ctx: Context): Type = { + if (self.isRepeatedParam) + if (isJava) translateParameterized(defn.RepeatedParamClass, defn.ArrayClass) + else translateParameterized(defn.RepeatedParamClass, defn.SeqClass) else self + } /** If this is an encoding of a (partially) applied type, return its arguments, * otherwise return Nil. diff --git a/src/dotty/tools/dotc/transform/ElimRepeated.scala b/src/dotty/tools/dotc/transform/ElimRepeated.scala index 7f2492d3cd03..ba2de659fe9f 100644 --- a/src/dotty/tools/dotc/transform/ElimRepeated.scala +++ b/src/dotty/tools/dotc/transform/ElimRepeated.scala @@ -63,9 +63,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)) From 3b0349bbf3986dc2e352a95f8eff898ea1714806 Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Thu, 30 Oct 2014 15:50:03 +0100 Subject: [PATCH 08/46] FunProtoTyped to be used when args are known to be typed --- src/dotty/tools/dotc/typer/ProtoTypes.scala | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/dotty/tools/dotc/typer/ProtoTypes.scala b/src/dotty/tools/dotc/typer/ProtoTypes.scala index 0aa0aa53814f..917c195fd1b9 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 From 998a5c8e6d6b0613c1e2c1f9f58d657f5332aad1 Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Thu, 30 Oct 2014 15:50:57 +0100 Subject: [PATCH 09/46] readAnnotationContents that should be able to resolve overloaded constructors. --- .../tools/dotc/core/pickling/UnPickler.scala | 48 ++++++++++++++----- 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/src/dotty/tools/dotc/core/pickling/UnPickler.scala b/src/dotty/tools/dotc/core/pickling/UnPickler.scala index 60000441c22c..627500035caf 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 @@ -814,19 +815,42 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot: * readAnnotation, readSymbolAnnotation, or readAnnotInfoArg */ 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) + ctx.atPhase(ctx.typerPhase) { implicit ctx => // needed to enable implicit search + // and fix circullar dependency between annotation.currect invoking + // elimrepeated that reads the same annotation + + val atp = readTypeRef() + 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 } + println(atp) + val typer = ctx.typer + val proto = new FunProtoTyped(args, atp, typer) + val alts = atp.member(nme.CONSTRUCTOR).alternatives.map(_.termRef) + + val constructors = ctx.typer.resolveOverloaded(alts, proto) + assert(constructors.size == 1) // this is parsed from bytecode tree. there's nothing user can do about it + + val constr = constructors.head + val targs = atp.argTypes + val fun = tpd.New(atp withoutArgs targs) + .select(TermRef.withSig(atp.normalizedPrefix, constr.termSymbol.asTerm)) + .appliedToTypes(targs) + val apply = untpd.Apply(fun, args) + new typer.ApplyToTyped(apply, fun, constr, args, atp).result // needed to handle varargs } - New(atp, args.toList) } /** Read an annotation and as a side effect store it into From 12209dd492f7cf203030fd86d53cd6be6bd77464 Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Thu, 30 Oct 2014 16:13:03 +0100 Subject: [PATCH 10/46] Allow resolving overloads without inferring views. --- src/dotty/tools/dotc/typer/Applications.scala | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala index 931acb4b533a..3fd56640e16d 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 */ @@ -886,7 +902,7 @@ trait Applications extends Compatibility { self: Typer => * to form the method type. * todo: use techniques like for implicits to pick candidates quickly? */ - def resolveOverloaded(alts: List[TermRef], pt: Type, targs: List[Type] = Nil)(implicit ctx: Context): List[TermRef] = track("resolveOverloaded") { + def resolveOverloaded(alts: List[TermRef], pt: Type, targs: List[Type] = Nil, resolveImplicits: Boolean = true)(implicit ctx: Context): List[TermRef] = track("resolveOverloaded") { def isDetermined(alts: List[TermRef]) = alts.isEmpty || alts.tail.isEmpty @@ -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 (resolveImplicits) 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)}%, %") From 68dfe2a7619edfb9829876643c9177723a40bb84 Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Thu, 30 Oct 2014 16:13:51 +0100 Subject: [PATCH 11/46] Fix StackOveflow due to implicit resolution in readAnnotationContents --- src/dotty/tools/dotc/core/pickling/UnPickler.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dotty/tools/dotc/core/pickling/UnPickler.scala b/src/dotty/tools/dotc/core/pickling/UnPickler.scala index 627500035caf..b165f91faf77 100644 --- a/src/dotty/tools/dotc/core/pickling/UnPickler.scala +++ b/src/dotty/tools/dotc/core/pickling/UnPickler.scala @@ -840,7 +840,7 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot: val proto = new FunProtoTyped(args, atp, typer) val alts = atp.member(nme.CONSTRUCTOR).alternatives.map(_.termRef) - val constructors = ctx.typer.resolveOverloaded(alts, proto) + val constructors = ctx.typer.resolveOverloaded(alts, proto, Nil, false) assert(constructors.size == 1) // this is parsed from bytecode tree. there's nothing user can do about it val constr = constructors.head From 11449db93f426a3fc64eded180852661d889804e Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Thu, 30 Oct 2014 16:20:57 +0100 Subject: [PATCH 12/46] Infer if overloading resolution should trigger implicit search. This doesn't require additional argument. Decision can be made solely from the phaseId. --- .../tools/dotc/core/pickling/UnPickler.scala | 61 +++++++++---------- src/dotty/tools/dotc/typer/Applications.scala | 4 +- 2 files changed, 30 insertions(+), 35 deletions(-) diff --git a/src/dotty/tools/dotc/core/pickling/UnPickler.scala b/src/dotty/tools/dotc/core/pickling/UnPickler.scala index b165f91faf77..aa277d6b09fc 100644 --- a/src/dotty/tools/dotc/core/pickling/UnPickler.scala +++ b/src/dotty/tools/dotc/core/pickling/UnPickler.scala @@ -815,42 +815,37 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot: * readAnnotation, readSymbolAnnotation, or readAnnotInfoArg */ protected def readAnnotationContents(end: Int)(implicit ctx: Context): Tree = { - ctx.atPhase(ctx.typerPhase) { implicit ctx => // needed to enable implicit search - // and fix circullar dependency between annotation.currect invoking - // elimrepeated that reads the same annotation - - val atp = readTypeRef() - 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) - } + val atp = readTypeRef() + 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 } - println(atp) - val typer = ctx.typer - val proto = new FunProtoTyped(args, atp, typer) - val alts = atp.member(nme.CONSTRUCTOR).alternatives.map(_.termRef) - - val constructors = ctx.typer.resolveOverloaded(alts, proto, Nil, false) - assert(constructors.size == 1) // this is parsed from bytecode tree. there's nothing user can do about it - - val constr = constructors.head - val targs = atp.argTypes - val fun = tpd.New(atp withoutArgs targs) - .select(TermRef.withSig(atp.normalizedPrefix, constr.termSymbol.asTerm)) - .appliedToTypes(targs) - val apply = untpd.Apply(fun, args) - new typer.ApplyToTyped(apply, fun, constr, args, atp).result // needed to handle varargs + t.toList } + println(atp) + val typer = ctx.typer + val proto = new FunProtoTyped(args, atp, typer) + val alts = atp.member(nme.CONSTRUCTOR).alternatives.map(_.termRef) + + val constructors = ctx.typer.resolveOverloaded(alts, proto, Nil) + assert(constructors.size == 1) // this is parsed from bytecode tree. there's nothing user can do about it + + val constr = constructors.head + val targs = atp.argTypes + val fun = tpd.New(atp withoutArgs targs) + .select(TermRef.withSig(atp.normalizedPrefix, constr.termSymbol.asTerm)) + .appliedToTypes(targs) + val apply = untpd.Apply(fun, args) + new typer.ApplyToTyped(apply, fun, constr, args, atp).result // needed to handle varargs } /** Read an annotation and as a side effect store it into diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala index 3fd56640e16d..9b2e64f356f0 100644 --- a/src/dotty/tools/dotc/typer/Applications.scala +++ b/src/dotty/tools/dotc/typer/Applications.scala @@ -902,7 +902,7 @@ trait Applications extends Compatibility { self: Typer => * to form the method type. * todo: use techniques like for implicits to pick candidates quickly? */ - def resolveOverloaded(alts: List[TermRef], pt: Type, targs: List[Type] = Nil, resolveImplicits: Boolean = true)(implicit ctx: Context): List[TermRef] = track("resolveOverloaded") { + def resolveOverloaded(alts: List[TermRef], pt: Type, targs: List[Type] = Nil)(implicit ctx: Context): List[TermRef] = track("resolveOverloaded") { def isDetermined(alts: List[TermRef]) = alts.isEmpty || alts.tail.isEmpty @@ -965,7 +965,7 @@ trait Applications extends Compatibility { self: Typer => def narrowByTrees(alts: List[TermRef], args: List[Tree], resultType: Type): List[TermRef] = alts filter ( alt => - if (resolveImplicits) isApplicable(alt, targs, args, resultType) + if (!ctx.isAfterTyper) isApplicable(alt, targs, args, resultType) else isDirectlyApplicable(alt, targs, args, resultType) ) From edee88013c1f400e52b474bd2541625d13bb2b8b Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Thu, 30 Oct 2014 16:21:16 +0100 Subject: [PATCH 13/46] Dotty typer deviation triggered in Unpickler --- src/dotty/tools/dotc/core/pickling/UnPickler.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/dotty/tools/dotc/core/pickling/UnPickler.scala b/src/dotty/tools/dotc/core/pickling/UnPickler.scala index aa277d6b09fc..fd752b5341f5 100644 --- a/src/dotty/tools/dotc/core/pickling/UnPickler.scala +++ b/src/dotty/tools/dotc/core/pickling/UnPickler.scala @@ -845,7 +845,8 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot: .select(TermRef.withSig(atp.normalizedPrefix, constr.termSymbol.asTerm)) .appliedToTypes(targs) val apply = untpd.Apply(fun, args) - new typer.ApplyToTyped(apply, fun, constr, args, atp).result // needed to handle varargs + new typer.ApplyToTyped(apply, fun, constr, args, atp).result.asInstanceOf[tpd.Tree] // needed to handle varargs + // Dotty deviation, for scalac the last cast wouldn't be required } /** Read an annotation and as a side effect store it into From a273c3f33a46b31be629cdbb60f4736642a420be Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Mon, 3 Nov 2014 11:55:51 +0100 Subject: [PATCH 14/46] Fix ElimRepeated not transforming modifiers in tree. --- src/dotty/tools/dotc/core/pickling/UnPickler.scala | 2 +- src/dotty/tools/dotc/transform/ElimRepeated.scala | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/dotty/tools/dotc/core/pickling/UnPickler.scala b/src/dotty/tools/dotc/core/pickling/UnPickler.scala index fd752b5341f5..c503f447b4fb 100644 --- a/src/dotty/tools/dotc/core/pickling/UnPickler.scala +++ b/src/dotty/tools/dotc/core/pickling/UnPickler.scala @@ -831,7 +831,7 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot: } t.toList } - println(atp) + // println(atp) val typer = ctx.typer val proto = new FunProtoTyped(args, atp, typer) val alts = atp.member(nme.CONSTRUCTOR).alternatives.map(_.termRef) diff --git a/src/dotty/tools/dotc/transform/ElimRepeated.scala b/src/dotty/tools/dotc/transform/ElimRepeated.scala index ba2de659fe9f..8bb2bdedf2d3 100644 --- a/src/dotty/tools/dotc/transform/ElimRepeated.scala +++ b/src/dotty/tools/dotc/transform/ElimRepeated.scala @@ -94,10 +94,13 @@ class ElimRepeated extends MiniPhaseTransform with InfoTransformer { thisTransfo override def transformDefDef(tree: DefDef)(implicit ctx: Context, info: TransformerInfo): Tree = { assert(ctx.phase == thisTransformer) def overridesJava = tree.symbol.allOverriddenSymbols.exists(_ is JavaDefined) + val newAnnots = tree.mods.annotations.mapConserve(annotTransformer.transform) + val newTree = if (newAnnots eq tree.mods.annotations) tree + else cpy.DefDef(tree)(mods = Modifiers(tree.mods.flags, tree.mods.privateWithin, newAnnots)) if (tree.symbol.info.isVarArgsMethod && overridesJava) - addVarArgsBridge(tree)(ctx.withPhase(thisTransformer.next)) + addVarArgsBridge(newTree)(ctx.withPhase(thisTransformer.next)) else - tree + newTree } /** Add a Java varargs bridge From 5a15ee9fde347787227a3fa8e31e17f32fd8a5bb Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Mon, 3 Nov 2014 13:51:57 +0100 Subject: [PATCH 15/46] Rename PolyType.copy method. It clashes with generated one. See #209 for explanation. --- src/dotty/tools/dotc/core/Types.scala | 4 ++-- src/dotty/tools/dotc/typer/ProtoTypes.scala | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index b4603a34a014..601870e55f44 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -2033,9 +2033,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] = this.paramNames, paramBounds: List[TypeBounds] = this.paramBounds, 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/typer/ProtoTypes.scala b/src/dotty/tools/dotc/typer/ProtoTypes.scala index 917c195fd1b9..8d29916fa71d 100644 --- a/src/dotty/tools/dotc/typer/ProtoTypes.scala +++ b/src/dotty/tools/dotc/typer/ProtoTypes.scala @@ -321,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) From e935eaa9220eff300ecca891d41c0c421501faf4 Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Mon, 3 Nov 2014 14:28:17 +0100 Subject: [PATCH 16/46] #204 check for global uniqueness of definitions. Check now fails after erasure. Should become error after fixed. --- .../tools/dotc/transform/TreeChecker.scala | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/dotty/tools/dotc/transform/TreeChecker.scala b/src/dotty/tools/dotc/transform/TreeChecker.scala index dd84cd53acdf..baaadb53f709 100644 --- a/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -67,19 +67,28 @@ class TreeChecker { class Checker(phasesToCheck: Seq[Phase]) extends ReTyper { - val definedSyms = new mutable.HashSet[Symbol] - - 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 + 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 ${tree.symbol} is defined at least twice in different parts of AST") + // should become an error + case None => + everDefinedSyms(sym) = tree + } + assert(!nowDefinedSyms.contains(tree.symbol), i"doubly defined symbol: ${tree.symbol}in $tree") + 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 +99,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 { From 35bf9148b6054c3651d597f90b7b721845e8734a Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Mon, 3 Nov 2014 14:42:55 +0100 Subject: [PATCH 17/46] Allow checking that trees and their defined symbols have modifiers in sync. --- src/dotty/tools/dotc/config/ScalaSettings.scala | 1 + src/dotty/tools/dotc/transform/TreeChecker.scala | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/dotty/tools/dotc/config/ScalaSettings.scala b/src/dotty/tools/dotc/config/ScalaSettings.scala index abde6cb5317f..05b936136aff 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/transform/TreeChecker.scala b/src/dotty/tools/dotc/transform/TreeChecker.scala index baaadb53f709..39f4bb067f23 100644 --- a/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -76,12 +76,23 @@ class TreeChecker { everDefinedSyms.get(sym) match { case Some(t) => if(t ne tree) - ctx.warning(i"symbol ${tree.symbol} is defined at least twice in different parts of AST") + ctx.warning(i"symbol ${sym} is defined at least twice in different parts of AST") // should become an error case None => everDefinedSyms(sym) = tree } - assert(!nowDefinedSyms.contains(tree.symbol), i"doubly defined symbol: ${tree.symbol}in $tree") + assert(!nowDefinedSyms.contains(sym), i"doubly defined symbol: ${sym} 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 _ => + } + } + nowDefinedSyms += tree.symbol //println(i"defined: ${tree.symbol}") val res = op From cc1d36f64d324b972ec3116f93c4f62fafd706bc Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Mon, 3 Nov 2014 14:52:01 +0100 Subject: [PATCH 18/46] Show full name of doubly defined symbols --- src/dotty/tools/dotc/transform/TreeChecker.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dotty/tools/dotc/transform/TreeChecker.scala b/src/dotty/tools/dotc/transform/TreeChecker.scala index 39f4bb067f23..5c45f4fc5651 100644 --- a/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -76,12 +76,12 @@ class TreeChecker { everDefinedSyms.get(sym) match { case Some(t) => if(t ne tree) - ctx.warning(i"symbol ${sym} is defined at least twice in different parts of AST") + 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} in $tree") + assert(!nowDefinedSyms.contains(sym), i"doubly defined symbol: ${sym.fullName} in $tree") if(ctx.settings.YcheckMods.value) { tree match { From 03627e71d9fdc4b2211d244cc8fd844d57997357 Mon Sep 17 00:00:00 2001 From: Ondrej Lhotak Date: Thu, 4 Sep 2014 17:06:02 +0200 Subject: [PATCH 19/46] Initial implementation of Java scanner and parser Ported from scalac 2.11.x branch SHA 9753f23f9362b25a9f481b11dd8d51187187882a This is mostly a direct port, with few significant dotty-specific changes needed. The two more significant changes are: In dotty, the first constructor of a class is pulled out separately from the other stats in the Template. The keyword detection code (buildKeywordArray) was moved into Tokens so that it can more cleanly be shared by the Scala and Java scanners. --- src/dotty/tools/dotc/core/Flags.scala | 9 + .../tools/dotc/parsing/JavaParsers.scala | 887 ++++++++++++++++++ .../tools/dotc/parsing/JavaScanners.scala | 537 +++++++++++ src/dotty/tools/dotc/parsing/JavaTokens.scala | 92 ++ src/dotty/tools/dotc/parsing/Parsers.scala | 90 +- src/dotty/tools/dotc/parsing/Scanners.scala | 233 +++-- src/dotty/tools/dotc/parsing/Tokens.scala | 143 ++- src/dotty/tools/dotc/typer/Checking.scala | 2 +- src/dotty/tools/dotc/typer/FrontEnd.scala | 5 +- 9 files changed, 1794 insertions(+), 204 deletions(-) create mode 100644 src/dotty/tools/dotc/parsing/JavaParsers.scala create mode 100644 src/dotty/tools/dotc/parsing/JavaScanners.scala create mode 100644 src/dotty/tools/dotc/parsing/JavaTokens.scala diff --git a/src/dotty/tools/dotc/core/Flags.scala b/src/dotty/tools/dotc/core/Flags.scala index c966f0d61e81..0e86a293638d 100644 --- a/src/dotty/tools/dotc/core/Flags.scala +++ b/src/dotty/tools/dotc/core/Flags.scala @@ -356,6 +356,12 @@ object Flags { /** Symbol is a Java-style varargs method */ final val JavaVarargs = termFlag(37, "") + /** Symbol is a Java default method */ + final val DefaultMethod = termFlag(38, "") + + /** Symbol is a Java enum */ + final val Enum = commonFlag(40, "") + // 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/parsing/JavaParsers.scala b/src/dotty/tools/dotc/parsing/JavaParsers.scala new file mode 100644 index 000000000000..095342c48291 --- /dev/null +++ b/src/dotty/tools/dotc/parsing/JavaParsers.scala @@ -0,0 +1,887 @@ +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]) = { + 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) + } + val (constr, stats1) = pullOutFirstConstr(stats) + val constr1 = if(constr == EmptyTree) makeConstructor(List(), tparams) else constr.asInstanceOf[DefDef] + Template(constr1, parents, EmptyValDef, stats1) + } + + def makeSyntheticParam(count: Int, tpt: Tree): ValDef = + makeParam(nme.syntheticParamName(count), tpt) + def makeParam(name: String, tpt: Tree): ValDef = + makeParam(name.toTermName, tpt) + def makeParam(name: TermName, tpt: Tree, flags: FlagSet = Flags.Param): ValDef = + ValDef(Modifiers(flags | Flags.JavaDefined), name, tpt, EmptyTree) + + def makeConstructor(formals: List[Tree], tparams: List[TypeDef]) = { + val vparams = mapWithIndex(formals)((p, i) => makeSyntheticParam(i + 1, p)) + DefDef(Modifiers(Flags.JavaDefined), nme.CONSTRUCTOR, tparams, List(vparams), TypeTree(), EmptyTree) + } + + // ------------- 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.Static + 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(Modifiers(flags), name, Nil, TypeBoundsTree(EmptyTree, hi)) + } + + 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, dontAddMutable = true) + } + + 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(mods, nme.CONSTRUCTOR, parentTParams, List(vparams), TypeTree(), methodBody()) + } + } + } 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(mods1 | Flags.Method, name.toTermName, tparams, List(vparams), rtpt, body) + } + } + } else { + if (inInterface) mods1 |= Flags.Final | Flags.Static + 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, dontAddMutable: Boolean = false): ValDef = { + val tpt1 = optArrayBrackets(tpt) + if (in.token == EQUALS && !(mods is Flags.Param)) skipTo(COMMA, SEMI) + val mods1 = if (mods is Flags.Final) mods &~ Flags.Final else if(dontAddMutable) mods else mods | Flags.Mutable + atPos(pos) { + ValDef(mods1, name, tpt1, EmptyTree) + } + } + + 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.Static else mods) + case _ => + termDecl(mods, parentToken, parentTParams) + } + + def makeCompanionObject(cdef: TypeDef, statics: List[Tree]): Tree = + atPos(cdef.pos) { + ModuleDef((cdef.mods & (Flags.AccessFlags | Flags.JavaDefined)).toTermFlags, cdef.name.toTermName, + makeTemplate(List(), statics, List())) + } + + 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.mods, cdef.name, + cpy.Template(template, template.constr, template.parents, template.self, + importCompanionObject(cdef) :: template.body), + cdef.tparams) + } + + 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(mods, name, makeTemplate(superclass :: interfaces, body, tparams)) + }) + } + + 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(mods | Flags.Trait | Flags.Interface | Flags.Abstract, + name, tparams, + makeTemplate(parents, body, tparams)) + }) + } + + 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.Static + val decls = memberDecl(mods, parentToken, parentTParams) + (if ((mods is Flags.Static) || inInterface && !(decls exists (_.isInstanceOf[DefDef]))) + statics + else + members) ++= decls + } + } + def forwarders(sdef: Tree): List[Tree] = sdef match { + case TypeDef(mods, name, _) if (parentToken == INTERFACE) => + var rhs: Tree = Select(Ident(parentName.toTermName), name) + List(TypeDef(Modifiers(Flags.Protected), name, rhs)) + 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, Flags.PrivateLocalParamAccessor) + } + val constr = DefDef(Modifiers(Flags.JavaDefined), nme.CONSTRUCTOR, + List(), List(constructorParams), TypeTree(), EmptyTree) + val body1 = body.filterNot(_.isInstanceOf[DefDef]) + val templ = makeTemplate(annotationParents, constr :: body1, List()) + addCompanionObject(statics, atPos(offset) { + TypeDef(mods, name, templ) + }) + } + + 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( + Modifiers(Flags.JavaDefined | Flags.Static | Flags.Method), nme.values, List(), + ListOfNil, + arrayOf(enumType), + unimplementedExpr), + DefDef( + Modifiers(Flags.JavaDefined | Flags.Static | Flags.Method), nme.valueOf, List(), + List(List(makeParam("x", TypeTree(StringType)))), + enumType, + unimplementedExpr)) + 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(mods | Flags.Enum, name, List(), + makeTemplate(superclazz :: interfaces, body, List())) + }) + } + + 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(Modifiers(Flags.Enum | Flags.Stable | Flags.JavaDefined | Flags.Static), name.toTermName, enumType, unimplementedExpr) + } + } + + 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 000000000000..faac8e1638ca --- /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 000000000000..9530e0516196 --- /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 1b08b7400868..e8a6fd815ba6 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 4d8fdd10de4d..5eb8357a41ff 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 09124d0d1886..226a3710db2b 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/typer/Checking.scala b/src/dotty/tools/dotc/typer/Checking.scala index 4466e05edff6..a0c43c568f4b 100644 --- a/src/dotty/tools/dotc/typer/Checking.scala +++ b/src/dotty/tools/dotc/typer/Checking.scala @@ -182,7 +182,7 @@ 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) + 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 4f3b03fa1775..d276792e76bf 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) } From ade0565fcdf6cb95818f538a95f798c7456d4c72 Mon Sep 17 00:00:00 2001 From: Ondrej Lhotak Date: Wed, 8 Oct 2014 11:49:19 +0200 Subject: [PATCH 20/46] desugar Java repeated parms into an Array instead of Seq --- src/dotty/tools/dotc/TypeErasure.scala | 5 ++--- src/dotty/tools/dotc/ast/Desugar.scala | 7 ++++--- src/dotty/tools/dotc/core/TypeApplications.scala | 10 +++++----- src/dotty/tools/dotc/core/Types.scala | 4 +++- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/dotty/tools/dotc/TypeErasure.scala b/src/dotty/tools/dotc/TypeErasure.scala index 81369f28d8e3..1786e2e291ea 100644 --- a/src/dotty/tools/dotc/TypeErasure.scala +++ b/src/dotty/tools/dotc/TypeErasure.scala @@ -95,10 +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) - if (isJava) tp.translateParameterized(defn.RepeatedParamClass, defn.ArrayClass) - else 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 b7786e00c428..1aab16469166 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/core/TypeApplications.scala b/src/dotty/tools/dotc/core/TypeApplications.scala index 3808cb17c55c..3beb680d9c92 100644 --- a/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/src/dotty/tools/dotc/core/TypeApplications.scala @@ -283,12 +283,12 @@ class TypeApplications(val self: Type) extends AnyVal { /** If this is repeated parameter type, its underlying Seq type, * or, if isJava is true, Array type, else the type itself. */ - def underlyingIfRepeated(isJava: Boolean)(implicit ctx: Context): Type = { - if (self.isRepeatedParam) - if (isJava) translateParameterized(defn.RepeatedParamClass, defn.ArrayClass) - else translateParameterized(defn.RepeatedParamClass, defn.SeqClass) + def underlyingIfRepeated(isJava: Boolean)(implicit ctx: Context): Type = + 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, * otherwise return Nil. diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index 601870e55f44..2997e9e779a6 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -1974,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 } From 07c4c96aff715a4ec856ccec405f92448a8610e0 Mon Sep 17 00:00:00 2001 From: Ondrej Lhotak Date: Wed, 8 Oct 2014 16:21:31 +0200 Subject: [PATCH 21/46] Java Select: try typing as both SelectFromTypeTree and Select --- src/dotty/tools/dotc/typer/Typer.scala | 41 ++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 93a8dff7d9ff..fa8ea6ec2c27 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -169,9 +169,9 @@ 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)) + 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 +279,40 @@ 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) => + println(s"$tree converted to $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") { From 2c5959b3a52b468e123a1f75d47cf053ce1e272a Mon Sep 17 00:00:00 2001 From: Ondrej Lhotak Date: Wed, 8 Oct 2014 16:55:49 +0200 Subject: [PATCH 22/46] support running java-interop tests --- test/dotc/tests.scala | 7 +++++++ test/test/CompilerTest.scala | 6 +++--- .../java-interop/{pos => failing}/t1751/A1_2.scala | 0 .../java-interop/{pos => failing}/t1751/A2_1.scala | 0 .../java-interop/{pos => failing}/t1751/SuiteClasses.java | 0 tests/disabled/java-interop/{pos => failing}/t2409/J.java | 0 .../java-interop/{pos => failing}/t2409/t2409.scala | 0 tests/disabled/java-interop/{pos => failing}/t294/Ann.java | 0 .../disabled/java-interop/{pos => failing}/t294/Ann2.java | 0 .../java-interop/{pos => failing}/t294/Test_1.scala | 0 .../java-interop/{pos => failing}/t294/Test_2.scala | 0 tests/disabled/java-interop/pos/t1782/Test_1.scala | 2 +- 12 files changed, 11 insertions(+), 4 deletions(-) rename tests/disabled/java-interop/{pos => failing}/t1751/A1_2.scala (100%) rename tests/disabled/java-interop/{pos => failing}/t1751/A2_1.scala (100%) rename tests/disabled/java-interop/{pos => failing}/t1751/SuiteClasses.java (100%) rename tests/disabled/java-interop/{pos => failing}/t2409/J.java (100%) rename tests/disabled/java-interop/{pos => failing}/t2409/t2409.scala (100%) rename tests/disabled/java-interop/{pos => failing}/t294/Ann.java (100%) rename tests/disabled/java-interop/{pos => failing}/t294/Ann2.java (100%) rename tests/disabled/java-interop/{pos => failing}/t294/Test_1.scala (100%) rename tests/disabled/java-interop/{pos => failing}/t294/Test_2.scala (100%) diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala index 8553ecb29dad..3f1801a50776 100644 --- a/test/dotc/tests.scala +++ b/test/dotc/tests.scala @@ -137,5 +137,12 @@ class tests extends CompilerTest { "-Xprompt", "#runs", "2")) + val javaDir = "./tests/disabled/java-interop/" + @Test def java_all = compileFiles(javaDir+"pos/") + + @Test def java_2409 = compileDir(javaDir+"failing/t2409") + @Test def java_1751 = compileDir(javaDir+"failing/t1751") + @Test def java_294 = compileDir(javaDir+"failing/t294") + //@Test def dotc_compilercommand = compileFile(dotcDir + "tools/dotc/config/", "CompilerCommand") } diff --git a/test/test/CompilerTest.scala b/test/test/CompilerTest.scala index c9c7c602bdea..ccee7467f0b5 100644 --- a/test/test/CompilerTest.scala +++ b/test/test/CompilerTest.scala @@ -28,13 +28,13 @@ class CompilerTest extends DottyTest { case "-deep" :: args1 => (dir.deepFiles, args1) case _ => (dir.files, args) } - val fileNames = files.toArray.map(_.toString).filter(_ endsWith ".scala") + val fileNames = files.toArray.map(_.toString).filter(name => (name endsWith ".scala") || (name endsWith ".java")) compileArgs(fileNames ++ normArgs, xerrors) } def compileFiles(path: String, args: List[String] = Nil)(implicit defaultOptions: List[String]): Unit = { val dir = Directory(path) - val fileNames = dir.files.toArray.map(_.toString).filter(_ endsWith ".scala") + val fileNames = dir.files.toArray.map(_.toString).filter(name => (name endsWith ".scala") || (name endsWith ".java")) for (name <- fileNames) { println(s"testing $name") compileArgs((name :: args).toArray, 0) @@ -57,4 +57,4 @@ object CompilerTest extends App { // new CompilerTest().compileDir(dotcDir + "tools/dotc") // new CompilerTest().compileFile(dotcDir + "tools/dotc/", "Run") -} \ No newline at end of file +} diff --git a/tests/disabled/java-interop/pos/t1751/A1_2.scala b/tests/disabled/java-interop/failing/t1751/A1_2.scala similarity index 100% rename from tests/disabled/java-interop/pos/t1751/A1_2.scala rename to tests/disabled/java-interop/failing/t1751/A1_2.scala diff --git a/tests/disabled/java-interop/pos/t1751/A2_1.scala b/tests/disabled/java-interop/failing/t1751/A2_1.scala similarity index 100% rename from tests/disabled/java-interop/pos/t1751/A2_1.scala rename to tests/disabled/java-interop/failing/t1751/A2_1.scala diff --git a/tests/disabled/java-interop/pos/t1751/SuiteClasses.java b/tests/disabled/java-interop/failing/t1751/SuiteClasses.java similarity index 100% rename from tests/disabled/java-interop/pos/t1751/SuiteClasses.java rename to tests/disabled/java-interop/failing/t1751/SuiteClasses.java diff --git a/tests/disabled/java-interop/pos/t2409/J.java b/tests/disabled/java-interop/failing/t2409/J.java similarity index 100% rename from tests/disabled/java-interop/pos/t2409/J.java rename to tests/disabled/java-interop/failing/t2409/J.java diff --git a/tests/disabled/java-interop/pos/t2409/t2409.scala b/tests/disabled/java-interop/failing/t2409/t2409.scala similarity index 100% rename from tests/disabled/java-interop/pos/t2409/t2409.scala rename to tests/disabled/java-interop/failing/t2409/t2409.scala diff --git a/tests/disabled/java-interop/pos/t294/Ann.java b/tests/disabled/java-interop/failing/t294/Ann.java similarity index 100% rename from tests/disabled/java-interop/pos/t294/Ann.java rename to tests/disabled/java-interop/failing/t294/Ann.java diff --git a/tests/disabled/java-interop/pos/t294/Ann2.java b/tests/disabled/java-interop/failing/t294/Ann2.java similarity index 100% rename from tests/disabled/java-interop/pos/t294/Ann2.java rename to tests/disabled/java-interop/failing/t294/Ann2.java diff --git a/tests/disabled/java-interop/pos/t294/Test_1.scala b/tests/disabled/java-interop/failing/t294/Test_1.scala similarity index 100% rename from tests/disabled/java-interop/pos/t294/Test_1.scala rename to tests/disabled/java-interop/failing/t294/Test_1.scala diff --git a/tests/disabled/java-interop/pos/t294/Test_2.scala b/tests/disabled/java-interop/failing/t294/Test_2.scala similarity index 100% rename from tests/disabled/java-interop/pos/t294/Test_2.scala rename to tests/disabled/java-interop/failing/t294/Test_2.scala diff --git a/tests/disabled/java-interop/pos/t1782/Test_1.scala b/tests/disabled/java-interop/pos/t1782/Test_1.scala index 6467a74c2974..47495c082929 100644 --- a/tests/disabled/java-interop/pos/t1782/Test_1.scala +++ b/tests/disabled/java-interop/pos/t1782/Test_1.scala @@ -1,6 +1,6 @@ @ImplementedBy(classOf[Provider]) trait Service { - def someMethod() + def someMethod(): Unit } class Provider From ef7fc8ff04e54858f593660be69ad92fe45a42ef Mon Sep 17 00:00:00 2001 From: Ondrej Lhotak Date: Thu, 9 Oct 2014 22:36:30 +0200 Subject: [PATCH 23/46] make elimrepeated addVarArgsBridge at thisTransformer instead of thisTransformer.next --- src/dotty/tools/dotc/transform/ElimRepeated.scala | 1 - 1 file changed, 1 deletion(-) diff --git a/src/dotty/tools/dotc/transform/ElimRepeated.scala b/src/dotty/tools/dotc/transform/ElimRepeated.scala index 8bb2bdedf2d3..5b80a0bf784d 100644 --- a/src/dotty/tools/dotc/transform/ElimRepeated.scala +++ b/src/dotty/tools/dotc/transform/ElimRepeated.scala @@ -11,7 +11,6 @@ import Contexts.Context import Symbols._ import Denotations._, SymDenotations._ import Decorators.StringInterpolators -import dotty.tools.dotc.core.Annotations.ConcreteAnnotation import scala.collection.mutable import DenotTransformers._ import Names.Name From 95e845ba131b3d2495b7e8664a568858251e5157 Mon Sep 17 00:00:00 2001 From: Ondrej Lhotak Date: Fri, 10 Oct 2014 13:44:59 +0200 Subject: [PATCH 24/46] add mapping ENUM -> Enum to PickleBuffer --- src/dotty/tools/dotc/core/pickling/PickleBuffer.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/dotty/tools/dotc/core/pickling/PickleBuffer.scala b/src/dotty/tools/dotc/core/pickling/PickleBuffer.scala index 9f8d4fc2d141..c16b794b7922 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) From 36cb1028c0806991fae9e5d33fe9cb0f2d596ed0 Mon Sep 17 00:00:00 2001 From: Ondrej Lhotak Date: Fri, 10 Oct 2014 13:48:21 +0200 Subject: [PATCH 25/46] add comment explaining why checkValue skips Java compilation units --- src/dotty/tools/dotc/typer/Checking.scala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/dotty/tools/dotc/typer/Checking.scala b/src/dotty/tools/dotc/typer/Checking.scala index a0c43c568f4b..982b97f7e243 100644 --- a/src/dotty/tools/dotc/typer/Checking.scala +++ b/src/dotty/tools/dotc/typer/Checking.scala @@ -182,6 +182,8 @@ trait Checking { def checkValue(tree: Tree, proto: Type)(implicit ctx: Context): tree.type = { if (!proto.isInstanceOf[SelectionProto]) { val sym = tree.tpe.termSymbol + // 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 From 6ef59b13f27154da202c0096c7841a0b0ecb9f92 Mon Sep 17 00:00:00 2001 From: Ondrej Lhotak Date: Fri, 10 Oct 2014 13:50:15 +0200 Subject: [PATCH 26/46] add comment to explain why refctx passed explicitly to selectionType --- src/dotty/tools/dotc/typer/Typer.scala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index fa8ea6ec2c27..d0757ab3643e 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -169,6 +169,8 @@ 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 + // 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)(refctx)) From 95d7ff8e71faec79813c0c2a541a395f877b0040 Mon Sep 17 00:00:00 2001 From: Ondrej Lhotak Date: Fri, 10 Oct 2014 13:51:25 +0200 Subject: [PATCH 27/46] remove debugging println --- src/dotty/tools/dotc/typer/Typer.scala | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index d0757ab3643e..4bb6e172b065 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -303,9 +303,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit } convertToSelectFromType(tree.qualifier, tree.name) match { - case Some(sftt) => - println(s"$tree converted to $sftt") - typedSelectFromTypeTree(sftt, pt) + case Some(sftt) => typedSelectFromTypeTree(sftt, pt) case _ => ctx.error(d"Could not convert $tree to a SelectFromTypeTree"); EmptyTree } } From 7983a096ad80a9fe244ccd7361a6ddd9517344f2 Mon Sep 17 00:00:00 2001 From: Ondrej Lhotak Date: Wed, 29 Oct 2014 17:10:17 +0100 Subject: [PATCH 28/46] Flags.Static renamed to JavaStatic --- src/dotty/tools/dotc/parsing/JavaParsers.scala | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/dotty/tools/dotc/parsing/JavaParsers.scala b/src/dotty/tools/dotc/parsing/JavaParsers.scala index 095342c48291..81e2bb50260d 100644 --- a/src/dotty/tools/dotc/parsing/JavaParsers.scala +++ b/src/dotty/tools/dotc/parsing/JavaParsers.scala @@ -369,7 +369,7 @@ object JavaParsers { flags |= Flags.Private in.nextToken() case STATIC => - flags |= Flags.Static + flags |= Flags.JavaStatic in.nextToken() case ABSTRACT => flags |= Flags.Abstract @@ -524,7 +524,7 @@ object JavaParsers { } } } else { - if (inInterface) mods1 |= Flags.Final | Flags.Static + if (inInterface) mods1 |= Flags.Final | Flags.JavaStatic val result = fieldDecls(Position(offset), mods1, rtpt, name) accept(SEMI) result @@ -582,7 +582,7 @@ object JavaParsers { 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.Static else mods) + typeDecl(if (definesInterface(parentToken)) mods | Flags.JavaStatic else mods) case _ => termDecl(mods, parentToken, parentTParams) } @@ -732,9 +732,9 @@ object JavaParsers { } else if (in.token == SEMI) { in.nextToken() } else { - if (in.token == ENUM || definesInterface(in.token)) mods |= Flags.Static + if (in.token == ENUM || definesInterface(in.token)) mods |= Flags.JavaStatic val decls = memberDecl(mods, parentToken, parentTParams) - (if ((mods is Flags.Static) || inInterface && !(decls exists (_.isInstanceOf[DefDef]))) + (if ((mods is Flags.JavaStatic) || inInterface && !(decls exists (_.isInstanceOf[DefDef]))) statics else members) ++= decls @@ -802,12 +802,12 @@ object JavaParsers { } val predefs = List( DefDef( - Modifiers(Flags.JavaDefined | Flags.Static | Flags.Method), nme.values, List(), + Modifiers(Flags.JavaDefined | Flags.JavaStatic | Flags.Method), nme.values, List(), ListOfNil, arrayOf(enumType), unimplementedExpr), DefDef( - Modifiers(Flags.JavaDefined | Flags.Static | Flags.Method), nme.valueOf, List(), + Modifiers(Flags.JavaDefined | Flags.JavaStatic | Flags.Method), nme.valueOf, List(), List(List(makeParam("x", TypeTree(StringType)))), enumType, unimplementedExpr)) @@ -839,7 +839,7 @@ object JavaParsers { skipAhead() accept(RBRACE) } - ValDef(Modifiers(Flags.Enum | Flags.Stable | Flags.JavaDefined | Flags.Static), name.toTermName, enumType, unimplementedExpr) + ValDef(Modifiers(Flags.Enum | Flags.Stable | Flags.JavaDefined | Flags.JavaStatic), name.toTermName, enumType, unimplementedExpr) } } From baaf851e3a5a74993ee1778d4135344037371dea Mon Sep 17 00:00:00 2001 From: Ondrej Lhotak Date: Wed, 29 Oct 2014 17:12:36 +0100 Subject: [PATCH 29/46] fix calls to tree copier that now requires multiple parameter lists --- src/dotty/tools/dotc/parsing/JavaParsers.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dotty/tools/dotc/parsing/JavaParsers.scala b/src/dotty/tools/dotc/parsing/JavaParsers.scala index 81e2bb50260d..f524827b9538 100644 --- a/src/dotty/tools/dotc/parsing/JavaParsers.scala +++ b/src/dotty/tools/dotc/parsing/JavaParsers.scala @@ -618,8 +618,8 @@ object JavaParsers { if (statics.isEmpty) cdef else { val template = cdef.rhs.asInstanceOf[Template] - cpy.TypeDef(cdef, cdef.mods, cdef.name, - cpy.Template(template, template.constr, template.parents, template.self, + cpy.TypeDef(cdef)(cdef.mods, cdef.name, + cpy.Template(template)(template.constr, template.parents, template.self, importCompanionObject(cdef) :: template.body), cdef.tparams) } From 44ae00661116be3158f0c3dec94fb9a1951f7895 Mon Sep 17 00:00:00 2001 From: Ondrej Lhotak Date: Wed, 29 Oct 2014 17:28:02 +0100 Subject: [PATCH 30/46] make annotation classes abstract (since they are interfaces) --- src/dotty/tools/dotc/parsing/JavaParsers.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dotty/tools/dotc/parsing/JavaParsers.scala b/src/dotty/tools/dotc/parsing/JavaParsers.scala index f524827b9538..d30a4ceb0114 100644 --- a/src/dotty/tools/dotc/parsing/JavaParsers.scala +++ b/src/dotty/tools/dotc/parsing/JavaParsers.scala @@ -770,7 +770,7 @@ object JavaParsers { val body1 = body.filterNot(_.isInstanceOf[DefDef]) val templ = makeTemplate(annotationParents, constr :: body1, List()) addCompanionObject(statics, atPos(offset) { - TypeDef(mods, name, templ) + TypeDef(mods | Flags.Abstract, name, templ) }) } From f1602ab22bf0b26d2e68bf564e6f53271a5707d2 Mon Sep 17 00:00:00 2001 From: Ondrej Lhotak Date: Thu, 30 Oct 2014 17:08:22 +0100 Subject: [PATCH 31/46] For Java constructors, do not move out to ctx.outer A Java constructor needs to see the import of the companion object of the class. It is not necessary to move to an outer context because a Java constructor does not have an implementation. scalac also does it this way: see Namers.Namer.createNamer.isConstrParam. --- src/dotty/tools/dotc/typer/Namer.scala | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala index 0ca681d32f4c..bc64e10fc78b 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, From 4dabffd47955b3e02174598d57c5dd6c9b6752bc Mon Sep 17 00:00:00 2001 From: Ondrej Lhotak Date: Wed, 29 Oct 2014 17:29:40 +0100 Subject: [PATCH 32/46] create dummy first constructor for Java classes The dummy constructor is needed so that the real constructors see the import of the companion object. The constructor has a parameter of type Unit so that no Java code can call it. --- .../tools/dotc/parsing/JavaParsers.scala | 47 ++++++++++--------- test/dotc/tests.scala | 1 - .../{failing => pos}/t2409/J.java | 0 .../{failing => pos}/t2409/t2409.scala | 0 4 files changed, 26 insertions(+), 22 deletions(-) rename tests/disabled/java-interop/{failing => pos}/t2409/J.java (100%) rename tests/disabled/java-interop/{failing => pos}/t2409/t2409.scala (100%) diff --git a/src/dotty/tools/dotc/parsing/JavaParsers.scala b/src/dotty/tools/dotc/parsing/JavaParsers.scala index d30a4ceb0114..36f1c8e18e6d 100644 --- a/src/dotty/tools/dotc/parsing/JavaParsers.scala +++ b/src/dotty/tools/dotc/parsing/JavaParsers.scala @@ -112,7 +112,7 @@ object JavaParsers { 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]) = { + 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 => @@ -120,21 +120,26 @@ object JavaParsers { (constr, first :: tail) case nil => (EmptyTree, nil) } - val (constr, stats1) = pullOutFirstConstr(stats) - val constr1 = if(constr == EmptyTree) makeConstructor(List(), tparams) else constr.asInstanceOf[DefDef] - Template(constr1, parents, EmptyValDef, stats1) + 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: String, tpt: Tree): ValDef = - makeParam(name.toTermName, tpt) - def makeParam(name: TermName, tpt: Tree, flags: FlagSet = Flags.Param): ValDef = - ValDef(Modifiers(flags | Flags.JavaDefined), name, tpt, EmptyTree) + def makeParam(name: TermName, tpt: Tree): ValDef = + ValDef(Modifiers(Flags.JavaDefined | Flags.PrivateLocalParamAccessor), name, tpt, EmptyTree) - def makeConstructor(formals: List[Tree], tparams: List[TypeDef]) = { + def makeConstructor(formals: List[Tree], tparams: List[TypeDef], flags: FlagSet = Flags.JavaDefined) = { val vparams = mapWithIndex(formals)((p, i) => makeSyntheticParam(i + 1, p)) - DefDef(Modifiers(Flags.JavaDefined), nme.CONSTRUCTOR, tparams, List(vparams), TypeTree(), EmptyTree) + DefDef(Modifiers(flags), nme.CONSTRUCTOR, tparams, List(vparams), TypeTree(), EmptyTree) } // ------------- general parsing --------------------------- @@ -447,7 +452,7 @@ object JavaParsers { PostfixOp(t, nme.raw.STAR) } } - varDecl(Position(in.offset), Modifiers(Flags.JavaDefined | Flags.Param), t, ident().toTermName, dontAddMutable = true) + varDecl(Position(in.offset), Modifiers(Flags.JavaDefined | Flags.Param), t, ident().toTermName) } def optThrows(): Unit = { @@ -571,12 +576,12 @@ object JavaParsers { buf.toList } - def varDecl(pos: Position, mods: Modifiers, tpt: Tree, name: TermName, dontAddMutable: Boolean = false): ValDef = { + 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 &~ Flags.Final else if(dontAddMutable) mods else mods | Flags.Mutable + val mods1 = if(mods is Flags.Final) mods else mods | Flags.Mutable atPos(pos) { - ValDef(mods1, name, tpt1, EmptyTree) + ValDef(mods1, name, tpt1, if(mods is Flags.Param) EmptyTree else unimplementedExpr) } } @@ -590,7 +595,7 @@ object JavaParsers { def makeCompanionObject(cdef: TypeDef, statics: List[Tree]): Tree = atPos(cdef.pos) { ModuleDef((cdef.mods & (Flags.AccessFlags | Flags.JavaDefined)).toTermFlags, cdef.name.toTermName, - makeTemplate(List(), statics, List())) + makeTemplate(List(), statics, List(), false)) } private val wild = Ident(nme.WILDCARD) withPos Position(-1) @@ -689,7 +694,7 @@ object JavaParsers { val interfaces = interfacesOpt() val (statics, body) = typeBody(CLASS, name, tparams) addCompanionObject(statics, atPos(offset) { - TypeDef(mods, name, makeTemplate(superclass :: interfaces, body, tparams)) + TypeDef(mods, name, makeTemplate(superclass :: interfaces, body, tparams, true)) }) } @@ -709,7 +714,7 @@ object JavaParsers { addCompanionObject(statics, atPos(offset) { TypeDef(mods | Flags.Trait | Flags.Interface | Flags.Abstract, name, tparams, - makeTemplate(parents, body, tparams)) + makeTemplate(parents, body, tparams, false)) }) } @@ -763,12 +768,12 @@ object JavaParsers { val name = identForType() val (statics, body) = typeBody(AT, name, List()) val constructorParams = body.collect { - case dd: DefDef => makeParam(dd.name, dd.tpt, Flags.PrivateLocalParamAccessor) + case dd: DefDef => makeParam(dd.name, dd.tpt) } val constr = DefDef(Modifiers(Flags.JavaDefined), nme.CONSTRUCTOR, List(), List(constructorParams), TypeTree(), EmptyTree) val body1 = body.filterNot(_.isInstanceOf[DefDef]) - val templ = makeTemplate(annotationParents, constr :: body1, List()) + val templ = makeTemplate(annotationParents, constr :: body1, List(), false) addCompanionObject(statics, atPos(offset) { TypeDef(mods | Flags.Abstract, name, templ) }) @@ -808,7 +813,7 @@ object JavaParsers { unimplementedExpr), DefDef( Modifiers(Flags.JavaDefined | Flags.JavaStatic | Flags.Method), nme.valueOf, List(), - List(List(makeParam("x", TypeTree(StringType)))), + List(List(makeParam("x".toTermName, TypeTree(StringType)))), enumType, unimplementedExpr)) accept(RBRACE) @@ -821,7 +826,7 @@ object JavaParsers { List(Literal(Constant(null)),Literal(Constant(0)))) addCompanionObject(consts ::: statics ::: predefs, atPos(offset) { TypeDef(mods | Flags.Enum, name, List(), - makeTemplate(superclazz :: interfaces, body, List())) + makeTemplate(superclazz :: interfaces, body, List(), true)) }) } diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala index 3f1801a50776..c08dda4c42f8 100644 --- a/test/dotc/tests.scala +++ b/test/dotc/tests.scala @@ -140,7 +140,6 @@ class tests extends CompilerTest { val javaDir = "./tests/disabled/java-interop/" @Test def java_all = compileFiles(javaDir+"pos/") - @Test def java_2409 = compileDir(javaDir+"failing/t2409") @Test def java_1751 = compileDir(javaDir+"failing/t1751") @Test def java_294 = compileDir(javaDir+"failing/t294") diff --git a/tests/disabled/java-interop/failing/t2409/J.java b/tests/disabled/java-interop/pos/t2409/J.java similarity index 100% rename from tests/disabled/java-interop/failing/t2409/J.java rename to tests/disabled/java-interop/pos/t2409/J.java diff --git a/tests/disabled/java-interop/failing/t2409/t2409.scala b/tests/disabled/java-interop/pos/t2409/t2409.scala similarity index 100% rename from tests/disabled/java-interop/failing/t2409/t2409.scala rename to tests/disabled/java-interop/pos/t2409/t2409.scala From dd6a7e785c9b7eb11f7c58b55db4af3c4e5c1e5f Mon Sep 17 00:00:00 2001 From: Ondrej Lhotak Date: Thu, 30 Oct 2014 21:46:16 +0100 Subject: [PATCH 33/46] don't try to make a body for a setter of a Java field transformSym explicitly checks that a field is JavaDefined and does not create a symbol for it. Creation of a setter body looks for the symbol and fails because it does not find it. We do not need setter bodies for Java fields because we are not generating bytecode for them. --- src/dotty/tools/dotc/transform/GettersSetters.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dotty/tools/dotc/transform/GettersSetters.scala b/src/dotty/tools/dotc/transform/GettersSetters.scala index e1b4b59a0234..bbe5740ffde0 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)) From d6fdc8495e6a8e92e1648a801b63a6271adbb7d1 Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Tue, 4 Nov 2014 11:50:42 +0100 Subject: [PATCH 34/46] Extract AnnotationTransformer functionality from ElimRepeated to a trait to be reused by FirstTransform --- .../tools/dotc/transform/ElimRepeated.scala | 46 ++++--------------- .../tools/dotc/transform/TreeTransform.scala | 31 +++++++++++++ 2 files changed, 40 insertions(+), 37 deletions(-) diff --git a/src/dotty/tools/dotc/transform/ElimRepeated.scala b/src/dotty/tools/dotc/transform/ElimRepeated.scala index 5b80a0bf784d..d3e32fe02620 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,39 +22,11 @@ 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" - object annotTransformer extends TreeMap { - override def transform(tree: Tree)(implicit ctx: Context): Tree = super.transform(tree) match { - case x @(_: Ident|_ :Select|_: Apply| _: TypeApply| _: DefDef) => transformTypeOfTree(x) - case x => x - } - } - - /** - * Overriden to solve a particular problem with not being eliminated inside annotation trees - * Dmitry: this should solve problem for now, - * following YAGNI principle I am convinced that we shouldn't make a solution - * for a generalized problem(transforming annotations trees) - * that manifests itself only here. - */ - 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(annotTransformer.transform) - 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) - } - } - def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context): Type = elimRepeated(tp) @@ -89,17 +63,15 @@ class ElimRepeated extends MiniPhaseTransform with InfoTransformer { thisTransfo 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) - val newAnnots = tree.mods.annotations.mapConserve(annotTransformer.transform) - val newTree = if (newAnnots eq tree.mods.annotations) tree - else cpy.DefDef(tree)(mods = Modifiers(tree.mods.flags, tree.mods.privateWithin, newAnnots)) if (tree.symbol.info.isVarArgsMethod && overridesJava) - addVarArgsBridge(newTree)(ctx.withPhase(thisTransformer.next)) - else - newTree + addVarArgsBridge(tree)(ctx.withPhase(thisTransformer.next)) + else + transformAnnotations(tree) } /** Add a Java varargs bridge @@ -122,7 +94,7 @@ class ElimRepeated extends MiniPhaseTransform with InfoTransformer { thisTransfo .appliedToArgs(vrefs :+ TreeGen.wrapArray(varArgRef, elemtp)) .appliedToArgss(vrefss1) }) - Thicket(ddef, bridgeDef) + Thicket(transformAnnotations(ddef), transformAnnotations(bridgeDef)) } /** Convert type from Scala to Java varargs method */ diff --git a/src/dotty/tools/dotc/transform/TreeTransform.scala b/src/dotty/tools/dotc/transform/TreeTransform.scala index d3d8a183b848..1823ae029d99 100644 --- a/src/dotty/tools/dotc/transform/TreeTransform.scala +++ b/src/dotty/tools/dotc/transform/TreeTransform.scala @@ -169,6 +169,37 @@ object TreeTransforms { def phase = this } + /** A helper trait to transform annotations on MemberDefs */ + trait AnnotationTransformer extends MiniPhaseTransform { + + val annotationTransformer = mkTreeTransformer + + def transformAnnotations(tree: MemberDef)(implicit ctx: Context): MemberDef ={ + val newAnnots = tree.mods.annotations.mapConserve(annotationTransformer.transform) + if (newAnnots eq tree.mods.annotations) tree + else { + val mods = tree.mods.copy(annotations = newAnnots) + tree match { + case t: DefDef => cpy.DefDef(t)(mods = mods) + case t: ValDef => cpy.ValDef(t)(mods = mods) + case t: TypeDef => cpy.TypeDef(t)(mods = mods) + } + } + } + + override def transformDefDef(tree: DefDef)(implicit ctx: Context, info: TransformerInfo): Tree = { + transformAnnotations(tree) + } + + override def transformTypeDef(tree: TypeDef)(implicit ctx: Context, info: TransformerInfo): Tree = { + transformAnnotations(tree) + } + + override def transformValDef(tree: tpd.ValDef)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = { + transformAnnotations(tree) + } + } + val NoTransform = new TreeTransform { def phase = unsupported("phase") idx = -1 From cc8ca00fc1718bcbb49e3c61f3c0682eac2a7e7c Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Tue, 4 Nov 2014 12:23:40 +0100 Subject: [PATCH 35/46] AnnotationTransformer now also transforms types Required as gettersAndSetters ignores modifiers in tree and uses ones in the type instead. This means that gettersAndSetters carries over modifiers from type to tree and this one violates postconditions. --- .../tools/dotc/transform/FirstTransform.scala | 16 ++++++++++++--- .../tools/dotc/transform/TreeTransform.scala | 20 ++++++++++++++++++- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/dotty/tools/dotc/transform/FirstTransform.scala b/src/dotty/tools/dotc/transform/FirstTransform.scala index 7687be457977..67ce7347765b 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 @@ -27,11 +29,14 @@ import NameOps._ * - checks the bounds of AppliedTypeTrees * - stubs out native methods */ -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}") @@ -82,13 +87,16 @@ class FirstTransform extends MiniPhaseTransform with IdentityDenotTransformer { addMissingCompanions(reorder(stats)) } - override def transformDefDef(ddef: DefDef)(implicit ctx: Context, info: TransformerInfo) = + override def transformDefDef(ddef: DefDef)(implicit ctx: Context, info: TransformerInfo) = { + val r = 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 + transformAnnotations(r) + } override def transformStats(trees: List[Tree])(implicit ctx: Context, info: TransformerInfo): List[Tree] = ast.Trees.flatten(reorderAndComplete(trees)(ctx.withPhase(thisTransformer.next))) @@ -107,6 +115,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/TreeTransform.scala b/src/dotty/tools/dotc/transform/TreeTransform.scala index 1823ae029d99..276080565df1 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 @@ -170,10 +174,24 @@ object TreeTransforms { } /** A helper trait to transform annotations on MemberDefs */ - trait AnnotationTransformer extends MiniPhaseTransform { + 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.transform) + 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) + } + } + def transformAnnotations(tree: MemberDef)(implicit ctx: Context): MemberDef ={ val newAnnots = tree.mods.annotations.mapConserve(annotationTransformer.transform) if (newAnnots eq tree.mods.annotations) tree From 32954ba55955f4335bb34007269e3d405faa1780 Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Tue, 4 Nov 2014 15:19:41 +0100 Subject: [PATCH 36/46] Extracting ApplyOverloaded to be reused in UnPickler and ClassfileParser --- src/dotty/tools/dotc/ast/tpd.scala | 18 ++++++++++++++++++ src/dotty/tools/dotc/core/Annotations.scala | 15 +++++++++++++++ .../dotc/core/pickling/ClassfileParser.scala | 2 +- .../tools/dotc/core/pickling/UnPickler.scala | 18 +++--------------- 4 files changed, 37 insertions(+), 16 deletions(-) diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala index c735f079c0e7..9bf19dc5ccc2 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._ @@ -677,6 +678,23 @@ 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)(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) + val apply = untpd.Apply(fun, args) + + new typer.ApplyToTyped(apply, fun, selected, args, 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/core/Annotations.scala b/src/dotty/tools/dotc/core/Annotations.scala index 92b28a1934ad..814b6db49616 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) + } + + 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/pickling/ClassfileParser.scala b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala index fb5a6309b30c..8bf84e1a95a6 100644 --- a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala +++ b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala @@ -444,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 => diff --git a/src/dotty/tools/dotc/core/pickling/UnPickler.scala b/src/dotty/tools/dotc/core/pickling/UnPickler.scala index c503f447b4fb..72804870014d 100644 --- a/src/dotty/tools/dotc/core/pickling/UnPickler.scala +++ b/src/dotty/tools/dotc/core/pickling/UnPickler.scala @@ -832,22 +832,10 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot: t.toList } // println(atp) - val typer = ctx.typer - val proto = new FunProtoTyped(args, atp, typer) - val alts = atp.member(nme.CONSTRUCTOR).alternatives.map(_.termRef) - - val constructors = ctx.typer.resolveOverloaded(alts, proto, Nil) - assert(constructors.size == 1) // this is parsed from bytecode tree. there's nothing user can do about it - - val constr = constructors.head val targs = atp.argTypes - val fun = tpd.New(atp withoutArgs targs) - .select(TermRef.withSig(atp.normalizedPrefix, constr.termSymbol.asTerm)) - .appliedToTypes(targs) - val apply = untpd.Apply(fun, args) - new typer.ApplyToTyped(apply, fun, constr, args, atp).result.asInstanceOf[tpd.Tree] // needed to handle varargs - // Dotty deviation, for scalac the last cast wouldn't be required - } + + 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 From e2c5fcdf97e351e471e79502aa7d23bd973241ab Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Tue, 4 Nov 2014 15:22:18 +0100 Subject: [PATCH 37/46] Java annotations parsing problem Annotations in java could be compiled as-if array-only annotation had arguments constructor. That isn't true for scala. Also, type checking creation of single-element array requires implicit resolution to provide ClassTag. This makes problems while reading deferred annotation. --- tests/pos/annot.scala | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/pos/annot.scala b/tests/pos/annot.scala index cda24e05daaf..ab80aba27e82 100644 --- a/tests/pos/annot.scala +++ b/tests/pos/annot.scala @@ -2,7 +2,11 @@ import java.beans.Transient class Test { - @SuppressWarnings(Array("hi")) def foo() = ??? + @SuppressWarnings(Array("hi")) def foo() = ??? // evalutation of annotation on type cannot be deffered as requires implicit resolution(only generic Array$.apply applies here) + + @SuppressWarnings(Array("hi", "foo")) def foo2() = ??? //can be deffered as there is a non-generic method + +// @SuppressWarnings("hi") def foo3() = ??? // can be written in java and is serialized this way in bytecode. doesn't typecheck @Transient(false) def bar = ??? From 3bb70e8620e48a4eace118cc05006ab83a112682 Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Mon, 17 Nov 2014 16:31:44 +0100 Subject: [PATCH 38/46] Annotations have JavaSeqLiterals inside. --- src/dotty/tools/dotc/core/pickling/ClassfileParser.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala index 8bf84e1a95a6..f92573d224de 100644 --- a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala +++ b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala @@ -422,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) } From 22c9a9bfc96284dc3b827c1e8a6a2a4331ebc9c3 Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Mon, 17 Nov 2014 16:32:35 +0100 Subject: [PATCH 39/46] Add handling of parsed annotations to applyOverloaded. see annot.scala for examples --- src/dotty/tools/dotc/ast/tpd.scala | 26 ++++++++++++++++++--- src/dotty/tools/dotc/core/Annotations.scala | 2 +- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala index 9bf19dc5ccc2..61761bcae520 100644 --- a/src/dotty/tools/dotc/ast/tpd.scala +++ b/src/dotty/tools/dotc/ast/tpd.scala @@ -679,7 +679,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { } } - def applyOverloaded(receiver: Tree, method: TermName, args: List[Tree], targs: List[Type], expectedType: Type)(implicit ctx: Context): Tree = { + 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) @@ -691,9 +691,29 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { val fun = receiver .select(TermRef.withSig(receiver.tpe.normalizedPrefix, selected.termSymbol.asTerm)) .appliedToTypes(targs) - val apply = untpd.Apply(fun, args) - new typer.ApplyToTyped(apply, fun, selected, args, expectedType).result.asInstanceOf[Tree] // needed to handle varargs + val callArgs: List[Tree] = if(args.isEmpty) Nil else { + val lastParamType = selected.widen.paramTypess.head.last + val lastParam = args.last + if (isAnnotConstructor && !(lastParam.tpe <:< lastParamType)) { + val defn = ctx.definitions + val prefix = args.take(selected.widen.paramTypess.head.size - 1) + lastParamType match { + case defn.ArrayType(el) => + lastParam.tpe match { + case defn.ArrayType(el2) if (el2 <:< el) => // we have a JavaSeqLiteral with a more precise type + prefix ::: List(tpd.Typed(lastParam, TypeTree(defn.ArrayType(el)))) + case _ => + ??? + } + //case defn.ArrayType(el) if(lastParam) + case _ => args + } + } else args + } + + val apply = untpd.Apply(fun, callArgs) + new typer.ApplyToTyped(apply, fun, selected, callArgs, expectedType).result.asInstanceOf[Tree] // needed to handle varargs } @tailrec diff --git a/src/dotty/tools/dotc/core/Annotations.scala b/src/dotty/tools/dotc/core/Annotations.scala index 814b6db49616..79aa058efafb 100644 --- a/src/dotty/tools/dotc/core/Annotations.scala +++ b/src/dotty/tools/dotc/core/Annotations.scala @@ -66,7 +66,7 @@ object Annotations { 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) + tpd.applyOverloaded(New(atp withoutArgs targs), nme.CONSTRUCTOR, args, targs, atp, isAnnotConstructor = true) } def applyResolve(atp: Type, args: List[Tree])(implicit ctx: Context): Annotation = { From 38cebe090a97930fe872d37370c66f72da360409 Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Mon, 17 Nov 2014 17:20:50 +0100 Subject: [PATCH 40/46] Adapting branch to absence of modifiers in trees. --- .../tools/dotc/parsing/JavaParsers.scala | 50 +++++++++---------- .../tools/dotc/transform/ElimRepeated.scala | 6 +-- .../tools/dotc/transform/FirstTransform.scala | 2 - .../tools/dotc/transform/TreeTransform.scala | 27 +--------- 4 files changed, 29 insertions(+), 56 deletions(-) diff --git a/src/dotty/tools/dotc/parsing/JavaParsers.scala b/src/dotty/tools/dotc/parsing/JavaParsers.scala index 36f1c8e18e6d..ab805f261f11 100644 --- a/src/dotty/tools/dotc/parsing/JavaParsers.scala +++ b/src/dotty/tools/dotc/parsing/JavaParsers.scala @@ -135,11 +135,11 @@ object JavaParsers { def makeSyntheticParam(count: Int, tpt: Tree): ValDef = makeParam(nme.syntheticParamName(count), tpt) def makeParam(name: TermName, tpt: Tree): ValDef = - ValDef(Modifiers(Flags.JavaDefined | Flags.PrivateLocalParamAccessor), name, tpt, EmptyTree) + 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(Modifiers(flags), nme.CONSTRUCTOR, tparams, List(vparams), TypeTree(), EmptyTree) + DefDef(nme.CONSTRUCTOR, tparams, List(vparams), TypeTree(), EmptyTree).withMods(Modifiers(flags)) } // ------------- general parsing --------------------------- @@ -420,7 +420,7 @@ object JavaParsers { atPos(in.offset) { val name = identForType() val hi = if (in.token == EXTENDS) { in.nextToken() ; bound() } else EmptyTree - TypeDef(Modifiers(flags), name, Nil, TypeBoundsTree(EmptyTree, hi)) + TypeDef(name, Nil, TypeBoundsTree(EmptyTree, hi)).withMods(Modifiers(flags)) } def bound(): Tree = @@ -490,7 +490,7 @@ object JavaParsers { optThrows() List { atPos(offset) { - DefDef(mods, nme.CONSTRUCTOR, parentTParams, List(vparams), TypeTree(), methodBody()) + DefDef(nme.CONSTRUCTOR, parentTParams, List(vparams), TypeTree(), methodBody()).withMods(mods) } } } else { @@ -525,7 +525,7 @@ object JavaParsers { //if (inInterface) mods1 |= Flags.Deferred List { atPos(offset) { - DefDef(mods1 | Flags.Method, name.toTermName, tparams, List(vparams), rtpt, body) + DefDef(name.toTermName, tparams, List(vparams), rtpt, body).withMods(mods1 | Flags.Method) } } } else { @@ -581,7 +581,7 @@ object JavaParsers { 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(mods1, name, tpt1, if(mods is Flags.Param) EmptyTree else unimplementedExpr) + ValDef(name, tpt1, if(mods is Flags.Param) EmptyTree else unimplementedExpr).withMods(mods1) } } @@ -594,8 +594,8 @@ object JavaParsers { def makeCompanionObject(cdef: TypeDef, statics: List[Tree]): Tree = atPos(cdef.pos) { - ModuleDef((cdef.mods & (Flags.AccessFlags | Flags.JavaDefined)).toTermFlags, cdef.name.toTermName, - makeTemplate(List(), statics, List(), false)) + 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) @@ -623,10 +623,10 @@ object JavaParsers { if (statics.isEmpty) cdef else { val template = cdef.rhs.asInstanceOf[Template] - cpy.TypeDef(cdef)(cdef.mods, cdef.name, + cpy.TypeDef(cdef)(cdef.name, cpy.Template(template)(template.constr, template.parents, template.self, importCompanionObject(cdef) :: template.body), - cdef.tparams) + cdef.tparams).withMods(cdef.mods) } List(makeCompanionObject(cdefNew, statics), cdefNew) @@ -694,7 +694,7 @@ object JavaParsers { val interfaces = interfacesOpt() val (statics, body) = typeBody(CLASS, name, tparams) addCompanionObject(statics, atPos(offset) { - TypeDef(mods, name, makeTemplate(superclass :: interfaces, body, tparams, true)) + TypeDef(name, makeTemplate(superclass :: interfaces, body, tparams, true)).withMods(mods) }) } @@ -712,9 +712,9 @@ object JavaParsers { } val (statics, body) = typeBody(INTERFACE, name, tparams) addCompanionObject(statics, atPos(offset) { - TypeDef(mods | Flags.Trait | Flags.Interface | Flags.Abstract, + TypeDef( name, tparams, - makeTemplate(parents, body, tparams, false)) + makeTemplate(parents, body, tparams, false)).withMods(mods | Flags.Trait | Flags.JavaInterface | Flags.Abstract) }) } @@ -746,9 +746,9 @@ object JavaParsers { } } def forwarders(sdef: Tree): List[Tree] = sdef match { - case TypeDef(mods, name, _) if (parentToken == INTERFACE) => + case TypeDef(name, _) if (parentToken == INTERFACE) => var rhs: Tree = Select(Ident(parentName.toTermName), name) - List(TypeDef(Modifiers(Flags.Protected), name, rhs)) + List(TypeDef(name, rhs).withMods(Modifiers(Flags.Protected))) case _ => List() } @@ -770,12 +770,12 @@ object JavaParsers { val constructorParams = body.collect { case dd: DefDef => makeParam(dd.name, dd.tpt) } - val constr = DefDef(Modifiers(Flags.JavaDefined), nme.CONSTRUCTOR, - List(), List(constructorParams), TypeTree(), EmptyTree) + 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(mods | Flags.Abstract, name, templ) + TypeDef(name, templ).withMods(mods | Flags.Abstract) }) } @@ -807,15 +807,15 @@ object JavaParsers { } val predefs = List( DefDef( - Modifiers(Flags.JavaDefined | Flags.JavaStatic | Flags.Method), nme.values, List(), + nme.values, List(), ListOfNil, arrayOf(enumType), - unimplementedExpr), + unimplementedExpr).withMods(Modifiers(Flags.JavaDefined | Flags.JavaStatic | Flags.Method)), DefDef( - Modifiers(Flags.JavaDefined | Flags.JavaStatic | Flags.Method), nme.valueOf, List(), + nme.valueOf, List(), List(List(makeParam("x".toTermName, TypeTree(StringType)))), enumType, - unimplementedExpr)) + unimplementedExpr).withMods(Modifiers(Flags.JavaDefined | Flags.JavaStatic | Flags.Method))) accept(RBRACE) /* val superclazz = @@ -825,8 +825,8 @@ object JavaParsers { Select(New(javaLangDot(tpnme.Enum)), nme.CONSTRUCTOR), List(enumType)), List(Literal(Constant(null)),Literal(Constant(0)))) addCompanionObject(consts ::: statics ::: predefs, atPos(offset) { - TypeDef(mods | Flags.Enum, name, List(), - makeTemplate(superclazz :: interfaces, body, List(), true)) + TypeDef(name, List(), + makeTemplate(superclazz :: interfaces, body, List(), true)).withMods(mods | Flags.Enum) }) } @@ -844,7 +844,7 @@ object JavaParsers { skipAhead() accept(RBRACE) } - ValDef(Modifiers(Flags.Enum | Flags.Stable | Flags.JavaDefined | Flags.JavaStatic), name.toTermName, enumType, unimplementedExpr) + ValDef(name.toTermName, enumType, unimplementedExpr).withMods(Modifiers(Flags.Enum | Flags.Stable | Flags.JavaDefined | Flags.JavaStatic)) } } diff --git a/src/dotty/tools/dotc/transform/ElimRepeated.scala b/src/dotty/tools/dotc/transform/ElimRepeated.scala index d3e32fe02620..ff56ae872fcd 100644 --- a/src/dotty/tools/dotc/transform/ElimRepeated.scala +++ b/src/dotty/tools/dotc/transform/ElimRepeated.scala @@ -57,7 +57,7 @@ class ElimRepeated extends MiniPhaseTransform with InfoTransformer with Annotati 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) @@ -71,7 +71,7 @@ class ElimRepeated extends MiniPhaseTransform with InfoTransformer with Annotati if (tree.symbol.info.isVarArgsMethod && overridesJava) addVarArgsBridge(tree)(ctx.withPhase(thisTransformer.next)) else - transformAnnotations(tree) + tree } /** Add a Java varargs bridge @@ -94,7 +94,7 @@ class ElimRepeated extends MiniPhaseTransform with InfoTransformer with Annotati .appliedToArgs(vrefs :+ TreeGen.wrapArray(varArgRef, elemtp)) .appliedToArgss(vrefss1) }) - Thicket(transformAnnotations(ddef), transformAnnotations(bridgeDef)) + Thicket(ddef, bridgeDef) } /** Convert type from Scala to Java varargs method */ diff --git a/src/dotty/tools/dotc/transform/FirstTransform.scala b/src/dotty/tools/dotc/transform/FirstTransform.scala index 67ce7347765b..5e3af53da352 100644 --- a/src/dotty/tools/dotc/transform/FirstTransform.scala +++ b/src/dotty/tools/dotc/transform/FirstTransform.scala @@ -88,14 +88,12 @@ class FirstTransform extends MiniPhaseTransform with IdentityDenotTransformer wi } override def transformDefDef(ddef: DefDef)(implicit ctx: Context, info: TransformerInfo) = { - val r = 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 - transformAnnotations(r) } override def transformStats(trees: List[Tree])(implicit ctx: Context, info: TransformerInfo): List[Tree] = diff --git a/src/dotty/tools/dotc/transform/TreeTransform.scala b/src/dotty/tools/dotc/transform/TreeTransform.scala index 276080565df1..3869adf6cf7d 100644 --- a/src/dotty/tools/dotc/transform/TreeTransform.scala +++ b/src/dotty/tools/dotc/transform/TreeTransform.scala @@ -184,38 +184,13 @@ object TreeTransforms { ref match { case ref: SymDenotation => val annotTrees = ref.annotations.map(_.tree) - val annotTrees1 = annotTrees.mapConserve(annotationTransformer.transform) + 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) } } - - def transformAnnotations(tree: MemberDef)(implicit ctx: Context): MemberDef ={ - val newAnnots = tree.mods.annotations.mapConserve(annotationTransformer.transform) - if (newAnnots eq tree.mods.annotations) tree - else { - val mods = tree.mods.copy(annotations = newAnnots) - tree match { - case t: DefDef => cpy.DefDef(t)(mods = mods) - case t: ValDef => cpy.ValDef(t)(mods = mods) - case t: TypeDef => cpy.TypeDef(t)(mods = mods) - } - } - } - - override def transformDefDef(tree: DefDef)(implicit ctx: Context, info: TransformerInfo): Tree = { - transformAnnotations(tree) - } - - override def transformTypeDef(tree: TypeDef)(implicit ctx: Context, info: TransformerInfo): Tree = { - transformAnnotations(tree) - } - - override def transformValDef(tree: tpd.ValDef)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = { - transformAnnotations(tree) - } } val NoTransform = new TreeTransform { From 4b71995f9cfe1e16ec2e3343a3bce601158a84e3 Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Mon, 17 Nov 2014 17:21:08 +0100 Subject: [PATCH 41/46] Fixing memoize transforming java fields. --- src/dotty/tools/dotc/transform/Memoize.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dotty/tools/dotc/transform/Memoize.scala b/src/dotty/tools/dotc/transform/Memoize.scala index ef70b9ecf34a..f4b00d6a5e86 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 From 265ac7ac52a920bba0e7c101103d8cbe7d65d18c Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Mon, 17 Nov 2014 17:31:15 +0100 Subject: [PATCH 42/46] Moving java tests to pos --- .../java-interop/{pos => failing}/t1459/AbstractBase.java | 0 tests/disabled/java-interop/{pos => failing}/t1459/App.scala | 0 .../disabled/java-interop/{pos => failing}/t1459/Caller.java | 0 .../disabled/java-interop/{pos => failing}/t2569/Child.scala | 0 .../disabled/java-interop/{pos => failing}/t2569/Parent.java | 0 .../java-interop/{pos => failing}/varargs-bridge/A.java | 0 .../java-interop/{pos => failing}/varargs-bridge/B.scala | 0 tests/new/t296.scala | 5 +++++ .../java-interop/pos => pos/java-interop}/t0288/Foo.scala | 0 .../java-interop/pos => pos/java-interop}/t0288/Outer.java | 0 .../pos => pos/java-interop}/t0695/JavaClass.java | 0 .../java-interop/pos => pos/java-interop}/t0695/Test.scala | 0 .../java-interop/pos => pos/java-interop}/t1101/J.java | 0 .../java-interop/pos => pos/java-interop}/t1101/S.scala | 0 .../java-interop/pos => pos/java-interop}/t1102/J.java | 0 .../java-interop/pos => pos/java-interop}/t1102/S.scala | 0 .../java-interop/pos => pos/java-interop}/t1150/J.java | 0 .../java-interop/pos => pos/java-interop}/t1150/S.scala | 0 .../java-interop/pos => pos/java-interop}/t1152/J.java | 0 .../java-interop/pos => pos/java-interop}/t1152/S.scala | 0 .../java-interop/pos => pos/java-interop}/t1176/J.java | 0 .../java-interop/pos => pos/java-interop}/t1176/S.scala | 0 .../java-interop/pos => pos/java-interop}/t1186/t1186.java | 0 .../java-interop/pos => pos/java-interop}/t1196/J.java | 0 .../java-interop/pos => pos/java-interop}/t1196/S.scala | 0 .../java-interop/pos => pos/java-interop}/t1197/J.java | 0 .../java-interop/pos => pos/java-interop}/t1197/S.scala | 0 .../java-interop/pos => pos/java-interop}/t1203b/J.java | 0 .../java-interop/pos => pos/java-interop}/t1203b/S.scala | 0 .../java-interop/pos => pos/java-interop}/t1230/J.java | 0 .../java-interop/pos => pos/java-interop}/t1230/S.scala | 0 .../java-interop/pos => pos/java-interop}/t1231/J.java | 0 .../java-interop/pos => pos/java-interop}/t1231/S.scala | 0 .../java-interop/pos => pos/java-interop}/t1232/J.java | 0 .../java-interop/pos => pos/java-interop}/t1232/J2.java | 0 .../java-interop/pos => pos/java-interop}/t1232/S.scala | 0 .../java-interop/pos => pos/java-interop}/t1235/Test.java | 0 .../java-interop/pos => pos/java-interop}/t1254/t1254.java | 0 .../java-interop/pos => pos/java-interop}/t1263/Test.java | 0 .../java-interop/pos => pos/java-interop}/t1263/test.scala | 0 .../pos => pos/java-interop}/t1409/AbstractImpl.java | 0 .../pos => pos/java-interop}/t1409/ConcreteImpl.scala | 0 .../pos => pos/java-interop}/t1409/OuterInterface.java | 0 .../java-interop}/t1642/JavaCallingScalaHashMap.java | 0 .../java-interop/pos => pos/java-interop}/t1711/Seq.scala | 0 .../java-interop/pos => pos/java-interop}/t1711/Test.java | 0 .../java-interop/pos => pos/java-interop}/t1745/J.java | 0 .../java-interop/pos => pos/java-interop}/t1745/S.scala | 0 .../failing => pos/java-interop}/t1751/A1_2.scala | 0 .../failing => pos/java-interop}/t1751/A2_1.scala | 0 .../failing => pos/java-interop}/t1751/SuiteClasses.java | 0 .../java-interop/pos => pos/java-interop}/t1782/Ann.java | 0 .../java-interop/pos => pos/java-interop}/t1782/Days.java | 0 .../pos => pos/java-interop}/t1782/ImplementedBy.java | 0 .../java-interop/pos => pos/java-interop}/t1782/Test_1.scala | 0 .../java-interop/pos => pos/java-interop}/t1836/J.java | 0 .../java-interop/pos => pos/java-interop}/t1836/S.scala | 0 .../java-interop/pos => pos/java-interop}/t1840/J.java | 0 .../java-interop/pos => pos/java-interop}/t1840/S.scala | 0 .../pos => pos/java-interop}/t1937/NumberGenerator.java | 0 .../java-interop/pos => pos/java-interop}/t2377/Q.java | 0 .../java-interop/pos => pos/java-interop}/t2377/a.scala | 0 .../java-interop/pos => pos/java-interop}/t2409/J.java | 0 .../java-interop/pos => pos/java-interop}/t2409/t2409.scala | 0 .../pos => pos/java-interop}/t2413/TestJava.java | 0 .../pos => pos/java-interop}/t2413/TestScalac.scala | 0 .../java-interop/pos => pos/java-interop}/t2433/A.java | 0 .../java-interop/pos => pos/java-interop}/t2433/B.java | 0 .../java-interop/pos => pos/java-interop}/t2433/Test.scala | 0 .../java-interop/pos => pos/java-interop}/t2464/JavaOne.java | 0 .../pos => pos/java-interop}/t2464/ScalaOne_1.scala | 0 .../pos => pos/java-interop}/t2464/t2464_2.scala | 0 .../java-interop/pos => pos/java-interop}/t2764/Ann.java | 0 .../java-interop/pos => pos/java-interop}/t2764/Enum.java | 0 .../java-interop/pos => pos/java-interop}/t2764/Use.scala | 0 .../java-interop/failing => pos/java-interop}/t294/Ann.java | 0 .../java-interop/failing => pos/java-interop}/t294/Ann2.java | 0 .../failing => pos/java-interop}/t294/Test_1.scala | 0 .../failing => pos/java-interop}/t294/Test_2.scala | 0 .../java-interop/pos => pos/java-interop}/t2940/Cycle.java | 0 .../java-interop/pos => pos/java-interop}/t2940/Error.scala | 0 .../java-interop}/t2956/BeanDefinitionVisitor.java | 0 .../java-interop/pos => pos/java-interop}/t2956/t2956.scala | 0 83 files changed, 5 insertions(+) rename tests/disabled/java-interop/{pos => failing}/t1459/AbstractBase.java (100%) rename tests/disabled/java-interop/{pos => failing}/t1459/App.scala (100%) rename tests/disabled/java-interop/{pos => failing}/t1459/Caller.java (100%) rename tests/disabled/java-interop/{pos => failing}/t2569/Child.scala (100%) rename tests/disabled/java-interop/{pos => failing}/t2569/Parent.java (100%) rename tests/disabled/java-interop/{pos => failing}/varargs-bridge/A.java (100%) rename tests/disabled/java-interop/{pos => failing}/varargs-bridge/B.scala (100%) create mode 100644 tests/new/t296.scala rename tests/{disabled/java-interop/pos => pos/java-interop}/t0288/Foo.scala (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t0288/Outer.java (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t0695/JavaClass.java (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t0695/Test.scala (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1101/J.java (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1101/S.scala (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1102/J.java (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1102/S.scala (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1150/J.java (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1150/S.scala (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1152/J.java (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1152/S.scala (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1176/J.java (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1176/S.scala (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1186/t1186.java (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1196/J.java (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1196/S.scala (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1197/J.java (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1197/S.scala (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1203b/J.java (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1203b/S.scala (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1230/J.java (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1230/S.scala (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1231/J.java (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1231/S.scala (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1232/J.java (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1232/J2.java (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1232/S.scala (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1235/Test.java (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1254/t1254.java (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1263/Test.java (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1263/test.scala (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1409/AbstractImpl.java (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1409/ConcreteImpl.scala (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1409/OuterInterface.java (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1642/JavaCallingScalaHashMap.java (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1711/Seq.scala (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1711/Test.java (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1745/J.java (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1745/S.scala (100%) rename tests/{disabled/java-interop/failing => pos/java-interop}/t1751/A1_2.scala (100%) rename tests/{disabled/java-interop/failing => pos/java-interop}/t1751/A2_1.scala (100%) rename tests/{disabled/java-interop/failing => pos/java-interop}/t1751/SuiteClasses.java (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1782/Ann.java (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1782/Days.java (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1782/ImplementedBy.java (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1782/Test_1.scala (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1836/J.java (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1836/S.scala (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1840/J.java (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1840/S.scala (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t1937/NumberGenerator.java (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t2377/Q.java (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t2377/a.scala (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t2409/J.java (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t2409/t2409.scala (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t2413/TestJava.java (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t2413/TestScalac.scala (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t2433/A.java (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t2433/B.java (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t2433/Test.scala (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t2464/JavaOne.java (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t2464/ScalaOne_1.scala (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t2464/t2464_2.scala (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t2764/Ann.java (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t2764/Enum.java (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t2764/Use.scala (100%) rename tests/{disabled/java-interop/failing => pos/java-interop}/t294/Ann.java (100%) rename tests/{disabled/java-interop/failing => pos/java-interop}/t294/Ann2.java (100%) rename tests/{disabled/java-interop/failing => pos/java-interop}/t294/Test_1.scala (100%) rename tests/{disabled/java-interop/failing => pos/java-interop}/t294/Test_2.scala (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t2940/Cycle.java (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t2940/Error.scala (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t2956/BeanDefinitionVisitor.java (100%) rename tests/{disabled/java-interop/pos => pos/java-interop}/t2956/t2956.scala (100%) diff --git a/tests/disabled/java-interop/pos/t1459/AbstractBase.java b/tests/disabled/java-interop/failing/t1459/AbstractBase.java similarity index 100% rename from tests/disabled/java-interop/pos/t1459/AbstractBase.java rename to tests/disabled/java-interop/failing/t1459/AbstractBase.java diff --git a/tests/disabled/java-interop/pos/t1459/App.scala b/tests/disabled/java-interop/failing/t1459/App.scala similarity index 100% rename from tests/disabled/java-interop/pos/t1459/App.scala rename to tests/disabled/java-interop/failing/t1459/App.scala diff --git a/tests/disabled/java-interop/pos/t1459/Caller.java b/tests/disabled/java-interop/failing/t1459/Caller.java similarity index 100% rename from tests/disabled/java-interop/pos/t1459/Caller.java rename to tests/disabled/java-interop/failing/t1459/Caller.java diff --git a/tests/disabled/java-interop/pos/t2569/Child.scala b/tests/disabled/java-interop/failing/t2569/Child.scala similarity index 100% rename from tests/disabled/java-interop/pos/t2569/Child.scala rename to tests/disabled/java-interop/failing/t2569/Child.scala diff --git a/tests/disabled/java-interop/pos/t2569/Parent.java b/tests/disabled/java-interop/failing/t2569/Parent.java similarity index 100% rename from tests/disabled/java-interop/pos/t2569/Parent.java rename to tests/disabled/java-interop/failing/t2569/Parent.java diff --git a/tests/disabled/java-interop/pos/varargs-bridge/A.java b/tests/disabled/java-interop/failing/varargs-bridge/A.java similarity index 100% rename from tests/disabled/java-interop/pos/varargs-bridge/A.java rename to tests/disabled/java-interop/failing/varargs-bridge/A.java diff --git a/tests/disabled/java-interop/pos/varargs-bridge/B.scala b/tests/disabled/java-interop/failing/varargs-bridge/B.scala similarity index 100% rename from tests/disabled/java-interop/pos/varargs-bridge/B.scala rename to tests/disabled/java-interop/failing/varargs-bridge/B.scala diff --git a/tests/new/t296.scala b/tests/new/t296.scala new file mode 100644 index 000000000000..bb3b22984ae3 --- /dev/null +++ b/tests/new/t296.scala @@ -0,0 +1,5 @@ +object Bug { + def foo (l: => String, l1: => String) : String = 12 match { + case 12 => l1 + case _ => l} +} diff --git a/tests/disabled/java-interop/pos/t0288/Foo.scala b/tests/pos/java-interop/t0288/Foo.scala similarity index 100% rename from tests/disabled/java-interop/pos/t0288/Foo.scala rename to tests/pos/java-interop/t0288/Foo.scala diff --git a/tests/disabled/java-interop/pos/t0288/Outer.java b/tests/pos/java-interop/t0288/Outer.java similarity index 100% rename from tests/disabled/java-interop/pos/t0288/Outer.java rename to tests/pos/java-interop/t0288/Outer.java diff --git a/tests/disabled/java-interop/pos/t0695/JavaClass.java b/tests/pos/java-interop/t0695/JavaClass.java similarity index 100% rename from tests/disabled/java-interop/pos/t0695/JavaClass.java rename to tests/pos/java-interop/t0695/JavaClass.java diff --git a/tests/disabled/java-interop/pos/t0695/Test.scala b/tests/pos/java-interop/t0695/Test.scala similarity index 100% rename from tests/disabled/java-interop/pos/t0695/Test.scala rename to tests/pos/java-interop/t0695/Test.scala diff --git a/tests/disabled/java-interop/pos/t1101/J.java b/tests/pos/java-interop/t1101/J.java similarity index 100% rename from tests/disabled/java-interop/pos/t1101/J.java rename to tests/pos/java-interop/t1101/J.java diff --git a/tests/disabled/java-interop/pos/t1101/S.scala b/tests/pos/java-interop/t1101/S.scala similarity index 100% rename from tests/disabled/java-interop/pos/t1101/S.scala rename to tests/pos/java-interop/t1101/S.scala diff --git a/tests/disabled/java-interop/pos/t1102/J.java b/tests/pos/java-interop/t1102/J.java similarity index 100% rename from tests/disabled/java-interop/pos/t1102/J.java rename to tests/pos/java-interop/t1102/J.java diff --git a/tests/disabled/java-interop/pos/t1102/S.scala b/tests/pos/java-interop/t1102/S.scala similarity index 100% rename from tests/disabled/java-interop/pos/t1102/S.scala rename to tests/pos/java-interop/t1102/S.scala diff --git a/tests/disabled/java-interop/pos/t1150/J.java b/tests/pos/java-interop/t1150/J.java similarity index 100% rename from tests/disabled/java-interop/pos/t1150/J.java rename to tests/pos/java-interop/t1150/J.java diff --git a/tests/disabled/java-interop/pos/t1150/S.scala b/tests/pos/java-interop/t1150/S.scala similarity index 100% rename from tests/disabled/java-interop/pos/t1150/S.scala rename to tests/pos/java-interop/t1150/S.scala diff --git a/tests/disabled/java-interop/pos/t1152/J.java b/tests/pos/java-interop/t1152/J.java similarity index 100% rename from tests/disabled/java-interop/pos/t1152/J.java rename to tests/pos/java-interop/t1152/J.java diff --git a/tests/disabled/java-interop/pos/t1152/S.scala b/tests/pos/java-interop/t1152/S.scala similarity index 100% rename from tests/disabled/java-interop/pos/t1152/S.scala rename to tests/pos/java-interop/t1152/S.scala diff --git a/tests/disabled/java-interop/pos/t1176/J.java b/tests/pos/java-interop/t1176/J.java similarity index 100% rename from tests/disabled/java-interop/pos/t1176/J.java rename to tests/pos/java-interop/t1176/J.java diff --git a/tests/disabled/java-interop/pos/t1176/S.scala b/tests/pos/java-interop/t1176/S.scala similarity index 100% rename from tests/disabled/java-interop/pos/t1176/S.scala rename to tests/pos/java-interop/t1176/S.scala diff --git a/tests/disabled/java-interop/pos/t1186/t1186.java b/tests/pos/java-interop/t1186/t1186.java similarity index 100% rename from tests/disabled/java-interop/pos/t1186/t1186.java rename to tests/pos/java-interop/t1186/t1186.java diff --git a/tests/disabled/java-interop/pos/t1196/J.java b/tests/pos/java-interop/t1196/J.java similarity index 100% rename from tests/disabled/java-interop/pos/t1196/J.java rename to tests/pos/java-interop/t1196/J.java diff --git a/tests/disabled/java-interop/pos/t1196/S.scala b/tests/pos/java-interop/t1196/S.scala similarity index 100% rename from tests/disabled/java-interop/pos/t1196/S.scala rename to tests/pos/java-interop/t1196/S.scala diff --git a/tests/disabled/java-interop/pos/t1197/J.java b/tests/pos/java-interop/t1197/J.java similarity index 100% rename from tests/disabled/java-interop/pos/t1197/J.java rename to tests/pos/java-interop/t1197/J.java diff --git a/tests/disabled/java-interop/pos/t1197/S.scala b/tests/pos/java-interop/t1197/S.scala similarity index 100% rename from tests/disabled/java-interop/pos/t1197/S.scala rename to tests/pos/java-interop/t1197/S.scala diff --git a/tests/disabled/java-interop/pos/t1203b/J.java b/tests/pos/java-interop/t1203b/J.java similarity index 100% rename from tests/disabled/java-interop/pos/t1203b/J.java rename to tests/pos/java-interop/t1203b/J.java diff --git a/tests/disabled/java-interop/pos/t1203b/S.scala b/tests/pos/java-interop/t1203b/S.scala similarity index 100% rename from tests/disabled/java-interop/pos/t1203b/S.scala rename to tests/pos/java-interop/t1203b/S.scala diff --git a/tests/disabled/java-interop/pos/t1230/J.java b/tests/pos/java-interop/t1230/J.java similarity index 100% rename from tests/disabled/java-interop/pos/t1230/J.java rename to tests/pos/java-interop/t1230/J.java diff --git a/tests/disabled/java-interop/pos/t1230/S.scala b/tests/pos/java-interop/t1230/S.scala similarity index 100% rename from tests/disabled/java-interop/pos/t1230/S.scala rename to tests/pos/java-interop/t1230/S.scala diff --git a/tests/disabled/java-interop/pos/t1231/J.java b/tests/pos/java-interop/t1231/J.java similarity index 100% rename from tests/disabled/java-interop/pos/t1231/J.java rename to tests/pos/java-interop/t1231/J.java diff --git a/tests/disabled/java-interop/pos/t1231/S.scala b/tests/pos/java-interop/t1231/S.scala similarity index 100% rename from tests/disabled/java-interop/pos/t1231/S.scala rename to tests/pos/java-interop/t1231/S.scala diff --git a/tests/disabled/java-interop/pos/t1232/J.java b/tests/pos/java-interop/t1232/J.java similarity index 100% rename from tests/disabled/java-interop/pos/t1232/J.java rename to tests/pos/java-interop/t1232/J.java diff --git a/tests/disabled/java-interop/pos/t1232/J2.java b/tests/pos/java-interop/t1232/J2.java similarity index 100% rename from tests/disabled/java-interop/pos/t1232/J2.java rename to tests/pos/java-interop/t1232/J2.java diff --git a/tests/disabled/java-interop/pos/t1232/S.scala b/tests/pos/java-interop/t1232/S.scala similarity index 100% rename from tests/disabled/java-interop/pos/t1232/S.scala rename to tests/pos/java-interop/t1232/S.scala diff --git a/tests/disabled/java-interop/pos/t1235/Test.java b/tests/pos/java-interop/t1235/Test.java similarity index 100% rename from tests/disabled/java-interop/pos/t1235/Test.java rename to tests/pos/java-interop/t1235/Test.java diff --git a/tests/disabled/java-interop/pos/t1254/t1254.java b/tests/pos/java-interop/t1254/t1254.java similarity index 100% rename from tests/disabled/java-interop/pos/t1254/t1254.java rename to tests/pos/java-interop/t1254/t1254.java diff --git a/tests/disabled/java-interop/pos/t1263/Test.java b/tests/pos/java-interop/t1263/Test.java similarity index 100% rename from tests/disabled/java-interop/pos/t1263/Test.java rename to tests/pos/java-interop/t1263/Test.java diff --git a/tests/disabled/java-interop/pos/t1263/test.scala b/tests/pos/java-interop/t1263/test.scala similarity index 100% rename from tests/disabled/java-interop/pos/t1263/test.scala rename to tests/pos/java-interop/t1263/test.scala diff --git a/tests/disabled/java-interop/pos/t1409/AbstractImpl.java b/tests/pos/java-interop/t1409/AbstractImpl.java similarity index 100% rename from tests/disabled/java-interop/pos/t1409/AbstractImpl.java rename to tests/pos/java-interop/t1409/AbstractImpl.java diff --git a/tests/disabled/java-interop/pos/t1409/ConcreteImpl.scala b/tests/pos/java-interop/t1409/ConcreteImpl.scala similarity index 100% rename from tests/disabled/java-interop/pos/t1409/ConcreteImpl.scala rename to tests/pos/java-interop/t1409/ConcreteImpl.scala diff --git a/tests/disabled/java-interop/pos/t1409/OuterInterface.java b/tests/pos/java-interop/t1409/OuterInterface.java similarity index 100% rename from tests/disabled/java-interop/pos/t1409/OuterInterface.java rename to tests/pos/java-interop/t1409/OuterInterface.java diff --git a/tests/disabled/java-interop/pos/t1642/JavaCallingScalaHashMap.java b/tests/pos/java-interop/t1642/JavaCallingScalaHashMap.java similarity index 100% rename from tests/disabled/java-interop/pos/t1642/JavaCallingScalaHashMap.java rename to tests/pos/java-interop/t1642/JavaCallingScalaHashMap.java diff --git a/tests/disabled/java-interop/pos/t1711/Seq.scala b/tests/pos/java-interop/t1711/Seq.scala similarity index 100% rename from tests/disabled/java-interop/pos/t1711/Seq.scala rename to tests/pos/java-interop/t1711/Seq.scala diff --git a/tests/disabled/java-interop/pos/t1711/Test.java b/tests/pos/java-interop/t1711/Test.java similarity index 100% rename from tests/disabled/java-interop/pos/t1711/Test.java rename to tests/pos/java-interop/t1711/Test.java diff --git a/tests/disabled/java-interop/pos/t1745/J.java b/tests/pos/java-interop/t1745/J.java similarity index 100% rename from tests/disabled/java-interop/pos/t1745/J.java rename to tests/pos/java-interop/t1745/J.java diff --git a/tests/disabled/java-interop/pos/t1745/S.scala b/tests/pos/java-interop/t1745/S.scala similarity index 100% rename from tests/disabled/java-interop/pos/t1745/S.scala rename to tests/pos/java-interop/t1745/S.scala diff --git a/tests/disabled/java-interop/failing/t1751/A1_2.scala b/tests/pos/java-interop/t1751/A1_2.scala similarity index 100% rename from tests/disabled/java-interop/failing/t1751/A1_2.scala rename to tests/pos/java-interop/t1751/A1_2.scala diff --git a/tests/disabled/java-interop/failing/t1751/A2_1.scala b/tests/pos/java-interop/t1751/A2_1.scala similarity index 100% rename from tests/disabled/java-interop/failing/t1751/A2_1.scala rename to tests/pos/java-interop/t1751/A2_1.scala diff --git a/tests/disabled/java-interop/failing/t1751/SuiteClasses.java b/tests/pos/java-interop/t1751/SuiteClasses.java similarity index 100% rename from tests/disabled/java-interop/failing/t1751/SuiteClasses.java rename to tests/pos/java-interop/t1751/SuiteClasses.java diff --git a/tests/disabled/java-interop/pos/t1782/Ann.java b/tests/pos/java-interop/t1782/Ann.java similarity index 100% rename from tests/disabled/java-interop/pos/t1782/Ann.java rename to tests/pos/java-interop/t1782/Ann.java diff --git a/tests/disabled/java-interop/pos/t1782/Days.java b/tests/pos/java-interop/t1782/Days.java similarity index 100% rename from tests/disabled/java-interop/pos/t1782/Days.java rename to tests/pos/java-interop/t1782/Days.java diff --git a/tests/disabled/java-interop/pos/t1782/ImplementedBy.java b/tests/pos/java-interop/t1782/ImplementedBy.java similarity index 100% rename from tests/disabled/java-interop/pos/t1782/ImplementedBy.java rename to tests/pos/java-interop/t1782/ImplementedBy.java diff --git a/tests/disabled/java-interop/pos/t1782/Test_1.scala b/tests/pos/java-interop/t1782/Test_1.scala similarity index 100% rename from tests/disabled/java-interop/pos/t1782/Test_1.scala rename to tests/pos/java-interop/t1782/Test_1.scala diff --git a/tests/disabled/java-interop/pos/t1836/J.java b/tests/pos/java-interop/t1836/J.java similarity index 100% rename from tests/disabled/java-interop/pos/t1836/J.java rename to tests/pos/java-interop/t1836/J.java diff --git a/tests/disabled/java-interop/pos/t1836/S.scala b/tests/pos/java-interop/t1836/S.scala similarity index 100% rename from tests/disabled/java-interop/pos/t1836/S.scala rename to tests/pos/java-interop/t1836/S.scala diff --git a/tests/disabled/java-interop/pos/t1840/J.java b/tests/pos/java-interop/t1840/J.java similarity index 100% rename from tests/disabled/java-interop/pos/t1840/J.java rename to tests/pos/java-interop/t1840/J.java diff --git a/tests/disabled/java-interop/pos/t1840/S.scala b/tests/pos/java-interop/t1840/S.scala similarity index 100% rename from tests/disabled/java-interop/pos/t1840/S.scala rename to tests/pos/java-interop/t1840/S.scala diff --git a/tests/disabled/java-interop/pos/t1937/NumberGenerator.java b/tests/pos/java-interop/t1937/NumberGenerator.java similarity index 100% rename from tests/disabled/java-interop/pos/t1937/NumberGenerator.java rename to tests/pos/java-interop/t1937/NumberGenerator.java diff --git a/tests/disabled/java-interop/pos/t2377/Q.java b/tests/pos/java-interop/t2377/Q.java similarity index 100% rename from tests/disabled/java-interop/pos/t2377/Q.java rename to tests/pos/java-interop/t2377/Q.java diff --git a/tests/disabled/java-interop/pos/t2377/a.scala b/tests/pos/java-interop/t2377/a.scala similarity index 100% rename from tests/disabled/java-interop/pos/t2377/a.scala rename to tests/pos/java-interop/t2377/a.scala diff --git a/tests/disabled/java-interop/pos/t2409/J.java b/tests/pos/java-interop/t2409/J.java similarity index 100% rename from tests/disabled/java-interop/pos/t2409/J.java rename to tests/pos/java-interop/t2409/J.java diff --git a/tests/disabled/java-interop/pos/t2409/t2409.scala b/tests/pos/java-interop/t2409/t2409.scala similarity index 100% rename from tests/disabled/java-interop/pos/t2409/t2409.scala rename to tests/pos/java-interop/t2409/t2409.scala diff --git a/tests/disabled/java-interop/pos/t2413/TestJava.java b/tests/pos/java-interop/t2413/TestJava.java similarity index 100% rename from tests/disabled/java-interop/pos/t2413/TestJava.java rename to tests/pos/java-interop/t2413/TestJava.java diff --git a/tests/disabled/java-interop/pos/t2413/TestScalac.scala b/tests/pos/java-interop/t2413/TestScalac.scala similarity index 100% rename from tests/disabled/java-interop/pos/t2413/TestScalac.scala rename to tests/pos/java-interop/t2413/TestScalac.scala diff --git a/tests/disabled/java-interop/pos/t2433/A.java b/tests/pos/java-interop/t2433/A.java similarity index 100% rename from tests/disabled/java-interop/pos/t2433/A.java rename to tests/pos/java-interop/t2433/A.java diff --git a/tests/disabled/java-interop/pos/t2433/B.java b/tests/pos/java-interop/t2433/B.java similarity index 100% rename from tests/disabled/java-interop/pos/t2433/B.java rename to tests/pos/java-interop/t2433/B.java diff --git a/tests/disabled/java-interop/pos/t2433/Test.scala b/tests/pos/java-interop/t2433/Test.scala similarity index 100% rename from tests/disabled/java-interop/pos/t2433/Test.scala rename to tests/pos/java-interop/t2433/Test.scala diff --git a/tests/disabled/java-interop/pos/t2464/JavaOne.java b/tests/pos/java-interop/t2464/JavaOne.java similarity index 100% rename from tests/disabled/java-interop/pos/t2464/JavaOne.java rename to tests/pos/java-interop/t2464/JavaOne.java diff --git a/tests/disabled/java-interop/pos/t2464/ScalaOne_1.scala b/tests/pos/java-interop/t2464/ScalaOne_1.scala similarity index 100% rename from tests/disabled/java-interop/pos/t2464/ScalaOne_1.scala rename to tests/pos/java-interop/t2464/ScalaOne_1.scala diff --git a/tests/disabled/java-interop/pos/t2464/t2464_2.scala b/tests/pos/java-interop/t2464/t2464_2.scala similarity index 100% rename from tests/disabled/java-interop/pos/t2464/t2464_2.scala rename to tests/pos/java-interop/t2464/t2464_2.scala diff --git a/tests/disabled/java-interop/pos/t2764/Ann.java b/tests/pos/java-interop/t2764/Ann.java similarity index 100% rename from tests/disabled/java-interop/pos/t2764/Ann.java rename to tests/pos/java-interop/t2764/Ann.java diff --git a/tests/disabled/java-interop/pos/t2764/Enum.java b/tests/pos/java-interop/t2764/Enum.java similarity index 100% rename from tests/disabled/java-interop/pos/t2764/Enum.java rename to tests/pos/java-interop/t2764/Enum.java diff --git a/tests/disabled/java-interop/pos/t2764/Use.scala b/tests/pos/java-interop/t2764/Use.scala similarity index 100% rename from tests/disabled/java-interop/pos/t2764/Use.scala rename to tests/pos/java-interop/t2764/Use.scala diff --git a/tests/disabled/java-interop/failing/t294/Ann.java b/tests/pos/java-interop/t294/Ann.java similarity index 100% rename from tests/disabled/java-interop/failing/t294/Ann.java rename to tests/pos/java-interop/t294/Ann.java diff --git a/tests/disabled/java-interop/failing/t294/Ann2.java b/tests/pos/java-interop/t294/Ann2.java similarity index 100% rename from tests/disabled/java-interop/failing/t294/Ann2.java rename to tests/pos/java-interop/t294/Ann2.java diff --git a/tests/disabled/java-interop/failing/t294/Test_1.scala b/tests/pos/java-interop/t294/Test_1.scala similarity index 100% rename from tests/disabled/java-interop/failing/t294/Test_1.scala rename to tests/pos/java-interop/t294/Test_1.scala diff --git a/tests/disabled/java-interop/failing/t294/Test_2.scala b/tests/pos/java-interop/t294/Test_2.scala similarity index 100% rename from tests/disabled/java-interop/failing/t294/Test_2.scala rename to tests/pos/java-interop/t294/Test_2.scala diff --git a/tests/disabled/java-interop/pos/t2940/Cycle.java b/tests/pos/java-interop/t2940/Cycle.java similarity index 100% rename from tests/disabled/java-interop/pos/t2940/Cycle.java rename to tests/pos/java-interop/t2940/Cycle.java diff --git a/tests/disabled/java-interop/pos/t2940/Error.scala b/tests/pos/java-interop/t2940/Error.scala similarity index 100% rename from tests/disabled/java-interop/pos/t2940/Error.scala rename to tests/pos/java-interop/t2940/Error.scala diff --git a/tests/disabled/java-interop/pos/t2956/BeanDefinitionVisitor.java b/tests/pos/java-interop/t2956/BeanDefinitionVisitor.java similarity index 100% rename from tests/disabled/java-interop/pos/t2956/BeanDefinitionVisitor.java rename to tests/pos/java-interop/t2956/BeanDefinitionVisitor.java diff --git a/tests/disabled/java-interop/pos/t2956/t2956.scala b/tests/pos/java-interop/t2956/t2956.scala similarity index 100% rename from tests/disabled/java-interop/pos/t2956/t2956.scala rename to tests/pos/java-interop/t2956/t2956.scala From ec104eff6f770c780a26e6cf930063690fb2a340 Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Mon, 17 Nov 2014 17:31:29 +0100 Subject: [PATCH 43/46] Enabling java tests --- test/dotc/tests.scala | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala index c08dda4c42f8..f4aa074de095 100644 --- a/test/dotc/tests.scala +++ b/test/dotc/tests.scala @@ -113,7 +113,9 @@ class tests extends CompilerTest { @Test def dotc_config = compileDir(dotcDir + "tools/dotc/config", twice) @Test def dotc_core = compileDir(dotcDir + "tools/dotc/core", twice)(allowDeepSubtypes) @Test def dotc_core_pickling = compileDir(dotcDir + "tools/dotc/core/pickling", twice)(allowDeepSubtypes) - @Test def dotc_transform = compileDir(dotcDir + "tools/dotc/transform", twice) + // @Test def dotc_transform = compileDir(dotcDir + "tools/dotc/transform", twice) + // @odersky causes race error in ResolveSuper + @Test def dotc_parsing = compileDir(dotcDir + "tools/dotc/parsing", twice) @Test def dotc_printing = compileDir(dotcDir + "tools/dotc/printing", twice) @Test def dotc_reporting = compileDir(dotcDir + "tools/dotc/reporting", twice) @@ -137,11 +139,9 @@ class tests extends CompilerTest { "-Xprompt", "#runs", "2")) - val javaDir = "./tests/disabled/java-interop/" - @Test def java_all = compileFiles(javaDir+"pos/") + val javaDir = "./tests/pos/java-interop/" + @Test def java_all = compileFiles(javaDir) - @Test def java_1751 = compileDir(javaDir+"failing/t1751") - @Test def java_294 = compileDir(javaDir+"failing/t294") //@Test def dotc_compilercommand = compileFile(dotcDir + "tools/dotc/config/", "CompilerCommand") } From 31aef8132822b4b57c958e7fa17bad24d47fb8d6 Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Thu, 20 Nov 2014 17:54:24 +0100 Subject: [PATCH 44/46] Address reviewer feedback: restructure applyOverloaded. --- src/dotty/tools/dotc/ast/tpd.scala | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala index 61761bcae520..98609f9f1a38 100644 --- a/src/dotty/tools/dotc/ast/tpd.scala +++ b/src/dotty/tools/dotc/ast/tpd.scala @@ -692,26 +692,33 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { .select(TermRef.withSig(receiver.tpe.normalizedPrefix, selected.termSymbol.asTerm)) .appliedToTypes(targs) - val callArgs: List[Tree] = if(args.isEmpty) Nil else { - val lastParamType = selected.widen.paramTypess.head.last - val lastParam = args.last - if (isAnnotConstructor && !(lastParam.tpe <:< lastParamType)) { + 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) - lastParamType match { + 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 + 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 defn.ArrayType(el) if(lastParam) 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 } From 14654c374a4a843832ddcfaf419f79d756842237 Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Thu, 20 Nov 2014 19:41:11 +0100 Subject: [PATCH 45/46] Drop java-defined trees in FirstTransform --- src/dotty/tools/dotc/transform/FirstTransform.scala | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/dotty/tools/dotc/transform/FirstTransform.scala b/src/dotty/tools/dotc/transform/FirstTransform.scala index 5e3af53da352..7bfb2b397471 100644 --- a/src/dotty/tools/dotc/transform/FirstTransform.scala +++ b/src/dotty/tools/dotc/transform/FirstTransform.scala @@ -28,6 +28,7 @@ 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 with AnnotationTransformer { thisTransformer => import ast.tpd._ @@ -84,7 +85,10 @@ class FirstTransform extends MiniPhaseTransform with IdentityDenotTransformer wi Thicket(stat :: newCompanion(stat.name.toTermName).trees) case stat => stat } - addMissingCompanions(reorder(stats)) + + def skipJava(stats: List[Tree]): List[Tree] = stats.filter(t => !(t.symbol is Flags.JavaDefined)) + + addMissingCompanions(reorder(skipJava(stats))) } override def transformDefDef(ddef: DefDef)(implicit ctx: Context, info: TransformerInfo) = { From 859a7fe21d4e2b9a2f336bc38815b21367a2993b Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Sat, 22 Nov 2014 20:25:36 +0100 Subject: [PATCH 46/46] Do not skip packages in FirstTransform Packages also get a JavaDefined flag, but they shouldn't be removed by FirstTransform. --- src/dotty/tools/dotc/transform/FirstTransform.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/dotty/tools/dotc/transform/FirstTransform.scala b/src/dotty/tools/dotc/transform/FirstTransform.scala index 7bfb2b397471..29cef09fe97c 100644 --- a/src/dotty/tools/dotc/transform/FirstTransform.scala +++ b/src/dotty/tools/dotc/transform/FirstTransform.scala @@ -86,7 +86,8 @@ class FirstTransform extends MiniPhaseTransform with IdentityDenotTransformer wi case stat => stat } - def skipJava(stats: List[Tree]): List[Tree] = stats.filter(t => !(t.symbol is Flags.JavaDefined)) + 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))) }