@@ -14,14 +14,14 @@ import typer.RefChecks.{checkAllOverrides, checkSelfAgainstParents, OverridingPa
14
14
import typer .Checking .{checkBounds , checkAppliedTypesIn }
15
15
import typer .ErrorReporting .{Addenda , err }
16
16
import typer .ProtoTypes .{AnySelectionProto , LhsProto }
17
- import util .{SimpleIdentitySet , EqHashMap , EqHashSet , SrcPos , Property }
17
+ import util .{SimpleIdentitySet , EqHashMap , SrcPos , Property }
18
18
import transform .SymUtils .*
19
- import transform .{Recheck , PreRecheck , CapturedVars }
19
+ import transform .{Recheck , PreRecheck }
20
20
import Recheck .*
21
21
import scala .collection .mutable
22
22
import CaptureSet .{withCaptureSetsExplained , IdempotentCaptRefMap , CompareResult }
23
23
import StdNames .nme
24
- import NameKinds .{ DefaultGetterName , WildcardParamName }
24
+ import NameKinds .DefaultGetterName
25
25
import reporting .trace
26
26
27
27
/** The capture checker */
@@ -147,49 +147,33 @@ object CheckCaptures:
147
147
private def disallowRootCapabilitiesIn (tp : Type , carrier : Symbol , what : String , have : String , addendum : String , pos : SrcPos )(using Context ) =
148
148
val check = new TypeTraverser :
149
149
150
- private val seen = new EqHashSet [TypeRef ]
151
-
152
- /** Check that there is at least one method containing carrier and defined
153
- * in the scope of tparam. E.g. this is OK:
154
- * def f[T] = { ... var x: T ... }
155
- * So is this:
156
- * class C[T] { def f() = { class D { var x: T }}}
157
- * But this is not OK:
158
- * class C[T] { object o { var x: T }}
159
- */
160
150
extension (tparam : Symbol ) def isParametricIn (carrier : Symbol ): Boolean =
161
- carrier.exists && {
162
- val encl = carrier.owner.enclosingMethodOrClass
163
- if encl.isClass then tparam.isParametricIn(encl)
164
- else
165
- def recur (encl : Symbol ): Boolean =
166
- if tparam.owner == encl then true
167
- else if encl.isStatic || ! encl.exists then false
168
- else recur(encl.owner.enclosingMethodOrClass)
169
- recur(encl)
170
- }
151
+ val encl = carrier.owner.enclosingMethodOrClass
152
+ if encl.isClass then tparam.isParametricIn(encl)
153
+ else
154
+ def recur (encl : Symbol ): Boolean =
155
+ if tparam.owner == encl then true
156
+ else if encl.isStatic || ! encl.exists then false
157
+ else recur(encl.owner.enclosingMethodOrClass)
158
+ recur(encl)
171
159
172
160
def traverse (t : Type ) =
173
161
t.dealiasKeepAnnots match
174
162
case t : TypeRef =>
175
- if ! seen.contains(t) then
176
- capt.println(i " disallow $t, $tp, $what, ${t.isSealed}" )
177
- seen += t
178
- t.info match
179
- case TypeBounds (_, hi) if ! t.isSealed && ! t.symbol.isParametricIn(carrier) =>
180
- if hi.isAny then
181
- val detailStr =
182
- if t eq tp then " variable"
183
- else i " refers to the type variable $t, which "
184
- report.error(
185
- em """ $what cannot $have $tp since
186
- |that type $detailStr is not sealed.
187
- | $addendum""" ,
188
- pos)
189
- else
190
- traverse(hi)
191
- case _ =>
192
- traverseChildren(t)
163
+ capt.println(i " disallow $t, $tp, $what, ${t.symbol.is(Sealed )}" )
164
+ t.info match
165
+ case TypeBounds (_, hi)
166
+ if ! t.symbol.is(Sealed ) && ! t.symbol.isParametricIn(carrier) =>
167
+ if hi.isAny then
168
+ report.error(
169
+ em """ $what cannot $have $tp since
170
+ |that type refers to the type variable $t, which is not sealed.
171
+ | $addendum""" ,
172
+ pos)
173
+ else
174
+ traverse(hi)
175
+ case _ =>
176
+ traverseChildren(t)
193
177
case AnnotatedType (_, ann) if ann.symbol == defn.UncheckedCapturesAnnot =>
194
178
()
195
179
case t =>
@@ -276,12 +260,11 @@ class CheckCaptures extends Recheck, SymTransformer:
276
260
pos, provenance)
277
261
278
262
/** Check subcapturing `cs1 <: cs2`, report error on failure */
279
- def checkSubset (cs1 : CaptureSet , cs2 : CaptureSet , pos : SrcPos ,
280
- provenance : => String = " " , cs1description : String = " " )(using Context ) =
263
+ def checkSubset (cs1 : CaptureSet , cs2 : CaptureSet , pos : SrcPos , provenance : => String = " " )(using Context ) =
281
264
checkOK(
282
265
cs1.subCaptures(cs2, frozen = false ),
283
- if cs1.elems.size == 1 then i " reference ${cs1.elems.toList.head}$cs1description is not "
284
- else i " references $cs1$cs1description are not all " ,
266
+ if cs1.elems.size == 1 then i " reference ${cs1.elems.toList.head} is not "
267
+ else i " references $cs1 are not all " ,
285
268
pos, provenance)
286
269
287
270
/** The current environment */
@@ -559,10 +542,10 @@ class CheckCaptures extends Recheck, SymTransformer:
559
542
val TypeApply (fn, args) = tree
560
543
val polyType = atPhase(thisPhase.prev):
561
544
fn.tpe.widen.asInstanceOf [TypeLambda ]
562
- for case (arg : TypeTree , formal , pname) <- args.lazyZip(polyType.paramRefs ).lazyZip((polyType.paramNames)) do
563
- if formal.isSealed then
545
+ for case (arg : TypeTree , pinfo , pname) <- args.lazyZip(polyType.paramInfos ).lazyZip((polyType.paramNames)) do
546
+ if pinfo.bounds.hi.hasAnnotation(defn. Caps_SealedAnnot ) then
564
547
def where = if fn.symbol.exists then i " in an argument of ${fn.symbol}" else " "
565
- disallowRootCapabilitiesIn(arg.knownType, NoSymbol ,
548
+ disallowRootCapabilitiesIn(arg.knownType, fn.symbol ,
566
549
i " Sealed type variable $pname" , " be instantiated to" ,
567
550
i " This is often caused by a local capability $where\n leaking as part of its result. " ,
568
551
tree.srcPos)
@@ -603,58 +586,13 @@ class CheckCaptures extends Recheck, SymTransformer:
603
586
openClosures = openClosures.tail
604
587
end recheckClosureBlock
605
588
606
- /** Maps mutable variables to the symbols that capture them (in the
607
- * CheckCaptures sense, i.e. symbol is referred to from a different method
608
- * than the one it is defined in).
609
- */
610
- private val capturedBy = util.HashMap [Symbol , Symbol ]()
611
-
612
- /** Maps anonymous functions appearing as function arguments to
613
- * the function that is called.
614
- */
615
- private val anonFunCallee = util.HashMap [Symbol , Symbol ]()
616
-
617
- /** Populates `capturedBy` and `anonFunCallee`. Called by `checkUnit`.
618
- */
619
- private def collectCapturedMutVars (using Context ) = new TreeTraverser :
620
- def traverse (tree : Tree )(using Context ) = tree match
621
- case id : Ident =>
622
- val sym = id.symbol
623
- if sym.is(Mutable , butNot = Method ) && sym.owner.isTerm then
624
- val enclMeth = ctx.owner.enclosingMethod
625
- if sym.enclosingMethod != enclMeth then
626
- capturedBy(sym) = enclMeth
627
- case Apply (fn, args) =>
628
- for case closureDef(mdef) <- args do
629
- anonFunCallee(mdef.symbol) = fn.symbol
630
- traverseChildren(tree)
631
- case Inlined (_, bindings, expansion) =>
632
- traverse(bindings)
633
- traverse(expansion)
634
- case mdef : DefDef =>
635
- if ! mdef.symbol.isInlineMethod then traverseChildren(tree)
636
- case _ =>
637
- traverseChildren(tree)
638
-
639
589
override def recheckValDef (tree : ValDef , sym : Symbol )(using Context ): Type =
640
590
try
641
591
if sym.is(Module ) then sym.info // Modules are checked by checking the module class
642
592
else
643
593
if sym.is(Mutable ) && ! sym.hasAnnotation(defn.UncheckedCapturesAnnot ) then
644
- val (carrier, addendum) = capturedBy.get(sym) match
645
- case Some (encl) =>
646
- val enclStr =
647
- if encl.isAnonymousFunction then
648
- val location = anonFunCallee.get(encl) match
649
- case Some (meth) if meth.exists => i " argument in a call to $meth"
650
- case _ => " "
651
- s " an anonymous function $location"
652
- else encl.show
653
- (NoSymbol , i " \n Note that $sym does not count as local since it is captured by $enclStr" )
654
- case _ =>
655
- (sym, " " )
656
- disallowRootCapabilitiesIn(
657
- tree.tpt.knownType, carrier, i " Mutable $sym" , " have type" , addendum, sym.srcPos)
594
+ disallowRootCapabilitiesIn(tree.tpt.knownType, sym,
595
+ i " mutable $sym" , " have type" , " " , sym.srcPos)
658
596
checkInferredResult(super .recheckValDef(tree, sym), tree)
659
597
finally
660
598
if ! sym.is(Param ) then
@@ -742,15 +680,9 @@ class CheckCaptures extends Recheck, SymTransformer:
742
680
if ! param.hasAnnotation(defn.ConstructorOnlyAnnot ) then
743
681
checkSubset(param.termRef.captureSet, thisSet, param.srcPos) // (3)
744
682
for pureBase <- cls.pureBaseClass do // (4)
745
- def selfType = impl.body
746
- .collect:
747
- case TypeDef (tpnme.SELF , rhs) => rhs
748
- .headOption
749
- .getOrElse(tree)
750
- .orElse(tree)
751
683
checkSubset(thisSet,
752
684
CaptureSet .empty.withDescription(i " of pure base class $pureBase" ),
753
- selfType .srcPos, cs1description = " captured by this self type " )
685
+ tree .srcPos)
754
686
super .recheckClassDef(tree, impl, cls)
755
687
finally
756
688
curEnv = saved
@@ -1190,8 +1122,6 @@ class CheckCaptures extends Recheck, SymTransformer:
1190
1122
1191
1123
override def needsCheck (overriding : Symbol , overridden : Symbol )(using Context ): Boolean =
1192
1124
! setup.isPreCC(overriding) && ! setup.isPreCC(overridden)
1193
-
1194
- override def checkInheritedTraitParameters : Boolean = false
1195
1125
end OverridingPairsCheckerCC
1196
1126
1197
1127
def traverse (t : Tree )(using Context ) =
@@ -1228,12 +1158,11 @@ class CheckCaptures extends Recheck, SymTransformer:
1228
1158
private val setup : SetupAPI = thisPhase.prev.asInstanceOf [Setup ]
1229
1159
1230
1160
override def checkUnit (unit : CompilationUnit )(using Context ): Unit =
1231
- setup.setupUnit(unit.tpdTree, completeDef)
1232
- collectCapturedMutVars.traverse(unit.tpdTree)
1161
+ setup.setupUnit(ctx.compilationUnit.tpdTree, completeDef)
1233
1162
1234
1163
if ctx.settings.YccPrintSetup .value then
1235
1164
val echoHeader = " [[syntax tree at end of cc setup]]"
1236
- val treeString = show(unit .tpdTree)
1165
+ val treeString = show(ctx.compilationUnit .tpdTree)
1237
1166
report.echo(s " $echoHeader\n $treeString\n " )
1238
1167
1239
1168
withCaptureSetsExplained :
@@ -1369,39 +1298,6 @@ class CheckCaptures extends Recheck, SymTransformer:
1369
1298
checker.traverse(tree.knownType)
1370
1299
end healTypeParam
1371
1300
1372
- def checkNoLocalRootIn (sym : Symbol , info : Type , pos : SrcPos )(using Context ): Unit =
1373
- val check = new TypeTraverser :
1374
- def traverse (tp : Type ) = tp match
1375
- case tp : TermRef if tp.isLocalRootCapability =>
1376
- if tp.localRootOwner == sym then
1377
- report.error(i " local root $tp cannot appear in type of $sym" , pos)
1378
- case tp : ClassInfo =>
1379
- traverseChildren(tp)
1380
- for mbr <- tp.decls do
1381
- if ! mbr.is(Private ) then checkNoLocalRootIn(sym, mbr.info, mbr.srcPos)
1382
- case _ =>
1383
- traverseChildren(tp)
1384
- check.traverse(info)
1385
-
1386
- def checkArraysAreSealedIn (tp : Type , pos : SrcPos )(using Context ): Unit =
1387
- val check = new TypeTraverser :
1388
- def traverse (t : Type ): Unit =
1389
- t match
1390
- case AppliedType (tycon, arg :: Nil ) if tycon.typeSymbol == defn.ArrayClass =>
1391
- if ! (pos.span.isSynthetic && ctx.reporter.errorsReported)
1392
- && ! arg.typeSymbol.name.is(WildcardParamName )
1393
- then
1394
- CheckCaptures .disallowRootCapabilitiesIn(arg, NoSymbol ,
1395
- " Array" , " have element type" ,
1396
- " Since arrays are mutable, they have to be treated like variables,\n so their element type must be sealed." ,
1397
- pos)
1398
- traverseChildren(t)
1399
- case defn.RefinedFunctionOf (rinfo : MethodType ) =>
1400
- traverse(rinfo)
1401
- case _ =>
1402
- traverseChildren(t)
1403
- check.traverse(tp)
1404
-
1405
1301
/** Perform the following kinds of checks
1406
1302
* - Check all explicitly written capturing types for well-formedness using `checkWellFormedPost`.
1407
1303
* - Check that arguments of TypeApplys and AppliedTypes conform to their bounds.
@@ -1413,11 +1309,10 @@ class CheckCaptures extends Recheck, SymTransformer:
1413
1309
val lctx = tree match
1414
1310
case _ : DefTree | _ : TypeDef if tree.symbol.exists => ctx.withOwner(tree.symbol)
1415
1311
case _ => ctx
1416
- trace(i " post check $tree" ):
1417
- traverseChildren(tree)(using lctx)
1418
- check(tree)
1312
+ traverseChildren(tree)(using lctx)
1313
+ check(tree)
1419
1314
def check (tree : Tree )(using Context ) = tree match
1420
- case TypeApply (fun, args) =>
1315
+ case t @ TypeApply (fun, args) =>
1421
1316
fun.knownType.widen match
1422
1317
case tl : PolyType =>
1423
1318
val normArgs = args.lazyZip(tl.paramInfos).map: (arg, bounds) =>
@@ -1426,10 +1321,6 @@ class CheckCaptures extends Recheck, SymTransformer:
1426
1321
checkBounds(normArgs, tl)
1427
1322
args.lazyZip(tl.paramNames).foreach(healTypeParam(_, _, fun.symbol))
1428
1323
case _ =>
1429
- case _ : ValOrDefDef | _ : TypeDef =>
1430
- checkNoLocalRootIn(tree.symbol, tree.symbol.info, tree.symbol.srcPos)
1431
- case tree : TypeTree =>
1432
- checkArraysAreSealedIn(tree.tpe, tree.srcPos)
1433
1324
case _ =>
1434
1325
end check
1435
1326
end checker
0 commit comments