Skip to content

Commit 779fbc7

Browse files
committed
Addendum when apply error involves default arg
This is useful because the default arg is not visible as the reason the application did not typecheck. It uses the existing mechanism to update messages.
1 parent b21d883 commit 779fbc7

File tree

7 files changed

+66
-28
lines changed

7 files changed

+66
-28
lines changed

compiler/src/dotty/tools/dotc/reporting/ExploringReporter.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ package reporting
44

55
import scala.language.unsafeNulls
66

7-
import collection.mutable
7+
import collection.mutable.ListBuffer
88
import core.Contexts.Context
99
import Diagnostic.*
1010

1111
/** A re-usable Reporter used in Contexts#test */
1212
class ExploringReporter extends StoreReporter(null, fromTyperState = false):
13-
infos = new mutable.ListBuffer[Diagnostic]
13+
infos = ListBuffer.empty[Diagnostic]
1414

1515
override def hasUnreportedErrors: Boolean =
1616
infos.exists(_.isInstanceOf[Error])

compiler/src/dotty/tools/dotc/reporting/Message.scala

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -394,14 +394,16 @@ abstract class Message(val errorId: ErrorMessageID)(using Context) { self =>
394394

395395
def mapMsg(f: String => String): Message = new Message(errorId):
396396
val kind = self.kind
397-
def msg(using Context) = f(self.msg)
398-
def explain(using Context) = self.explain
397+
protected def msg(using Context) = f(self.msg)
398+
override protected def msgPostscript(using Context) = self.msgPostscript
399+
protected def explain(using Context) = self.explain
399400
override def canExplain = self.canExplain
400401

401402
def appendExplanation(suffix: => String): Message = new Message(errorId):
402403
val kind = self.kind
403-
def msg(using Context) = self.msg
404-
def explain(using Context) = self.explain ++ suffix
404+
protected def msg(using Context) = self.msg
405+
override protected def msgPostscript(using Context) = self.msgPostscript
406+
protected def explain(using Context) = self.explain ++ suffix
405407
override def canExplain = true
406408

407409
/** Override with `true` for messages that should always be shown even if their

compiler/src/dotty/tools/dotc/reporting/StoreReporter.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package dotc
33
package reporting
44

55
import core.Contexts.*
6-
import collection.mutable
6+
import collection.mutable.ListBuffer
77
import config.Printers.typr
88
import Diagnostic.*
99

@@ -19,11 +19,11 @@ import Diagnostic.*
1919
*/
2020
class StoreReporter(outer: Reporter | Null = Reporter.NoReporter, fromTyperState: Boolean = false) extends Reporter {
2121

22-
protected var infos: mutable.ListBuffer[Diagnostic] | Null = null
22+
protected var infos: ListBuffer[Diagnostic] | Null = null
2323

2424
override def doReport(dia: Diagnostic)(using Context): Unit = {
2525
typr.println(s">>>> StoredError: ${dia.message}") // !!! DEBUG
26-
if (infos == null) infos = new mutable.ListBuffer
26+
if (infos == null) infos = ListBuffer.empty
2727
infos.uncheckedNN += dia
2828
}
2929

compiler/src/dotty/tools/dotc/typer/Applications.scala

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,18 @@ import reporting.*
2525
import Nullables.*, NullOpsDecorator.*
2626
import config.{Feature, SourceVersion}
2727

28-
import collection.mutable
28+
import collection.mutable.ListBuffer
2929
import config.Printers.{overload, typr, unapp}
30+
import inlines.Inlines
31+
import interfaces.Diagnostic.ERROR
3032
import TypeApplications.*
3133
import Annotations.Annotation
3234

3335
import Constants.{Constant, IntTag}
3436
import Denotations.SingleDenotation
3537
import annotation.threadUnsafe
3638

37-
import scala.util.control.NonFatal
38-
import dotty.tools.dotc.inlines.Inlines
39+
import scala.util.chaining.given
3940

4041
object Applications {
4142
import tpd.*
@@ -260,7 +261,7 @@ object Applications {
260261

261262
end UnapplyArgs
262263

263-
def wrapDefs(defs: mutable.ListBuffer[Tree] | Null, tree: Tree)(using Context): Tree =
264+
def wrapDefs(defs: ListBuffer[Tree] | Null, tree: Tree)(using Context): Tree =
264265
if (defs != null && defs.nonEmpty) tpd.Block(defs.toList, tree) else tree
265266

266267
/** Optionally, if `sym` is a symbol created by `resolveMapped`, i.e. representing
@@ -872,8 +873,8 @@ trait Applications extends Compatibility {
872873
extends Application(methRef, fun.tpe, args, resultType) {
873874
type TypedArg = Tree
874875
def isVarArg(arg: Trees.Tree[T]): Boolean = untpd.isWildcardStarArg(arg)
875-
private var typedArgBuf = new mutable.ListBuffer[Tree]
876-
private var liftedDefs: mutable.ListBuffer[Tree] | Null = null
876+
private var typedArgBuf = ListBuffer.empty[Tree]
877+
private var liftedDefs: ListBuffer[Tree] | Null = null
877878
private var myNormalizedFun: Tree = fun
878879
init()
879880

@@ -911,11 +912,11 @@ trait Applications extends Compatibility {
911912

912913
override def liftFun(): Unit =
913914
if (liftedDefs == null) {
914-
liftedDefs = new mutable.ListBuffer[Tree]
915+
liftedDefs = ListBuffer.empty[Tree]
915916
myNormalizedFun = lifter.liftApp(liftedDefs.uncheckedNN, myNormalizedFun)
916917
}
917918

918-
/** The index of the first difference between lists of trees `xs` and `ys`
919+
/** The index of the first difference between lists of trees `xs` and `ys`.
919920
* -1 if there are no differences.
920921
*/
921922
private def firstDiff[T <: Trees.Tree[?]](xs: List[T], ys: List[T], n: Int = 0): Int = xs match {
@@ -939,11 +940,25 @@ trait Applications extends Compatibility {
939940
isPureExpr(arg)
940941
|| arg.isInstanceOf[RefTree | Apply | TypeApply] && arg.symbol.name.is(DefaultGetterName)
941942

942-
val result: Tree = {
943+
def defaultsAddendum(args: List[Tree]): Unit =
944+
def check(arg: Tree): Boolean = arg match
945+
case TypeApply(Select(_, name), _) => name.is(DefaultGetterName)
946+
case Apply(Select(_, name), _) => name.is(DefaultGetterName)
947+
case _ => false
948+
val faulties = args.filter(check)
949+
ctx.reporter.mapBufferedMessages:
950+
case Diagnostic(msg: TypeMismatch, pos, ERROR)
951+
if msg.inTree.exists(t => faulties.exists(_.span == t.span)) =>
952+
val noteText = i"Error occurred in an application involving default arguments."
953+
val explained = i"Expanded application: ${cpy.Apply(app)(normalizedFun, args)}"
954+
Diagnostic.Error(msg.append(s"\n$noteText").appendExplanation(s"\n\n$explained"), pos)
955+
case dia => dia
956+
957+
val result: Tree = {
943958
var typedArgs = typedArgBuf.toList
944959
def app0 = cpy.Apply(app)(normalizedFun, typedArgs) // needs to be a `def` because typedArgs can change later
945960
val app1 =
946-
if (!success || typedArgs.exists(_.tpe.isError)) app0.withType(UnspecifiedErrorType)
961+
if !success || typedArgs.exists(_.tpe.isError).tap(if (_) then defaultsAddendum(typedArgs)) then app0.withType(UnspecifiedErrorType)
947962
else {
948963
if isJavaAnnotConstr(methRef.symbol) then
949964
// #19951 Make sure all arguments are NamedArgs for Java annotations
@@ -960,7 +975,7 @@ trait Applications extends Compatibility {
960975
liftFun()
961976

962977
// lift arguments in the definition order
963-
val argDefBuf = mutable.ListBuffer.empty[Tree]
978+
val argDefBuf = ListBuffer.empty[Tree]
964979
typedArgs = lifter.liftArgs(argDefBuf, methType, typedArgs)
965980
// Lifted arguments ordered based on the original order of typedArgBuf and
966981
// with all non-explicit default parameters at the end in declaration order.
@@ -1105,7 +1120,6 @@ trait Applications extends Compatibility {
11051120
if fun1.symbol.name == nme.apply && fun1.span.isSynthetic then
11061121
fun1 match
11071122
case Select(qualifier, _) =>
1108-
import dotty.tools.dotc.interfaces.Diagnostic.ERROR
11091123
failedState.reporter.mapBufferedMessages:
11101124
case Diagnostic(msg: TypeMismatch, pos, ERROR)
11111125
if msg.inTree.exists(t => tree.args.exists(_.span == t.span)) =>
@@ -1204,7 +1218,7 @@ trait Applications extends Compatibility {
12041218
val (lhs1, name, rhss) = (tree: @unchecked) match
12051219
case Apply(Select(lhs, name), rhss) => (typedExpr(lhs), name, rhss)
12061220
case Apply(untpd.TypedSplice(Select(lhs1, name)), rhss) => (lhs1, name, rhss)
1207-
val liftedDefs = new mutable.ListBuffer[Tree]
1221+
val liftedDefs = ListBuffer.empty[Tree]
12081222
val lhs2 = untpd.TypedSplice(LiftComplex.liftAssigned(liftedDefs, lhs1))
12091223
val assign = untpd.Assign(lhs2,
12101224
untpd.Apply(untpd.Select(lhs2, name.asSimpleName.dropRight(1)), rhss))

tests/neg/t4727.check

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
-- [E007] Type Mismatch Error: tests/neg/t4727.scala:7:8 ---------------------------------------------------------------
2+
7 | new C[Int] // error
3+
| ^^^^^^
4+
| Found: Null
5+
| Required: Int
6+
| Error occurred in an application involving default arguments.
7+
| Note that implicit conversions were not tried because the result of an implicit conversion
8+
| must be more specific than Int
9+
|---------------------------------------------------------------------------------------------------------------------
10+
| Explanation (enabled by `-explain`)
11+
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
12+
|
13+
| Tree: C.$lessinit$greater$default$1[Int]
14+
| I tried to show that
15+
| Null
16+
| conforms to
17+
| Int
18+
| but none of the attempts shown below succeeded:
19+
|
20+
| ==> Null <: Int = false
21+
|
22+
| The tests were made under the empty constraint
23+
|
24+
| Expanded application: new C[Int](C.$lessinit$greater$default$1[Int])
25+
---------------------------------------------------------------------------------------------------------------------
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
//> using options -explain
2+
13
class C[T](x : T = null)
24

35
object Test {
46
def main(args: Array[String]): Unit = {
5-
new C[Int]
7+
new C[Int] // error
68
}
79
}

tests/untried/neg/t4727.check

Lines changed: 0 additions & 5 deletions
This file was deleted.

0 commit comments

Comments
 (0)