From f2896413eff7413a4786d92a2d4aba57ee366150 Mon Sep 17 00:00:00 2001 From: Yichen Xu Date: Wed, 27 Mar 2024 15:19:15 +0100 Subject: [PATCH 1/2] Fix the mapping of term-dependent annotations --- compiler/src/dotty/tools/dotc/core/Annotations.scala | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Annotations.scala b/compiler/src/dotty/tools/dotc/core/Annotations.scala index 45dba97a79f7..8ff90d3ca9bc 100644 --- a/compiler/src/dotty/tools/dotc/core/Annotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Annotations.scala @@ -7,6 +7,7 @@ import ast.tpd, tpd.* import util.Spans.Span import printing.{Showable, Printer} import printing.Texts.Text +import cc.isRetainsLike import scala.annotation.internal.sharable @@ -65,7 +66,7 @@ object Annotations { foldOver(if tp1 frozen_=:= tree.tpe then x else tp1, tree) val diff = findDiff(NoType, args) if tm.isRange(diff) then EmptyAnnotation - else if diff.exists then derivedAnnotation(tm.mapOver(tree)) + else if diff.exists || symbol.isRetainsLike then derivedAnnotation(tm.mapOver(tree)) else this /** Does this annotation refer to a parameter of `tl`? */ @@ -73,9 +74,13 @@ object Annotations { val args = arguments if args.isEmpty then false else tree.existsSubTree: - case id: (Ident | This) => id.tpe.stripped match + case id: Ident => id.tpe.stripped match case TermParamRef(tl1, _) => tl eq tl1 case _ => false + case ref: This => ref.tpe match + case TermParamRef(tl1, _) => tl eq tl1 + case AnnotatedType(tp1, annot1) => annot1.refersToParamOf(tl) + case _ => false case _ => false /** A string representation of the annotation. Overridden in BodyAnnotation. From 9a3f20fd3c70a8b202ed79002fbfa6026a54ea58 Mon Sep 17 00:00:00 2001 From: Yichen Xu Date: Wed, 27 Mar 2024 17:19:33 +0100 Subject: [PATCH 2/2] Document the fix and add the test --- .../src/dotty/tools/dotc/core/Annotations.scala | 13 ++++++++++--- tests/pos-custom-args/captures/tablediff.scala | 11 +++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) create mode 100644 tests/pos-custom-args/captures/tablediff.scala diff --git a/compiler/src/dotty/tools/dotc/core/Annotations.scala b/compiler/src/dotty/tools/dotc/core/Annotations.scala index 8ff90d3ca9bc..558463618d81 100644 --- a/compiler/src/dotty/tools/dotc/core/Annotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Annotations.scala @@ -64,9 +64,13 @@ object Annotations { else val tp1 = tm(tree.tpe) foldOver(if tp1 frozen_=:= tree.tpe then x else tp1, tree) - val diff = findDiff(NoType, args) + val diff = if symbol.isRetainsLike then defn.AnyType else findDiff(NoType, args) + // If this is a @retains annotation, the diff check seems to be unreliable. + // We work around this issue by always mapping @retains annotations. See #20035. + // + // FIXME: investigate why the diff check is incorrect for @retains if tm.isRange(diff) then EmptyAnnotation - else if diff.exists || symbol.isRetainsLike then derivedAnnotation(tm.mapOver(tree)) + else if diff.exists then derivedAnnotation(tm.mapOver(tree)) else this /** Does this annotation refer to a parameter of `tl`? */ @@ -79,7 +83,10 @@ object Annotations { case _ => false case ref: This => ref.tpe match case TermParamRef(tl1, _) => tl eq tl1 - case AnnotatedType(tp1, annot1) => annot1.refersToParamOf(tl) + case AnnotatedType(tp1, annot1) => + // The type of captured elements in @retains annotation could themself + // refer to term parameters. See #20035. + annot1.refersToParamOf(tl) case _ => false case _ => false diff --git a/tests/pos-custom-args/captures/tablediff.scala b/tests/pos-custom-args/captures/tablediff.scala new file mode 100644 index 000000000000..244ee1a46a23 --- /dev/null +++ b/tests/pos-custom-args/captures/tablediff.scala @@ -0,0 +1,11 @@ +import language.experimental.captureChecking + +trait Seq[+A]: + def zipAll[A1 >: A, B](that: Seq[B]^, thisElem: A1, thatElem: B): Seq[(A1, B)]^{this, that} + def map[B](f: A => B): Seq[B]^{this, f} + +def zipAllOption[X](left: Seq[X], right: Seq[X]) = + left.map(Option(_)).zipAll(right.map(Option(_)), None, None) + +def fillRow[T](headRow: Seq[T], tailRow: Seq[T]) = + val paddedZip = zipAllOption(headRow, tailRow)