@@ -519,8 +519,7 @@ class CheckCaptures extends Recheck, SymTransformer:
519
519
def includeCallCaptures (sym : Symbol , resType : Type , tree : Tree )(using Context ): Unit = resType match
520
520
case _ : MethodOrPoly => // wait until method is fully applied
521
521
case _ =>
522
- if sym.exists then
523
- if curEnv.isOpen then markFree(capturedVars(sym), tree)
522
+ if sym.exists && curEnv.isOpen then markFree(capturedVars(sym), tree)
524
523
525
524
/** Under the sealed policy, disallow the root capability in type arguments.
526
525
* Type arguments come either from a TypeApply node or from an AppliedType
@@ -556,16 +555,21 @@ class CheckCaptures extends Recheck, SymTransformer:
556
555
if param.isUseParam then markFree(arg.nuType.deepCaptureSet, errTree)
557
556
end disallowCapInTypeArgs
558
557
558
+ /** Rechecking idents involves:
559
+ * - adding call captures for idents referring to methods
560
+ * - marking as free the identifier with any selections or .rd
561
+ * modifiers implied by the expected type
562
+ */
559
563
override def recheckIdent (tree : Ident , pt : Type )(using Context ): Type =
560
564
val sym = tree.symbol
561
565
if sym.is(Method ) then
562
566
// If ident refers to a parameterless method, charge its cv to the environment
563
567
includeCallCaptures(sym, sym.info, tree)
564
568
else if ! sym.isStatic then
565
- // Otherwise charge its symbol, but add all selections implied by the e
566
- // expected type `pt`.
567
- // Example: If we have `x` and the expected type says we select that with `.a.b`,
568
- // we charge `x.a.b` instead of `x`.
569
+ // Otherwise charge its symbol, but add all selections and also any `.rd`
570
+ // modifier implied by the expected type `pt`.
571
+ // Example: If we have `x` and the expected type says we select that with `.a.b`
572
+ // where `b` is a read-only method, we charge `x.a.b.rd ` instead of `x`.
569
573
def addSelects (ref : TermRef , pt : Type ): CaptureRef = pt match
570
574
case pt : PathSelectionProto if ref.isTracked =>
571
575
if pt.sym.isReadOnlyMethod then
@@ -582,7 +586,8 @@ class CheckCaptures extends Recheck, SymTransformer:
582
586
super .recheckIdent(tree, pt)
583
587
584
588
/** The expected type for the qualifier of a selection. If the selection
585
- * could be part of a capabaility path, we return a PathSelectionProto.
589
+ * could be part of a capability path or is a a read-only method, we return
590
+ * a PathSelectionProto.
586
591
*/
587
592
override def selectionProto (tree : Select , pt : Type )(using Context ): Type =
588
593
val sym = tree.symbol
@@ -616,6 +621,9 @@ class CheckCaptures extends Recheck, SymTransformer:
616
621
}
617
622
case _ => denot
618
623
624
+ // Don't allow update methods to be called unless the qualifier captures
625
+ // contain an exclusive referenece. TODO This should probabkly rolled into
626
+ // qualifier logic once we have it.
619
627
if tree.symbol.isUpdateMethod && ! qualType.captureSet.isExclusive then
620
628
report.error(
621
629
em """ cannot call update ${tree.symbol} from $qualType,
@@ -651,8 +659,8 @@ class CheckCaptures extends Recheck, SymTransformer:
651
659
selType
652
660
}// .showing(i"recheck sel $tree, $qualType = $result")
653
661
654
- /** Hook for massaging a function before it is applied. Copies all @use annotations
655
- * on method parameter symbols to the corresponding paramInfo types.
662
+ /** Hook for massaging a function before it is applied. Copies all @use and @consume
663
+ * annotations on method parameter symbols to the corresponding paramInfo types.
656
664
*/
657
665
override def prepareFunction (funtpe : MethodType , meth : Symbol )(using Context ): MethodType =
658
666
val paramInfosWithUses =
@@ -682,7 +690,8 @@ class CheckCaptures extends Recheck, SymTransformer:
682
690
includeCallCaptures(meth, res, tree)
683
691
res
684
692
685
- /** Recheck argument, and, if formal parameter carries a `@use`,
693
+ /** Recheck argument against a "freshened" version of `formal` where toplevel `cap`
694
+ * occurrences are replaced by `Fresh.Cap`. Also, if formal parameter carries a `@use`,
686
695
* charge the deep capture set of the actual argument to the environment.
687
696
*/
688
697
protected override def recheckArg (arg : Tree , formal : Type )(using Context ): Type =
@@ -773,16 +782,21 @@ class CheckCaptures extends Recheck, SymTransformer:
773
782
774
783
/** First half of result pair:
775
784
* Refine the type of a constructor call `new C(t_1, ..., t_n)`
776
- * to C{val x_1: T_1, ..., x_m: T_m} where x_1, ..., x_m are the tracked
777
- * parameters of C and T_1, ..., T_m are the types of the corresponding arguments.
785
+ * to C{val x_1: @refineOverride T_1, ..., x_m: @refineOverride T_m}
786
+ * where x_1, ..., x_m are the tracked parameters of C and
787
+ * T_1, ..., T_m are the types of the corresponding arguments. The @refineOveride
788
+ * annotations avoid problematic intersections of capture sets when those
789
+ * parameters are selected.
778
790
*
779
791
* Second half: union of initial capture set and all capture sets of arguments
780
- * to tracked parameters.
792
+ * to tracked parameters. The initial capture set `initCs` is augmented with
793
+ * - Fresh.Cap if `core` extends Mutable
794
+ * - Fresh.Cap.rd if `core` extends Capability
781
795
*/
782
796
def addParamArgRefinements (core : Type , initCs : CaptureSet ): (Type , CaptureSet ) =
783
797
var refined : Type = core
784
798
var allCaptures : CaptureSet =
785
- if core.derivesFromMutable then CaptureSet .fresh()
799
+ if core.derivesFromMutable then initCs ++ CaptureSet .fresh()
786
800
else if core.derivesFromCapability then initCs ++ Fresh .Cap ().readOnly.singletonCaptureSet
787
801
else initCs
788
802
for (getterName, argType) <- mt.paramNames.lazyZip(argTypes) do
@@ -1488,7 +1502,7 @@ class CheckCaptures extends Recheck, SymTransformer:
1488
1502
/** If actual is a capturing type T^C extending Mutable, and expected is an
1489
1503
* unboxed non-singleton value type not extending mutable, narrow the capture
1490
1504
* set `C` to `ro(C)`.
1491
- * The unboxed condition ensures that the expected is not a type variable
1505
+ * The unboxed condition ensures that the expected type is not a type variable
1492
1506
* that's upper bounded by a read-only type. In this case it would not be sound
1493
1507
* to narrow to the read-only set, since that set can be propagated
1494
1508
* by the type variable instantiation.
@@ -1514,9 +1528,9 @@ class CheckCaptures extends Recheck, SymTransformer:
1514
1528
actual
1515
1529
else
1516
1530
val improvedVAR = improveCaptures(actual.widen.dealiasKeepAnnots, actual)
1517
- val improvedRO = improveReadOnly(improvedVAR, expected)
1531
+ val improved = improveReadOnly(improvedVAR, expected)
1518
1532
val adapted = adaptBoxed(
1519
- improvedRO .withReachCaptures(actual), expected, tree,
1533
+ improved .withReachCaptures(actual), expected, tree,
1520
1534
covariant = true , alwaysConst = false , boxErrors)
1521
1535
if adapted eq improvedVAR // no .rd improvement, no box-adaptation
1522
1536
then actual // might as well use actual instead of improved widened
@@ -1563,17 +1577,19 @@ class CheckCaptures extends Recheck, SymTransformer:
1563
1577
1564
1578
/** Check that overrides don't change the @use or @consume status of their parameters */
1565
1579
override def additionalChecks (member : Symbol , other : Symbol )(using Context ): Unit =
1566
- def fail (msg : String ) =
1567
- report.error(
1568
- OverrideError (msg, self, member, other, self.memberInfo(member), self.memberInfo(other)),
1569
- if member.owner == clazz then member.srcPos else clazz.srcPos)
1570
1580
for
1571
1581
(params1, params2) <- member.rawParamss.lazyZip(other.rawParamss)
1572
1582
(param1, param2) <- params1.lazyZip(params2)
1573
1583
do
1574
1584
def checkAnnot (cls : ClassSymbol ) =
1575
1585
if param1.hasAnnotation(cls) != param2.hasAnnotation(cls) then
1576
- fail(i " has a parameter ${param1.name} with different @ ${cls.name} status than the corresponding parameter in the overridden definition " )
1586
+ report.error(
1587
+ OverrideError (
1588
+ i " has a parameter ${param1.name} with different @ ${cls.name} status than the corresponding parameter in the overridden definition " ,
1589
+ self, member, other, self.memberInfo(member), self.memberInfo(other)
1590
+ ),
1591
+ if member.owner == clazz then member.srcPos else clazz.srcPos)
1592
+
1577
1593
checkAnnot(defn.UseAnnot )
1578
1594
checkAnnot(defn.ConsumeAnnot )
1579
1595
end OverridingPairsCheckerCC
0 commit comments