Skip to content

Commit 00badaa

Browse files
committed
Avoid awkward special cases when type mapping AnnotatedTypes
A TypeMap previously mapped the annotation only if it returned a different result for the parent type. There is no good reason for this behavior. We now map always, but allow the mapping operation to be defined in the annotation. The change uncovers a bug illustrated in annotDepMethType.scala, which is fixed in the next commit.
1 parent 8e06c68 commit 00badaa

File tree

4 files changed

+41
-16
lines changed

4 files changed

+41
-16
lines changed

compiler/src/dotty/tools/dotc/ast/TreeInfo.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -113,11 +113,11 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] =>
113113
case _ => 0
114114
}
115115

116-
/** The (last) list of arguments of an application */
117-
def arguments(tree: Tree): List[Tree] = unsplice(tree) match {
118-
case Apply(_, args) => args
119-
case TypeApply(fn, _) => arguments(fn)
120-
case Block(_, expr) => arguments(expr)
116+
/** All term arguments of an application in a single flattened list */
117+
def allArguments(tree: Tree): List[Tree] = unsplice(tree) match {
118+
case Apply(fn, args) => allArguments(fn) ::: args
119+
case TypeApply(fn, _) => allArguments(fn)
120+
case Block(_, expr) => allArguments(expr)
121121
case _ => Nil
122122
}
123123

compiler/src/dotty/tools/dotc/core/Annotations.scala

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import scala.util.Try
99
import util.Spans.Span
1010
import printing.{Showable, Printer}
1111
import printing.Texts.Text
12+
import annotation.internal.sharable
1213

1314
object Annotations {
1415

@@ -28,7 +29,8 @@ object Annotations {
2829
def derivedAnnotation(tree: Tree)(using Context): Annotation =
2930
if (tree eq this.tree) this else Annotation(tree)
3031

31-
def arguments(using Context): List[Tree] = ast.tpd.arguments(tree)
32+
/** All arguments to this annotation in a single flat list */
33+
def arguments(using Context): List[Tree] = ast.tpd.allArguments(tree)
3234

3335
def argument(i: Int)(using Context): Option[Tree] = {
3436
val args = arguments
@@ -46,6 +48,25 @@ object Annotations {
4648
/** The tree evaluation has finished. */
4749
def isEvaluated: Boolean = true
4850

51+
/** Normally, map type map over all tree nodes of this annotation, but can
52+
* be overridden. Returns EmptyAnnotation if type type map produces a range
53+
* type, since ranges cannot be types of trees.
54+
*/
55+
def mapWith(tm: TypeMap)(using Context) =
56+
val args = arguments
57+
if args.isEmpty then this
58+
else
59+
val findDiff = new TreeAccumulator[Type]:
60+
def apply(x: Type, tree: Tree)(using Context): Type =
61+
if tm.isRange(x) then x
62+
else
63+
val tp1 = tm(tree.tpe)
64+
foldOver(if tp1 =:= tree.tpe then x else tp1, tree)
65+
val diff = findDiff(NoType, args)
66+
if tm.isRange(diff) then EmptyAnnotation
67+
else if diff.exists then derivedAnnotation(tm.mapOver(tree))
68+
else this
69+
4970
/** A string representation of the annotation. Overridden in BodyAnnotation.
5071
*/
5172
def toText(printer: Printer): Text = printer.annotText(this)
@@ -200,6 +221,8 @@ object Annotations {
200221
apply(defn.SourceFileAnnot, Literal(Constant(path)))
201222
}
202223

224+
@sharable val EmptyAnnotation = Annotation(EmptyTree)
225+
203226
def ThrowsAnnotation(cls: ClassSymbol)(using Context): Annotation = {
204227
val tref = cls.typeRef
205228
Annotation(defn.ThrowsAnnot.typeRef.appliedTo(tref), Ident(tref))

compiler/src/dotty/tools/dotc/core/TypeOps.scala

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -162,9 +162,13 @@ object TypeOps:
162162
// with Nulls (which have no base classes). Under -Yexplicit-nulls, we take
163163
// corrective steps, so no widening is wanted.
164164
simplify(l, theMap) | simplify(r, theMap)
165-
case AnnotatedType(parent, annot)
166-
if annot.symbol == defn.UncheckedVarianceAnnot && !ctx.mode.is(Mode.Type) && !theMap.isInstanceOf[SimplifyKeepUnchecked] =>
167-
simplify(parent, theMap)
165+
case tp @ AnnotatedType(parent, annot) =>
166+
val parent1 = simplify(parent, theMap)
167+
if annot.symbol == defn.UncheckedVarianceAnnot
168+
&& !ctx.mode.is(Mode.Type)
169+
&& !theMap.isInstanceOf[SimplifyKeepUnchecked]
170+
then parent1
171+
else tp.derivedAnnotatedType(parent1, annot)
168172
case _: MatchType =>
169173
val normed = tp.tryNormalize
170174
if (normed.exists) normed else mapOver

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5380,6 +5380,8 @@ object Types {
53805380
variance = saved
53815381
derivedLambdaType(tp)(ptypes1, this(restpe))
53825382

5383+
def isRange(tp: Type): Boolean = tp.isInstanceOf[Range]
5384+
53835385
/** Map this function over given type */
53845386
def mapOver(tp: Type): Type = {
53855387
record(s"TypeMap mapOver ${getClass}")
@@ -5423,8 +5425,9 @@ object Types {
54235425

54245426
case tp @ AnnotatedType(underlying, annot) =>
54255427
val underlying1 = this(underlying)
5426-
if (underlying1 eq underlying) tp
5427-
else derivedAnnotatedType(tp, underlying1, mapOver(annot))
5428+
val annot1 = annot.mapWith(this)
5429+
if annot1 eq EmptyAnnotation then underlying1
5430+
else derivedAnnotatedType(tp, underlying1, annot1)
54285431

54295432
case _: ThisType
54305433
| _: BoundType
@@ -5496,9 +5499,6 @@ object Types {
54965499
else newScopeWith(elems1: _*)
54975500
}
54985501

5499-
def mapOver(annot: Annotation): Annotation =
5500-
annot.derivedAnnotation(mapOver(annot.tree))
5501-
55025502
def mapOver(tree: Tree): Tree = treeTypeMap(tree)
55035503

55045504
/** Can be overridden. By default, only the prefix is mapped. */
@@ -5545,8 +5545,6 @@ object Types {
55455545

55465546
protected def emptyRange = range(defn.NothingType, defn.AnyType)
55475547

5548-
protected def isRange(tp: Type): Boolean = tp.isInstanceOf[Range]
5549-
55505548
protected def lower(tp: Type): Type = tp match {
55515549
case tp: Range => tp.lo
55525550
case _ => tp

0 commit comments

Comments
 (0)