From b4e1a96e280398916440088e50934c6ae1b65fe0 Mon Sep 17 00:00:00 2001 From: odersky Date: Tue, 2 Dec 2025 17:39:55 +0100 Subject: [PATCH] Use a better span for an anonymous class An anonymous class is expanded roughly to { class $anon{ ... }; new $anon } Previously the `new` part had a zero extent span at the end of the class. When used with significant indentation, this caused some puzzlement in error messages since one thought the last class definition was to blame. The span is now the whole anonymous class. --- .../src/dotty/tools/dotc/typer/Typer.scala | 6 +- tests/neg-custom-args/captures/capt1.check | 13 +-- tests/neg-custom-args/captures/capt1.scala | 4 +- .../captures/method-uses.scala | 4 +- .../captures/mut-iterator4.check | 23 ++---- .../captures/mut-iterator4.scala | 6 +- tests/neg/6570-1.check | 16 ++-- tests/neg/6570.check | 80 +++++++++---------- tests/neg/i13703.check | 8 +- 9 files changed, 78 insertions(+), 82 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 4b54419bd7a2..31d5a465b271 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1251,7 +1251,11 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer typedAhead(parent, tree => inferTypeParams(typedType(tree), pt)) val anon = tpnme.ANON_CLASS val clsDef = TypeDef(anon, templ1).withFlags(Final | Synthetic) - typed(cpy.Block(tree)(clsDef :: Nil, New(Ident(anon), Nil)), pt) + typed( + cpy.Block(tree)( + clsDef :: Nil, + New(Ident(anon), Nil).withSpan(tree.span)), + pt) case _ => var tpt1 = typedType(tree.tpt) val tsym = tpt1.tpe.underlyingClassRef(refinementOK = false).typeSymbol diff --git a/tests/neg-custom-args/captures/capt1.check b/tests/neg-custom-args/captures/capt1.check index 906991c4019e..a684c1463902 100644 --- a/tests/neg-custom-args/captures/capt1.check +++ b/tests/neg-custom-args/captures/capt1.check @@ -34,13 +34,14 @@ | Note that capability x is not included in capture set {}. | | longer explanation available when compiling with `-explain` --- [E007] Type Mismatch Error: tests/neg-custom-args/captures/capt1.scala:28:40 ---------------------------------------- -28 | def m() = if x == null then y else y // error - | ^ - | Found: A^{x} - | Required: A +-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/capt1.scala:27:2 ----------------------------------------- +27 | new A: // error + | ^ + | Found: A^{x} + | Required: A | - | Note that capability x is not included in capture set {}. + | Note that capability x is not included in capture set {}. +28 | def m() = if x == null then y else y | | longer explanation available when compiling with `-explain` -- [E007] Type Mismatch Error: tests/neg-custom-args/captures/capt1.scala:36:24 ---------------------------------------- diff --git a/tests/neg-custom-args/captures/capt1.scala b/tests/neg-custom-args/captures/capt1.scala index 01eda5e049f8..0d44d3171aa8 100644 --- a/tests/neg-custom-args/captures/capt1.scala +++ b/tests/neg-custom-args/captures/capt1.scala @@ -24,8 +24,8 @@ def h3(x: Cap): A = F(22) // error def h4(x: Cap, y: Int): A = - new A: - def m() = if x == null then y else y // error + new A: // error + def m() = if x == null then y else y def f1(c: Cap): () ->{c} c.type = () => c // ok diff --git a/tests/neg-custom-args/captures/method-uses.scala b/tests/neg-custom-args/captures/method-uses.scala index 576e227e5d74..6c3310d49f7f 100644 --- a/tests/neg-custom-args/captures/method-uses.scala +++ b/tests/neg-custom-args/captures/method-uses.scala @@ -23,8 +23,8 @@ def test3(xs: List[() => Unit]): () ->{xs*} Unit = () => def test4(xs: List[() => Unit]) = () => xs.head // error, ok under deferredReaches def test5(xs: List[() => Unit]) = new: - println(xs.head) // error, ok under deferredReaches // error + println(xs.head) // error, ok under deferredReaches def test6(xs: List[() => Unit]) = - val x= new { println(xs.head) } // error // error + val x= new { println(xs.head) } // error x diff --git a/tests/neg-custom-args/captures/mut-iterator4.check b/tests/neg-custom-args/captures/mut-iterator4.check index 9ab60ada56ce..fcf3c9c35916 100644 --- a/tests/neg-custom-args/captures/mut-iterator4.check +++ b/tests/neg-custom-args/captures/mut-iterator4.check @@ -1,29 +1,20 @@ -- Error: tests/neg-custom-args/captures/mut-iterator4.scala:9:26 ------------------------------------------------------ -9 | update def next() = f(Iterator.this.next()) // error // error +9 | update def next() = f(Iterator.this.next()) // error | ^^^^^^^^^^^^^ | Read-only method map accesses exclusive capability (Iterator.this : Iterator[T]^); | method map should be declared an update method to allow this. | | where: ^ refers to the universal root capability --- [E007] Type Mismatch Error: tests/neg-custom-args/captures/mut-iterator4.scala:9:47 --------------------------------- -9 | update def next() = f(Iterator.this.next()) // error // error - | ^ - |Found: Iterator[U^'s1]^{Iterator.this.rd, f, Iterator.this, cap} - |Required: Iterator[U]^{Iterator.this, f} - | - |Note that capability cap is not included in capture set {Iterator.this, f}. - | - |where: cap is a fresh root capability created in method map when constructing instance Object with (Iterator[U]^{cap².rd}) {...} - | - | longer explanation available when compiling with `-explain` --- [E007] Type Mismatch Error: tests/neg-custom-args/captures/mut-iterator4.scala:23:34 -------------------------------- -23 | update def next() = f(it.next()) // error - | ^ - |Found: Iterator[U^'s2]^{it.rd, f, it, cap} +-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/mut-iterator4.scala:21:81 -------------------------------- +21 |def mappedIterator[T, U](it: Iterator[T]^, f: T => U): Iterator[U]^{it, f} = new Iterator: // error + | ^ + |Found: Iterator[U^'s1]^{it.rd, f, it, cap} |Required: Iterator[U]^{it, f} | |Note that capability cap is not included in capture set {it, f}. | |where: cap is a fresh root capability created in method mappedIterator when constructing instance Object with (Iterator[U]^{cap².rd}) {...} +22 | def hasNext = it.hasNext +23 | update def next() = f(it.next()) | | longer explanation available when compiling with `-explain` diff --git a/tests/neg-custom-args/captures/mut-iterator4.scala b/tests/neg-custom-args/captures/mut-iterator4.scala index 72c60d26edfc..1d6716e5f82d 100644 --- a/tests/neg-custom-args/captures/mut-iterator4.scala +++ b/tests/neg-custom-args/captures/mut-iterator4.scala @@ -6,7 +6,7 @@ trait Iterator[T] extends Stateful: def map[U](f: T => U): Iterator[U]^{Iterator.this, f} = new Iterator: def hasNext = Iterator.this.hasNext - update def next() = f(Iterator.this.next()) // error // error + update def next() = f(Iterator.this.next()) // error end Iterator @@ -18,9 +18,9 @@ def listIterator[T](xs: List[T]): Iterator[T]^ = new Iterator[T]: current = xs1 x -def mappedIterator[T, U](it: Iterator[T]^, f: T => U): Iterator[U]^{it, f} = new Iterator: +def mappedIterator[T, U](it: Iterator[T]^, f: T => U): Iterator[U]^{it, f} = new Iterator: // error def hasNext = it.hasNext - update def next() = f(it.next()) // error + update def next() = f(it.next()) class IO extends SharedCapability: def write(x: Any): Unit = () diff --git a/tests/neg/6570-1.check b/tests/neg/6570-1.check index 0abf96e2d350..6e48c72d18c7 100644 --- a/tests/neg/6570-1.check +++ b/tests/neg/6570-1.check @@ -1,14 +1,14 @@ --- [E007] Type Mismatch Error: tests/neg/6570-1.scala:23:27 ------------------------------------------------------------ +-- [E007] Type Mismatch Error: tests/neg/6570-1.scala:23:14 ------------------------------------------------------------ 23 | def thing = new Trait1 {} // error - | ^ - | Found: Object with Trait1 {...} - | Required: N[Box[Int & String]] + | ^^^^^^^^^^^^^ + | Found: Object with Trait1 {...} + | Required: N[Box[Int & String]] | - | Note: a match type could not be fully reduced: + | Note: a match type could not be fully reduced: | - | trying to reduce N[Box[Int & String]] - | failed since selector Box[Int & String] - | is uninhabited (there are no values of that type). + | trying to reduce N[Box[Int & String]] + | failed since selector Box[Int & String] + | is uninhabited (there are no values of that type). | | longer explanation available when compiling with `-explain` -- [E007] Type Mismatch Error: tests/neg/6570-1.scala:36:54 ------------------------------------------------------------ diff --git a/tests/neg/6570.check b/tests/neg/6570.check index e849814449eb..3cfef5b70ac9 100644 --- a/tests/neg/6570.check +++ b/tests/neg/6570.check @@ -17,17 +17,17 @@ | x >: Int | | longer explanation available when compiling with `-explain` --- [E007] Type Mismatch Error: tests/neg/6570.scala:29:29 -------------------------------------------------------------- +-- [E007] Type Mismatch Error: tests/neg/6570.scala:29:16 -------------------------------------------------------------- 29 | def thing = new Trait1 {} // error - | ^ - | Found: Object with Base.Trait1 {...} - | Required: Base.N[String & Int] + | ^^^^^^^^^^^^^ + | Found: Object with Base.Trait1 {...} + | Required: Base.N[String & Int] | - | Note: a match type could not be fully reduced: + | Note: a match type could not be fully reduced: | - | trying to reduce Base.N[String & Int] - | failed since selector String & Int - | is uninhabited (there are no values of that type). + | trying to reduce Base.N[String & Int] + | failed since selector String & Int + | is uninhabited (there are no values of that type). | | longer explanation available when compiling with `-explain` -- [E007] Type Mismatch Error: tests/neg/6570.scala:47:32 -------------------------------------------------------------- @@ -46,43 +46,43 @@ | a >: Int | | longer explanation available when compiling with `-explain` --- [E007] Type Mismatch Error: tests/neg/6570.scala:51:29 -------------------------------------------------------------- +-- [E007] Type Mismatch Error: tests/neg/6570.scala:51:16 -------------------------------------------------------------- 51 | def thing = new Trait1 {} // error - | ^ - | Found: Object with Base.Trait1 {...} - | Required: Base.N[String & Int] + | ^^^^^^^^^^^^^ + | Found: Object with Base.Trait1 {...} + | Required: Base.N[String & Int] | - | Note: a match type could not be fully reduced: + | Note: a match type could not be fully reduced: | - | trying to reduce Base.N[String & Int] - | failed since selector String & Int - | is uninhabited (there are no values of that type). + | trying to reduce Base.N[String & Int] + | failed since selector String & Int + | is uninhabited (there are no values of that type). | | longer explanation available when compiling with `-explain` --- [E007] Type Mismatch Error: tests/neg/6570.scala:69:29 -------------------------------------------------------------- +-- [E007] Type Mismatch Error: tests/neg/6570.scala:69:16 -------------------------------------------------------------- 69 | def thing = new Trait1 {} // error - | ^ - | Found: Object with Base.Trait1 {...} - | Required: Base.N[String & Int] + | ^^^^^^^^^^^^^ + | Found: Object with Base.Trait1 {...} + | Required: Base.N[String & Int] | - | Note: a match type could not be fully reduced: + | Note: a match type could not be fully reduced: | - | trying to reduce Base.N[String & Int] - | failed since selector String & Int - | is uninhabited (there are no values of that type). + | trying to reduce Base.N[String & Int] + | failed since selector String & Int + | is uninhabited (there are no values of that type). | | longer explanation available when compiling with `-explain` --- [E007] Type Mismatch Error: tests/neg/6570.scala:86:29 -------------------------------------------------------------- +-- [E007] Type Mismatch Error: tests/neg/6570.scala:86:16 -------------------------------------------------------------- 86 | def thing = new Trait1 {} // error - | ^ - | Found: Object with Base.Trait1 {...} - | Required: Base.N[String & Int] + | ^^^^^^^^^^^^^ + | Found: Object with Base.Trait1 {...} + | Required: Base.N[String & Int] | - | Note: a match type could not be fully reduced: + | Note: a match type could not be fully reduced: | - | trying to reduce Base.N[String & Int] - | failed since selector String & Int - | is uninhabited (there are no values of that type). + | trying to reduce Base.N[String & Int] + | failed since selector String & Int + | is uninhabited (there are no values of that type). | | longer explanation available when compiling with `-explain` -- [E007] Type Mismatch Error: tests/neg/6570.scala:103:32 ------------------------------------------------------------- @@ -101,16 +101,16 @@ | t >: Int | | longer explanation available when compiling with `-explain` --- [E007] Type Mismatch Error: tests/neg/6570.scala:107:29 ------------------------------------------------------------- +-- [E007] Type Mismatch Error: tests/neg/6570.scala:107:16 ------------------------------------------------------------- 107 | def thing = new Trait1 {} // error - | ^ - | Found: Object with Base.Trait1 {...} - | Required: Base.N[String & Int] + | ^^^^^^^^^^^^^ + | Found: Object with Base.Trait1 {...} + | Required: Base.N[String & Int] | - | Note: a match type could not be fully reduced: + | Note: a match type could not be fully reduced: | - | trying to reduce Base.N[String & Int] - | failed since selector String & Int - | is uninhabited (there are no values of that type). + | trying to reduce Base.N[String & Int] + | failed since selector String & Int + | is uninhabited (there are no values of that type). | | longer explanation available when compiling with `-explain` diff --git a/tests/neg/i13703.check b/tests/neg/i13703.check index a02bbdf407f7..c92349a476d1 100644 --- a/tests/neg/i13703.check +++ b/tests/neg/i13703.check @@ -1,7 +1,7 @@ --- [E007] Type Mismatch Error: tests/neg/i13703.scala:3:78 ------------------------------------------------------------- +-- [E007] Type Mismatch Error: tests/neg/i13703.scala:3:52 ------------------------------------------------------------- 3 |val f2: Foo { val i: Int; def i_=(x: Int): Unit } = new Foo { var i: Int = 0 } // error - | ^ - | Found: Object with Foo {...} - | Required: Foo{val i: Int; def i_=(x: Int): Unit} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | Found: Object with Foo {...} + | Required: Foo{val i: Int; def i_=(x: Int): Unit} | | longer explanation available when compiling with `-explain`