Skip to content

Commit 3552326

Browse files
authored
Merge pull request #1974 from dotty-staging/fix/ctx-capture
Avoid accidental captures of Context
2 parents 6189ffe + 7c4a9ec commit 3552326

File tree

14 files changed

+88
-60
lines changed

14 files changed

+88
-60
lines changed

compiler/src/dotty/tools/dotc/core/Annotations.scala

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -117,11 +117,17 @@ object Annotations {
117117
}
118118

119119
/** Create an annotation where the symbol and the tree are computed lazily. */
120-
def deferredSymAndTree(sym: => Symbol, treeFn: Context => Tree)(implicit ctx: Context): Annotation =
120+
def deferredSymAndTree(symf: Context => Symbol, treeFn: Context => Tree)(implicit ctx: Context): Annotation =
121121
new LazyAnnotation {
122-
lazy val symf = sym
123-
124-
override def symbol(implicit ctx: Context): Symbol = symf
122+
private[this] var mySym: Symbol = _
123+
124+
override def symbol(implicit ctx: Context): Symbol = {
125+
if (mySym == null || mySym.defRunId != ctx.runId) {
126+
mySym = symf(ctx)
127+
assert(mySym != null)
128+
}
129+
mySym
130+
}
125131
def complete(implicit ctx: Context) = treeFn(ctx)
126132
}
127133

