@@ -114,88 +114,6 @@ extends tpd.TreeTraverser:
114
114
case _ => tp
115
115
case _ => tp
116
116
117
- private def superTypeIsImpure (tp : Type ): Boolean = {
118
- tp.dealias match
119
- case CapturingType (_, refs) =>
120
- ! refs.isAlwaysEmpty
121
- case tp : (TypeRef | AppliedType ) =>
122
- val sym = tp.typeSymbol
123
- if sym.isClass then
124
- sym == defn.AnyClass
125
- // we assume Any is a shorthand of {cap} Any, so if Any is an upper
126
- // bound, the type is taken to be impure.
127
- else superTypeIsImpure(tp.superType)
128
- case tp : (RefinedOrRecType | MatchType ) =>
129
- superTypeIsImpure(tp.underlying)
130
- case tp : AndType =>
131
- superTypeIsImpure(tp.tp1) || needsVariable(tp.tp2)
132
- case tp : OrType =>
133
- superTypeIsImpure(tp.tp1) && superTypeIsImpure(tp.tp2)
134
- case _ =>
135
- false
136
- }.showing(i " super type is impure $tp = $result" , capt)
137
-
138
- /** Should a capture set variable be added on type `tp`? */
139
- def needsVariable (tp : Type ): Boolean = {
140
- tp.typeParams.isEmpty && tp.match
141
- case tp : (TypeRef | AppliedType ) =>
142
- val tp1 = tp.dealias
143
- if tp1 ne tp then needsVariable(tp1)
144
- else
145
- val sym = tp1.typeSymbol
146
- if sym.isClass then
147
- ! sym.isPureClass && sym != defn.AnyClass
148
- else superTypeIsImpure(tp1)
149
- case tp : (RefinedOrRecType | MatchType ) =>
150
- needsVariable(tp.underlying)
151
- case tp : AndType =>
152
- needsVariable(tp.tp1) && needsVariable(tp.tp2)
153
- case tp : OrType =>
154
- needsVariable(tp.tp1) || needsVariable(tp.tp2)
155
- case CapturingType (parent, refs) =>
156
- needsVariable(parent)
157
- && refs.isConst // if refs is a variable, no need to add another
158
- && ! refs.isUniversal // if refs is {cap}, an added variable would not change anything
159
- case _ =>
160
- false
161
- }.showing(i " can have inferred capture $tp = $result" , capt)
162
-
163
- /** Add a capture set variable to `tp` if necessary, or maybe pull out
164
- * an embedded capture set variable from a part of `tp`.
165
- */
166
- def addVar (tp : Type ) = tp match
167
- case tp @ RefinedType (parent @ CapturingType (parent1, refs), rname, rinfo) =>
168
- CapturingType (tp.derivedRefinedType(parent1, rname, rinfo), refs, parent.isBoxed)
169
- case tp : RecType =>
170
- tp.parent match
171
- case parent @ CapturingType (parent1, refs) =>
172
- CapturingType (tp.derivedRecType(parent1), refs, parent.isBoxed)
173
- case _ =>
174
- tp // can return `tp` here since unlike RefinedTypes, RecTypes are never created
175
- // by `mapInferred`. Hence if the underlying type admits capture variables
176
- // a variable was already added, and the first case above would apply.
177
- case AndType (tp1 @ CapturingType (parent1, refs1), tp2 @ CapturingType (parent2, refs2)) =>
178
- assert(refs1.asVar.elems.isEmpty)
179
- assert(refs2.asVar.elems.isEmpty)
180
- assert(tp1.isBoxed == tp2.isBoxed)
181
- CapturingType (AndType (parent1, parent2), refs1 ** refs2, tp1.isBoxed)
182
- case tp @ OrType (tp1 @ CapturingType (parent1, refs1), tp2 @ CapturingType (parent2, refs2)) =>
183
- assert(refs1.asVar.elems.isEmpty)
184
- assert(refs2.asVar.elems.isEmpty)
185
- assert(tp1.isBoxed == tp2.isBoxed)
186
- CapturingType (OrType (parent1, parent2, tp.isSoft), refs1 ++ refs2, tp1.isBoxed)
187
- case tp @ OrType (tp1 @ CapturingType (parent1, refs1), tp2) =>
188
- CapturingType (OrType (parent1, tp2, tp.isSoft), refs1, tp1.isBoxed)
189
- case tp @ OrType (tp1, tp2 @ CapturingType (parent2, refs2)) =>
190
- CapturingType (OrType (tp1, parent2, tp.isSoft), refs2, tp2.isBoxed)
191
- case _ if needsVariable(tp) =>
192
- val cs = tp.dealias match
193
- case CapturingType (_, refs) => CaptureSet .Var (refs.elems)
194
- case _ => CaptureSet .Var ()
195
- CapturingType (tp, cs)
196
- case _ =>
197
- tp
198
-
199
117
private var isTopLevel = true
200
118
201
119
private def mapNested (ts : List [Type ]): List [Type ] =
@@ -246,7 +164,7 @@ extends tpd.TreeTraverser:
246
164
resType = this (tp.resType))
247
165
case _ =>
248
166
mapOver(tp)
249
- addVar(addCaptureRefinements(tp1))
167
+ Setup . addVar(addCaptureRefinements(tp1))
250
168
end apply
251
169
end mapInferred
252
170
@@ -385,9 +303,9 @@ extends tpd.TreeTraverser:
385
303
val polyType = fn.tpe.widen.asInstanceOf [TypeLambda ]
386
304
for case (arg : TypeTree , pinfo, pname) <- args.lazyZip(polyType.paramInfos).lazyZip((polyType.paramNames)) do
387
305
if pinfo.bounds.hi.hasAnnotation(defn.Caps_SealedAnnot ) then
388
- def where = if fn.symbol.exists then i " in the body of ${fn.symbol}" else " "
306
+ def where = if fn.symbol.exists then i " in an argument of ${fn.symbol}" else " "
389
307
CheckCaptures .disallowRootCapabilitiesIn(arg.knownType,
390
- i " Sealed type variable $pname" , " be instantiated to" ,
308
+ i " Sealed type variable $pname" , " be instantiated to" ,
391
309
i " This is often caused by a local capability $where\n leaking as part of its result. " ,
392
310
tree.srcPos)
393
311
case _ =>
@@ -428,7 +346,7 @@ extends tpd.TreeTraverser:
428
346
if prevLambdas.isEmpty then restp
429
347
else SubstParams (prevPsymss, prevLambdas)(restp)
430
348
431
- if tree.tpt.hasRememberedType && ! sym.isConstructor then
349
+ if sym.exists && tree.tpt.hasRememberedType && ! sym.isConstructor then
432
350
val newInfo = integrateRT(sym.info, sym.paramSymss, Nil , Nil )
433
351
.showing(i " update info $sym: ${sym.info} --> $result" , capt)
434
352
if newInfo ne sym.info then
@@ -474,4 +392,97 @@ object Setup:
474
392
475
393
def isDuringSetup (using Context ): Boolean =
476
394
ctx.property(IsDuringSetupKey ).isDefined
395
+
396
+ private def superTypeIsImpure (tp : Type )(using Context ): Boolean = {
397
+ tp.dealias match
398
+ case CapturingType (_, refs) =>
399
+ ! refs.isAlwaysEmpty
400
+ case tp : (TypeRef | AppliedType ) =>
401
+ val sym = tp.typeSymbol
402
+ if sym.isClass then
403
+ sym == defn.AnyClass
404
+ // we assume Any is a shorthand of {cap} Any, so if Any is an upper
405
+ // bound, the type is taken to be impure.
406
+ else superTypeIsImpure(tp.superType)
407
+ case tp : (RefinedOrRecType | MatchType ) =>
408
+ superTypeIsImpure(tp.underlying)
409
+ case tp : AndType =>
410
+ superTypeIsImpure(tp.tp1) || needsVariable(tp.tp2)
411
+ case tp : OrType =>
412
+ superTypeIsImpure(tp.tp1) && superTypeIsImpure(tp.tp2)
413
+ case _ =>
414
+ false
415
+ }.showing(i " super type is impure $tp = $result" , capt)
416
+
417
+ /** Should a capture set variable be added on type `tp`? */
418
+ def needsVariable (tp : Type )(using Context ): Boolean = {
419
+ tp.typeParams.isEmpty && tp.match
420
+ case tp : (TypeRef | AppliedType ) =>
421
+ val sym = tp.typeSymbol
422
+ if sym.isClass then
423
+ ! sym.isPureClass && sym != defn.AnyClass
424
+ else
425
+ sym != defn.FromJavaObjectSymbol
426
+ // For capture checking, we assume Object from Java is the same as Any
427
+ && {
428
+ val tp1 = tp.dealias
429
+ if tp1 ne tp then needsVariable(tp1)
430
+ else superTypeIsImpure(tp1)
431
+ }
432
+ case tp : (RefinedOrRecType | MatchType ) =>
433
+ needsVariable(tp.underlying)
434
+ case tp : AndType =>
435
+ needsVariable(tp.tp1) && needsVariable(tp.tp2)
436
+ case tp : OrType =>
437
+ needsVariable(tp.tp1) || needsVariable(tp.tp2)
438
+ case CapturingType (parent, refs) =>
439
+ needsVariable(parent)
440
+ && refs.isConst // if refs is a variable, no need to add another
441
+ && ! refs.isUniversal // if refs is {cap}, an added variable would not change anything
442
+ case _ =>
443
+ false
444
+ }.showing(i " can have inferred capture $tp = $result" , capt)
445
+
446
+ /** Add a capture set variable to `tp` if necessary, or maybe pull out
447
+ * an embedded capture set variable from a part of `tp`.
448
+ */
449
+ def decorate (tp : Type , addedSet : Type => CaptureSet )(using Context ): Type = tp match
450
+ case tp @ RefinedType (parent @ CapturingType (parent1, refs), rname, rinfo) =>
451
+ CapturingType (tp.derivedRefinedType(parent1, rname, rinfo), refs, parent.isBoxed)
452
+ case tp : RecType =>
453
+ tp.parent match
454
+ case parent @ CapturingType (parent1, refs) =>
455
+ CapturingType (tp.derivedRecType(parent1), refs, parent.isBoxed)
456
+ case _ =>
457
+ tp // can return `tp` here since unlike RefinedTypes, RecTypes are never created
458
+ // by `mapInferred`. Hence if the underlying type admits capture variables
459
+ // a variable was already added, and the first case above would apply.
460
+ case AndType (tp1 @ CapturingType (parent1, refs1), tp2 @ CapturingType (parent2, refs2)) =>
461
+ assert(refs1.elems.isEmpty)
462
+ assert(refs2.elems.isEmpty)
463
+ assert(tp1.isBoxed == tp2.isBoxed)
464
+ CapturingType (AndType (parent1, parent2), refs1 ** refs2, tp1.isBoxed)
465
+ case tp @ OrType (tp1 @ CapturingType (parent1, refs1), tp2 @ CapturingType (parent2, refs2)) =>
466
+ assert(refs1.elems.isEmpty)
467
+ assert(refs2.elems.isEmpty)
468
+ assert(tp1.isBoxed == tp2.isBoxed)
469
+ CapturingType (OrType (parent1, parent2, tp.isSoft), refs1 ++ refs2, tp1.isBoxed)
470
+ case tp @ OrType (tp1 @ CapturingType (parent1, refs1), tp2) =>
471
+ CapturingType (OrType (parent1, tp2, tp.isSoft), refs1, tp1.isBoxed)
472
+ case tp @ OrType (tp1, tp2 @ CapturingType (parent2, refs2)) =>
473
+ CapturingType (OrType (tp1, parent2, tp.isSoft), refs2, tp2.isBoxed)
474
+ case _ if needsVariable(tp) =>
475
+ CapturingType (tp, addedSet(tp))
476
+ case _ =>
477
+ tp
478
+
479
+ /** Add a capture set variable to `tp` if necessary, or maybe pull out
480
+ * an embedded capture set variable from a part of `tp`.
481
+ */
482
+ def addVar (tp : Type )(using Context ): Type =
483
+ decorate(tp,
484
+ addedSet = _.dealias.match
485
+ case CapturingType (_, refs) => CaptureSet .Var (refs.elems)
486
+ case _ => CaptureSet .Var ())
487
+
477
488
end Setup
0 commit comments