Skip to content

Commit 4b37a9a

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 2a3cab5 commit 4b37a9a

File tree

3 files changed

+106
-90
lines changed

3 files changed

+106
-90
lines changed

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

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

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

@@ -244,7 +260,7 @@ class CheckCaptures extends Recheck, SymTransformer:
244260

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

247-
class CaptureChecker(ictx: Context) extends Rechecker(ictx):
263+
class CaptureChecker(ictx: Context) extends Rechecker(ictx), CheckerAPI:
248264

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

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

509521
val param = fn.symbol.paramNamed(pname)
510-
if param.isUseParam then markFree(arg.knownType.deepCaptureSet, pos)
522+
if param.isUseParam then markFree(arg.nuType.deepCaptureSet, pos)
511523
end disallowCapInTypeArgs
512524

513525
override def recheckIdent(tree: Ident, pt: Type)(using Context): Type =
@@ -788,8 +800,8 @@ class CheckCaptures extends Recheck, SymTransformer:
788800
*/
789801
def checkContains(tree: TypeApply)(using Context): Unit = tree match
790802
case ContainsImpl(csArg, refArg) =>
791-
val cs = csArg.knownType.captureSet
792-
val ref = refArg.knownType
803+
val cs = csArg.nuType.captureSet
804+
val ref = refArg.nuType
793805
capt.println(i"check contains $cs , $ref")
794806
ref match
795807
case ref: CaptureRef if ref.isTracked =>
@@ -871,7 +883,7 @@ class CheckCaptures extends Recheck, SymTransformer:
871883
case _ =>
872884
(sym, "")
873885
disallowRootCapabilitiesIn(
874-
tree.tpt.knownType, carrier, i"Mutable $sym", "have type", addendum, sym.srcPos)
886+
tree.tpt.nuType, carrier, i"Mutable $sym", "have type", addendum, sym.srcPos)
875887
checkInferredResult(super.recheckValDef(tree, sym), tree)
876888
finally
877889
if !sym.is(Param) then
@@ -1572,7 +1584,7 @@ class CheckCaptures extends Recheck, SymTransformer:
15721584
private val setup: SetupAPI = thisPhase.prev.asInstanceOf[Setup]
15731585

15741586
override def checkUnit(unit: CompilationUnit)(using Context): Unit =
1575-
setup.setupUnit(unit.tpdTree, completeDef)
1587+
setup.setupUnit(unit.tpdTree, this)
15761588
collectCapturedMutVars.traverse(unit.tpdTree)
15771589

15781590
if ctx.settings.YccPrintSetup.value then
@@ -1715,7 +1727,7 @@ class CheckCaptures extends Recheck, SymTransformer:
17151727
traverseChildren(tp)
17161728

17171729
if tree.isInstanceOf[InferredTypeTree] then
1718-
checker.traverse(tree.knownType)
1730+
checker.traverse(tree.nuType)
17191731
end healTypeParam
17201732

17211733
/** Under the unsealed policy: Arrays are like vars, check that their element types
@@ -1755,10 +1767,10 @@ class CheckCaptures extends Recheck, SymTransformer:
17551767
check(tree)
17561768
def check(tree: Tree)(using Context) = tree match
17571769
case TypeApply(fun, args) =>
1758-
fun.knownType.widen match
1770+
fun.nuType.widen match
17591771
case tl: PolyType =>
17601772
val normArgs = args.lazyZip(tl.paramInfos).map: (arg, bounds) =>
1761-
arg.withType(arg.knownType.forceBoxStatus(
1773+
arg.withType(arg.nuType.forceBoxStatus(
17621774
bounds.hi.isBoxedCapturing | bounds.lo.isBoxedCapturing))
17631775
checkBounds(normArgs, tl)
17641776
args.lazyZip(tl.paramNames).foreach(healTypeParam(_, _, fun.symbol))
@@ -1778,7 +1790,7 @@ class CheckCaptures extends Recheck, SymTransformer:
17781790
def traverse(t: Tree)(using Context) = t match
17791791
case tree: InferredTypeTree =>
17801792
case tree: New =>
1781-
case tree: TypeTree => checkAppliedTypesIn(tree.withKnownType)
1793+
case tree: TypeTree => checkAppliedTypesIn(tree.withType(tree.nuType))
17821794
case _ => traverseChildren(t)
17831795
checkApplied.traverse(unit)
17841796
end postCheck

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

Lines changed: 25 additions & 24 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,16 +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, sym: Symbol, 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(
389-
if boxed then box(transformed) else Fresh.fromCap(transformed, sym))
390-
391381
/** Substitute parameter symbols in `from` to paramRefs in corresponding
392382
* method or poly types `to`. We use a single BiTypeMap to do everything.
393383
* @param from a list of lists of type or term parameter symbols of a curried method
@@ -437,7 +427,18 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
437427
atPhase(thisPhase.next)(sym.info)
438428

439429
/** A traverser that adds knownTypes and updates symbol infos */
440-
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, sym: Symbol, 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(
441+
if boxed then box(transformed) else Fresh.fromCap(transformed, sym))
441442

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

471472
def traverse(tree: Tree)(using Context): Unit =
@@ -505,7 +506,7 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
505506

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

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

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

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

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

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

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

0 commit comments

Comments
 (0)