Skip to content

Commit

Permalink
missing cases for less eager dealiasing after following type alias
Browse files Browse the repository at this point in the history
  • Loading branch information
pweisenburger committed May 30, 2022
1 parent a4b11d1 commit 11af161
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 26 deletions.
58 changes: 37 additions & 21 deletions compiler/src/dotty/tools/dotc/core/TypeComparer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,31 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
else if GADTused then CompareResult.OKwithGADTUsed
else CompareResult.OK

/** original aliases of types used to instantiate type parameters
* collected in `recur` and to be restored after sub type check */
private var realiases: List[(TypeParamRef, NamedType, Type)] = List.empty

private def realiasConstraints() =
this.realiases foreach { (param, alias, dealiased) =>
constraint.entry(param) match
case TypeBounds(lo, hi) =>
val aliasLo = (alias ne lo) && (dealiased eq lo)
val aliasHi = (alias ne hi) && (dealiased eq hi)
if aliasLo || aliasHi then
constraint = constraint.updateEntry(param, TypeBounds(
if aliasLo then alias else lo,
if aliasHi then alias else hi))
case tp =>
if (alias ne tp) && (dealiased eq tp) then
constraint = constraint.updateEntry(param, alias)
}

private inline def aliasedConstraint(param: Type, alias: NamedType, dealiased: Type) =
if alias.symbol.isStatic then
param.stripTypeVar match
case param: TypeParamRef => this.realiases ::= (param, alias, dealiased)
case _ =>

/** The current approximation state. See `ApproxState`. */
private var approx: ApproxState = ApproxState.Fresh
protected def approxState: ApproxState = approx
Expand Down Expand Up @@ -210,18 +235,24 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
try op finally comparedTypeLambdas = saved

protected def isSubType(tp1: Type, tp2: Type, a: ApproxState): Boolean = {
val outermostCall = leftRoot eq null
val savedApprox = approx
val savedLeftRoot = leftRoot
if (a == ApproxState.Fresh) {
this.approx = ApproxState.None
this.leftRoot = tp1
}
else this.approx = a
try recur(tp1, tp2)
if outermostCall then this.realiases = List.empty
try
val res = recur(tp1, tp2)
if outermostCall then realiasConstraints()
res
catch {
case ex: Throwable => handleRecursive("subtype", i"$tp1 <:< $tp2", ex, weight = 2)
}
finally {
if outermostCall then this.realiases = List.empty
this.approx = savedApprox
this.leftRoot = savedLeftRoot
}
Expand Down Expand Up @@ -297,13 +328,15 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
val info2 = tp2.info
info2 match
case info2: TypeAlias =>
aliasedConstraint(tp1, tp2, info2.alias)
if recur(tp1, info2.alias) then return true
if tp2.asInstanceOf[TypeRef].canDropAlias then return false
case _ =>
tp1 match
case tp1: NamedType =>
tp1.info match {
case info1: TypeAlias =>
aliasedConstraint(tp2, tp1, info1.alias)
if recur(info1.alias, tp2) then return true
if tp1.asInstanceOf[TypeRef].canDropAlias then return false
case _ =>
Expand Down Expand Up @@ -413,26 +446,9 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
case tp1: NamedType =>
tp1.info match {
case info1: TypeAlias =>
def realiasConstraint() = tp2 match {
case tp2: TypeParamRef =>
constraint.entry(tp2) match {
case TypeBounds(lo, hi) =>
val aliasLo = (tp1 ne lo) && (info1.alias eq lo)
val aliasHi = (tp1 ne hi) && (info1.alias eq hi)
if aliasLo || aliasHi then
constraint = constraint.updateEntry(tp2, TypeBounds(
if aliasLo then tp1 else lo,
if aliasHi then tp1 else hi))
case tp =>
if (tp1 ne tp) && (info1.alias eq tp) then
constraint = constraint.updateEntry(tp2, tp1)
}
case _ =>
}
val res = recur(info1.alias, tp2)
if (tp1.symbol.isStatic) realiasConstraint()
if (res) return true
if (tp1.prefix.isStable) return tryLiftedToThis1
aliasedConstraint(tp2, tp1, info1.alias)
if recur(info1.alias, tp2) then return true
if tp1.prefix.isStable then return tryLiftedToThis1
case _ =>
if (tp1 eq NothingType) || isBottom(tp1) then return true
}
Expand Down
9 changes: 5 additions & 4 deletions compiler/src/dotty/tools/dotc/transform/patmat/Space.scala
Original file line number Diff line number Diff line change
Expand Up @@ -666,19 +666,20 @@ class SpaceEngine(using Context) extends SpaceLogic {

/** Abstract sealed types, or-types, Boolean and Java enums can be decomposed */
def canDecompose(tp: Type): Boolean =
val res = tp.dealias match
val underlying = tp.dealias
val res = underlying match
case _: SingletonType => false
case _: OrType => true
case and: AndType => canDecompose(and.tp1) || canDecompose(and.tp2)
case _ =>
val cls = tp.classSymbol
val cls = underlying.classSymbol
cls.is(Sealed)
&& cls.isOneOf(AbstractOrTrait)
&& !cls.hasAnonymousChild
&& cls.children.nonEmpty
|| cls.isAllOf(JavaEnumTrait)
|| tp.isRef(defn.BooleanClass)
|| tp.isRef(defn.UnitClass)
|| underlying.isRef(defn.BooleanClass)
|| underlying.isRef(defn.UnitClass)
//debug.println(s"decomposable: ${tp.show} = $res")
res

Expand Down
5 changes: 5 additions & 0 deletions tests/run-macros/i15304.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Test.MyString
Test.MyString
Test.MyString
scala.Seq[Test.MyString]
scala.Tuple2[Test.MyString, scala.Int]
9 changes: 9 additions & 0 deletions tests/run-macros/i15304/Macro_1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import scala.quoted._

def typeNameOf[A: Type](using Quotes): Expr[String] =
val name = Type.show[A]
Expr(name)

inline def typeNameOf[A]: String = ${ typeNameOf[A] }

inline def typeNameOfF1[A](f: A => Unit): String = ${ typeNameOf[A] }
9 changes: 9 additions & 0 deletions tests/run-macros/i15304/Test_2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
object Test:
type MyString = String

def main(args: Array[String]): Unit =
println(typeNameOf[MyString])
println(typeNameOfF1 { (x: MyString) => })
println(typeNameOfF1[MyString] { (x: MyString) => })
println(typeNameOfF1 { (x: Seq[MyString]) => })
println(typeNameOfF1 { (x: (MyString, Int)) => })
2 changes: 1 addition & 1 deletion tests/run-macros/quote-matcher-runtime.check
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ Pattern: scala.StringContext.apply("abc", "xyz")
Result: Some(List())

Scrutinee: scala.StringContext.apply("abc", "xyz")
Pattern: scala.StringContext.apply(scala.quoted.runtime.Patterns.patternHole[java.lang.String], scala.quoted.runtime.Patterns.patternHole[java.lang.String])
Pattern: scala.StringContext.apply(scala.quoted.runtime.Patterns.patternHole[scala.Predef.String], scala.quoted.runtime.Patterns.patternHole[scala.Predef.String])
Result: Some(List(Expr("abc"), Expr("xyz")))

Scrutinee: scala.StringContext.apply("abc", "xyz")
Expand Down

0 comments on commit 11af161

Please sign in to comment.