diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index 909387bbb809..23dde1139c03 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -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) @@ -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 diff --git a/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala b/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala index 630adc0c0884..5f5a0c01db17 100644 --- a/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala +++ b/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala @@ -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 diff --git a/compiler/src/dotty/tools/dotc/reporting/messages.scala b/compiler/src/dotty/tools/dotc/reporting/messages.scala index c281cbab544e..a2afaab0ecce 100644 --- a/compiler/src/dotty/tools/dotc/reporting/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/messages.scala @@ -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 `` 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 `` 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""" diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index d3e3a0d06bd8..8b4e00a11d35 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -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 @@ -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 diff --git a/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala b/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala index 3b114de6a05c..7bfda4e4b5fa 100644 --- a/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala @@ -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) diff --git a/tests/neg/i8623.check b/tests/neg/i8623.check index 39337a7839d8..61c6988c3c37 100644 --- a/tests/neg/i8623.check +++ b/tests/neg/i8623.check @@ -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: .tasty.pos(unseal(given_QC[Any])) - | But the part corresponding to `` 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` diff --git a/tests/neg/valueOf-skolem.scala b/tests/neg/valueOf-skolem.scala new file mode 100644 index 000000000000..4507315e91da --- /dev/null +++ b/tests/neg/valueOf-skolem.scala @@ -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 + )