Skip to content

Commit 4285536

Browse files
committed
Refactor handling of rechecked types
- Always store new types on rechecking - Store them in a hashmap which is associated with the rechecker of the current compilation unit - After rechecking is done, the map is forgotten, unless keepTypes is true. Under keepTypes, then map is kept in an attachment of the unit's root tree. Change in nomenclature: knownType --> nuType rememberType --> setNuType hasRememberedType --> hasNuType
1 parent 47f7d14 commit 4285536

File tree

3 files changed

+105
-89
lines changed

3 files changed

+105
-89
lines changed

compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,22 @@ object CheckCaptures:
223223
checkNotUniversal.traverse(tpe.widen)
224224
end checkNotUniversalInUnboxedResult
225225

226+
trait CheckerAPI:
227+
/** Complete symbol info of a val or a def */
228+
def completeDef(tree: ValOrDefDef, sym: Symbol)(using Context): Type
229+
230+
extension [T <: Tree](tree: T)
231+
232+
/** Set new type of the tree if none was installed yet. */
233+
def setNuType(tpe: Type): Unit
234+
235+
/** The new type of the tree, or if none was installed, the original type */
236+
def nuType(using Context): Type
237+
238+
/** Was a new type installed for this tree? */
239+
def hasNuType: Boolean
240+
end CheckerAPI
241+
226242
class CheckCaptures extends Recheck, SymTransformer:
227243
thisPhase =>
228244

@@ -243,7 +259,7 @@ class CheckCaptures extends Recheck, SymTransformer:
243259

244260
val ccState1 = new CCState // Dotty problem: Rename to ccState ==> Crash in ExplicitOuter
245261

246-
class CaptureChecker(ictx: Context) extends Rechecker(ictx):
262+
class CaptureChecker(ictx: Context) extends Rechecker(ictx), CheckerAPI:
247263

248264
/** The current environment */
249265
private val rootEnv: Env = inContext(ictx):
@@ -261,10 +277,6 @@ class CheckCaptures extends Recheck, SymTransformer:
261277
*/
262278
private val todoAtPostCheck = new mutable.ListBuffer[() => Unit]
263279

264-
override def keepType(tree: Tree) =
265-
super.keepType(tree)
266-
|| tree.isInstanceOf[Try] // type of `try` needs tp be checked for * escapes
267-
268280
/** Instantiate capture set variables appearing contra-variantly to their
269281
* upper approximation.
270282
*/
@@ -286,8 +298,8 @@ class CheckCaptures extends Recheck, SymTransformer:
286298
*/
287299
private def interpolateVarsIn(tpt: Tree)(using Context): Unit =
288300
if tpt.isInstanceOf[InferredTypeTree] then
289-
interpolator().traverse(tpt.knownType)
290-
.showing(i"solved vars in ${tpt.knownType}", capt)
301+
interpolator().traverse(tpt.nuType)
302+
.showing(i"solved vars in ${tpt.nuType}", capt)
291303
for msg <- ccState.approxWarnings do
292304
report.warning(msg, tpt.srcPos)
293305
ccState.approxWarnings.clear()
@@ -501,11 +513,11 @@ class CheckCaptures extends Recheck, SymTransformer:
501513
then ("\nThis is often caused by a local capability$where\nleaking as part of its result.", fn.srcPos)
502514
else if arg.span.exists then ("", arg.srcPos)
503515
else ("", fn.srcPos)
504-
disallowRootCapabilitiesIn(arg.knownType, NoSymbol,
516+
disallowRootCapabilitiesIn(arg.nuType, NoSymbol,
505517
i"Type variable $pname of $sym", "be instantiated to", addendum, pos)
506518

507519
val param = fn.symbol.paramNamed(pname)
508-
if param.isUseParam then markFree(arg.knownType.deepCaptureSet, pos)
520+
if param.isUseParam then markFree(arg.nuType.deepCaptureSet, pos)
509521
end disallowCapInTypeArgs
510522

511523
override def recheckIdent(tree: Ident, pt: Type)(using Context): Type =
@@ -769,8 +781,8 @@ class CheckCaptures extends Recheck, SymTransformer:
769781
*/
770782
def checkContains(tree: TypeApply)(using Context): Unit = tree match
771783
case ContainsImpl(csArg, refArg) =>
772-
val cs = csArg.knownType.captureSet
773-
val ref = refArg.knownType
784+
val cs = csArg.nuType.captureSet
785+
val ref = refArg.nuType
774786
capt.println(i"check contains $cs , $ref")
775787
ref match
776788
case ref: CaptureRef if ref.isTracked =>
@@ -852,7 +864,7 @@ class CheckCaptures extends Recheck, SymTransformer:
852864
case _ =>
853865
(sym, "")
854866
disallowRootCapabilitiesIn(
855-
tree.tpt.knownType, carrier, i"Mutable $sym", "have type", addendum, sym.srcPos)
867+
tree.tpt.nuType, carrier, i"Mutable $sym", "have type", addendum, sym.srcPos)
856868
checkInferredResult(super.recheckValDef(tree, sym), tree)
857869
finally
858870
if !sym.is(Param) then
@@ -1533,7 +1545,7 @@ class CheckCaptures extends Recheck, SymTransformer:
15331545
private val setup: SetupAPI = thisPhase.prev.asInstanceOf[Setup]
15341546

