Skip to content

Commit 0cbf315

Browse files
committed
Keep track of provenance of capturing types
1 parent 27154fa commit 0cbf315

File tree

6 files changed

+46
-20
lines changed

6 files changed

+46
-20
lines changed

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,30 @@ case class CaptureAnnotation(refs: CaptureSet, boxed: Boolean)(cls: Symbol) exte
2525
import CaptureAnnotation.*
2626
import tpd.*
2727

28+
private var myOrigins: Set[AnnotatedType] | Null = null
29+
30+
def origins: Set[AnnotatedType] =
31+
if myOrigins == null then myOrigins = Set()
32+
myOrigins.nn
33+
34+
def withOrigins(origins: Set[AnnotatedType]): CaptureAnnotation =
35+
if myOrigins == null then
36+
myOrigins = origins
37+
this
38+
else if origins.subsetOf(myOrigins.nn) then
39+
this
40+
else
41+
CaptureAnnotation(refs, boxed)(cls).withOrigins(myOrigins.nn ++ origins)
42+
43+
private var myProvenance: Set[AnnotatedType] | Null = null
44+
45+
def provenance: Set[AnnotatedType] =
46+
if myProvenance == null then
47+
myProvenance = origins ++ origins.flatMap:
48+
case AnnotatedType(_, ann: CaptureAnnotation) => ann.provenance
49+
case _ => Set()
50+
myProvenance.nn
51+
2852
/** A cache for the version of this annotation which differs in its boxed status. */
2953
var boxDual: CaptureAnnotation | Null = null
3054

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

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -179,14 +179,23 @@ extension (tp: Type)
179179
&& !cs.keepAlways
180180
then tp
181181
else tp match
182-
case CapturingType(parent, cs1) => parent.capturing(cs1 ++ cs)
182+
case tp @ CapturingType(parent, cs1) => parent.capturing(cs1 ++ cs).withOrigin(tp)
183183
case _ => CapturingType(tp, cs)
184184

185+
def withOrigins(origins: Set[AnnotatedType])(using Context) = tp match
186+
case tp @ AnnotatedType(p, ann: CaptureAnnotation) =>
187+
tp.derivedAnnotatedType(p, ann.withOrigins(origins))
188+
case _ =>
189+
tp
190+
191+
def withOrigin(origin: AnnotatedType)(using Context) =
192+
withOrigins(Set(origin))
193+
185194
/** @pre `tp` is a CapturingType */
186195
def derivedCapturingType(parent: Type, refs: CaptureSet)(using Context): Type = tp match
187196
case tp @ CapturingType(p, r) =>
188197
if (parent eq p) && (refs eq r) then tp
189-
else CapturingType(parent, refs, tp.isBoxed)
198+
else CapturingType(parent, refs, tp.isBoxed).withOrigin(tp)
190199

