Skip to content

Commit c4bed34

Browse files
committed
Two performance optimizations
1) Split out wildApprox into separate function 2) Be more careful not to follow static prefix chains where not needed
1 parent 80acc2d commit c4bed34

File tree

6 files changed

+71
-57
lines changed

6 files changed

+71
-57
lines changed

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

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,8 @@ class TypeComparer(initctx: Context) extends DotClass {
163163
*/
164164
def approximation(param: PolyParam, fromBelow: Boolean): Type = {
165165
val avoidParam = new TypeMap {
166-
override def apply(tp: Type) = mapOver {
166+
override def stopAtStatic = true
167+
def apply(tp: Type) = mapOver {
167168
tp match {
168169
case tp: RefinedType if param occursIn tp.refinedInfo => tp.parent
169170
case _ => tp
@@ -269,18 +270,16 @@ class TypeComparer(initctx: Context) extends DotClass {
269270
def compareNamed = tp1 match {
270271
case tp1: NamedType =>
271272
val sym1 = tp1.symbol
272-
val sym2 = tp2.symbol
273-
val pre1 = tp1.prefix
274-
val pre2 = tp2.prefix
275-
276-
( if (sym1 == sym2) (
277-
ctx.erasedTypes
273+
( if (sym1 == tp2.symbol) (
274+
ctx.erasedTypes
278275
|| sym1.isStaticOwner
279-
|| isSubType(pre1, pre2)
280-
|| pre1.isInstanceOf[ThisType] && pre2.isInstanceOf[ThisType]
281-
)
282-
else
283-
tp1.name == tp2.name && isSubType(pre1, pre2)
276+
|| { val pre1 = tp1.prefix
277+
val pre2 = tp2.prefix
278+
isSubType(pre1, pre2) ||
279+
pre1.isInstanceOf[ThisType] && pre2.isInstanceOf[ThisType]
280+
}
281+
) else
282+
tp1.name == tp2.name && isSubType(tp1.prefix, tp2.prefix)
284283
) || secondTryNamed(tp1, tp2)
285284
case _ =>
286285
secondTry(tp1, tp2)

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,17 +50,18 @@ trait TypeOps { this: Context =>
5050
/** Implementation of Types#simplified */
5151
final def simplify(tp: Type, theMap: SimplifyMap): Type = tp match {
5252
case tp: NamedType =>
53-
tp.derivedSelect(simplify(tp.prefix, theMap))
54-
case _: ThisType | NoPrefix =>
53+
if (tp.symbol.isStatic) tp
54+
else tp.derivedSelect(simplify(tp.prefix, theMap))
55+
case tp: PolyParam =>
56+
typerState.constraint.typeVarOfParam(tp) orElse tp
57+
case _: ThisType | _: BoundType | NoPrefix =>
5558
tp
5659
case tp: RefinedType =>
5760
tp.derivedRefinedType(simplify(tp.parent, theMap), tp.refinedName, simplify(tp.refinedInfo, theMap))
5861
case AndType(l, r) =>
5962
simplify(l, theMap) & simplify(r, theMap)
6063
case OrType(l, r) =>
6164
simplify(l, theMap) | simplify(r, theMap)
62-
case tp: PolyParam =>
63-
typerState.constraint.typeVarOfParam(tp) orElse tp
6465
case _ =>
6566
(if (theMap != null) theMap else new SimplifyMap).mapOver(tp)
6667
}

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2080,14 +2080,17 @@ object Types {
20802080

20812081
abstract class TypeMap(implicit ctx: Context) extends (Type => Type) { thisMap =>
20822082

2083+
protected def stopAtStatic = true
2084+
20832085
def apply(tp: Type): Type
20842086

20852087
protected var variance = 1
20862088

20872089
/** Map this function over given type */
20882090
def mapOver(tp: Type): Type = tp match {
20892091
case tp: NamedType =>
2090-
tp.derivedSelect(this(tp.prefix))
2092+
if (stopAtStatic && tp.symbol.isStatic) tp
2093+
else tp.derivedSelect(this(tp.prefix))
20912094

20922095
case _: ThisType
20932096
| _: BoundType
@@ -2173,6 +2176,7 @@ object Types {
21732176
tp.derivedClassInfo(this(tp.prefix))
21742177

21752178
def andThen(f: Type => Type): TypeMap = new TypeMap {
2179+
override def stopAtStatic = thisMap.stopAtStatic
21762180
def apply(tp: Type) = f(thisMap(tp))
21772181
}
21782182
}
@@ -2191,6 +2195,7 @@ object Types {
21912195
}
21922196

21932197
object IdentityTypeMap extends TypeMap()(NoContext) {
2198+
override def stopAtStatic = true
21942199
def apply(tp: Type) = tp
21952200
}
21962201

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,9 @@ object Implicits {
5656
case mt: MethodType =>
5757
mt.isImplicit ||
5858
mt.paramTypes.length != 1 ||
59-
!(argType <:< ((new WildApprox) apply mt.paramTypes.head))(ctx.fresh.withExploreTyperState)
59+
!(argType <:< wildApprox(mt.paramTypes.head)(ctx.fresh.withExploreTyperState))
6060
case rtp =>
61-
discardForView((new WildApprox) apply rtp, argType)
61+
discardForView(wildApprox(rtp), argType)
6262
}
6363
case tpw: TermRef =>
6464
false // can't discard overloaded refs
@@ -270,6 +270,7 @@ trait ImplicitRunInfo { self: RunInfo =>
270270
*/
271271
object liftToClasses extends TypeMap {
272272
private implicit val ctx: Context = liftingCtx
273+
override def stopAtStatic = true
273274
def apply(tp: Type) = tp match {
274275
case tp: TypeRef if tp.symbol.isAbstractOrAliasType =>
275276
val pre = tp.prefix
@@ -439,7 +440,7 @@ trait Implicits { self: Typer =>
439440
}
440441

441442
/** The expected type where parameters and uninstantiated typevars are replaced by wildcard types */
442-
val wildProto = implicitProto(pt, new WildApprox)
443+
val wildProto = implicitProto(pt, wildApprox(_))
443444

444445
/** Search failures; overridden in ExplainedImplicitSearch */
445446
protected def nonMatchingImplicit(ref: TermRef): SearchFailure = NoImplicitMatches

src/dotty/tools/dotc/typer/Inferencing.scala

Lines changed: 44 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -520,44 +520,52 @@ object Inferencing {
520520
/** Approximate occurrences of parameter types and uninstantiated typevars
521521
* by wildcard types.
522522
*/
523-
class WildApprox(implicit ctx: Context) extends TypeMap {
524-
override def apply(tp: Type) = tp match {
525-
case PolyParam(pt, pnum) =>
526-
WildcardType(apply(pt.paramBounds(pnum)).bounds)
527-
case MethodParam(mt, pnum) =>
528-
WildcardType(TypeBounds.upper(apply(mt.paramTypes(pnum))))
529-
case tp: TypeVar =>
530-
val inst = tp.instanceOpt
531-
if (inst.exists) apply(inst)
532-
else ctx.typerState.constraint.at(tp.origin) match {
533-
case bounds: TypeBounds => apply(WildcardType(bounds))
534-
case NoType => WildcardType
535-
}
536-
case tp: AndType =>
537-
val tp1a = apply(tp.tp1)
538-
val tp2a = apply(tp.tp2)
539-
def wildBounds(tp: Type) =
540-
if (tp.isInstanceOf[WildcardType]) tp.bounds else TypeBounds.upper(tp)
541-
if (tp1a.isInstanceOf[WildcardType] || tp2a.isInstanceOf[WildcardType])
542-
WildcardType(wildBounds(tp1a) & wildBounds(tp2a))
543-
else
544-
tp.derivedAndType(tp1a, tp2a)
545-
case tp: OrType =>
546-
val tp1a = apply(tp.tp1)
547-
val tp2a = apply(tp.tp2)
548-
if (tp1a.isInstanceOf[WildcardType] || tp2a.isInstanceOf[WildcardType])
549-
WildcardType(tp1a.bounds | tp2a.bounds)
550-
else
551-
tp.derivedOrType(tp1a, tp2a)
552-
case tp: SelectionProto =>
553-
tp.derivedSelectionProto(tp.name, this(tp.refinedInfo), NoViewsAllowed)
554-
case tp: ViewProto =>
555-
tp.derivedViewProto(this(tp.argType), this(tp.resultType))
556-
case _ =>
557-
mapOver(tp)
558-
}
523+
final def wildApprox(tp: Type, theMap: WildApproxMap = null)(implicit ctx: Context): Type = tp match {
524+
case tp: NamedType => // default case, inlined for speed
525+
if (tp.symbol.isStatic) tp
526+
else tp.derivedSelect(wildApprox(tp.prefix, theMap))
527+
case PolyParam(pt, pnum) =>
528+
WildcardType(wildApprox(pt.paramBounds(pnum)).bounds)
529+
case MethodParam(mt, pnum) =>
530+
WildcardType(TypeBounds.upper(wildApprox(mt.paramTypes(pnum))))
531+
case tp: TypeVar =>
532+
val inst = tp.instanceOpt
533+
if (inst.exists) wildApprox(inst)
534+
else ctx.typerState.constraint.at(tp.origin) match {
535+
case bounds: TypeBounds => wildApprox(WildcardType(bounds))
536+
case NoType => WildcardType
537+
}
538+
case tp: AndType =>
539+
val tp1a = wildApprox(tp.tp1)
540+
val tp2a = wildApprox(tp.tp2)
541+
def wildBounds(tp: Type) =
542+
if (tp.isInstanceOf[WildcardType]) tp.bounds else TypeBounds.upper(tp)
543+
if (tp1a.isInstanceOf[WildcardType] || tp2a.isInstanceOf[WildcardType])
544+
WildcardType(wildBounds(tp1a) & wildBounds(tp2a))
545+
else
546+
tp.derivedAndType(tp1a, tp2a)
547+
case tp: OrType =>
548+
val tp1a = wildApprox(tp.tp1)
549+
val tp2a = wildApprox(tp.tp2)
550+
if (tp1a.isInstanceOf[WildcardType] || tp2a.isInstanceOf[WildcardType])
551+
WildcardType(tp1a.bounds | tp2a.bounds)
552+
else
553+
tp.derivedOrType(tp1a, tp2a)
554+
case tp: SelectionProto =>
555+
tp.derivedSelectionProto(tp.name, wildApprox(tp.refinedInfo), NoViewsAllowed)
556+
case tp: ViewProto =>
557+
tp.derivedViewProto(wildApprox(tp.argType), wildApprox(tp.resultType))
558+
case _: ThisType | _: BoundType | NoPrefix => // default case, inlined for speed
559+
tp
560+
case tp: RefinedType => // default case, inlined for speed
561+
tp.derivedRefinedType(wildApprox(tp.parent, theMap), tp.refinedName, wildApprox(tp.refinedInfo, theMap))
562+
case _ =>
563+
(if (theMap != null) theMap else new WildApproxMap).mapOver(tp)
559564
}
560565

566+
private[Inferencing] class WildApproxMap(implicit ctx: Context) extends TypeMap {
567+
def apply(tp: Type) = wildApprox(tp, this)
568+
}
561569

562570
/** Add all parameters in given polytype `pt` to the constraint's domain.
563571
* If the constraint contains already some of these parameters in its domain,

src/dotty/tools/dotc/typer/Namer.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -551,7 +551,7 @@ class Namer { typer: Typer =>
551551
defContext(sym).denotNamed(original)
552552
def paramProto(paramss: List[List[Type]], idx: Int): Type = paramss match {
553553
case params :: paramss1 =>
554-
if (idx < params.length) (new WildApprox) apply params(idx)
554+
if (idx < params.length) wildApprox(params(idx))
555555
else paramProto(paramss1, idx - params.length)
556556
case nil =>
557557
WildcardType

0 commit comments

Comments
 (0)