Skip to content

Commit 9d990fb

Browse files
authored
Drop retains annotations in inferred type trees (scala#20057)
2 parents d71a347 + 98cbe06 commit 9d990fb

File tree

4 files changed

+38
-3
lines changed

4 files changed

+38
-3
lines changed

compiler/src/dotty/tools/dotc/cc/CaptureOps.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,14 @@ extension (tp: AnnotatedType)
445445
case ann: CaptureAnnotation => ann.boxed
446446
case _ => false
447447

448+
/** Drop retains annotations in the type. */
449+
class CleanupRetains(using Context) extends TypeMap:
450+
def apply(tp: Type): Type =
451+
tp match
452+
case AnnotatedType(tp, annot) if annot.symbol == defn.RetainsAnnot || annot.symbol == defn.RetainsByNameAnnot =>
453+
RetainingType(tp, Nil, byName = annot.symbol == defn.RetainsByNameAnnot)
454+
case _ => mapOver(tp)
455+
448456
/** An extractor for `caps.reachCapability(ref)`, which is used to express a reach
449457
* capability as a tree in a @retains annotation.
450458
*/

compiler/src/dotty/tools/dotc/transform/PostTyper.scala

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import config.Feature
1919
import util.SrcPos
2020
import reporting.*
2121
import NameKinds.WildcardParamName
22+
import cc.*
2223

2324
object PostTyper {
2425
val name: String = "posttyper"
@@ -279,6 +280,21 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase =>
279280
if !tree.symbol.is(Package) then tree
280281
else errorTree(tree, em"${tree.symbol} cannot be used as a type")
281282

283+
// Cleans up retains annotations in inferred type trees. This is needed because
284+
// during the typer, it is infeasible to correctly infer the capture sets in most
285+
// cases, resulting ill-formed capture sets that could crash the pickler later on.
286+
// See #20035.
287+
private def cleanupRetainsAnnot(symbol: Symbol, tpt: Tree)(using Context): Tree =
288+
tpt match
289+
case tpt: InferredTypeTree
290+
if !symbol.allOverriddenSymbols.hasNext =>
291+
// if there are overridden symbols, the annotation comes from an explicit type of the overridden symbol
292+
// and should be retained.
293+
val tm = new CleanupRetains
294+
val tpe1 = tm(tpt.tpe)
295+
tpt.withType(tpe1)
296+
case _ => tpt
297+
282298
override def transform(tree: Tree)(using Context): Tree =
283299
try tree match {
284300
// TODO move CaseDef case lower: keep most probable trees first for performance
@@ -388,7 +404,7 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase =>
388404
registerIfHasMacroAnnotations(tree)
389405
checkErasedDef(tree)
390406
Checking.checkPolyFunctionType(tree.tpt)
391-
val tree1 = cpy.ValDef(tree)(rhs = normalizeErasedRhs(tree.rhs, tree.symbol))
407+
val tree1 = cpy.ValDef(tree)(tpt = cleanupRetainsAnnot(tree.symbol, tree.tpt), rhs = normalizeErasedRhs(tree.rhs, tree.symbol))
392408
if tree1.removeAttachment(desugar.UntupledParam).isDefined then
393409
checkStableSelection(tree.rhs)
394410
processValOrDefDef(super.transform(tree1))
@@ -398,7 +414,7 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase =>
398414
checkErasedDef(tree)
399415
Checking.checkPolyFunctionType(tree.tpt)
400416
annotateContextResults(tree)
401-
val tree1 = cpy.DefDef(tree)(rhs = normalizeErasedRhs(tree.rhs, tree.symbol))
417+
val tree1 = cpy.DefDef(tree)(tpt = cleanupRetainsAnnot(tree.symbol, tree.tpt), rhs = normalizeErasedRhs(tree.rhs, tree.symbol))
402418
processValOrDefDef(superAcc.wrapDefDef(tree1)(super.transform(tree1).asInstanceOf[DefDef]))
403419
case tree: TypeDef =>
404420
registerIfHasMacroAnnotations(tree)

tests/neg-custom-args/captures/byname.check

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
| Found: (x$0: Int) ->{cap2} Int
1010
| Required: (x$0: Int) -> Int
1111
|
12-
| Note that the expected type Int => Int
12+
| Note that the expected type Int ->{} Int
1313
| is the previously inferred result type of method test
1414
| which is also the type seen in separately compiled sources.
1515
| The new inferred type (x$0: Int) ->{cap2} Int
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import language.experimental.captureChecking
2+
3+
trait Seq[+A]:
4+
def zipAll[A1 >: A, B](that: Seq[B]^, thisElem: A1, thatElem: B): Seq[(A1, B)]^{this, that}
5+
def map[B](f: A => B): Seq[B]^{this, f}
6+
7+
def zipAllOption[X](left: Seq[X], right: Seq[X]) =
8+
left.map(Option(_)).zipAll(right.map(Option(_)), None, None)
9+
10+
def fillRow[T](headRow: Seq[T], tailRow: Seq[T]) =
11+
val paddedZip = zipAllOption(headRow, tailRow)

0 commit comments

Comments
 (0)