Skip to content

Commit 3a2831e

Browse files
committed
Optimize canDropAlias
Cache canDopAlias calls in TypeRefs. Performance tests pointed to a ~1% showdown before, which is really in the noise. However, stats showed that the number of iterations in the exists call of `canDropAlias` is significant (a bit more than total member operations). With this optimization, the number of calls gets reduced to 1% of what it was.
1 parent e2399f1 commit 3a2831e

File tree

2 files changed

+29
-24
lines changed

2 files changed

+29
-24
lines changed

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

+2-24
Original file line numberDiff line numberDiff line change
@@ -231,28 +231,6 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
231231
}
232232
}
233233

234-
/** Given an alias type `type A = B` where a recursive comparison with `B` yields
235-
* `false`, can we conclude that the comparison is definitely false?
236-
* This could not be the case if `A` overrides some abstract type. Example:
237-
*
238-
* class C { type A }
239-
* class D { type A = Int }
240-
* val c: C
241-
* val d: D & c.type
242-
* c.A <:< d.A ?
243-
*
244-
* The test should return true, by performing the logic in the bottom half of
245-
* firstTry (where we check the names of types). But just following the alias
246-
* from d.A to Int reduces the problem to `c.A <:< Int`, which returns `false`.
247-
* So we can't drop the alias here, we need to do the backtracking to the name-
248-
* based tests.
249-
*/
250-
def canDropAlias(tp: NamedType): Boolean =
251-
val sym = tp.symbol
252-
!sym.canMatchInheritedSymbols
253-
|| !tp.prefix.baseClasses.exists(
254-
_.info.nonPrivateDecl(sym.name).symbol.is(Deferred))
255-
256234
def firstTry: Boolean = tp2 match {
257235
case tp2: NamedType =>
258236
def compareNamed(tp1: Type, tp2: NamedType): Boolean =
@@ -261,14 +239,14 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
261239
info2 match
262240
case info2: TypeAlias =>
263241
if recur(tp1, info2.alias) then return true
264-
if canDropAlias(tp2) then return false
242+
if tp2.asInstanceOf[TypeRef].canDropAlias then return false
265243
case _ =>
266244
tp1 match
267245
case tp1: NamedType =>
268246
tp1.info match {
269247
case info1: TypeAlias =>
270248
if recur(info1.alias, tp2) then return true
271-
if canDropAlias(tp1) then return false
249+
if tp1.asInstanceOf[TypeRef].canDropAlias then return false
272250
case _ =>
273251
}
274252
val sym2 = tp2.symbol

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

+27
Original file line numberDiff line numberDiff line change
@@ -2403,6 +2403,33 @@ object Types {
24032403
type ThisType = TypeRef
24042404
type ThisName = TypeName
24052405

2406+
private var myCanDropAliasPeriod: Period = Nowhere
2407+
private var myCanDropAlias: Boolean = _
2408+
2409+
/** Given an alias type `type A = B` where a recursive comparison with `B` yields
2410+
* `false`, can we conclude that the comparison is definitely false?
2411+
* This could not be the case if `A` overrides some abstract type. Example:
2412+
*
2413+
* class C { type A }
2414+
* class D { type A = Int }
2415+
* val c: C
2416+
* val d: D & c.type
2417+
* c.A <:< d.A ?
2418+
*
2419+
* The test should return true, by performing the logic in the bottom half of
2420+
* firstTry (where we check the names of types). But just following the alias
2421+
* from d.A to Int reduces the problem to `c.A <:< Int`, which returns `false`.
2422+
* So we can't drop the alias here, we need to do the backtracking to the name-
2423+
* based tests.
2424+
*/
2425+
def canDropAlias(using ctx: Context) =
2426+
if myCanDropAliasPeriod != ctx.period then
2427+
myCanDropAlias =
2428+
!symbol.canMatchInheritedSymbols
2429+
|| !prefix.baseClasses.exists(_.info.decls.lookup(name).is(Deferred))
2430+
myCanDropAliasPeriod = ctx.period
2431+
myCanDropAlias
2432+
24062433
override def designator: Designator = myDesignator
24072434
override protected def designator_=(d: Designator): Unit = myDesignator = d
24082435

0 commit comments

Comments
 (0)