From 1034d4e420c2b0724945486f341c53a07e6a90e0 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 10 Apr 2013 10:09:06 +0200 Subject: Removing automatic legal prefix checking. It turned out this led to cycles in subtyping. We need to check for legal prefixes only for types that are declared or inferred in source. For the rest, we should assume that the type is OK. --- src/dotty/tools/dotc/core/Contexts.scala | 35 +++++++++++++++------- src/dotty/tools/dotc/core/Printers.scala | 4 +-- src/dotty/tools/dotc/core/SymDenotations.scala | 1 - src/dotty/tools/dotc/core/Types.scala | 17 ++++++++--- .../tools/dotc/core/pickling/ClassfileParser.scala | 2 +- 5 files changed, 40 insertions(+), 19 deletions(-) (limited to 'src/dotty') diff --git a/src/dotty/tools/dotc/core/Contexts.scala b/src/dotty/tools/dotc/core/Contexts.scala index 092330ac9..29da40caf 100644 --- a/src/dotty/tools/dotc/core/Contexts.scala +++ b/src/dotty/tools/dotc/core/Contexts.scala @@ -128,17 +128,32 @@ object Contexts { protected def diagnostics_=(diagnostics: Option[StringBuilder]) = _diagnostics = diagnostics def diagnostics: Option[StringBuilder] = _diagnostics - /** Should prefix of type selections to be checked whether it's stable? - * Disabled when reading Scala pickled information. - */ - private var _checkPrefix: Boolean = true - protected def checkPrefix_=(checkPrefix: Boolean) = _checkPrefix = checkPrefix - def checkPrefix: Boolean = _checkPrefix - + /** A map in which more contextual properties can be stored */ private var _moreProperties: Map[String, Any] = _ protected def moreProperties_=(moreProperties: Map[String, Any]) = _moreProperties = moreProperties def moreProperties: Map[String, Any] = _moreProperties + /** If -Ydebug is on, the top of the stack trace where this context + * was created, otherwise `null`. + */ + private var creationTrace: Array[StackTraceElement] = _ + + setCreationTrace() + + private def setCreationTrace() = + if (true || this.settings.debug.value) + creationTrace = (new Throwable).getStackTrace().take(20) + + /** Print all enclosing context's creation stacktraces */ + def printCreationTraces() = { + println("=== context creation trace =======") + for (ctx <- outersIterator) { + println(s">>>>>>>>> $ctx") + if (ctx.creationTrace != null) println(ctx.creationTrace.mkString("\n")) + } + println("=== end context creation trace ===") + } + /** Leave message in diagnostics buffer if it exists */ def diagnose(str: => String) = for (sb <- diagnostics) { @@ -192,6 +207,7 @@ object Contexts { def fresh: FreshContext = { val newctx = super.clone.asInstanceOf[FreshContext] newctx.outer = this + newctx.setCreationTrace() newctx } } @@ -218,9 +234,8 @@ object Contexts { def withTree(tree: Tree): this.type = { this.tree = tree; this } def withReporter(reporter: Reporter): this.type = { this.reporter = reporter; this } def withDiagnostics(diagnostics: Option[StringBuilder]): this.type = { this.diagnostics = diagnostics; this } - def withCheckPrefix(checkPrefix: Boolean): this.type = { this.checkPrefix = checkPrefix; this } def withMoreProperties(moreProperties: Map[String, Any]): this.type = { this.moreProperties = moreProperties; this } - + def withProperty(prop: (String, Any)): this.type = withMoreProperties(moreProperties + prop) def withPhase(pid: PhaseId): this.type = withPeriod(Period(runId, pid)) @@ -229,7 +244,6 @@ object Contexts { withSettings(setting.updateIn(sstate, value)) def withDebug = withSetting(base.settings.debug, true) - } /** A class defining the initial context with given context base @@ -365,7 +379,6 @@ object Contexts { val theBase = new ContextBase // !!! DEBUG, so that we can use a minimal context for reporting even in code that normallly cannot access a context } - /** Initial size of superId table */ private final val InitialSuperIdsSize = 4096 diff --git a/src/dotty/tools/dotc/core/Printers.scala b/src/dotty/tools/dotc/core/Printers.scala index fe69c65e6..6255a79da 100644 --- a/src/dotty/tools/dotc/core/Printers.scala +++ b/src/dotty/tools/dotc/core/Printers.scala @@ -89,7 +89,7 @@ object Printers { } class PlainPrinter(_ctx: Context) extends Printer { - protected[this] implicit val ctx = _ctx.fresh.withCheckPrefix(false) + protected[this] implicit val ctx = _ctx def controlled(op: => Text): Text = if (ctx.toTextRecursions < maxToTextRecursions) @@ -499,7 +499,7 @@ object Printers { override protected def treatAsTypeArg(sym: Symbol) = sym.isType && (sym is ProtectedLocal) && - (ctx.traceIndented(s"$sym.allOverriddenSymbols")(sym.allOverriddenSymbols) exists (_ is TypeParam)) + (sym.allOverriddenSymbols exists (_ is TypeParam)) override protected def reconstituteParent(cls: ClassSymbol, parent: Type): Type = (parent /: parent.classSymbol.typeParams) { (parent, tparam) => diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala index 0b8f494d0..a559e9d79 100644 --- a/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/src/dotty/tools/dotc/core/SymDenotations.scala @@ -766,7 +766,6 @@ object SymDenotations { * gets invalidated. */ def memberFingerPrint(implicit ctx: Context): FingerPrint = { - assert(classSymbol.hasChildren) if (_memberFingerPrint == FingerPrint.empty) _memberFingerPrint = computeMemberFingerPrint _memberFingerPrint } diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index 22ea23b52..7656835cf 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -901,10 +901,15 @@ object Types { lastDenotation.current } else { val d = loadDenot +/* need to do elsewhere as it leads to a cycle in subtyping here. if (d.exists && !d.symbol.isAliasType && !prefix.isLegalPrefix) { - val ex = new MalformedType(prefix, d) - if (ctx.checkPrefix) throw ex else ctx.log(ex.getMessage) + val ex = new MalformedType(prefix, d, prefix.memberNames(abstractTypeNameFilter)) + if (ctx.checkPrefix) { + ctx.printCreationTrace() + throw ex + } else ctx.log(ex.getMessage) } +*/ if (d.exists || ctx.phaseId == FirstPhaseId) d else // name has changed; try load in earlier phase and make current @@ -1710,8 +1715,12 @@ object Types { class TypeError(msg: String) extends Exception(msg) class FatalTypeError(msg: String) extends TypeError(msg) - class MalformedType(pre: Type, denot: Denotation) - extends FatalTypeError(s"malformed type: $pre is not a legal prefix for $denot") + + class MalformedType(pre: Type, denot: Denotation, absMembers: Set[Name]) + extends FatalTypeError( + s"""malformed type: $pre is not a legal prefix for $denot because it contains abstract type member${if (absMembers.size == 1) "" else "s"} ${absMembers.mkString(", ")}""" + .stripMargin) + class CyclicReference(val denot: SymDenotation) extends FatalTypeError(s"cyclic reference involving $denot") diff --git a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala index e17588e60..801841915 100644 --- a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala +++ b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala @@ -18,7 +18,7 @@ class ClassfileParser( classRoot: ClassDenotation, moduleRoot: ClassDenotation)(cctx0: CondensedContext) { - implicit val cctx: CondensedContext = cctx0.fresh.withCheckPrefix(false) + implicit val cctx: CondensedContext = cctx0 import ClassfileConstants._ import cctx.base.{settings, loaders, definitions => defn} -- cgit v1.2.3