Skip to content

Commit 39f47f3

Browse files
authored
Merge pull request #4807 from dotty-staging/default-seq-v2
Resolve SeqType based on the standard library on the classpath
2 parents bfbd1af + c5b3bfb commit 39f47f3

File tree

13 files changed

+173
-52
lines changed

13 files changed

+173
-52
lines changed

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

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package ast
55
import dotty.tools.dotc.transform.{ExplicitOuter, Erasure}
66
import dotty.tools.dotc.typer.ProtoTypes.FunProtoTyped
77
import transform.SymUtils._
8+
import transform.TypeUtils._
89
import core._
910
import util.Positions._, Types._, Contexts._, Constants._, Names._, Flags._, NameOps._
1011
import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._, Symbols._
@@ -377,7 +378,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
377378
}
378379

379380
/** A tree representing a `newXYZArray` operation of the right
380-
* kind for the given element type in `typeArg`. No type arguments or
381+
* kind for the given element type in `elemTpe`. No type arguments or
381382
* `length` arguments are given.
382383
*/
383384
def newArray(elemTpe: Type, returnTpe: Type, pos: Position, dims: JavaSeqLiteral)(implicit ctx: Context): Tree = {
@@ -392,6 +393,24 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
392393
newArr.appliedToArgs(clsOf(elemTpe) :: clsOf(returnTpe) :: dims :: Nil).withPos(pos)
393394
}
394395

396+
/** The wrapped array method name for an array of type elemtp */
397+
def wrapArrayMethodName(elemtp: Type)(implicit ctx: Context): TermName = {
398+
val elemCls = elemtp.classSymbol
399+
if (elemCls.isPrimitiveValueClass) nme.wrapXArray(elemCls.name)
400+
else if (elemCls.derivesFrom(defn.ObjectClass) && !elemCls.isNotRuntimeClass) nme.wrapRefArray
401+
else nme.genericWrapArray
402+
}
403+
404+
/** A tree representing a `wrapXYZArray(tree)` operation of the right
405+
* kind for the given element type in `elemTpe`.
406+
*/
407+
def wrapArray(tree: Tree, elemtp: Type)(implicit ctx: Context): Tree = {
408+
ref(defn.getWrapVarargsArrayModule)
409+
.select(wrapArrayMethodName(elemtp))
410+
.appliedToTypes(if (elemtp.isPrimitiveValueType) Nil else elemtp :: Nil)
411+
.appliedTo(tree)
412+
}
413+
395414
// ------ Creating typed equivalents of trees that exist only in untyped form -------
396415

397416
/** new C(args), calling the primary constructor of C */

compiler/src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import scala.collection.{ mutable, immutable }
99
import PartialFunction._
1010
import collection.mutable
1111
import util.common.alwaysZero
12-
import dotty.tools.dotc.transform.TreeGen
1312

