diff --git a/nullaway/src/main/java/com/uber/nullaway/generics/GenericsChecks.java b/nullaway/src/main/java/com/uber/nullaway/generics/GenericsChecks.java index 2e397298ab..6f6cb10bac 100644 --- a/nullaway/src/main/java/com/uber/nullaway/generics/GenericsChecks.java +++ b/nullaway/src/main/java/com/uber/nullaway/generics/GenericsChecks.java @@ -729,7 +729,14 @@ private MethodInferenceResult runInferenceForCall( methodSymbol, invocationTree, allInvocations); - typeVarNullability = solver.solve(); + typeVarNullability = new HashMap<>(solver.solve()); + // The solver only computes a solution for variables that appear in constraints. For + // unconstrained variables, treat them as NONNULL, consistent with solver behavior for + // unconstrained variables that do appear in the constraint graph. + for (int i = 0; i < methodSymbol.getTypeParameters().size(); i++) { + Symbol.TypeVariableSymbol typeVar = methodSymbol.getTypeParameters().get(i); + typeVarNullability.putIfAbsent(typeVar, ConstraintSolver.InferredNullability.NONNULL); + } // Store inferred types for lambda arguments new InvocationArguments(invocationTree, methodSymbol.type.asMethodType()) diff --git a/nullaway/src/test/java/com/uber/nullaway/jspecify/GenericMethodTests.java b/nullaway/src/test/java/com/uber/nullaway/jspecify/GenericMethodTests.java index d53ab579bb..1ac0bdb378 100644 --- a/nullaway/src/test/java/com/uber/nullaway/jspecify/GenericMethodTests.java +++ b/nullaway/src/test/java/com/uber/nullaway/jspecify/GenericMethodTests.java @@ -1528,6 +1528,45 @@ public static T notNull(@Nullable T object, String message) { .doTest(); } + @Test + public void issue1453() { + makeHelper() + .addSourceLines( + "NullUtil.java", + """ + package com.uber; + import org.jspecify.annotations.NullMarked; + import org.jspecify.annotations.Nullable; + @NullMarked + public class NullUtil { + @SuppressWarnings("NullAway") + public static T assumeNonNull(@Nullable T object) { + return object; + } + } + """) + .addSourceLines( + "Test.java", + """ + package com.uber; + import java.util.List; + import org.jspecify.annotations.NullMarked; + import org.jspecify.annotations.Nullable; + import static com.uber.NullUtil.assumeNonNull; + import java.util.concurrent.atomic.AtomicReference; + @NullMarked + class Test { + private final AtomicReference<@Nullable List> ref = new AtomicReference<>(); + void test() { + for (String s: assumeNonNull(ref.get())) { + System.out.println(s); + } + } + } + """) + .doTest(); + } + private CompilationTestHelper makeHelper() { return makeTestHelperWithArgs( JSpecifyJavacConfig.withJSpecifyModeArgs(