From bea74309fe44544c9cedd44b7dd693b3ab59f7e4 Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Wed, 25 Apr 2018 22:59:43 +0200 Subject: [PATCH] Fix #4375: Properly erase SeqLiteral Before this commit, the `SeqLiteral#elems` were typed based on the SeqLiteral prototype, which means that nothing ensured that the elems types conformed to the type of `SeqLiteral#elemtpt`. In i4375.scala this means that erasing `SeqLiteral([1, 2], Object)` did not box each element because the expected element type was `WildcardType`. To prevent this sort of issue, we now use the type of SeqLiteral#elemtpt if it exists as the expected type of each element in the sequence. --- .../src/dotty/tools/dotc/typer/Typer.scala | 31 +++++++++++++------ tests/pos/i4375.scala | 13 ++++++++ 2 files changed, 34 insertions(+), 10 deletions(-) create mode 100644 tests/pos/i4375.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index fcba55cf99d4..cc9857787df3 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1126,20 +1126,31 @@ class Typer extends Namer } def typedSeqLiteral(tree: untpd.SeqLiteral, pt: Type)(implicit ctx: Context): SeqLiteral = track("typedSeqLiteral") { - val proto1 = pt.elemType match { + val elemProto = pt.elemType match { case NoType => WildcardType case bounds: TypeBounds => WildcardType(bounds) case elemtp => elemtp } - val elems1 = tree.elems mapconserve (typed(_, proto1)) - 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 assign(elems1: List[Tree], elemtpt1: Tree) = + assignType(cpy.SeqLiteral(tree)(elems1, elemtpt1), elems1, elemtpt1) + + if (!tree.elemtpt.isEmpty) { + val elemtpt1 = typed(tree.elemtpt, elemProto) + val elems1 = tree.elems.mapconserve(typed(_, elemtpt1.tpe)) + assign(elems1, elemtpt1) + } else { + val elems1 = tree.elems.mapconserve(typed(_, elemProto)) + val elemtptType = + if (isFullyDefined(elemProto, ForceDegree.none)) + elemProto + 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, elemtptType) + assign(elems1, elemtpt1) + } } def typedInlined(tree: untpd.Inlined, pt: Type)(implicit ctx: Context): Inlined = { diff --git a/tests/pos/i4375.scala b/tests/pos/i4375.scala new file mode 100644 index 000000000000..233ab854a842 --- /dev/null +++ b/tests/pos/i4375.scala @@ -0,0 +1,13 @@ +object Test { + type Id[A] >: A + def test: Unit = { + val a: Array[_ >: Id[Int]] = Array(1, 2) + val b = a(0) + } + + class VC(i: String) extends AnyVal + def test2: Unit = { + val c: Array[_ >: Id[VC]] = Array(new VC("")) + val d = c(0) + } +}