Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions compiler/src/dotty/tools/dotc/config/ScalaSettings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ private sealed trait WarningSettings:
private val WunstableInlineAccessors = BooleanSetting(WarningSetting, "WunstableInlineAccessors", "Warn an inline methods has references to non-stable binary APIs.")
private val WtoStringInterpolated = BooleanSetting(WarningSetting, "Wtostring-interpolated", "Warn a standard interpolator used toString on a reference type.")
private val WrecurseWithDefault = BooleanSetting(WarningSetting, "Wrecurse-with-default", "Warn when a method calls itself with a default argument.")
private val WdubiousContextual = BooleanSetting(WarningSetting, "Wwrong-arrow", "Warn if function arrow was used instead of context literal ?=>.")
private val Wunused: Setting[List[ChoiceWithHelp[String]]] = MultiChoiceHelpSetting(
WarningSetting,
name = "Wunused",
Expand Down Expand Up @@ -311,6 +312,7 @@ private sealed trait WarningSettings:
def unstableInlineAccessors(using Context): Boolean = allOr(WunstableInlineAccessors)
def toStringInterpolated(using Context): Boolean = allOr(WtoStringInterpolated)
def recurseWithDefault(using Context): Boolean = allOr(WrecurseWithDefault)
def dubiousContextual(using Context): Boolean = allOr(WdubiousContextual)
def checkInit(using Context): Boolean = allOr(WcheckInit)

/** -X "Extended" or "Advanced" settings */
Expand Down
10 changes: 10 additions & 0 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3824,6 +3824,16 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
val ifun = desugar.makeContextualFunction(paramTypes, paramNamesOrNil, tree, erasedParams)
typr.println(i"make contextual function $tree / $pt ---> $ifun")
typedFunctionValue(ifun, pt)
.tap:
case tree @ Block((m1: DefDef) :: _, _: Closure) if ctx.settings.Whas.dubiousContextual =>
m1.rhs match
case Block((m2: DefDef) :: _, _: Closure) if m1.paramss.lengthCompare(m2.paramss) == 0 =>
val p1s = m1.symbol.info.asInstanceOf[MethodType].paramInfos
val p2s = m2.symbol.info.asInstanceOf[MethodType].paramInfos
if p1s.corresponds(p2s)(_ =:= _) then
report.warning(em"Context function adapts a lambda with the same parameter types, possibly ?=> was intended.", tree.srcPos)
case _ =>
case _ =>
}

/** Typecheck and adapt tree, returning a typed tree. Parameters as for `typedUnadapted` */
Expand Down
22 changes: 22 additions & 0 deletions tests/warn/i21187.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//> using options -Wall

def oops(msg: String) = sys.error(msg)

class Zone
object Zone:
inline def apply[T](inline f: Zone ?=> T): T = f(using new Zone)

inline def zone[A](inline f: Zone ?=> A) = Zone.apply(z => f(using z)) // warn suspicious contextualizing
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this be reported with:

def zone[A](f: Zone ?=> A) = Zone.apply(z => f(using z))

as well? Maybe the warning should only be for the inline cases, where it might cause most issues.

What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's the same issue, which is that the function literal is wrapped in a context function. I added it to the test to document the behavior is the same.


def zone_?[A](f: Zone ?=> A) = Zone.apply(z => f(using z)) // warn

// intended
//inline def zone[A](inline f: Zone ?=> A): A = Zone.apply(z ?=> f(using z))

@main def hello =
// this swallows exceptions!
zone(oops("here")) // warn function value is not used
zone_?(oops("here")) // warn

// this doesn't
Zone(oops("not here"))
Loading