From 63f1a3c5d0149d173eb8f65405b5983591752229 Mon Sep 17 00:00:00 2001 From: Shane Delmore Date: Mon, 24 Oct 2016 17:34:37 -0700 Subject: Improve error message for WrongNumberOfArgs --- .../tools/dotc/reporting/diagnostic/messages.scala | 35 ++++++++++++++++++++++ src/dotty/tools/dotc/typer/ErrorReporting.scala | 4 +-- src/dotty/tools/dotc/typer/TypeAssigner.scala | 6 ++-- src/dotty/tools/dotc/typer/Typer.scala | 2 +- 4 files changed, 41 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index f76512bc7..57d96224a 100644 --- a/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -10,6 +10,7 @@ import util.{SourceFile, NoSource} import util.{SourcePosition, NoSourcePosition} import config.Settings.Setting import interfaces.Diagnostic.{ERROR, WARNING, INFO} +import dotty.tools.dotc.ast.tpd import printing.Highlighting._ import printing.Formatting @@ -605,4 +606,38 @@ object messages { |${"func(bool => // do something...)"} |""".stripMargin } + case class WrongNumberOfArgs(fntpe: Type, argKind: String, expectedArgs: List[TypeParamInfo], actual: List[untpd.Tree])(implicit ctx: Context) + extends Message(18) { + val kind = "Syntax" + val expectedCount = expectedArgs.length + val actualCount = actual.length + val msgPrefix = if (actualCount > expectedCount) "Too many" else "Not enough" + + val expectedArgString = (fntpe.widen match { + case pt: MethodOrPoly => pt //ensure we return a type that will have useful typeParms + case _ => fntpe + }).typeParams.map(_.paramName.show.split("\\$").last).mkString("[", ", ", "]") + + val actualArgString = actual.map(_.show.split("\\.").last).mkString("[", ", ", "]") + + val msg = + hl"""|$msgPrefix ${argKind} arguments for $fntpe + |expected: $expectedArgString + |actual: $actualArgString""".stripMargin + + val explanation = { + if (actualCount > expectedCount) + hl"""|You have supplied too many type parameters + | + |For example List takes a single type parameter (List[A]) + | If you need to hold more types in a list then you need to combine them + | into another data type that can contain the number of types you need, + | In this example one solution would be to use a Tuple: + | val tuple2: Tuple2[Int, String = (1, "one) + | List[(Int, String)] = List(tuple2)""".stripMargin + else + hl"""|You have not supplied enough type parameters + | If you specify one type parameter then you need to specify every type parameter.""".stripMargin + } + } } diff --git a/src/dotty/tools/dotc/typer/ErrorReporting.scala b/src/dotty/tools/dotc/typer/ErrorReporting.scala index 1d22dc646..a18c83ff8 100644 --- a/src/dotty/tools/dotc/typer/ErrorReporting.scala +++ b/src/dotty/tools/dotc/typer/ErrorReporting.scala @@ -49,8 +49,8 @@ object ErrorReporting { errorMsg(ex.show, ctx) } - def wrongNumberOfArgs(fntpe: Type, kind: String, expected: Int, pos: Position)(implicit ctx: Context) = - errorType(em"wrong number of ${kind}arguments for $fntpe, expected: $expected", pos) + def wrongNumberOfArgs(fntpe: Type, kind: String, expectedArgs: List[TypeParamInfo], actual: List[untpd.Tree], pos: Position)(implicit ctx: Context) = + errorType(WrongNumberOfArgs(fntpe, kind, expectedArgs, actual)(ctx), pos) class Errors(implicit ctx: Context) { diff --git a/src/dotty/tools/dotc/typer/TypeAssigner.scala b/src/dotty/tools/dotc/typer/TypeAssigner.scala index 861847b11..b1fed308c 100644 --- a/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -314,7 +314,7 @@ trait TypeAssigner { val ownType = fn.tpe.widen match { case fntpe @ MethodType(_, ptypes) => if (sameLength(ptypes, args) || ctx.phase.prev.relaxedTyping) fntpe.instantiate(args.tpes) - else wrongNumberOfArgs(fn.tpe, "", ptypes.length, tree.pos) + else wrongNumberOfArgs(fn.tpe, "", fntpe.typeParams, args, tree.pos) case t => errorType(i"${err.exprStr(fn)} does not take parameters", tree.pos) } @@ -369,7 +369,7 @@ trait TypeAssigner { else { val argTypes = args.tpes if (sameLength(argTypes, paramNames) || ctx.phase.prev.relaxedTyping) pt.instantiate(argTypes) - else wrongNumberOfArgs(fn.tpe, "type ", pt.paramNames.length, tree.pos) + else wrongNumberOfArgs(fn.tpe, "type", pt.typeParams, args, tree.pos) } case _ => errorType(i"${err.exprStr(fn)} does not take type parameters", tree.pos) @@ -451,7 +451,7 @@ trait TypeAssigner { val ownType = if (hasNamedArg(args)) (tycon.tpe /: args)(refineNamed) else if (sameLength(tparams, args)) tycon.tpe.appliedTo(args.tpes) - else wrongNumberOfArgs(tycon.tpe, "type ", tparams.length, tree.pos) + else wrongNumberOfArgs(tycon.tpe, "type", tparams, args, tree.pos) tree.withType(ownType) } diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 6fb0dd7c7..56c04c063 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -1035,7 +1035,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit if (hasNamedArg(args)) typedNamedArgs(args) else { if (args.length != tparams.length) { - wrongNumberOfArgs(tpt1.tpe, "type ", tparams.length, tree.pos) + wrongNumberOfArgs(tpt1.tpe, "type", tparams, args, tree.pos) args = args.take(tparams.length) } def typedArg(arg: untpd.Tree, tparam: TypeParamInfo) = { -- cgit v1.2.3