Skip to content

Commit 10b59f8

Browse files
committed
Refine dealiasing operations
- some keep their annotations - some only keep refining annotations - most of them still strip all annotations
1 parent 4800cef commit 10b59f8

File tree

10 files changed

+58
-39
lines changed

10 files changed

+58
-39
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/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/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/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/TypeComparer.scala

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
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 `|`.
@@ -644,7 +644,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
644644
}
645645
compareHKLambda
646646
case AndType(tp11, tp12) =>
647-
val tp2a = tp2.dealias
647+
val tp2a = tp2.dealiasKeepRefiningAnnots
648648
if (tp2a ne tp2) // Follow the alias; this might avoid truncating the search space in the either below
649649
return recur(tp1, tp2a)
650650

@@ -690,13 +690,13 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
690690
*/
691691
def isMatchingApply(tp1: Type): Boolean = tp1 match {
692692
case AppliedType(tycon1, args1) =>
693-
tycon1.dealias match {
693+
tycon1.dealiasKeepRefiningAnnots match {
694694
case tycon1: TypeParamRef =>
695695
(tycon1 == tycon2 ||
696696
canConstrain(tycon1) && tryInstantiate(tycon1, tycon2)) &&
697697
isSubArgs(args1, args2, tp1, tparams)
698698
case tycon1: TypeRef =>
699-
tycon2.dealias match {
699+
tycon2.dealiasKeepRefiningAnnots match {
700700
case tycon2: TypeRef if tycon1.symbol == tycon2.symbol =>
701701
isSubType(tycon1.prefix, tycon2.prefix) &&
702702
isSubArgs(args1, args2, tp1, tparams)
@@ -1104,11 +1104,10 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
11041104
* is some combination of TypeRefs that point to classes, where the
11051105
* combiners are AppliedTypes, RefinedTypes, RecTypes, And/Or-Types or AnnotatedTypes.
11061106
*/
1107-
private def isCovered(tp: Type): Boolean = tp.dealias.stripTypeVar match {
1107+
private def isCovered(tp: Type): Boolean = tp.dealiasKeepRefiningAnnots.stripTypeVar match {
11081108
case tp: TypeRef => tp.symbol.isClass && tp.symbol != NothingClass && tp.symbol != NullClass
11091109
case tp: AppliedType => isCovered(tp.tycon)
11101110
case tp: RefinedOrRecType => isCovered(tp.parent)
1111-
case tp: AnnotatedType => isCovered(tp.underlying)
11121111
case tp: AndType => isCovered(tp.tp1) && isCovered(tp.tp2)
11131112
case tp: OrType => isCovered(tp.tp1) && isCovered(tp.tp2)
11141113
case _ => false

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

Lines changed: 44 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -931,6 +931,11 @@ object Types {
931931
*/
932932
def stripAnnots(implicit ctx: Context): Type = this
933933

934+
def rewrapAnnots(tp: Type)(implicit ctx: Context): Type = tp.stripTypeVar match {
935+
case AnnotatedType(tp1, annot) => AnnotatedType(rewrapAnnots(tp1), annot)
936+
case _ => this
937+
}
938+
934939
/** Strip PolyType prefix */
935940
def stripPoly(implicit ctx: Context): Type = this match {
936941
case tp: PolyType => tp.resType.stripPoly
@@ -1017,48 +1022,57 @@ object Types {
10171022
this
10181023
}
10191024

1020-
private def dealias1(keepAnnots: Boolean)(implicit ctx: Context): Type = this match {
1025+
private def dealias1(keep: AnnotatedType => Context => Boolean)(implicit ctx: Context): Type = this match {
10211026
case tp: TypeRef =>
10221027
if (tp.symbol.isClass) tp
10231028
else tp.info match {
1024-
case TypeAlias(alias) => alias.dealias1(keepAnnots): @tailrec
1029+
case TypeAlias(alias) => alias.dealias1(keep): @tailrec
10251030
case _ => tp
10261031
}
10271032
case app @ AppliedType(tycon, args) =>
1028-
val tycon1 = tycon.dealias1(keepAnnots)
1029-
if (tycon1 ne tycon) app.superType.dealias1(keepAnnots): @tailrec
1033+
val tycon1 = tycon.dealias1(keep)
1034+
if (tycon1 ne tycon) app.superType.dealias1(keep): @tailrec
10301035
else this
10311036
case tp: TypeVar =>
10321037
val tp1 = tp.instanceOpt
1033-
if (tp1.exists) tp1.dealias1(keepAnnots): @tailrec else tp
1038+
if (tp1.exists) tp1.dealias1(keep): @tailrec else tp
10341039
case tp: AnnotatedType =>
1035-
val tp1 = tp.tpe.dealias1(keepAnnots)
1036-
if (keepAnnots) tp.derivedAnnotatedType(tp1, tp.annot) else tp1
1040+
val tp1 = tp.tpe.dealias1(keep)
1041+
if (keep(tp)(ctx)) tp.derivedAnnotatedType(tp1, tp.annot) else tp1
10371042
case tp: LazyRef =>
1038-
tp.ref.dealias1(keepAnnots): @tailrec
1043+
tp.ref.dealias1(keep): @tailrec
10391044
case _ => this
10401045
}
10411046

1047+
/** Follow aliases and dereferences LazyRefs, annotated types and instantiated
1048+
* TypeVars until type is no longer alias type, annotated type, LazyRef,
1049+
* or instantiated type variable.
1050+
*/
1051+
final def dealias(implicit ctx: Context): Type = dealias1(keepNever)
1052+
10421053
/** Follow aliases and dereferences LazyRefs and instantiated TypeVars until type
10431054
* is no longer alias type, LazyRef, or instantiated type variable.
10441055
* Goes through annotated types and rewraps annotations on the result.
10451056
*/
1046-
final def dealiasKeepAnnots(implicit ctx: Context): Type =
1047-
dealias1(keepAnnots = true)
1057+
final def dealiasKeepAnnots(implicit ctx: Context): Type = dealias1(keepAlways)
10481058

1049-
/** Follow aliases and dereferences LazyRefs, annotated types and instantiated
1050-
* TypeVars until type is no longer alias type, annotated type, LazyRef,
1051-
* or instantiated type variable.
1052-
*/
1053-
final def dealias(implicit ctx: Context): Type =
1054-
dealias1(keepAnnots = false)
1059+
/** Like `dealiasKeepAnnots`, but keeps only refining annotations */
1060+
final def dealiasKeepRefiningAnnots(implicit ctx: Context): Type = dealias1(keepIfRefining)
10551061

1056-
/** Perform successive widenings and dealiasings until none can be applied anymore */
1057-
@tailrec final def widenDealias(implicit ctx: Context): Type = {
1058-
val res = this.widen.dealias
1059-
if (res eq this) res else res.widenDealias
1062+
private def widenDealias1(keep: AnnotatedType => Context => Boolean)(implicit ctx: Context): Type = {
1063+
val res = this.widen.dealias1(keep)
1064+
if (res eq this) res else res.widenDealias1(keep)
10601065
}
10611066

1067+
/** Perform successive widenings and dealiasings until none can be applied anymore */
1068+
final def widenDealias(implicit ctx: Context): Type = widenDealias1(keepNever)
1069+
1070+
/** Perform successive widenings and dealiasings while rewrapping annotations, until none can be applied anymore */
1071+
final def widenDealiasKeepAnnots(implicit ctx: Context): Type = widenDealias1(keepAlways)
1072+
1073+
/** Perform successive widenings and dealiasings while rewrapping refining annotations, until none can be applied anymore */
1074+
final def widenDealiasKeepRefiningAnnots(implicit ctx: Context): Type = widenDealias1(keepIfRefining)
1075+
10621076
/** Widen from constant type to its underlying non-constant
10631077
* base type.
10641078
*/
@@ -1805,8 +1819,8 @@ object Types {
18051819
case arg: TypeBounds =>
18061820
val v = param.paramVariance
18071821
val pbounds = param.paramInfo
1808-
if (v > 0 && pbounds.loBound.dealias.isBottomType) TypeAlias(arg.hiBound & rebase(pbounds.hiBound))
1809-
else if (v < 0 && pbounds.hiBound.dealias.isTopType) TypeAlias(arg.loBound | rebase(pbounds.loBound))
1822+
if (v > 0 && pbounds.loBound.dealiasKeepAnnots.isBottomType) TypeAlias(arg.hiBound & rebase(pbounds.hiBound))
1823+
else if (v < 0 && pbounds.hiBound.dealiasKeepAnnots.isTopType) TypeAlias(arg.loBound | rebase(pbounds.loBound))
18101824
else arg recoverable_& rebase(pbounds)
18111825
case arg => TypeAlias(arg)
18121826
}
@@ -4165,11 +4179,12 @@ object Types {
41654179
*/
41664180
def tryWiden(tp: NamedType, pre: Type): Type = pre.member(tp.name) match {
41674181
case d: SingleDenotation =>
4168-
d.info.dealias match {
4182+
val tp1 = d.info.dealiasKeepAnnots
4183+
tp1.stripAnnots match {
41694184
case TypeAlias(alias) =>
41704185
// if H#T = U, then for any x in L..H, x.T =:= U,
41714186
// hence we can replace with U under all variances
4172-
reapply(alias)
4187+
reapply(alias.rewrapAnnots(tp1))
41734188
case TypeBounds(lo, hi) =>
41744189
// If H#T = _ >: S <: U, then for any x in L..H, S <: x.T <: U,
41754190
// hence we can replace with S..U under all variances
@@ -4595,7 +4610,7 @@ object Types {
45954610
case _ => false
45964611
}
45974612

4598-
// ----- Decorator implicits --------------------------------------------
4613+
// ----- Helpers and Decorator implicits --------------------------------------
45994614

46004615
implicit def decorateTypeApplications(tpe: Type): TypeApplications = new TypeApplications(tpe)
46014616

@@ -4608,4 +4623,8 @@ object Types {
46084623
else tps2.nonEmpty && tps1.head.equals(tps2.head, bs) && tps1.tail.equalElements(tps2.tail, bs)
46094624
}
46104625
}
4626+
4627+
private val keepAlways: AnnotatedType => Context => Boolean = _ => _ => true
4628+
private val keepNever: AnnotatedType => Context => Boolean = _ => _ => false
4629+
private val keepIfRefining: AnnotatedType => Context => Boolean = tp => ctx => tp.isRefining(ctx)
46114630
}

compiler/src/dotty/tools/dotc/typer/Applications.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ object Applications {
4646
val ref = extractorMember(tp, name)
4747
if (ref.isOverloaded)
4848
errorType(i"Overloaded reference to $ref is not allowed in extractor", errorPos)
49-
ref.info.widenExpr.annotatedToRepeated.dealias
49+
ref.info.widenExpr.annotatedToRepeated.dealiasKeepAnnots
5050
}
5151

5252
/** Does `tp` fit the "product match" conditions as an unapply result type

compiler/src/dotty/tools/dotc/typer/Implicits.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -763,7 +763,7 @@ trait Implicits { self: Typer =>
763763
tree match {
764764
case Select(qual, nme.apply) if defn.isFunctionType(qual.tpe.widen) =>
765765
val qt = qual.tpe.widen
766-
val qt1 = qt.dealias
766+
val qt1 = qt.dealiasKeepAnnots
767767
def addendum = if (qt1 eq qt) "" else (i"\nwhich is an alias of: $qt1")
768768
em"parameter of ${qual.tpe.widen}$addendum"
769769
case _ =>

compiler/src/dotty/tools/dotc/typer/Inliner.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
224224
*/
225225
private def paramBindingDef(name: Name, paramtp: Type, arg: Tree,
226226
bindingsBuf: mutable.ListBuffer[ValOrDefDef]): ValOrDefDef = {
227-
val argtpe = arg.tpe.dealias
227+
val argtpe = arg.tpe.dealiasKeepAnnots
228228
val isByName = paramtp.dealias.isInstanceOf[ExprType]
229229
val inlineFlag = if (paramtp.hasAnnotation(defn.InlineParamAnnot)) Inline else EmptyFlags
230230
val (bindingFlags, bindingType) =

compiler/src/dotty/tools/dotc/util/common.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import core.Types.WildcardType
88
object common {
99

1010
val alwaysTrue = Function.const(true) _
11+
val alwaysFalse = Function.const(false) _
1112
val alwaysZero = Function.const(0) _
1213
val alwaysWildcardType = Function.const(WildcardType) _
1314

0 commit comments

Comments
 (0)