Skip to content

Commit

Permalink
Improve missing argument list error (#17126)
Browse files Browse the repository at this point in the history
Fixes #17123
  • Loading branch information
nicolasstucki authored Apr 3, 2023
2 parents b1470fa + 3420f1b commit f97f3ce
Show file tree
Hide file tree
Showing 13 changed files with 187 additions and 24 deletions.
6 changes: 6 additions & 0 deletions compiler/src/dotty/tools/dotc/core/Contexts.scala
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,12 @@ object Contexts {
def useColors: Boolean =
base.settings.color.value == "always"

def withColors: FreshContext =
fresh.setSetting(ctx.settings.color, "always")

def withoutColors: FreshContext =
fresh.setSetting(ctx.settings.color, "never")

/** Is the explicit nulls option set? */
def explicitNulls: Boolean = base.settings.YexplicitNulls.value

Expand Down
3 changes: 1 addition & 2 deletions compiler/src/dotty/tools/dotc/inlines/Inlines.scala
Original file line number Diff line number Diff line change
Expand Up @@ -381,8 +381,7 @@ object Inlines:

/** Expand call to scala.compiletime.codeOf */
def codeOf(arg: Tree, pos: SrcPos)(using Context): Tree =
val ctx1 = ctx.fresh.setSetting(ctx.settings.color, "never")
Literal(Constant(arg.show(using ctx1))).withSpan(pos.span)
Literal(Constant(arg.show(using ctx.withoutColors))).withSpan(pos.span)
end Intrinsics

/** Produces an inlined version of `call` via its `inlined` method.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ enum ErrorMessageID(val isActive: Boolean = true) extends java.lang.Enum[ErrorMe
case ValueDiscardingID // errorNumber 175
case UnusedNonUnitValueID // errorNumber 176
case ConstrProxyShadowsID // errorNumber 177
case MissingArgumentListID // errorNumber: 178

def errorNumber = ordinal - 1

Expand Down
10 changes: 10 additions & 0 deletions compiler/src/dotty/tools/dotc/reporting/messages.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1501,6 +1501,16 @@ class MissingArgument(pname: Name, methString: String)(using Context)
else s"missing argument for parameter $pname of $methString"
def explain(using Context) = ""

class MissingArgumentList(method: String, sym: Symbol)(using Context)
extends TypeMsg(MissingArgumentListID) {
def msg(using Context) =
val symDcl = if sym.exists then "\n\n " + hl(sym.showDcl(using ctx.withoutColors)) else ""
i"missing argument list for $method$symDcl"
def explain(using Context) = {
i"""Unapplied methods are only converted to functions when a function type is expected."""
}
}

class DoesNotConformToBound(tpe: Type, which: String, bound: Type)(using Context)
extends TypeMismatchMsg(
if which == "lower" then bound else tpe,
Expand Down
22 changes: 17 additions & 5 deletions compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,24 @@ object ErrorReporting {
errorType(WrongNumberOfTypeArgs(fntpe, expectedArgs, actual), pos)

def missingArgs(tree: Tree, mt: Type)(using Context): Unit =
def isCallableWithoutArgumentsLists(mt: Type): Boolean = mt match
case pt: PolyType => isCallableWithoutArgumentsLists(pt.resType)
case mt: MethodType if mt.isImplicitMethod => isCallableWithoutArgumentsLists(mt.resType)
case mt: MethodType => false
case _ => true
def isCallableWithSingleEmptyArgumentList(mt: Type): Boolean =
mt match
case mt: MethodType if mt.paramNames.isEmpty => isCallableWithoutArgumentsLists(mt.resType)
case mt: MethodType if mt.isImplicitMethod => isCallableWithSingleEmptyArgumentList(mt.resType)
case pt: PolyType => isCallableWithSingleEmptyArgumentList(pt.resType)
case _ => false
val meth = err.exprStr(methPart(tree))
mt match
case mt: MethodType if mt.paramNames.isEmpty =>
report.error(MissingEmptyArgumentList(meth), tree.srcPos)
case _ =>
report.error(em"missing arguments for $meth", tree.srcPos)
val info = if tree.symbol.exists then tree.symbol.info else mt
if isCallableWithSingleEmptyArgumentList(info) then
report.error(MissingEmptyArgumentList(meth), tree.srcPos)
else
report.error(MissingArgumentList(meth, tree.symbol), tree.srcPos)


def matchReductionAddendum(tps: Type*)(using Context): String =
val collectMatchTrace = new TypeAccumulator[String]:
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3080,7 +3080,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler

lazy val ConstantCode: Printer[Constant] = new Printer[Constant]:
def show(const: Constant): String =
const.show(using ctx.fresh.setSetting(ctx.settings.color, "never"))
const.show(using ctx.withoutColors)

lazy val ConstantStructure: Printer[Constant] = new Printer[Constant]:
def show(const: Constant): String =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ class SyntaxHighlightingTests extends DottyTest {
import SyntaxHighlighting._

private def test(source: String, expected: String): Unit = {
val testCtx = ctx.fresh.setSetting(ctx.settings.color, "always")
val highlighted = SyntaxHighlighting.highlight(source)(using testCtx)
val highlighted = SyntaxHighlighting.highlight(source)(using ctx.withColors)
.replace(NoColor, ">")
.replace(CommentColor, "<C|")
.replace(KeywordColor, "<K|")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ trait ErrorMessagesTest extends DottyTest {
protected def newContext = {
val rep = new StoreReporter(null)
with UniqueMessagePositions with HideNonSensicalMessages
initialCtx.setReporter(rep).setSetting(ctx.settings.color, "never")
initialCtx.setReporter(rep).withoutColors
}

class Report(messages: List[Message], ictx: Context) {
Expand Down
24 changes: 18 additions & 6 deletions tests/neg/i16820.check
Original file line number Diff line number Diff line change
@@ -1,18 +1,30 @@
-- Error: tests/neg/i16820.scala:5:11 ----------------------------------------------------------------------------------
-- [E178] Type Error: tests/neg/i16820.scala:5:11 ----------------------------------------------------------------------
5 | val x1 = f // error
| ^
| missing arguments for method f in object Test
| missing argument list for method f in object Test
|
| def f(xs: Int*): Int
|
| longer explanation available when compiling with `-explain`
-- [E100] Syntax Error: tests/neg/i16820.scala:6:11 --------------------------------------------------------------------
6 | val x2 = g // error
| ^
| method g in object Test must be called with () argument
|
| longer explanation available when compiling with `-explain`
-- Error: tests/neg/i16820.scala:7:40 ----------------------------------------------------------------------------------
-- [E178] Type Error: tests/neg/i16820.scala:7:40 ----------------------------------------------------------------------
7 | val x3 = java.nio.file.Paths.get(".").toRealPath // error
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| missing arguments for method toRealPath in trait Path
-- Error: tests/neg/i16820.scala:11:14 ---------------------------------------------------------------------------------
| missing argument list for method toRealPath in trait Path
|
| def toRealPath(x$0: java.nio.file.LinkOption*): java.nio.file.Path
|
| longer explanation available when compiling with `-explain`
-- [E178] Type Error: tests/neg/i16820.scala:11:14 ---------------------------------------------------------------------
11 |def test = Foo(3) // error
| ^^^^^^
| missing arguments for method apply in object Foo
| missing argument list for method apply in object Foo
|
| def apply(x: Int)(xs: String*): Foo
|
| longer explanation available when compiling with `-explain`
86 changes: 86 additions & 0 deletions tests/neg/i17123.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
-- [E100] Syntax Error: tests/neg/i17123.scala:7:2 ---------------------------------------------------------------------
7 | m1 // error
| ^^
| method m1 in object ConfusingErrorMessage must be called with () argument
|
| longer explanation available when compiling with `-explain`
-- [E178] Type Error: tests/neg/i17123.scala:9:2 -----------------------------------------------------------------------
9 | m2 // error
| ^^
| missing argument list for method m2 in object ConfusingErrorMessage
|
| def m2()(): Unit
|
| longer explanation available when compiling with `-explain`
-- [E178] Type Error: tests/neg/i17123.scala:10:4 ----------------------------------------------------------------------
10 | m2() // error
| ^^^^
| missing argument list for method m2 in object ConfusingErrorMessage
|
| def m2()(): Unit
|
| longer explanation available when compiling with `-explain`
-- [E178] Type Error: tests/neg/i17123.scala:11:2 ----------------------------------------------------------------------
11 | m3 // error
| ^^
| missing argument list for method m3 in object ConfusingErrorMessage
|
| def m3()()(): Unit
|
| longer explanation available when compiling with `-explain`
-- [E178] Type Error: tests/neg/i17123.scala:12:4 ----------------------------------------------------------------------
12 | m3() // error
| ^^^^
| missing argument list for method m3 in object ConfusingErrorMessage
|
| def m3()()(): Unit
|
| longer explanation available when compiling with `-explain`
-- [E178] Type Error: tests/neg/i17123.scala:13:6 ----------------------------------------------------------------------
13 | m3()() // error
| ^^^^^^
| missing argument list for method m3 in object ConfusingErrorMessage
|
| def m3()()(): Unit
|
| longer explanation available when compiling with `-explain`
-- [E178] Type Error: tests/neg/i17123.scala:15:2 ----------------------------------------------------------------------
15 | f3 // error
| ^^
| missing argument list for method f3 in object ConfusingErrorMessage
|
| def f3()(i: Int)(): Unit
|
| longer explanation available when compiling with `-explain`
-- [E178] Type Error: tests/neg/i17123.scala:16:2 ----------------------------------------------------------------------
16 | f3() // error
| ^^^^
| missing argument list for method f3 in object ConfusingErrorMessage
|
| def f3()(i: Int)(): Unit
|
| longer explanation available when compiling with `-explain`
-- [E178] Type Error: tests/neg/i17123.scala:17:6 ----------------------------------------------------------------------
17 | f3()(2) // error
| ^^^^^^^
| missing argument list for method f3 in object ConfusingErrorMessage
|
| def f3()(i: Int)(): Unit
|
| longer explanation available when compiling with `-explain`
-- [E178] Type Error: tests/neg/i17123.scala:19:2 ----------------------------------------------------------------------
19 | i3 // error
| ^^
| missing argument list for method i3 in object ConfusingErrorMessage
|
| def i3()(using d: DummyImplicit)(): Unit
|
| longer explanation available when compiling with `-explain`
-- [E178] Type Error: tests/neg/i17123.scala:20:2 ----------------------------------------------------------------------
20 | i3() // error
| ^^^^
| missing argument list for method i3 in object ConfusingErrorMessage
|
| def i3()(using d: DummyImplicit)(): Unit
|
| longer explanation available when compiling with `-explain`
22 changes: 22 additions & 0 deletions tests/neg/i17123.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
object ConfusingErrorMessage {
def m1() = ()
def m2()() = ()
def m3()()() = ()
def f3()(i: Int)() = ()
def i3()(using d: DummyImplicit)() = ()
m1 // error
m1()
m2 // error
m2() // error
m3 // error
m3() // error
m3()() // error
m3()()()
f3 // error
f3() // error
f3()(2) // error
f3()(2)()
i3 // error
i3() // error
i3()()
}
2 changes: 1 addition & 1 deletion tests/neg/i7816.scala
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
object A {
def f()(>) = ??? // error
import f.NonExistent // error
import f.NonExistent
}
28 changes: 22 additions & 6 deletions tests/neg/indent-colons.check
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,31 @@
| Not found: file
|
| longer explanation available when compiling with `-explain`
-- Error: tests/neg/indent-colons.scala:5:2 ----------------------------------------------------------------------------
-- [E178] Type Error: tests/neg/indent-colons.scala:5:2 ----------------------------------------------------------------
5 | tryEither: // error
| ^^^^^^^^^
| missing arguments for method tryEither
-- Error: tests/neg/indent-colons.scala:11:2 ---------------------------------------------------------------------------
| missing argument list for method tryEither
|
| def tryEither[T](x: T)(y: Int => T): T
|
| where: T is a type variable
|
| longer explanation available when compiling with `-explain`
-- [E178] Type Error: tests/neg/indent-colons.scala:11:2 ---------------------------------------------------------------
11 | tryEither: // error
| ^^^^^^^^^
| missing arguments for method tryEither
-- Error: tests/neg/indent-colons.scala:18:2 ---------------------------------------------------------------------------
| missing argument list for method tryEither
|
| def tryEither[T](x: T)(y: Int => T): T
|
| where: T is a type variable
|
| longer explanation available when compiling with `-explain`
-- [E178] Type Error: tests/neg/indent-colons.scala:18:2 ---------------------------------------------------------------
18 | Some(3).fold: // error
| ^^^^^^^^^^^^
| missing arguments for method fold in class Option
| missing argument list for method fold in class Option
|
| final def fold[B](ifEmpty: => B)(f: A => B): B
|
| longer explanation available when compiling with `-explain`

0 comments on commit f97f3ce

Please sign in to comment.