Skip to content

Strip Nulls from Java members when unsafeNulls is enabled #13337

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Oct 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 | _: Select 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)
Expand Down
17 changes: 17 additions & 0 deletions tests/explicit-nulls/unsafe-common/unsafe-java-call/J.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
public class J {
public String f1() {
return "";
}

public int f2() {
return 0;
}

public <T> T g1() {
return null;
}
}

class J2<T> {
public T x = null;
}
37 changes: 37 additions & 0 deletions tests/explicit-nulls/unsafe-common/unsafe-java-call/S.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Check Java calls have been cast to non-nullable.

val j: J = new J

val s1: String = j.f1() // error

val s1n: String | Null = j.f1()

val i1: Int = j.f2()

val s2: String = j.g1[String]() // error

val s2n: String | Null = j.g1[String]()

val s3: String = j.g1[String | Null]() // error

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]() // error

val n1: Null = 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 clo3[T >: Null <: AnyRef | Null]: T = j.g1[T]()

def testJ2[T]: T =
val j2: J2[T] = new J2
j2.x // error