From 9a378b10a706f283a7337a1debe02e586d08c5ed Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 15 Jan 2016 17:39:15 +0100 Subject: Compute type params in namer without completing the whole info Type params should be computed before computing the whole info of a type. Without the patch we get a cyclic reference in the compileMixed test. Note that compileIndexedSeq does not pass with this commit (it passed before), this is fixed in the next commit. --- src/dotty/tools/dotc/core/SymDenotations.scala | 8 +++++++ src/dotty/tools/dotc/core/TypeApplications.scala | 25 ++++++++++++-------- src/dotty/tools/dotc/core/TypeOps.scala | 2 +- src/dotty/tools/dotc/typer/Namer.scala | 29 ++++++++++++++++++++---- 4 files changed, 49 insertions(+), 15 deletions(-) (limited to 'src/dotty/tools') diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala index 8016c57f3..d384bd5c4 100644 --- a/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1802,6 +1802,14 @@ object SymDenotations { def withModuleClass(moduleClassFn: Context => Symbol): this.type = { myModuleClassFn = moduleClassFn; this } } + /** A subclass of LazyTypes where type parameters can be completed independently of + * the info. + */ + abstract class TypeParamsCompleter extends LazyType { + /** The type parameters computed by the completer before completion has finished */ + def completerTypeParams(sym: Symbol): List[TypeSymbol] + } + val NoSymbolFn = (ctx: Context) => NoSymbol /** A missing completer */ diff --git a/src/dotty/tools/dotc/core/TypeApplications.scala b/src/dotty/tools/dotc/core/TypeApplications.scala index aab327ce9..e09328205 100644 --- a/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/src/dotty/tools/dotc/core/TypeApplications.scala @@ -4,6 +4,7 @@ package core import Types._ import Contexts._ import Symbols._ +import SymDenotations.TypeParamsCompleter import Decorators._ import util.Stats._ import util.common._ @@ -240,15 +241,21 @@ class TypeApplications(val self: Type) extends AnyVal { case self: TypeRef => val tsym = self.symbol if (tsym.isClass) tsym.typeParams - else if (tsym.isAliasType) self.underlying.typeParams - else if (tsym.isCompleting) - // We are facing a problem when computing the type parameters of an uncompleted - // abstract type. We can't access the bounds of the symbol yet because that - // would cause a cause a cyclic reference. So we return `Nil` instead - // and try to make up for it later. The acrobatics in Scala2Unpicker#readType - // for reading a TypeRef show what's neeed. - Nil - else tsym.info.typeParams + else tsym.infoOrCompleter match { + case completer: TypeParamsCompleter => + val tparams = completer.completerTypeParams(tsym) + if (tsym.isClass) tparams + else defn.LambdaTrait(tparams.map(_.variance)).typeParams + case _ => + if (!tsym.isCompleting || tsym.isAliasType) tsym.info.typeParams + else + // We are facing a problem when computing the type parameters of an uncompleted + // abstract type. We can't access the bounds of the symbol yet because that + // would cause a cause a cyclic reference. So we return `Nil` instead + // and try to make up for it later. The acrobatics in Scala2Unpicker#readType + // for reading a TypeRef show what's needed. + Nil + } case self: RefinedType => // inlined and optimized version of // val sym = self.LambdaTrait diff --git a/src/dotty/tools/dotc/core/TypeOps.scala b/src/dotty/tools/dotc/core/TypeOps.scala index 04cd2249d..6896468ba 100644 --- a/src/dotty/tools/dotc/core/TypeOps.scala +++ b/src/dotty/tools/dotc/core/TypeOps.scala @@ -35,7 +35,7 @@ trait TypeOps { this: Context => // TODO: Make standalone object. * Instead we produce an annotated type that marks the prefix as unsafe: * * (x: (C @ UnsafeNonvariant)#T)C#T - + * We also set a global state flag `unsafeNonvariant` to the current run. * When typing a Select node, typer will check that flag, and if it * points to the current run will scan the result type of the select for diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala index b24916be8..406e7378f 100644 --- a/src/dotty/tools/dotc/typer/Namer.scala +++ b/src/dotty/tools/dotc/typer/Namer.scala @@ -478,10 +478,31 @@ class Namer { typer: Typer => } /** The completer of a symbol defined by a member def or import (except ClassSymbols) */ - class Completer(val original: Tree)(implicit ctx: Context) extends LazyType { + class Completer(val original: Tree)(implicit ctx: Context) extends TypeParamsCompleter { protected def localContext(owner: Symbol) = ctx.fresh.setOwner(owner).setTree(original) + private var myTypeParams: List[TypeSymbol] = null + private var nestedCtx: Context = null + + def completerTypeParams(sym: Symbol): List[TypeSymbol] = { + if (myTypeParams == null) { + //println(i"completing type params of $sym in ${sym.owner}") + myTypeParams = original match { + case tdef: TypeDef => + nestedCtx = localContext(sym).setNewScope + locally { + implicit val ctx: Context = nestedCtx + completeParams(tdef.tparams) + tdef.tparams.map(symbolOfTree(_).asType) + } + case _ => + Nil + } + } + myTypeParams + } + private def typeSig(sym: Symbol): Type = original match { case original: ValDef => if (sym is Module) moduleValSig(sym) @@ -492,7 +513,7 @@ class Namer { typer: Typer => typer1.defDefSig(original, sym)(localContext(sym).setTyper(typer1)) case original: TypeDef => assert(!original.isClassDef) - typeDefSig(original, sym)(localContext(sym).setNewScope) + typeDefSig(original, sym, completerTypeParams(sym))(nestedCtx) case imp: Import => try { val expr1 = typedAheadExpr(imp.expr, AnySelectionProto) @@ -840,9 +861,7 @@ class Namer { typer: Typer => else valOrDefDefSig(ddef, sym, typeParams, paramSymss, wrapMethType) } - def typeDefSig(tdef: TypeDef, sym: Symbol)(implicit ctx: Context): Type = { - completeParams(tdef.tparams) - val tparamSyms = tdef.tparams map symbolOfTree + def typeDefSig(tdef: TypeDef, sym: Symbol, tparamSyms: List[TypeSymbol])(implicit ctx: Context): Type = { val isDerived = tdef.rhs.isInstanceOf[untpd.DerivedTypeTree] //val toParameterize = tparamSyms.nonEmpty && !isDerived //val needsLambda = sym.allOverriddenSymbols.exists(_ is HigherKinded) && !isDerived -- cgit v1.2.3