diff options
author | odersky <odersky@gmail.com> | 2017-02-21 17:10:14 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-02-21 17:10:14 +0100 |
commit | 355232690d96e458764159a66f3fed0135c059a3 (patch) | |
tree | c6183190768ead9ddaa5e5103dad7f5007b9c182 /compiler | |
parent | 6189ffe415c8905cc5802f0505d837b4142999db (diff) | |
parent | 7c4a9ec39ad3c6302767442de34f53c28cc3bebb (diff) | |
download | dotty-355232690d96e458764159a66f3fed0135c059a3.tar.gz dotty-355232690d96e458764159a66f3fed0135c059a3.tar.bz2 dotty-355232690d96e458764159a66f3fed0135c059a3.zip |
Merge pull request #1974 from dotty-staging/fix/ctx-capture
Avoid accidental captures of Context
Diffstat (limited to 'compiler')
13 files changed, 87 insertions, 59 deletions
diff --git a/compiler/src/dotty/tools/dotc/core/Annotations.scala b/compiler/src/dotty/tools/dotc/core/Annotations.scala index 985b1ea3d..5464dce4f 100644 --- a/compiler/src/dotty/tools/dotc/core/Annotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Annotations.scala @@ -117,11 +117,17 @@ object Annotations { } /** Create an annotation where the symbol and the tree are computed lazily. */ - def deferredSymAndTree(sym: => Symbol, treeFn: Context => Tree)(implicit ctx: Context): Annotation = + def deferredSymAndTree(symf: Context => Symbol, treeFn: Context => Tree)(implicit ctx: Context): Annotation = new LazyAnnotation { - lazy val symf = sym - - override def symbol(implicit ctx: Context): Symbol = symf + private[this] var mySym: Symbol = _ + + override def symbol(implicit ctx: Context): Symbol = { + if (mySym == null || mySym.defRunId != ctx.runId) { + mySym = symf(ctx) + assert(mySym != null) + } + mySym + } def complete(implicit ctx: Context) = treeFn(ctx) } diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index c2a7d7ea6..308e6e306 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -401,12 +401,12 @@ trait TypeOps { this: Context => // TODO: Make standalone object. def forwardRefs(from: Symbol, to: Type, prefs: List[TypeRef]) = to match { case to @ TypeBounds(lo1, hi1) if lo1 eq hi1 => for (pref <- prefs) { - def forward(): Unit = + def forward()(implicit ctx: Context): Unit = for (argSym <- pref.decls) if (argSym is BaseTypeArg) forwardRef(argSym, from, to, cls, decls) pref.info match { - case info: TempClassInfo => info.addSuspension(forward) + case info: TempClassInfo => info.addSuspension(implicit ctx => forward()) case _ => forward() } } diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 1174e863e..200e94a1e 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -3088,14 +3088,14 @@ object Types { * be no longer temporary. These actions will be performed once `cls` gets a real * ClassInfo. */ - private var suspensions: List[() => Unit] = Nil + private var suspensions: List[Context => Unit] = Nil - def addSuspension(suspension: () => Unit): Unit = suspensions ::= suspension + def addSuspension(suspension: Context => Unit): Unit = suspensions ::= suspension /** Install classinfo with known parents in `denot` and resume all suspensions */ def finalize(denot: SymDenotation, parents: List[TypeRef])(implicit ctx: Context) = { denot.info = derivedClassInfo(classParents = parents) - suspensions.foreach(_()) + suspensions.foreach(_(ctx)) } } diff --git a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala index 5b751ef3c..36d478c6d 100644 --- a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala +++ b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala @@ -806,7 +806,7 @@ class ClassfileParser( def classSymbol(externalName: Name)(implicit ctx: Context): Symbol = { /** Return the symbol of `innerName`, having the given `externalName`. */ def innerSymbol(externalName: Name, innerName: Name, static: Boolean): Symbol = { - def getMember(sym: Symbol, name: Name): Symbol = + def getMember(sym: Symbol, name: Name)(implicit ctx: Context): Symbol = if (static) if (sym == classRoot.symbol) staticScope.lookup(name) else sym.companionModule.info.member(name).symbol diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index ffd594454..fcba957c0 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -554,7 +554,9 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle val end = readEnd() val tp = readType() val lazyAnnotTree = readLater(end, rdr => ctx => rdr.readTerm()(ctx)) - annots += Annotation.deferredSymAndTree(tp.typeSymbol, _ => lazyAnnotTree.complete) + annots += Annotation.deferredSymAndTree( + implicit ctx => tp.typeSymbol, + implicit ctx => lazyAnnotTree.complete) case tag => assert(false, s"illegal modifier tag $tag at $currentAddr, end = $end") } @@ -769,7 +771,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle cls.setApplicableFlags(fork.indexStats(end)) val constr = readIndexedDef().asInstanceOf[DefDef] - def mergeTypeParamsAndAliases(tparams: List[TypeDef], stats: List[Tree]): (List[Tree], List[Tree]) = + def mergeTypeParamsAndAliases(tparams: List[TypeDef], stats: List[Tree])(implicit ctx: Context): (List[Tree], List[Tree]) = (tparams, stats) match { case (tparam :: tparams1, (alias: TypeDef) :: stats1) if tparam.name == alias.name.expandedName(cls) => diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index b01f6cc6a..3a2a45fd2 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -932,9 +932,10 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas protected def deferredAnnot(end: Int)(implicit ctx: Context): Annotation = { val start = readIndex val atp = readTypeRef() + val phase = ctx.phase Annotation.deferred( - atp.typeSymbol, implicit ctx1 => - atReadPos(start, () => readAnnotationContents(end)(ctx1.withPhase(ctx.phase)))) + atp.typeSymbol, implicit ctx => + atReadPos(start, () => readAnnotationContents(end)(ctx.withPhase(phase)))) } /* Read an abstract syntax tree */ diff --git a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala index 1c3ff8ea0..0d1068b8c 100644 --- a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -7,6 +7,7 @@ import Contexts.Context, Scopes.Scope, Denotations.Denotation, Annotations.Annot import StdNames.{nme, tpnme} import ast.Trees._, ast._ import typer.Implicits._ +import typer.ImportInfo import config.Config import java.lang.Integer.toOctalString import config.Config.summarizeDepth @@ -503,6 +504,17 @@ class PlainPrinter(_ctx: Context) extends Printer { "?Unknown Implicit Result?" } + def toText(importInfo: ImportInfo): Text = { + val siteStr = importInfo.site.show + val exprStr = if (siteStr endsWith ".type") siteStr dropRight 5 else siteStr + val selectorStr = importInfo.selectors match { + case Ident(name) :: Nil => name.show + case _ => "{...}" + } + s"import $exprStr.$selectorStr" + } + + private var maxSummarized = Int.MaxValue def summarized[T](depth: Int)(op: => T): T = { diff --git a/compiler/src/dotty/tools/dotc/printing/Printer.scala b/compiler/src/dotty/tools/dotc/printing/Printer.scala index 506773a4b..e163a83f3 100644 --- a/compiler/src/dotty/tools/dotc/printing/Printer.scala +++ b/compiler/src/dotty/tools/dotc/printing/Printer.scala @@ -6,6 +6,7 @@ import Texts._, ast.Trees._ import Types.Type, Symbols.Symbol, Contexts.Context, Scopes.Scope, Constants.Constant, Names.Name, Denotations._, Annotations.Annotation import typer.Implicits.SearchResult +import typer.ImportInfo /** The base class of all printers */ @@ -98,6 +99,9 @@ abstract class Printer { /** Textual representation of implicit search result */ def toText(result: SearchResult): Text + /** Textual representation of info relating to an import clause */ + def toText(result: ImportInfo): Text + /** Perform string or text-producing operation `op` so that only a * summarized text with given recursion depth is shown */ diff --git a/compiler/src/dotty/tools/dotc/transform/TailRec.scala b/compiler/src/dotty/tools/dotc/transform/TailRec.scala index 3e7a7ed89..aa0845605 100644 --- a/compiler/src/dotty/tools/dotc/transform/TailRec.scala +++ b/compiler/src/dotty/tools/dotc/transform/TailRec.scala @@ -119,7 +119,7 @@ class TailRec extends MiniPhaseTransform with DenotTransformer with FullParamete // now this speculatively transforms tree and throws away result in many cases val rhsSemiTransformed = { val transformer = new TailRecElimination(origMeth, dd.tparams, owner, thisTpe, mandatory, label, abstractOverClass = defIsTopLevel) - val rhs = atGroupEnd(transformer.transform(dd.rhs)(_)) + val rhs = atGroupEnd(implicit ctx => transformer.transform(dd.rhs)) rewrote = transformer.rewrote rhs } diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 0ed6ed6b4..5e092871d 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -683,7 +683,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => * * { val xs = es; e' = e' + args } */ - def typedOpAssign: Tree = track("typedOpAssign") { + def typedOpAssign(implicit ctx: Context): Tree = track("typedOpAssign") { val Apply(Select(lhs, name), rhss) = tree val lhs1 = typedExpr(lhs) val liftedDefs = new mutable.ListBuffer[Tree] @@ -805,16 +805,16 @@ trait Applications extends Compatibility { self: Typer with Dynamic => * whereas overloaded variants need to have a conforming variant. */ def trySelectUnapply(qual: untpd.Tree)(fallBack: Tree => Tree): Tree = { - val genericProto = new UnapplyFunProto(WildcardType, this) - def specificProto = new UnapplyFunProto(selType, this) // try first for non-overloaded, then for overloaded ocurrences def tryWithName(name: TermName)(fallBack: Tree => Tree)(implicit ctx: Context): Tree = - tryEither { - implicit ctx => typedExpr(untpd.Select(qual, name), specificProto) + tryEither { implicit ctx => + val specificProto = new UnapplyFunProto(selType, this) + typedExpr(untpd.Select(qual, name), specificProto) } { (sel, _) => - tryEither { - implicit ctx => typedExpr(untpd.Select(qual, name), genericProto) + tryEither { implicit ctx => + val genericProto = new UnapplyFunProto(WildcardType, this) + typedExpr(untpd.Select(qual, name), genericProto) } { (_, _) => fallBack(sel) } diff --git a/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala b/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala index f7efb2ac2..3bee0bbe8 100644 --- a/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala +++ b/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala @@ -5,6 +5,7 @@ package typer import ast.{tpd, untpd} import ast.Trees._ import core._ +import printing.{Printer, Showable} import util.SimpleMap import Symbols._, Names._, Denotations._, Types._, Contexts._, StdNames._, Flags._ import Decorators.StringInterpolators @@ -13,9 +14,9 @@ object ImportInfo { /** The import info for a root import from given symbol `sym` */ def rootImport(refFn: () => TermRef)(implicit ctx: Context) = { val selectors = untpd.Ident(nme.WILDCARD) :: Nil - def expr = tpd.Ident(refFn()) - def imp = tpd.Import(expr, selectors) - new ImportInfo(imp.symbol, selectors, None, isRootImport = true) + def expr(implicit ctx: Context) = tpd.Ident(refFn()) + def imp(implicit ctx: Context) = tpd.Import(expr, selectors) + new ImportInfo(implicit ctx => imp.symbol, selectors, None, isRootImport = true) } } @@ -27,14 +28,14 @@ object ImportInfo { * @param isRootImport true if this is one of the implicit imports of scala, java.lang, * scala.Predef or dotty.DottyPredef in the start context, false otherwise. */ -class ImportInfo(symf: => Symbol, val selectors: List[untpd.Tree], - symNameOpt: Option[TermName], val isRootImport: Boolean = false)(implicit ctx: Context) { +class ImportInfo(symf: Context => Symbol, val selectors: List[untpd.Tree], + symNameOpt: Option[TermName], val isRootImport: Boolean = false) extends Showable { // Dotty deviation: we cannot use a lazy val here for the same reason // that we cannot use one for `DottyPredefModuleRef`. - def sym = { + def sym(implicit ctx: Context) = { if (mySym == null) { - mySym = symf + mySym = symf(ctx) assert(mySym != null) } mySym @@ -91,7 +92,7 @@ class ImportInfo(symf: => Symbol, val selectors: List[untpd.Tree], } /** The implicit references imported by this import clause */ - def importedImplicits: List[TermRef] = { + def importedImplicits(implicit ctx: Context): List[TermRef] = { val pre = site if (isWildcardImport) { val refs = pre.implicitMembers @@ -115,23 +116,21 @@ class ImportInfo(symf: => Symbol, val selectors: List[untpd.Tree], * override import Predef.{any2stringAdd => _, StringAdd => _, _} // disables String + * override import java.lang.{} // disables all imports */ - lazy val unimported: Symbol = { - lazy val sym = site.termSymbol - def maybeShadowsRoot = symNameOpt match { - case Some(symName) => defn.ShadowableImportNames.contains(symName) - case None => false + def unimported(implicit ctx: Context): Symbol = { + if (myUnimported == null) { + lazy val sym = site.termSymbol + def maybeShadowsRoot = symNameOpt match { + case Some(symName) => defn.ShadowableImportNames.contains(symName) + case None => false + } + myUnimported = + if (maybeShadowsRoot && defn.RootImportTypes.exists(_.symbol == sym)) sym + else NoSymbol + assert(myUnimported != null) } - if (maybeShadowsRoot && defn.RootImportTypes.exists(_.symbol == sym)) sym - else NoSymbol + myUnimported } + private[this] var myUnimported: Symbol = _ - override def toString = { - val siteStr = site.show - val exprStr = if (siteStr endsWith ".type") siteStr dropRight 5 else siteStr - val selectorStr = selectors match { - case Ident(name) :: Nil => name.show - case _ => "{...}" - } - i"import $exprStr.$selectorStr" - } + def toText(printer: Printer) = printer.toText(this) } diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 3860ba225..d5f171fe3 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -24,6 +24,7 @@ import language.implicitConversions import reporting.diagnostic.messages._ trait NamerContextOps { this: Context => + import NamerContextOps._ /** Enter symbol into current class, if current class is owner of current context, * or into current scope, if not. Should always be called instead of scope.enter @@ -119,22 +120,25 @@ trait NamerContextOps { this: Context => else monotpe } - /** Find moduleClass/sourceModule in effective scope */ - private def findModuleBuddy(name: Name)(implicit ctx: Context) = { - val scope = effectiveScope - val it = scope.lookupAll(name).filter(_ is Module) - assert(it.hasNext, s"no companion $name in $scope") - it.next - } - /** Add moduleClass or sourceModule functionality to completer * for a module or module class */ - def adjustModuleCompleter(completer: LazyType, name: Name) = + def adjustModuleCompleter(completer: LazyType, name: Name) = { + val scope = this.effectiveScope if (name.isTermName) - completer withModuleClass (_ => findModuleBuddy(name.moduleClassName)) + completer withModuleClass (implicit ctx => findModuleBuddy(name.moduleClassName, scope)) else - completer withSourceModule (_ => findModuleBuddy(name.sourceModuleName)) + completer withSourceModule (implicit ctx => findModuleBuddy(name.sourceModuleName, scope)) + } +} + +object NamerContextOps { + /** Find moduleClass/sourceModule in effective scope */ + private def findModuleBuddy(name: Name, scope: Scope)(implicit ctx: Context) = { + val it = scope.lookupAll(name).filter(_ is Module) + assert(it.hasNext, s"no companion $name in $scope") + it.next + } } /** This class creates symbols from definitions and imports and gives them @@ -378,7 +382,7 @@ class Namer { typer: Typer => case ref: RefTree => Some(ref.name.asTermName) case _ => None } - ctx.fresh.setImportInfo(new ImportInfo(sym, imp.selectors, impNameOpt)) + ctx.fresh.setImportInfo(new ImportInfo(implicit ctx => sym, imp.selectors, impNameOpt)) } /** A new context for the interior of a class */ diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 26f7bc65b..06200d3e4 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -145,7 +145,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit */ def bindingString(prec: Int, whereFound: Context, qualifier: String = "") = if (prec == wildImport || prec == namedImport) { - ex"""imported$qualifier by ${hl"${whereFound.importInfo.toString}"}""" + ex"""imported$qualifier by ${hl"${whereFound.importInfo}"}""" } else ex"""defined$qualifier in ${hl"${whereFound.owner.toString}"}""" |