Skip to content

Commit 29ca0dc

Browse files
authored
Error instead of crash when generating trees referring to skolems (#24380)
Previously, the valueOf inline call succeeded (because the ValueOf synthesizer calls `ref` which calls `singleton`), leading to an invalid tree which crashed in the backend with: "assertion failed: Cannot create ClassBType from NoSymbol"
2 parents 6903682 + 451a4b5 commit 29ca0dc

File tree

7 files changed

+50
-45
lines changed

7 files changed

+50
-45
lines changed

compiler/src/dotty/tools/dotc/ast/tpd.scala

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,15 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
480480
else if tp.symbol.hasAnnotation(defn.ScalaStaticAnnot) then
481481
Ident(tp)
482482
else
483+
// Throw an error here if we detect a skolem to improve the error message in tests/neg/i8623.scala
484+
def checkNoSkolemInPrefix(pre: Type): Unit = pre.dealias match
485+
case pre: SkolemType =>
486+
throw TypeError(em"cannot construct a tree referring to $tp because of skolem prefix $pre")
487+
case pre: TermRef => checkNoSkolemInPrefix(pre.prefix)
488+
case _ =>
489+
483490
val pre = tp.prefix
491+
checkNoSkolemInPrefix(tp)
484492
if pre.isSingleton then followOuterLinks(singleton(pre.dealias, needLoad)).select(tp)
485493
else
486494
val res = Select(TypeTree(pre), tp)
@@ -517,9 +525,10 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
517525
def singleton(tp: Type, needLoad: Boolean = true)(using Context): Tree = tp.dealias match {
518526
case tp: TermRef => ref(tp, needLoad)
519527
case tp: ThisType => This(tp.cls)
520-
case tp: SkolemType => singleton(tp.narrow(), needLoad)
521528
case SuperType(qual, _) => singleton(qual, needLoad)
522529
case ConstantType(value) => Literal(value)
530+
case tp: SkolemType =>
531+
throw TypeError(em"cannot construct a tree referring to skolem $tp")
523532
}
524533

525534
/** A tree representing a `newXYZArray` operation of the right

compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ enum ErrorMessageID(val isActive: Boolean = true) extends java.lang.Enum[ErrorMe
155155
case UnknownNamedEnclosingClassOrObjectID // errorNumber: 139
156156
case IllegalCyclicTypeReferenceID // errorNumber: 140
157157
case MissingTypeParameterInTypeAppID // errorNumber: 141
158-
case SkolemInInferredID // errorNumber: 142
158+
case SkolemInInferredID extends ErrorMessageID(isActive = false) // errorNumber: 142
159159
case ErasedTypesCanOnlyBeFunctionTypesID // errorNumber: 143
160160
case CaseClassMissingNonImplicitParamListID // errorNumber: 144
161161
case EnumerationsShouldNotBeEmptyID // errorNumber: 145

compiler/src/dotty/tools/dotc/reporting/messages.scala

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1353,25 +1353,6 @@ extends CyclicMsg(CyclicReferenceInvolvingImplicitID) {
13531353
|"""
13541354
}
13551355

1356-
class SkolemInInferred(tree: tpd.Tree, pt: Type, argument: tpd.Tree)(using Context)
1357-
extends TypeMsg(SkolemInInferredID):
1358-
def msg(using Context) =
1359-
def argStr =
1360-
if argument.isEmpty then ""
1361-
else i" from argument of type ${argument.tpe.widen}"
1362-
i"""Failure to generate given instance for type $pt$argStr)
1363-
|
1364-
|I found: $tree
1365-
|But the part corresponding to `<skolem>` is not a reference that can be generated.
1366-
|This might be because resolution yielded as given instance a function that is not
1367-
|known to be total and side-effect free."""
1368-
def explain(using Context) =
1369-
i"""The part of given resolution that corresponds to `<skolem>` produced a term that
1370-
|is not a stable reference. Therefore a given instance could not be generated.
1371-
|
1372-
|To trouble-shoot the problem, try to supply an explicit expression instead of
1373-
|relying on implicit search at this point."""
1374-
13751356
class SuperQualMustBeParent(qual: untpd.Ident, cls: ClassSymbol)(using Context)
13761357
extends ReferenceMsg(SuperQualMustBeParentID) {
13771358
def msg(using Context) = i"""|$qual does not name a parent of $cls"""

compiler/src/dotty/tools/dotc/typer/Implicits.scala

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1082,18 +1082,6 @@ trait Implicits:
10821082
val res = implicitArgTree(defn.CanEqualClass.typeRef.appliedTo(ltp, rtp), span)
10831083
implicits.println(i"CanEqual witness found for $ltp / $rtp: $res: ${res.tpe}")
10841084

1085-
object hasSkolem extends TreeAccumulator[Boolean]:
1086-
def apply(x: Boolean, tree: Tree)(using Context): Boolean =
1087-
x || {
1088-
tree match
1089-
case tree: Ident => tree.symbol.isSkolem
1090-
case Select(qual, _) => apply(x, qual)
1091-
case Apply(fn, _) => apply(x, fn)
1092-
case TypeApply(fn, _) => apply(x, fn)
1093-
case _: This => false
1094-
case _ => foldOver(x, tree)
1095-
}
1096-
10971085
/** Find an implicit parameter or conversion.
10981086
* @param pt The expected type of the parameter or conversion.
10991087
* @param argument If an implicit conversion is searched, the argument to which
@@ -1141,8 +1129,6 @@ trait Implicits:
11411129
result.tstate.commit()
11421130
if result.gstate ne ctx.gadt then
11431131
ctx.gadtState.restore(result.gstate)
1144-
if hasSkolem(false, result.tree) then
1145-
report.error(SkolemInInferred(result.tree, pt, argument), ctx.source.atSpan(span))
11461132
implicits.println(i"success: $result")
11471133
implicits.println(i"committing ${result.tstate.constraint} yielding ${ctx.typerState.constraint} in ${ctx.typerState}")
11481134
result

compiler/src/dotty/tools/dotc/typer/Synthesizer.scala

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -828,7 +828,14 @@ object Synthesizer:
828828

829829
/** Tuple used to store the synthesis result with a list of errors. */
830830
type TreeWithErrors = (Tree, List[String])
831-
private def withNoErrors(tree: Tree): TreeWithErrors = (tree, List.empty)
831+
832+
private inline def withNoErrors(inline tree: => Tree): TreeWithErrors =
833+
try
834+
(tree, List.empty)
835+
catch
836+
case tp: TypeError =>
837+
withErrors(tp.getMessage)
838+
832839
private def withErrors(errors: String*): TreeWithErrors = (EmptyTree, errors.toList)
833840

834841
private val EmptyTreeNoError: TreeWithErrors = withNoErrors(EmptyTree)

tests/neg/i8623.check

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
1-
-- [E142] Type Error: tests/neg/i8623.scala:11:2 -----------------------------------------------------------------------
1+
-- [E008] Not Found Error: tests/neg/i8623.scala:11:9 ------------------------------------------------------------------
22
11 | unseal.pos // error
3-
| ^^^^^^
4-
| Failure to generate given instance for type ?{ pos: ? } from argument of type ?1.tasty.Tree)
3+
| ^^^^^^^^^^
4+
| value pos is not a member of ?1.tasty.Tree.
5+
| Extension methods were tried, but the search failed with:
56
|
6-
| I found: <skolem>.tasty.pos(unseal(given_QC[Any]))
7-
| But the part corresponding to `<skolem>` is not a reference that can be generated.
8-
| This might be because resolution yielded as given instance a function that is not
9-
| known to be total and side-effect free.
7+
| cannot construct a tree referring to ?1.tasty.type because of skolem prefix (?1 : QC)
8+
|
9+
| where: ?1 is an unknown value of type QC
10+
|
1011
|
1112
| where: ?1 is an unknown value of type QC
12-
|
13-
| longer explanation available when compiling with `-explain`

tests/neg/valueOf-skolem.scala

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
case class Foo(
2+
aaaa: Int
3+
)
4+
5+
case class Bar(
6+
foo: Foo,
7+
bar: Bla[foo.aaaa.type]
8+
)
9+
10+
class Bla[T](using Ev[T])
11+
12+
class Ev[T](x: T)
13+
object Ev:
14+
inline given ev: [T] => Ev[T] =
15+
Ev(valueOf[T])
16+
17+
object Test:
18+
def test: Unit =
19+
val x =
20+
Bar(
21+
Foo(0),
22+
Bla() // error
23+
)

0 commit comments

Comments
 (0)