scala / scala3

The Scala 3 compiler, also known as Dotty.
https://dotty.epfl.ch
Apache License 2.0
5.86k stars 1.06k forks source link

Crasher in Term.show for Skolem type #13422

Closed jrudolph closed 3 years ago

jrudolph commented 3 years ago

Compiler version

3.0.1

Reproducer

With branch https://github.com/jrudolph/parboiled2/tree/skkolem-crasher run parboiledCoreJVM/Test/compile in sbt.

Output

scala.MatchError: Skolem(1943876506) (of class dotty.tools.dotc.core.Types$SkolemType)
    at scala.quoted.runtime.impl.printers.Extractors$ExtractorsPrinter.visitType(Extractors.scala:233)
    at scala.quoted.runtime.impl.printers.Extractors$.showType(Extractors.scala:12)
    at scala.quoted.runtime.impl.QuotesImpl$$anon$17.show(QuotesImpl.scala:2898)
    at scala.quoted.runtime.impl.QuotesImpl$$anon$17.show(QuotesImpl.scala:2897)
    at scala.quoted.runtime.impl.QuotesImpl$reflect$TypeReprMethods$.show(QuotesImpl.scala:1660)
    at scala.quoted.runtime.impl.QuotesImpl$reflect$TypeReprMethods$.show(QuotesImpl.scala:1660)
    at scala.quoted.runtime.impl.printers.SourceCode$SourceCodePrinter.printType(SourceCode.scala:1228)
    at scala.quoted.runtime.impl.printers.SourceCode$SourceCodePrinter.printType(SourceCode.scala:1102)
    at scala.quoted.runtime.impl.printers.SourceCode$SourceCodePrinter.printTypeAndAnnots$1(SourceCode.scala:1003)
    at scala.quoted.runtime.impl.printers.SourceCode$SourceCodePrinter.printTypeTree(SourceCode.scala:1005)
    at scala.quoted.runtime.impl.printers.SourceCode$SourceCodePrinter.printTree(SourceCode.scala:528)
    at scala.quoted.runtime.impl.printers.SourceCode$SourceCodePrinter.printTrees$$anonfun$1(SourceCode.scala:656)
    at scala.quoted.runtime.impl.printers.SourceCode$SourceCodePrinter.printSeparated$3(SourceCode.scala:647)
    at scala.quoted.runtime.impl.printers.SourceCode$SourceCodePrinter.printList(SourceCode.scala:651)
    at scala.quoted.runtime.impl.printers.SourceCode$SourceCodePrinter.printTrees(SourceCode.scala:656)
    at scala.quoted.runtime.impl.printers.SourceCode$SourceCodePrinter.printTree$$anonfun$8(SourceCode.scala:418)
    at scala.quoted.runtime.impl.printers.SourceCode$SourceCodePrinter.inSquare(SourceCode.scala:88)
    at scala.quoted.runtime.impl.printers.SourceCode$SourceCodePrinter.printTree(SourceCode.scala:418)
    at scala.quoted.runtime.impl.printers.SourceCode$SourceCodePrinter.printQualTree(SourceCode.scala:546)
    at scala.quoted.runtime.impl.printers.SourceCode$SourceCodePrinter.printTree(SourceCode.scala:399)
    at scala.quoted.runtime.impl.printers.SourceCode$SourceCodePrinter.printQualTree(SourceCode.scala:546)
    at scala.quoted.runtime.impl.printers.SourceCode$SourceCodePrinter.printTree(SourceCode.scala:399)
    at scala.quoted.runtime.impl.printers.SourceCode$.showTree(SourceCode.scala:10)
    at scala.quoted.runtime.impl.QuotesImpl$$anon$10.show(QuotesImpl.scala:2870)
    at scala.quoted.runtime.impl.QuotesImpl$$anon$10.show(QuotesImpl.scala:2869)
    at scala.quoted.runtime.impl.QuotesImpl$reflect$TreeMethods$.show(QuotesImpl.scala:95)
    at scala.quoted.runtime.impl.QuotesImpl$reflect$TreeMethods$.show(QuotesImpl.scala:95)
