Skip to content

Method with Object... varargs parameter cannot be overridden under -Yexplicit-nulls #13040

Closed
@ScoreUnder

Description

@ScoreUnder

Compiler version

3.0.0 and 3.0.1-RC2

Minimized code

intf.java

interface Intf {
    void test(Object... x);
}

impl.scala

class Impl extends Intf:
  override def test(x: Object | Null*): Unit = ???

Output

scalac3 -Yexplicit-nulls -explain impl.scala

1 |class Impl extends Intf:
  |      ^
  |      error overriding method test in trait Intf of type (x$0: Array[? <: Object | Null]): Unit;
  |        method test of type (x: Array[? <: (Object | Null) & AnyRef]): Unit has incompatible type
`-explain` stuff
Explanation
===========

I tried to show that
  (x: Array[? <: (Object | Null) & AnyRef]): Unit
conforms to
  (x$0: Array[? <: Object | Null]): Unit
but the comparison trace ended with `false`:
          
  ==> (x: Array[? <: (Object | Null) & AnyRef]): Unit  <:  (x$0: Array[? <: Object | Null]): Unit
    ==> (x: Array[? <: (Object | Null) & AnyRef]): Unit  <:  (x$0: Array[? <: Object | Null]): Unit (recurring)
      ==> Array[? <: (Object | Null) & AnyRef]  <:  Array[? <: Object | Null] in frozen constraint
        ==> Array[? <: (Object | Null) & AnyRef]  <:  Array[? <: Object | Null] (recurring) in frozen constraint
          ==> Nothing  <:  Nothing in frozen constraint
            ==> Nothing  <:  Nothing (recurring) in frozen constraint
            <== Nothing  <:  Nothing (recurring) in frozen constraint = true
          <== Nothing  <:  Nothing in frozen constraint = true
          ==> Any  <:  (Object | Null) & AnyRef in frozen constraint
            ==> Any  <:  (Object | Null) & AnyRef (recurring) in frozen constraint
              ==> Any  <:  Object | Null (recurring) in frozen constraint
                ==> Any  <:  Object (recurring) in frozen constraint
                <== Any  <:  Object (recurring) in frozen constraint = false
                ==> Any  <:  Null (recurring) in frozen constraint
                <== Any  <:  Null (recurring) in frozen constraint = false
              <== Any  <:  Object | Null (recurring) in frozen constraint = false
            <== Any  <:  (Object | Null) & AnyRef (recurring) in frozen constraint = false
          <== Any  <:  (Object | Null) & AnyRef in frozen constraint = false
          ==> Nothing  <:  Nothing in frozen constraint
            ==> Nothing  <:  Nothing (recurring) in frozen constraint
            <== Nothing  <:  Nothing (recurring) in frozen constraint = true
          <== Nothing  <:  Nothing in frozen constraint = true
          ==> (Object | Null) & AnyRef  <:  Any in frozen constraint
            ==> (Object | Null) & AnyRef  <:  Any (recurring) in frozen constraint
            <== (Object | Null) & AnyRef  <:  Any (recurring) in frozen constraint = true
          <== (Object | Null) & AnyRef  <:  Any in frozen constraint = true
          ==> (Object | Null) & AnyRef  <:  Object | Null in frozen constraint
            ==> (Object | Null) & AnyRef  <:  Object | Null (recurring) in frozen constraint
              ==> (Object | Null) & AnyRef  <:  Object (recurring) in frozen constraint
                ==> (Object | Null) & AnyRef  <:  Any (recurring) in frozen constraint
                <== (Object | Null) & AnyRef  <:  Any (recurring) in frozen constraint = true
              <== (Object | Null) & AnyRef  <:  Object (recurring) in frozen constraint = true
            <== (Object | Null) & AnyRef  <:  Object | Null (recurring) in frozen constraint = true
          <== (Object | Null) & AnyRef  <:  Object | Null in frozen constraint = true
        <== Array[? <: (Object | Null) & AnyRef]  <:  Array[? <: Object | Null] (recurring) in frozen constraint = true
      <== Array[? <: (Object | Null) & AnyRef]  <:  Array[? <: Object | Null] in frozen constraint = true
      ==> Array[? <: Object | Null]  <:  Array[? <: (Object | Null) & AnyRef] in frozen constraint
        ==> Array[? <: Object | Null]  <:  Array[? <: (Object | Null) & AnyRef] (recurring) in frozen constraint
          ==> Nothing  <:  Nothing in frozen constraint
            ==> Nothing  <:  Nothing (recurring) in frozen constraint
            <== Nothing  <:  Nothing (recurring) in frozen constraint = true
          <== Nothing  <:  Nothing in frozen constraint = true
          ==> Any  <:  Object | Null in frozen constraint
            ==> Any  <:  Object | Null (recurring) in frozen constraint
              ==> Any  <:  Object (recurring) in frozen constraint
                ==> Any  <:  Any (recurring) in frozen constraint
                <== Any  <:  Any (recurring) in frozen constraint = true
              <== Any  <:  Object (recurring) in frozen constraint = true
            <== Any  <:  Object | Null (recurring) in frozen constraint = true
          <== Any  <:  Object | Null in frozen constraint = true
          ==> Any  <:  (Object | Null) & AnyRef in frozen constraint
            ==> Any  <:  (Object | Null) & AnyRef (recurring) in frozen constraint
              ==> Any  <:  Object | Null (recurring) in frozen constraint
                ==> Any  <:  Object (recurring) in frozen constraint
                <== Any  <:  Object (recurring) in frozen constraint = false
                ==> Any  <:  Null (recurring) in frozen constraint
                <== Any  <:  Null (recurring) in frozen constraint = false
              <== Any  <:  Object | Null (recurring) in frozen constraint = false
            <== Any  <:  (Object | Null) & AnyRef (recurring) in frozen constraint = false
          <== Any  <:  (Object | Null) & AnyRef in frozen constraint = false
        <== Array[? <: Object | Null]  <:  Array[? <: (Object | Null) & AnyRef] (recurring) in frozen constraint = false
      <== Array[? <: Object | Null]  <:  Array[? <: (Object | Null) & AnyRef] in frozen constraint = false
    <== (x: Array[? <: (Object | Null) & AnyRef]): Unit  <:  (x$0: Array[? <: Object | Null]): Unit (recurring) = false
  <== (x: Array[? <: (Object | Null) & AnyRef]): Unit  <:  (x$0: Array[? <: Object | Null]): Unit = false