191200
/** If this is a unboxed capturing type with nonempty capture set, its boxed version.
192201
* Or, if type is a TypeBounds of capturing types, the version where the bounds are boxed.
@@ -196,7 +205,7 @@ extension (tp: Type)
196205
case tp @ CapturingType(parent, refs) if !tp.isBoxed && !refs.isAlwaysEmpty =>
197206
tp.annot match
198207
case ann: CaptureAnnotation if !parent.derivesFrom(defn.Caps_CapSet) =>
199-
AnnotatedType(parent, ann.boxedAnnot)
208+
AnnotatedType(parent, ann.boxedAnnot).withOrigin(tp)
200209
case ann => tp
201210
case tp: RealTypeBounds =>
202211
tp.derivedTypeBounds(tp.lo.boxed, tp.hi.boxed)
@@ -209,7 +218,7 @@ extension (tp: Type)
209218
*/
210219
def unboxed(using Context): Type = tp.dealias match
211220
case tp @ CapturingType(parent, refs) if tp.isBoxed && !refs.isAlwaysEmpty =>
212-
CapturingType(parent, refs)
221+
CapturingType(parent, refs).withOrigin(tp)
213222
case tp: RealTypeBounds =>
214223
tp.derivedTypeBounds(tp.lo.unboxed, tp.hi.unboxed)
215224
case _ =>
@@ -303,7 +312,7 @@ extension (tp: Type)
303312
case ref: Capability if ref.isTracked || ref.isInstanceOf[DerivedCapability] =>
304313
ref.singletonCaptureSet
305314
case _ => refs
306-
CapturingType(parent, refs1, boxed)
315+
CapturingType(parent, refs1, boxed).withOrigin(tp)
307316
case _ =>
308317
tp
309318

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ object CapturingType:
3737
if refs.isAlwaysEmpty && !refs.keepAlways then parent
3838
else parent match
3939
case parent @ CapturingType(parent1, refs1) if boxed || !parent.isBoxed =>
40-
apply(parent1, refs ++ refs1, boxed)
40+
apply(parent1, refs ++ refs1, boxed).withOrigin(parent)
4141
case _ =>
4242
if parent.derivesFromMutable then refs.setMutable()
4343
refs.adoptClassifier(parent.classifier)

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

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -204,25 +204,27 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
204204
/** Pull out an embedded capture set from a part of `tp` */
205205
def normalizeCaptures(tp: Type)(using Context): Type = tp match
206206
case tp @ RefinedType(parent @ CapturingType(parent1, refs), rname, rinfo) =>
207-
CapturingType(tp.derivedRefinedType(parent1, rname, rinfo), refs, parent.isBoxed)
207+
CapturingType(tp.derivedRefinedType(parent1, rname, rinfo), refs, parent.isBoxed).withOrigin(parent)
208208
case tp: RecType =>
209209
tp.parent match
210210
case parent @ CapturingType(parent1, refs) =>
211-
CapturingType(tp.derivedRecType(parent1), refs, parent.isBoxed)
211+
CapturingType(tp.derivedRecType(parent1), refs, parent.isBoxed).withOrigin(parent)
212212
case _ =>
213213
tp // can return `tp` here since unlike RefinedTypes, RecTypes are never created
214214
// by `mapInferred`. Hence if the underlying type admits capture variables
215215
// a variable was already added, and the first case above would apply.
216216
case AndType(tp1 @ CapturingType(parent1, refs1), tp2 @ CapturingType(parent2, refs2)) =>
217217
assert(tp1.isBoxed == tp2.isBoxed)
218218
CapturingType(AndType(parent1, parent2), refs1 ** refs2, tp1.isBoxed)
219+
.withOrigins(Set(tp1, tp2))
219220
case tp @ OrType(tp1 @ CapturingType(parent1, refs1), tp2 @ CapturingType(parent2, refs2)) =>
220221
assert(tp1.isBoxed == tp2.isBoxed)
221222
CapturingType(OrType(parent1, parent2, tp.isSoft), refs1 ++ refs2, tp1.isBoxed)
223+
.withOrigins(Set(tp1, tp2))
222224
case tp @ OrType(tp1 @ CapturingType(parent1, refs1), tp2) =>
223-
CapturingType(OrType(parent1, tp2, tp.isSoft), refs1, tp1.isBoxed)
225+
CapturingType(OrType(parent1, tp2, tp.isSoft), refs1, tp1.isBoxed).withOrigin(tp1)
224226
case tp @ OrType(tp1, tp2 @ CapturingType(parent2, refs2)) =>
225-
CapturingType(OrType(tp1, parent2, tp.isSoft), refs2, tp2.isBoxed)
227+
CapturingType(OrType(tp1, parent2, tp.isSoft), refs2, tp2.isBoxed).withOrigin(tp2)
226228
case tp @ AppliedType(tycon, args)
227229
if !defn.isFunctionClass(tp.dealias.typeSymbol) && (tp.dealias eq tp) =>
228230
tp.derivedAppliedType(tycon, args.mapConserve(_.boxDeeply))
@@ -266,7 +268,6 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
266268
tp.typeSymbol match
267269
case cls: ClassSymbol
268270
if !defn.isFunctionClass(cls) && cls.is(CaptureChecked) =>
269-
RecType: _ =>
270271
cls.paramGetters.foldLeft(tp): (core, getter) =>
271272
if atPhase(thisPhase.next)(getter.hasTrackedParts)
272273
&& getter.isRefiningParamAccessor

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ object ccConfig:
5454

5555
/** Not used currently. Handy for trying out new features */
5656
def newScheme(using ctx: Context): Boolean =
57-
Feature.sourceVersion.stable.isAtLeast(SourceVersion.`3.7`)
57+
Feature.sourceVersion.stable.isAtLeast(SourceVersion.`3.9`)
5858

5959
def allowUse(using Context): Boolean =
6060
Feature.sourceVersion.stable.isAtMost(SourceVersion.`3.7`)

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

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -367,14 +367,6 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
367367
case tp2: LazyRef =>
368368
isBottom(tp1)
369369
|| !tp2.evaluating && recur(tp1, tp2.ref)
370-
case tp2: RecType =>
371-
def compareRec = tp1.safeDealias match
372-
case tp1: RecType =>
373-
val rthis1 = tp1.recThis
374-
recur(tp1.parent, tp2.parent.substRecThis(tp2, rthis1))
375-
case _ =>
376-
secondTry
377-
compareRec
378370
case CapturingType(_, _) =>
379371
secondTry
380372
case tp2: AnnotatedType if !tp2.isRefining =>

0 commit comments

Comments
 (0)