Fix isNullable / isNonNullable, expand tests.

This addresses the issue in a previous CL.
https://dart-review.googlesource.com/c/sdk/+/106620/3/tests/language_2/nnbd/static_errors/equals_parameter_made_nullable_at_invoke_test.dart#30

Change-Id: Ib510ddbfe42c8e6d7cb0c4793a30e050b7e56bd0
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/106962
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Leaf Petersen <leafp@google.com>
diff --git a/pkg/analyzer/lib/src/generated/type_system.dart b/pkg/analyzer/lib/src/generated/type_system.dart
index 879f4e7..59dedf3 100644
--- a/pkg/analyzer/lib/src/generated/type_system.dart
+++ b/pkg/analyzer/lib/src/generated/type_system.dart
@@ -2112,11 +2112,11 @@
   bool isNonNullable(DartType type) {
     if (type.isDynamic || type.isVoid || type.isDartCoreNull) {
       return false;
-    } else if (type.isDartAsyncFutureOr) {
-      isNonNullable((type as InterfaceType).typeArguments[0]);
     } else if ((type as TypeImpl).nullabilitySuffix ==
         NullabilitySuffix.question) {
       return false;
+    } else if (type.isDartAsyncFutureOr) {
+      return isNonNullable((type as InterfaceType).typeArguments[0]);
     } else if (type is TypeParameterType) {
       return isNonNullable(type.bound);
     }
@@ -2127,10 +2127,13 @@
   bool isNullable(DartType type) {
     if (type.isDynamic || type.isVoid || type.isDartCoreNull) {
       return true;
+    } else if ((type as TypeImpl).nullabilitySuffix ==
+        NullabilitySuffix.question) {
+      return true;
     } else if (type.isDartAsyncFutureOr) {
-      isNullable((type as InterfaceType).typeArguments[0]);
+      return isNullable((type as InterfaceType).typeArguments[0]);
     }
-    return (type as TypeImpl).nullabilitySuffix != NullabilitySuffix.none;
+    return false;
   }
 
   /// Check that [f1] is a subtype of [f2] for a member override.
diff --git a/pkg/analyzer/test/generated/type_system_test.dart b/pkg/analyzer/test/generated/type_system_test.dart
index abbf98e..fc17f6d 100644
--- a/pkg/analyzer/test/generated/type_system_test.dart
+++ b/pkg/analyzer/test/generated/type_system_test.dart
@@ -54,6 +54,7 @@
   InterfaceType get intType => typeProvider.intType;
   InterfaceType get iterableType => typeProvider.iterableType;
   InterfaceType get listType => typeProvider.listType;
+  DartType get neverType => typeProvider.neverType;
   DartType get nullType => typeProvider.nullType;
   InterfaceType get numType => typeProvider.numType;
   InterfaceType get objectType => typeProvider.objectType;
@@ -2728,56 +2729,222 @@
 
 @reflectiveTest
 class TypeSystemTest extends AbstractTypeSystemTest {
-  DartType get futureOrWithNoneType =>
-      typeProvider.futureOrType.instantiate([noneType]);
+  DartType get functionClassTypeNone {
+    return InterfaceTypeImpl.explicit(
+      typeProvider.functionType.element,
+      const <DartType>[],
+      nullabilitySuffix: NullabilitySuffix.none,
+    );
+  }
 
-  DartType get futureOrWithQuestionType =>
-      typeProvider.futureOrType.instantiate([questionType]);
+  DartType get functionClassTypeQuestion {
+    return InterfaceTypeImpl.explicit(
+      typeProvider.functionType.element,
+      const <DartType>[],
+      nullabilitySuffix: NullabilitySuffix.question,
+    );
+  }
 
-  DartType get futureOrWithStarType =>
-      typeProvider.futureOrType.instantiate([starType]);
+  DartType get functionClassTypeStar {
+    return InterfaceTypeImpl.explicit(
+      typeProvider.functionType.element,
+      const <DartType>[],
+      nullabilitySuffix: NullabilitySuffix.star,
+    );
+  }
 
   DartType get noneType => (typeProvider.stringType as TypeImpl)
       .withNullability(NullabilitySuffix.none);
 
+  FunctionType get nothingToVoidFunctionTypeNone {
+    return FunctionTypeImpl.synthetic(
+      voidType,
+      const <TypeParameterElement>[],
+      const <ParameterElement>[],
+      nullabilitySuffix: NullabilitySuffix.none,
+    );
+  }
+
+  FunctionType get nothingToVoidFunctionTypeQuestion {
+    return FunctionTypeImpl.synthetic(
+      voidType,
+      const <TypeParameterElement>[],
+      const <ParameterElement>[],
+      nullabilitySuffix: NullabilitySuffix.question,
+    );
+  }
+
+  FunctionType get nothingToVoidFunctionTypeStar {
+    return FunctionTypeImpl.synthetic(
+      voidType,
+      const <TypeParameterElement>[],
+      const <ParameterElement>[],
+      nullabilitySuffix: NullabilitySuffix.star,
+    );
+  }
+
   DartType get questionType => (typeProvider.stringType as TypeImpl)
       .withNullability(NullabilitySuffix.question);
 
   DartType get starType => (typeProvider.stringType as TypeImpl)
       .withNullability(NullabilitySuffix.star);
 
+  DartType futureOrTypeNone({@required DartType argument}) {
+    var element = typeProvider.futureOrType.element;
+    return InterfaceTypeImpl.explicit(
+      element,
+      <DartType>[argument],
+      nullabilitySuffix: NullabilitySuffix.none,
+    );
+  }
+
+  DartType futureOrTypeQuestion({@required DartType argument}) {
+    var element = typeProvider.futureOrType.element;
+    return InterfaceTypeImpl.explicit(
+      element,
+      <DartType>[argument],
+      nullabilitySuffix: NullabilitySuffix.question,
+    );
+  }
+
+  DartType futureOrTypeStar({@required DartType argument}) {
+    var element = typeProvider.futureOrType.element;
+    return InterfaceTypeImpl.explicit(
+      element,
+      <DartType>[argument],
+      nullabilitySuffix: NullabilitySuffix.star,
+    );
+  }
+
   test_isNonNullable_dynamic() {
     expect(typeSystem.isNonNullable(dynamicType), false);
   }
 
-  test_isNonNullable_futureOr_noneArg() {
-    expect(typeSystem.isNonNullable(futureOrWithNoneType), true);
+  test_isNonNullable_function_none() {
+    expect(typeSystem.isNonNullable(nothingToVoidFunctionTypeNone), true);
   }
 
-  test_isNonNullable_futureOr_questionArg() {
-    expect(typeSystem.isNonNullable(futureOrWithQuestionType), true);
+  test_isNonNullable_function_question() {
+    expect(typeSystem.isNonNullable(nothingToVoidFunctionTypeQuestion), false);
   }
 
-  test_isNonNullable_futureOr_starArg() {
-    expect(typeSystem.isNonNullable(futureOrWithStarType), true);
+  test_isNonNullable_function_star() {
+    expect(typeSystem.isNonNullable(nothingToVoidFunctionTypeStar), true);
   }
 
-  test_isNonNullable_none() {
+  test_isNonNullable_functionClass_none() {
+    expect(typeSystem.isNonNullable(functionClassTypeNone), true);
+  }
+
+  test_isNonNullable_functionClass_question() {
+    expect(typeSystem.isNonNullable(functionClassTypeQuestion), false);
+  }
+
+  test_isNonNullable_functionClass_star() {
+    expect(typeSystem.isNonNullable(functionClassTypeStar), true);
+  }
+
+  test_isNonNullable_futureOr_noneArgument_none() {
+    expect(
+      typeSystem.isNonNullable(
+        futureOrTypeNone(argument: noneType),
+      ),
+      true,
+    );
+  }
+
+  test_isNonNullable_futureOr_noneArgument_question() {
+    expect(
+      typeSystem.isNonNullable(
+        futureOrTypeQuestion(argument: noneType),
+      ),
+      false,
+    );
+  }
+
+  test_isNonNullable_futureOr_noneArgument_star() {
+    expect(
+      typeSystem.isNonNullable(
+        futureOrTypeStar(argument: noneType),
+      ),
+      true,
+    );
+  }
+
+  test_isNonNullable_futureOr_questionArgument_none() {
+    expect(
+      typeSystem.isNonNullable(
+        futureOrTypeNone(argument: questionType),
+      ),
+      false,
+    );
+  }
+
+  test_isNonNullable_futureOr_questionArgument_question() {
+    expect(
+      typeSystem.isNonNullable(
+        futureOrTypeQuestion(argument: questionType),
+      ),
+      false,
+    );
+  }
+
+  test_isNonNullable_futureOr_questionArgument_star() {
+    expect(
+      typeSystem.isNonNullable(
+        futureOrTypeStar(argument: questionType),
+      ),
+      false,
+    );
+  }
+
+  test_isNonNullable_futureOr_starArgument_none() {
+    expect(
+      typeSystem.isNonNullable(
+        futureOrTypeNone(argument: starType),
+      ),
+      true,
+    );
+  }
+
+  test_isNonNullable_futureOr_starArgument_question() {
+    expect(
+      typeSystem.isNonNullable(
+        futureOrTypeStar(argument: questionType),
+      ),
+      false,
+    );
+  }
+
+  test_isNonNullable_futureOr_starArgument_star() {
+    expect(
+      typeSystem.isNonNullable(
+        futureOrTypeStar(argument: starType),
+      ),
+      true,
+    );
+  }
+
+  test_isNonNullable_interface_none() {
     expect(typeSystem.isNonNullable(noneType), true);
   }
 
+  test_isNonNullable_interface_question() {
+    expect(typeSystem.isNonNullable(questionType), false);
+  }
+
+  test_isNonNullable_interface_star() {
+    expect(typeSystem.isNonNullable(starType), true);
+  }
+
+  test_isNonNullable_never() {
+    expect(typeSystem.isNonNullable(neverType), true);
+  }
+
   test_isNonNullable_null() {
     expect(typeSystem.isNonNullable(nullType), false);
   }
 
-  test_isNonNullable_question() {
-    expect(typeSystem.isNonNullable(questionType), false);
-  }
-
-  test_isNonNullable_star() {
-    expect(typeSystem.isNonNullable(starType), true);
-  }
-
   test_isNonNullable_typeParameter_noneBound_none() {
     expect(
       typeSystem.isNonNullable(
@@ -2831,34 +2998,131 @@
     expect(typeSystem.isNullable(dynamicType), true);
   }
 
-  test_isNullable_futureOr_noneArg() {
-    expect(typeSystem.isNullable(futureOrWithNoneType), true);
+  test_isNullable_function_none() {
+    expect(typeSystem.isNullable(nothingToVoidFunctionTypeNone), false);
   }
 
-  test_isNullable_futureOr_questionArg() {
-    expect(typeSystem.isNullable(futureOrWithQuestionType), true);
+  test_isNullable_function_question() {
+    expect(typeSystem.isNullable(nothingToVoidFunctionTypeQuestion), true);
   }
 
-  test_isNullable_futureOr_starArg() {
-    expect(typeSystem.isNullable(futureOrWithStarType), true);
+  test_isNullable_function_star() {
+    expect(typeSystem.isNullable(nothingToVoidFunctionTypeStar), false);
   }
 
-  test_isNullable_none() {
+  test_isNullable_functionClass_none() {
+    expect(typeSystem.isNullable(functionClassTypeNone), false);
+  }
+
+  test_isNullable_functionClass_question() {
+    expect(typeSystem.isNullable(functionClassTypeQuestion), true);
+  }
+
+  test_isNullable_functionClass_star() {
+    expect(typeSystem.isNullable(functionClassTypeStar), false);
+  }
+
+  test_isNullable_futureOr_noneArgument_none() {
+    expect(
+      typeSystem.isNullable(
+        futureOrTypeNone(argument: noneType),
+      ),
+      false,
+    );
+  }
+
+  test_isNullable_futureOr_noneArgument_question() {
+    expect(
+      typeSystem.isNullable(
+        futureOrTypeQuestion(argument: noneType),
+      ),
+      true,
+    );
+  }
+
+  test_isNullable_futureOr_noneArgument_star() {
+    expect(
+      typeSystem.isNullable(
+        futureOrTypeStar(argument: noneType),
+      ),
+      false,
+    );
+  }
+
+  test_isNullable_futureOr_questionArgument_none() {
+    expect(
+      typeSystem.isNullable(
+        futureOrTypeNone(argument: questionType),
+      ),
+      true,
+    );
+  }
+
+  test_isNullable_futureOr_questionArgument_question() {
+    expect(
+      typeSystem.isNullable(
+        futureOrTypeQuestion(argument: questionType),
+      ),
+      true,
+    );
+  }
+
+  test_isNullable_futureOr_questionArgument_star() {
+    expect(
+      typeSystem.isNullable(
+        futureOrTypeStar(argument: questionType),
+      ),
+      true,
+    );
+  }
+
+  test_isNullable_futureOr_starArgument_none() {
+    expect(
+      typeSystem.isNullable(
+        futureOrTypeNone(argument: starType),
+      ),
+      false,
+    );
+  }
+
+  test_isNullable_futureOr_starArgument_question() {
+    expect(
+      typeSystem.isNullable(
+        futureOrTypeQuestion(argument: starType),
+      ),
+      true,
+    );
+  }
+
+  test_isNullable_futureOr_starArgument_star() {
+    expect(
+      typeSystem.isNullable(
+        futureOrTypeStar(argument: starType),
+      ),
+      false,
+    );
+  }
+
+  test_isNullable_interface_none() {
     expect(typeSystem.isNullable(noneType), false);
   }
 
+  test_isNullable_interface_question() {
+    expect(typeSystem.isNullable(questionType), true);
+  }
+
+  test_isNullable_interface_star() {
+    expect(typeSystem.isNullable(starType), false);
+  }
+
+  test_isNullable_never() {
+    expect(typeSystem.isNullable(neverType), false);
+  }
+
   test_isNullable_null() {
     expect(typeSystem.isNullable(nullType), true);
   }
 
-  test_isNullable_question() {
-    expect(typeSystem.isNullable(questionType), true);
-  }
-
-  test_isNullable_star() {
-    expect(typeSystem.isNullable(starType), true);
-  }
-
   test_isNullable_typeParameter_noneBound_none() {
     expect(
       typeSystem.isNullable(
@@ -2900,7 +3164,7 @@
       typeSystem.isNullable(
         typeParameterTypeStar(bound: starType),
       ),
-      true,
+      false,
     );
   }
 
@@ -2912,17 +3176,31 @@
     expect(typeSystem.isPotentiallyNonNullable(dynamicType), false);
   }
 
-  test_isPotentiallyNonNullable_futureOr_noneArg() {
-    expect(typeSystem.isPotentiallyNonNullable(futureOrWithNoneType), false);
-  }
-
-  test_isPotentiallyNonNullable_futureOr_questionArg() {
+  test_isPotentiallyNonNullable_futureOr_noneArgument_none() {
     expect(
-        typeSystem.isPotentiallyNonNullable(futureOrWithQuestionType), false);
+      typeSystem.isPotentiallyNonNullable(
+        futureOrTypeNone(argument: noneType),
+      ),
+      true,
+    );
   }
 
-  test_isPotentiallyNonNullable_futureOr_starArg() {
-    expect(typeSystem.isPotentiallyNonNullable(futureOrWithStarType), false);
+  test_isPotentiallyNonNullable_futureOr_questionArgument_none() {
+    expect(
+      typeSystem.isPotentiallyNonNullable(
+        futureOrTypeNone(argument: questionType),
+      ),
+      false,
+    );
+  }
+
+  test_isPotentiallyNonNullable_futureOr_starArgument_none() {
+    expect(
+      typeSystem.isPotentiallyNonNullable(
+        futureOrTypeNone(argument: starType),
+      ),
+      true,
+    );
   }
 
   test_isPotentiallyNonNullable_none() {
@@ -2938,7 +3216,7 @@
   }
 
   test_isPotentiallyNonNullable_star() {
-    expect(typeSystem.isPotentiallyNonNullable(starType), false);
+    expect(typeSystem.isPotentiallyNonNullable(starType), true);
   }
 
   test_isPotentiallyNonNullable_void() {
@@ -2949,16 +3227,31 @@
     expect(typeSystem.isPotentiallyNullable(dynamicType), true);
   }
 
-  test_isPotentiallyNullable_futureOr_noneArg() {
-    expect(typeSystem.isPotentiallyNullable(futureOrWithNoneType), false);
+  test_isPotentiallyNullable_futureOr_noneArgument_none() {
+    expect(
+      typeSystem.isPotentiallyNullable(
+        futureOrTypeNone(argument: noneType),
+      ),
+      false,
+    );
   }
 
-  test_isPotentiallyNullable_futureOr_questionArg() {
-    expect(typeSystem.isPotentiallyNullable(futureOrWithQuestionType), false);
+  test_isPotentiallyNullable_futureOr_questionArgument_none() {
+    expect(
+      typeSystem.isPotentiallyNullable(
+        futureOrTypeNone(argument: questionType),
+      ),
+      true,
+    );
   }
 
-  test_isPotentiallyNullable_futureOr_starArg() {
-    expect(typeSystem.isPotentiallyNullable(futureOrWithStarType), false);
+  test_isPotentiallyNullable_futureOr_starArgument_none() {
+    expect(
+      typeSystem.isPotentiallyNullable(
+        futureOrTypeNone(argument: starType),
+      ),
+      false,
+    );
   }
 
   test_isPotentiallyNullable_none() {
@@ -2985,23 +3278,29 @@
     expect(bound, isNotNull);
     var element = TypeParameterElementImpl.synthetic('T');
     element.bound = bound;
-    return TypeParameterTypeImpl(element,
-        nullabilitySuffix: NullabilitySuffix.none);
+    return TypeParameterTypeImpl(
+      element,
+      nullabilitySuffix: NullabilitySuffix.none,
+    );
   }
 
   DartType typeParameterTypeQuestion({@required DartType bound}) {
     expect(bound, isNotNull);
     var element = TypeParameterElementImpl.synthetic('T');
     element.bound = bound;
-    return TypeParameterTypeImpl(element,
-        nullabilitySuffix: NullabilitySuffix.question);
+    return TypeParameterTypeImpl(
+      element,
+      nullabilitySuffix: NullabilitySuffix.question,
+    );
   }
 
   DartType typeParameterTypeStar({@required DartType bound}) {
     expect(bound, isNotNull);
     var element = TypeParameterElementImpl.synthetic('T');
     element.bound = bound;
-    return TypeParameterTypeImpl(element,
-        nullabilitySuffix: NullabilitySuffix.star);
+    return TypeParameterTypeImpl(
+      element,
+      nullabilitySuffix: NullabilitySuffix.star,
+    );
   }
 }
diff --git a/pkg/analyzer/test/src/diagnostics/not_initialized_non_nullable_top_level_variable_test.dart b/pkg/analyzer/test/src/diagnostics/not_initialized_non_nullable_top_level_variable_test.dart
index 9399e70..218e4ef 100644
--- a/pkg/analyzer/test/src/diagnostics/not_initialized_non_nullable_top_level_variable_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/not_initialized_non_nullable_top_level_variable_test.dart
@@ -22,6 +22,14 @@
   AnalysisOptionsImpl get analysisOptions =>
       AnalysisOptionsImpl()..enabledExperiments = [EnableString.non_nullable];
 
+  test_futureOr_questionArgument_none() async {
+    assertNoErrorsInCode('''
+import 'dart:async';
+
+FutureOr<int?> v;
+''');
+  }
+
   test_hasInitializer() async {
     assertNoErrorsInCode('''
 int v = 0;
diff --git a/pkg/analyzer/test/src/diagnostics/not_initialized_potentially_non_nullable_local_variable_test.dart b/pkg/analyzer/test/src/diagnostics/not_initialized_potentially_non_nullable_local_variable_test.dart
index fb5d0d0..5a63b51 100644
--- a/pkg/analyzer/test/src/diagnostics/not_initialized_potentially_non_nullable_local_variable_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/not_initialized_potentially_non_nullable_local_variable_test.dart
@@ -74,6 +74,16 @@
 ''');
   }
 
+  test_futureOr_questionArgument_none() async {
+    assertNoErrorsInCode('''
+import 'dart:async';
+
+f() {
+  FutureOr<int?> v;
+}
+''');
+  }
+
   test_hasInitializer() async {
     assertNoErrorsInCode('''
 f() {
diff --git a/tests/language_2/nnbd/static_errors/equals_parameter_made_nullable_at_invoke_test.dart b/tests/language_2/nnbd/static_errors/equals_parameter_made_nullable_at_invoke_test.dart
index 9757f79..2d6c7a6 100644
--- a/tests/language_2/nnbd/static_errors/equals_parameter_made_nullable_at_invoke_test.dart
+++ b/tests/language_2/nnbd/static_errors/equals_parameter_made_nullable_at_invoke_test.dart
@@ -27,7 +27,7 @@
   // Caveat: it is NOT that the argument is promoted to non-null. Otherwise,
   // types which we can't cleanly promote, such as FutureOr<int?>, would not be
   // assignable in comparisons.
-  FutureOr<int?> foInt = Future.value(0);
+  FutureOr<int?> foInt;
 
   // Valid comparison.
   o == foInt;