Skip to content

Commit 25ee50b

Browse files
authored
Merge pull request #4626 from dotty-staging/add-refining-annotations
Add refining annotations
2 parents 9d92d85 + dde7ce9 commit 25ee50b

18 files changed

+143
-60
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ object desugar {
7878
case tp: NamedType if tp.symbol.exists && (tp.symbol.owner eq originalOwner) =>
7979
val defctx = ctx.outersIterator.dropWhile(_.scope eq ctx.scope).next()
8080
var local = defctx.denotNamed(tp.name ++ suffix).suchThat(_.isParamOrAccessor).symbol
81-
if (local.exists) (defctx.owner.thisType select local).dealias
81+
if (local.exists) (defctx.owner.thisType select local).dealiasKeepAnnots
8282
else {
8383
def msg =
8484
s"no matching symbol for ${tp.symbol.showLocated} in ${defctx.owner} / ${defctx.effectiveScope.toList}"

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,31 @@ object Trees {
213213

214214
override def toText(printer: Printer) = printer.toText(this)
215215

216+
def sameTree(that: Tree[_]): Boolean = {
217+
def isSame(x: Any, y: Any): Boolean =
218+
x.asInstanceOf[AnyRef].eq(y.asInstanceOf[AnyRef]) || {
219+
x match {
220+
case x: Tree[_] =>
221+
y match {
222+
case y: Tree[_] => x.sameTree(y)
223+
case _ => false
224+
}
225+
case x: List[_] =>
226+
y match {
227+
case y: List[_] => x.corresponds(y)(isSame)
228+
case _ => false
229+
}
230+
case _ =>
231+
false
232+
}
233+
}
234+
this.getClass == that.getClass && {
235+
val it1 = this.productIterator
236+
val it2 = that.productIterator
237+
it1.corresponds(it2)(isSame)
238+
}
239+
}
240+
216241
override def hashCode(): Int = uniqueId // for debugging; was: System.identityHashCode(this)
217242
override def equals(that: Any) = this eq that.asInstanceOf[AnyRef]
218243

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -963,7 +963,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
963963
val alternatives = ctx.typer.resolveOverloaded(allAlts, proto)
964964
assert(alternatives.size == 1,
965965
i"${if (alternatives.isEmpty) "no" else "multiple"} overloads available for " +
966-
i"$method on ${receiver.tpe.widenDealias} with targs: $targs%, %; args: $args%, % of types ${args.tpes}%, %; expectedType: $expectedType." +
966+
i"$method on ${receiver.tpe.widenDealiasKeepAnnots} with targs: $targs%, %; args: $args%, % of types ${args.tpes}%, %; expectedType: $expectedType." +
967967
i" isAnnotConstructor = $isAnnotConstructor.\n" +
968968
i"all alternatives: ${allAlts.map(_.symbol.showDcl).mkString(", ")}\n" +
969969
i"matching alternatives: ${alternatives.map(_.symbol.showDcl).mkString(", ")}.") // this is parsed from bytecode tree. there's nothing user can do about it

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ object Annotations {
3434
def isEvaluated: Boolean = true
3535

3636
def ensureCompleted(implicit ctx: Context): Unit = tree
37+
38+
def sameAnnotation(that: Annotation)(implicit ctx: Context) =
39+
symbol == that.symbol && tree.sameTree(that.tree)
3740
}
3841

3942
case class ConcreteAnnotation(t: Tree) extends Annotation {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ trait ConstraintHandling {
275275
case tp: OrType => isFullyDefined(tp.tp1) && isFullyDefined(tp.tp2)
276276
case _ => true
277277
}
278-
def isOrType(tp: Type): Boolean = tp.stripTypeVar.dealias match {
278+
def isOrType(tp: Type): Boolean = tp.dealias match {
279279
case tp: OrType => true
280280
case tp: RefinedOrRecType => isOrType(tp.parent)
281281
case AndType(tp1, tp2) => isOrType(tp1) | isOrType(tp2)

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,8 @@ class Definitions {
694694
def ClassfileAnnotationClass(implicit ctx: Context) = ClassfileAnnotationType.symbol.asClass
695695
lazy val StaticAnnotationType = ctx.requiredClassRef("scala.annotation.StaticAnnotation")
696696
def StaticAnnotationClass(implicit ctx: Context) = StaticAnnotationType.symbol.asClass
697+
lazy val RefiningAnnotationType = ctx.requiredClassRef("scala.annotation.RefiningAnnotation")
698+
def RefiningAnnotationClass(implicit ctx: Context) = RefiningAnnotationType.symbol.asClass
697699

698700
// Annotation classes
699701
lazy val AliasAnnotType = ctx.requiredClassRef("scala.annotation.internal.Alias")

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
387387
* that are not top-level are not affected.
388388
*/
389389
def replace(param: TypeParamRef, tp: Type)(implicit ctx: Context): OrderingConstraint = {
390-
val replacement = tp.dealias.stripTypeVar
390+
val replacement = tp.dealiasKeepAnnots.stripTypeVar
391391
if (param == replacement) this
392392
else {
393393
assert(replacement.isValueTypeOrLambda)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1208,7 +1208,7 @@ object SymDenotations {
12081208
case tp: LambdaType => tp.paramInfos.exists(hasSkolems) || hasSkolems(tp.resType)
12091209
case tp: AndType => hasSkolems(tp.tp1) || hasSkolems(tp.tp2)
12101210
case tp: OrType => hasSkolems(tp.tp1) || hasSkolems(tp.tp2)
1211-
case tp: AnnotatedType => hasSkolems(tp.tpe)
1211+
case tp: AnnotatedType => hasSkolems(tp.parent)
12121212
case _ => false
12131213
}
12141214

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

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -236,8 +236,8 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
236236
compareWild
237237
case tp2: LazyRef =>
238238
!tp2.evaluating && recur(tp1, tp2.ref)
239-
case tp2: AnnotatedType =>
240-
recur(tp1, tp2.tpe) // todo: refine?
239+
case tp2: AnnotatedType if !tp2.isRefining =>
240+
recur(tp1, tp2.parent)
241241
case tp2: ThisType =>
242242
def compareThis = {
243243
val cls2 = tp2.cls
@@ -345,13 +345,13 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
345345
// because that would cause an assertionError. Return false instead.
346346
// See i859.scala for an example where we hit this case.
347347
!tp1.evaluating && recur(tp1.ref, tp2)
348-
case tp1: AnnotatedType =>
349-
recur(tp1.tpe, tp2)
348+
case tp1: AnnotatedType if !tp1.isRefining =>
349+
recur(tp1.parent, tp2)
350350
case AndType(tp11, tp12) =>
351351
if (tp11.stripTypeVar eq tp12.stripTypeVar) recur(tp11, tp2)
352352
else thirdTry
353353
case tp1 @ OrType(tp11, tp12) =>
354-
def joinOK = tp2.dealias match {
354+
def joinOK = tp2.dealiasKeepRefiningAnnots match {
355355
case tp2: AppliedType if !tp2.tycon.typeSymbol.isClass =>
356356
// If we apply the default algorithm for `A[X] | B[Y] <: C[Z]` where `C` is a
357357
// type parameter, we will instantiate `C` to `A` and then fail when comparing
@@ -510,7 +510,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
510510
}
511511
compareTypeLambda
512512
case OrType(tp21, tp22) =>
513-
val tp1a = tp1.widenDealias
513+
val tp1a = tp1.widenDealiasKeepRefiningAnnots
514514
if (tp1a ne tp1)
515515
// Follow the alias; this might avoid truncating the search space in the either below
516516
// Note that it's safe to widen here because singleton types cannot be part of `|`.
@@ -567,6 +567,9 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
567567
false
568568
}
569569
compareTypeBounds
570+
case tp2: AnnotatedType if tp2.isRefining =>
571+
(tp1.derivesAnnotWith(tp2.annot.sameAnnotation) || defn.isBottomType(tp1)) &&
572+
recur(tp1, tp2.parent)
570573
case ClassInfo(pre2, cls2, _, _, _) =>
571574
def compareClassInfo = tp1 match {
572575
case ClassInfo(pre1, cls1, _, _, _) =>
@@ -641,7 +644,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
641644
}
642645
compareHKLambda
643646
case AndType(tp11, tp12) =>
644-
val tp2a = tp2.dealias
647+
val tp2a = tp2.dealiasKeepRefiningAnnots
645648
if (tp2a ne tp2) // Follow the alias; this might avoid truncating the search space in the either below
646649
return recur(tp1, tp2a)
647650

@@ -661,6 +664,8 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
661664
case _ =>
662665
}
663666
either(recur(tp11, tp2), recur(tp12, tp2))
667+
case tp1: AnnotatedType if tp1.isRefining =>
668+
isNewSubType(tp1.parent)
664669
case JavaArrayType(elem1) =>
665670
def compareJavaArray = tp2 match {
666671
case JavaArrayType(elem2) => isSubType(elem1, elem2)
@@ -685,13 +690,13 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
685690
*/
686691
def isMatchingApply(tp1: Type): Boolean = tp1 match {
687692
case AppliedType(tycon1, args1) =>
688-
tycon1.dealias match {
693+
tycon1.dealiasKeepRefiningAnnots match {
689694
case tycon1: TypeParamRef =>
690695
(tycon1 == tycon2 ||
691696
canConstrain(tycon1) && tryInstantiate(tycon1, tycon2)) &&
692697
isSubArgs(args1, args2, tp1, tparams)
693698
case tycon1: TypeRef =>
694-
tycon2.dealias match {
699+
tycon2.dealiasKeepRefiningAnnots match {
695700
case tycon2: TypeRef if tycon1.symbol == tycon2.symbol =>
696701
isSubType(tycon1.prefix, tycon2.prefix) &&
697702
isSubArgs(args1, args2, tp1, tparams)
@@ -700,7 +705,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
700705
}
701706
case tycon1: TypeVar =>
702707
isMatchingApply(tycon1.underlying)
703-
case tycon1: AnnotatedType =>
708+
case tycon1: AnnotatedType if !tycon1.isRefining =>
704709
isMatchingApply(tycon1.underlying)
705710
case _ =>
706711
false
@@ -811,7 +816,9 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
811816
fourthTry
812817
}
813818
}
814-
case _: TypeVar | _: AnnotatedType =>
819+
case _: TypeVar =>
820+
recur(tp1, tp2.superType)
821+
case tycon2: AnnotatedType if !tycon2.isRefining =>
815822
recur(tp1, tp2.superType)
816823
case tycon2: AppliedType =>
817824
fallback(tycon2.lowerBound)
@@ -1097,11 +1104,10 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
10971104
* is some combination of TypeRefs that point to classes, where the
10981105
* combiners are AppliedTypes, RefinedTypes, RecTypes, And/Or-Types or AnnotatedTypes.
10991106
*/
1100-
private def isCovered(tp: Type): Boolean = tp.dealias.stripTypeVar match {
1107+
private def isCovered(tp: Type): Boolean = tp.dealiasKeepRefiningAnnots.stripTypeVar match {
11011108
case tp: TypeRef => tp.symbol.isClass && tp.symbol != NothingClass && tp.symbol != NullClass
11021109
case tp: AppliedType => isCovered(tp.tycon)
11031110
case tp: RefinedOrRecType => isCovered(tp.parent)
1104-
case tp: AnnotatedType => isCovered(tp.underlying)
11051111
case tp: AndType => isCovered(tp.tp1) && isCovered(tp.tp2)
11061112
case tp: OrType => isCovered(tp.tp1) && isCovered(tp.tp2)
11071113
case _ => false
@@ -1546,7 +1552,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
15461552
}
15471553
case tp1: TypeVar if tp1.isInstantiated =>
15481554
tp1.underlying & tp2
1549-
case tp1: AnnotatedType =>
1555+
case tp1: AnnotatedType if !tp1.isRefining =>
15501556
tp1.underlying & tp2
15511557
case _ =>
15521558
NoType
@@ -1565,7 +1571,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
15651571
ExprType(rt1 | tp2.widenExpr)
15661572
case tp1: TypeVar if tp1.isInstantiated =>
15671573
tp1.underlying | tp2
1568-
case tp1: AnnotatedType =>
1574+
case tp1: AnnotatedType if !tp1.isRefining =>
15691575
tp1.underlying | tp2
15701576
case _ =>
15711577
NoType

0 commit comments

Comments
 (0)