From 25fa24ee57d039751bd96f054824c8f9da5ac68e Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 17 Mar 2021 12:20:25 +0100 Subject: [PATCH 1/2] Move classType checks for new expressions to PostTyper When typechecking a new expression, we cannot reliably tell what the actual underlying type is since this might depend on type inference that still has to happen at this point. --- .../tools/dotc/transform/PostTyper.scala | 1 + .../src/dotty/tools/dotc/typer/Typer.scala | 4 ---- .../fatal-warnings/pureStatement.scala | 2 +- tests/neg/alloc-abstract.scala | 14 +++++------ tests/neg/creator-applys.scala | 24 +++---------------- tests/neg/i11781.scala | 4 ++++ tests/neg/i8569.check | 14 ++++------- tests/neg/i8569.scala | 8 +++++-- tests/neg/i8569a.check | 6 +++++ tests/neg/i8569a.scala | 14 +++++++++++ tests/neg/iarrays.scala | 2 +- tests/pos/i11781.scala | 24 +++++++++++++++++++ 12 files changed, 71 insertions(+), 46 deletions(-) create mode 100644 tests/neg/i11781.scala create mode 100644 tests/neg/i8569a.check create mode 100644 tests/neg/i8569a.scala create mode 100644 tests/pos/i11781.scala diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala index 675ac9f58a35..8e9b95a0c572 100644 --- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala @@ -295,6 +295,7 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase case Select(nu: New, nme.CONSTRUCTOR) if isCheckable(nu) => // need to check instantiability here, because the type of the New itself // might be a type constructor. + ctx.typer.checkClassType(tree.tpe, tree.srcPos, traitReq = false, stablePrefixReq = true) Checking.checkInstantiable(tree.tpe, nu.srcPos) withNoCheckNews(nu :: Nil)(app1) case _ => diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 85780105840c..11e198af2a8a 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -772,10 +772,6 @@ class Typer extends Namer case _ => var tpt1 = typedType(tree.tpt) tpt1 = tpt1.withType(ensureAccessible(tpt1.tpe, superAccess = false, tpt1.srcPos)) - - if (checkClassType(typeOfNew(tpt1), tpt1.srcPos, traitReq = false, stablePrefixReq = true) eq defn.ObjectType) - tpt1 = TypeTree(defn.ObjectType).withSpan(tpt1.span) - tpt1 match { case AppliedTypeTree(_, targs) => for case targ: TypeBoundsTree <- targs do diff --git a/tests/neg-custom-args/fatal-warnings/pureStatement.scala b/tests/neg-custom-args/fatal-warnings/pureStatement.scala index e05a258a9f37..80ee7c589dc7 100644 --- a/tests/neg-custom-args/fatal-warnings/pureStatement.scala +++ b/tests/neg-custom-args/fatal-warnings/pureStatement.scala @@ -26,7 +26,7 @@ object Test { doSideEffects(1) // error: pure expression does nothing in statement position - val broken = new IDontExist("") // error // error + val broken = new IDontExist("") // error broken.foo // no extra error, and no pure expression warning broken.foo() // same } diff --git a/tests/neg/alloc-abstract.scala b/tests/neg/alloc-abstract.scala index e0bcef133d67..8b053d19d576 100644 --- a/tests/neg/alloc-abstract.scala +++ b/tests/neg/alloc-abstract.scala @@ -3,13 +3,13 @@ class Test[T] { type Foo[T] = Array[T] - new T // error: not a class type - new T() // error: not a class type - new U // error: not a class type - new U() // error: not a class type - new IArray[String] // error: not a class type - new IArray[String]() // error: not a class type - new IArray[String](10) // error: not a class type // error: too mamy arguments + new T // error: does not have a constructor + new T() // error: does not have a constructor + new U // error: does not have a constructor + new U() // error: does not have a constructor + new IArray[String] // error: does not have a constructor + new IArray[String]() // error: does not have a constructor + new IArray[String](10) // error: does not have a constructor new Foo[String](10) // ok } \ No newline at end of file diff --git a/tests/neg/creator-applys.scala b/tests/neg/creator-applys.scala index 93245e519e6a..13fe06497784 100644 --- a/tests/neg/creator-applys.scala +++ b/tests/neg/creator-applys.scala @@ -10,26 +10,8 @@ class Test { def run = s"C $x $y" } - val x1 = new Test().A() // error: object A does not take parameters - val x2 = new Test().B() // error: value B is not a member of Test - val x3 = new Test().B[Int]() // error: value B is not a member of Test + val x1 = new Test().A() // error: not stable + val x2 = new Test().B() // error: not stable + val x3 = new Test().B[Int]() // error: not stable } - -object Test2 { - class A(s: String = "A") { - def run = s - } - object A { - def apply() = A("X") // error: recursive method needs return type - } -} - -object Test3 { - class A(s: String = "A") { - def run = s - } - object A { - def apply(): A = A("X") // error too many arguments - } -} \ No newline at end of file diff --git a/tests/neg/i11781.scala b/tests/neg/i11781.scala new file mode 100644 index 000000000000..391d4e94b008 --- /dev/null +++ b/tests/neg/i11781.scala @@ -0,0 +1,4 @@ + +trait A: + type Foo + new Foo // error: does not have a constructor diff --git a/tests/neg/i8569.check b/tests/neg/i8569.check index b8d9accd6520..c33cb68d750c 100644 --- a/tests/neg/i8569.check +++ b/tests/neg/i8569.check @@ -1,12 +1,6 @@ --- [E083] Type Error: tests/neg/i8569.scala:8:8 ------------------------------------------------------------------------ -8 | outer.Inner(2) // error - | ^^^^^^^^^^^ - | Outer is not a valid class prefix, since it is not an immutable path - -longer explanation available when compiling with `-explain` --- [E083] Type Error: tests/neg/i8569.scala:9:6 ------------------------------------------------------------------------ -9 | new outer.Inner(2) // error - | ^^^^^ - | (Test.outer : => Outer) is not a valid type prefix, since it is not an immutable path +-- [E083] Type Error: tests/neg/i8569.scala:13:21 ---------------------------------------------------------------------- +13 | val x = outer.Inner(2) // error (at posttyper) + | ^^^^^^^^^^^^^^ + | Outer is not a valid class prefix, since it is not an immutable path longer explanation available when compiling with `-explain` diff --git a/tests/neg/i8569.scala b/tests/neg/i8569.scala index bd1dc09567ee..2842f576bd9d 100644 --- a/tests/neg/i8569.scala +++ b/tests/neg/i8569.scala @@ -2,9 +2,13 @@ class Outer(x: Int) { class Inner(y: Int) { } } +class Outer2(x: Int) { + class Inner(y: Int) { + } +} object Test { def outer = Outer(1) + def outer2 = Outer2(1) - outer.Inner(2) // error - new outer.Inner(2) // error + val x = outer.Inner(2) // error (at posttyper) } \ No newline at end of file diff --git a/tests/neg/i8569a.check b/tests/neg/i8569a.check new file mode 100644 index 000000000000..b6ba88cba3b6 --- /dev/null +++ b/tests/neg/i8569a.check @@ -0,0 +1,6 @@ +-- [E083] Type Error: tests/neg/i8569a.scala:13:14 --------------------------------------------------------------------- +13 | val x = new outer2.Inner(2) // error (at typer) + | ^^^^^^ + | (Test.outer2 : => Outer2) is not a valid type prefix, since it is not an immutable path + +longer explanation available when compiling with `-explain` diff --git a/tests/neg/i8569a.scala b/tests/neg/i8569a.scala new file mode 100644 index 000000000000..e62a5fab565a --- /dev/null +++ b/tests/neg/i8569a.scala @@ -0,0 +1,14 @@ +class Outer(x: Int) { + class Inner(y: Int) { + } +} +class Outer2(x: Int) { + class Inner(y: Int) { + } +} +object Test { + def outer = Outer(1) + def outer2 = Outer2(1) + + val x = new outer2.Inner(2) // error (at typer) +} \ No newline at end of file diff --git a/tests/neg/iarrays.scala b/tests/neg/iarrays.scala index 88e77085972d..2ecd70d1e6d3 100644 --- a/tests/neg/iarrays.scala +++ b/tests/neg/iarrays.scala @@ -1,7 +1,7 @@ object Test { // Can't allocate an IArray - new IArray[String](10) // error: not a class type // error: too many arguments + new IArray[String](10) // error: does not have a constructor val xs = IArray(1, 2, 3) diff --git a/tests/pos/i11781.scala b/tests/pos/i11781.scala new file mode 100644 index 000000000000..08fc5b5823eb --- /dev/null +++ b/tests/pos/i11781.scala @@ -0,0 +1,24 @@ +object Test: + class C1[A](a: A) + type D1[A] = C1[A] + new D1(1) + + class C2[B, A](a: A) + type D2[A] = C2[Int, A] + new D2(1) + new D2[Int](1) + + class E(x: Int) extends D2[Int](x) + class F(x: Int) extends D2(x) + +object Ah { + final case class Values[B, +A](a: A) + + trait Object[B] { + final type Values[+A] = Ah.Values[B, A] + object Values { + def blah: Values[Unit] = + new Values(()) + } + } +} \ No newline at end of file From eb7e94a09a8a6202a54dcb35786da8ed21e1d5dd Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 17 Mar 2021 12:26:07 +0100 Subject: [PATCH 2/2] Add test --- tests/neg/creator-applys2.scala | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 tests/neg/creator-applys2.scala diff --git a/tests/neg/creator-applys2.scala b/tests/neg/creator-applys2.scala new file mode 100644 index 000000000000..45833c1d896c --- /dev/null +++ b/tests/neg/creator-applys2.scala @@ -0,0 +1,18 @@ + +object Test2 { + class A(s: String = "A") { + def run = s + } + object A { + def apply() = A("X") // error: recursive method needs return type + } +} + +object Test3 { + class A(s: String = "A") { + def run = s + } + object A { + def apply(): A = A("X") // error too many arguments + } +} \ No newline at end of file