Skip to content

Resolve SeqType based on the standard library on the classpath #4807

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
Jul 19, 2018
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
21 changes: 20 additions & 1 deletion compiler/src/dotty/tools/dotc/ast/tpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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._
Expand Down Expand Up @@ -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 = {
Expand All @@ -392,6 +393,24 @@ 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 = {
ref(defn.getWrapVarargsArrayModule)
.select(wrapArrayMethodName(elemtp))
.appliedToTypes(if (elemtp.isPrimitiveValueType) Nil else elemtp :: Nil)
.appliedTo(tree)
}

// ------ Creating typed equivalents of trees that exist only in untyped form -------

/** new C(args), calling the primary constructor of C */
Expand Down
28 changes: 17 additions & 11 deletions compiler/src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down Expand Up @@ -345,11 +344,6 @@ class Definitions {
def Predef_classOf(implicit ctx: Context) = Predef_classOfR.symbol
lazy val Predef_undefinedR = ScalaPredefModule.requiredMethodRef("???")
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
methodNames.map(ScalaPredefModule.requiredMethodRef(_).symbol)
})

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

// TODO: Remove once we drop support for 2.12 standard library
private[this] lazy val isNewCollections = ctx.base.staticRef("scala.collection.IterableOnce".toTypeName).exists

def getWrapVarargsArrayModule = if (isNewCollections) ScalaRuntimeModule else ScalaPredefModule

// The set of all wrap{X, Ref}Array methods, where X is a value type
val WrapArrayMethods = new PerRun[collection.Set[Symbol]]({ implicit ctx =>
val methodNames = ScalaValueTypes.map(ast.tpd.wrapArrayMethodName) + nme.wrapRefArray
methodNames.map(getWrapVarargsArrayModule.requiredMethodRef(_).symbol)
})

lazy val NilModuleRef = ctx.requiredModuleRef("scala.collection.immutable.Nil")
def NilModule(implicit ctx: Context) = NilModuleRef.symbol

Expand All @@ -401,7 +406,9 @@ 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 =
if (isNewCollections) ctx.requiredClassRef("scala.collection.immutable.Seq")
else ctx.requiredClassRef("scala.collection.Seq")
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
Expand Down Expand Up @@ -1210,12 +1217,11 @@ class Definitions {

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

private[this] var _isInitialized = false
private def isInitialized = _isInitialized
private[this] var isInitialized = false

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

_isInitialized = true
isInitialized = true
}
}

Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ class ElimRepeated extends MiniPhase with InfoTransformer { thisPhase =>
private def seqToArray(tree: Tree, pt: Type)(implicit ctx: Context): Tree = tree match {
case SeqLiteral(elems, elemtpt) =>
JavaSeqLiteral(elems, elemtpt)
case app@Apply(fun, args) if defn.Predef_wrapArray().contains(fun.symbol) => // rewrite a call to `wrapXArray(arr)` to `arr`
case app@Apply(fun, args) if defn.WrapArrayMethods().contains(fun.symbol) => // rewrite a call to `wrapXArray(arr)` to `arr`
args.head
case _ =>
val elemType = tree.tpe.elemType
Expand Down Expand Up @@ -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)
})

Expand Down
10 changes: 1 addition & 9 deletions compiler/src/dotty/tools/dotc/transform/SeqLiterals.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
26 changes: 0 additions & 26 deletions compiler/src/dotty/tools/dotc/transform/TreeGen.scala

This file was deleted.

2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/Implicits.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
3 changes: 3 additions & 0 deletions compiler/test/dotty/tools/dotc/FromTastyTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ class FromTastyTests extends ParallelTesting {

// Fails on MacOS
"annot-bootstrap.scala",

// ScalaRunTime cannot be unpickled because it is already loaded
"repeatedArgs213.scala",
),
recompilationBlacklist = Set(
)
Expand Down
43 changes: 43 additions & 0 deletions tests/neg/repeatedArgs213.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import scala.collection.{immutable, mutable}
import java.nio.file.Paths

