summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bincompat-backward.whitelist.conf26
-rw-r--r--bincompat-forward.whitelist.conf14
-rw-r--r--project/plugins.sbt2
-rwxr-xr-xsrc/compiler/scala/tools/ant/templates/tool-unix.tmpl15
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala15
-rw-r--r--src/compiler/scala/tools/nsc/classpath/ClassPathFactory.scala6
-rw-r--r--src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala51
-rw-r--r--src/compiler/scala/tools/nsc/classpath/FileUtils.scala2
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalaSettings.scala1
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala6
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala31
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala13
-rw-r--r--src/compiler/scala/tools/util/PathResolver.scala1
-rw-r--r--src/reflect/scala/reflect/internal/StdAttachments.scala6
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala17
-rw-r--r--src/reflect/scala/reflect/internal/Types.scala77
-rw-r--r--src/reflect/scala/reflect/internal/settings/MutableSettings.scala1
-rw-r--r--src/reflect/scala/reflect/io/PlainFile.scala80
-rw-r--r--src/reflect/scala/reflect/runtime/JavaUniverseForce.scala1
-rw-r--r--src/reflect/scala/reflect/runtime/Settings.scala1
-rw-r--r--test/files/neg/t7046-2.check3
-rw-r--r--test/files/neg/t7046-2/Macros_1.scala15
-rw-r--r--test/files/neg/t7046-2/Test_2.scala14
-rw-r--r--test/files/neg/t7046.check3
-rw-r--r--test/files/neg/t7046/Macros_1.scala15
-rw-r--r--test/files/neg/t7046/Test_2.scala35
-rw-r--r--test/files/pos/t7046-2/Macros_1.scala14
-rw-r--r--test/files/pos/t7046-2/Test_2.scala9
-rw-r--r--test/files/run/t7046-1/Macros_1.scala15
-rw-r--r--test/files/run/t7046-1/Test_2.scala23
-rw-r--r--test/files/run/t7046-2/Macros_1.scala15
-rw-r--r--test/files/run/t7046-2/Test_2.scala14
-rw-r--r--test/files/run/virtpatmat_staging.flags2
-rw-r--r--test/pending/neg/t5729.check7
-rw-r--r--test/pending/neg/t5729.scala (renamed from test/files/pos/t5729.scala)0
35 files changed, 480 insertions, 70 deletions
diff --git a/bincompat-backward.whitelist.conf b/bincompat-backward.whitelist.conf
index af80bedf5b..6e260872c9 100644
--- a/bincompat-backward.whitelist.conf
+++ b/bincompat-backward.whitelist.conf
@@ -16,6 +16,32 @@ filter {
{
matchName="scala.sys.process.ProcessImpl#CompoundProcess.getExitValue"
problemName=DirectMissingMethodProblem
+ },
+ # these next seven can be removed once there is a fix for
+ # https://github.com/typesafehub/migration-manager/issues/147
+ {
+ matchName="scala.collection.Iterator#Leading#1.hd_="
+ problemName=DirectMissingMethodProblem
+ },
+ {
+ matchName="scala.collection.Iterator#Leading#1.hd"
+ problemName=DirectMissingMethodProblem
+ },
+ {
+ matchName="scala.collection.Iterator#Leading#1.status_="
+ problemName=DirectMissingMethodProblem
+ },
+ {
+ matchName="scala.collection.Iterator#Leading#1.lookahead_="
+ problemName=DirectMissingMethodProblem
+ },
+ {
+ matchName="scala.collection.Iterator#Leading#1.status"
+ problemName=DirectMissingMethodProblem
+ },
+ {
+ matchName="scala.collection.Iterator#Leading#1.lookahead"
+ problemName=DirectMissingMethodProblem
}
]
}
diff --git a/bincompat-forward.whitelist.conf b/bincompat-forward.whitelist.conf
index 541268e50e..7ccd2ea8fa 100644
--- a/bincompat-forward.whitelist.conf
+++ b/bincompat-forward.whitelist.conf
@@ -20,6 +20,20 @@ filter {
{
matchName="scala.sys.process.ProcessImpl#CompoundProcess.futureThread"
problemName=DirectMissingMethodProblem
+ },
+ {
+ matchName="scala.reflect.runtime.Settings.Yvirtpatmat"
+ problemName=DirectMissingMethodProblem
+ },
+ {
+ matchName="scala.reflect.io.PlainNioFile"
+ problemName=MissingClassProblem
+ },
+ # this one can be removed once there is a fix for
+ # https://github.com/typesafehub/migration-manager/issues/147
+ {
+ matchName="scala.collection.Iterator#Leading#1.trailer"
+ problemName=DirectMissingMethodProblem
}
]
}
diff --git a/project/plugins.sbt b/project/plugins.sbt
index e056de55ec..d2476d9207 100644
--- a/project/plugins.sbt
+++ b/project/plugins.sbt
@@ -19,4 +19,4 @@ buildInfoKeys := Seq[BuildInfoKey](buildClasspath)
buildInfoPackage := "scalabuild"
-libraryDependencies += "com.typesafe" %% "mima-reporter" % "0.1.11"
+libraryDependencies += "com.typesafe" %% "mima-reporter" % "0.1.12"
diff --git a/src/compiler/scala/tools/ant/templates/tool-unix.tmpl b/src/compiler/scala/tools/ant/templates/tool-unix.tmpl
index 5e6b3c041e..b5a238f7be 100755
--- a/src/compiler/scala/tools/ant/templates/tool-unix.tmpl
+++ b/src/compiler/scala/tools/ant/templates/tool-unix.tmpl
@@ -160,7 +160,7 @@ while [[ $# -gt 0 ]]; do
shift 2
;;
-nobootcp)
- unset usebootcp
+ usebootcp="false"
shift
;;
-usebootcp)
@@ -189,15 +189,22 @@ declare -a classpath_args
# default to the boot classpath for speed, except on cygwin/mingw/msys because
# JLine on Windows requires a custom DLL to be loaded.
-unset usebootcp
-if [[ -z "$cygwin$mingw$msys" ]]; then
+if [[ "$usebootcp" != "false" && -z "$cygwin$mingw$msys" ]]; then
usebootcp="true"
fi
# If using the boot classpath, also pass an empty classpath
# to java to suppress "." from materializing.
-if [[ -n $usebootcp ]]; then
+if [[ "$usebootcp" == "true" ]]; then
classpath_args=("-Xbootclasspath/a:$TOOL_CLASSPATH" -classpath "\"\"")
+ # Note that the version numbers go 1.7, 1.8, 9, 10, ...
+ java_release="$(cat $JAVA_HOME/release | grep JAVA_VERSION)"
+ if [[ ! "$java_release" =~ JAVA_VERSION=\"1\. ]]; then
+ # Java 9 removed sun.boot.class.path, and the supposed replacement to at least see
+ # the appended boot classpath (jdk.boot.class.path.append) is not visible.
+ # So we have to pass a custom system property that PathResolver will find.
+ classpath_args+=("-Dscala.boot.class.path=$TOOL_CLASSPATH")
+ fi
else
classpath_args=(-classpath "$TOOL_CLASSPATH")
fi
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index e58d2d3b43..464fa1ad18 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -185,6 +185,19 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
}
}
+ private var propCnt = 0
+ @inline final def withPropagateCyclicReferences[T](t: => T): T = {
+ try {
+ propCnt = propCnt+1
+ t
+ } finally {
+ propCnt = propCnt-1
+ assert(propCnt >= 0)
+ }
+ }
+
+ def propagateCyclicReferences: Boolean = propCnt > 0
+
/** Representing ASTs as graphs */
object treeBrowsers extends {
val global: Global.this.type = Global.this
@@ -333,8 +346,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
// to create it on that side. For this one my strategy is a constant def at the file
// where I need it, and then an override in Global with the setting.
override protected val etaExpandKeepsStar = settings.etaExpandKeepsStar.value
- // Here comes another one...
- override protected val enableTypeVarExperimentals = settings.Xexperimental.value
def getSourceFile(f: AbstractFile): BatchSourceFile = new BatchSourceFile(f, reader read f)
diff --git a/src/compiler/scala/tools/nsc/classpath/ClassPathFactory.scala b/src/compiler/scala/tools/nsc/classpath/ClassPathFactory.scala
index 3a29f1ba11..80c5ec8828 100644
--- a/src/compiler/scala/tools/nsc/classpath/ClassPathFactory.scala
+++ b/src/compiler/scala/tools/nsc/classpath/ClassPathFactory.scala
@@ -4,6 +4,7 @@
package scala.tools.nsc.classpath
import scala.reflect.io.{AbstractFile, VirtualDirectory}
+import scala.reflect.io.Path.string2path
import scala.tools.nsc.Settings
import FileUtils.AbstractFileOps
import scala.tools.nsc.util.ClassPath
@@ -52,7 +53,10 @@ class ClassPathFactory(settings: Settings) {
protected def classesInPathImpl(path: String, expand: Boolean) =
for {
file <- expandPath(path, expand)
- dir <- Option(AbstractFile.getDirectory(file))
+ dir <- {
+ def asImage = if (file.endsWith(".jimage")) Some(AbstractFile.getFile(file)) else None
+ Option(AbstractFile.getDirectory(file)).orElse(asImage)
+ }
} yield newClassPath(dir)
private def createSourcePath(file: AbstractFile): ClassPath =
diff --git a/src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala b/src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala
index c4be59d7eb..133a656206 100644
--- a/src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala
+++ b/src/compiler/scala/tools/nsc/classpath/DirectoryClassPath.scala
@@ -4,7 +4,9 @@
package scala.tools.nsc.classpath
import java.io.File
-import java.net.URL
+import java.net.{URI, URL}
+import java.nio.file.{FileSystems, Files, SimpleFileVisitor}
+import java.util.function.IntFunction
import java.util
import java.util.Comparator
@@ -119,6 +121,53 @@ trait JFileDirectoryLookup[FileEntryType <: ClassRepresentation] extends Directo
def asClassPathStrings: Seq[String] = Seq(dir.getPath)
}
+object JImageDirectoryLookup {
+ import java.nio.file._, java.net.URI, scala.collection.JavaConverters._
+ def apply(): List[ClassPath] = {
+ try {
+ val fs = FileSystems.getFileSystem(URI.create("jrt:/"))
+ val dir: Path = fs.getPath("/modules")
+ val modules = Files.list(dir).iterator().asScala.toList
+ modules.map(m => new JImageDirectoryLookup(fs, m.getFileName.toString))
+ } catch {
+ case _: ProviderNotFoundException | _: FileSystemNotFoundException =>
+ Nil
+ }
+ }
+}
+class JImageDirectoryLookup(fs: java.nio.file.FileSystem, module: String) extends DirectoryLookup[ClassFileEntryImpl] with NoSourcePaths {
+ import java.nio.file.Path, java.nio.file._
+ type F = Path
+ val dir: Path = fs.getPath("/modules/" + module)
+
+ protected def emptyFiles: Array[Path] = Array.empty
+ protected def getSubDir(packageDirName: String): Option[Path] = {
+ val packageDir = dir.resolve(packageDirName)
+ if (Files.exists(packageDir) && Files.isDirectory(packageDir)) Some(packageDir)
+ else None
+ }
+ protected def listChildren(dir: Path, filter: Option[Path => Boolean]): Array[Path] = {
+ import scala.collection.JavaConverters._
+ val f = filter.getOrElse((p: Path) => true)
+ Files.list(dir).iterator().asScala.filter(f).toArray[Path]
+ }
+ protected def getName(f: Path): String = f.getFileName.toString
+ protected def toAbstractFile(f: Path): AbstractFile = new scala.reflect.io.PlainNioFile(f)
+ protected def isPackage(f: Path): Boolean = Files.isDirectory(f) && mayBeValidPackage(f.getFileName.toString)
+
+ def asURLs: Seq[URL] = Seq(dir.toUri.toURL)
+ def asClassPathStrings: Seq[String] = asURLs.map(_.toString)
+
+ def findClassFile(className: String): Option[AbstractFile] = {
+ val relativePath = FileUtils.dirPath(className) + ".class"
+ val classFile = dir.resolve(relativePath)
+ if (Files.exists(classFile)) Some(new scala.reflect.io.PlainNioFile(classFile)) else None
+ }
+ override protected def createFileEntry(file: AbstractFile): ClassFileEntryImpl = ClassFileEntryImpl(file)
+ override protected def isMatchingFile(f: Path): Boolean = Files.isRegularFile(f) && f.getFileName.toString.endsWith(".class")
+ override private[nsc] def classes(inPackage: String): Seq[ClassFileEntry] = files(inPackage)
+}
+
case class DirectoryClassPath(dir: File) extends JFileDirectoryLookup[ClassFileEntryImpl] with NoSourcePaths {
override def findClass(className: String): Option[ClassRepresentation] = findClassFile(className) map ClassFileEntryImpl
diff --git a/src/compiler/scala/tools/nsc/classpath/FileUtils.scala b/src/compiler/scala/tools/nsc/classpath/FileUtils.scala
index bbcfcb24ca..2ade83c6f9 100644
--- a/src/compiler/scala/tools/nsc/classpath/FileUtils.scala
+++ b/src/compiler/scala/tools/nsc/classpath/FileUtils.scala
@@ -63,7 +63,7 @@ object FileUtils {
// probably it should match a pattern like [a-z_]{1}[a-z0-9_]* but it cannot be changed
// because then some tests in partest don't pass
- private def mayBeValidPackage(dirName: String): Boolean =
+ def mayBeValidPackage(dirName: String): Boolean =
(dirName != "META-INF") && (dirName != "") && (dirName.charAt(0) != '.')
def mkFileFilter(f: JFile => Boolean) = new FileFilter {
diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
index 5eb99e0d98..a3b9df1518 100644
--- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
@@ -215,6 +215,7 @@ trait ScalaSettings extends AbsScalaSettings
val inferByName = BooleanSetting ("-Yinfer-by-name", "Allow inference of by-name types. This is a temporary option to ease transition. See SI-7899.").withDeprecationMessage(removalIn212)
val YdisableFlatCpCaching = BooleanSetting ("-YdisableFlatCpCaching", "Do not cache flat classpath representation of classpath elements from jars across compiler instances.")
val YpartialUnification = BooleanSetting ("-Ypartial-unification", "Enable partial unification in type constructor inference")
+ val Yvirtpatmat = BooleanSetting ("-Yvirtpatmat", "Enable pattern matcher virtualization")
val exposeEmptyPackage = BooleanSetting ("-Yexpose-empty-package", "Internal only: expose the empty package.").internalOnly()
val Ydelambdafy = ChoiceSetting ("-Ydelambdafy", "strategy", "Strategy used for translating lambdas into JVM code.", List("inline", "method"), "method")
diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
index fcfcc8feb9..2d8d591b6d 100644
--- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
@@ -655,9 +655,6 @@ trait ContextErrors {
def ParentFinalInheritanceError(parent: Tree, mixin: Symbol) =
NormalTypeError(parent, "illegal inheritance from final "+mixin)
- def ParentSealedInheritanceError(parent: Tree, psym: Symbol) =
- NormalTypeError(parent, "illegal inheritance from sealed " + psym )
-
def ParentSelfTypeConformanceError(parent: Tree, selfType: Type) =
NormalTypeError(parent,
"illegal inheritance;\n self-type "+selfType+" does not conform to "+
@@ -1172,6 +1169,9 @@ trait ContextErrors {
def MissingParameterOrValTypeError(vparam: Tree) =
issueNormalTypeError(vparam, "missing parameter type")
+ def ParentSealedInheritanceError(parent: Tree, psym: Symbol) =
+ NormalTypeError(parent, "illegal inheritance from sealed " + psym )
+
def RootImportError(tree: Tree) =
issueNormalTypeError(tree, "_root_ cannot be imported")
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index 27a586e543..b445bc5837 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -115,7 +115,7 @@ trait Namers extends MethodSynthesis {
protected def owner = context.owner
def contextFile = context.unit.source.file
def typeErrorHandler[T](tree: Tree, alt: T): PartialFunction[Throwable, T] = {
- case ex: TypeError =>
+ case ex: TypeError if !global.propagateCyclicReferences =>
// H@ need to ensure that we handle only cyclic references
TypeSigError(tree, ex)
alt
@@ -1031,12 +1031,33 @@ trait Namers extends MethodSynthesis {
private def templateSig(templ: Template): Type = {
val clazz = context.owner
+
+ val parentTrees = typer.typedParentTypes(templ)
+
+ val pending = mutable.ListBuffer[AbsTypeError]()
+ parentTrees foreach { tpt =>
+ val ptpe = tpt.tpe
+ if(!ptpe.isError) {
+ val psym = ptpe.typeSymbol
+ val sameSourceFile = context.unit.source.file == psym.sourceFile
+
+ if (psym.isSealed && !phase.erasedTypes)
+ if (sameSourceFile)
+ psym addChild context.owner
+ else
+ pending += ParentSealedInheritanceError(tpt, psym)
+ if (psym.isLocalToBlock && !phase.erasedTypes)
+ psym addChild context.owner
+ }
+ }
+ pending.foreach(ErrorUtils.issueTypeError)
+
def checkParent(tpt: Tree): Type = {
if (tpt.tpe.isError) AnyRefTpe
else tpt.tpe
}
- val parents = typer.typedParentTypes(templ) map checkParent
+ val parents = parentTrees map checkParent
enterSelf(templ.self)
@@ -1830,6 +1851,12 @@ trait Namers extends MethodSynthesis {
abstract class TypeCompleter extends LazyType {
val tree: Tree
+ override def forceDirectSuperclasses: Unit = {
+ tree.foreach {
+ case dt: DefTree => global.withPropagateCyclicReferences(Option(dt.symbol).map(_.maybeInitialize))
+ case _ =>
+ }
+ }
}
def mkTypeCompleter(t: Tree)(c: Symbol => Unit) = new LockingTypeCompleter with FlagAgnosticCompleter {
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 82733c1643..fc0a0368ab 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -1678,7 +1678,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
supertpts mapConserve (tpt => checkNoEscaping.privates(context.owner, tpt))
}
catch {
- case ex: TypeError =>
+ case ex: TypeError if !global.propagateCyclicReferences =>
// fallback in case of cyclic errors
// @H none of the tests enter here but I couldn't rule it out
// upd. @E when a definition inherits itself, we end up here
@@ -1739,13 +1739,6 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
context.deprecationWarning(parent.pos, psym, report, version)
}
- if (psym.isSealed && !phase.erasedTypes)
- if (sameSourceFile)
- psym addChild context.owner
- else
- pending += ParentSealedInheritanceError(parent, psym)
- if (psym.isLocalToBlock && !phase.erasedTypes)
- psym addChild context.owner
val parentTypeOfThis = parent.tpe.dealias.typeOfThis
if (!(selfType <:< parentTypeOfThis) &&
@@ -2561,7 +2554,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
// TODO: add fallback __match sentinel to predef
val matchStrategy: Tree =
- if (!(settings.Xexperimental && context.isNameInScope(vpmName._match))) null // fast path, avoiding the next line if there's no __match to be seen
+ if (!(settings.Yvirtpatmat && context.isNameInScope(vpmName._match))) null // fast path, avoiding the next line if there's no __match to be seen
else newTyper(context.makeImplicit(reportAmbiguousErrors = false)).silent(_.typed(Ident(vpmName._match)), reportAmbiguousErrors = false) orElse (_ => null)
if (matchStrategy ne null) // virtualize
@@ -5554,6 +5547,8 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
}
try runTyper() catch {
+ case ex: CyclicReference if global.propagateCyclicReferences =>
+ throw ex
case ex: TypeError =>
tree.clearType()
// The only problematic case are (recoverable) cyclic reference errors which can pop up almost anywhere.
diff --git a/src/compiler/scala/tools/util/PathResolver.scala b/src/compiler/scala/tools/util/PathResolver.scala
index c351b6ace1..188cabbc8d 100644
--- a/src/compiler/scala/tools/util/PathResolver.scala
+++ b/src/compiler/scala/tools/util/PathResolver.scala
@@ -234,6 +234,7 @@ final class PathResolver(settings: Settings) {
// Assemble the elements!
def basis = List[Traversable[ClassPath]](
+ JImageDirectoryLookup.apply(), // 0. The Java 9 classpath (backed by the jrt:/ virtual system)
classesInPath(javaBootClassPath), // 1. The Java bootstrap class path.
contentsOfDirsInPath(javaExtDirs), // 2. The Java extension class path.
classesInExpandedPath(javaUserClassPath), // 3. The Java application class path.
diff --git a/src/reflect/scala/reflect/internal/StdAttachments.scala b/src/reflect/scala/reflect/internal/StdAttachments.scala
index fd8f51cfb1..fc49de1cf6 100644
--- a/src/reflect/scala/reflect/internal/StdAttachments.scala
+++ b/src/reflect/scala/reflect/internal/StdAttachments.scala
@@ -81,4 +81,10 @@ trait StdAttachments {
/** An attachment carrying information between uncurry and erasure */
case class TypeParamVarargsAttachment(val typeParamRef: Type)
+
+ /** Attached to a class symbol to indicate that its children have been observed
+ * via knownDirectSubclasses. Children added subsequently will trigger an
+ * error to indicate that the earlier observation was incomplete.
+ */
+ case object KnownDirectSubclassesCalled extends PlainAttachment
}
diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala
index 0da153349a..e664b5ad08 100644
--- a/src/reflect/scala/reflect/internal/Symbols.scala
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -121,6 +121,16 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def knownDirectSubclasses = {
// See `getFlag` to learn more about the `isThreadsafe` call in the body of this method.
if (!isCompilerUniverse && !isThreadsafe(purpose = AllOps)) initialize
+
+ enclosingPackage.info.decls.foreach { sym =>
+ if(sourceFile == sym.sourceFile) {
+ sym.rawInfo.forceDirectSuperclasses
+ }
+ }
+
+ if(!isPastTyper)
+ updateAttachment(KnownDirectSubclassesCalled)
+
children
}
@@ -3298,7 +3308,12 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
private[this] var childSet: Set[Symbol] = Set()
override def children = childSet
- override def addChild(sym: Symbol) { childSet = childSet + sym }
+ override def addChild(sym: Symbol) {
+ if(!isPastTyper && hasAttachment[KnownDirectSubclassesCalled.type] && !childSet.contains(sym))
+ globalError(s"knownDirectSubclasses of ${this.name} observed before subclass ${sym.name} registered")
+
+ childSet = childSet + sym
+ }
def anonOrRefinementString = {
if (hasCompleteInfo) {
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala
index 5e1bf37b80..ad7e3ffe8f 100644
--- a/src/reflect/scala/reflect/internal/Types.scala
+++ b/src/reflect/scala/reflect/internal/Types.scala
@@ -91,7 +91,6 @@ trait Types
private var explainSwitch = false
private final val emptySymbolSet = immutable.Set.empty[Symbol]
- private final val traceTypeVars = sys.props contains "scalac.debug.tvar"
private final val breakCycles = settings.breakCycles.value
/** In case anyone wants to turn on type parameter bounds being used
* to seed type constraints.
@@ -99,8 +98,6 @@ trait Types
private final val propagateParameterBoundsToTypeVars = sys.props contains "scalac.debug.prop-constraints"
private final val sharperSkolems = sys.props contains "scalac.experimental.sharper-skolems"
- protected val enableTypeVarExperimentals = settings.Xexperimental.value
-
/** Caching the most recent map has a 75-90% hit rate. */
private object substTypeMapCache {
private[this] var cached: SubstTypeMap = new SubstTypeMap(Nil, Nil)
@@ -315,6 +312,11 @@ trait Types
/** If this is a lazy type, assign a new type to `sym`. */
def complete(sym: Symbol) {}
+ /** If this is a lazy type corresponding to a subclass add it to its
+ * parents children
+ */
+ def forceDirectSuperclasses: Unit = ()
+
/** The term symbol associated with the type
* Note that the symbol of the normalized type is returned (@see normalize)
*/
@@ -2823,13 +2825,13 @@ trait Types
// now, pattern-matching returns the most recent constr
object TypeVar {
@inline final def trace[T](action: String, msg: => String)(value: T): T = {
- if (traceTypeVars) {
- val s = msg match {
- case "" => ""
- case str => "( " + str + " )"
- }
- Console.err.println("[%10s] %-25s%s".format(action, value, s))
- }
+ // Uncomment the following for a compiler that has some diagnostics about type inference
+ // I doubt this is ever useful in the wild, so a recompile will be needed
+// val s = msg match {
+// case "" => ""
+// case str => "( " + str + " )"
+// }
+// Console.err.println("[%10s] %-25s%s".format(action, value, s))
value
}
@@ -2850,7 +2852,9 @@ trait Types
val exclude = bounds.isEmptyBounds || (bounds exists typeIsNonClassType)
if (exclude) new TypeConstraint
- else TypeVar.trace("constraint", "For " + tparam.fullLocationString)(new TypeConstraint(bounds))
+ else TypeVar.trace("constraint", "For " + tparam.fullLocationString)(
+ new TypeConstraint(bounds)
+ )
}
else new TypeConstraint
}
@@ -2879,7 +2883,9 @@ trait Types
else throw new Error("Invalid TypeVar construction: " + ((origin, constr, args, params)))
)
- trace("create", "In " + tv.originLocation)(tv)
+ trace("create", "In " + tv.originLocation)(
+ tv
+ )
}
private def createTypeVar(tparam: Symbol, untouchable: Boolean): TypeVar =
createTypeVar(tparam.tpeHK, deriveConstraint(tparam), Nil, tparam.typeParams, untouchable)
@@ -2983,7 +2989,9 @@ trait Types
else if (newArgs.size == params.size) {
val tv = TypeVar(origin, constr, newArgs, params)
tv.linkSuspended(this)
- TypeVar.trace("applyArgs", "In " + originLocation + ", apply args " + newArgs.mkString(", ") + " to " + originName)(tv)
+ TypeVar.trace("applyArgs", s"In $originLocation, apply args ${newArgs.mkString(", ")} to $originName")(
+ tv
+ )
}
else
TypeVar(typeSymbol).setInst(ErrorType)
@@ -3002,31 +3010,20 @@ trait Types
// only one of them is in the set of tvars that need to be solved, but
// they share the same TypeConstraint instance
- // When comparing to types containing skolems, remember the highest level
- // of skolemization. If that highest level is higher than our initial
- // skolemizationLevel, we can't re-use those skolems as the solution of this
- // typevar, which means we'll need to repack our inst into a fresh existential.
- // were we compared to skolems at a higher skolemizationLevel?
- // EXPERIMENTAL: value will not be considered unless enableTypeVarExperimentals is true
- // see SI-5729 for why this is still experimental
- private var encounteredHigherLevel = false
- private def shouldRepackType = enableTypeVarExperimentals && encounteredHigherLevel
-
// <region name="constraint mutators + undoLog">
// invariant: before mutating constr, save old state in undoLog
// (undoLog is used to reset constraints to avoid piling up unrelated ones)
- def setInst(tp: Type): this.type = {
- if (tp eq this) {
+ def setInst(tp: Type): this.type =
+ if (tp ne this) {
+ undoLog record this
+ constr.inst = TypeVar.trace("setInst", s"In $originLocation, $originName=$tp")(
+ tp
+ )
+ this
+ } else {
log(s"TypeVar cycle: called setInst passing $this to itself.")
- return this
+ this
}
- undoLog record this
- // if we were compared against later typeskolems, repack the existential,
- // because skolems are only compatible if they were created at the same level
- val res = if (shouldRepackType) repackExistential(tp) else tp
- constr.inst = TypeVar.trace("setInst", "In " + originLocation + ", " + originName + "=" + res)(res)
- this
- }
def addLoBound(tp: Type, isNumericBound: Boolean = false) {
assert(tp != this, tp) // implies there is a cycle somewhere (?)
@@ -3251,19 +3248,13 @@ trait Types
case ts: TypeSkolem => ts.level > level
case _ => false
}
- // side-effects encounteredHigherLevel
- private def containsSkolemAboveLevel(tp: Type) =
- (tp exists isSkolemAboveLevel) && { encounteredHigherLevel = true ; true }
- /** Can this variable be related in a constraint to type `tp`?
+
+ /** Can this variable be related in a constraint to type `tp`?
* This is not the case if `tp` contains type skolems whose
* skolemization level is higher than the level of this variable.
*/
- def isRelatable(tp: Type) = (
- shouldRepackType // short circuit if we already know we've seen higher levels
- || !containsSkolemAboveLevel(tp) // side-effects tracking boolean
- || enableTypeVarExperimentals // -Xexperimental: always say we're relatable, track consequences
- )
+ def isRelatable(tp: Type) = !(tp exists isSkolemAboveLevel)
override def normalize: Type = (
if (instValid) inst
@@ -3311,7 +3302,7 @@ trait Types
// to never be resumed with the current implementation
assert(!suspended, this)
TypeVar.trace("clone", originLocation)(
- TypeVar(origin, constr.cloneInternal, typeArgs, params) // @M TODO: clone args/params?
+ TypeVar(origin, constr.cloneInternal, typeArgs, params)
)
}
}
diff --git a/src/reflect/scala/reflect/internal/settings/MutableSettings.scala b/src/reflect/scala/reflect/internal/settings/MutableSettings.scala
index 5a2c802476..ab933ae617 100644
--- a/src/reflect/scala/reflect/internal/settings/MutableSettings.scala
+++ b/src/reflect/scala/reflect/internal/settings/MutableSettings.scala
@@ -54,6 +54,7 @@ abstract class MutableSettings extends AbsSettings {
def uniqid: BooleanSetting
def verbose: BooleanSetting
def YpartialUnification: BooleanSetting
+ def Yvirtpatmat: BooleanSetting
def Yrecursion: IntSetting
def maxClassfileName: IntSetting
diff --git a/src/reflect/scala/reflect/io/PlainFile.scala b/src/reflect/scala/reflect/io/PlainFile.scala
index eb0940e703..989081ebe0 100644
--- a/src/reflect/scala/reflect/io/PlainFile.scala
+++ b/src/reflect/scala/reflect/io/PlainFile.scala
@@ -40,7 +40,6 @@ class PlainFile(val givenPath: Path) extends AbstractFile {
override def output = givenPath.toFile.outputStream()
override def sizeOption = Some(givenPath.length.toInt)
- override def toString = path
override def hashCode(): Int = fpath.hashCode()
override def equals(that: Any): Boolean = that match {
case x: PlainFile => fpath == x.fpath
@@ -91,3 +90,82 @@ class PlainFile(val givenPath: Path) extends AbstractFile {
def lookupNameUnchecked(name: String, directory: Boolean): AbstractFile =
new PlainFile(givenPath / name)
}
+
+private[scala] class PlainNioFile(nioPath: java.nio.file.Path) extends AbstractFile {
+ import java.nio.file._
+
+ assert(nioPath ne null)
+
+ /** Returns the underlying File if any and null otherwise. */
+ override def file: java.io.File = try {
+ nioPath.toFile
+ } catch {
+ case _: UnsupportedOperationException => null
+ }
+
+ override def underlyingSource = Some(this)
+
+ private val fpath = nioPath.toAbsolutePath.toString
+
+ /** Returns the name of this abstract file. */
+ def name = nioPath.getFileName.toString
+
+ /** Returns the path of this abstract file. */
+ def path = nioPath.toString
+
+ /** The absolute file. */
+ def absolute = new PlainNioFile(nioPath.toAbsolutePath)
+
+ override def container: AbstractFile = new PlainNioFile(nioPath.getParent)
+ override def input = Files.newInputStream(nioPath)
+ override def output = Files.newOutputStream(nioPath)
+ override def sizeOption = Some(Files.size(nioPath).toInt)
+ override def hashCode(): Int = fpath.hashCode()
+ override def equals(that: Any): Boolean = that match {
+ case x: PlainNioFile => fpath == x.fpath
+ case _ => false
+ }
+
+ /** Is this abstract file a directory? */
+ def isDirectory: Boolean = Files.isDirectory(nioPath)
+
+ /** Returns the time that this abstract file was last modified. */
+ def lastModified: Long = Files.getLastModifiedTime(nioPath).toMillis
+
+ /** Returns all abstract subfiles of this abstract directory. */
+ def iterator: Iterator[AbstractFile] = {
+ try {
+ import scala.collection.JavaConverters._
+ val it = Files.newDirectoryStream(nioPath).iterator()
+ it.asScala.map(new PlainNioFile(_))
+ } catch {
+ case _: NotDirectoryException => Iterator.empty
+ }
+ }
+
+ /**
+ * Returns the abstract file in this abstract directory with the
+ * specified name. If there is no such file, returns null. The
+ * argument "directory" tells whether to look for a directory or
+ * or a regular file.
+ */
+ def lookupName(name: String, directory: Boolean): AbstractFile = {
+ val child = nioPath.resolve(name)
+ if ((Files.isDirectory(child) && directory) || (Files.isRegularFile(child) && !directory)) new PlainNioFile(child)
+ else null
+ }
+
+ /** Does this abstract file denote an existing file? */
+ def create(): Unit = if (!exists) Files.createFile(nioPath)
+
+ /** Delete the underlying file or directory (recursively). */
+ def delete(): Unit =
+ if (Files.isRegularFile(nioPath)) Files.deleteIfExists(nioPath)
+ else if (Files.isDirectory(nioPath)) new Directory(nioPath.toFile).deleteRecursively()
+
+ /** Returns a plain file with the given name. It does not
+ * check that it exists.
+ */
+ def lookupNameUnchecked(name: String, directory: Boolean): AbstractFile =
+ new PlainNioFile(nioPath.resolve(name))
+}
diff --git a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
index dbafbfc6ba..d5d62b2203 100644
--- a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
+++ b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
@@ -48,6 +48,7 @@ trait JavaUniverseForce { self: runtime.JavaUniverse =>
this.OuterArgCanBeElided
this.UseInvokeSpecial
this.TypeParamVarargsAttachment
+ this.KnownDirectSubclassesCalled
this.noPrint
this.typeDebug
this.Range
diff --git a/src/reflect/scala/reflect/runtime/Settings.scala b/src/reflect/scala/reflect/runtime/Settings.scala
index 3b33f089e1..2d8bacd3b2 100644
--- a/src/reflect/scala/reflect/runtime/Settings.scala
+++ b/src/reflect/scala/reflect/runtime/Settings.scala
@@ -48,6 +48,7 @@ private[reflect] class Settings extends MutableSettings {
val uniqid = new BooleanSetting(false)
val verbose = new BooleanSetting(false)
val YpartialUnification = new BooleanSetting(false)
+ val Yvirtpatmat = new BooleanSetting(false)
val Yrecursion = new IntSetting(0)
val maxClassfileName = new IntSetting(255)
diff --git a/test/files/neg/t7046-2.check b/test/files/neg/t7046-2.check
new file mode 100644
index 0000000000..b4efd8b5e9
--- /dev/null
+++ b/test/files/neg/t7046-2.check
@@ -0,0 +1,3 @@
+error: knownDirectSubclasses of Foo observed before subclass Bar registered
+error: knownDirectSubclasses of Foo observed before subclass Baz registered
+two errors found
diff --git a/test/files/neg/t7046-2/Macros_1.scala b/test/files/neg/t7046-2/Macros_1.scala
new file mode 100644
index 0000000000..2a5bf82f62
--- /dev/null
+++ b/test/files/neg/t7046-2/Macros_1.scala
@@ -0,0 +1,15 @@
+import scala.language.experimental.macros
+import scala.reflect.macros.blackbox.Context
+
+object Macros {
+ def impl[T](c: Context)(implicit ttag: c.WeakTypeTag[T]): c.Expr[List[String]] = {
+ import c.universe._;
+ val ttpe = ttag.tpe
+ val tsym = ttpe.typeSymbol.asClass
+ val subclasses = tsym.knownDirectSubclasses.toList.map(_.name.toString)
+
+ c.Expr[List[String]](q"$subclasses")
+ }
+
+ def knownDirectSubclasses[T]: List[String] = macro impl[T]
+}
diff --git a/test/files/neg/t7046-2/Test_2.scala b/test/files/neg/t7046-2/Test_2.scala
new file mode 100644
index 0000000000..18a2ebcbc2
--- /dev/null
+++ b/test/files/neg/t7046-2/Test_2.scala
@@ -0,0 +1,14 @@
+object Test extends App {
+ def nested: Unit = {
+ val subs = Macros.knownDirectSubclasses[Foo]
+ assert(subs == List("Bar", "Baz"))
+
+ sealed trait Foo
+ object Foo {
+ trait Bar extends Foo
+ trait Baz extends Foo
+ }
+ }
+
+ nested
+}
diff --git a/test/files/neg/t7046.check b/test/files/neg/t7046.check
new file mode 100644
index 0000000000..689520a0aa
--- /dev/null
+++ b/test/files/neg/t7046.check
@@ -0,0 +1,3 @@
+error: knownDirectSubclasses of Foo observed before subclass Local registered
+error: knownDirectSubclasses of Foo observed before subclass Riddle registered
+two errors found
diff --git a/test/files/neg/t7046/Macros_1.scala b/test/files/neg/t7046/Macros_1.scala
new file mode 100644
index 0000000000..2a5bf82f62
--- /dev/null
+++ b/test/files/neg/t7046/Macros_1.scala
@@ -0,0 +1,15 @@
+import scala.language.experimental.macros
+import scala.reflect.macros.blackbox.Context
+
+object Macros {
+ def impl[T](c: Context)(implicit ttag: c.WeakTypeTag[T]): c.Expr[List[String]] = {
+ import c.universe._;
+ val ttpe = ttag.tpe
+ val tsym = ttpe.typeSymbol.asClass
+ val subclasses = tsym.knownDirectSubclasses.toList.map(_.name.toString)
+
+ c.Expr[List[String]](q"$subclasses")
+ }
+
+ def knownDirectSubclasses[T]: List[String] = macro impl[T]
+}
diff --git a/test/files/neg/t7046/Test_2.scala b/test/files/neg/t7046/Test_2.scala
new file mode 100644
index 0000000000..fcb3e46a0f
--- /dev/null
+++ b/test/files/neg/t7046/Test_2.scala
@@ -0,0 +1,35 @@
+object Test extends App {
+ val subs = Macros.knownDirectSubclasses[Foo]
+ assert(subs == List("Wibble", "Wobble", "Bar", "Baz"))
+}
+
+sealed trait Foo
+object Foo {
+ trait Wibble extends Foo
+ case object Wobble extends Foo
+}
+
+trait Bar extends Foo
+
+object Blah {
+ type Quux = Foo
+}
+
+import Blah._
+
+trait Baz extends Quux
+
+class Boz[T](t: T)
+class Unrelated extends Boz(Test.subs)
+
+object Enigma {
+ locally {
+ // local class not seen
+ class Local extends Foo
+ }
+
+ def foo: Unit = {
+ // local class not seen
+ class Riddle extends Foo
+ }
+}
diff --git a/test/files/pos/t7046-2/Macros_1.scala b/test/files/pos/t7046-2/Macros_1.scala
new file mode 100644
index 0000000000..07c0c61281
--- /dev/null
+++ b/test/files/pos/t7046-2/Macros_1.scala
@@ -0,0 +1,14 @@
+package p1
+
+import scala.reflect.macros.blackbox._
+import language.experimental._
+
+object Macro {
+ def impl(c: Context): c.Tree = {
+ import c.universe._
+ val tsym = rootMirror.staticClass("p1.Base")
+ val subclasses = tsym.knownDirectSubclasses.toList.map(_.name.toString)
+ q"$subclasses"
+ }
+ def p1_Base_knownDirectSubclasses: List[String] = macro impl
+}
diff --git a/test/files/pos/t7046-2/Test_2.scala b/test/files/pos/t7046-2/Test_2.scala
new file mode 100644
index 0000000000..74e30a863d
--- /dev/null
+++ b/test/files/pos/t7046-2/Test_2.scala
@@ -0,0 +1,9 @@
+package p1
+
+sealed trait Base
+
+object Test {
+ val x = Macro.p1_Base_knownDirectSubclasses
+}
+
+case class B(val b: Test.x.type)
diff --git a/test/files/run/t7046-1/Macros_1.scala b/test/files/run/t7046-1/Macros_1.scala
new file mode 100644
index 0000000000..2a5bf82f62
--- /dev/null
+++ b/test/files/run/t7046-1/Macros_1.scala
@@ -0,0 +1,15 @@
+import scala.language.experimental.macros
+import scala.reflect.macros.blackbox.Context
+
+object Macros {
+ def impl[T](c: Context)(implicit ttag: c.WeakTypeTag[T]): c.Expr[List[String]] = {
+ import c.universe._;
+ val ttpe = ttag.tpe
+ val tsym = ttpe.typeSymbol.asClass
+ val subclasses = tsym.knownDirectSubclasses.toList.map(_.name.toString)
+
+ c.Expr[List[String]](q"$subclasses")
+ }
+
+ def knownDirectSubclasses[T]: List[String] = macro impl[T]
+}
diff --git a/test/files/run/t7046-1/Test_2.scala b/test/files/run/t7046-1/Test_2.scala
new file mode 100644
index 0000000000..28459fde72
--- /dev/null
+++ b/test/files/run/t7046-1/Test_2.scala
@@ -0,0 +1,23 @@
+object Test extends App {
+ val subs = Macros.knownDirectSubclasses[Foo]
+ assert(subs == List("Wibble", "Wobble", "Bar", "Baz"))
+}
+
+sealed trait Foo
+object Foo {
+ trait Wibble extends Foo
+ case object Wobble extends Foo
+}
+
+trait Bar extends Foo
+
+object Blah {
+ type Quux = Foo
+}
+
+import Blah._
+
+trait Baz extends Quux
+
+class Boz[T](t: T)
+class Unrelated extends Boz(Test.subs)
diff --git a/test/files/run/t7046-2/Macros_1.scala b/test/files/run/t7046-2/Macros_1.scala
new file mode 100644
index 0000000000..2a5bf82f62
--- /dev/null
+++ b/test/files/run/t7046-2/Macros_1.scala
@@ -0,0 +1,15 @@
+import scala.language.experimental.macros
+import scala.reflect.macros.blackbox.Context
+
+object Macros {
+ def impl[T](c: Context)(implicit ttag: c.WeakTypeTag[T]): c.Expr[List[String]] = {
+ import c.universe._;
+ val ttpe = ttag.tpe
+ val tsym = ttpe.typeSymbol.asClass
+ val subclasses = tsym.knownDirectSubclasses.toList.map(_.name.toString)
+
+ c.Expr[List[String]](q"$subclasses")
+ }
+
+ def knownDirectSubclasses[T]: List[String] = macro impl[T]
+}
diff --git a/test/files/run/t7046-2/Test_2.scala b/test/files/run/t7046-2/Test_2.scala
new file mode 100644
index 0000000000..79407f522f
--- /dev/null
+++ b/test/files/run/t7046-2/Test_2.scala
@@ -0,0 +1,14 @@
+object Test extends App {
+ def nested: Unit = {
+ sealed trait Foo
+ object Foo {
+ trait Bar extends Foo
+ trait Baz extends Foo
+ }
+
+ val subs = Macros.knownDirectSubclasses[Foo]
+ assert(subs == List("Bar", "Baz"))
+ }
+
+ nested
+}
diff --git a/test/files/run/virtpatmat_staging.flags b/test/files/run/virtpatmat_staging.flags
index 0a22f7c729..bec3aa96e9 100644
--- a/test/files/run/virtpatmat_staging.flags
+++ b/test/files/run/virtpatmat_staging.flags
@@ -1,2 +1,2 @@
-Yrangepos:false
--Xexperimental
+-Yvirtpatmat
diff --git a/test/pending/neg/t5729.check b/test/pending/neg/t5729.check
new file mode 100644
index 0000000000..10c13db8b6
--- /dev/null
+++ b/test/pending/neg/t5729.check
@@ -0,0 +1,7 @@
+t5729.scala:5: error: ambiguous reference to overloaded definition,
+both method join in object Test of type [S](in: Seq[T[S]])String
+and method join in object Test of type (in: Seq[T[_]])Int
+match argument types (Seq[T[_]])
+ join(null: Seq[T[_]])
+ ^
+one error found
diff --git a/test/files/pos/t5729.scala b/test/pending/neg/t5729.scala
index 9fd9c9ffbb..9fd9c9ffbb 100644
--- a/test/files/pos/t5729.scala
+++ b/test/pending/neg/t5729.scala