From 65639176ce59fd64cbecd90bf5680e64e471938f Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 10 Mar 2016 17:15:20 +0100 Subject: Add second field to SeqLiteral The field keeps track of the element type. This is necessary because JavaSeqLiteral is nonvariant and the elements might be empty, so we cannot always compute the type from the element types. --- src/dotty/tools/dotc/ast/Desugar.scala | 2 +- src/dotty/tools/dotc/ast/Trees.scala | 30 ++++++++++++---------- src/dotty/tools/dotc/ast/tpd.scala | 22 ++++++++-------- src/dotty/tools/dotc/ast/untpd.scala | 4 +-- .../dotc/core/classfile/ClassfileParser.scala | 9 ++++++- src/dotty/tools/dotc/core/tasty/TreePickler.scala | 4 +-- .../tools/dotc/core/tasty/TreeUnpickler.scala | 5 ++-- .../dotc/core/unpickleScala2/Scala2Unpickler.scala | 6 ++--- src/dotty/tools/dotc/printing/RefinedPrinter.scala | 4 +-- src/dotty/tools/dotc/transform/ElimRepeated.scala | 4 +-- src/dotty/tools/dotc/transform/SeqLiterals.scala | 4 +-- src/dotty/tools/dotc/transform/TreeTransform.scala | 3 ++- src/dotty/tools/dotc/typer/Applications.scala | 7 +++-- src/dotty/tools/dotc/typer/ReTyper.scala | 2 +- src/dotty/tools/dotc/typer/TypeAssigner.scala | 14 +++++----- src/dotty/tools/dotc/typer/Typer.scala | 9 ++++++- 16 files changed, 74 insertions(+), 55 deletions(-) (limited to 'src') diff --git a/src/dotty/tools/dotc/ast/Desugar.scala b/src/dotty/tools/dotc/ast/Desugar.scala index 8ba155097..1eafea049 100644 --- a/src/dotty/tools/dotc/ast/Desugar.scala +++ b/src/dotty/tools/dotc/ast/Desugar.scala @@ -1000,7 +1000,7 @@ object desugar { collect(expr) case NamedArg(_, arg) => collect(arg) - case SeqLiteral(elems) => + case SeqLiteral(elems, _) => elems foreach collect case Alternative(trees) => for (tree <- trees; (vble, _) <- getVariables(tree)) diff --git a/src/dotty/tools/dotc/ast/Trees.scala b/src/dotty/tools/dotc/ast/Trees.scala index 54ace3be4..5fbbad9a1 100644 --- a/src/dotty/tools/dotc/ast/Trees.scala +++ b/src/dotty/tools/dotc/ast/Trees.scala @@ -515,16 +515,18 @@ object Trees { type ThisTree[-T >: Untyped] = Try[T] } - /** Seq(elems) */ - case class SeqLiteral[-T >: Untyped] private[ast] (elems: List[Tree[T]]) + /** Seq(elems) + * @param tpt The element type of the sequence. + */ + case class SeqLiteral[-T >: Untyped] private[ast] (elems: List[Tree[T]], elemtpt: Tree[T]) extends Tree[T] { type ThisTree[-T >: Untyped] = SeqLiteral[T] } /** Array(elems) */ - class JavaSeqLiteral[T >: Untyped] private[ast] (elems: List[Tree[T]]) - extends SeqLiteral(elems) { - override def toString = s"JavaSeqLiteral($elems)" + class JavaSeqLiteral[T >: Untyped] private[ast] (elems: List[Tree[T]], elemtpt: Tree[T]) + extends SeqLiteral(elems, elemtpt) { + override def toString = s"JavaSeqLiteral($elems, $elemtpt)" } /** A type tree that represents an existing or inferred type */ @@ -974,12 +976,12 @@ object Trees { case tree: Try if (expr eq tree.expr) && (cases eq tree.cases) && (finalizer eq tree.finalizer) => tree case _ => finalize(tree, untpd.Try(expr, cases, finalizer)) } - def SeqLiteral(tree: Tree)(elems: List[Tree])(implicit ctx: Context): SeqLiteral = tree match { + def SeqLiteral(tree: Tree)(elems: List[Tree], elemtpt: Tree)(implicit ctx: Context): SeqLiteral = tree match { case tree: JavaSeqLiteral => - if (elems eq tree.elems) tree - else finalize(tree, new JavaSeqLiteral(elems)) - case tree: SeqLiteral if elems eq tree.elems => tree - case _ => finalize(tree, untpd.SeqLiteral(elems)) + if ((elems eq tree.elems) && (elemtpt eq tree.elemtpt)) tree + else finalize(tree, new JavaSeqLiteral(elems, elemtpt)) + case tree: SeqLiteral if (elems eq tree.elems) && (elemtpt eq tree.elemtpt) => tree + case _ => finalize(tree, untpd.SeqLiteral(elems, elemtpt)) } def TypeTree(tree: Tree)(original: Tree): TypeTree = tree match { case tree: TypeTree if original eq tree.original => tree @@ -1125,8 +1127,8 @@ object Trees { cpy.Return(tree)(transform(expr), transformSub(from)) case Try(block, cases, finalizer) => cpy.Try(tree)(transform(block), transformSub(cases), transform(finalizer)) - case SeqLiteral(elems) => - cpy.SeqLiteral(tree)(transform(elems)) + case SeqLiteral(elems, elemtpt) => + cpy.SeqLiteral(tree)(transform(elems), transform(elemtpt)) case TypeTree(original) => tree case SingletonTypeTree(ref) => @@ -1229,8 +1231,8 @@ object Trees { this(this(x, expr), from) case Try(block, handler, finalizer) => this(this(this(x, block), handler), finalizer) - case SeqLiteral(elems) => - this(x, elems) + case SeqLiteral(elems, elemtpt) => + this(this(x, elems), elemtpt) case TypeTree(original) => x case SingletonTypeTree(ref) => diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala index 9a6f74331..a6d97478b 100644 --- a/src/dotty/tools/dotc/ast/tpd.scala +++ b/src/dotty/tools/dotc/ast/tpd.scala @@ -123,14 +123,11 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { def Try(block: Tree, cases: List[CaseDef], finalizer: Tree)(implicit ctx: Context): Try = ta.assignType(untpd.Try(block, cases, finalizer), block, cases) - def SeqLiteral(elems: List[Tree])(implicit ctx: Context): SeqLiteral = - ta.assignType(untpd.SeqLiteral(elems), elems) + def SeqLiteral(elems: List[Tree], elemtpt: Tree)(implicit ctx: Context): SeqLiteral = + ta.assignType(untpd.SeqLiteral(elems, elemtpt), elems, elemtpt) - def SeqLiteral(tpe: Type, elems: List[Tree])(implicit ctx: Context): SeqLiteral = - if (tpe derivesFrom defn.SeqClass) SeqLiteral(elems) else JavaSeqLiteral(elems) - - def JavaSeqLiteral(elems: List[Tree])(implicit ctx: Context): SeqLiteral = - ta.assignType(new untpd.JavaSeqLiteral(elems), elems) + def JavaSeqLiteral(elems: List[Tree], elemtpt: Tree)(implicit ctx: Context): SeqLiteral = + ta.assignType(new untpd.JavaSeqLiteral(elems, elemtpt), elems, elemtpt) def TypeTree(original: Tree)(implicit ctx: Context): TypeTree = TypeTree(original.tpe, original) @@ -564,11 +561,14 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { } } - override def SeqLiteral(tree: Tree)(elems: List[Tree])(implicit ctx: Context): SeqLiteral = { - val tree1 = untpd.cpy.SeqLiteral(tree)(elems) + override def SeqLiteral(tree: Tree)(elems: List[Tree], elemtpt: Tree)(implicit ctx: Context): SeqLiteral = { + val tree1 = untpd.cpy.SeqLiteral(tree)(elems, elemtpt) tree match { - case tree: SeqLiteral if sameTypes(elems, tree.elems) => tree1.withTypeUnchecked(tree.tpe) - case _ => ta.assignType(tree1, elems) + case tree: SeqLiteral + if sameTypes(elems, tree.elems) && (elemtpt.tpe eq tree.elemtpt.tpe) => + tree1.withTypeUnchecked(tree.tpe) + case _ => + ta.assignType(tree1, elems, elemtpt) } } diff --git a/src/dotty/tools/dotc/ast/untpd.scala b/src/dotty/tools/dotc/ast/untpd.scala index 85052a4da..c7a7036c3 100644 --- a/src/dotty/tools/dotc/ast/untpd.scala +++ b/src/dotty/tools/dotc/ast/untpd.scala @@ -127,8 +127,8 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { def CaseDef(pat: Tree, guard: Tree, body: Tree): CaseDef = new CaseDef(pat, guard, body) def Return(expr: Tree, from: Tree): Return = new Return(expr, from) def Try(expr: Tree, cases: List[CaseDef], finalizer: Tree): Try = new Try(expr, cases, finalizer) - def SeqLiteral(elems: List[Tree]): SeqLiteral = new SeqLiteral(elems) - def JavaSeqLiteral(elems: List[Tree]): JavaSeqLiteral = new JavaSeqLiteral(elems) + def SeqLiteral(elems: List[Tree], elemtpt: Tree): SeqLiteral = new SeqLiteral(elems, elemtpt) + def JavaSeqLiteral(elems: List[Tree], elemtpt: Tree): JavaSeqLiteral = new JavaSeqLiteral(elems, elemtpt) def TypeTree(original: Tree): TypeTree = new TypeTree(original) def TypeTree() = new TypeTree(EmptyTree) def SingletonTypeTree(ref: Tree): SingletonTypeTree = new SingletonTypeTree(ref) diff --git a/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala index 9ea24324b..25558a79a 100644 --- a/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala +++ b/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala @@ -438,7 +438,14 @@ class ClassfileParser( case None => hasError = true } if (hasError) None - else if (skip) None else Some(JavaSeqLiteral(arr.toList)) + else if (skip) None + else { + val elems = arr.toList + val elemType = + if (elems.isEmpty) defn.ObjectType + else ctx.typeComparer.lub(elems.tpes).widen + Some(JavaSeqLiteral(elems, TypeTree(elemType))) + } case ANNOTATION_TAG => parseAnnotation(index, skip) map (_.tree) } diff --git a/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/src/dotty/tools/dotc/core/tasty/TreePickler.scala index bb6c3cd2e..d7fc62a16 100644 --- a/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -407,9 +407,9 @@ class TreePickler(pickler: TastyPickler) { case Try(block, cases, finalizer) => writeByte(TRY) withLength { pickleTree(block); cases.foreach(pickleTree); pickleTreeUnlessEmpty(finalizer) } - case SeqLiteral(elems) => + case SeqLiteral(elems, elemtpt) => writeByte(REPEATED) - withLength { elems.foreach(pickleTree) } + withLength { pickleTree(elemtpt); elems.foreach(pickleTree) } case TypeTree(original) => pickleTpt(tree) case Bind(name, body) => diff --git a/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 16caac02e..9d692cc93 100644 --- a/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -801,7 +801,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) { val fn = readTerm() val isJava = fn.tpe.isInstanceOf[JavaMethodType] def readArg() = readTerm() match { - case SeqLiteral(elems) if isJava => JavaSeqLiteral(elems) + case SeqLiteral(elems, elemtpt) if isJava => JavaSeqLiteral(elems, elemtpt) case arg => arg } tpd.Apply(fn, until(end)(readArg())) @@ -837,7 +837,8 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) { case TRY => Try(readTerm(), readCases(end), ifBefore(end)(readTerm(), EmptyTree)) case REPEATED => - SeqLiteral(until(end)(readTerm())) + val elemtpt = readTpt() + SeqLiteral(until(end)(readTerm()), elemtpt) case BIND => val name = readName() val info = readType() diff --git a/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index 7a13388ae..2831de3e0 100644 --- a/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -850,8 +850,8 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas val end = readNat() + readIndex // array elements are trees representing instances of scala.annotation.Annotation SeqLiteral( - defn.SeqType.appliedTo(defn.AnnotationType :: Nil), - until(end, () => readClassfileAnnotArg(readNat()))) + until(end, () => readClassfileAnnotArg(readNat())), + TypeTree(defn.AnnotationType)) } private def readAnnotInfoArg()(implicit ctx: Context): Tree = { @@ -1063,7 +1063,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas case ARRAYVALUEtree => val elemtpt = readTreeRef() val trees = until(end, readTreeRef) - SeqLiteral(defn.SeqType.appliedTo(elemtpt.tpe :: Nil), trees) + SeqLiteral(trees, elemtpt) // note can't deal with trees passed to Java methods as arrays here case FUNCTIONtree => diff --git a/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/src/dotty/tools/dotc/printing/RefinedPrinter.scala index a03a01e8d..e21f12410 100644 --- a/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -380,8 +380,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { changePrec(GlobalPrec) { "throw " ~ toText(expr) } - case SeqLiteral(elems) => - "[" ~ toTextGlobal(elems, ",") ~ "]" + case SeqLiteral(elems, elemtpt) => + "[" ~ toTextGlobal(elems, ",") ~ " : " ~ toText(elemtpt) ~ "]" case tpt: untpd.DerivedTypeTree => "" case TypeTree(orig) => diff --git a/src/dotty/tools/dotc/transform/ElimRepeated.scala b/src/dotty/tools/dotc/transform/ElimRepeated.scala index 98abbb26d..30778267d 100644 --- a/src/dotty/tools/dotc/transform/ElimRepeated.scala +++ b/src/dotty/tools/dotc/transform/ElimRepeated.scala @@ -71,8 +71,8 @@ class ElimRepeated extends MiniPhaseTransform with InfoTransformer with Annotati /** Convert sequence argument to Java array */ private def seqToArray(tree: Tree)(implicit ctx: Context): Tree = tree match { - case SeqLiteral(elems) => - JavaSeqLiteral(elems) + case SeqLiteral(elems, elemtpt) => + JavaSeqLiteral(elems, elemtpt) case _ => val elemType = tree.tpe.firstBaseArgInfo(defn.SeqClass) var elemClass = elemType.classSymbol diff --git a/src/dotty/tools/dotc/transform/SeqLiterals.scala b/src/dotty/tools/dotc/transform/SeqLiterals.scala index 6e29d7e09..49ea69530 100644 --- a/src/dotty/tools/dotc/transform/SeqLiterals.scala +++ b/src/dotty/tools/dotc/transform/SeqLiterals.scala @@ -32,9 +32,9 @@ class SeqLiterals extends MiniPhaseTransform { override def transformSeqLiteral(tree: SeqLiteral)(implicit ctx: Context, info: TransformerInfo): Tree = tree match { case tree: JavaSeqLiteral => tree case _ => - val arr = JavaSeqLiteral(tree.elems) + val arr = JavaSeqLiteral(tree.elems, tree.elemtpt) //println(i"trans seq $tree, arr = $arr: ${arr.tpe} ${arr.tpe.elemType}") - val elemtp = arr.tpe.elemType.bounds.hi + val elemtp = tree.elemtpt.tpe val elemCls = elemtp.classSymbol val (wrapMethStr, targs) = if (elemCls.isPrimitiveValueClass) (s"wrap${elemCls.name}Array", Nil) diff --git a/src/dotty/tools/dotc/transform/TreeTransform.scala b/src/dotty/tools/dotc/transform/TreeTransform.scala index 7a2280baa..7fe003388 100644 --- a/src/dotty/tools/dotc/transform/TreeTransform.scala +++ b/src/dotty/tools/dotc/transform/TreeTransform.scala @@ -1148,7 +1148,8 @@ object TreeTransforms { if (mutatedInfo eq null) tree else { val elems = transformTrees(tree.elems, mutatedInfo, cur) - goSeqLiteral(cpy.SeqLiteral(tree)(elems), mutatedInfo.nx.nxTransSeqLiteral(cur)) + val elemtpt = transform(tree.elemtpt, mutatedInfo, cur) + goSeqLiteral(cpy.SeqLiteral(tree)(elems, elemtpt), mutatedInfo.nx.nxTransSeqLiteral(cur)) } case tree: TypeTree => implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForTypeTree, info.nx.nxPrepTypeTree, tree, cur) diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala index 3b8c56ea6..3ad9902a4 100644 --- a/src/dotty/tools/dotc/typer/Applications.scala +++ b/src/dotty/tools/dotc/typer/Applications.scala @@ -442,7 +442,10 @@ trait Applications extends Compatibility { self: Typer => def makeVarArg(n: Int, elemFormal: Type): Unit = { val args = typedArgBuf.takeRight(n).toList typedArgBuf.trimEnd(n) - val seqLit = if (methodType.isJava) JavaSeqLiteral(args) else SeqLiteral(args) + val elemtpt = TypeTree(elemFormal) + val seqLit = + if (methodType.isJava) JavaSeqLiteral(args, elemtpt) + else SeqLiteral(args, elemtpt) typedArgBuf += seqToRepeated(seqLit) } @@ -771,7 +774,7 @@ trait Applications extends Compatibility { self: Typer => for (argType <- argTypes) assert(!argType.isInstanceOf[TypeBounds], unapplyApp.tpe.show) val bunchedArgs = argTypes match { case argType :: Nil => - if (argType.isRepeatedParam) untpd.SeqLiteral(args) :: Nil + if (argType.isRepeatedParam) untpd.SeqLiteral(args, untpd.TypeTree()) :: Nil else if (args.lengthCompare(1) > 0 && ctx.canAutoTuple) untpd.Tuple(args) :: Nil else args case _ => args diff --git a/src/dotty/tools/dotc/typer/ReTyper.scala b/src/dotty/tools/dotc/typer/ReTyper.scala index 49718fd00..225451886 100644 --- a/src/dotty/tools/dotc/typer/ReTyper.scala +++ b/src/dotty/tools/dotc/typer/ReTyper.scala @@ -92,7 +92,7 @@ class ReTyper extends Typer { try super.typedUnadapted(tree, pt) catch { case NonFatal(ex) => - Printers.transforms.println(i"exception while typing $tree of class ${tree.getClass} # ${tree.uniqueId}") + println(i"exception while typing $tree of class ${tree.getClass} # ${tree.uniqueId}") throw ex } diff --git a/src/dotty/tools/dotc/typer/TypeAssigner.scala b/src/dotty/tools/dotc/typer/TypeAssigner.scala index 476839ab3..84951fd2b 100644 --- a/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -392,14 +392,12 @@ trait TypeAssigner { if (cases.isEmpty) tree.withType(expr.tpe) else tree.withType(ctx.typeComparer.lub(expr.tpe :: cases.tpes)) - def assignType(tree: untpd.SeqLiteral, elems: List[Tree])(implicit ctx: Context) = tree match { - case tree: JavaSeqLiteral => - tree.withType(defn.ArrayOf(ctx.typeComparer.lub(elems.tpes).widen)) - 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.SeqLiteral, elems: List[Tree], elemtpt: Tree)(implicit ctx: Context) = { + val ownType = tree match { + case tree: JavaSeqLiteral => defn.ArrayOf(elemtpt.tpe) + case _ => if (ctx.erasedTypes) defn.SeqType else defn.SeqType.appliedTo(elemtpt.tpe) + } + tree.withType(ownType) } def assignType(tree: untpd.SingletonTypeTree, ref: Tree)(implicit ctx: Context) = diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index fdb92a40b..2683b2364 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -836,7 +836,14 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def typedSeqLiteral(tree: untpd.SeqLiteral, pt: Type)(implicit ctx: Context): SeqLiteral = track("typedSeqLiteral") { val proto1 = pt.elemType orElse WildcardType val elems1 = tree.elems mapconserve (typed(_, proto1)) - assignType(cpy.SeqLiteral(tree)(elems1), elems1) + val proto2 = // the computed type of the `elemtpt` field + if (!tree.elemtpt.isEmpty) WildcardType + else if (isFullyDefined(proto1, ForceDegree.none)) proto1 + else if (tree.elems.isEmpty && tree.isInstanceOf[Trees.JavaSeqLiteral[_]]) + defn.ObjectType // generic empty Java varargs are of type Object[] + else ctx.typeComparer.lub(elems1.tpes) + val elemtpt1 = typed(tree.elemtpt, proto2) + assignType(cpy.SeqLiteral(tree)(elems1, elemtpt1), elems1, elemtpt1) } def typedTypeTree(tree: untpd.TypeTree, pt: Type)(implicit ctx: Context): TypeTree = track("typedTypeTree") { -- cgit v1.2.3