diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala index b2ebf3aef51a..268bc6114a5c 100644 --- a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -421,6 +421,7 @@ private sealed trait YSettings: val YshowVarBounds: Setting[Boolean] = BooleanSetting("-Yshow-var-bounds", "Print type variables with their bounds.") val YnoDecodeStacktraces: Setting[Boolean] = BooleanSetting("-Yno-decode-stacktraces", "Show raw StackOverflow stacktraces, instead of decoding them into triggering operations.") + val YnoEnrichErrorMessages: Setting[Boolean] = BooleanSetting("-Yno-enrich-error-messages", "Show raw error messages, instead of enriching them with contextual information.") val Yinstrument: Setting[Boolean] = BooleanSetting("-Yinstrument", "Add instrumentation code that counts allocations and closure creations.") val YinstrumentDefs: Setting[Boolean] = BooleanSetting("-Yinstrument-defs", "Add instrumentation code that counts method calls; needs -Yinstrument to be set, too.") diff --git a/compiler/src/dotty/tools/dotc/report.scala b/compiler/src/dotty/tools/dotc/report.scala index 11ab38b3f5ae..75261fb6890e 100644 --- a/compiler/src/dotty/tools/dotc/report.scala +++ b/compiler/src/dotty/tools/dotc/report.scala @@ -132,23 +132,17 @@ object report: private object messageRendering extends MessageRendering // Should only be called from Run#enrichErrorMessage. - def enrichErrorMessage(errorMessage: String)(using Context): String = try { + def enrichErrorMessage(errorMessage: String)(using Context): String = + if ctx.settings.YnoEnrichErrorMessages.value then errorMessage + else try enrichErrorMessage1(errorMessage) + catch case _: Throwable => errorMessage // don't introduce new errors trying to report errors, so swallow exceptions + + private def enrichErrorMessage1(errorMessage: String)(using Context): String = { + import untpd.*, config.Settings.* def formatExplain(pairs: List[(String, Any)]) = pairs.map((k, v) => f"$k%20s: $v").mkString("\n") val settings = ctx.settings.userSetSettings(ctx.settingsState).sortBy(_.name) - val tree = ctx.tree - val sym = tree.symbol - val pos = tree.sourcePos - val path = pos.source.path - val site = ctx.outersIterator.map(_.owner).filter(sym => !sym.exists || sym.isClass || sym.is(Method)).next() - - import untpd.* - extension (tree: Tree) def summaryString: String = tree match - case Literal(const) => s"Literal($const)" - case Ident(name) => s"Ident(${name.decode})" - case Select(qual, name) => s"Select(${qual.summaryString}, ${name.decode})" - case tree: NameTree => (if tree.isType then "type " else "") + tree.name.decode - case tree => s"${tree.className}${if tree.symbol.exists then s"(${tree.symbol})" else ""}" + def showSetting(s: Setting[?]): String = if s.value == "" then s"${s.name} \"\"" else s"${s.name} ${s.value}" val info1 = formatExplain(List( "while compiling" -> ctx.compilationUnit, @@ -156,26 +150,8 @@ object report: "mode" -> ctx.mode, "library version" -> scala.util.Properties.versionString, "compiler version" -> dotty.tools.dotc.config.Properties.versionString, - "settings" -> settings.map(s => if s.value == "" then s"${s.name} \"\"" else s"${s.name} ${s.value}").mkString(" "), - )) - val symbolInfos = if sym eq NoSymbol then List("symbol" -> sym) else List( - "symbol" -> sym.showLocated, - "symbol definition" -> s"${sym.showDcl} (a ${sym.className})", - "symbol package" -> sym.enclosingPackageClass.fullName, - "symbol owners" -> sym.showExtendedLocation, - ) - val info2 = formatExplain(List( - "tree" -> tree.summaryString, - "tree position" -> (if pos.exists then s"$path:${pos.line + 1}:${pos.column}" else s"$path:"), - "tree type" -> tree.typeOpt.show, - ) ::: symbolInfos ::: List( - "call site" -> s"${site.showLocated} in ${site.enclosingPackageClass}" + "settings" -> settings.map(showSetting).mkString(" "), )) - val context_s = try - s""" == Source file context for tree position == - | - |${messageRendering.messageAndPos(Diagnostic.Error("", pos))}""".stripMargin - catch case _: Exception => "" s""" | $errorMessage | @@ -184,9 +160,6 @@ object report: | https://github.com/lampepfl/dotty/issues/new/choose | |$info1 - | - |$info2 - | - |$context_s""".stripMargin - } catch case _: Throwable => errorMessage // don't introduce new errors trying to report errors, so swallow exceptions + |""".stripMargin + } end report diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 04aca960845e..5cba406a302e 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -850,7 +850,7 @@ trait Implicits: && !to.isError && !ctx.isAfterTyper && ctx.mode.is(Mode.ImplicitsEnabled) - && from.isValueType + && from.widen.isValueType && ( from.isValueSubType(to) || inferView(dummyTreeOfType(from), to) (using ctx.fresh.addMode(Mode.ImplicitExploration).setExploreTyperState()).isSuccess diff --git a/tests/neg/i18650.min.scala b/tests/neg/i18650.min.scala new file mode 100644 index 000000000000..0756c05bfc25 --- /dev/null +++ b/tests/neg/i18650.min.scala @@ -0,0 +1,8 @@ +class Church[B]: + type Nat = Tuple1[B] + +class Test: + given makeChurch[C]: Church[C] = ??? // necessary to cause crash + + def churchTest(c: Church[Int]): Unit = + val res1 = summon[c.Nat =:= Int] // error (not a compiler crash) diff --git a/tests/neg/i18650.min2.scala b/tests/neg/i18650.min2.scala new file mode 100644 index 000000000000..43ea86492d54 --- /dev/null +++ b/tests/neg/i18650.min2.scala @@ -0,0 +1,8 @@ +class Church[B]: + type Nat = Tuple1[B] + +class Test2: + given makeChurch2[C](using DummyImplicit): Church[C] = ??? + + def churchTest2(c: Church[Int]): Unit = + val res2 = summon[c.Nat =:= Int] // error (not a compiler crash) diff --git a/tests/neg/i18650.scala b/tests/neg/i18650.scala new file mode 100644 index 000000000000..d627c6ea329b --- /dev/null +++ b/tests/neg/i18650.scala @@ -0,0 +1,26 @@ +trait Lam: + type F[_] + extension [A, B](f: F[A => B]) def apply(arg: F[A]): F[B] + def lam[A, B](f: F[A] => F[B]): F[A => B] + final def id[A]: F[A => A] = lam(identity[F[A]]) + +object LamInterpreter extends Lam: + type F[t] = t + def lam[A, B](f: F[A] => F[B]): F[A => B] = f + extension [A, B](f: F[A => B]) def apply(arg: F[A]): F[B] = f(arg) + + +class Church[A](using val l: Lam): + import l.* + type Nat = F[(A => A) => (A => A)] + def zero: Nat = id + extension (n: Nat) def suc: Nat = lam(f => lam(x => f(n(f)(x)))) + +given [A](using l: Lam): Church[A] = Church() + + +@main +def churchTest = + given Lam = LamInterpreter + val c: Church[Int] = summon + summon[c.Nat =:= ((Int => Int) => (Int => Int))] // error (not a compiler crash)