From b992d988e9e0600444bba1a64cb367d5a2b323e7 Mon Sep 17 00:00:00 2001 From: noti0na1 Date: Thu, 19 Aug 2021 11:20:20 +0000 Subject: [PATCH 1/3] Strip Nulls from Java calls under unsafeNulls --- .../src/dotty/tools/dotc/typer/Typer.scala | 9 ++++++++ .../unsafe-common/unsafe-java-call/J.java | 13 ++++++++++++ .../unsafe-common/unsafe-java-call/S.scala | 21 +++++++++++++++++++ 3 files changed, 43 insertions(+) create mode 100644 tests/explicit-nulls/unsafe-common/unsafe-java-call/J.java create mode 100644 tests/explicit-nulls/unsafe-common/unsafe-java-call/S.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index b77c21893ef7..7810e07d1411 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -3746,6 +3746,15 @@ class Typer extends Namer if target <:< pt then return readapt(tree.cast(target)) + // if unsafeNulls is enabled, try to strip nulls from Java function calls + if Nullables.unsafeNullsEnabled then + tree match + case _: Apply if tree.symbol.is(JavaDefined) => + wtp match + case OrNull(wtp1) => return readapt(tree.cast(wtp1)) + case _ => + case _ => + def recover(failure: SearchFailureType) = if canDefineFurther(wtp) || canDefineFurther(pt) then readapt(tree) else err.typeMismatch(tree, pt, failure) diff --git a/tests/explicit-nulls/unsafe-common/unsafe-java-call/J.java b/tests/explicit-nulls/unsafe-common/unsafe-java-call/J.java new file mode 100644 index 000000000000..3ed89edb14a7 --- /dev/null +++ b/tests/explicit-nulls/unsafe-common/unsafe-java-call/J.java @@ -0,0 +1,13 @@ +public class J { + public String f1() { + return ""; + } + + public int f2() { + return 0; + } + + public T g1() { + return null; + } +} \ No newline at end of file diff --git a/tests/explicit-nulls/unsafe-common/unsafe-java-call/S.scala b/tests/explicit-nulls/unsafe-common/unsafe-java-call/S.scala new file mode 100644 index 000000000000..3a8e26840280 --- /dev/null +++ b/tests/explicit-nulls/unsafe-common/unsafe-java-call/S.scala @@ -0,0 +1,21 @@ +import scala.language.unsafeNulls + +val j: J = new J + +val s1: String = j.f1() + +val i1: Int = j.f2() + +val s2: String = j.g1[String]() + +val i2: Int = j.g1[Int]() + +val a1: Any = j.g1[Any]() + +val ar1: AnyRef = j.g1[AnyRef]() + +val n1: Null = j.g1[Null]() + +val ar2: AnyRef = j.g1[Null]() + +def clo[T]: T = j.g1[T]() \ No newline at end of file From 8598031834939ff2de3fad95c56d30c1604316a0 Mon Sep 17 00:00:00 2001 From: noti0na1 Date: Thu, 19 Aug 2021 11:33:56 +0000 Subject: [PATCH 2/3] Update test --- .../unsafe-common/unsafe-java-call/S.scala | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/tests/explicit-nulls/unsafe-common/unsafe-java-call/S.scala b/tests/explicit-nulls/unsafe-common/unsafe-java-call/S.scala index 3a8e26840280..431f479846f2 100644 --- a/tests/explicit-nulls/unsafe-common/unsafe-java-call/S.scala +++ b/tests/explicit-nulls/unsafe-common/unsafe-java-call/S.scala @@ -1,21 +1,33 @@ -import scala.language.unsafeNulls +// Check Java calls have been cast to non-nullable. val j: J = new J -val s1: String = j.f1() +val s1: String = j.f1() // error + +val s1n: String | Null = j.f1() val i1: Int = j.f2() -val s2: String = j.g1[String]() +val s2: String = j.g1[String]() // error + +val s2n: String | Null = j.g1[String]() + +val s3: String = j.g1[String | Null]() // error -val i2: Int = j.g1[Int]() +val s3n: String | Null = j.g1[String | Null]() + +val i2: Int = j.g1[Int]() // error val a1: Any = j.g1[Any]() -val ar1: AnyRef = j.g1[AnyRef]() +val ar1: AnyRef = j.g1[AnyRef]() // error val n1: Null = j.g1[Null]() -val ar2: AnyRef = j.g1[Null]() +val ar2: AnyRef = j.g1[Null]() // error + +def clo1[T]: T = j.g1[T]() // error + +def clo2[T <: AnyRef]: T = j.g1[T | Null]() // error -def clo[T]: T = j.g1[T]() \ No newline at end of file +def clo3[T >: Null <: AnyRef | Null]: T = j.g1[T]() \ No newline at end of file From 9b9a969669129d418d89e8fdfb219eca0349a256 Mon Sep 17 00:00:00 2001 From: noti0na1 Date: Fri, 20 Aug 2021 12:13:09 +0000 Subject: [PATCH 3/3] Add support for Java fields --- compiler/src/dotty/tools/dotc/typer/Typer.scala | 2 +- tests/explicit-nulls/unsafe-common/unsafe-java-call/J.java | 4 ++++ tests/explicit-nulls/unsafe-common/unsafe-java-call/S.scala | 6 +++++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 7810e07d1411..3d07f2b87250 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -3749,7 +3749,7 @@ class Typer extends Namer // if unsafeNulls is enabled, try to strip nulls from Java function calls if Nullables.unsafeNullsEnabled then tree match - case _: Apply if tree.symbol.is(JavaDefined) => + case _: Apply | _: Select if tree.symbol.is(JavaDefined) => wtp match case OrNull(wtp1) => return readapt(tree.cast(wtp1)) case _ => diff --git a/tests/explicit-nulls/unsafe-common/unsafe-java-call/J.java b/tests/explicit-nulls/unsafe-common/unsafe-java-call/J.java index 3ed89edb14a7..554b91749889 100644 --- a/tests/explicit-nulls/unsafe-common/unsafe-java-call/J.java +++ b/tests/explicit-nulls/unsafe-common/unsafe-java-call/J.java @@ -10,4 +10,8 @@ public int f2() { public T g1() { return null; } +} + +class J2 { + public T x = null; } \ No newline at end of file diff --git a/tests/explicit-nulls/unsafe-common/unsafe-java-call/S.scala b/tests/explicit-nulls/unsafe-common/unsafe-java-call/S.scala index 431f479846f2..3b5108bacfa9 100644 --- a/tests/explicit-nulls/unsafe-common/unsafe-java-call/S.scala +++ b/tests/explicit-nulls/unsafe-common/unsafe-java-call/S.scala @@ -30,4 +30,8 @@ def clo1[T]: T = j.g1[T]() // error def clo2[T <: AnyRef]: T = j.g1[T | Null]() // error -def clo3[T >: Null <: AnyRef | Null]: T = j.g1[T]() \ No newline at end of file +def clo3[T >: Null <: AnyRef | Null]: T = j.g1[T]() + +def testJ2[T]: T = + val j2: J2[T] = new J2 + j2.x // error