Skip to content

Commit 779afd2

Browse files
committed
Merge pull request #213 from dotty-staging/javaparser
Javaparser & ElimRepeated fixes & Annotation-fixes
2 parents 33feb9d + 859a7fe commit 779afd2

File tree

117 files changed

+2150
-271
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

117 files changed

+2150
-271
lines changed

src/dotty/tools/dotc/TypeErasure.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,9 @@ object TypeErasure {
9595
def erasure(tp: Type)(implicit ctx: Context): Type = scalaErasureFn(tp)(erasureCtx)
9696
def semiErasure(tp: Type)(implicit ctx: Context): Type = semiErasureFn(tp)(erasureCtx)
9797
def sigName(tp: Type, isJava: Boolean)(implicit ctx: Context): TypeName = {
98+
val seqClass = if(isJava) defn.ArrayClass else defn.SeqClass
9899
val normTp =
99-
if (tp.isRepeatedParam) tp.translateParameterized(defn.RepeatedParamClass, defn.SeqClass)
100+
if (tp.isRepeatedParam) tp.translateParameterized(defn.RepeatedParamClass, seqClass)
100101
else tp
101102
(if (isJava) javaSigFn else scalaSigFn).sigName(normTp)(erasureCtx)
102103
}

src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -771,11 +771,12 @@ object desugar {
771771
else // l.op(r), or val x = r; l.op(x), plus handle named args specially
772772
makeBinop(l, op, r)
773773
case PostfixOp(t, op) =>
774-
if ((ctx.mode is Mode.Type) && op == nme.raw.STAR)
774+
if ((ctx.mode is Mode.Type) && op == nme.raw.STAR) {
775+
val seqClass = if (ctx.compilationUnit.isJava) defn.ArrayClass else defn.SeqClass
775776
Annotated(
776777
New(ref(defn.RepeatedAnnot.typeRef), Nil :: Nil),
777-
AppliedTypeTree(ref(defn.SeqClass.typeRef), t))
778-
else {
778+
AppliedTypeTree(ref(seqClass.typeRef), t))
779+
} else {
779780
assert(ctx.mode.isExpr, ctx.mode)
780781
Select(t, op)
781782
}

src/dotty/tools/dotc/ast/tpd.scala

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package dotty.tools
22
package dotc
33
package ast
44

5+
import dotty.tools.dotc.typer.ProtoTypes.FunProtoTyped
56
import transform.SymUtils._
67
import core._
78
import util.Positions._, Types._, Contexts._, Constants._, Names._, Flags._
@@ -126,8 +127,8 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
126127
if (tpe derivesFrom defn.SeqClass) SeqLiteral(elems) else JavaSeqLiteral(elems)
127128

128129
def JavaSeqLiteral(elems: List[Tree])(implicit ctx: Context): SeqLiteral =
129-
new untpd.JavaSeqLiteral(elems)
130-
.withType(defn.ArrayClass.typeRef.appliedTo(ctx.typeComparer.lub(elems.tpes)))
130+
ta.assignType(new untpd.JavaSeqLiteral(elems), elems)
131+
131132

132133
def TypeTree(original: Tree)(implicit ctx: Context): TypeTree =
133134
TypeTree(original.tpe, original)
@@ -677,6 +678,50 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
677678
Throw(New(defn.ClassCastExceptionClass.typeRef, Nil)) withPos tree.pos
678679
}
679680
}
681+
682+
def applyOverloaded(receiver: Tree, method: TermName, args: List[Tree], targs: List[Type], expectedType: Type, isAnnotConstructor: Boolean = false)(implicit ctx: Context): Tree = {
683+
val typer = ctx.typer
684+
val proto = new FunProtoTyped(args, expectedType, typer)
685+
val alts = receiver.tpe.member(method).alternatives.map(_.termRef)
686+
687+
val alternatives = ctx.typer.resolveOverloaded(alts, proto, Nil)
688+
assert(alternatives.size == 1) // this is parsed from bytecode tree. there's nothing user can do about it
689+
690+
val selected = alternatives.head
691+
val fun = receiver
692+
.select(TermRef.withSig(receiver.tpe.normalizedPrefix, selected.termSymbol.asTerm))
693+
.appliedToTypes(targs)
694+
695+
def adaptLastArg(lastParam: Tree, expectedType: Type) = {
696+
if (isAnnotConstructor && !(lastParam.tpe <:< expectedType)) {
697+
val defn = ctx.definitions
698+
val prefix = args.take(selected.widen.paramTypess.head.size - 1)
699+
expectedType match {
700+
case defn.ArrayType(el) =>
701+
lastParam.tpe match {
702+
case defn.ArrayType(el2) if (el2 <:< el) =>
703+
// we have a JavaSeqLiteral with a more precise type
704+
// we cannot construct a tree as JavaSeqLiteral infered to precise type
705+
// if we add typed than it would be both type-correct and
706+
// will pass Ycheck
707+
prefix ::: List(tpd.Typed(lastParam, TypeTree(defn.ArrayType(el))))
708+
case _ =>
709+
???
710+
}
711+
case _ => args
712+
}
713+
} else args
714+
}
715+
716+
val callArgs: List[Tree] = if(args.isEmpty) Nil else {
717+
val expectedType = selected.widen.paramTypess.head.last
718+
val lastParam = args.last
719+
adaptLastArg(lastParam, expectedType)
720+
}
721+
722+
val apply = untpd.Apply(fun, callArgs)
723+
new typer.ApplyToTyped(apply, fun, selected, callArgs, expectedType).result.asInstanceOf[Tree] // needed to handle varargs
724+
}
680725