compiler/src/dotty/tools/dotc/core/TypeOps.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -401,12 +401,12 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
401401
def forwardRefs(from: Symbol, to: Type, prefs: List[TypeRef]) = to match {
402402
case to @ TypeBounds(lo1, hi1) if lo1 eq hi1 =>
403403
for (pref <- prefs) {
404-
def forward(): Unit =
404+
def forward()(implicit ctx: Context): Unit =
405405
for (argSym <- pref.decls)
406406
if (argSym is BaseTypeArg)
407407
forwardRef(argSym, from, to, cls, decls)
408408
pref.info match {
409-
case info: TempClassInfo => info.addSuspension(forward)
409+
case info: TempClassInfo => info.addSuspension(implicit ctx => forward())
410410
case _ => forward()
411411
}
412412
}

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3088,14 +3088,14 @@ object Types {
30883088
* be no longer temporary. These actions will be performed once `cls` gets a real
30893089
* ClassInfo.
30903090
*/
3091-
private var suspensions: List[() => Unit] = Nil
3091+
private var suspensions: List[Context => Unit] = Nil
30923092

3093-
def addSuspension(suspension: () => Unit): Unit = suspensions ::= suspension
3093+
def addSuspension(suspension: Context => Unit): Unit = suspensions ::= suspension
30943094

30953095
/** Install classinfo with known parents in `denot` and resume all suspensions */
30963096
def finalize(denot: SymDenotation, parents: List[TypeRef])(implicit ctx: Context) = {
30973097
denot.info = derivedClassInfo(classParents = parents)
3098-
suspensions.foreach(_())
3098+
suspensions.foreach(_(ctx))
30993099
}
31003100
}
31013101

compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -806,7 +806,7 @@ class ClassfileParser(
806806
def classSymbol(externalName: Name)(implicit ctx: Context): Symbol = {
807807
/** Return the symbol of `innerName`, having the given `externalName`. */
808808
def innerSymbol(externalName: Name, innerName: Name, static: Boolean): Symbol = {
809-
def getMember(sym: Symbol, name: Name): Symbol =
809+
def getMember(sym: Symbol, name: Name)(implicit ctx: Context): Symbol =
810810
if (static)
811811
if (sym == classRoot.symbol) staticScope.lookup(name)
812812
else sym.companionModule.info.member(name).symbol

compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -554,7 +554,9 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle
554554
val end = readEnd()
555555
val tp = readType()
556556
val lazyAnnotTree = readLater(end, rdr => ctx => rdr.readTerm()(ctx))
557-
annots += Annotation.deferredSymAndTree(tp.typeSymbol, _ => lazyAnnotTree.complete)
557+
annots += Annotation.deferredSymAndTree(
558+
implicit ctx => tp.typeSymbol,
559+
implicit ctx => lazyAnnotTree.complete)
558560
case tag =>
559561
assert(false, s"illegal modifier tag $tag at $currentAddr, end = $end")
560562
}
@@ -769,7 +771,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpickle
769771
cls.setApplicableFlags(fork.indexStats(end))
770772
val constr = readIndexedDef().asInstanceOf[DefDef]
771773

772-
def mergeTypeParamsAndAliases(tparams: List[TypeDef], stats: List[Tree]): (List[Tree], List[Tree]) =
774+
def mergeTypeParamsAndAliases(tparams: List[TypeDef], stats: List[Tree])(implicit ctx: Context): (List[Tree], List[Tree]) =
773775
(tparams, stats) match {
774776
case (tparam :: tparams1, (alias: TypeDef) :: stats1)
775777
if tparam.name == alias.name.expandedName(cls) =>

compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -932,9 +932,10 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
932932
protected def deferredAnnot(end: Int)(implicit ctx: Context): Annotation = {
933933
val start = readIndex
934934
val atp = readTypeRef()
935+
val phase = ctx.phase
935936
Annotation.deferred(
936-
atp.typeSymbol, implicit ctx1 =>
937-
atReadPos(start, () => readAnnotationContents(end)(ctx1.withPhase(ctx.phase))))
937+
atp.typeSymbol, implicit ctx =>
938+
atReadPos(start, () => readAnnotationContents(end)(ctx.withPhase(phase))))
938939
}
939940

940941
/* Read an abstract syntax tree */

compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import Contexts.Context, Scopes.Scope, Denotations.Denotation, Annotations.Annot
77
import StdNames.{nme, tpnme}
88
import ast.Trees._, ast._
99
import typer.Implicits._
10+
import typer.ImportInfo
1011
import config.Config
1112
import java.lang.Integer.toOctalString
1213
import config.Config.summarizeDepth
@@ -503,6 +504,17 @@ class PlainPrinter(_ctx: Context) extends Printer {
503504
"?Unknown Implicit Result?"
504505
}
505506

507+
def toText(importInfo: ImportInfo): Text = {
508+
val siteStr = importInfo.site.show
509+
val exprStr = if (siteStr endsWith ".type") siteStr dropRight 5 else siteStr
510+
val selectorStr = importInfo.selectors match {
511+
case Ident(name) :: Nil => name.show
512+
case _ => "{...}"
513+
}
514+
s"import $exprStr.$selectorStr"
515+
}
516+
517+
506518
private var maxSummarized = Int.MaxValue
507519

508520
def summarized[T](depth: Int)(op: => T): T = {

compiler/src/dotty/tools/dotc/printing/Printer.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import Texts._, ast.Trees._
66
import Types.Type, Symbols.Symbol, Contexts.Context, Scopes.Scope, Constants.Constant,
77
Names.Name, Denotations._, Annotations.Annotation
88
import typer.Implicits.SearchResult
9+
import typer.ImportInfo
910

1011
/** The base class of all printers
1112
*/
@@ -98,6 +99,9 @@ abstract class Printer {
9899
/** Textual representation of implicit search result */
99100
def toText(result: SearchResult): Text
100101

102+
/** Textual representation of info relating to an import clause */
103+
def toText(result: ImportInfo): Text
104+
101105
/** Perform string or text-producing operation `op` so that only a
102106
* summarized text with given recursion depth is shown
103107
*/

compiler/src/dotty/tools/dotc/transform/TailRec.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ class TailRec extends MiniPhaseTransform with DenotTransformer with FullParamete
119119
// now this speculatively transforms tree and throws away result in many cases
120120
val rhsSemiTransformed = {
121121
val transformer = new TailRecElimination(origMeth, dd.tparams, owner, thisTpe, mandatory, label, abstractOverClass = defIsTopLevel)
122-
val rhs = atGroupEnd(transformer.transform(dd.rhs)(_))
122+
val rhs = atGroupEnd(implicit ctx => transformer.transform(dd.rhs))
123123
rewrote = transformer.rewrote
124124
rhs
125125
}

compiler/src/dotty/tools/dotc/typer/Applications.scala

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -683,7 +683,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
683683
*
684684
* { val xs = es; e' = e' + args }
685685
*/
686-
def typedOpAssign: Tree = track("typedOpAssign") {
686+
def typedOpAssign(implicit ctx: Context): Tree = track("typedOpAssign") {
687687
val Apply(Select(lhs, name), rhss) = tree
688688
val lhs1 = typedExpr(lhs)
689689
val liftedDefs = new mutable.ListBuffer[Tree]
@@ -805,16 +805,16 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
805805
* whereas overloaded variants need to have a conforming variant.
806806
*/
807807
def trySelectUnapply(qual: untpd.Tree)(fallBack: Tree => Tree): Tree = {
808-
val genericProto = new UnapplyFunProto(WildcardType, this)
809-
def specificProto = new UnapplyFunProto(selType, this)
810808
// try first for non-overloaded, then for overloaded ocurrences
811809
def tryWithName(name: TermName)(fallBack: Tree => Tree)(implicit ctx: Context): Tree =
812-
tryEither {
813-
implicit ctx => typedExpr(untpd.Select(qual, name), specificProto)
810+
tryEither { implicit ctx =>
811+
val specificProto = new UnapplyFunProto(selType, this)
812+
typedExpr(untpd.Select(qual, name), specificProto)
814813
} {
815814
(sel, _) =>
816-
tryEither {
817-
implicit ctx => typedExpr(untpd.Select(qual, name), genericProto)
815+
tryEither { implicit ctx =>
816+
val genericProto = new UnapplyFunProto(WildcardType, this)
817+
typedExpr(untpd.Select(qual, name), genericProto)
818818
} {
819819
(_, _) => fallBack(sel)
820820
}

compiler/src/dotty/tools/dotc/typer/ImportInfo.scala

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package typer
55
import ast.{tpd, untpd}
66
import ast.Trees._
77
import core._
8+
import printing.{Printer, Showable}
89
import util.SimpleMap
910
import Symbols._, Names._, Denotations._, Types._, Contexts._, StdNames._, Flags._
1011
import Decorators.StringInterpolators
@@ -13,9 +14,9 @@ object ImportInfo {
1314
/** The import info for a root import from given symbol `sym` */
1415
def rootImport(refFn: () => TermRef)(implicit ctx: Context) = {
1516
val selectors = untpd.Ident(nme.WILDCARD) :: Nil
16-
def expr = tpd.Ident(refFn())
17-
def imp = tpd.Import(expr, selectors)
18-
new ImportInfo(imp.symbol, selectors, None, isRootImport = true)
17+
def expr(implicit ctx: Context) = tpd.Ident(refFn())
18+
def imp(implicit ctx: Context) = tpd.Import(expr, selectors)
19+
new ImportInfo(implicit ctx => imp.symbol, selectors, None, isRootImport = true)
1920
}
2021
}
2122

@@ -27,14 +28,14 @@ object ImportInfo {
2728
* @param isRootImport true if this is one of the implicit imports of scala, java.lang,
2829
* scala.Predef or dotty.DottyPredef in the start context, false otherwise.
2930
*/
30-
class ImportInfo(symf: => Symbol, val selectors: List[untpd.Tree],
31-
symNameOpt: Option[TermName], val isRootImport: Boolean = false)(implicit ctx: Context) {
31+
class ImportInfo(symf: Context => Symbol, val selectors: List[untpd.Tree],
32+
symNameOpt: Option[TermName], val isRootImport: Boolean = false) extends Showable {
3233

3334
// Dotty deviation: we cannot use a lazy val here for the same reason
3435
// that we cannot use one for `DottyPredefModuleRef`.
35-
def sym = {
36+
def sym(implicit ctx: Context) = {
3637
if (mySym == null) {
37-
mySym = symf
38+
mySym = symf(ctx)
3839
assert(mySym != null)
3940
}
4041
mySym
@@ -91,7 +92,7 @@ class ImportInfo(symf: => Symbol, val selectors: List[untpd.Tree],
9192
}
9293

9394
/** The implicit references imported by this import clause */
94-
def importedImplicits: List[TermRef] = {
95+
def importedImplicits(implicit ctx: Context): List[TermRef] = {
9596
val pre = site
9697
if (isWildcardImport) {
9798
val refs = pre.implicitMembers
@@ -115,23 +116,21 @@ class ImportInfo(symf: => Symbol, val selectors: List[untpd.Tree],
115116
* override import Predef.{any2stringAdd => _, StringAdd => _, _} // disables String +
116117
* override import java.lang.{} // disables all imports
117118
*/
118-
lazy val unimported: Symbol = {
119-
lazy val sym = site.termSymbol
120-
def maybeShadowsRoot = symNameOpt match {
121-
case Some(symName) => defn.ShadowableImportNames.contains(symName)
122-
case None => false
119+
def unimported(implicit ctx: Context): Symbol = {
120+
if (myUnimported == null) {
121+
lazy val sym = site.termSymbol
122+
def maybeShadowsRoot = symNameOpt match {
123+
case Some(symName) => defn.ShadowableImportNames.contains(symName)
124+
case None => false
125+
}
126+
myUnimported =
127+
if (maybeShadowsRoot && defn.RootImportTypes.exists(_.symbol == sym)) sym
128+
else NoSymbol
129+
assert(myUnimported != null)
123130
}
124-
if (maybeShadowsRoot && defn.RootImportTypes.exists(_.symbol == sym)) sym
125-
else NoSymbol
131+
myUnimported
126132
}
133+
private[this] var myUnimported: Symbol = _
127134

128-
override def toString = {
129-
val siteStr = site.show
130-
val exprStr = if (siteStr endsWith ".type") siteStr dropRight 5 else siteStr
131-
val selectorStr = selectors match {
132-
case Ident(name) :: Nil => name.show
133-
case _ => "{...}"
134-
}
135-
i"import $exprStr.$selectorStr"
136-
}
135+
def toText(printer: Printer) = printer.toText(this)
137136
}

compiler/src/dotty/tools/dotc/typer/Namer.scala

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import language.implicitConversions
2424
import reporting.diagnostic.messages._
2525

2626
trait NamerContextOps { this: Context =>
27+
import NamerContextOps._
2728

2829
/** Enter symbol into current class, if current class is owner of current context,
2930
* or into current scope, if not. Should always be called instead of scope.enter
@@ -119,22 +120,25 @@ trait NamerContextOps { this: Context =>
119120
else monotpe
120121
}
121122

122-
/** Find moduleClass/sourceModule in effective scope */
123-
private def findModuleBuddy(name: Name)(implicit ctx: Context) = {
124-
val scope = effectiveScope
125-
val it = scope.lookupAll(name).filter(_ is Module)
126-
assert(it.hasNext, s"no companion $name in $scope")
127-
it.next
128-
}
129-
130123
/** Add moduleClass or sourceModule functionality to completer
131124
* for a module or module class
132125
*/
133-
def adjustModuleCompleter(completer: LazyType, name: Name) =
126+
def adjustModuleCompleter(completer: LazyType, name: Name) = {
127+
val scope = this.effectiveScope
134128
if (name.isTermName)
135-
completer withModuleClass (_ => findModuleBuddy(name.moduleClassName))
129+
completer withModuleClass (implicit ctx => findModuleBuddy(name.moduleClassName, scope))
136130
else
137-
completer withSourceModule (_ => findModuleBuddy(name.sourceModuleName))
131+
completer withSourceModule (implicit ctx => findModuleBuddy(name.sourceModuleName, scope))
132+
}
133+
}
134+
135+
object NamerContextOps {
136+
/** Find moduleClass/sourceModule in effective scope */
137+
private def findModuleBuddy(name: Name, scope: Scope)(implicit ctx: Context) = {
138+
val it = scope.lookupAll(name).filter(_ is Module)
139+
assert(it.hasNext, s"no companion $name in $scope")
140+
it.next
141+
}
138142
}
139143

140144
/** This class creates symbols from definitions and imports and gives them
@@ -378,7 +382,7 @@ class Namer { typer: Typer =>
378382
case ref: RefTree => Some(ref.name.asTermName)
379383
case _ => None
380384
}
381-
ctx.fresh.setImportInfo(new ImportInfo(sym, imp.selectors, impNameOpt))
385+
ctx.fresh.setImportInfo(new ImportInfo(implicit ctx => sym, imp.selectors, impNameOpt))
382386
}
383387

384388
/** A new context for the interior of a class */

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
145145
*/
146146
def bindingString(prec: Int, whereFound: Context, qualifier: String = "") =
147147
if (prec == wildImport || prec == namedImport) {
148-
ex"""imported$qualifier by ${hl"${whereFound.importInfo.toString}"}"""
148+
ex"""imported$qualifier by ${hl"${whereFound.importInfo}"}"""
149149
} else
150150
ex"""defined$qualifier in ${hl"${whereFound.owner.toString}"}"""
151151

tests/repl/imports.check

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ scala> buf += xs
1111
11 |buf += xs
1212
| ^^
1313
| found: scala.collection.immutable.List[Int](o.xs)
14-
| required: String
14+
| required: Int
1515
|
1616
scala> buf ++= xs
1717
val res1: scala.collection.mutable.ListBuffer[Int] = ListBuffer(1, 2, 3)

0 commit comments

Comments
 (0)