1413
object Definitions {
1514

@@ -345,11 +344,6 @@ class Definitions {
345344
def Predef_classOf(implicit ctx: Context) = Predef_classOfR.symbol
346345
lazy val Predef_undefinedR = ScalaPredefModule.requiredMethodRef("???")
347346
def Predef_undefined(implicit ctx: Context) = Predef_undefinedR.symbol
348-
// The set of all wrap{X, Ref}Array methods, where X is a value type
349-
val Predef_wrapArray = new PerRun[collection.Set[Symbol]]({ implicit ctx =>
350-
val methodNames = ScalaValueTypes.map(TreeGen.wrapArrayMethodName) + nme.wrapRefArray
351-
methodNames.map(ScalaPredefModule.requiredMethodRef(_).symbol)
352-
})
353347

354348
lazy val ScalaRuntimeModuleRef = ctx.requiredModuleRef("scala.runtime.ScalaRunTime")
355349
def ScalaRuntimeModule(implicit ctx: Context) = ScalaRuntimeModuleRef.symbol
@@ -390,6 +384,17 @@ class Definitions {
390384
def newGenericArrayMethod(implicit ctx: Context) = DottyArraysModule.requiredMethod("newGenericArray")
391385
def newArrayMethod(implicit ctx: Context) = DottyArraysModule.requiredMethod("newArray")
392386

387+
// TODO: Remove once we drop support for 2.12 standard library
388+
private[this] lazy val isNewCollections = ctx.base.staticRef("scala.collection.IterableOnce".toTypeName).exists
389+
390+
def getWrapVarargsArrayModule = if (isNewCollections) ScalaRuntimeModule else ScalaPredefModule
391+
392+
// The set of all wrap{X, Ref}Array methods, where X is a value type
393+
val WrapArrayMethods = new PerRun[collection.Set[Symbol]]({ implicit ctx =>
394+
val methodNames = ScalaValueTypes.map(ast.tpd.wrapArrayMethodName) + nme.wrapRefArray
395+
methodNames.map(getWrapVarargsArrayModule.requiredMethodRef(_).symbol)
396+
})
397+
393398
lazy val NilModuleRef = ctx.requiredModuleRef("scala.collection.immutable.Nil")
394399
def NilModule(implicit ctx: Context) = NilModuleRef.symbol
395400

@@ -401,7 +406,9 @@ class Definitions {
401406
List(AnyClass.typeRef), EmptyScope)
402407
lazy val SingletonType: TypeRef = SingletonClass.typeRef
403408

404-
lazy val SeqType: TypeRef = ctx.requiredClassRef("scala.collection.Seq")
409+
lazy val SeqType: TypeRef =
410+
if (isNewCollections) ctx.requiredClassRef("scala.collection.immutable.Seq")
411+
else ctx.requiredClassRef("scala.collection.Seq")
405412
def SeqClass(implicit ctx: Context) = SeqType.symbol.asClass
406413
lazy val Seq_applyR = SeqClass.requiredMethodRef(nme.apply)
407414
def Seq_apply(implicit ctx: Context) = Seq_applyR.symbol
@@ -1210,12 +1217,11 @@ class Definitions {
12101217

12111218
lazy val reservedScalaClassNames: Set[Name] = syntheticScalaClasses.map(_.name).toSet
12121219

1213-
private[this] var _isInitialized = false
1214-
private def isInitialized = _isInitialized
1220+
private[this] var isInitialized = false
12151221

12161222
def init()(implicit ctx: Context) = {
12171223
this.ctx = ctx
1218-
if (!_isInitialized) {
1224+
if (!isInitialized) {
12191225
// Enter all symbols from the scalaShadowing package in the scala package
12201226
for (m <- ScalaShadowingPackageClass.info.decls)
12211227
ScalaPackageClass.enter(m)
@@ -1230,7 +1236,7 @@ class Definitions {
12301236
// force initialization of every symbol that is synthesized or hijacked by the compiler
12311237
val forced = syntheticCoreClasses ++ syntheticCoreMethods ++ ScalaValueClasses()
12321238

1233-
_isInitialized = true
1239+
isInitialized = true
12341240
}
12351241
}
12361242

compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ class ElimRepeated extends MiniPhase with InfoTransformer { thisPhase =>
9898
private def seqToArray(tree: Tree, pt: Type)(implicit ctx: Context): Tree = tree match {
9999
case SeqLiteral(elems, elemtpt) =>
100100
JavaSeqLiteral(elems, elemtpt)
101-
case app@Apply(fun, args) if defn.Predef_wrapArray().contains(fun.symbol) => // rewrite a call to `wrapXArray(arr)` to `arr`
101+
case app@Apply(fun, args) if defn.WrapArrayMethods().contains(fun.symbol) => // rewrite a call to `wrapXArray(arr)` to `arr`
102102
args.head
103103
case _ =>
104104
val elemType = tree.tpe.elemType
@@ -143,7 +143,7 @@ class ElimRepeated extends MiniPhase with InfoTransformer { thisPhase =>
143143
val elemtp = varArgRef.tpe.widen.argTypes.head
144144
ref(original.termRef)
145145
.appliedToTypes(trefs)
146-
.appliedToArgs(vrefs :+ TreeGen.wrapArray(varArgRef, elemtp))
146+
.appliedToArgs(vrefs :+ tpd.wrapArray(varArgRef, elemtp))
147147
.appliedToArgss(vrefss1)
148148
})
149149

compiler/src/dotty/tools/dotc/transform/SeqLiterals.scala

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,6 @@ class SeqLiterals extends MiniPhase {
3535
val arr = JavaSeqLiteral(tree.elems, tree.elemtpt)
3636
//println(i"trans seq $tree, arr = $arr: ${arr.tpe} ${arr.tpe.elemType}")
3737
val elemtp = tree.elemtpt.tpe
38-
val elemCls = elemtp.classSymbol
39-
val (wrapMethStr, targs) =
40-
if (elemCls.isPrimitiveValueClass) (s"wrap${elemCls.name}Array", Nil)
41-
else if (elemtp derivesFrom defn.ObjectClass) ("wrapRefArray", elemtp :: Nil)
42-
else ("genericWrapArray", elemtp :: Nil)
43-
ref(defn.ScalaPredefModule)
44-
.select(wrapMethStr.toTermName)
45-
.appliedToTypes(targs)
46-
.appliedTo(arr)
38+
wrapArray(arr, elemtp)
4739
}
4840
}

compiler/src/dotty/tools/dotc/transform/TreeGen.scala

Lines changed: 0 additions & 26 deletions
This file was deleted.

compiler/src/dotty/tools/dotc/typer/Implicits.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ object Implicits {
7171
/** The implicit references */
7272
def refs: List[ImplicitRef]
7373

74-
private var SingletonClass: ClassSymbol = null
74+
private[this] var SingletonClass: ClassSymbol = null
7575

7676
/** Widen type so that it is neither a singleton type nor a type that inherits from scala.Singleton. */
7777
private def widenSingleton(tp: Type)(implicit ctx: Context): Type = {

compiler/test/dotty/tools/dotc/FromTastyTests.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ class FromTastyTests extends ParallelTesting {
3939

4040
// Fails on MacOS
4141
"annot-bootstrap.scala",
42+
43+
// ScalaRunTime cannot be unpickled because it is already loaded
44+
"repeatedArgs213.scala",
4245
),
4346
recompilationBlacklist = Set(
4447
)

tests/neg/repeatedArgs213.scala

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import scala.collection.{immutable, mutable}
2+
import java.nio.file.Paths
3+
4+
// Code below is to trick the compiler into thinking that we are
5+
// compiling with the 2.13 standard library on the classpath.
6+
package scala.collection {
7+
class IterableOnce
8+
}
9+
10+
package scala.runtime {
11+
object ScalaRunTime {
12+
abstract class ArraySeq[+A] extends immutable.Seq[A]
13+
14+
def genericWrapArray[T](xs: Array[T]): ArraySeq[T] = ???
15+
def wrapRefArray[T <: AnyRef](xs: Array[T]): ArraySeq[T] = ???
16+
def wrapIntArray(xs: Array[Int]): ArraySeq[Int] = ???
17+
def wrapDoubleArray(xs: Array[Double]): ArraySeq[Double] = ???
18+
def wrapLongArray(xs: Array[Long]): ArraySeq[Long] = ???
19+
def wrapFloatArray(xs: Array[Float]): ArraySeq[Float] = ???
20+
def wrapCharArray(xs: Array[Char]): ArraySeq[Char] = ???
21+
def wrapByteArray(xs: Array[Byte]): ArraySeq[Byte] = ???
22+
def wrapShortArray(xs: Array[Short]): ArraySeq[Short] = ???
23+
def wrapBooleanArray(xs: Array[Boolean]): ArraySeq[Boolean] = ???
24+
def wrapUnitArray(xs: Array[Unit]): ArraySeq[Unit] = ???
25+
}
26+
}
27+
28+
// Start of Test
29+
class repeatedArgs {
30+
def bar(xs: String*): Int = xs.length
31+
32+
def test(xs: immutable.Seq[String], ys: collection.Seq[String], zs: Array[String]): Unit = {
33+
bar("a", "b", "c")
34+
bar(xs: _*)
35+
bar(ys: _*) // error: immutable.Seq expected, found Seq
36+
bar(zs: _*) // error: immutable.Seq expected, found Array
37+
38+
Paths.get("Hello", "World")
39+
Paths.get("Hello", xs: _*)
40+
Paths.get("Hello", ys: _*) // error: immutable.Seq expected, found Seq
41+
Paths.get("Hello", zs: _*) // error: immutable.Seq expected, found Array
42+
}
43+
}

tests/pos/repeatedArgs.scala

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,22 @@
1-
object testRepeated {
2-
def foo = java.lang.System.out.format("%4$2s %3$2s %2$2s %1$2s", "a", "b", "c", "d")
1+
import scala.collection.{immutable, mutable}
2+
import java.nio.file.Paths
3+
4+
class repeatedArgs {
5+
def bar(xs: String*): Int = xs.length
6+
7+
def test(xs: immutable.Seq[String], ys: collection.Seq[String], zs: Array[String]): Unit = {
8+
bar("a", "b", "c")
9+
bar(xs: _*)
10+
bar(ys: _*) // error in 2.13
11+
bar(zs: _*)
12+
13+
Paths.get("Hello", "World")
14+
Paths.get("Hello", xs: _*)
15+
Paths.get("Hello", ys: _*) // error in 2.13
16+
Paths.get("Hello", zs: _*)
17+
18+
val List(_, others: _*) = xs.toList // toList should not be needed, see #4790
19+
val x: collection.Seq[String] = others
20+
// val y: immutable.Seq[String] = others // ok in 2.13
21+
}
322
}

tests/pos/repeatedArgs213.scala

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import scala.collection.{immutable, mutable}
2+
import java.nio.file.Paths
3+
4+
// Code below is to trick the compiler into thinking that we are
5+
// compiling with the 2.13 standard library on the classpath.
6+
package scala.collection {
7+
class IterableOnce
8+
}
9+
10+
package scala.runtime {
11+
object ScalaRunTime {
12+
abstract class ArraySeq[+A] extends immutable.Seq[A]
13+
14+
def genericWrapArray[T](xs: Array[T]): ArraySeq[T] = ???
15+
def wrapRefArray[T <: AnyRef](xs: Array[T]): ArraySeq[T] = ???
16+
def wrapIntArray(xs: Array[Int]): ArraySeq[Int] = ???
17+
def wrapDoubleArray(xs: Array[Double]): ArraySeq[Double] = ???
18+
def wrapLongArray(xs: Array[Long]): ArraySeq[Long] = ???
19+
def wrapFloatArray(xs: Array[Float]): ArraySeq[Float] = ???
20+
def wrapCharArray(xs: Array[Char]): ArraySeq[Char] = ???
21+
def wrapByteArray(xs: Array[Byte]): ArraySeq[Byte] = ???
22+
def wrapShortArray(xs: Array[Short]): ArraySeq[Short] = ???
23+
def wrapBooleanArray(xs: Array[Boolean]): ArraySeq[Boolean] = ???
24+
def wrapUnitArray(xs: Array[Unit]): ArraySeq[Unit] = ???
25+
}
26+
}
27+
28+
// Start of Test
29+
class repeatedArgs {
30+
def bar(xs: String*): Int = xs.length
31+
32+
def test(xs: immutable.Seq[String]): Unit = {
33+
bar("a", "b", "c")
34+
bar(xs: _*)
35+
36+
Paths.get("Hello", "World")
37+
Paths.get("Hello", xs: _*)
38+
39+
val List(_, others: _*) = xs.toList // toList should not be needed, see #4790
40+
val x: immutable.Seq[String] = others
41+
}
42+
}

tests/pos/seqtype-cycle/Test1.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
class Test {
2+
def bar = Array(1) // call to Array(_: Repeated)
3+
}

tests/pos/seqtype-cycle/Test2.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package object scala {
2+
// needed for some reasons
3+
type Throwable = java.lang.Throwable
4+
type IndexOutOfBoundsException = java.lang.IndexOutOfBoundsException
5+
6+
type Seq[+A] = scala.collection.Seq[A]
7+
val Seq = scala.collection.Seq
8+
}

tests/pos/seqtype-cycle/Test3.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package scala
2+
3+
class specialized(types: Int*) extends scala.annotation.StaticAnnotation
4+
5+
package collection {
6+
class Foo[@specialized(1, 2) A]
7+
8+
trait Seq[A] extends Foo[A]
9+
object Seq extends SeqFactory[Seq]
10+
11+
trait SeqFactory[CC[X] <: Seq[X]]
12+
}

0 commit comments

Comments
 (0)