@@ -519,8 +519,7 @@ class CheckCaptures extends Recheck, SymTransformer:
519519 def includeCallCaptures (sym : Symbol , resType : Type , tree : Tree )(using Context ): Unit = resType match
520520 case _ : MethodOrPoly => // wait until method is fully applied
521521 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)
524523
525524 /** Under the sealed policy, disallow the root capability in type arguments.
526525 * Type arguments come either from a TypeApply node or from an AppliedType
@@ -556,16 +555,21 @@ class CheckCaptures extends Recheck, SymTransformer:
556555 if param.isUseParam then markFree(arg.nuType.deepCaptureSet, errTree)
557556 end disallowCapInTypeArgs
558557
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+ */
559563 override def recheckIdent (tree : Ident , pt : Type )(using Context ): Type =
560564 val sym = tree.symbol
561565 if sym.is(Method ) then
562566 // If ident refers to a parameterless method, charge its cv to the environment
563567 includeCallCaptures(sym, sym.info, tree)
564568 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`.
569573 def addSelects (ref : TermRef , pt : Type ): CaptureRef = pt match
570574 case pt : PathSelectionProto if ref.isTracked =>
571575 if pt.sym.isReadOnlyMethod then
@@ -582,7 +586,8 @@ class CheckCaptures extends Recheck, SymTransformer:
582586 super .recheckIdent(tree, pt)
583587
584588 /** 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.
586591 */
587592 override def selectionProto (tree : Select , pt : Type )(using Context ): Type =
588593 val sym = tree.symbol
@@ -616,6 +621,9 @@ class CheckCaptures extends Recheck, SymTransformer:
616621 }
617622 case _ => denot
618623
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.
619627 if tree.symbol.isUpdateMethod && ! qualType.captureSet.isExclusive then
620628 report.error(
621629 em """ cannot call update ${tree.symbol} from $qualType,
@@ -651,8 +659,8 @@ class CheckCaptures extends Recheck, SymTransformer:
651659 selType
652660 }// .showing(i"recheck sel $tree, $qualType = $result")
653661
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.
656664 */
657665 override def prepareFunction (funtpe : MethodType , meth : Symbol )(using Context ): MethodType =
658666 val paramInfosWithUses =
@@ -682,7 +690,8 @@ class CheckCaptures extends Recheck, SymTransformer:
682690 includeCallCaptures(meth, res, tree)
683691 res
684692
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`,
686695 * charge the deep capture set of the actual argument to the environment.
687696 */
688697 protected override def recheckArg (arg : Tree , formal : Type )(using Context ): Type =
@@ -773,16 +782,21 @@ class CheckCaptures extends Recheck, SymTransformer:
773782
774783 /** First half of result pair:
775784 * 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.
778790 *
779791 * 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
781795 */
782796 def addParamArgRefinements (core : Type , initCs : CaptureSet ): (Type , CaptureSet ) =
783797 var refined : Type = core
784798 var allCaptures : CaptureSet =
785- if core.derivesFromMutable then CaptureSet .fresh()
799+ if core.derivesFromMutable then initCs ++ CaptureSet .fresh()
786800 else if core.derivesFromCapability then initCs ++ Fresh .Cap ().readOnly.singletonCaptureSet
787801 else initCs
788802 for (getterName, argType) <- mt.paramNames.lazyZip(argTypes) do
@@ -1488,7 +1502,7 @@ class CheckCaptures extends Recheck, SymTransformer:
14881502 /** If actual is a capturing type T^C extending Mutable, and expected is an
14891503 * unboxed non-singleton value type not extending mutable, narrow the capture
14901504 * 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
14921506 * that's upper bounded by a read-only type. In this case it would not be sound
14931507 * to narrow to the read-only set, since that set can be propagated
14941508 * by the type variable instantiation.
@@ -1514,9 +1528,9 @@ class CheckCaptures extends Recheck, SymTransformer:
15141528 actual
15151529 else
15161530 val improvedVAR = improveCaptures(actual.widen.dealiasKeepAnnots, actual)
1517- val improvedRO = improveReadOnly(improvedVAR, expected)
1531+ val improved = improveReadOnly(improvedVAR, expected)
15181532 val adapted = adaptBoxed(
1519- improvedRO .withReachCaptures(actual), expected, tree,
1533+ improved .withReachCaptures(actual), expected, tree,
15201534 covariant = true , alwaysConst = false , boxErrors)
15211535 if adapted eq improvedVAR // no .rd improvement, no box-adaptation
15221536 then actual // might as well use actual instead of improved widened
@@ -1563,17 +1577,19 @@ class CheckCaptures extends Recheck, SymTransformer:
15631577
15641578 /** Check that overrides don't change the @use or @consume status of their parameters */
15651579 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)
15701580 for
15711581 (params1, params2) <- member.rawParamss.lazyZip(other.rawParamss)
15721582 (param1, param2) <- params1.lazyZip(params2)
15731583 do
15741584 def checkAnnot (cls : ClassSymbol ) =
15751585 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+
15771593 checkAnnot(defn.UseAnnot )
15781594 checkAnnot(defn.ConsumeAnnot )
15791595 end OverridingPairsCheckerCC
0 commit comments