diff options
author | Adriaan Moors <adriaan@lightbend.com> | 2016-11-30 17:45:59 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-11-30 17:45:59 -0800 |
commit | c2eb299b0e1ed2f321a81d4afbdb36762e2c0e7b (patch) | |
tree | b184b8e08dc9077a39b4f48e86e5e4959ffb3c01 /src/compiler/scala | |
parent | 038c15e405b9498863a2236707686a7933748c60 (diff) | |
parent | dde13b56f421a6f956abebc58f041acec8744149 (diff) | |
download | scala-c2eb299b0e1ed2f321a81d4afbdb36762e2c0e7b.tar.gz scala-c2eb299b0e1ed2f321a81d4afbdb36762e2c0e7b.tar.bz2 scala-c2eb299b0e1ed2f321a81d4afbdb36762e2c0e7b.zip |
Merge pull request #5284 from milessabin/topic/si-7046
SI-7046 reflection doesn't see all knownDirectSubclasses
This appears to do the right thing in the most typical scenarios in which `knownDirectSubclasses` would be used. The missing 5% is that subclasses defined in local scopes might not be seen by `knownDirectSubclasses` (see `Local` and `Riddle` in the test below). In mitigation, though, it is almost certain that a local subclass would represent an error in any scenario where `knownDirectSubclasses` might be used.
Errors for such situations are reported by recording (via a symbol attachment) that `knownDirectSubclasses` has been called and reporting an error if any additional children are added subsequently.
Despite these limitations and caveats, I believe that this represents a huge improvement over the status quo, and would eliminate 100% of the failures that I've seen in practice with people using shapeless for type class derivation.
Diffstat (limited to 'src/compiler/scala')
4 files changed, 48 insertions, 13 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 9c9be4eb4d..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 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 78e8c8c073..7ffc6c6b48 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 @@ -1028,12 +1028,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) @@ -1827,6 +1848,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 de72d9feed..ec676c30a5 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) && @@ -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. |