Skip to content

Commit 75ff6db

Browse files
committed
Improve mapping TypeMaps over annotations
Remove hardwired references to ConcreteAnnotation and simplify the logic in TypeMap. # Conflicts: # compiler/src/dotty/tools/dotc/core/Annotations.scala # compiler/src/dotty/tools/dotc/core/Types.scala
1 parent 3ae89f6 commit 75ff6db

File tree

2 files changed

+65
-32
lines changed

2 files changed

+65
-32
lines changed

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

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,17 @@ import StdNames._
77
import dotty.tools.dotc.ast.tpd
88
import scala.util.Try
99
import util.Spans.Span
10+
import printing.{Showable, Printer, Texts}
11+
import Texts.{Text, Str}
12+
import annotation.internal.sharable
1013

1114
object Annotations {
1215

1316
def annotClass(tree: Tree)(using Context) =
1417
if (tree.symbol.isConstructor) tree.symbol.owner
1518
else tree.tpe.typeSymbol
1619

17-
abstract class Annotation {
20+
abstract class Annotation extends Showable {
1821
def tree(using Context): Tree
1922

2023
def symbol(using Context): Symbol = annotClass(tree)
@@ -44,6 +47,34 @@ object Annotations {
4447
/** The tree evaluation has finished. */
4548
def isEvaluated: Boolean = true
4649

50+
/** The annotation should be part of mappings?
51+
* Currently overridden only in ConcreteAnnotation, which simulates the previous behavior.
52+
*/
53+
def isMappable: Boolean = false
54+
55+
/** Normally, map type map over all tree nodes of this annotation, but can
56+
* be overridden. Returns EmptyAnnotation if type type map produces a range
57+
* type, since ranges cannot be types of trees.
58+
*/
59+
def mapWith(tm: TypeMap)(using Context) =
60+
val findDiff = new TreeAccumulator[Type]:
61+
def apply(x: Type, tree: Tree)(using Context): Type =
62+
if tm.isRange(x) then x
63+
else
64+
val tp1 = tm(tree.tpe)
65+
foldOver(if tp1 =:= tree.tpe then x else tp1, tree)
66+
val diff = findDiff(NoType, tree)
67+
if tm.isRange(diff) then EmptyAnnotation
68+
else if diff.exists then derivedAnnotation(tm.mapOver(tree))
69+
else this
70+
71+
/** A string representation of the annotation.
72+
*/
73+
final def toText(printer: Printer): Text = printer.toText(this)
74+
75+
/** A text representing thge arguments of this annotation. Overridden in ConcreteAnnotation */
76+
def argsText(printer: Printer): Text = ""
77+
4778
def ensureCompleted(using Context): Unit = tree
4879

4980
def sameAnnotation(that: Annotation)(using Context): Boolean =
@@ -52,6 +83,20 @@ object Annotations {
5283

5384
case class ConcreteAnnotation(t: Tree) extends Annotation {
5485
def tree(using Context): Tree = t
86+
override def isMappable = true
87+
override def argsText(printer: Printer): Text =
88+
def toTextArg(arg: Tree): Text = arg match
89+
case Typed(SeqLiteral(elems, _), _) => printer.toTextGlobal(elems, ", ")
90+
case _ => printer.toText(arg)
91+
def recur(tree: Tree): Text = tree match
92+
case TypeApply(fn, args) =>
93+
recur(fn) ~ "[" ~ printer.toTextGlobal(args, ", ") ~ "]"
94+
case Apply(fn, args) =>
95+
recur(fn)
96+
~ (Str("(") ~ Text(args.map(toTextArg), ", ") ~ ")" provided args.nonEmpty)
97+
case _ =>
98+
""
99+
recur(t)
55100
}
56101

57102
abstract class LazyAnnotation extends Annotation {
@@ -194,6 +239,8 @@ object Annotations {
194239
apply(defn.SourceFileAnnot, Literal(Constant(path)))
195240
}
196241

242+
@sharable val EmptyAnnotation = Annotation(EmptyTree)
243+
197244
def ThrowsAnnotation(cls: ClassSymbol)(using Context): Annotation = {
198245
val tref = cls.typeRef
199246
Annotation(defn.ThrowsAnnot.typeRef.appliedTo(tref), Ident(tref))

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

Lines changed: 17 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3579,13 +3579,15 @@ object Types {
35793579
private var myDependencyStatus: DependencyStatus = Unknown
35803580
private var myParamDependencyStatus: DependencyStatus = Unknown
35813581

3582-
private def refersToParam(tree: Tree)(using Context): Boolean =
3583-
tree.existsSubTree {
3584-
case id: Ident => id.tpe match
3585-
case TermParamRef(`thisLambdaType`, _) => true
3582+
private def refersToParam(ann: Annotation)(using Context): Boolean = ann match
3583+
case ConcreteAnnotation(tree) =>
3584+
tree.existsSubTree {
3585+
case id: Ident => id.tpe match
3586+
case TermParamRef(`thisLambdaType`, _) => true
3587+
case _ => false
35863588
case _ => false
3587-
case _ => false
3588-
}
3589+
}
3590+
case _ => false
35893591

35903592
private def depStatus(initial: DependencyStatus, tp: Type)(using Context): DependencyStatus =
35913593
class DepAcc extends TypeAccumulator[DependencyStatus]:
@@ -3612,7 +3614,7 @@ object Types {
36123614
case tp: AppliedType => tp.fold(status, compute(_, _, theAcc))
36133615
case tp: TypeVar if !tp.isInstantiated => combine(status, Provisional)
36143616
case tp: TermParamRef if tp.binder eq thisLambdaType => TrueDeps
3615-
case AnnotatedType(parent, ConcreteAnnotation(ann)) =>
3617+
case AnnotatedType(parent, ann) =>
36163618
if refersToParam(ann) then TrueDeps else compute(status, parent, theAcc)
36173619
case _: ThisType | _: BoundType | NoPrefix => status
36183620
case _ =>
@@ -3668,7 +3670,7 @@ object Types {
36683670
def apply(tp: Type) = tp match {
36693671
case tp @ TermParamRef(`thisLambdaType`, _) =>
36703672
range(defn.NothingType, atVariance(1)(apply(tp.underlying)))
3671-
case AnnotatedType(parent, ConcreteAnnotation(ann)) if refersToParam(ann) =>
3673+
case AnnotatedType(parent, ann) if refersToParam(ann) =>
36723674
mapOver(parent)
36733675
case _ => mapOver(tp)
36743676
}
@@ -5392,16 +5394,7 @@ object Types {
53925394
variance = saved
53935395
derivedLambdaType(tp)(ptypes1, this(restpe))
53945396

5395-
protected def isRange(tp: Type): Boolean = tp.isInstanceOf[Range]
5396-
5397-
private def diffType(ann: Tree): Type =
5398-
val acc = new TreeAccumulator[Type]:
5399-
def apply(x: Type, tree: Tree)(using Context): Type =
5400-
if isRange(x) then x
5401-
else
5402-
val tp1 = thisMap(tree.tpe)
5403-
foldOver(if tp1 =:= tree.tpe then x else tp1, tree)
5404-
acc(NoType, ann)
5397+
def isRange(tp: Type): Boolean = tp.isInstanceOf[Range]
54055398

54065399
/** Map this function over given type */
54075400
def mapOver(tp: Type): Type = {
@@ -5446,16 +5439,12 @@ object Types {
54465439

54475440
case tp @ AnnotatedType(underlying, annot) =>
54485441
val underlying1 = this(underlying)
5449-
if (underlying1 ne underlying) || annot.isInstanceOf[ConcreteAnnotation] then
5450-
val diff = diffType(annot.tree)
5451-
if isRange(diff) then
5452-
// Can't map a tree type to a Range, drop annotation instead
5453-
underlying1
5454-
else
5455-
val annot1 = if diff.exists then mapOver(annot) else annot
5456-
derivedAnnotatedType(tp, underlying1, annot1)
5457-
else
5458-
derivedAnnotatedType(tp, underlying1, annot)
5442+
val annot1 =
5443+
if (underlying1 ne underlying) || annot.isMappable
5444+
then annot.mapWith(this)
5445+
else annot
5446+
if annot1 eq EmptyAnnotation then underlying1
5447+
else derivedAnnotatedType(tp, underlying1, annot1)
54595448

54605449
case _: ThisType
54615450
| _: BoundType
@@ -5527,9 +5516,6 @@ object Types {
55275516
else newScopeWith(elems1: _*)
55285517
}
55295518

5530-
def mapOver(annot: Annotation): Annotation =
5531-
annot.derivedAnnotation(mapOver(annot.tree))
5532-
55335519
def mapOver(tree: Tree): Tree = treeTypeMap(tree)
55345520

55355521
/** Can be overridden. By default, only the prefix is mapped. */

0 commit comments

Comments
 (0)