Skip to content

Commit

Permalink
Fix widen types before checking an implicit view exists (#18719)
Browse files Browse the repository at this point in the history
Fixes #18650
  • Loading branch information
odersky committed Oct 19, 2023
2 parents 5f5b517 + 8a2773f commit bf994f9
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 39 deletions.
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/config/ScalaSettings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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.")
Expand Down
49 changes: 11 additions & 38 deletions compiler/src/dotty/tools/dotc/report.scala
Original file line number Diff line number Diff line change
Expand Up @@ -132,50 +132,26 @@ 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,
"during phase" -> ctx.phase.megaPhase,
"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:<unknown>"),
"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 => "<Cannot read source file>"
s"""
| $errorMessage
|
Expand All @@ -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
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/Implicits.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions tests/neg/i18650.min.scala
Original file line number Diff line number Diff line change
@@ -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)
8 changes: 8 additions & 0 deletions tests/neg/i18650.min2.scala
Original file line number Diff line number Diff line change
@@ -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)
26 changes: 26 additions & 0 deletions tests/neg/i18650.scala
Original file line number Diff line number Diff line change
@@ -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)

0 comments on commit bf994f9

Please sign in to comment.