Skip to content
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
11 changes: 10 additions & 1 deletion compiler/src/dotty/tools/dotc/ast/tpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,15 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
else if tp.symbol.hasAnnotation(defn.ScalaStaticAnnot) then
Ident(tp)
else
// Throw an error here if we detect a skolem to improve the error message in tests/neg/i8623.scala
def checkNoSkolemInPrefix(pre: Type): Unit = pre.dealias match
case pre: SkolemType =>
throw TypeError(em"cannot construct a tree referring to $tp because of skolem prefix $pre")
case pre: TermRef => checkNoSkolemInPrefix(pre.prefix)
case _ =>

val pre = tp.prefix
checkNoSkolemInPrefix(tp)
if pre.isSingleton then followOuterLinks(singleton(pre.dealias, needLoad)).select(tp)
else
val res = Select(TypeTree(pre), tp)
Expand Down Expand Up @@ -517,9 +525,10 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
def singleton(tp: Type, needLoad: Boolean = true)(using Context): Tree = tp.dealias match {
case tp: TermRef => ref(tp, needLoad)
case tp: ThisType => This(tp.cls)
case tp: SkolemType => singleton(tp.narrow(), needLoad)
case SuperType(qual, _) => singleton(qual, needLoad)
case ConstantType(value) => Literal(value)
case tp: SkolemType =>
throw TypeError(em"cannot construct a tree referring to skolem $tp")
}

/** A tree representing a `newXYZArray` operation of the right
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ enum ErrorMessageID(val isActive: Boolean = true) extends java.lang.Enum[ErrorMe
case UnknownNamedEnclosingClassOrObjectID // errorNumber: 139
case IllegalCyclicTypeReferenceID // errorNumber: 140
case MissingTypeParameterInTypeAppID // errorNumber: 141
case SkolemInInferredID // errorNumber: 142
case SkolemInInferredID extends ErrorMessageID(isActive = false) // errorNumber: 142
case ErasedTypesCanOnlyBeFunctionTypesID // errorNumber: 143
case CaseClassMissingNonImplicitParamListID // errorNumber: 144
case EnumerationsShouldNotBeEmptyID // errorNumber: 145
Expand Down
19 changes: 0 additions & 19 deletions compiler/src/dotty/tools/dotc/reporting/messages.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1353,25 +1353,6 @@ extends CyclicMsg(CyclicReferenceInvolvingImplicitID) {
|"""
}

class SkolemInInferred(tree: tpd.Tree, pt: Type, argument: tpd.Tree)(using Context)
extends TypeMsg(SkolemInInferredID):
def msg(using Context) =
def argStr =
if argument.isEmpty then ""
else i" from argument of type ${argument.tpe.widen}"
i"""Failure to generate given instance for type $pt$argStr)
|
|I found: $tree
|But the part corresponding to `<skolem>` is not a reference that can be generated.
|This might be because resolution yielded as given instance a function that is not
|known to be total and side-effect free."""
def explain(using Context) =
i"""The part of given resolution that corresponds to `<skolem>` produced a term that
|is not a stable reference. Therefore a given instance could not be generated.
|
|To trouble-shoot the problem, try to supply an explicit expression instead of
|relying on implicit search at this point."""

class SuperQualMustBeParent(qual: untpd.Ident, cls: ClassSymbol)(using Context)
extends ReferenceMsg(SuperQualMustBeParentID) {
def msg(using Context) = i"""|$qual does not name a parent of $cls"""
Expand Down
14 changes: 0 additions & 14 deletions compiler/src/dotty/tools/dotc/typer/Implicits.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1089,18 +1089,6 @@ trait Implicits:
val res = implicitArgTree(defn.CanEqualClass.typeRef.appliedTo(ltp, rtp), span)
implicits.println(i"CanEqual witness found for $ltp / $rtp: $res: ${res.tpe}")

object hasSkolem extends TreeAccumulator[Boolean]:
def apply(x: Boolean, tree: Tree)(using Context): Boolean =
x || {
tree match
case tree: Ident => tree.symbol.isSkolem
case Select(qual, _) => apply(x, qual)
case Apply(fn, _) => apply(x, fn)
case TypeApply(fn, _) => apply(x, fn)
case _: This => false
case _ => foldOver(x, tree)
}

/** Find an implicit parameter or conversion.
* @param pt The expected type of the parameter or conversion.
* @param argument If an implicit conversion is searched, the argument to which
Expand Down Expand Up @@ -1148,8 +1136,6 @@ trait Implicits:
result.tstate.commit()
if result.gstate ne ctx.gadt then
ctx.gadtState.restore(result.gstate)
if hasSkolem(false, result.tree) then
report.error(SkolemInInferred(result.tree, pt, argument), ctx.source.atSpan(span))
implicits.println(i"success: $result")
implicits.println(i"committing ${result.tstate.constraint} yielding ${ctx.typerState.constraint} in ${ctx.typerState}")
result
Expand Down
9 changes: 8 additions & 1 deletion compiler/src/dotty/tools/dotc/typer/Synthesizer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -828,7 +828,14 @@ object Synthesizer:

/** Tuple used to store the synthesis result with a list of errors. */
type TreeWithErrors = (Tree, List[String])
private def withNoErrors(tree: Tree): TreeWithErrors = (tree, List.empty)

private inline def withNoErrors(inline tree: => Tree): TreeWithErrors =
try
(tree, List.empty)
catch
case tp: TypeError =>
withErrors(tp.getMessage)

private def withErrors(errors: String*): TreeWithErrors = (EmptyTree, errors.toList)

private val EmptyTreeNoError: TreeWithErrors = withNoErrors(EmptyTree)
Expand Down
17 changes: 8 additions & 9 deletions tests/neg/i8623.check
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
-- [E142] Type Error: tests/neg/i8623.scala:11:2 -----------------------------------------------------------------------
-- [E008] Not Found Error: tests/neg/i8623.scala:11:9 ------------------------------------------------------------------
11 | unseal.pos // error
| ^^^^^^
| Failure to generate given instance for type ?{ pos: ? } from argument of type ?1.tasty.Tree)
| ^^^^^^^^^^
| value pos is not a member of ?1.tasty.Tree.
| Extension methods were tried, but the search failed with:
|
| I found: <skolem>.tasty.pos(unseal(given_QC[Any]))
| But the part corresponding to `<skolem>` is not a reference that can be generated.
| This might be because resolution yielded as given instance a function that is not
| known to be total and side-effect free.
| cannot construct a tree referring to ?1.tasty.type because of skolem prefix (?1 : QC)
|
| where: ?1 is an unknown value of type QC
|
|
| where: ?1 is an unknown value of type QC
|
| longer explanation available when compiling with `-explain`
23 changes: 23 additions & 0 deletions tests/neg/valueOf-skolem.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
case class Foo(
aaaa: Int
)

case class Bar(
foo: Foo,
bar: Bla[foo.aaaa.type]
)

class Bla[T](using Ev[T])

class Ev[T](x: T)
object Ev:
inline given ev: [T] => Ev[T] =
Ev(valueOf[T])

object Test:
def test: Unit =
val x =
Bar(
Foo(0),
Bla() // error
)
Loading