nicolasstucki commented 3 years ago

I could not start SBT on that project

error: error while loading AnnotatedElement, class file '/usr/local/Cellar/openjdk@8/1.8.0+282/libexec/openjdk.jdk/Contents/Home/jre/lib/rt.jar(java/lang/reflect/AnnotatedElement.class)' is broken
(bad constant pool tag 18 at byte 76)
error: error while loading CharSequence, class file '/usr/local/Cellar/openjdk@8/1.8.0+282/libexec/openjdk.jdk/Contents/Home/jre/lib/rt.jar(java/lang/CharSequence.class)' is broken
(bad constant pool tag 18 at byte 10)

@jrudolph what version of the JDK are you using? Or could you help me minimize the issue?

nicolasstucki commented 3 years ago

Self contained version

Macro_1.scala ```scala package org.parboiled2 import scala.annotation.unchecked.uncheckedVariance import scala.annotation.compileTimeOnly import scala.collection.immutable import org.parboiled2.support._ import org.parboiled2.support.hlist.HList import org.parboiled2.support.hlist.ops.hlist.Prepend import org.parboiled2.support._ import org.parboiled2.support.hlist._ inline def rule(inline r: Any): Unit = ${ ParserMacros.ruleImpl('r) } object ParserMacros { import scala.quoted._ def ruleImpl(r: Expr[Any])(using Quotes): Expr[Unit] = { import quotes.reflect.* r.asTerm.show throw new Throwable("OK") } } sealed class Rule[-I <: HList, +O <: HList] { def ~[I2 <: HList, O2 <: HList](that: Rule[I2, O2])(implicit i: TailSwitch[I2, O @uncheckedVariance, I @uncheckedVariance], o: TailSwitch[O @uncheckedVariance, I2, O2] ): Rule[i.Out, o.Out] = ??? } package support { import org.parboiled2.support.hlist._ import org.parboiled2.Rule import org.parboiled2.support.hlist.ops.hlist.Prepend sealed trait FCapture[T] object FCapture { implicit def apply[T]: FCapture[T] = ??? } sealed trait Join[I <: HList, L <: HList, R] { type In <: HList type Out <: HList } object Join extends LowPrioJoin { implicit def forHList[I <: HList, L <: HList, R <: HList, O <: HList](implicit x: Prepend.Aux[L, R, O] ): Aux[I, L, R, I, O] = ??? } sealed abstract class LowPrioJoin { type Aux[I <: HList, L <: HList, R, In0 <: HList, Out0 <: HList] = Join[I, L, R] { type In = In0; type Out = Out0 } implicit def forAny[I <: HList, L <: HList, R, In <: HList, Out <: HList](implicit x: Aux[I, L, R :: HNil, In, Out] ): Aux[I, L, R, In, Out] = ??? } package hlist { sealed trait HList extends Product with Serializable final case class ::[+H, +T <: HList](head: H, tail: T) extends HList sealed trait HNil extends HList case object HNil extends HNil object HList { import org.parboiled2.support.hlist.syntax.HListOps implicit def hlistOps[L <: HList](l: L): HListOps[L] = new HListOps(l) } package ops { object hlist { trait DepFn2[T, U] { type Out def apply(t: T, u: U): Out } trait Prepend[P <: HList, S <: HList] extends DepFn2[P, S] with Serializable { type Out <: HList } trait LowestPriorityPrepend { type Aux[P <: HList, S <: HList, Out0 <: HList] = Prepend[P, S] { type Out = Out0 } implicit def hlistPrepend[PH, PT <: HList, S <: HList, PtOut <: HList](implicit pt: Prepend.Aux[PT, S, PtOut] ): Prepend.Aux[PH :: PT, S, PH :: PtOut] = new Prepend[PH :: PT, S] { type Out = PH :: PtOut def apply(prefix: PH :: PT, suffix: S): Out = prefix.head :: pt(prefix.tail, suffix) } } trait LowPriorityPrepend extends LowestPriorityPrepend { override type Aux[P <: HList, S <: HList, Out0 <: HList] = Prepend[P, S] { type Out = Out0 } implicit def hnilPrepend0[P <: HList, S >: HNil.type <: HNil]: Aux[P, S, P] = new Prepend[P, S] { type Out = P def apply(prefix: P, suffix: S): P = prefix } } object Prepend extends LowPriorityPrepend { def apply[P <: HList, S <: HList](implicit prepend: Prepend[P, S]): Aux[P, S, prepend.Out] = prepend implicit def hnilPrepend1[P >: HNil.type <: HNil, S <: HList]: Aux[P, S, S] = new Prepend[P, S] { type Out = S def apply(prefix: P, suffix: S): S = suffix } } } } package syntax { final class HListOps[L <: HList](l: L) extends Serializable { def ::[H](h: H): H :: L = org.parboiled2.support.hlist.::(h, l) } } } sealed trait Lifter[M[_], I <: HList, O <: HList] { type In <: HList type StrictOut <: HList type OptionalOut <: HList } object Lifter { implicit def forReduction[M[_], L <: HList, R <: L]: Lifter[M, L, R] { type In = L type StrictOut = R type OptionalOut = L } = ??? } sealed trait TailSwitch[L <: HList, T <: HList, R <: HList] { type Out <: HList } object TailSwitch { type TailSwitch0[L <: HList, TI <: HList, R <: HList] <: HList = TI match { case L => R } type Aux[L <: HList, LI <: HList, T <: HList, TI <: HList, R <: HList, RI <: HList, Out <: HList] = TailSwitch[L, T, R] { type Out = R } implicit def tailSwitch[L <: HList, T <: HList, R <: HList]: TailSwitch[L, T, R] { type Out = T match { case L => R } } = ??? } sealed trait ActionOps[I <: HList, O <: HList] { type Out } object ActionOps { implicit def ops1[II <: HList, A]: ActionOps[II, A :: HNil] { type Out = Ops1[II, A] } = ??? sealed trait Ops1[II <: HList, A] { def apply[Z, RR](f: (Z, A) => RR) (implicit j: Join[Z :: II, HNil, RR], c: FCapture[(Z, A) => RR]): Rule[j.In, j.Out] } } } ```
Test_2.scala ```scala package org.parboiled2 import org.parboiled2.support.hlist._ import org.parboiled2.support._ abstract class Calculator { def Expression = rule { (??? : Rule[HNil, Int :: HNil]) ~ zeroOrMore( rule2ActionOperator((??? : Rule[HNil, HNil]) ~ (??? : Rule[HNil, Int :: HNil])) ~> ((_: Int) + _) ) } def zeroOrMore[I <: HList, O <: HList](r: Rule[I, O])(implicit l: Lifter[scala.collection.immutable.Seq, I, O] ): Rule[l.In, l.OptionalOut] = ??? def rule2ActionOperator[I <: HList, O <: HList](r: Rule[I, O])(implicit ops: ActionOps[I, O] ): ActionOperator[I, O, ops.Out] = ??? sealed trait ActionOperator[I <: HList, O <: HList, Ops] { def ~> : Ops } } ```
nicolasstucki commented 3 years ago