681726
@tailrec
682727
def sameTypes(trees: List[tpd.Tree], trees1: List[tpd.Tree]): Boolean = {

src/dotty/tools/dotc/config/ScalaSettings.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ class ScalaSettings extends Settings.SettingGroup {
9999
val Yhelp = BooleanSetting("-Y", "Print a synopsis of private options.")
100100
val browse = PhasesSetting("-Ybrowse", "Browse the abstract syntax tree after")
101101
val Ycheck = PhasesSetting("-Ycheck", "Check the tree at the end of")
102+
val YcheckMods = BooleanSetting("-Ycheck-mods", "Check that symbols and their defining trees have modifiers in sync")
102103
val YcheckTypedTrees = BooleanSetting("-YcheckTypedTrees", "Check all constructured typed trees for type correctness")
103104
val Yshow = PhasesSetting("-Yshow", "(Requires -Xshow-class or -Xshow-object) Show after")
104105
val Xcloselim = BooleanSetting("-Yclosure-elim", "Perform closure elimination.")

src/dotty/tools/dotc/core/Annotations.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ package core
33

44
import Symbols._, Types._, util.Positions._, Contexts._, Constants._, ast.tpd._
55
import config.ScalaVersion
6+
import StdNames._
7+
import dotty.tools.dotc.ast.{tpd, untpd}
8+
import dotty.tools.dotc.typer.ProtoTypes.FunProtoTyped
69

710
object Annotations {
811

@@ -61,12 +64,24 @@ object Annotations {
6164
def apply(atp: Type, args: List[Tree])(implicit ctx: Context): Annotation =
6265
apply(New(atp, args))
6366

67+
private def resolveConstructor(atp: Type, args:List[Tree])(implicit ctx: Context): Tree = {
68+
val targs = atp.argTypes
69+
tpd.applyOverloaded(New(atp withoutArgs targs), nme.CONSTRUCTOR, args, targs, atp, isAnnotConstructor = true)
70+
}
71+
72+
def applyResolve(atp: Type, args: List[Tree])(implicit ctx: Context): Annotation = {
73+
apply(resolveConstructor(atp, args))
74+
}
75+
6476
def deferred(sym: Symbol, treeFn: Context => Tree)(implicit ctx: Context): Annotation =
6577
new LazyAnnotation(sym)(treeFn)
6678

6779
def deferred(atp: Type, args: List[Tree])(implicit ctx: Context): Annotation =
6880
deferred(atp.classSymbol, implicit ctx => New(atp, args))
6981

82+
def deferredResolve(atp: Type, args: List[Tree])(implicit ctx: Context): Annotation =
83+
deferred(atp.classSymbol, implicit ctx => resolveConstructor(atp, args))
84+
7085
def makeAlias(sym: TermSymbol)(implicit ctx: Context) =
7186
apply(defn.AliasAnnot, List(
7287
ref(TermRef.withSigAndDenot(sym.owner.thisType, sym.name, sym.signature, sym))))

src/dotty/tools/dotc/core/Flags.scala

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ object Flags {
318318
/** An unpickled Scala 2.x class */
319319
final val Scala2x = typeFlag(26, "<scala-2.x>")
320320

321-
/** A method that has default params */ // TODO: drop
321+
/** A method that has default params */
322322
final val DefaultParameterized = termFlag(27, "<defaultparam>")
323323

324324
/** Symbol is initialized to the default value, e.g. var x: T = _ */
@@ -356,6 +356,12 @@ object Flags {
356356
/** Symbol is a Java-style varargs method */
357357
final val JavaVarargs = termFlag(37, "<varargs>")
358358

359+
/** Symbol is a Java default method */
360+
final val DefaultMethod = termFlag(38, "<defaultmethod>")
361+
362+
/** Symbol is a Java enum */
363+
final val Enum = commonFlag(40, "<enum>")
364+
359365
// Flags following this one are not pickled
360366

361367
/** Symbol always defines a fresh named type */
@@ -547,6 +553,9 @@ object Flags {
547553

548554
/** A Java interface, potentially with default methods */
549555
final val JavaTrait = allOf(JavaDefined, Trait, NoInits)
556+
557+
/** A Java interface */
558+
final val JavaInterface = allOf(JavaDefined, Trait)
550559

551560
/** A Java companion object */
552561
final val JavaModule = allOf(JavaDefined, Module)

src/dotty/tools/dotc/core/TypeApplications.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,10 @@ class TypeApplications(val self: Type) extends AnyVal {
284284
* or, if isJava is true, Array type, else the type itself.
285285
*/
286286
def underlyingIfRepeated(isJava: Boolean)(implicit ctx: Context): Type =
287-
if (self.isRepeatedParam) translateParameterized(defn.RepeatedParamClass, defn.SeqClass)
287+
if (self.isRepeatedParam) {
288+
val seqClass = if(isJava) defn.ArrayClass else defn.SeqClass
289+
translateParameterized(defn.RepeatedParamClass, seqClass)
290+
}
288291
else self
289292

290293
/** If this is an encoding of a (partially) applied type, return its arguments,

src/dotty/tools/dotc/core/Types.scala

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ object Types {
3535

3636
private var recCount = 0 // used temporarily for debugging. TODO: remove
3737

38+
private var nextId = 0
39+
3840
/** The class of types.
3941
* The principal subclasses and sub-objects are as follows:
4042
*
@@ -70,6 +72,13 @@ object Types {
7072

7173
// ----- Tests -----------------------------------------------------
7274

75+
val uniqId = {
76+
nextId = nextId + 1
77+
// if(nextId == 19555)
78+
// println("foo")
79+
nextId
80+
}
81+
7382
/** Is this type different from NoType? */
7483
def exists: Boolean = true
7584

@@ -1965,7 +1974,9 @@ object Types {
19651974
def fromSymbols(params: List[Symbol], resultType: Type)(implicit ctx: Context) = {
19661975
def paramInfo(param: Symbol): Type = param.info match {
19671976
case AnnotatedType(annot, tp) if annot matches defn.RepeatedAnnot =>
1968-
tp.translateParameterized(defn.SeqClass, defn.RepeatedParamClass)
1977+
val typeSym = param.info.typeSymbol.asClass
1978+
assert(typeSym == defn.SeqClass || typeSym == defn.ArrayClass)
1979+
tp.translateParameterized(typeSym, defn.RepeatedParamClass)
19691980
case tp =>
19701981
tp
19711982
}
@@ -2024,9 +2035,9 @@ object Types {
20242035

20252036
def derivedPolyType(paramNames: List[TypeName], paramBounds: List[TypeBounds], restpe: Type)(implicit ctx: Context) =
20262037
if ((paramNames eq this.paramNames) && (paramBounds eq this.paramBounds) && (restpe eq this.resultType)) this
2027-
else copy(paramNames, paramBounds, restpe)
2038+
else duplicate(paramNames, paramBounds, restpe)
20282039

2029-
def copy(paramNames: List[TypeName], paramBounds: List[TypeBounds], restpe: Type)(implicit ctx: Context) =
2040+
def duplicate(paramNames: List[TypeName] = this.paramNames, paramBounds: List[TypeBounds] = this.paramBounds, restpe: Type)(implicit ctx: Context) =
20302041
PolyType(paramNames)(
20312042
x => paramBounds mapConserve (_.subst(this, x).bounds),
20322043
x => restpe.subst(this, x))

src/dotty/tools/dotc/core/pickling/ClassfileParser.scala

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ class ClassfileParser(
128128
for (i <- 0 until in.nextChar) parseMember(method = false)
129129
for (i <- 0 until in.nextChar) parseMember(method = true)
130130
classInfo = parseAttributes(classRoot.symbol, classInfo)
131+
if (isAnnotation) addAnnotationConstructor(classInfo)
131132
setClassInfo(classRoot, classInfo)
132133
setClassInfo(moduleRoot, staticInfo)
133134
}
@@ -421,7 +422,7 @@ class ClassfileParser(
421422
case None => hasError = true
422423
}
423424
if (hasError) None
424-
else if (skip) None else Some(SeqLiteral(arr.toList))
425+
else if (skip) None else Some(JavaSeqLiteral(arr.toList))
425426
case ANNOTATION_TAG =>
426427
parseAnnotation(index, skip) map (_.tree)
427428
}
@@ -443,7 +444,7 @@ class ClassfileParser(
443444
}
444445
}
445446
if (hasError || skip) None
446-
else Some(Annotation.deferred(attrType, argbuf.toList))
447+
else Some(Annotation.deferredResolve(attrType, argbuf.toList))
447448
} catch {
448449
case f: FatalError => throw f // don't eat fatal errors, they mean a class was not found
449450
case ex: Throwable =>
@@ -551,6 +552,45 @@ class ClassfileParser(
551552
newType
552553
}
553554

555+
/** Add a synthetic constructor and potentially also default getters which
556+
* reflects the fields of the annotation with given `classInfo`.
557+
* Annotations in Scala are assumed to get all their arguments as constructor
558+
* parameters. For Java annotations we need to fake it by making up the constructor.
559+
* Note that default getters have type Nothing. That's OK because we need
560+
* them only to signal that the corresponding parameter is optional.
561+
*/
562+
def addAnnotationConstructor(classInfo: Type, tparams: List[Symbol] = Nil)(implicit ctx: Context): Unit = {
563+
def addDefaultGetter(attr: Symbol, n: Int) =
564+
ctx.newSymbol(
565+
owner = moduleRoot.symbol,
566+
name = nme.CONSTRUCTOR.defaultGetterName(n),
567+
flags = attr.flags & Flags.AccessFlags,
568+
info = defn.NothingType).entered
569+
570+
classInfo match {
571+
case classInfo @ TempPolyType(tparams, restpe) if tparams.isEmpty =>
572+
addAnnotationConstructor(restpe, tparams)
573+
case classInfo: TempClassInfoType =>
574+
val attrs = classInfo.decls.toList.filter(_.isTerm)
575+
val targs = tparams.map(_.typeRef)
576+
val methType = MethodType(
577+
attrs.map(_.name.asTermName),
578+
attrs.map(_.info.resultType),
579+
classRoot.typeRef.appliedTo(targs))
580+
val constr = ctx.newSymbol(
581+
owner = classRoot.symbol,
582+
name = nme.CONSTRUCTOR,
583+
flags = Flags.Synthetic,
584+
info = if (tparams.isEmpty) methType else TempPolyType(tparams, methType)
585+
).entered
586+
for ((attr, i) <- attrs.zipWithIndex)
587+
if (attr.hasAnnotation(defn.AnnotationDefaultAnnot)) {
588+
constr.setFlag(Flags.HasDefaultParams)
589+
addDefaultGetter(attr, i)
590+
}
591+
}
592+
}
593+
554594
/** Enter own inner classes in the right scope. It needs the scopes to be set up,
555595
* and implicitly current class' superclasses.
556596
*/

src/dotty/tools/dotc/core/pickling/PickleBuffer.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,8 @@ object PickleBuffer {
251251
SPECIALIZED -> Specialized,
252252
DEFAULTINIT -> DefaultInit,
253253
VBRIDGE -> VBridge,
254-
VARARGS -> JavaVarargs)
254+
VARARGS -> JavaVarargs,
255+
ENUM -> Enum)
255256

256257
// generate initial maps from Scala flags to Dotty flags
257258
val termMap, typeMap = new Array[Long](64)

src/dotty/tools/dotc/core/pickling/UnPickler.scala

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@ import java.lang.Double.longBitsToDouble
99

1010
import Contexts._, Symbols._, Types._, Scopes._, SymDenotations._, Names._, NameOps._
1111
import StdNames._, Denotations._, NameOps._, Flags._, Constants._, Annotations._
12+
import dotty.tools.dotc.typer.ProtoTypes.{FunProtoTyped, FunProto}
1213
import util.Positions._
13-
import ast.Trees, ast.tpd._, ast.untpd
14+
import dotty.tools.dotc.ast.{tpd, Trees, untpd}, ast.tpd._
1415
import printing.Texts._
1516
import printing.Printer
1617
import io.AbstractFile
@@ -815,19 +816,26 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot:
815816
*/
816817
protected def readAnnotationContents(end: Int)(implicit ctx: Context): Tree = {
817818
val atp = readTypeRef()
818-
val args = new ListBuffer[Tree]
819-
while (readIndex != end) {
820-
val argref = readNat()
821-
args += {
822-
if (isNameEntry(argref)) {
823-
val name = at(argref, readName)
824-
val arg = readClassfileAnnotArg(readNat())
825-
NamedArg(name.asTermName, arg)
826-
} else readAnnotArg(argref)
819+
val args = {
820+
val t = new ListBuffer[Tree]
821+
822+
while (readIndex != end) {
823+
val argref = readNat()
824+
t += {
825+
if (isNameEntry(argref)) {
826+
val name = at(argref, readName)
827+
val arg = readClassfileAnnotArg(readNat())
828+
NamedArg(name.asTermName, arg)
829+
} else readAnnotArg(argref)
830+
}
827831
}
832+
t.toList
828833
}
829-
New(atp, args.toList)
830-
}
834+
// println(atp)
835+
val targs = atp.argTypes
836+
837+
tpd.applyOverloaded(tpd.New(atp withoutArgs targs), nme.CONSTRUCTOR, args, targs, atp)
838+
}
831839

832840
/** Read an annotation and as a side effect store it into
833841
* the symbol it requests. Called at top-level, for all

0 commit comments

Comments
 (0)