Skip to content

Commit a872390

Browse files
committed
Error instead of crash when generating trees referring to skolems
Previously, the valueOf inline call succeeded (because the ValueOf synthesizer calls `tpd.ref` which calls `tpd.singleton`), leading to an invalid tree which crashed in the backend with: "assertion failed: Cannot create ClassBType from NoSymbol". Fixed by throwing a TypeError from `tpd.singleton`, unfortunatley this means tests/neg/i8623.scala gets a worse error message because the implicit search fails early, but arguably this is more correct.
1 parent 32bfd5f commit a872390

File tree

7 files changed

+40
-45
lines changed

7 files changed

+40
-45
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -517,9 +517,10 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
517517
def singleton(tp: Type, needLoad: Boolean = true)(using Context): Tree = tp.dealias match {
518518
case tp: TermRef => ref(tp, needLoad)
519519
case tp: ThisType => This(tp.cls)
520-
case tp: SkolemType => singleton(tp.narrow(), needLoad)
521520
case SuperType(qual, _) => singleton(qual, needLoad)
522521
case ConstantType(value) => Literal(value)
522+
case tp: SkolemType =>
523+
throw TypeError(em"cannot construct a tree referring to skolem $tp")
523524
}
524525

525526
/** 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
@@ -1089,18 +1089,6 @@ trait Implicits:
10891089
val res = implicitArgTree(defn.CanEqualClass.typeRef.appliedTo(ltp, rtp), span)
10901090
implicits.println(i"CanEqual witness found for $ltp / $rtp: $res: ${res.tpe}")
10911091

1092-
object hasSkolem extends TreeAccumulator[Boolean]:
1093-
def apply(x: Boolean, tree: Tree)(using Context): Boolean =
1094-
x || {
1095-
tree match
1096-
case tree: Ident => tree.symbol.isSkolem
1097-
case Select(qual, _) => apply(x, qual)
1098-
case Apply(fn, _) => apply(x, fn)
1099-
case TypeApply(fn, _) => apply(x, fn)
1100-
case _: This => false
1101-
case _ => foldOver(x, tree)
1102-
}
1103-
11041092
/** Find an implicit parameter or conversion.
11051093
* @param pt The expected type of the parameter or conversion.
11061094
* @param argument If an implicit conversion is searched, the argument to which
@@ -1148,8 +1136,6 @@ trait Implicits:
11481136
result.tstate.commit()
11491137
if result.gstate ne ctx.gadt then
11501138
ctx.gadtState.restore(result.gstate)
1151-
if hasSkolem(false, result.tree) then
1152-
report.error(SkolemInInferred(result.tree, pt, argument), ctx.source.atSpan(span))
11531139
implicits.println(i"success: $result")
11541140
implicits.println(i"committing ${result.tstate.constraint} yielding ${ctx.typerState.constraint} in ${ctx.typerState}")
11551141
result

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -828,7 +828,12 @@ 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+
private inline def withNoErrors(inline tree: => Tree): TreeWithErrors =
832+
try
833+
(tree, List.empty)
834+
catch
835+
case tp: TypeError =>
836+
withErrors(tp.getMessage)
832837
private def withErrors(errors: String*): TreeWithErrors = (EmptyTree, errors.toList)
833838

834839
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 skolem (?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)