diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index b9a6edcc6bc3..964f50ceb18d 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -5,6 +5,7 @@ package ast import dotty.tools.dotc.transform.{ExplicitOuter, Erasure} import dotty.tools.dotc.typer.ProtoTypes.FunProtoTyped import transform.SymUtils._ +import transform.TypeUtils._ import core._ import util.Positions._, Types._, Contexts._, Constants._, Names._, Flags._, NameOps._ import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._, Symbols._ @@ -377,7 +378,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { } /** A tree representing a `newXYZArray` operation of the right - * kind for the given element type in `typeArg`. No type arguments or + * kind for the given element type in `elemTpe`. No type arguments or * `length` arguments are given. */ def newArray(elemTpe: Type, returnTpe: Type, pos: Position, dims: JavaSeqLiteral)(implicit ctx: Context): Tree = { @@ -392,6 +393,32 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { newArr.appliedToArgs(clsOf(elemTpe) :: clsOf(returnTpe) :: dims :: Nil).withPos(pos) } + /** The wrapped array method name for an array of type elemtp */ + def wrapArrayMethodName(elemtp: Type)(implicit ctx: Context): TermName = { + val elemCls = elemtp.classSymbol + if (elemCls.isPrimitiveValueClass) nme.wrapXArray(elemCls.name) + else if (elemCls.derivesFrom(defn.ObjectClass) && !elemCls.isNotRuntimeClass) nme.wrapRefArray + else nme.genericWrapArray + } + + /** A tree representing a `wrapXYZArray(tree)` operation of the right + * kind for the given element type in `elemTpe`. + */ + def wrapArray(tree: Tree, elemtp: Type)(implicit ctx: Context): Tree = { + val wrapped = ref(defn.ScalaPredefModule) + .select(wrapArrayMethodName(elemtp)) + .appliedToTypes(if (elemtp.isPrimitiveValueType) Nil else elemtp :: Nil) + .appliedTo(tree) + + if (ctx.settings.YimmutableSeq.value) { + // wrapXYZArray returns a `mutable.Seq`. We need to convert to a `immutable.Seq`. + // TODO: revert once we use the 2.13 standard library and have better + // collections for immutable wrapped arrays (i.e. immutbale.ArraySeq) + wrapped.select(nme.toList) + } + else wrapped + } + // ------ Creating typed equivalents of trees that exist only in untyped form ------- /** new C(args), calling the primary constructor of C */ diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala index dfda54f034e7..27086d3f1c86 100644 --- a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -124,6 +124,7 @@ class ScalaSettings extends Settings.SettingGroup { val YcheckAllPatmat = BooleanSetting("-Ycheck-all-patmat", "Check exhaustivity and redundancy of all pattern matching (used for testing the algorithm)") val YretainTrees = BooleanSetting("-Yretain-trees", "Retain trees for top-level classes, accessible from ClassSymbol#tree") val YshowTreeIds = BooleanSetting("-Yshow-tree-ids", "Uniquely tag all tree nodes in debugging output.") + val YimmutableSeq = BooleanSetting("-Yimmutable-seq", "Use collection.immutable.Seq as the default Seq type") val YprofileEnabled = BooleanSetting("-Yprofile-enabled", "Enable profiling.") val YprofileDestination = StringSetting("-Yprofile-destination", "file", "where to send profiling output - specify a file, default is to the console.", "") diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 18f46407ddd8..e8f98d5a78d7 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -9,7 +9,6 @@ import scala.collection.{ mutable, immutable } import PartialFunction._ import collection.mutable import util.common.alwaysZero -import dotty.tools.dotc.transform.TreeGen object Definitions { @@ -347,7 +346,7 @@ class Definitions { def Predef_undefined(implicit ctx: Context) = Predef_undefinedR.symbol // The set of all wrap{X, Ref}Array methods, where X is a value type val Predef_wrapArray = new PerRun[collection.Set[Symbol]]({ implicit ctx => - val methodNames = ScalaValueTypes.map(TreeGen.wrapArrayMethodName) + nme.wrapRefArray + val methodNames = ScalaValueTypes.map(ast.tpd.wrapArrayMethodName) + nme.wrapRefArray methodNames.map(ScalaPredefModule.requiredMethodRef(_).symbol) }) @@ -401,7 +400,12 @@ class Definitions { List(AnyClass.typeRef), EmptyScope) lazy val SingletonType: TypeRef = SingletonClass.typeRef - lazy val SeqType: TypeRef = ctx.requiredClassRef("scala.collection.Seq") + lazy val SeqType: TypeRef = { + val fullName = + if (ctx.settings.YimmutableSeq.value) "scala.collection.immutable.Seq" + else "scala.collection.Seq" + ctx.requiredClassRef(fullName) + } def SeqClass(implicit ctx: Context) = SeqType.symbol.asClass lazy val Seq_applyR = SeqClass.requiredMethodRef(nme.apply) def Seq_apply(implicit ctx: Context) = Seq_applyR.symbol diff --git a/compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala b/compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala index 23b6dfb4dd5e..12ca02ac1439 100644 --- a/compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala +++ b/compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala @@ -143,7 +143,7 @@ class ElimRepeated extends MiniPhase with InfoTransformer { thisPhase => val elemtp = varArgRef.tpe.widen.argTypes.head ref(original.termRef) .appliedToTypes(trefs) - .appliedToArgs(vrefs :+ TreeGen.wrapArray(varArgRef, elemtp)) + .appliedToArgs(vrefs :+ tpd.wrapArray(varArgRef, elemtp)) .appliedToArgss(vrefss1) }) diff --git a/compiler/src/dotty/tools/dotc/transform/SeqLiterals.scala b/compiler/src/dotty/tools/dotc/transform/SeqLiterals.scala index 756e4f045cb6..2e17a211a04d 100644 --- a/compiler/src/dotty/tools/dotc/transform/SeqLiterals.scala +++ b/compiler/src/dotty/tools/dotc/transform/SeqLiterals.scala @@ -35,14 +35,6 @@ class SeqLiterals extends MiniPhase { val arr = JavaSeqLiteral(tree.elems, tree.elemtpt) //println(i"trans seq $tree, arr = $arr: ${arr.tpe} ${arr.tpe.elemType}") val elemtp = tree.elemtpt.tpe - val elemCls = elemtp.classSymbol - val (wrapMethStr, targs) = - if (elemCls.isPrimitiveValueClass) (s"wrap${elemCls.name}Array", Nil) - else if (elemtp derivesFrom defn.ObjectClass) ("wrapRefArray", elemtp :: Nil) - else ("genericWrapArray", elemtp :: Nil) - ref(defn.ScalaPredefModule) - .select(wrapMethStr.toTermName) - .appliedToTypes(targs) - .appliedTo(arr) + wrapArray(arr, elemtp) } } diff --git a/compiler/src/dotty/tools/dotc/transform/TreeGen.scala b/compiler/src/dotty/tools/dotc/transform/TreeGen.scala deleted file mode 100644 index a6dfdebc3cf4..000000000000 --- a/compiler/src/dotty/tools/dotc/transform/TreeGen.scala +++ /dev/null @@ -1,26 +0,0 @@ -package dotty.tools.dotc -package transform - -import core._ -import Symbols._, Contexts._, Types._, Names._, StdNames._ -import ast._ -import Trees._ -import TypeUtils._ - -object TreeGen { - - import tpd._ - - def wrapArrayMethodName(elemtp: Type)(implicit ctx: Context): TermName = { - val elemCls = elemtp.classSymbol - if (elemCls.isPrimitiveValueClass) nme.wrapXArray(elemCls.name) - else if (elemCls.derivesFrom(defn.ObjectClass) && !elemCls.isNotRuntimeClass) nme.wrapRefArray - else nme.genericWrapArray - } - - def wrapArray(tree: Tree, elemtp: Type)(implicit ctx: Context): Tree = - ref(defn.ScalaPredefModule) - .select(wrapArrayMethodName(elemtp)) - .appliedToTypes(if (elemtp.isPrimitiveValueType) Nil else elemtp :: Nil) - .appliedTo(tree) -} diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 848d928d7cf5..4ba82bc897b9 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -71,7 +71,7 @@ object Implicits { /** The implicit references */ def refs: List[ImplicitRef] - private var SingletonClass: ClassSymbol = null + private[this] var SingletonClass: ClassSymbol = null /** Widen type so that it is neither a singleton type nor a type that inherits from scala.Singleton. */ private def widenSingleton(tp: Type)(implicit ctx: Context): Type = { diff --git a/compiler/test/dotty/tools/dotc/CompilationTests.scala b/compiler/test/dotty/tools/dotc/CompilationTests.scala index e0b81251ed29..dee3defaba28 100644 --- a/compiler/test/dotty/tools/dotc/CompilationTests.scala +++ b/compiler/test/dotty/tools/dotc/CompilationTests.scala @@ -58,6 +58,7 @@ class CompilationTests extends ParallelTesting { compileFile("tests/pos-special/completeFromSource/Test.scala", defaultOptions.and("-sourcepath", "tests/pos-special")) + compileFile("tests/pos-special/completeFromSource/Test2.scala", defaultOptions.and("-sourcepath", "tests/pos-special")) + compileFile("tests/pos-special/completeFromSource/Test3.scala", defaultOptions.and("-sourcepath", "tests/pos-special", "-scansource")) + + compileFile("tests/pos-special/repeatedArgs.scala", defaultOptions.and("-Yimmutable-seq")) + compileFilesInDir("tests/pos-special/fatal-warnings", defaultOptions.and("-Xfatal-warnings")) + compileList( "compileMixed", @@ -189,8 +190,9 @@ class CompilationTests extends ParallelTesting { compileFile("tests/neg-custom-args/i3882.scala", allowDeepSubtypes) + compileFile("tests/neg-custom-args/i4372.scala", allowDeepSubtypes) + compileFile("tests/neg-custom-args/i1754.scala", allowDeepSubtypes) + - compileFilesInDir("tests/neg-custom-args/isInstanceOf", allowDeepSubtypes and "-Xfatal-warnings") + - compileFile("tests/neg-custom-args/i3627.scala", allowDeepSubtypes) + compileFile("tests/neg-custom-args/i3627.scala", allowDeepSubtypes) + + compileFile("tests/neg-custom-args/repeatedArgs.scala", defaultOptions.and("-Yimmutable-seq")) + + compileFilesInDir("tests/neg-custom-args/isInstanceOf", allowDeepSubtypes and "-Xfatal-warnings") }.checkExpectedErrors() // Run tests ----------------------------------------------------------------- diff --git a/tests/neg-custom-args/repeatedArgs.scala b/tests/neg-custom-args/repeatedArgs.scala new file mode 100644 index 000000000000..8c20a3ae7b86 --- /dev/null +++ b/tests/neg-custom-args/repeatedArgs.scala @@ -0,0 +1,19 @@ +import scala.collection.{immutable, mutable} +import java.nio.file.Paths + +/** Compiled with `-Yimmutable-seq` */ +class repeatedArgs { + def bar(xs: String*): Int = xs.length + + def test(xs: immutable.Seq[String], ys: collection.Seq[String], zs: Array[String]): Unit = { + bar("a", "b", "c") + bar(xs: _*) + bar(ys: _*) // error: immutable.Seq expected, found Seq + bar(zs: _*) // error: immutable.Seq expected, found Array + + Paths.get("Hello", "World") + Paths.get("Hello", xs: _*) + Paths.get("Hello", ys: _*) // error: immutable.Seq expected, found Seq + Paths.get("Hello", zs: _*) // error: immutable.Seq expected, found Array + } +} diff --git a/tests/pos-special/repeatedArgs.scala b/tests/pos-special/repeatedArgs.scala new file mode 100644 index 000000000000..1db5ad0acfd9 --- /dev/null +++ b/tests/pos-special/repeatedArgs.scala @@ -0,0 +1,18 @@ +import scala.collection.{immutable, mutable} +import java.nio.file.Paths + +/** Compiled with `-Yimmutable-seq` */ +class repeatedArgs { + def bar(xs: String*): Int = xs.length + + def test(xs: immutable.Seq[String]): Unit = { + bar("a", "b", "c") + bar(xs: _*) + + Paths.get("Hello", "World") + Paths.get("Hello", xs: _*) + + val List(_, others: _*) = xs.toList // toList should not be needed, see #4790 + val x: immutable.Seq[String] = others + } +} diff --git a/tests/pos/repeatedArgs.scala b/tests/pos/repeatedArgs.scala index f9abb4aee70e..4bd51e5a15ef 100644 --- a/tests/pos/repeatedArgs.scala +++ b/tests/pos/repeatedArgs.scala @@ -1,3 +1,22 @@ -object testRepeated { - def foo = java.lang.System.out.format("%4$2s %3$2s %2$2s %1$2s", "a", "b", "c", "d") +import scala.collection.{immutable, mutable} +import java.nio.file.Paths + +class repeatedArgs { + def bar(xs: String*): Int = xs.length + + def test(xs: immutable.Seq[String], ys: collection.Seq[String], zs: Array[String]): Unit = { + bar("a", "b", "c") + bar(xs: _*) + bar(ys: _*) // error in 2.13 + bar(zs: _*) + + Paths.get("Hello", "World") + Paths.get("Hello", xs: _*) + Paths.get("Hello", ys: _*) // error in 2.13 + Paths.get("Hello", zs: _*) + + val List(_, others: _*) = xs.toList // toList should not be needed, see #4790 + val x: collection.Seq[String] = others + // val y: immutable.Seq[String] = others // ok in 2.13 + } }