diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index d3c0eeab73d9..cd5df4f78614 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -301,6 +301,11 @@ object Types { def isFromJavaObject(using Context): Boolean = typeSymbol eq defn.FromJavaObjectSymbol + def containsFromJavaObject(using Context): Boolean = this match + case tp: OrType => tp.tp1.containsFromJavaObject || tp.tp2.containsFromJavaObject + case tp: AndType => tp.tp1.containsFromJavaObject && tp.tp2.containsFromJavaObject + case _ => isFromJavaObject + /** True iff `symd` is a denotation of a class type parameter and the reference * `
 . ` is an actual argument reference, i.e. `pre` is not the
      *  ThisType of `symd`'s owner, or a reference to `symd`'s owner.'
@@ -4933,8 +4938,23 @@ object Types {
     }
 
     def & (that: TypeBounds)(using Context): TypeBounds =
-      if ((this.lo frozen_<:< that.lo) && (that.hi frozen_<:< this.hi)) that
-      else if ((that.lo frozen_<:< this.lo) && (this.hi frozen_<:< that.hi)) this
+      // This will try to preserve the FromJavaObjects type in upper bounds.
+      // For example, (? <: FromJavaObjects | Null) & (? <: Any),
+      // we want to get (? <: FromJavaObjects | Null) intead of (? <: Any),
+      // because we may check the result <:< (? <: Object | Null) later.
+      if this.hi.containsFromJavaObject
+        && (this.hi frozen_<:< that.hi)
+        && (that.lo frozen_<:< this.lo) then
+        // FromJavaObject in tp1.hi guarantees tp2.hi <:< tp1.hi
+        // prefer tp1 if FromJavaObject is in its hi
+        this
+      else if that.hi.containsFromJavaObject
+        && (that.hi frozen_<:< this.hi)
+        && (this.lo frozen_<:< that.lo) then
+        // Similarly, prefer tp2 if FromJavaObject is in its hi
+        that
+      else if (this.lo frozen_<:< that.lo) && (that.hi frozen_<:< this.hi) then that
+      else if (that.lo frozen_<:< this.lo) && (this.hi frozen_<:< that.hi) then this
       else TypeBounds(this.lo | that.lo, this.hi & that.hi)
 
     def | (that: TypeBounds)(using Context): TypeBounds =
diff --git a/compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala b/compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala
index 429c0e7445b2..71d814bb0a62 100644
--- a/compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala
+++ b/compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala
@@ -15,6 +15,7 @@ import Decorators._
 import Denotations._, SymDenotations._
 import TypeErasure.erasure
 import DenotTransformers._
+import NullOpsDecorator._
 
 object ElimRepeated {
   val name: String = "elimRepeated"
@@ -335,6 +336,9 @@ class ElimRepeated extends MiniPhase with InfoTransformer { thisPhase =>
     val array = tp.translateFromRepeated(toArray = true) // Array[? <: T]
     val element = array.elemType.hiBound // T
 
-    if element <:< defn.AnyRefType || element.typeSymbol.isPrimitiveValueClass then array
+
+    if element <:< defn.AnyRefType
+      || ctx.mode.is(Mode.SafeNulls) && element.stripNull <:< defn.AnyRefType
+      || element.typeSymbol.isPrimitiveValueClass then array
     else defn.ArrayOf(TypeBounds.upper(AndType(element, defn.AnyRefType))) // Array[? <: T & AnyRef]
 }
diff --git a/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala b/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala
index 30ccc69e37ca..40c860bf3bdc 100644
--- a/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala
+++ b/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala
@@ -107,7 +107,14 @@ object ResolveSuper {
         // of the superaccessor's type, see i5433.scala for an example where this matters
         val otherTp = other.asSeenFrom(base.typeRef).info
         val accTp = acc.asSeenFrom(base.typeRef).info
-        if (!(otherTp.overrides(accTp, matchLoosely = true)))
+        // Since the super class can be Java defined,
+        // we use releaxed overriding check for explicit nulls if one of the symbols is Java defined.
+        // This forces `Null` being a subtype of reference types during override checking.
+        val relaxedCtxForNulls =
+        if ctx.explicitNulls && (sym.is(JavaDefined) || acc.is(JavaDefined)) then
+          ctx.retractMode(Mode.SafeNulls)
+        else ctx
+        if (!(otherTp.overrides(accTp, matchLoosely = true)(using relaxedCtxForNulls)))
           report.error(IllegalSuperAccessor(base, memberName, targetName, acc, accTp, other.symbol, otherTp), base.srcPos)
 
       bcs = bcs.tail
diff --git a/tests/explicit-nulls/pos/i13040/Impl.scala b/tests/explicit-nulls/pos/i13040/Impl.scala
new file mode 100644
index 000000000000..d26927db2e94
--- /dev/null
+++ b/tests/explicit-nulls/pos/i13040/Impl.scala
@@ -0,0 +1,5 @@
+class Impl extends Intf:
+  override def test(x: Object | Null*): Unit = ???
+
+class Impl2 extends Intf:
+  override def test(x: Object*): Unit = ???
diff --git a/tests/explicit-nulls/pos/i13040/Intf.java b/tests/explicit-nulls/pos/i13040/Intf.java
new file mode 100644
index 000000000000..816c94485cc4
--- /dev/null
+++ b/tests/explicit-nulls/pos/i13040/Intf.java
@@ -0,0 +1,3 @@
+interface Intf {
+    void test(Object... x);
+}
diff --git a/tests/explicit-nulls/pos/i13486.scala b/tests/explicit-nulls/pos/i13486.scala
new file mode 100644
index 000000000000..d9fafc157d4c
--- /dev/null
+++ b/tests/explicit-nulls/pos/i13486.scala
@@ -0,0 +1,7 @@
+class MyPrintStream extends java.io.PrintStream(??? : java.io.OutputStream):
+  override def printf(format: String | Null, args: Array[? <: Object | Null])
+  : java.io.PrintStream | Null = ???
+
+class MyPrintStream2 extends java.io.PrintStream(??? : java.io.OutputStream):
+  override def printf(format: String, args: Array[? <: Object])
+  : java.io.PrintStream = ???
diff --git a/tests/explicit-nulls/pos/i13608.scala b/tests/explicit-nulls/pos/i13608.scala
new file mode 100644
index 000000000000..29f9f8692086
--- /dev/null
+++ b/tests/explicit-nulls/pos/i13608.scala
@@ -0,0 +1,3 @@
+import scala.util.control.NoStackTrace
+
+case class ParseException(line: Int, character: Int, message: String) extends NoStackTrace