Skip to content

Fix typing of SeqLiterals #1166

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 18, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/ast/Desugar.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
30 changes: 16 additions & 14 deletions src/dotty/tools/dotc/ast/Trees.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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) =>
Expand Down Expand Up @@ -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) =>
Expand Down
24 changes: 12 additions & 12 deletions src/dotty/tools/dotc/ast/tpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
}
}

Expand Down Expand Up @@ -852,7 +852,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
ctx.typer.resolveOverloaded(allAlts, proto, Nil)
assert(alternatives.size == 1,
i"${if (alternatives.isEmpty) "no" else "multiple"} overloads available for " +
i"$method on ${receiver.tpe.widenDealias} with targs: $targs, args: $args and expectedType: $expectedType." +
i"$method on ${receiver.tpe.widenDealias} with targs: $targs%, %; args: $args%, % of types ${args.tpes}%, %; expectedType: $expectedType." +
i" isAnnotConstructor = $isAnnotConstructor.\n" +
i"all alternatives: ${allAlts.map(_.symbol.showDcl).mkString(", ")}\n" +
i"matching alternatives: ${alternatives.map(_.symbol.showDcl).mkString(", ")}.") // this is parsed from bytecode tree. there's nothing user can do about it
Expand Down
4 changes: 2 additions & 2 deletions src/dotty/tools/dotc/ast/untpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/core/SymDenotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -616,7 +616,7 @@ object SymDenotations {

/** Is this symbol a class references to which that are supertypes of null? */
final def isNullableClass(implicit ctx: Context): Boolean =
isClass && !isValueClass && !(this is ModuleClass)
isClass && !isValueClass && !(this is ModuleClass) && symbol != defn.NothingClass

/** Is this definition accessible as a member of tree with type `pre`?
* @param pre The type of the tree from which the selection is made
Expand Down
9 changes: 8 additions & 1 deletion src/dotty/tools/dotc/core/classfile/ClassfileParser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
4 changes: 2 additions & 2 deletions src/dotty/tools/dotc/core/tasty/TreePickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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) =>
Expand Down
5 changes: 3 additions & 2 deletions src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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()))
Expand Down Expand Up @@ -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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -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 =>
Expand Down
4 changes: 2 additions & 2 deletions src/dotty/tools/dotc/printing/RefinedPrinter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 =>
"<derived typetree watching " ~ summarized(toText(tpt.watched)) ~ ">"
case TypeTree(orig) =>
Expand Down
4 changes: 2 additions & 2 deletions src/dotty/tools/dotc/transform/ElimRepeated.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions src/dotty/tools/dotc/transform/SeqLiterals.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 2 additions & 1 deletion src/dotty/tools/dotc/transform/TreeTransform.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
7 changes: 5 additions & 2 deletions src/dotty/tools/dotc/typer/Applications.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}

Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/typer/ReTyper.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
14 changes: 6 additions & 8 deletions src/dotty/tools/dotc/typer/TypeAssigner.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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) =
Expand Down
9 changes: 8 additions & 1 deletion src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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") {
Expand Down
4 changes: 2 additions & 2 deletions test/test/DeSugarTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ class DeSugarTest extends ParserTest {
cpy.Typed(tree1)(transform(expr), transform(tpt, Type))
case CaseDef(pat, guard, body) =>
cpy.CaseDef(tree1)(transform(pat, Pattern), transform(guard), transform(body))
case SeqLiteral(elems) =>
cpy.SeqLiteral(tree1)(transform(elems))
case SeqLiteral(elems, elemtpt) =>
cpy.SeqLiteral(tree1)(transform(elems), transform(elemtpt))
case UnApply(fun, implicits, patterns) =>
cpy.UnApply(tree1)(transform(fun, Expr), transform(implicits), transform(patterns))
case tree1 @ ValDef(name, tpt, _) =>
Expand Down
2 changes: 1 addition & 1 deletion tests/pickling/hk.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ object higherKinded {
}

class Ident[-T >: Untyped] extends Tree[T] {
type ThisType[-U] = Ident[U]
type ThisType[-U >: Untyped] = Ident[U]
}

val id = new Ident[Integer]
Expand Down
2 changes: 1 addition & 1 deletion tests/pos/hk.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ object higherKinded {
}

class Ident[-T >: Untyped] extends Tree[T] {
type ThisType[-U] = Ident[U]
type ThisType[-U >: Untyped] = Ident[U]
}

val id = new Ident[Integer]
Expand Down