Slightly minimized

Macro_1.scala ```scala package org.parboiled2 import scala.annotation.unchecked.uncheckedVariance import org.parboiled2.support._ import org.parboiled2.support.hlist._ inline def rule(inline r: Any): Unit = ${ ParserMacros.ruleImpl('r) } object ParserMacros { import scala.quoted._ def ruleImpl(r: Expr[Any])(using Quotes): Expr[Unit] = { import quotes.reflect.* r.asTerm.show throw new Throwable("OK") } } sealed class Rule[-I <: HList, +O <: HList] { def ~[I2 <: HList, O2 <: HList](that: Rule[I2, O2])(implicit i: TailSwitch[I2, O @uncheckedVariance, I @uncheckedVariance], o: TailSwitch[O @uncheckedVariance, I2, O2] ): Rule[i.Out, o.Out] = ??? } package support { sealed trait FCapture[T] object FCapture { implicit def apply[T]: FCapture[T] = ??? } sealed trait Join[I <: HList, L <: HList, R] { type In <: HList type Out <: HList } object Join extends LowPrioJoin { implicit def forHList[I <: HList, L <: HList, R <: HList, O <: HList](implicit x: Prepend.Aux[L, R, O] ): Aux[I, L, R, I, O] = ??? } sealed abstract class LowPrioJoin { type Aux[I <: HList, L <: HList, R, In0 <: HList, Out0 <: HList] = Join[I, L, R] { type In = In0; type Out = Out0 } implicit def forAny[I <: HList, L <: HList, R, In <: HList, Out <: HList](implicit x: Aux[I, L, R :: HNil, In, Out] ): Aux[I, L, R, In, Out] = ??? } package hlist { sealed trait HList extends Product with Serializable final case class ::[+H, +T <: HList](head: H, tail: T) extends HList sealed trait HNil extends HList case object HNil extends HNil trait Prepend[P <: HList, S <: HList] { type Out <: HList } object Prepend { type Aux[P <: HList, S <: HList, Out0 <: HList] = Prepend[P, S] { type Out = Out0 } implicit def hlistPrepend[PH, PT <: HList, S <: HList, PtOut <: HList](implicit pt: Prepend.Aux[PT, S, PtOut]): Prepend.Aux[PH :: PT, S, PH :: PtOut] = ??? implicit def hnilPrepend1[P >: HNil.type <: HNil, S <: HList]: Aux[P, S, S] = ??? } } sealed trait TailSwitch[L <: HList, T <: HList, R <: HList] { type Out <: HList } object TailSwitch { type TailSwitch0[L <: HList, TI <: HList, R <: HList] <: HList = TI match { case L => R } type Aux[L <: HList, LI <: HList, T <: HList, TI <: HList, R <: HList, RI <: HList, Out <: HList] = TailSwitch[L, T, R] { type Out = R } implicit def tailSwitch[L <: HList, T <: HList, R <: HList]: TailSwitch[L, T, R] { type Out = T match { case L => R } } = ??? } sealed trait ActionOps[I <: HList, O <: HList] { type Out } object ActionOps { def ops1[II <: HList, A]: ActionOps[II, A :: HNil] { type Out = Ops1[II, A] } = ??? sealed trait Ops1[II <: HList, A] { def apply[Z, RR](f: (Z, A) => RR) (implicit j: Join[Z :: II, HNil, RR], c: FCapture[(Z, A) => RR]): Rule[j.In, j.Out] } } } ```
Test_2.scala ```scala package org.parboiled2 import org.parboiled2.support.hlist._ import org.parboiled2.support._ abstract class Calculator { def Expression = rule { rule2ActionOperator((??? : Rule[HNil, HNil]).~[HNil, Int :: HNil](???))(ActionOps.ops1) } def zeroOrMore[I <: HList, O <: HList](r: Rule[I, O]): Rule[Nothing, Nothing] = ??? def rule2ActionOperator[I <: HList, O <: HList](r: Rule[I, O])(ops: ActionOps[I, O]): ActionOperator[I, O, ops.Out] = ??? sealed trait ActionOperator[I <: HList, O <: HList, Ops] { def ~> : Ops } } ```
nicolasstucki commented 3 years ago

Minimized

import scala.quoted._

inline def rule(inline r: Any): Unit = ${ ruleImpl('r) }

def ruleImpl(r: Expr[Any])(using Quotes): Expr[Unit] = {
  import quotes.reflect.*
  r.asTerm.show
  throw new Throwable("OK")
}
def test = rule {
  foo(bar(baz))
}

def foo[I](r: I): Nothing = ???

def bar(i: Baz): i.Out = ???

sealed trait Baz:
  type Out = Nothing match { case Nothing => Nothing }

def baz: Baz = ???