summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdriaan Moors <adriaan@lightbend.com>2016-10-18 10:37:17 -0700
committerGitHub <noreply@github.com>2016-10-18 10:37:17 -0700
commit5c3193aea0e53ff71238d419f69cd6532d9f8433 (patch)
treee5488eab17140c6f684366d28fae21c2e83a280e
parentc6a1e947004a4582e4daf7e7a330b30f27dccc61 (diff)
parentd171b2cc16cc129e0f3aa03c3df9b2fb86208aa6 (diff)
downloadscala-5c3193aea0e53ff71238d419f69cd6532d9f8433.tar.gz
scala-5c3193aea0e53ff71238d419f69cd6532d9f8433.tar.bz2
scala-5c3193aea0e53ff71238d419f69cd6532d9f8433.zip
Merge pull request #5345 from milessabin/topic/si-7046-backport
[nomerge] Partial fix for SI-7046
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala13
-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.scala9
-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.scala5
-rw-r--r--src/reflect/scala/reflect/runtime/JavaUniverseForce.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/reflection-mem-typecheck.scala2
-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
21 files changed, 252 insertions, 13 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index a618b080c8..8d72fd76bd 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -214,6 +214,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
diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
index 727f09290a..80cccaf2ae 100644
--- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
@@ -614,9 +614,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 "+
@@ -1135,6 +1132,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 4ad81b60ae..ee64a6646f 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -110,7 +110,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
@@ -912,12 +912,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)
@@ -1678,6 +1699,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 6b73a538df..508d205424 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -1643,7 +1643,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
@@ -1702,11 +1702,6 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
context.deprecationWarning(parent.pos, psym, msg)
}
- if (psym.isSealed && !phase.erasedTypes)
- if (sameSourceFile)
- psym addChild context.owner
- else
- pending += ParentSealedInheritanceError(parent, psym)
val parentTypeOfThis = parent.tpe.dealias.typeOfThis
if (!(selfType <:< parentTypeOfThis) &&
@@ -5421,6 +5416,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/reflect/scala/reflect/internal/StdAttachments.scala b/src/reflect/scala/reflect/internal/StdAttachments.scala
index cca33253be..3df31b538c 100644
--- a/src/reflect/scala/reflect/internal/StdAttachments.scala
+++ b/src/reflect/scala/reflect/internal/StdAttachments.scala
@@ -52,4 +52,10 @@ trait StdAttachments {
/** Untyped list of subpatterns attached to selector dummy. */
case class SubpatternsAttachment(patterns: List[Tree])
+
+ /** 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 3b9ee9048a..6116952c70 100644
--- a/src/reflect/scala/reflect/internal/Symbols.scala
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -110,6 +110,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
}
@@ -3351,7 +3361,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 9697e16da7..3a645616eb 100644
--- a/src/reflect/scala/reflect/internal/Types.scala
+++ b/src/reflect/scala/reflect/internal/Types.scala
@@ -310,6 +310,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)
*/
diff --git a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
index 7725e4a2f0..8481cd8996 100644
--- a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
+++ b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
@@ -41,6 +41,7 @@ trait JavaUniverseForce { self: runtime.JavaUniverse =>
this.ForAttachment
this.SyntheticUnitAttachment
this.SubpatternsAttachment
+ this.KnownDirectSubclassesCalled
this.noPrint
this.typeDebug
this.Range
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/reflection-mem-typecheck.scala b/test/files/run/reflection-mem-typecheck.scala
index e3cabf689d..f1fe983ede 100644
--- a/test/files/run/reflection-mem-typecheck.scala
+++ b/test/files/run/reflection-mem-typecheck.scala
@@ -11,7 +11,7 @@ object Test extends MemoryTest {
cm.mkToolBox()
}
- override def maxDelta = 10
+ override def maxDelta = 12
override def calcsPerIter = 8
override def calc() {
var snippet = """
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
+}