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

Avoid crash when superType does not exist after erasure #20188

Merged
merged 3 commits into from
Apr 15, 2024
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
8 changes: 4 additions & 4 deletions compiler/src/dotty/tools/dotc/core/TypeErasure.scala
Original file line number Diff line number Diff line change
Expand Up @@ -751,12 +751,12 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst
private def checkedSuperType(tp: TypeProxy)(using Context): Type =
val tp1 = tp.translucentSuperType
if !tp1.exists then
val msg = tp.typeConstructor match
val typeErr = tp.typeConstructor match
case tycon: TypeRef =>
MissingType(tycon.prefix, tycon.name).toMessage.message
MissingType(tycon.prefix, tycon.name)
case _ =>
i"Cannot resolve reference to $tp"
throw FatalError(msg)
TypeError(em"Cannot resolve reference to $tp")
throw typeErr
tp1

/** Widen term ref, skipping any `()` parameter of an eventual getter. Used to erase a TermRef.
Expand Down
3 changes: 2 additions & 1 deletion compiler/src/dotty/tools/dotc/core/TypeErrors.scala
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ abstract class TypeError(using creationContext: Context) extends Exception(""):
def toMessage(using Context): Message

/** Uses creationContext to produce the message */
override def getMessage: String = toMessage.message
override def getMessage: String =
try toMessage.message catch case ex: Throwable => "TypeError"

object TypeError:
def apply(msg: Message)(using Context) = new TypeError:
Expand Down
54 changes: 29 additions & 25 deletions compiler/src/dotty/tools/dotc/transform/TreeChecker.scala
Original file line number Diff line number Diff line change
Expand Up @@ -418,31 +418,35 @@ object TreeChecker {
}

override def typedUnadapted(tree: untpd.Tree, pt: Type, locked: TypeVars)(using Context): Tree = {
val res = tree match {
case _: untpd.TypedSplice | _: untpd.Thicket | _: EmptyValDef[?] =>
super.typedUnadapted(tree, pt, locked)
case _ if tree.isType =>
promote(tree)
case _ =>
val tree1 = super.typedUnadapted(tree, pt, locked)
def isSubType(tp1: Type, tp2: Type) =
(tp1 eq tp2) || // accept NoType / NoType
(tp1 <:< tp2)
def divergenceMsg(tp1: Type, tp2: Type) =
s"""Types differ
|Original type : ${tree.typeOpt.show}
|After checking: ${tree1.tpe.show}
|Original tree : ${tree.show}
|After checking: ${tree1.show}
|Why different :
""".stripMargin + core.TypeComparer.explained(_.isSubType(tp1, tp2))
if (tree.hasType) // it might not be typed because Typer sometimes constructs new untyped trees and resubmits them to typedUnadapted
assert(isSubType(tree1.tpe, tree.typeOpt), divergenceMsg(tree1.tpe, tree.typeOpt))
tree1
}
checkNoOrphans(res.tpe)
phasesToCheck.foreach(_.checkPostCondition(res))
res
try
val res = tree match
case _: untpd.TypedSplice | _: untpd.Thicket | _: EmptyValDef[?] =>
super.typedUnadapted(tree, pt, locked)
case _ if tree.isType =>
promote(tree)
case _ =>
val tree1 = super.typedUnadapted(tree, pt, locked)
def isSubType(tp1: Type, tp2: Type) =
(tp1 eq tp2) || // accept NoType / NoType
(tp1 <:< tp2)
def divergenceMsg(tp1: Type, tp2: Type) =
s"""Types differ
|Original type : ${tree.typeOpt.show}
|After checking: ${tree1.tpe.show}
|Original tree : ${tree.show}
|After checking: ${tree1.show}
|Why different :
""".stripMargin + core.TypeComparer.explained(_.isSubType(tp1, tp2))
if (tree.hasType) // it might not be typed because Typer sometimes constructs new untyped trees and resubmits them to typedUnadapted
assert(isSubType(tree1.tpe, tree.typeOpt), divergenceMsg(tree1.tpe, tree.typeOpt))
tree1
checkNoOrphans(res.tpe)
phasesToCheck.foreach(_.checkPostCondition(res))
res
catch case NonFatal(ex) if !ctx.run.enrichedErrorMessage =>
val treeStr = tree.show(using ctx.withPhase(ctx.phase.prev.megaPhase))
println(ctx.run.enrichErrorMessage(s"exception while retyping $treeStr of class ${tree.className} # ${tree.uniqueId}"))
throw ex
}

def checkNotRepeated(tree: Tree)(using Context): tree.type = {
Expand Down
7 changes: 0 additions & 7 deletions compiler/src/dotty/tools/dotc/typer/ReTyper.scala
Original file line number Diff line number Diff line change
Expand Up @@ -170,13 +170,6 @@ class ReTyper(nestingLevel: Int = 0) extends Typer(nestingLevel) with ReChecking
override def addCanThrowCapabilities(expr: untpd.Tree, cases: List[CaseDef])(using Context): untpd.Tree =
expr

override def typedUnadapted(tree: untpd.Tree, pt: Type, locked: TypeVars)(using Context): Tree =
try super.typedUnadapted(tree, pt, locked)
catch case NonFatal(ex) if ctx.phase != Phases.typerPhase && ctx.phase != Phases.inliningPhase && !ctx.run.enrichedErrorMessage =>
val treeStr = tree.show(using ctx.withPhase(ctx.phase.prev.megaPhase))
println(ctx.run.enrichErrorMessage(s"exception while retyping $treeStr of class ${tree.className} # ${tree.uniqueId}"))
throw ex

override def inlineExpansion(mdef: DefDef)(using Context): List[Tree] = mdef :: Nil

override def inferView(from: Tree, to: Type)(using Context): Implicits.SearchResult =
Expand Down
5 changes: 5 additions & 0 deletions tests/pos/i19929.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
trait A:
private type M

def foo(a: A{type M = Int}) =
val _: a.M = ??? // was crash
Loading