// Code below is to trick the compiler into thinking that we are
// compiling with the 2.13 standard library on the classpath.
package scala.collection {
class IterableOnce
}

package scala.runtime {
object ScalaRunTime {
abstract class ArraySeq[+A] extends immutable.Seq[A]

def genericWrapArray[T](xs: Array[T]): ArraySeq[T] = ???
def wrapRefArray[T <: AnyRef](xs: Array[T]): ArraySeq[T] = ???
def wrapIntArray(xs: Array[Int]): ArraySeq[Int] = ???
def wrapDoubleArray(xs: Array[Double]): ArraySeq[Double] = ???
def wrapLongArray(xs: Array[Long]): ArraySeq[Long] = ???
def wrapFloatArray(xs: Array[Float]): ArraySeq[Float] = ???
def wrapCharArray(xs: Array[Char]): ArraySeq[Char] = ???
def wrapByteArray(xs: Array[Byte]): ArraySeq[Byte] = ???
def wrapShortArray(xs: Array[Short]): ArraySeq[Short] = ???
def wrapBooleanArray(xs: Array[Boolean]): ArraySeq[Boolean] = ???
def wrapUnitArray(xs: Array[Unit]): ArraySeq[Unit] = ???
}
}

// Start of Test
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
}
}
23 changes: 21 additions & 2 deletions tests/pos/repeatedArgs.scala
Original file line number Diff line number Diff line change
@@ -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
}
}
42 changes: 42 additions & 0 deletions tests/pos/repeatedArgs213.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import scala.collection.{immutable, mutable}
import java.nio.file.Paths

// Code below is to trick the compiler into thinking that we are
// compiling with the 2.13 standard library on the classpath.
package scala.collection {
class IterableOnce
}

package scala.runtime {
object ScalaRunTime {
abstract class ArraySeq[+A] extends immutable.Seq[A]

def genericWrapArray[T](xs: Array[T]): ArraySeq[T] = ???
def wrapRefArray[T <: AnyRef](xs: Array[T]): ArraySeq[T] = ???
def wrapIntArray(xs: Array[Int]): ArraySeq[Int] = ???
def wrapDoubleArray(xs: Array[Double]): ArraySeq[Double] = ???
def wrapLongArray(xs: Array[Long]): ArraySeq[Long] = ???
def wrapFloatArray(xs: Array[Float]): ArraySeq[Float] = ???
def wrapCharArray(xs: Array[Char]): ArraySeq[Char] = ???
def wrapByteArray(xs: Array[Byte]): ArraySeq[Byte] = ???
def wrapShortArray(xs: Array[Short]): ArraySeq[Short] = ???
def wrapBooleanArray(xs: Array[Boolean]): ArraySeq[Boolean] = ???
def wrapUnitArray(xs: Array[Unit]): ArraySeq[Unit] = ???
}
}

// Start of Test
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
}
}
3 changes: 3 additions & 0 deletions tests/pos/seqtype-cycle/Test1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class Test {
def bar = Array(1) // call to Array(_: Repeated)
}
8 changes: 8 additions & 0 deletions tests/pos/seqtype-cycle/Test2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package object scala {
// needed for some reasons
type Throwable = java.lang.Throwable
type IndexOutOfBoundsException = java.lang.IndexOutOfBoundsException

type Seq[+A] = scala.collection.Seq[A]
val Seq = scala.collection.Seq
}
12 changes: 12 additions & 0 deletions tests/pos/seqtype-cycle/Test3.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package scala

class specialized(types: Int*) extends scala.annotation.StaticAnnotation

package collection {
class Foo[@specialized(1, 2) A]

trait Seq[A] extends Foo[A]
object Seq extends SeqFactory[Seq]

trait SeqFactory[CC[X] <: Seq[X]]
}