@@ -246,6 +246,28 @@ class CheckCaptures extends Recheck, SymTransformer:
246246
247247 override def isRunnable (using Context ) = super .isRunnable && Feature .ccEnabledSomewhere
248248
249+ /** We normally need a recompute if the prefix is a SingletonType and the
250+ * last denotation is not a SymDenotation. The SingletonType requirement is
251+ * so that we don't widen TermRefs with non-path prefixes to their underlying
252+ * type when recomputing their denotations with asSeenFrom. Such widened types
253+ * would become illegal members of capture sets.
254+ *
255+ * The SymDenotation requirement is so that we don't recompute termRefs of Symbols
256+ * which should be handled by SymTransformers alone. However, if the underlying type
257+ * of the prefix is a capturing type, we do need to recompute since in that case
258+ * the prefix might carry a parameter refinement created in Setup, and we need to
259+ * take these refinements into account.
260+ */
261+ override def needsRecompute (tp : NamedType , lastDenotation : SingleDenotation )(using Context ): Boolean =
262+ tp.prefix match
263+ case prefix : TermRef =>
264+ ! lastDenotation.isInstanceOf [SymDenotation ]
265+ || ! prefix.info.captureSet.isAlwaysEmpty
266+ case prefix : SingletonType =>
267+ ! lastDenotation.isInstanceOf [SymDenotation ]
268+ case _ =>
269+ false
270+
249271 def newRechecker ()(using Context ) = CaptureChecker (ctx)
250272
251273 override def run (using Context ): Unit =
@@ -694,12 +716,6 @@ class CheckCaptures extends Recheck, SymTransformer:
694716 markFree(ref.readOnly, tree)
695717 else
696718 val sel = ref.select(pt.select.symbol).asInstanceOf [TermRef ]
697- sel.recomputeDenot()
698- // We need to do a recomputeDenot here since we have not yet properly
699- // computed the type of the full path. This means that we erroneously
700- // think the denotation is the same as in the previous phase so no
701- // member computation is performed. A test case where this matters is
702- // read-only-use.scala, where the error on r3 goes unreported.
703719 markPathFree(sel, pt.pt, pt.select)
704720 case _ =>
705721 markFree(ref.adjustReadOnly(pt), tree)
@@ -1114,11 +1130,11 @@ class CheckCaptures extends Recheck, SymTransformer:
11141130 if sym.is(Module ) then sym.info // Modules are checked by checking the module class
11151131 else
11161132 if sym.is(Mutable ) && ! sym.hasAnnotation(defn.UncheckedCapturesAnnot ) then
1117- val addendum = capturedBy.get(sym) match
1133+ val addendum = setup. capturedBy.get(sym) match
11181134 case Some (encl) =>
11191135 val enclStr =
11201136 if encl.isAnonymousFunction then
1121- val location = anonFunCallee.get(encl) match
1137+ val location = setup. anonFunCallee.get(encl) match
11221138 case Some (meth) if meth.exists => i " argument in a call to $meth"
11231139 case _ => " "
11241140 s " an anonymous function $location"
@@ -1943,49 +1959,12 @@ class CheckCaptures extends Recheck, SymTransformer:
19431959 traverseChildren(t)
19441960 end checkOverrides
19451961
1946- /** Used for error reporting:
1947- * Maps mutable variables to the symbols that capture them (in the
1948- * CheckCaptures sense, i.e. symbol is referred to from a different method
1949- * than the one it is defined in).
1950- */
1951- private val capturedBy = util.HashMap [Symbol , Symbol ]()
1952-
1953- /** Used for error reporting:
1954- * Maps anonymous functions appearing as function arguments to
1955- * the function that is called.
1956- */
1957- private val anonFunCallee = util.HashMap [Symbol , Symbol ]()
1958-
1959- /** Used for error reporting:
1960- * Populates `capturedBy` and `anonFunCallee`. Called by `checkUnit`.
1961- */
1962- private def collectCapturedMutVars (using Context ) = new TreeTraverser :
1963- def traverse (tree : Tree )(using Context ) = tree match
1964- case id : Ident =>
1965- val sym = id.symbol
1966- if sym.isMutableVar && sym.owner.isTerm then
1967- val enclMeth = ctx.owner.enclosingMethod
1968- if sym.enclosingMethod != enclMeth then
1969- capturedBy(sym) = enclMeth
1970- case Apply (fn, args) =>
1971- for case closureDef(mdef) <- args do
1972- anonFunCallee(mdef.symbol) = fn.symbol
1973- traverseChildren(tree)
1974- case Inlined (_, bindings, expansion) =>
1975- traverse(bindings)
1976- traverse(expansion)
1977- case mdef : DefDef =>
1978- if ! mdef.symbol.isInlineMethod then traverseChildren(tree)
1979- case _ =>
1980- traverseChildren(tree)
1981-
19821962 private val setup : SetupAPI = thisPhase.prev.asInstanceOf [Setup ]
19831963
19841964 override def checkUnit (unit : CompilationUnit )(using Context ): Unit =
19851965 capt.println(i " cc check ${unit.source}" )
19861966 ccState.start()
19871967 setup.setupUnit(unit.tpdTree, this )
1988- collectCapturedMutVars.traverse(unit.tpdTree)
19891968
19901969 if ctx.settings.YccPrintSetup .value then
19911970 val echoHeader = " [[syntax tree at end of cc setup]]"
0 commit comments