Skip to content
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

Strip Nulls from Java members when unsafeNulls is enabled #13337

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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 9 additions & 0 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
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
@@ -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
@@ -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