scala / bug

Scala 2 bug reports only. Please, no questions — proper bug reports only.
https://scala-lang.org
232 stars 21 forks source link

Improve message for missing parameter type if no method takes a function #11517

Open som-snytt opened 5 years ago

som-snytt commented 5 years ago

As requested by tpolecat:

scala 2.13.0-RC1> "abc".indexOf(_ + 1)
                                ^
                  error: missing parameter type for expanded function ((<x$1: error>) => x$1.$plus(1))

scala 2.13.0-RC1> "abc".indexOf((x: Int) => x + 1)
java.lang.StackOverflowError
  at scala.collection.immutable.WrappedString.indexOf(WrappedString.scala:75)
  at scala.collection.SeqOps.indexOf(Seq.scala:381)
  at scala.collection.SeqOps.indexOf$(Seq.scala:381)
  at scala.collection.immutable.WrappedString.indexOf(WrappedString.scala:75)
  at scala.collection.SeqOps.indexOf(Seq.scala:381)
  at scala.collection.SeqOps.indexOf$(Seq.scala:381)

Oops, that's not what I meant to demonstrate. It looks like a runtime issue with WrappedString, not a compiler bug. I think tpolecat actually used substring. This is the dance he'd like avoid, which is especially confusing for beginners but annoying to all:

scala 2.13.0-RC1> "abc".substring(_ + 1)
                                  ^
                  error: missing parameter type for expanded function ((<x$1: error>) => x$1.$plus(1))

scala 2.13.0-RC1> "abc".substring((x: Int) => x + 1)
                                           ^
                  error: type mismatch;
                   found   : Int => Int
                   required: Int

Maybe for indexOf, I meant indexWhere.

scala 2.13.0-RC1> "abc".index(_ == 'b')
                        ^
                  error: value index is not a member of String
                  did you mean indexOf?

scala 2.13.0-RC1> "abc".indexOf(_ == 'b')
                                ^
                  error: missing parameter type for expanded function ((<x$1: error>) => x$1.$eq$eq('b'))

It would be amazing if both messages recommended indexWhere, as a method that has a similar name and takes a function.

I do read the amazing scaladocs, but this would also be amazing.

Worth adding that -Xlint adds:

scala 2.13.0-RC1> def f = "abc".indexOf((x: Char) => x == 'b')
                                ^
                  warning: a type was inferred to be `Any`; this may indicate a programming error.
f: Int

With improved inference in the face of overloads, maybe messaging can be improved despite overloads.

tpolecat commented 5 years ago

To be clear, what I to avoid is the situation where Scala says "missing parameter type" for a function in a position where no function type can possibly work, because when this happens you have to make the function typecheck first, before the compiler will tell you what the expected type was. I realize it's a special case but it's a common special case. "I expected a woozle but I found a function literal of some type that I don't know right now, but it doesn't matter because you can't put a function there."

adriaanm commented 5 years ago

With a patch along the following lines, you will get the more friendly error about the unexpected function while expecting a woozle, as well as the missing parameter times:

--- i/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ w/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -3057,7 +3057,8 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
                 issuedMissingParameterTypeError = true
               }

-              setError(fun)
+              // Improve error reporting: propagate what we know about the function's type -- we'll fail
+              fun setType appliedType(FunctionClass(vparams.length), vparams.map(param => if (param.tpt.isEmpty) WildcardType else silent(_.typedType(param.tpt).tpe).fold(WildcardType: Type){ case ErrorType => WildcardType case tp => tp }) :+ WildcardType)
             }
           } else {
             fun.body match {

It's trickier to not complain about the missing parameter types -- it's not clear to me how you know which of those errors is the most important (note that implicit conversions or other adaptations could apply after we type check the function literal against an expected type it at first doesn't meet, or perhaps never will -- the difference is not known at this point)

som-snytt commented 5 years ago

Thanks, Adriaan. This must be a busy time.

I might have expected that erroring out of doTypedApply one could notice that an erroneous arg has the wrong shape. But actually, looking at your check files, just seeing the mismatch between something with an arrow and something without is pretty good.

som-snytt commented 3 years ago

Same in Scala 3,

Starting scala3 REPL...
scala> "abc".indexOf(_ + 1)
1 |"abc".indexOf(_ + 1)
  |              ^
  |              Missing parameter type
  |
  |              I could not infer the type of the parameter _$1.

See linked ticket in 2023.

som-snytt commented 1 year ago

Also https://github.com/scala/bug/issues/4830

som-snytt commented 1 day ago

We know that Odersky is sympathetic to the needs of the learner and beginning user.

Also Odersky:

For me, Missing parameter type is perfectly fine as an error.