Skip to content

Commit

Permalink
Make rewritings of hk applications configurable
Browse files Browse the repository at this point in the history
Beta-reduce only if `Config.simplifyApplications` is true.
Turning off beta-reduction revealed two problems which are
also fixed in this commit:

1. Bad treatement of higher-kinded argyments in cyclicity checking
2. Wrong variance for higher-kinded arguments in TypeAccumulator
  • Loading branch information
odersky committed Jul 13, 2016
1 parent 1443fd4 commit f50cb20
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 18 deletions.
7 changes: 7 additions & 0 deletions src/dotty/tools/dotc/config/Config.scala
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,13 @@ object Config {
*/
final val splitProjections = false

/** If this flag is on, always rewrite an application `S[Ts]` where `S` is an alias for
* `[Xs] -> U` to `[Xs := Ts]U`. If this flag is off, the rewriting is only done if `S` is a
* reference to an instantiated parameter. Turning this flag on was observed to
* give a ~6% speedup on the JUnit test suite.
*/
final val simplifyApplications = true

/** Initial size of superId table */
final val InitialSuperIdsSize = 4096

Expand Down
28 changes: 13 additions & 15 deletions src/dotty/tools/dotc/core/TypeApplications.scala
Original file line number Diff line number Diff line change
Expand Up @@ -469,18 +469,21 @@ class TypeApplications(val self: Type) extends AnyVal {
case dealiased: TypeLambda =>
def tryReduce =
if (!args.exists(_.isInstanceOf[TypeBounds])) {
val reduced = dealiased.instantiate(args)
if (dealiased eq stripped) reduced
else reduced match {
case AppliedType(tycon, args) if variancesConform(typParams, tycon.typeParams) =>
// Reducing is safe for type inference, as kind of type constructor does not change
//println(i"reduced: $reduced instead of ${HKApply(self, args)}")
reduced
val followAlias = stripped match {
case stripped: TypeRef =>
stripped.symbol.is(BaseTypeArg)
case _ =>
// Reducing changes kind, keep hk application instead
//println(i"fallback: ${HKApply(self, args)} instead of $reduced")
HKApply(self, args)
Config.simplifyApplications && {
dealiased.resType match {
case AppliedType(tyconBody, _) =>
variancesConform(typParams, tyconBody.typeParams)
// Reducing is safe for type inference, as kind of type constructor does not change
case _ => false
}
}
}
if ((dealiased eq stripped) || followAlias) dealiased.instantiate(args)
else HKApply(self, args)
}
else dealiased.resType match {
case AppliedType(tycon, args1) if tycon.safeDealias ne tycon =>
Expand Down Expand Up @@ -665,11 +668,6 @@ class TypeApplications(val self: Type) extends AnyVal {
}
}

final def typeConstructor(implicit ctx: Context): Type = self.stripTypeVar match {
case AppliedType(tycon, _) => tycon
case self => self
}

/** If this is the image of a type argument; recover the type argument,
* otherwise NoType.
*/
Expand Down
23 changes: 20 additions & 3 deletions src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3422,8 +3422,9 @@ object Types {
case tp: HKApply =>
def mapArg(arg: Type, tparam: TypeParamInfo): Type = {
val saved = variance
if (tparam.paramVariance < 0) variance = -variance
else if (tparam.paramVariance == 0) variance = 0
val pvariance = tparam.paramVariance
if (pvariance < 0) variance = -variance
else if (pvariance == 0) variance = 0
try this(arg)
finally variance = saved
}
Expand Down Expand Up @@ -3629,7 +3630,23 @@ object Types {
this(x, prefix)

case tp @ HKApply(tycon, args) =>
foldOver(this(x, tycon), args)
def foldArgs(x: T, tparams: List[TypeParamInfo], args: List[Type]): T =
if (args.isEmpty) {
assert(tparams.isEmpty)
x
}
else {
val tparam = tparams.head
val saved = variance
val pvariance = tparam.paramVariance
if (pvariance < 0) variance = -variance
else if (pvariance == 0) variance = 0
val acc =
try this(x, args.head)
finally variance = saved
foldArgs(acc, tparams.tail, args.tail)
}
foldArgs(this(x, tycon), tp.typeParams, args)

case tp: AndOrType =>
this(this(x, tp.tp1), tp.tp2)
Expand Down
2 changes: 2 additions & 0 deletions src/dotty/tools/dotc/typer/Checking.scala
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,8 @@ object Checking {
tp.derivedRefinedType(this(parent), name, this(rinfo, nestedCycleOK, nestedCycleOK))
case tp: RecType =>
tp.rebind(this(tp.parent))
case tp @ HKApply(tycon, args) =>
tp.derivedAppliedType(this(tycon), args.map(this(_, nestedCycleOK, nestedCycleOK)))
case tp @ TypeRef(pre, name) =>
try {
// A prefix is interesting if it might contain (transitively) a reference
Expand Down

0 comments on commit f50cb20

Please sign in to comment.