Skip to content

Commit 7204538

Browse files
committed
Optimize wildApprox for applied types
1 parent 1e6572d commit 7204538

File tree

6 files changed

+95
-75
lines changed

6 files changed

+95
-75
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ trait Substituters { this: Context =>
190190
case _ => mapOver2(tp)
191191
}
192192

193+
// Specialize mapOver2 to get monomorphic dispatch for handling AppliedTypes
193194
override def mapOver2(tp: Type) = tp match {
194195
case tp: AppliedType =>
195196
def mapArgs(args: List[Type]): List[Type] = args match {
@@ -214,6 +215,7 @@ trait Substituters { this: Context =>
214215
case _ => mapOver2(tp)
215216
}
216217

218+
// Specialize mapOver2 to get monomorphic dispatch for handling AppliedTypes
217219
override def mapOver2(tp: Type) = tp match {
218220
case tp: AppliedType =>
219221
def mapArgs(args: List[Type]): List[Type] = args match {

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
7070
}
7171
}
7272

73+
// Specialize mapOver2 to get monomorphic dispatch for handling AppliedTypes
7374
override def mapOver2(tp: Type) = tp match {
7475
case tp: AppliedType =>
7576
def mapArgs(args: List[Type], tparams: List[ParamInfo]): List[Type] = args match {

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3853,6 +3853,7 @@ object Types {
38533853
mapOver2(tp)
38543854
}
38553855

3856+
// Broken out so that it can be specialized in frequently used type maps
38563857
def mapOver2(tp: Type) = tp match {
38573858
case tp: AppliedType =>
38583859
record(s"mapOver2 AppliedType")

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,9 @@ object Implicits {
7575
case mt: MethodType =>
7676
mt.isImplicit ||
7777
mt.paramInfos.length != 1 ||
78-
!(argType relaxed_<:< wildApprox(mt.paramInfos.head, null, Set.empty)(ctx.fresh.setExploreTyperState))
78+
!(argType relaxed_<:< wildApprox(mt.paramInfos.head)(ctx.fresh.setExploreTyperState))
7979
case rtp =>
80-
discardForView(wildApprox(rtp, null, Set.empty), argType)
80+
discardForView(wildApprox(rtp), argType)
8181
}
8282
case tpw: TermRef =>
8383
false // can't discard overloaded refs
@@ -756,7 +756,7 @@ trait Implicits { self: Typer =>
756756
}
757757

758758
/** The expected type where parameters and uninstantiated typevars are replaced by wildcard types */
759-
val wildProto = implicitProto(pt, wildApprox(_, null, Set.empty))
759+
val wildProto = implicitProto(pt, wildApprox)
760760

761761
/** Search failures; overridden in ExplainedImplicitSearch */
762762
protected def nonMatchingImplicit(ref: TermRef, trail: List[MessageContainer]): SearchFailure = NoImplicitMatches

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1029,7 +1029,7 @@ class Namer { typer: Typer =>
10291029
ctx.defContext(sym).denotNamed(original)
10301030
def paramProto(paramss: List[List[Type]], idx: Int): Type = paramss match {
10311031
case params :: paramss1 =>
1032-
if (idx < params.length) wildApprox(params(idx), null, Set.empty)
1032+
if (idx < params.length) wildApprox(params(idx))
10331033
else paramProto(paramss1, idx - params.length)
10341034
case nil =>
10351035
WildcardType

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

Lines changed: 87 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,9 @@ object ProtoTypes {
374374
/** A prototype for type constructors that are followed by a type application */
375375
@sharable object AnyTypeConstructorProto extends UncachedGroundType with MatchAlways
376376

377+
/** A prototype for left ahnd sides of assignments */
378+
@sharable object AssignProto extends UncachedGroundType with MatchAlways
379+
377380
/** Add all parameters of given type lambda `tl` to the constraint's domain.
378381
* If the constraint contains already some of these parameters in its domain,
379382
* make a copy of the type lambda and add the copy's type parameters instead.
@@ -471,80 +474,93 @@ object ProtoTypes {
471474
/** Approximate occurrences of parameter types and uninstantiated typevars
472475
* by wildcard types.
473476
*/
474-
final def wildApprox(tp: Type, theMap: WildApproxMap, seen: Set[TypeParamRef])(implicit ctx: Context): Type = tp match {
475-
case tp: NamedType => // default case, inlined for speed
476-
if (tp.symbol.isStatic) tp
477-
else tp.derivedSelect(wildApprox(tp.prefix, theMap, seen))
478-
case tp @ AppliedType(tycon, args) =>
479-
wildApprox(tycon, theMap, seen) match {
480-
case _: WildcardType => WildcardType // this ensures we get a * type
481-
case tycon1 => tp.derivedAppliedType(tycon1, args.mapConserve(wildApprox(_, theMap, seen)))
482-
}
483-
case tp: RefinedType => // default case, inlined for speed
484-
tp.derivedRefinedType(
485-
wildApprox(tp.parent, theMap, seen),
486-
tp.refinedName,
487-
wildApprox(tp.refinedInfo, theMap, seen))
488-
case tp: TypeAlias => // default case, inlined for speed
489-
tp.derivedTypeAlias(wildApprox(tp.alias, theMap, seen))
490-
case tp @ TypeParamRef(poly, pnum) =>
491-
def wildApproxBounds(bounds: TypeBounds) =
492-
if (bounds.lo.isInstanceOf[NamedType] && bounds.hi.isInstanceOf[NamedType])
493-
WildcardType(wildApprox(bounds, theMap, seen).bounds)
494-
else if (seen.contains(tp)) WildcardType
495-
else WildcardType(wildApprox(bounds, theMap, seen + tp).bounds)
496-
def unconstrainedApprox = wildApproxBounds(poly.paramInfos(pnum))
497-
def approxPoly =
498-
if (ctx.mode.is(Mode.TypevarsMissContext)) unconstrainedApprox
499-
else
500-
ctx.typerState.constraint.entry(tp) match {
501-
case bounds: TypeBounds => wildApproxBounds(bounds)
502-
case NoType => unconstrainedApprox
503-
case inst => wildApprox(inst, theMap, seen)
504-
}
505-
approxPoly
506-
case TermParamRef(mt, pnum) =>
507-
WildcardType(TypeBounds.upper(wildApprox(mt.paramInfos(pnum), theMap, seen)))
508-
case tp: TypeVar =>
509-
wildApprox(tp.underlying, theMap, seen)
510-
case tp: AndType =>
511-
def approxAnd = {
512-
val tp1a = wildApprox(tp.tp1, theMap, seen)
513-
val tp2a = wildApprox(tp.tp2, theMap, seen)
514-
def wildBounds(tp: Type) =
515-
if (tp.isInstanceOf[WildcardType]) tp.bounds else TypeBounds.upper(tp)
516-
if (tp1a.isInstanceOf[WildcardType] || tp2a.isInstanceOf[WildcardType])
517-
WildcardType(wildBounds(tp1a) & wildBounds(tp2a))
518-
else
519-
tp.derivedAndType(tp1a, tp2a)
520-
}
521-
approxAnd
522-
case tp: OrType =>
523-
def approxOr = {
524-
val tp1a = wildApprox(tp.tp1, theMap, seen)
525-
val tp2a = wildApprox(tp.tp2, theMap, seen)
526-
if (tp1a.isInstanceOf[WildcardType] || tp2a.isInstanceOf[WildcardType])
527-
WildcardType(tp1a.bounds | tp2a.bounds)
528-
else
529-
tp.derivedOrType(tp1a, tp2a)
530-
}
531-
approxOr
532-
case tp: SelectionProto =>
533-
tp.derivedSelectionProto(tp.name, wildApprox(tp.memberProto, theMap, seen), NoViewsAllowed)
534-
case tp: ViewProto =>
535-
tp.derivedViewProto(
536-
wildApprox(tp.argType, theMap, seen),
537-
wildApprox(tp.resultType, theMap, seen))
538-
case _: ThisType | _: BoundType | NoPrefix => // default case, inlined for speed
539-
tp
540-
case _ =>
541-
(if (theMap != null) theMap else new WildApproxMap(seen)).mapOver(tp)
477+
final def wildApprox(tp: Type)(implicit ctx: Context): Type = tp match {
478+
case tp: NamedType =>
479+
if (tp.symbol.isStatic) tp else tp.derivedSelect(wildApprox(tp.prefix))
480+
case _: ThisType => tp
481+
case _ => new WildApproxMap(Set.empty).mapOver2(tp)
542482
}
543483

544-
@sharable object AssignProto extends UncachedGroundType with MatchAlways
545-
546484
private[ProtoTypes] class WildApproxMap(val seen: Set[TypeParamRef])(implicit ctx: Context) extends TypeMap {
547-
def apply(tp: Type) = wildApprox(tp, this, seen)
485+
def apply(tp: Type) = tp match {
486+
case tp: NamedType =>
487+
if (tp.symbol.isStatic) tp else tp.derivedSelect(this(tp.prefix))
488+
case _: ThisType => tp
489+
case _ => mapOver2(tp)
490+
}
491+
492+
override def mapOver2(tp: Type) = tp match {
493+
case tp @ AppliedType(tycon, args) =>
494+
this(tycon) match {
495+
case _: WildcardType => WildcardType // this ensures we get a * type
496+
case tycon1 =>
497+
def mapArgs(args: List[Type]): List[Type] = args match {
498+
case arg :: otherArgs =>
499+
val arg1 = this(arg)
500+
val otherArgs1 = mapArgs(otherArgs)
501+
if ((arg1 eq arg) && (otherArgs1 eq otherArgs)) args
502+
else arg1 :: otherArgs1
503+
case nil =>
504+
nil
505+
}
506+
derivedAppliedType(tp, tycon1, mapArgs(tp.args))
507+
}
508+
case _ =>
509+
mapOver3(tp)
510+
}
511+
512+
override def mapOver3(tp: Type) = tp match {
513+
case tp @ TypeParamRef(poly, pnum) =>
514+
def wildApproxBounds(bounds: TypeBounds) =
515+
if (bounds.lo.isInstanceOf[NamedType] && bounds.hi.isInstanceOf[NamedType])
516+
WildcardType(this(bounds).bounds)
517+
else if (seen.contains(tp)) WildcardType
518+
else WildcardType(new WildApproxMap(seen + tp).apply(bounds).bounds)
519+
def unconstrainedApprox = wildApproxBounds(poly.paramInfos(pnum))
520+
def approxPoly =
521+
if (ctx.mode.is(Mode.TypevarsMissContext)) unconstrainedApprox
522+
else
523+
ctx.typerState.constraint.entry(tp) match {
524+
case bounds: TypeBounds => wildApproxBounds(bounds)
525+
case NoType => unconstrainedApprox
526+
case inst => this(inst)
527+
}
528+
approxPoly
529+
case TermParamRef(mt, pnum) =>
530+
WildcardType(TypeBounds.upper(this(mt.paramInfos(pnum))))
531+
case _: BoundType | NoPrefix | NoType => // inlined for speed
532+
tp
533+
case tp: TypeVar =>
534+
this(tp.underlying)
535+
case tp: AndType =>
536+
def approxAnd = {
537+
val tp1a = this(tp.tp1)
538+
val tp2a = this(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+
}
546+
approxAnd
547+
case tp: OrType =>
548+
def approxOr = {
549+
val tp1a = this(tp.tp1)
550+
val tp2a = this(tp.tp2)
551+
if (tp1a.isInstanceOf[WildcardType] || tp2a.isInstanceOf[WildcardType])
552+
WildcardType(tp1a.bounds | tp2a.bounds)
553+
else
554+
tp.derivedOrType(tp1a, tp2a)
555+
}
556+
approxOr
557+
case tp: SelectionProto =>
558+
tp.derivedSelectionProto(tp.name, this(tp.memberProto), NoViewsAllowed)
559+
case tp: ViewProto =>
560+
tp.derivedViewProto(this(tp.argType), this(tp.resultType))
561+
case _ =>
562+
super.mapOver3(tp)
563+
}
548564
}
549565

550566
/** Dummy tree to be used as an argument of a FunProto or ViewProto type */

0 commit comments

Comments
 (0)