Skip to content

Commit 307fcc4

Browse files
authored
Merge pull request #13647 from dotty-staging/explicit-nulls-override
Fix overriding in explicit nulls
2 parents adeb1ab + 79931f3 commit 307fcc4

File tree

7 files changed

+53
-4
lines changed

7 files changed

+53
-4
lines changed

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,11 @@ object Types {
301301

302302
def isFromJavaObject(using Context): Boolean = typeSymbol eq defn.FromJavaObjectSymbol
303303

304+
def containsFromJavaObject(using Context): Boolean = this match
305+
case tp: OrType => tp.tp1.containsFromJavaObject || tp.tp2.containsFromJavaObject
306+
case tp: AndType => tp.tp1.containsFromJavaObject && tp.tp2.containsFromJavaObject
307+
case _ => isFromJavaObject
308+
304309
/** True iff `symd` is a denotation of a class type parameter and the reference
305310
* `<pre> . <symd>` is an actual argument reference, i.e. `pre` is not the
306311
* ThisType of `symd`'s owner, or a reference to `symd`'s owner.'
@@ -4933,8 +4938,23 @@ object Types {
49334938
}
49344939

49354940
def & (that: TypeBounds)(using Context): TypeBounds =
4936-
if ((this.lo frozen_<:< that.lo) && (that.hi frozen_<:< this.hi)) that
4937-
else if ((that.lo frozen_<:< this.lo) && (this.hi frozen_<:< that.hi)) this
4941+
// This will try to preserve the FromJavaObjects type in upper bounds.
4942+
// For example, (? <: FromJavaObjects | Null) & (? <: Any),
4943+
// we want to get (? <: FromJavaObjects | Null) intead of (? <: Any),
4944+
// because we may check the result <:< (? <: Object | Null) later.
4945+
if this.hi.containsFromJavaObject
4946+
&& (this.hi frozen_<:< that.hi)
4947+
&& (that.lo frozen_<:< this.lo) then
4948+
// FromJavaObject in tp1.hi guarantees tp2.hi <:< tp1.hi
4949+
// prefer tp1 if FromJavaObject is in its hi
4950+
this
4951+
else if that.hi.containsFromJavaObject
4952+
&& (that.hi frozen_<:< this.hi)
4953+
&& (this.lo frozen_<:< that.lo) then
4954+
// Similarly, prefer tp2 if FromJavaObject is in its hi
4955+
that
4956+
else if (this.lo frozen_<:< that.lo) && (that.hi frozen_<:< this.hi) then that
4957+
else if (that.lo frozen_<:< this.lo) && (this.hi frozen_<:< that.hi) then this
49384958
else TypeBounds(this.lo | that.lo, this.hi & that.hi)
49394959

49404960
def | (that: TypeBounds)(using Context): TypeBounds =

compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import Decorators._
1515
import Denotations._, SymDenotations._
1616
import TypeErasure.erasure
1717
import DenotTransformers._
18+
import NullOpsDecorator._
1819

1920
object ElimRepeated {
2021
val name: String = "elimRepeated"
@@ -335,6 +336,9 @@ class ElimRepeated extends MiniPhase with InfoTransformer { thisPhase =>
335336
val array = tp.translateFromRepeated(toArray = true) // Array[? <: T]
336337
val element = array.elemType.hiBound // T
337338

338-
if element <:< defn.AnyRefType || element.typeSymbol.isPrimitiveValueClass then array
339+
340+
if element <:< defn.AnyRefType
341+
|| ctx.mode.is(Mode.SafeNulls) && element.stripNull <:< defn.AnyRefType
342+
|| element.typeSymbol.isPrimitiveValueClass then array
339343
else defn.ArrayOf(TypeBounds.upper(AndType(element, defn.AnyRefType))) // Array[? <: T & AnyRef]
340344
}

compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,14 @@ object ResolveSuper {
107107
// of the superaccessor's type, see i5433.scala for an example where this matters
108108
val otherTp = other.asSeenFrom(base.typeRef).info
109109
val accTp = acc.asSeenFrom(base.typeRef).info
110-
if (!(otherTp.overrides(accTp, matchLoosely = true)))
110+
// Since the super class can be Java defined,
111+
// we use releaxed overriding check for explicit nulls if one of the symbols is Java defined.
112+
// This forces `Null` being a subtype of reference types during override checking.
113+
val relaxedCtxForNulls =
114+
if ctx.explicitNulls && (sym.is(JavaDefined) || acc.is(JavaDefined)) then
115+
ctx.retractMode(Mode.SafeNulls)
116+
else ctx
117+
if (!(otherTp.overrides(accTp, matchLoosely = true)(using relaxedCtxForNulls)))
111118
report.error(IllegalSuperAccessor(base, memberName, targetName, acc, accTp, other.symbol, otherTp), base.srcPos)
112119

113120
bcs = bcs.tail
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
class Impl extends Intf:
2+
override def test(x: Object | Null*): Unit = ???
3+
4+
class Impl2 extends Intf:
5+
override def test(x: Object*): Unit = ???
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
interface Intf {
2+
void test(Object... x);
3+
}

tests/explicit-nulls/pos/i13486.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
class MyPrintStream extends java.io.PrintStream(??? : java.io.OutputStream):
2+
override def printf(format: String | Null, args: Array[? <: Object | Null])
3+
: java.io.PrintStream | Null = ???
4+
5+
class MyPrintStream2 extends java.io.PrintStream(??? : java.io.OutputStream):
6+
override def printf(format: String, args: Array[? <: Object])
7+
: java.io.PrintStream = ???

tests/explicit-nulls/pos/i13608.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import scala.util.control.NoStackTrace
2+
3+
case class ParseException(line: Int, character: Int, message: String) extends NoStackTrace

0 commit comments

Comments
 (0)