6161/** Methods for performing checks related to generic types and nullability. */
6262public final class GenericsChecks {
6363
64+ /** Marker interface for results of attempting to infer nullability of type variables at a call */
65+ private interface MethodInferenceResult {}
66+
67+ /**
68+ * Indicates successful inference of nullability of type variables at a call. Stores the inferred
69+ * type variable nullability.
70+ */
71+ private static final class InferenceSuccess implements MethodInferenceResult {
72+ final Map <Element , ConstraintSolver .InferredNullability > typeVarNullability ;
73+
74+ InferenceSuccess (Map <Element , ConstraintSolver .InferredNullability > typeVarNullability ) {
75+ this .typeVarNullability = typeVarNullability ;
76+ }
77+ }
78+
79+ /** Indicates failed inference of nullability of type variables at a call */
80+ private static final class InferenceFailure implements MethodInferenceResult {
81+ @ SuppressWarnings ("UnusedVariable" ) // keep this as it may be useful in the future
82+ final @ Nullable String errorMessage ;
83+
84+ InferenceFailure (@ Nullable String errorMessage ) {
85+ this .errorMessage = errorMessage ;
86+ }
87+ }
88+
6489 /**
65- * Maps a Tree representing a call to a generic method or constructor to the inferred nullability
66- * of its type arguments. The call must not have any explicit type arguments.
90+ * Maps a Tree representing a call to a generic method or constructor to the result of inferring
91+ * its type argument nullability. The call must not have any explicit type arguments. If a tree is
92+ * not present as a key in this map, it means inference has not yet been attempted for that call.
6793 */
68- private final Map <MethodInvocationTree , Map < Element , ConstraintSolver . InferredNullability > >
94+ private final Map <MethodInvocationTree , MethodInferenceResult >
6995 inferredTypeVarNullabilityForGenericCalls = new LinkedHashMap <>();
7096
7197 private final NullAway analysis ;
@@ -496,9 +522,11 @@ private Type inferGenericMethodCallType(
496522 Verify .verify (isGenericCallNeedingInference (invocationTree ));
497523 Symbol .MethodSymbol methodSymbol = ASTHelpers .getSymbol (invocationTree );
498524 Type type = methodSymbol .type ;
499- Map <Element , ConstraintSolver .InferredNullability > typeVarNullability =
500- inferredTypeVarNullabilityForGenericCalls .get (invocationTree );
501- if (typeVarNullability == null ) {
525+ Map <Element , ConstraintSolver .InferredNullability > typeVarNullability = null ;
526+ MethodInferenceResult result = inferredTypeVarNullabilityForGenericCalls .get (invocationTree );
527+ if (result instanceof InferenceSuccess ) {
528+ typeVarNullability = ((InferenceSuccess ) result ).typeVarNullability ;
529+ } else if (result == null ) { // have not yet attempted inference for this call
502530 // generic method call with no explicit generic arguments
503531 // update inferred type arguments based on the assignment context
504532 ConstraintSolver solver = makeSolver (state , analysis );
@@ -516,7 +544,8 @@ private Type inferGenericMethodCallType(
516544 allInvocations );
517545 typeVarNullability = solver .solve ();
518546 for (MethodInvocationTree invTree : allInvocations ) {
519- inferredTypeVarNullabilityForGenericCalls .put (invTree , typeVarNullability );
547+ inferredTypeVarNullabilityForGenericCalls .put (
548+ invTree , new InferenceSuccess (typeVarNullability ));
520549 }
521550 } catch (UnsatisfiableConstraintsException e ) {
522551 if (config .warnOnGenericInferenceFailure ()) {
@@ -531,6 +560,10 @@ private Type inferGenericMethodCallType(
531560 errorBuilder .createErrorDescription (
532561 errorMessage , analysis .buildDescription (invocationTree ), state , null ));
533562 }
563+ for (MethodInvocationTree invTree : allInvocations ) {
564+ inferredTypeVarNullabilityForGenericCalls .put (
565+ invTree , new InferenceFailure (e .getMessage ()));
566+ }
534567 }
535568 }
536569 // we get the return type of the method call with inferred nullability of type variables
@@ -1127,11 +1160,11 @@ private Type substituteTypeArgsInGenericMethodType(
11271160 com .sun .tools .javac .util .List <Type > explicitTypeArgs = convertTreesToTypes (typeArgumentTrees );
11281161
11291162 // There are no explicit type arguments, so use the inferred types
1130- if (explicitTypeArgs .isEmpty ()) {
1131- if ( inferredTypeVarNullabilityForGenericCalls .containsKey (tree )
1132- && tree instanceof MethodInvocationTree ) {
1163+ if (explicitTypeArgs .isEmpty () && tree instanceof MethodInvocationTree ) {
1164+ MethodInferenceResult result = inferredTypeVarNullabilityForGenericCalls .get (tree );
1165+ if ( result instanceof InferenceSuccess ) {
11331166 return getTypeWithInferredNullability (
1134- state , methodType , inferredTypeVarNullabilityForGenericCalls . get ( tree ) );
1167+ state , methodType , (( InferenceSuccess ) result ). typeVarNullability );
11351168 }
11361169 }
11371170 return TypeSubstitutionUtils .subst (
0 commit comments