Skip to content

Fix inefficieny in the presence of aliasing. #984

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Nov 30, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 9 additions & 30 deletions src/dotty/tools/dotc/core/TypeApplications.scala
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ class TypeApplications(val self: Type) extends AnyVal {
*/
final def baseArgInfos(base: Symbol)(implicit ctx: Context): List[Type] =
if (self derivesFrom base)
base.typeParams map (param => self.member(param.name).info.argInfo(param))
base.typeParams map (param => self.member(param.name).info.argInfo)
else
Nil

Expand All @@ -311,7 +311,7 @@ class TypeApplications(val self: Type) extends AnyVal {
/** The first type argument of the base type instance wrt `base` of this type */
final def firstBaseArgInfo(base: Symbol)(implicit ctx: Context): Type = base.typeParams match {
case param :: _ if self derivesFrom base =>
self.member(param.name).info.argInfo(param)
self.member(param.name).info.argInfo
case _ =>
NoType
}
Expand Down Expand Up @@ -369,9 +369,8 @@ class TypeApplications(val self: Type) extends AnyVal {
/** If this is an encoding of a (partially) applied type, return its arguments,
* otherwise return Nil.
* Existential types in arguments are returned as TypeBounds instances.
* @param interpolate See argInfo
*/
final def argInfos(interpolate: Boolean)(implicit ctx: Context): List[Type] = {
final def argInfos(implicit ctx: Context): List[Type] = {
var tparams: List[TypeSymbol] = null
def recur(tp: Type, refineCount: Int): mutable.ListBuffer[Type] = tp.stripTypeVar match {
case tp @ RefinedType(tycon, name) =>
Expand All @@ -381,7 +380,7 @@ class TypeApplications(val self: Type) extends AnyVal {
if (tparams == null) tparams = tycon.typeParams
if (buf.size < tparams.length) {
val tparam = tparams(buf.size)
if (name == tparam.name) buf += tp.refinedInfo.argInfo(tparam, interpolate)
if (name == tparam.name) buf += tp.refinedInfo.argInfo
else null
} else null
}
Expand All @@ -393,8 +392,6 @@ class TypeApplications(val self: Type) extends AnyVal {
if (buf == null) Nil else buf.toList
}

final def argInfos(implicit ctx: Context): List[Type] = argInfos(interpolate = true)

/** Argument types where existential types in arguments are disallowed */
def argTypes(implicit ctx: Context) = argInfos mapConserve noBounds

Expand All @@ -415,31 +412,13 @@ class TypeApplications(val self: Type) extends AnyVal {
self
}

/** If this is the image of a type argument to type parameter `tparam`,
* recover the type argument, otherwise NoType.
* @param interpolate If true, replace type bounds as arguments corresponding to
* variant type parameters by their dominating element. I.e. an argument
*
* T <: U
*
* for a covariant type-parameter becomes U, and an argument
*
* T >: L
*
* for a contravariant type-parameter becomes L.
/** If this is the image of a type argument; recover the type argument,
* otherwise NoType.
*/
final def argInfo(tparam: Symbol, interpolate: Boolean = true)(implicit ctx: Context): Type = self match {
final def argInfo(implicit ctx: Context): Type = self match {
case self: TypeAlias => self.alias
case TypeBounds(lo, hi) =>
if (interpolate) {
val v = tparam.variance
if (v > 0 && (lo isRef defn.NothingClass)) hi
else if (v < 0 && (hi isRef defn.AnyClass)) lo
else self
}
else self
case _ =>
NoType
case self: TypeBounds => self
case _ => NoType
}

/** The element type of a sequence or array */
Expand Down
60 changes: 30 additions & 30 deletions src/dotty/tools/dotc/core/TypeComparer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -140,38 +140,38 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {

private def firstTry(tp1: Type, tp2: Type): Boolean = tp2 match {
case tp2: NamedType =>
def compareAlias(info1: Type) = tp2.info match {
case info2: TypeAlias => isSubType(tp1, info2.alias)
case _ => info1 match {
case info1: TypeAlias => isSubType(info1.alias, tp2)
case _ => false
}
}
def compareNamed = {
implicit val ctx: Context = this.ctx // Dotty deviation: implicits need explicit type
tp1 match {
case tp1: NamedType =>
val sym1 = tp1.symbol
compareAlias(tp1.info) ||
(if ((sym1 ne NoSymbol) && (sym1 eq tp2.symbol))
ctx.erasedTypes || sym1.isStaticOwner || isSubType(tp1.prefix, tp2.prefix)
else
(tp1.name eq tp2.name) &&
isSubType(tp1.prefix, tp2.prefix) &&
(tp1.signature == tp2.signature) &&
!tp1.isInstanceOf[WithFixedSym] &&
!tp2.isInstanceOf[WithFixedSym]
) ||
compareHK(tp1, tp2, inOrder = true) ||
compareHK(tp2, tp1, inOrder = false) ||
thirdTryNamed(tp1, tp2)
case _ =>
compareHK(tp2, tp1, inOrder = false) ||
compareAlias(NoType) ||
secondTry(tp1, tp2)
def compareNamed(tp1: Type, tp2: NamedType): Boolean = {
implicit val ctx: Context = this.ctx
tp2.info match {
case info2: TypeAlias => firstTry(tp1, info2.alias)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like you could avoid a bunch of recursive calls to firstTry by using a utility function like:

def dealiasTypeRef(tp: TypeRef): Type =
  if (tp.symbol.isClass) tp
  else tp.info match {
   case TypeAlias(alias: TypeRef) => dealiasTypeRef(alias)
   case TypeAlias(alias) => alias
   case _ => tp
  }

case _ => tp1 match {
case tp1: NamedType =>
tp1.info match {
case info1: TypeAlias => compareNamed(info1.alias, tp2)
case _ =>
val sym1 = tp1.symbol
(if ((sym1 ne NoSymbol) && (sym1 eq tp2.symbol))
ctx.erasedTypes ||
sym1.isStaticOwner ||
isSubType(tp1.prefix, tp2.prefix) ||
thirdTryNamed(tp1, tp2)
else
(tp1.name eq tp2.name) &&
isSubType(tp1.prefix, tp2.prefix) &&
(tp1.signature == tp2.signature) &&
!tp1.isInstanceOf[WithFixedSym] &&
!tp2.isInstanceOf[WithFixedSym] ||
compareHK(tp1, tp2, inOrder = true) ||
compareHK(tp2, tp1, inOrder = false) ||
thirdTryNamed(tp1, tp2))
}
case _ =>
compareHK(tp2, tp1, inOrder = false) ||
secondTry(tp1, tp2)
}
}
}
compareNamed
compareNamed(tp1, tp2)
case tp2: ProtoType =>
isMatchedByProto(tp2, tp1)
case tp2: BoundType =>
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/core/tasty/TreePickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ class TreePickler(pickler: TastyPickler) {
case tpe: SkolemType =>
pickleType(tpe.info)
case tpe: RefinedType =>
val args = tpe.argInfos(interpolate = false)
val args = tpe.argInfos
if (args.isEmpty) {
writeByte(REFINEDtype)
withLength {
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/printing/RefinedPrinter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
}
homogenize(tp) match {
case tp: RefinedType =>
val args = tp.argInfos(interpolate = false)
val args = tp.argInfos
if (args.nonEmpty) {
val tycon = tp.unrefine
val cls = tycon.typeSymbol
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/reporting/Reporter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ trait Reporting { this: Context =>
else {
// Avoid evaluating question multiple time, since each evaluation
// may cause some extra logging output.
val q: String = question
lazy val q: String = question
traceIndented[T](s"==> $q?", (res: Any) => s"<== $q = ${resStr(res)}")(op)
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/typer/Namer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -848,7 +848,7 @@ class Namer { typer: Typer =>
def apply(tp: Type): Type = {
tp match {
case tp: RefinedType =>
val args = tp.argInfos(interpolate = false).mapconserve(this)
val args = tp.argInfos.mapconserve(this)
if (args.nonEmpty) {
val tycon = tp.withoutArgs(args)
val tparams = tycon.typeParams
Expand Down