Skip to content

Commit 686cdc7

Browse files
committed
New helper method: withContext
Prefer this over defining contexts locally. It's less sensitive to accidental recursions. Rename withContext -> withCompilerContext in compilerSupport
1 parent ebea9c2 commit 686cdc7

File tree

9 files changed

+39
-38
lines changed

9 files changed

+39
-38
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ object Contexts {
5252
/** The current context */
5353
def ctx(using ctx: Context): Context = ctx
5454

55+
/** Run `op` with given context */
56+
inline def withContext[T](c: Context)(inline op: Context ?=> T): T =
57+
op(using c)
58+
5559
/** A context is passed basically everywhere in dotc.
5660
* This is convenient but carries the risk of captured contexts in
5761
* objects that turn into space leaks. To combat this risk, here are some

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

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -99,21 +99,20 @@ object ContextFunctionResults:
9999
* Erased parameters are ignored; they contribute nothing to the
100100
* parameter count.
101101
*/
102-
def contextFunctionResultTypeCovering(meth: Symbol, paramCount: Int)(using preCtx: Context) =
103-
given Context = preCtx.withPhase(preCtx.erasurePhase)
104-
105-
// Recursive instances return pairs of context types and the
106-
// # of parameters they represent.
107-
def missingCR(tp: Type, crCount: Int): (Type, Int) =
108-
if crCount == 0 then (tp, 0)
109-
else
110-
val defn.ContextFunctionType(formals, resTpe, isErased): @unchecked = tp
111-
val result @ (rt, nparams) = missingCR(resTpe, crCount - 1)
112-
assert(nparams <= paramCount)
113-
if nparams == paramCount || isErased then result
114-
else (tp, nparams + formals.length)
115-
missingCR(meth.info.finalResultType, contextResultCount(meth))._1
116-
end contextFunctionResultTypeCovering
102+
def contextFunctionResultTypeCovering(meth: Symbol, paramCount: Int)(using Context) =
103+
withContext(ctx.withPhase(ctx.erasurePhase)) {
104+
// Recursive instances return pairs of context types and the
105+
// # of parameters they represent.
106+
def missingCR(tp: Type, crCount: Int): (Type, Int) =
107+
if crCount == 0 then (tp, 0)
108+
else
109+
val defn.ContextFunctionType(formals, resTpe, isErased): @unchecked = tp
110+
val result @ (rt, nparams) = missingCR(resTpe, crCount - 1)
111+
assert(nparams <= paramCount)
112+
if nparams == paramCount || isErased then result
113+
else (tp, nparams + formals.length)
114+
missingCR(meth.info.finalResultType, contextResultCount(meth))._1
115+
}
117116

118117
/** Should selection `tree` be eliminated since it refers to an `apply`
119118
* node of a context function type whose parameters will end up being

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -453,9 +453,8 @@ object Erasure {
453453
else implType.derivedLambdaType(paramInfos = samParamTypes)
454454
else implType.derivedLambdaType(resType = samResultType)
455455
val bridge = ctx.newSymbol(ctx.owner, AdaptedClosureName(meth.symbol.name.asTermName), Flags.Synthetic | Flags.Method, bridgeType)
456-
val bridgeCtx = ctx.withOwner(bridge)
457-
Closure(bridge, bridgeParamss => {
458-
given Context = bridgeCtx
456+
Closure(bridge, bridgeParamss =>
457+
withContext(ctx.withOwner(bridge)) {
459458
val List(bridgeParams) = bridgeParamss
460459
assert(ctx.typer.isInstanceOf[Erasure.Typer])
461460
val rhs = Apply(meth, bridgeParams.lazyZip(implParamTypes).map(ctx.typer.adapt(_, _)))

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

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,18 +37,18 @@ object Splicer {
3737
*
3838
* See: `Staging`
3939
*/
40-
def splice(tree: Tree, pos: SourcePosition, classLoader: ClassLoader)(using ctx: Context): Tree = tree match {
40+
def splice(tree: Tree, pos: SourcePosition, classLoader: ClassLoader)(using Context): Tree = tree match {
4141
case Quoted(quotedTree) => quotedTree
4242
case _ =>
4343
val interpreter = new Interpreter(pos, classLoader)
4444
val macroOwner = ctx.newSymbol(ctx.owner, nme.MACROkw, Macro | Synthetic, defn.AnyType, coord = tree.span)
45-
try {
46-
given Context = ctx.withOwner(macroOwner)
47-
// Some parts of the macro are evaluated during the unpickling performed in quotedExprToTree
48-
val interpretedExpr = interpreter.interpret[scala.quoted.QuoteContext => scala.quoted.Expr[Any]](tree)
49-
val interpretedTree = interpretedExpr.fold(tree)(macroClosure => PickledQuotes.quotedExprToTree(macroClosure(QuoteContext())))
50-
checkEscapedVariables(interpretedTree, macroOwner).changeOwner(macroOwner, ctx.owner)
51-
}
45+
try
46+
withContext(ctx.withOwner(macroOwner)) {
47+
// Some parts of the macro are evaluated during the unpickling performed in quotedExprToTree
48+
val interpretedExpr = interpreter.interpret[scala.quoted.QuoteContext => scala.quoted.Expr[Any]](tree)
49+
val interpretedTree = interpretedExpr.fold(tree)(macroClosure => PickledQuotes.quotedExprToTree(macroClosure(QuoteContext())))
50+
checkEscapedVariables(interpretedTree, macroOwner)
51+
}.changeOwner(macroOwner, ctx.owner)
5252
catch {
5353
case ex: CompilationUnit.SuspendException =>
5454
throw ex
@@ -70,7 +70,7 @@ object Splicer {
7070
}
7171

7272
/** Checks that no symbol that whas generated within the macro expansion has an out of scope reference */
73-
def checkEscapedVariables(tree: Tree, expansionOwner: Symbol)(using ctx: Context): tree.type =
73+
def checkEscapedVariables(tree: Tree, expansionOwner: Symbol)(using Context): tree.type =
7474
new TreeTraverser {
7575
private[this] var locals = Set.empty[Symbol]
7676
private def markSymbol(sym: Symbol)(implicit ctx: Context): Unit =
@@ -79,7 +79,7 @@ object Splicer {
7979
case tree: DefTree => markSymbol(tree.symbol)
8080
case _ =>
8181
}
82-
def traverse(tree: Tree)(using ctx: Context): Unit =
82+
def traverse(tree: Tree)(using Context): Unit =
8383
def traverseOver(lastEntered: Set[Symbol]) =
8484
try traverseChildren(tree)
8585
finally locals = lastEntered
@@ -98,7 +98,7 @@ object Splicer {
9898
case _ =>
9999
markDef(tree)
100100
traverseChildren(tree)
101-
private def isEscapedVariable(sym: Symbol)(using ctx: Context): Boolean =
101+
private def isEscapedVariable(sym: Symbol)(using Context): Boolean =
102102
sym.exists && !sym.is(Package)
103103
&& sym.owner.ownersIterator.exists(x =>
104104
x == expansionOwner || // symbol was generated within this macro expansion
@@ -412,7 +412,7 @@ object Splicer {
412412
}
413413

414414
private object MissingClassDefinedInCurrentRun {
415-
def unapply(targetException: NoClassDefFoundError)(using ctx: Context): Option[Symbol] = {
415+
def unapply(targetException: NoClassDefFoundError)(using Context): Option[Symbol] = {
416416
val className = targetException.getMessage
417417
if (className eq null) None
418418
else {

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,7 @@ trait ImportSuggestions:
149149
*/
150150
def shallowTest(ref: TermRef): Boolean =
151151
System.currentTimeMillis < deadLine
152-
&& {
153-
given Context = ctx.fresh.setExploreTyperState()
152+
&& withContext(ctx.fresh.setExploreTyperState()) {
154153
def test(pt: Type): Boolean = pt match
155154
case ViewProto(argType, OrType(rt1, rt2)) =>
156155
// Union types do not constrain results, since comparison with a union

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import Constants._
1313
import StagingContext._
1414
import StdNames._
1515
import transform.SymUtils._
16-
import Contexts.Context
16+
import Contexts.{Context, withContext, ctx}
1717
import Names.{Name, TermName}
1818
import NameKinds.{InlineAccessorName, InlineBinderName, InlineScrutineeName, BodyRetainerName}
1919
import ProtoTypes.selectionProto
@@ -1341,8 +1341,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
13411341
ctx.echo(i"suspension triggered by macro call to ${sym.showLocated} in ${sym.associatedFile}", call.sourcePos)
13421342
ctx.compilationUnit.suspend() // this throws a SuspendException
13431343

1344-
val evaluatedSplice = {
1345-
given Context = tastyreflect.MacroExpansion.context(inlinedFrom)(using ctx)
1344+
val evaluatedSplice = withContext(tastyreflect.MacroExpansion.context(inlinedFrom)) {
13461345
Splicer.splice(body, inlinedFrom.sourcePos, MacroClassLoader.fromContext)
13471346
}
13481347
val inlinedNormailizer = new TreeMap {

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1068,13 +1068,14 @@ class Typer extends Namer
10681068
case untpd.TypedSplice(expr1) =>
10691069
expr1.tpe
10701070
case _ =>
1071+
val curCtx = ctx
10711072
given nestedCtx as Context = ctx.fresh.setNewTyperState()
10721073
val protoArgs = args map (_ withType WildcardType)
10731074
val callProto = FunProto(protoArgs, WildcardType)(this, app.isUsingApply)
10741075
val expr1 = typedExpr(expr, callProto)
10751076
if nestedCtx.reporter.hasErrors then NoType
10761077
else
1077-
given Context = ctx
1078+
given Context = curCtx
10781079
nestedCtx.typerState.commit()
10791080
fnBody = cpy.Apply(fnBody)(untpd.TypedSplice(expr1), args)
10801081
expr1.tpe

compiler/test/dotty/tools/AnnotationsTests.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class AnnotationsTest:
1919
"public @interface Annot { String[] values() default {}; }"),
2020
VirtualJavaSource("A.java",
2121
"@Annot(values = {}) public class A {}")) { javaOutputDir =>
22-
withContext(javaOutputDir.toString + File.pathSeparator + TestConfiguration.basicClasspath) {
22+
withCompilerContext(javaOutputDir.toString + File.pathSeparator + TestConfiguration.basicClasspath) {
2323
(using ctx: Context) =>
2424
val defn = ctx.definitions
2525
val cls = ctx.requiredClass("A")

compiler/test/dotty/tools/compilerSupport.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import dotc.core.Comments.{ContextDoc, ContextDocstrings}
1313
/** Initialize a compiler context with the given classpath and
1414
* pass it to `op`.
1515
*/
16-
def withContext[T](classpath: String)(op: Context ?=> T): T =
16+
def withCompilerContext[T](classpath: String)(op: Context ?=> T): T =
1717
val compiler = Compiler()
1818
val run = compiler.newRun(initCtx(classpath))
1919
run.compileUnits(Nil) // Initialize phases

0 commit comments

Comments
 (0)