The tests were made under the empty constraint

Expectation

The type signature Object | Null* should be an appropriate match for Object... and allow the code to compile.


Another piece of example code

intf.java

interface Intf {
    void test(int x);
    void test(Object... x);
}

impl.scala

class Impl extends Intf:
  override def test(x: Int): Unit = ???
  override def test(x: Array[_ <: Object | Null]): Unit = ???

note: Array is used here because scala varargs is not compatible with java's when the method is overloaded. For non-Object varargs in this situation an Array is accepted by the compiler, but for Object varargs we hit the same bug.

Output (scalac3 -Yexplicit-nulls -explain impl.scala):

-- [E163] Declaration Error: impl.scala:3:15 ------------------------------------------------------------------------------------------------------------------------------------------------------
3 |  override def test(x: Array[_ <: Object | Null]): Unit = ???
  |               ^
  |               error overriding method test in trait Intf of type (x$0: Array[? <: Object | Null]): Unit;
  |                 method test of type (x: Array[? <: Object | Null]): Unit has incompatible type

Explanation
===========

I tried to show that
  (x: Array[? <: Object | Null]): Unit
conforms to
  (x$0: Array[? <: Object | Null]): Unit
but the comparison trace ended with `false`:
          
  ==> (x: Array[? <: Object | Null]): Unit  <:  (x$0: Array[? <: Object | Null]): Unit
    ==> (x: Array[? <: Object | Null]): Unit  <:  (x$0: Array[? <: Object | Null]): Unit (recurring)
      ==> Array[? <: Object | Null]  <:  Array[? <: Object | Null] in frozen constraint
        ==> Array[? <: Object | Null]  <:  Array[? <: Object | Null] (recurring) in frozen constraint
          ==> scala.type  <:  (scala : scala.type) in frozen constraint
            ==> scala.type  <:  (scala : scala.type) (recurring) in frozen constraint
            <== scala.type  <:  (scala : scala.type) (recurring) in frozen constraint = true
          <== scala.type  <:  (scala : scala.type) in frozen constraint = true
          ==> Nothing  <:  Nothing in frozen constraint
            ==> Nothing  <:  Nothing (recurring) in frozen constraint
            <== Nothing  <:  Nothing (recurring) in frozen constraint = true
          <== Nothing  <:  Nothing in frozen constraint = true
          ==> Any  <:  Object | Null in frozen constraint
            ==> Any  <:  Object | Null (recurring) in frozen constraint
              ==> Any  <:  Object (recurring) in frozen constraint
              <== Any  <:  Object (recurring) in frozen constraint = false
              ==> Any  <:  Null (recurring) in frozen constraint
              <== Any  <:  Null (recurring) in frozen constraint = false
            <== Any  <:  Object | Null (recurring) in frozen constraint = false
          <== Any  <:  Object | Null in frozen constraint = false
          ==> Nothing  <:  Nothing in frozen constraint
            ==> Nothing  <:  Nothing (recurring) in frozen constraint
            <== Nothing  <:  Nothing (recurring) in frozen constraint = true
          <== Nothing  <:  Nothing in frozen constraint = true
          ==> Object | Null  <:  Any in frozen constraint
            ==> Object | Null  <:  Any (recurring) in frozen constraint
              ==> Object  <:  Any (recurring) in frozen constraint
              <== Object  <:  Any (recurring) in frozen constraint = true
              ==> Null  <:  Any (recurring) in frozen constraint
              <== Null  <:  Any (recurring) in frozen constraint = true
            <== Object | Null  <:  Any (recurring) in frozen constraint = true
          <== Object | Null  <:  Any in frozen constraint = true
          ==> Object | Null  <:  Object | Null in frozen constraint
            ==> Object | Null  <:  Object | Null (recurring) in frozen constraint
              ==> Object  <:  Object | Null (recurring) in frozen constraint
                ==> Object  <:  Object (recurring) in frozen constraint
                  ==> Object  <:  Any (recurring) in frozen constraint
                  <== Object  <:  Any (recurring) in frozen constraint = true
                <== Object  <:  Object (recurring) in frozen constraint = true
              <== Object  <:  Object | Null (recurring) in frozen constraint = true
              ==> Null  <:  Object | Null (recurring) in frozen constraint
                ==> Null  <:  Object (recurring) in frozen constraint
                  ==> Null  <:  Any (recurring) in frozen constraint
                  <== Null  <:  Any (recurring) in frozen constraint = true
                <== Null  <:  Object (recurring) in frozen constraint = true
              <== Null  <:  Object | Null (recurring) in frozen constraint = true
            <== Object | Null  <:  Object | Null (recurring) in frozen constraint = true
          <== Object | Null  <:  Object | Null in frozen constraint = true
        <== Array[? <: Object | Null]  <:  Array[? <: Object | Null] (recurring) in frozen constraint = true
      <== Array[? <: Object | Null]  <:  Array[? <: Object | Null] in frozen constraint = true
      ==> Array[? <: Object | Null]  <:  Array[? <: Object | Null] in frozen constraint
        ==> Array[? <: Object | Null]  <:  Array[? <: Object | Null] (recurring) in frozen constraint
          ==> (scala : scala.type)  <:  scala.type in frozen constraint
            ==> (scala : scala.type)  <:  scala.type (recurring) in frozen constraint
            <== (scala : scala.type)  <:  scala.type (recurring) in frozen constraint = true
          <== (scala : scala.type)  <:  scala.type in frozen constraint = true
          ==> Nothing  <:  Nothing in frozen constraint
            ==> Nothing  <:  Nothing (recurring) in frozen constraint
            <== Nothing  <:  Nothing (recurring) in frozen constraint = true
          <== Nothing  <:  Nothing in frozen constraint = true
          ==> Any  <:  Object | Null in frozen constraint
            ==> Any  <:  Object | Null (recurring) in frozen constraint
              ==> Any  <:  Object (recurring) in frozen constraint
                ==> Any  <:  Any (recurring) in frozen constraint
                <== Any  <:  Any (recurring) in frozen constraint = true
              <== Any  <:  Object (recurring) in frozen constraint = true
            <== Any  <:  Object | Null (recurring) in frozen constraint = true
          <== Any  <:  Object | Null in frozen constraint = true
          ==> Any  <:  Object | Null in frozen constraint
            ==> Any  <:  Object | Null (recurring) in frozen constraint
              ==> Any  <:  Object (recurring) in frozen constraint
              <== Any  <:  Object (recurring) in frozen constraint = false
              ==> Any  <:  Null (recurring) in frozen constraint
              <== Any  <:  Null (recurring) in frozen constraint = false
            <== Any  <:  Object | Null (recurring) in frozen constraint = false
          <== Any  <:  Object | Null in frozen constraint = false
        <== Array[? <: Object | Null]  <:  Array[? <: Object | Null] (recurring) in frozen constraint = false
      <== Array[? <: Object | Null]  <:  Array[? <: Object | Null] in frozen constraint = false
    <== (x: Array[? <: Object | Null]): Unit  <:  (x$0: Array[? <: Object | Null]): Unit (recurring) = false
  <== (x: Array[? <: Object | Null]): Unit  <:  (x$0: Array[? <: Object | Null]): Unit = false

The tests were made under the empty constraint

1 error found

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions