From d2081988a065bdb5a321e8f6f2bbf94bf9d71eab Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 25 Aug 2021 17:16:15 +0200 Subject: [PATCH] Handle Ranges in dependent annotations # Conflicts: # compiler/src/dotty/tools/dotc/core/Types.scala --- .../src/dotty/tools/dotc/core/Types.scala | 34 ++++++++++++------- tests/pos/dependent-annot.scala | 7 ++++ 2 files changed, 28 insertions(+), 13 deletions(-) create mode 100644 tests/pos/dependent-annot.scala diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 56659d6da74a..06011ffd37f7 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -5392,6 +5392,17 @@ object Types { variance = saved derivedLambdaType(tp)(ptypes1, this(restpe)) + protected def isRange(tp: Type): Boolean = tp.isInstanceOf[Range] + + private def diffType(ann: Tree): Type = + val acc = new TreeAccumulator[Type]: + def apply(x: Type, tree: Tree)(using Context): Type = + if isRange(x) then x + else + val tp1 = thisMap(tree.tpe) + foldOver(if tp1 =:= tree.tpe then x else tp1, tree) + acc(NoType, ann) + /** Map this function over given type */ def mapOver(tp: Type): Type = { record(s"TypeMap mapOver ${getClass}") @@ -5435,17 +5446,16 @@ object Types { case tp @ AnnotatedType(underlying, annot) => val underlying1 = this(underlying) - val annot1 = - if underlying1 ne underlying then mapOver(annot) - else annot match - case ConcreteAnnotation(ann) - if ann.existsSubTree { t => - val tpe = t.typeOpt - tpe.exists && !(this(tpe) =:= tpe) - } => mapOver(annot) - case _ => annot - if (underlying1 eq underlying) && (annot eq annot1) then tp - else derivedAnnotatedType(tp, underlying1, annot1) + if (underlying1 ne underlying) || annot.isInstanceOf[ConcreteAnnotation] then + val diff = diffType(annot.tree) + if isRange(diff) then + // Can't map a tree type to a Range, drop annotation instead + underlying1 + else + val annot1 = if diff.exists then mapOver(annot) else annot + derivedAnnotatedType(tp, underlying1, annot1) + else + derivedAnnotatedType(tp, underlying1, annot) case _: ThisType | _: BoundType @@ -5566,8 +5576,6 @@ object Types { protected def emptyRange = range(defn.NothingType, defn.AnyType) - protected def isRange(tp: Type): Boolean = tp.isInstanceOf[Range] - protected def lower(tp: Type): Type = tp match { case tp: Range => tp.lo case _ => tp diff --git a/tests/pos/dependent-annot.scala b/tests/pos/dependent-annot.scala new file mode 100644 index 000000000000..28f0f8bd59e6 --- /dev/null +++ b/tests/pos/dependent-annot.scala @@ -0,0 +1,7 @@ +class C +class ann(x: Any*) extends annotation.Annotation + +def f(y: C, z: C) = + def g(): C @ann(y, z) = ??? + val ac: ((x: C) => Array[String @ann(x)]) = ??? + val dc = ac(g())