15351547
override def checkUnit(unit: CompilationUnit)(using Context): Unit =
1536-
setup.setupUnit(unit.tpdTree, completeDef)
1548+
setup.setupUnit(unit.tpdTree, this)
15371549
collectCapturedMutVars.traverse(unit.tpdTree)
15381550

15391551
if ctx.settings.YccPrintSetup.value then
@@ -1676,7 +1688,7 @@ class CheckCaptures extends Recheck, SymTransformer:
16761688
traverseChildren(tp)
16771689

16781690
if tree.isInstanceOf[InferredTypeTree] then
1679-
checker.traverse(tree.knownType)
1691+
checker.traverse(tree.nuType)
16801692
end healTypeParam
16811693

16821694
/** Under the unsealed policy: Arrays are like vars, check that their element types
@@ -1716,10 +1728,10 @@ class CheckCaptures extends Recheck, SymTransformer:
17161728
check(tree)
17171729
def check(tree: Tree)(using Context) = tree match
17181730
case TypeApply(fun, args) =>
1719-
fun.knownType.widen match
1731+
fun.nuType.widen match
17201732
case tl: PolyType =>
17211733
val normArgs = args.lazyZip(tl.paramInfos).map: (arg, bounds) =>
1722-
arg.withType(arg.knownType.forceBoxStatus(
1734+
arg.withType(arg.nuType.forceBoxStatus(
17231735
bounds.hi.isBoxedCapturing | bounds.lo.isBoxedCapturing))
17241736
checkBounds(normArgs, tl)
17251737
args.lazyZip(tl.paramNames).foreach(healTypeParam(_, _, fun.symbol))
@@ -1739,7 +1751,7 @@ class CheckCaptures extends Recheck, SymTransformer:
17391751
def traverse(t: Tree)(using Context) = t match
17401752
case tree: InferredTypeTree =>
17411753
case tree: New =>
1742-
case tree: TypeTree => checkAppliedTypesIn(tree.withKnownType)
1754+
case tree: TypeTree => checkAppliedTypesIn(tree.withType(tree.nuType))
17431755
case _ => traverseChildren(t)
17441756
checkApplied.traverse(unit)
17451757
end postCheck

compiler/src/dotty/tools/dotc/cc/Setup.scala

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import printing.{Printer, Texts}, Texts.{Text, Str}
1919
import collection.mutable
2020
import CCState.*
2121
import dotty.tools.dotc.util.NoSourcePosition
22+
import CheckCaptures.CheckerAPI
2223

2324
/** Operations accessed from CheckCaptures */
2425
trait SetupAPI:
@@ -28,10 +29,9 @@ trait SetupAPI:
2829

2930
/** Setup procedure to run for each compilation unit
3031
* @param tree the typed tree of the unit to check
31-
* @param recheckDef the recheck method to run on completion of symbols with
32-
* inferred (result-) types
32+
* @param checker the capture checker which will run subsequently.
3333
*/
34-
def setupUnit(tree: Tree, recheckDef: DefRecheck)(using Context): Unit
34+
def setupUnit(tree: Tree, checker: CheckerAPI)(using Context): Unit
3535

