Skip to content

Commit 88c4a6c

Browse files
oderskyDarkDimius
authored andcommitted
Allow And/OrTypes in baseType operations
Introduce new cases for AndTypes and OrTypes in methods `derivesFrom`, `baseClasses`, and `baseTypeWithArgs`. These cases are ultimately needed so that `baseTypeWithArgs` makes sense for union and intersection types. Also, fixed embarrassing typo in method `TypeBounds#|`.
1 parent 7a04b11 commit 88c4a6c

File tree

2 files changed

+31
-9
lines changed

2 files changed

+31
-9
lines changed

src/dotty/tools/dotc/core/TypeApplications.scala

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -170,17 +170,20 @@ class TypeApplications(val self: Type) extends AnyVal {
170170
/** The type arguments of this type's base type instance wrt.`base`.
171171
* Existential types in arguments are disallowed.
172172
*/
173-
final def baseArgTypes(base: Symbol)(implicit ctx: Context): List[Type] = baseArgInfos(base) mapConserve noBounds
173+
final def baseArgTypes(base: Symbol)(implicit ctx: Context): List[Type] =
174+
baseArgInfos(base) mapConserve noBounds
174175

175176
/** The type arguments of this type's base type instance wrt.`base`.
176177
* Existential types in arguments are approximanted by their lower bound.
177178
*/
178-
final def baseArgTypesLo(base: Symbol)(implicit ctx: Context): List[Type] = baseArgInfos(base) mapConserve boundsToLo
179+
final def baseArgTypesLo(base: Symbol)(implicit ctx: Context): List[Type] =
180+
baseArgInfos(base) mapConserve boundsToLo
179181

180182
/** The type arguments of this type's base type instance wrt.`base`.
181183
* Existential types in arguments are approximanted by their upper bound.
182184
*/
183-
final def baseArgTypesHi(base: Symbol)(implicit ctx: Context): List[Type] = baseArgInfos(base) mapConserve boundsToHi
185+
final def baseArgTypesHi(base: Symbol)(implicit ctx: Context): List[Type] =
186+
baseArgInfos(base) mapConserve boundsToHi
184187

185188
/** The first type argument of the base type instance wrt `base` of this type */
186189
final def firstBaseArgInfo(base: Symbol)(implicit ctx: Context): Type = base.typeParams match {
@@ -193,8 +196,11 @@ class TypeApplications(val self: Type) extends AnyVal {
193196
/** The base type including all type arguments of this type.
194197
* Existential types in arguments are returned as TypeBounds instances.
195198
*/
196-
final def baseTypeWithArgs(base: Symbol)(implicit ctx: Context): Type =
197-
self.baseTypeRef(base).appliedTo(baseArgInfos(base))
199+
final def baseTypeWithArgs(base: Symbol)(implicit ctx: Context): Type = self.dealias match {
200+
case AndType(tp1, tp2) => tp1.baseTypeWithArgs(base) & tp2.baseTypeWithArgs(base)
201+
case OrType(tp1, tp2) => tp1.baseTypeWithArgs(base) | tp2.baseTypeWithArgs(base)
202+
case _ => self.baseTypeRef(base).appliedTo(baseArgInfos(base))
203+
}
198204

199205
/** Translate a type of the form From[T] to To[T], keep other types as they are.
200206
* `from` and `to` must be static classes, both with one type parameter, and the same variance.
@@ -205,7 +211,7 @@ class TypeApplications(val self: Type) extends AnyVal {
205211
else self
206212

207213
/** If this is an encoding of a (partially) applied type, return its arguments,
208-
* otherwise return Nil.
214+
* otherwise return Nil.
209215
* Existential types in arguments are returned as TypeBounds instances.
210216
*/
211217
final def argInfos(implicit ctx: Context): List[Type] = {

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

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,19 @@ object Types {
102102
}
103103

104104
/** Is this type an instance of a non-bottom subclass of the given class `cls`? */
105-
final def derivesFrom(cls: Symbol)(implicit ctx: Context): Boolean =
106-
classSymbol.derivesFrom(cls)
105+
final def derivesFrom(cls: Symbol)(implicit ctx: Context): Boolean = this match {
106+
case tp: TypeRef =>
107+
val sym = tp.symbol
108+
if (sym.isClass) sym.derivesFrom(cls) else tp.underlying.derivesFrom(cls)
109+
case tp: TypeProxy =>
110+
tp.underlying.derivesFrom(cls)
111+
case tp: AndType =>
112+
tp.tp1.derivesFrom(cls) || tp.tp2.derivesFrom(cls)
113+
case tp: OrType =>
114+
tp.tp1.derivesFrom(cls) && tp.tp2.derivesFrom(cls)
115+
case _ =>
116+
false
117+
}
107118

108119
/** A type T is a legal prefix in a type selection T#A if
109120
* T is stable or T contains no abstract types
@@ -254,6 +265,7 @@ object Types {
254265

255266
/** The base classes of this type as determined by ClassDenotation
256267
* in linearization order, with the class itself as first element.
268+
* For AndTypes/OrTypes, the union/intersection of the operands' baseclasses.
257269
* Inherited by all type proxies. `Nil` for all other types.
258270
*/
259271
final def baseClasses(implicit ctx: Context): List[ClassSymbol] = track("baseClasses") {
@@ -262,6 +274,10 @@ object Types {
262274
tp.underlying.baseClasses
263275
case tp: ClassInfo =>
264276
tp.cls.baseClasses
277+
case AndType(tp1, tp2) =>
278+
tp1.baseClasses union tp2.baseClasses
279+
case OrType(tp1, tp2) =>
280+
tp1.baseClasses intersect tp2.baseClasses
265281
case _ => Nil
266282
}
267283
}
@@ -1863,7 +1879,7 @@ object Types {
18631879

18641880
def | (that: TypeBounds)(implicit ctx: Context): TypeBounds = {
18651881
val v = this commonVariance that
1866-
if (v == 0 && (this.lo eq this.hi) && (that.lo eq that.hi))
1882+
if (v != 0 && (this.lo eq this.hi) && (that.lo eq that.hi))
18671883
if (v > 0) derivedTypeAlias(this.hi | that.hi, v)
18681884
else derivedTypeAlias(this.lo & that.lo, v)
18691885
else derivedTypeBounds(this.lo & that.lo, this.hi | that.hi, v)

0 commit comments

Comments
 (0)