Skip to content

Improve parameter type inference error messaging #18190

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 18, 2023
Merged
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
20 changes: 12 additions & 8 deletions compiler/src/dotty/tools/dotc/reporting/messages.scala
Original file line number Diff line number Diff line change
Expand Up @@ -160,23 +160,27 @@ extends SyntaxMsg(CaseClassMissingParamListID) {

class AnonymousFunctionMissingParamType(param: untpd.ValDef,
tree: untpd.Function,
pt: Type)
inferredType: Type,
expectedType: Type,
)
(using Context)
extends TypeMsg(AnonymousFunctionMissingParamTypeID) {
def msg(using Context) = {
val ofFun =
if param.name.is(WildcardParamName)
|| (MethodType.syntheticParamNames(tree.args.length + 1) contains param.name)
then i" of expanded function:\n$tree"
then i"\n\nIn expanded function:\n$tree"
else ""

val inferred =
if (pt == WildcardType) ""
else i"\nWhat I could infer was: $pt"
if (inferredType == WildcardType) ""
else i"\n\nPartially inferred type for the parameter: $inferredType"

i"""Missing parameter type
|
|I could not infer the type of the parameter ${param.name}$ofFun.$inferred"""
val expected =
if (expectedType == WildcardType) ""
else i"\n\nExpected type for the whole anonymous function: $expectedType"

i"Could not infer type for parameter ${param.name} of anonymous function$ofFun$inferred$expected"
}

def explain(using Context) = ""
Expand Down Expand Up @@ -2985,4 +2989,4 @@ class ImplausiblePatternWarning(pat: tpd.Tree, selType: Type)(using Context)
i"""|Implausible pattern:
|$pat could match selector of type $selType
|only if there is an `equals` method identifying elements of the two types."""
def explain(using Context) = ""
def explain(using Context) = ""
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1620,7 +1620,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
else
inferredFromTarget(param, formal, calleeType, isErased, paramIndex).orElse(
if knownFormal then formal0
else errorType(AnonymousFunctionMissingParamType(param, tree, formal), param.srcPos)
else errorType(AnonymousFunctionMissingParamType(param, tree, inferredType = formal, expectedType = pt), param.srcPos)
)
val paramTpt = untpd.TypedSplice(
(if knownFormal then InferredTypeTree() else untpd.TypeTree())
Expand Down Expand Up @@ -3957,7 +3957,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
sym.isConstructor
|| sym.matchNullaryLoosely
|| Feature.warnOnMigration(msg, tree.srcPos, version = `3.0`)
&& {
&& {
msg.actions
.headOption
.foreach(Rewrites.applyAction)
Expand Down
14 changes: 8 additions & 6 deletions tests/neg/i11350.check
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
-- [E081] Type Error: tests/neg/i11350.scala:1:39 ----------------------------------------------------------------------
1 |class A1[T](action: A1[T] ?=> String = "") // error
| ^
| Missing parameter type
| Could not infer type for parameter evidence$1 of anonymous function
|
| I could not infer the type of the parameter evidence$1.
| What I could infer was: A1[<?>]
| Partially inferred type for the parameter: A1[<?>]
|
| Expected type for the whole anonymous function: (A1[<?>]) ?=> String
-- [E081] Type Error: tests/neg/i11350.scala:2:39 ----------------------------------------------------------------------
2 |class A2[T](action: A1[T] ?=> String = summon[A1[T]]) // error
| ^
| Missing parameter type
| Could not infer type for parameter evidence$2 of anonymous function
|
| Partially inferred type for the parameter: A1[<?>]
|
| I could not infer the type of the parameter evidence$2.
| What I could infer was: A1[<?>]
| Expected type for the whole anonymous function: (A1[<?>]) ?=> String
8 changes: 5 additions & 3 deletions tests/neg/i11561.check
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
-- [E081] Type Error: tests/neg/i11561.scala:2:32 ----------------------------------------------------------------------
2 | val updateText1 = copy(text = _) // error
| ^
| Missing parameter type
| Could not infer type for parameter _$1 of anonymous function
|
| I could not infer the type of the parameter _$1 of expanded function:
| _$1 => State.this.text = _$1.
| In expanded function:
| _$1 => State.this.text = _$1
|
| Expected type for the whole anonymous function: String
-- [E052] Type Error: tests/neg/i11561.scala:3:30 ----------------------------------------------------------------------
3 | val updateText2 = copy(text = (_: String)) // error
| ^^^^^^^^^^^^^^^^^^
Expand Down
16 changes: 10 additions & 6 deletions tests/neg/i17183.check
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
-- [E081] Type Error: tests/neg/i17183.scala:11:24 ---------------------------------------------------------------------
11 |def test = Context(f = (_, _) => ???) // error // error
| ^
| Missing parameter type
| Could not infer type for parameter _$1 of anonymous function
Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder if it would be possible to report

 Could not infer type for the 1st parameter of an anonymous function

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 would be possible, but I'm not sure it's desirable, I think here we need to show some internals

Copy link
Contributor

Choose a reason for hiding this comment

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

The internal names of _ and other unamed variables are only useful to us. Never to the user as they cannot use them in the source.

Copy link
Contributor Author

@Sporarum Sporarum Jul 13, 2023

Choose a reason for hiding this comment

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

I agree, but we need to show the desugarring anyways, as the issue might be that the user missunderstood how _ works
And therefore need names in the desugarring (but these could be something else than _$1)

|
| I could not infer the type of the parameter _$1 of expanded function:
| (_$1, _$2) => ???.
| In expanded function:
| (_$1, _$2) => ???
|
| Expected type for the whole anonymous function: MyFunc
-- [E081] Type Error: tests/neg/i17183.scala:11:27 ---------------------------------------------------------------------
11 |def test = Context(f = (_, _) => ???) // error // error
| ^
| Missing parameter type
| Could not infer type for parameter _$2 of anonymous function
|
| In expanded function:
| (_$1, _$2) => ???
|
| I could not infer the type of the parameter _$2 of expanded function:
| (_$1, _$2) => ???.
| Expected type for the whole anonymous function: MyFunc