3636
/** Symbol is a term member of a class that was not capture checked
3737
* The info of these symbols is made fluid.
@@ -378,15 +378,6 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
378378
tp2
379379
end transformExplicitType
380380

381-
/** Transform type of tree, and remember the transformed type as the type the tree */
382-
private def transformTT(tree: TypeTree, boxed: Boolean)(using Context): Unit =
383-
if !tree.hasRememberedType then
384-
val transformed =
385-
if tree.isInferred
386-
then transformInferredType(tree.tpe)
387-
else transformExplicitType(tree.tpe, tptToCheck = tree)
388-
tree.rememberType(if boxed then box(transformed) else transformed)
389-
390381
/** Substitute parameter symbols in `from` to paramRefs in corresponding
391382
* method or poly types `to`. We use a single BiTypeMap to do everything.
392383
* @param from a list of lists of type or term parameter symbols of a curried method
@@ -436,7 +427,17 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
436427
atPhase(thisPhase.next)(sym.info)
437428

438429
/** A traverser that adds knownTypes and updates symbol infos */
439-
def setupTraverser(recheckDef: DefRecheck) = new TreeTraverserWithPreciseImportContexts:
430+
def setupTraverser(checker: CheckerAPI) = new TreeTraverserWithPreciseImportContexts:
431+
import checker.*
432+
433+
/** Transform type of tree, and remember the transformed type as the type the tree */
434+
private def transformTT(tree: TypeTree, boxed: Boolean)(using Context): Unit =
435+
if !tree.hasNuType then
436+
val transformed =
437+
if tree.isInferred
438+
then transformInferredType(tree.tpe)
439+
else transformExplicitType(tree.tpe, tptToCheck = tree)
440+
tree.setNuType(if boxed then box(transformed) else transformed)
440441

441442
/** Transform the type of a val or var or the result type of a def */
442443
def transformResultType(tpt: TypeTree, sym: Symbol)(using Context): Unit =
@@ -464,7 +465,7 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
464465
traverse(parent)
465466
case _ =>
466467
traverseChildren(tp)
467-
addDescription.traverse(tpt.knownType)
468+
addDescription.traverse(tpt.nuType)
468469
end transformResultType
469470

470471
def traverse(tree: Tree)(using Context): Unit =
@@ -504,7 +505,7 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
504505

505506
case tree @ SeqLiteral(elems, tpt: TypeTree) =>
506507
traverse(elems)
507-
tpt.rememberType(box(transformInferredType(tpt.tpe)))
508+
tpt.setNuType(box(transformInferredType(tpt.tpe)))
508509

509510
case tree: Block =>
510511
inNestedLevel(traverseChildren(tree))
@@ -537,22 +538,22 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
537538
// with special treatment for constructors.
538539
def localReturnType =
539540
if sym.isConstructor then constrReturnType(sym.info, sym.paramSymss)
540-
else tree.tpt.knownType
541+
else tree.tpt.nuType
541542

542543
// A test whether parameter signature might change. This returns true if one of
543-
// the parameters has a remembered type. The idea here is that we store a remembered
544+
// the parameters has a new type installee. The idea here is that we store a new
544545
// type only if the transformed type is different from the original.
545546
def paramSignatureChanges = tree.match
546547
case tree: DefDef =>
547548
tree.paramss.nestedExists:
548-
case param: ValDef => param.tpt.hasRememberedType
549-
case param: TypeDef => param.rhs.hasRememberedType
549+
case param: ValDef => param.tpt.hasNuType
550+
case param: TypeDef => param.rhs.hasNuType
550551
case _ => false
551552

552553
// A symbol's signature changes if some of its parameter types or its result type
553554
// have a new type installed here (meaning hasRememberedType is true)
554555
def signatureChanges =
555-
tree.tpt.hasRememberedType && !sym.isConstructor || paramSignatureChanges
556+
tree.tpt.hasNuType && !sym.isConstructor || paramSignatureChanges
556557

557558
// Replace an existing symbol info with inferred types where capture sets of
558559
// TypeParamRefs and TermParamRefs are put in correspondence by BiTypeMaps with the
@@ -616,7 +617,7 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
616617
capt.println(i"forcing $sym, printing = ${ctx.mode.is(Mode.Printing)}")
617618
//if ctx.mode.is(Mode.Printing) then new Error().printStackTrace()
618619
denot.info = newInfo
619-
recheckDef(tree, sym)
620+
completeDef(tree, sym)
620621
updateInfo(sym, updatedInfo)
621622

622623
case tree: Bind =>
@@ -833,8 +834,8 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
833834
/** Run setup on a compilation unit with given `tree`.
834835
* @param recheckDef the function to run for completing a val or def
835836
*/
836-
def setupUnit(tree: Tree, recheckDef: DefRecheck)(using Context): Unit =
837-
setupTraverser(recheckDef).traverse(tree)(using ctx.withPhase(thisPhase))
837+
def setupUnit(tree: Tree, checker: CheckerAPI)(using Context): Unit =
838+
setupTraverser(checker).traverse(tree)(using ctx.withPhase(thisPhase))
838839

839840
// ------ Checks to run after main capture checking --------------------------
840841

0 commit comments

Comments
 (0)