Skip to content
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

WIP: Keep skolem types when unpickling/bringing a denotation to a new run, in more cases #22856

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
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
47 changes: 36 additions & 11 deletions compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
@@ -2455,21 +2455,36 @@ object Types extends TypeUtils {
d
}

def fromDesignator = designator match {
def fromDesignator(lastdMaybe: Option[SingleDenotation]) = designator match {
case name: Name =>
val sym = lastSymbol
val allowPrivate = sym == null || (sym == NoSymbol) || sym.lastKnownDenotation.flagsUNSAFE.is(Private)
finish(memberDenot(name, allowPrivate))
case sym: Symbol =>
val symd = sym.lastKnownDenotation
if (symd.validFor.runId != ctx.runId && !stillValid(symd))
finish(memberDenot(symd.initial.name, allowPrivate = false))
else if (prefix.isArgPrefixOf(symd))
finish(argDenot(sym.asType))
else if (infoDependsOnPrefix(symd, prefix))
finish(memberDenot(symd.initial.name, allowPrivate = symd.is(Private)))
else
finish(symd.current)
if (symd.validFor.runId != ctx.runId && !stillValid(symd))
val res0 = memberDenot(symd.initial.name, allowPrivate = false)
val res = lastdMaybe match
case Some(lastd) if hasSkolems(lastd.info) =>
// When updating denotation, changing types from skolem may cause issues
// with other parts of the tree
finish(lastd.derivedSingleDenotation(res0.symbol, lastd.info, prefix))
case _ =>
res0
finish(res)
else if (prefix.isArgPrefixOf(symd))
finish(argDenot(sym.asType))
else if (infoDependsOnPrefix(symd, prefix))
val res = lastdMaybe match
case Some(lastd) if hasSkolems(lastd.info) =>
// When updating denotation, changing types from skolem may cause issues
// with other parts of the tree
finish(lastd.derivedSingleDenotation(sym, lastd.info, prefix))
case _ =>
memberDenot(symd.initial.name, allowPrivate = symd.is(Private))
finish(res)
else
finish(symd.current)
}

lastDenotation match {
@@ -2482,9 +2497,9 @@ object Types extends TypeUtils {
if stillValid(lastd) && checkedPeriod.code != NowhereCode then finish(lastd.current)
else finish(memberDenot(lastd.initial.name, allowPrivate = lastd.is(Private)))
case _ =>
fromDesignator
fromDesignator(Some(lastd))
}
case _ => fromDesignator
case _ => fromDesignator(None)
}
}

@@ -7024,6 +7039,16 @@ object Types extends TypeUtils {
def isStable = true
}

def hasSkolems(tpe: Type)(using Context) =
object hasSkolemsAcc extends TypeAccumulator[Boolean]:
def apply(x: Boolean, tp: Type): Boolean =
x || {
tp match
case _: SkolemType => true
case _ => foldOver(false, tp)
}
hasSkolemsAcc(false, tpe)

// ----- Debug ---------------------------------------------------------

@sharable var debugTrace: Boolean = false
3 changes: 2 additions & 1 deletion compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
Original file line number Diff line number Diff line change
@@ -507,7 +507,8 @@ class TreeUnpickler(reader: TastyReader,
private def readSymNameRef()(using Context): Type = {
val sym = readSymRef()
val prefix = readType()
val res = NamedType(prefix, sym)
def pre = if TypeOps.isLegalPrefix(prefix) then prefix else QualSkolemType(prefix)
val res = NamedType(pre, sym)
prefix match {
case prefix: ThisType if (prefix.cls eq sym.owner) && !sym.is(Opaque) =>
res.withDenot(sym.denot)
2 changes: 2 additions & 0 deletions compiler/test/dotc/run-test-pickling.excludelist
Original file line number Diff line number Diff line change
@@ -50,3 +50,5 @@ named-tuples-strawman-2.scala
typeCheckErrors.scala
i18150.scala

# issue caused by -Xprint-types
decorators
18 changes: 18 additions & 0 deletions tests/pos-macros/i22585-b/Macro.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import scala.quoted.*

object Hammer2 {
inline def makeProductHammerMacro[I, O](): Hammer[I, O] =
${ makeProductHammerMacroImpl[I, O] }

def makeProductHammerMacroImpl[I: Type, O: Type](using Quotes): Expr[Hammer[I, O]] =
'{ makeHammer[I, O]() }

inline def makeHammer[S, O](): Hammer[S, O] =
new Hammer[S, O] {
lazy val (hammer: Hammer[?, Int], idx: Int) = ???

override def hammer(input: S): O = {
hammer.hammer(???.asInstanceOf).asInstanceOf[O]
}
}
}
9 changes: 9 additions & 0 deletions tests/pos-macros/i22585-b/Test.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
trait Hammer[I, O] {
def hammer(input: I): O
}

object HammerSpec {
case class A(x: Int)
case class B(x: Int)
Hammer2.makeProductHammerMacro[A, B]()
}
22 changes: 22 additions & 0 deletions tests/pos-macros/i22585-c/Macro.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import scala.quoted.*

trait Hammer[I, O] {
def hammer(input: I): O
}

object Hammer {
inline def makeProductHammerMacro[I, O](): Hammer[I, O] =
${ makeProductHammerMacroImpl[I, O] }

def makeProductHammerMacroImpl[I: Type, O: Type](using Quotes): Expr[Hammer[I, O]] =
'{ makeHammer[I, O]() }

inline def makeHammer[S, O](): Hammer[S, O] =
new Hammer[S, O] {
lazy val (hammer: Hammer[?, Int], idx: Int) = ???

override def hammer(input: S): O = {
hammer.hammer(???.asInstanceOf).asInstanceOf[O]
}
}
}
5 changes: 5 additions & 0 deletions tests/pos-macros/i22585-c/Test.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
object HammerSpec {
case class A(x: Int)
case class B(x: Int)
Hammer.makeProductHammerMacro[A, B]()
}
16 changes: 16 additions & 0 deletions tests/pos/i22585-a/inline_1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import scala.quoted.*

trait Hammer[I, O] {
def hammer(input: I): O
}

object Hammer {
inline def makeHammer[S, O](): Hammer[S, O] =
new Hammer[S, O] {
lazy val (hammer: Hammer[?, Int], idx: Int) = ???

override def hammer(input: S): O = {
hammer.hammer(???.asInstanceOf).asInstanceOf[O]
}
}
}
5 changes: 5 additions & 0 deletions tests/pos/i22585-a/main_2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
object HammerSpec {
case class A(x: Int)
case class B(x: Int)
Hammer.makeHammer[A, B]()
}
Loading
Oops, something went wrong.