Skip to content

@unchecked pattern binding on type with unsupported isInstanceOf fails compilation  #14896

Closed
@griggt

Description

@griggt

Compiler version

3.1.2 and 3.1.3-RC1-bin-20220407-31f871c-NIGHTLY

Minimized code

This arose while working on #14294, the examples below are extracted from our test suite and modified with an @unchecked annotation.

Example 1

object Ex  { def unapply(p: Any): Option[_ <: Int] = null }
object Foo { val Ex(_) = null: @unchecked }

(extracted from tests/pos/extractor-types.scala )

Example 2

import scala.scalajs.js

object Test {
  val obj = new js.Object {
    val a = 42
    val b = "foo"
  }

  val entries = js.Object.entries(obj)
  val js.Tuple2(k, v) = entries(0): @unchecked
}

(extracted from this Scala.js test)

Output

Example 1

$ scalac extractor-types.scala

-- Error: extractor-types.scala:2:17 -------------------------------------------
2 |object Foo { val Ex(_) = null: @unchecked }
  |                 ^^^^^
  |                 class Null cannot be used in runtime type tests

Example 2

$ scalac -scalajs -cp $(cs fetch -p org.scala-js:scalajs-library_2.13:1.9.0) ObjectTest.scala

-- Error: ObjectTest.scala:10:6 ------------------------------------------------
10 |  val js.Tuple2(k, v) = entries(0): @unchecked
   |      ^^^^^^^^^^^^^^^
   |isInstanceOf[scala.scalajs.js.Tuple2] not supported because it is a JS trait

Expectation

Both examples compile without the @unchecked annotation.
Both examples compile with Scala 2.13.

Since @unchecked was added to suppress the refutable pattern binding warning (currently under -source future), I expected compilation to be successful here as well.

It seems that adding @unchecked is causing a type test to be generated that wouldn't be otherwise. Below is a diff of -Xprint:typer on the first example:

 [[syntax trees at end of                     typer]] // extractor-types.scala
 package <empty> {
   final lazy module val Ex: Ex = new Ex()
   final module class Ex() extends Object() { this: Ex.type =>
     def unapply(p: Any): Option[? >: Nothing <: Int] = null
   }
   final lazy module val Foo: Foo = new Foo()
   final module class Foo() extends Object() { this: Foo.type =>
-    null:Null @unchecked match 
+    null:Null @unchecked:Null @unchecked @unchecked match
       {
-        case Ex(_) => ()
+        case Ex(_):Null => ()
       }
   }
 }

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions