Skip to content

Commit

Permalink
Expr#show: Don't crash when the expression contains an unsupported ty…
Browse files Browse the repository at this point in the history
…pe (like a SkolemType)

When the SkolemType appears as the prefix of a TypeRef, we avoid it by going
using `qualifier` which is defined in QuotesImpl to widen skolem, but skolems
can appear in any position, and so before this change we would get a compiler
crash in the added test case where the skolem appears as the prefix of a
TermRef.

We fix this by adding fallback cases in the quotes pretty-printer, now for the
test case we get:

    Test.f.ho(((arg: <<SkolemType(693709097) does not have a corresponding extractor> does not have a source representation>.x.type) => arg))

Which isn't great, but better than a crash.

Maybe we should run `Type#deskolemized` on a type before trying to print it in
SourceCode/Extractors, but currently these files are intentionally defined to
not depend on compiler internals and do not have a `Context` so we cannot even
call `deskolemized` on them.

Alternatively, maybe SkolemType should be a tasty-reflect constructor but that
would also be a pretty big change.
  • Loading branch information
smarter committed Sep 26, 2024
1 parent eb5c3e8 commit 0ee8762
Show file tree
Hide file tree
Showing 5 changed files with 30 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@ object Extractors {
this += "Alternatives(" ++= patterns += ")"
case TypedOrTest(tree, tpt) =>
this += "TypedOrTest(" += tree += ", " += tpt += ")"
case tree =>
this += s"<Internal compiler AST $tree does not have a corresponding reflect extractor>"
}

def visitConstant(x: Constant): this.type = x match {
Expand Down Expand Up @@ -241,6 +243,8 @@ object Extractors {
this += "MatchCase(" += pat += ", " += rhs += ")"
case FlexibleType(tp) =>
this += "FlexibleType(" += tp += ")"
case tp =>
this += s"<Internal compiler type $tp does not have a corresponding reflect extractor>"
}

def visitSignature(sig: Signature): this.type = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1292,7 +1292,9 @@ object SourceCode {
val sym = annot.tpe.typeSymbol
sym != Symbol.requiredClass("scala.forceInline") &&
sym.maybeOwner != Symbol.requiredPackage("scala.annotation.internal")
case x => cannotBeShownAsSource(x.show(using Printer.TreeStructure))
case x =>
cannotBeShownAsSource(x.show(using Printer.TreeStructure))
false
}
printAnnotations(annots)
if (annots.nonEmpty) this += " "
Expand Down Expand Up @@ -1463,8 +1465,8 @@ object SourceCode {
}
}

private def cannotBeShownAsSource(x: String): Nothing =
throw new Exception(s"$x does not have a source representation")
private def cannotBeShownAsSource(x: String): this.type =
this += s"<$x does not have a source representation>"

private object SpecialOp {
def unapply(arg: Tree): Option[(String, List[Term])] = arg match {
Expand Down
10 changes: 10 additions & 0 deletions tests/pos-macros/skolem/Macro_1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import scala.quoted.*

object Macro {

def impl(expr: Expr[Any])(using Quotes): Expr[Unit] =
println(expr.show)
'{ () }

inline def macr(inline x: Any): Unit = ${impl('x)}
}
9 changes: 9 additions & 0 deletions tests/pos-macros/skolem/Test_2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
trait Foo:
val x: Int
def ho(p: x.type => x.type): Unit = ()

object Test {
var f: Foo = ???
Macro.macr:
f.ho(arg => arg)
}
4 changes: 2 additions & 2 deletions tests/run-macros/i19905.check
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
java.lang.Exception: NoPrefix() does not have a source representation
java.lang.Exception: NoPrefix() does not have a source representation
<NoPrefix() does not have a source representation>
<NoPrefix() does not have a source representation>
NoPrefix()

0 comments on commit 0ee8762

Please sign in to comment.