Add language tests for "why not promoted" functionality.

These tests just cover the CFE functionality.  Once
https://github.com/dart-lang/sdk/issues/44905 is addressed, I'll add
test expectations for the analyzer.

Note: these tests uncovered two unreelated bugs: #45551 and #45552.

Bug: https://github.com/dart-lang/sdk/issues/44897
Change-Id: I465b157afc2cc15bcc5ce083aaa74614313a38a6
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/193581
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Leaf Petersen <leafp@google.com>
Reviewed-by: Bob Nystrom <rnystrom@google.com>
diff --git a/tests/language/why_not_promoted/argument_type_not_assignable_nullability_error_test.dart b/tests/language/why_not_promoted/argument_type_not_assignable_nullability_error_test.dart
new file mode 100644
index 0000000..cfde735
--- /dev/null
+++ b/tests/language/why_not_promoted/argument_type_not_assignable_nullability_error_test.dart
@@ -0,0 +1,593 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This test contains a test case for each condition that can lead to the front
+// end's `ArgumentTypeNotAssignableNullability` error, for which we wish to
+// report "why not promoted" context information.
+
+class C1 {
+  int? bad;
+  //   ^
+  // [context 1] 'bad' refers to a property so it couldn't be promoted.
+  f(int i) {}
+}
+
+required_unnamed(C1 c) {
+  if (c.bad == null) return;
+  c.f(c.bad);
+  //  ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
+  //    ^
+  // [cfe 1] The argument type 'int?' can't be assigned to the parameter type 'int' because 'int?' is nullable and 'int' isn't.
+}
+
+class C2 {
+  int? bad;
+  //   ^
+  // [context 2] 'bad' refers to a property so it couldn't be promoted.
+  f([int i = 0]) {}
+}
+
+optional_unnamed(C2 c) {
+  if (c.bad == null) return;
+  c.f(c.bad);
+  //  ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
+  //    ^
+  // [cfe 2] The argument type 'int?' can't be assigned to the parameter type 'int' because 'int?' is nullable and 'int' isn't.
+}
+
+class C3 {
+  int? bad;
+  //   ^
+  // [context 3] 'bad' refers to a property so it couldn't be promoted.
+  f({required int i}) {}
+}
+
+required_named(C3 c) {
+  if (c.bad == null) return;
+  c.f(i: c.bad);
+  //  ^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
+  //       ^
+  // [cfe 3] The argument type 'int?' can't be assigned to the parameter type 'int' because 'int?' is nullable and 'int' isn't.
+}
+
+class C4 {
+  int? bad;
+  //   ^
+  // [context 4] 'bad' refers to a property so it couldn't be promoted.
+  f({int i = 0}) {}
+}
+
+optional_named(C4 c) {
+  if (c.bad == null) return;
+  c.f(i: c.bad);
+  //  ^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
+  //       ^
+  // [cfe 4] The argument type 'int?' can't be assigned to the parameter type 'int' because 'int?' is nullable and 'int' isn't.
+}
+
+class C5 {
+  List<int>? bad;
+  //         ^
+  // [context 5] 'bad' refers to a property so it couldn't be promoted.
+  f<T>(List<T> x) {}
+}
+
+type_inferred(C5 c) {
+  if (c.bad == null) return;
+  c.f(c.bad);
+  //  ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
+  //    ^
+  // [cfe 5] The argument type 'List<int>?' can't be assigned to the parameter type 'List<int>' because 'List<int>?' is nullable and 'List<int>' isn't.
+}
+
+class C6 {
+  int? bad;
+  //   ^
+  // [context 6] 'bad' refers to a property so it couldn't be promoted.
+  C6(int i);
+}
+
+C6? constructor_with_implicit_new(C6 c) {
+  if (c.bad == null) return null;
+  return C6(c.bad);
+  //        ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
+  //          ^
+  // [cfe 6] The argument type 'int?' can't be assigned to the parameter type 'int' because 'int?' is nullable and 'int' isn't.
+}
+
+class C7 {
+  int? bad;
+  //   ^
+  // [context 7] 'bad' refers to a property so it couldn't be promoted.
+  C7(int i);
+}
+
+C7? constructor_with_explicit_new(C7 c) {
+  if (c.bad == null) return null;
+  return new C7(c.bad);
+  //            ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
+  //              ^
+  // [cfe 7] The argument type 'int?' can't be assigned to the parameter type 'int' because 'int?' is nullable and 'int' isn't.
+}
+
+class C8 {
+  int? bad;
+  //   ^
+  // [context 8] 'bad' refers to a property so it couldn't be promoted.
+}
+
+userDefinableBinaryOpRhs(C8 c) {
+  if (c.bad == null) return;
+  1 + c.bad;
+  //  ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
+  //    ^
+  // [cfe 8] A value of type 'int?' can't be assigned to a variable of type 'num' because 'int?' is nullable and 'num' isn't.
+}
+
+class C9 {
+  int? bad;
+  f(int i) {}
+}
+
+questionQuestionRhs(C9 c, int? i) {
+  // Note: "why not supported" functionality is currently not supported for the
+  // RHS of `??` because it requires more clever reasoning than we currently do:
+  // we would have to understand that the reason `i ?? c.bad` has a type of
+  // `int?` rather than `int` is because `c.bad` was not promoted.  We currently
+  // only support detecting non-promotion when the expression that had the wrong
+  // type *is* the expression that wasn't promoted.
+  if (c.bad == null) return;
+  c.f(i ?? c.bad);
+  //  ^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
+  //    ^
+  // [cfe] The argument type 'int?' can't be assigned to the parameter type 'int' because 'int?' is nullable and 'int' isn't.
+}
+
+class C10 {
+  D10? bad;
+  f(bool b) {}
+}
+
+class D10 {
+  bool operator ==(covariant D10 other) => true;
+}
+
+equalRhs(C10 c, D10 d) {
+  if (c.bad == null) return;
+  // Note: we don't report an error here because `==` always accepts `null`.
+  c.f(d == c.bad);
+  c.f(d != c.bad);
+}
+
+class C11 {
+  bool? bad;
+  //    ^
+  // [context 9] 'bad' refers to a property so it couldn't be promoted.
+  // [context 10] 'bad' refers to a property so it couldn't be promoted.
+  f(bool b) {}
+}
+
+andOperand(C11 c, bool b) {
+  if (c.bad == null) return;
+  c.f(c.bad && b);
+  //  ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //    ^
+  // [cfe 9] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
+  c.f(b && c.bad);
+  //       ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //         ^
+  // [cfe 10] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
+}
+
+class C12 {
+  bool? bad;
+  //    ^
+  // [context 11] 'bad' refers to a property so it couldn't be promoted.
+  // [context 12] 'bad' refers to a property so it couldn't be promoted.
+  f(bool b) {}
+}
+
+orOperand(C12 c, bool b) {
+  if (c.bad == null) return;
+  c.f(c.bad || b);
+  //  ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //    ^
+  // [cfe 11] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
+  c.f(b || c.bad);
+  //       ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //         ^
+  // [cfe 12] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
+}
+
+class C13 {
+  bool? bad;
+  //    ^
+  // [context 13] 'bad' refers to a property so it couldn't be promoted.
+}
+
+assertStatementCondition(C13 c) {
+  if (c.bad == null) return;
+  assert(c.bad);
+  //     ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //       ^
+  // [cfe 13] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
+}
+
+class C14 {
+  bool? bad;
+  //    ^
+  // [context 14] 'bad' refers to a property so it couldn't be promoted.
+  C14.assertInitializerCondition(C14 c)
+      : bad = c.bad!,
+        assert(c.bad);
+        //     ^^^^^
+        // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+        //       ^
+        // [cfe 14] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
+}
+
+class C15 {
+  bool? bad;
+  //    ^
+  // [context 15] 'bad' refers to a property so it couldn't be promoted.
+  f(bool b) {}
+}
+
+notOperand(C15 c) {
+  if (c.bad == null) return;
+  c.f(!c.bad);
+  //   ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //     ^
+  // [cfe 15] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
+}
+
+class C16 {
+  bool? bad;
+  //    ^
+  // [context 16] 'bad' refers to a property so it couldn't be promoted.
+  // [context 17] 'bad' refers to a property so it couldn't be promoted.
+  // [context 18] 'bad' refers to a property so it couldn't be promoted.
+  // [context 19] 'bad' refers to a property so it couldn't be promoted.
+}
+
+forLoopCondition(C16 c) {
+  if (c.bad == null) return;
+  for (; c.bad;) {}
+  //     ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //       ^
+  // [cfe 16] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
+  [for (; c.bad;) null];
+  //      ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //        ^
+  // [cfe 17] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
+  ({for (; c.bad;) null});
+  //       ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //         ^
+  // [cfe 18] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
+  ({for (; c.bad;) null: null});
+  //       ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //         ^
+  // [cfe 19] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
+}
+
+class C17 {
+  bool? bad;
+  //    ^
+  // [context 20] 'bad' refers to a property so it couldn't be promoted.
+  f(int i) {}
+}
+
+conditionalExpressionCondition(C17 c) {
+  if (c.bad == null) return;
+  c.f(c.bad ? 1 : 2);
+  //  ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //    ^
+  // [cfe 20] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
+}
+
+class C18 {
+  bool? bad;
+  //    ^
+  // [context 21] 'bad' refers to a property so it couldn't be promoted.
+}
+
+doLoopCondition(C18 c) {
+  if (c.bad == null) return;
+  do {} while (c.bad);
+  //           ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //             ^
+  // [cfe 21] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
+}
+
+class C19 {
+  bool? bad;
+  //    ^
+  // [context 22] 'bad' refers to a property so it couldn't be promoted.
+  // [context 23] 'bad' refers to a property so it couldn't be promoted.
+  // [context 24] 'bad' refers to a property so it couldn't be promoted.
+  // [context 25] 'bad' refers to a property so it couldn't be promoted.
+}
+
+ifCondition(C19 c) {
+  if (c.bad == null) return;
+  if (c.bad) {}
+  //  ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //    ^
+  // [cfe 22] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
+  [if (c.bad) null];
+  //   ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //     ^
+  // [cfe 23] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
+  ({if (c.bad) null});
+  //    ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //      ^
+  // [cfe 24] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
+  ({if (c.bad) null: null});
+  //    ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //      ^
+  // [cfe 25] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
+}
+
+class C20 {
+  bool? bad;
+  //    ^
+  // [context 26] 'bad' refers to a property so it couldn't be promoted.
+}
+
+whileCondition(C20 c) {
+  if (c.bad == null) return;
+  while (c.bad) {}
+  //     ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //       ^
+  // [cfe 26] A value of type 'bool?' can't be assigned to a variable of type 'bool' because 'bool?' is nullable and 'bool' isn't.
+}
+
+class C21 {
+  int? bad;
+  //   ^
+  // [context 27] 'bad' refers to a property so it couldn't be promoted.
+}
+
+assignmentRhs(C21 c, int i) {
+  if (c.bad == null) return;
+  i = c.bad;
+  //  ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
+  //    ^
+  // [cfe 27] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
+}
+
+class C22 {
+  int? bad;
+  //   ^
+  // [context 28] 'bad' refers to a property so it couldn't be promoted.
+}
+
+variableInitializer(C22 c) {
+  if (c.bad == null) return;
+  int i = c.bad;
+  //      ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
+  //        ^
+  // [cfe 28] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
+}
+
+class C23 {
+  int? bad;
+  //   ^
+  // [context 29] 'bad' refers to a property so it couldn't be promoted.
+  final int x;
+  final int y;
+  C23.constructorInitializer(C23 c)
+      : x = c.bad!,
+        y = c.bad;
+        //  ^^^^^
+        // [analyzer] COMPILE_TIME_ERROR.FIELD_INITIALIZER_NOT_ASSIGNABLE
+        //    ^
+        // [cfe 29] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
+}
+
+class C24 {
+  int? bad;
+  //   ^
+  // [context 30] 'bad' refers to a property so it couldn't be promoted.
+  // [context 31] 'bad' refers to a property so it couldn't be promoted.
+  // [context 32] 'bad' refers to a property so it couldn't be promoted.
+  // [context 33] 'bad' refers to a property so it couldn't be promoted.
+}
+
+forVariableInitializer(C24 c) {
+  if (c.bad == null) return;
+  for (int i = c.bad; false;) {}
+  //           ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
+  //             ^
+  // [cfe 30] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
+  [for (int i = c.bad; false;) null];
+  //            ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
+  //              ^
+  // [cfe 31] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
+  ({for (int i = c.bad; false;) null});
+  //             ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
+  //               ^
+  // [cfe 32] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
+  ({for (int i = c.bad; false;) null: null});
+  //             ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
+  //               ^
+  // [cfe 33] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
+}
+
+class C25 {
+  int? bad;
+  //   ^
+  // [context 34] 'bad' refers to a property so it couldn't be promoted.
+  // [context 35] 'bad' refers to a property so it couldn't be promoted.
+  // [context 36] 'bad' refers to a property so it couldn't be promoted.
+  // [context 37] 'bad' refers to a property so it couldn't be promoted.
+}
+
+forAssignmentInitializer(C25 c, int i) {
+  if (c.bad == null) return;
+  for (i = c.bad; false;) {}
+  //       ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
+  //         ^
+  // [cfe 34] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
+  [for (i = c.bad; false;) null];
+  //        ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
+  //          ^
+  // [cfe 35] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
+  ({for (i = c.bad; false;) null});
+  //         ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
+  //           ^
+  // [cfe 36] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
+  ({for (i = c.bad; false;) null: null});
+  //         ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.INVALID_ASSIGNMENT
+  //           ^
+  // [cfe 37] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
+}
+
+class C26 {
+  int? bad;
+  //   ^
+  // [context 38] 'bad' refers to a property so it couldn't be promoted.
+}
+
+compoundAssignmentRhs(C26 c) {
+  num n = 0;
+  if (c.bad == null) return;
+  n += c.bad;
+  //   ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
+  //     ^
+  // [cfe 38] A value of type 'int?' can't be assigned to a variable of type 'num' because 'int?' is nullable and 'num' isn't.
+}
+
+class C27 {
+  int? bad;
+  //   ^
+  // [context 39] 'bad' refers to a property so it couldn't be promoted.
+}
+
+indexGet(C27 c, List<int> values) {
+  if (c.bad == null) return;
+  values[c.bad];
+  //     ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
+  //       ^
+  // [cfe 39] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
+}
+
+class C28 {
+  int? bad;
+  //   ^
+  // [context 40] 'bad' refers to a property so it couldn't be promoted.
+}
+
+indexSet(C28 c, List<int> values) {
+  if (c.bad == null) return;
+  values[c.bad] = 0;
+  //     ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
+  //       ^
+  // [cfe 40] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
+}
+
+class C29 {
+  int? bad;
+}
+
+indexSetCompound(C29 c, List<int> values) {
+  // TODO(paulberry): get this to work with the CFE
+  if (c.bad == null) return;
+  values[c.bad] += 1;
+  //     ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
+  //       ^
+  // [cfe] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
+}
+
+class C30 {
+  int? bad;
+}
+
+indexSetIfNull(C30 c, List<int?> values) {
+  // TODO(paulberry): get this to work with the CFE
+  if (c.bad == null) return;
+  values[c.bad] ??= 1;
+  //     ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
+  //       ^
+  // [cfe] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
+}
+
+class C31 {
+  int? bad;
+}
+
+indexSetPreIncDec(C31 c, List<int> values) {
+  // TODO(paulberry): get this to work with the CFE
+  if (c.bad == null) return;
+  ++values[c.bad];
+  //       ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
+  //         ^
+  // [cfe] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
+  --values[c.bad];
+  //       ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
+  //         ^
+  // [cfe] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
+}
+
+class C32 {
+  int? bad;
+}
+
+indexSetPostIncDec(C32 c, List<int> values) {
+  // TODO(paulberry): get this to work with the CFE
+  if (c.bad == null) return;
+  values[c.bad]++;
+  //     ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
+  //       ^
+  // [cfe] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
+  values[c.bad]--;
+  //     ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.ARGUMENT_TYPE_NOT_ASSIGNABLE
+  //       ^
+  // [cfe] A value of type 'int?' can't be assigned to a variable of type 'int' because 'int?' is nullable and 'int' isn't.
+}
diff --git a/tests/language/why_not_promoted/assignment_error_test.dart b/tests/language/why_not_promoted/assignment_error_test.dart
new file mode 100644
index 0000000..6f363d8
--- /dev/null
+++ b/tests/language/why_not_promoted/assignment_error_test.dart
@@ -0,0 +1,113 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+abstract class C {
+  C? operator +(int i);
+  int get cProperty => 0;
+}
+
+direct_assignment(int? i, int? j) {
+  if (i == null) return;
+  i = j;
+//^
+// [context 1] Variable 'i' could be null due to an intervening write.
+  i.isEven;
+//^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //^
+  // [cfe 1] Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
+}
+
+compound_assignment(C? c, int i) {
+  if (c == null) return;
+  c += i;
+//^
+// [context 2] Variable 'c' could be null due to an intervening write.
+  c.cProperty;
+//^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //^
+  // [cfe 2] Property 'cProperty' cannot be accessed on 'C?' because it is potentially null.
+}
+
+via_postfix_op(C? c) {
+  if (c == null) return;
+  c++;
+//^
+// [context 3] Variable 'c' could be null due to an intervening write.
+  c.cProperty;
+//^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //^
+  // [cfe 3] Property 'cProperty' cannot be accessed on 'C?' because it is potentially null.
+}
+
+via_prefix_op(C? c) {
+  if (c == null) return;
+  ++c;
+  //^
+  // [context 4] Variable 'c' could be null due to an intervening write.
+  c.cProperty;
+//^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //^
+  // [cfe 4] Property 'cProperty' cannot be accessed on 'C?' because it is potentially null.
+}
+
+via_for_each_statement(int? i, List<int?> list) {
+  if (i == null) return;
+  for (i in list) {
+  //   ^
+  // [context 5] Variable 'i' could be null due to an intervening write.
+    i.isEven;
+//  ^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+    //^
+    // [cfe 5] Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
+  }
+}
+
+via_for_each_list_element(int? i, List<int?> list) {
+  if (i == null) return;
+  [for (i in list) i.isEven];
+  //    ^
+  // [context 6] Variable 'i' could be null due to an intervening write.
+  //               ^
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //                 ^
+  // [cfe 6] Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
+}
+
+via_for_each_set_element(int? i, List<int?> list) {
+  if (i == null) return;
+  ({for (i in list) i.isEven});
+  //     ^
+  // [context 7] Variable 'i' could be null due to an intervening write.
+  //                ^
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //                  ^
+  // [cfe 7] Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
+}
+
+via_for_each_map_key(int? i, List<int?> list) {
+  if (i == null) return;
+  ({for (i in list) i.isEven: null});
+  //     ^
+  // [context 8] Variable 'i' could be null due to an intervening write.
+  //                ^
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //                  ^
+  // [cfe 8] Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
+}
+
+via_for_each_map_value(int? i, List<int?> list) {
+  if (i == null) return;
+  ({for (i in list) null: i.isEven});
+  //     ^
+  // [context 9] Variable 'i' could be null due to an intervening write.
+  //                      ^
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //                        ^
+  // [cfe 9] Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
+}
diff --git a/tests/language/why_not_promoted/extension_property_error_test.dart b/tests/language/why_not_promoted/extension_property_error_test.dart
new file mode 100644
index 0000000..db7d3ee
--- /dev/null
+++ b/tests/language/why_not_promoted/extension_property_error_test.dart
@@ -0,0 +1,85 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class C {
+  get_property_via_explicit_this() {
+    if (this.i == null) return;
+    this.i.isEven;
+//  ^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+//         ^
+// [cfe 1] Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
+  }
+
+  get_property_via_explicit_this_parenthesized() {
+    if ((this).i == null) return;
+    (this).i.isEven;
+//  ^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+//           ^
+// [cfe 2] Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
+  }
+
+  get_property_by_implicit_this() {
+    if (i == null) return;
+    i.isEven;
+//  ^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+//    ^
+// [cfe 3] Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
+  }
+}
+
+extension E on C {
+  int? get i => null;
+  //       ^
+  // [context 1] 'i' refers to a property so it couldn't be promoted.
+  // [context 2] 'i' refers to a property so it couldn't be promoted.
+  // [context 3] 'i' refers to a property so it couldn't be promoted.
+  // [context 4] 'i' refers to a property so it couldn't be promoted.
+  // [context 5] 'i' refers to a property so it couldn't be promoted.
+  int? get j => null;
+}
+
+class D extends C {
+  get_property_by_implicit_super() {
+    if (i == null) return;
+    i.isEven;
+//  ^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+//    ^
+// [cfe 4] Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
+  }
+}
+
+get_property_via_prefixed_identifier(C c) {
+  if (c.i == null) return;
+  c.i.isEven;
+//^^^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+//    ^
+// [cfe 5] Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
+}
+
+get_property_via_prefixed_identifier_mismatched_target(C c1, C c2) {
+  // Note: no context on this error because the property the user is attempting
+  // to promote is on c1, but the property the user is accessing is on c2.
+  if (c1.i == null) return;
+  c2.i.isEven;
+//^^^^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+//     ^
+// [cfe] Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
+}
+
+get_property_via_prefixed_identifier_mismatched_property(C c) {
+  // Note: no context on this error because the property the user is attempting
+  // to promote is C.i, but the property the user is accessing is C.j.
+  if (c.i == null) return;
+  c.j.isEven;
+//^^^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+//    ^
+// [cfe] Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
+}
diff --git a/tests/language/why_not_promoted/field_error_test.dart b/tests/language/why_not_promoted/field_error_test.dart
new file mode 100644
index 0000000..b32683d
--- /dev/null
+++ b/tests/language/why_not_promoted/field_error_test.dart
@@ -0,0 +1,93 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class C {
+  int? i;
+  //   ^
+  // [context 1] 'i' refers to a property so it couldn't be promoted.
+  // [context 2] 'i' refers to a property so it couldn't be promoted.
+  // [context 3] 'i' refers to a property so it couldn't be promoted.
+  // [context 4] 'i' refers to a property so it couldn't be promoted.
+  // [context 5] 'i' refers to a property so it couldn't be promoted.
+  // [context 6] 'i' refers to a property so it couldn't be promoted.
+  int? j;
+
+  get_field_via_explicit_this() {
+    if (this.i == null) return;
+    this.i.isEven;
+//  ^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+//         ^
+// [cfe 1] Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
+  }
+
+  get_field_via_explicit_this_parenthesized() {
+    if ((this).i == null) return;
+    (this).i.isEven;
+//  ^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+//           ^
+// [cfe 2] Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
+  }
+
+  get_field_by_implicit_this() {
+    if (i == null) return;
+    i.isEven;
+//  ^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+//    ^
+// [cfe 3] Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
+  }
+}
+
+class D extends C {
+  get_field_via_explicit_super() {
+    if (super.i == null) return;
+    super.i.isEven;
+//  ^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+//          ^
+// [cfe 4] Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
+  }
+
+  get_field_by_implicit_super() {
+    if (i == null) return;
+    i.isEven;
+//  ^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+//    ^
+// [cfe 5] Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
+  }
+}
+
+get_field_via_prefixed_identifier(C c) {
+  if (c.i == null) return;
+  c.i.isEven;
+//^^^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+//    ^
+// [cfe 6] Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
+}
+
+get_field_via_prefixed_identifier_mismatched_target(C c1, C c2) {
+  // Note: no context on this error because the property the user is attempting
+  // to promote is on c1, but the property the user is accessing is on c2.
+  if (c1.i == null) return;
+  c2.i.isEven;
+//^^^^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+//     ^
+// [cfe] Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
+}
+
+get_field_via_prefixed_identifier_mismatched_property(C c) {
+  // Note: no context on this error because the property the user is attempting
+  // to promote is C.i, but the property the user is accessing is C.j.
+  if (c.i == null) return;
+  c.j.isEven;
+//^^^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+//    ^
+// [cfe] Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
+}
diff --git a/tests/language/why_not_promoted/for_in_loop_type_not_iterable_nullability_error_test.dart b/tests/language/why_not_promoted/for_in_loop_type_not_iterable_nullability_error_test.dart
new file mode 100644
index 0000000..225e86b
--- /dev/null
+++ b/tests/language/why_not_promoted/for_in_loop_type_not_iterable_nullability_error_test.dart
@@ -0,0 +1,93 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This test contains a test case for each condition that can lead to the front
+// end's `ForInLoopTypeNotIterableNullability` or
+// `ForInLoopTypeNotIterablePartNullability` errors, for which we wish to report
+// "why not promoted" context information.
+
+class C1 {
+  List<int>? bad;
+  //         ^
+  // [context 1] 'bad' refers to a property so it couldn't be promoted.
+  // [context 2] 'bad' refers to a property so it couldn't be promoted.
+  // [context 3] 'bad' refers to a property so it couldn't be promoted.
+  // [context 4] 'bad' refers to a property so it couldn't be promoted.
+  // [context 5] 'bad' refers to a property so it couldn't be promoted.
+  // [context 6] 'bad' refers to a property so it couldn't be promoted.
+  // [context 7] 'bad' refers to a property so it couldn't be promoted.
+  // [context 8] 'bad' refers to a property so it couldn't be promoted.
+}
+
+forStatement(C1 c) {
+  if (c.bad == null) return;
+  for (var x in c.bad) {}
+  //            ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //              ^
+  // [cfe 1] The type 'List<int>?' used in the 'for' loop must implement 'Iterable<dynamic>' because 'List<int>?' is nullable and 'Iterable<dynamic>' isn't.
+}
+
+forElementInList(C1 c) {
+  if (c.bad == null) return;
+  [for (var x in c.bad) null];
+  //             ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //               ^
+  // [cfe 2] The type 'List<int>?' used in the 'for' loop must implement 'Iterable<dynamic>' because 'List<int>?' is nullable and 'Iterable<dynamic>' isn't.
+}
+
+forElementInSet(C1 c) {
+  if (c.bad == null) return;
+  <dynamic>{for (var x in c.bad) null};
+  //                      ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //                        ^
+  // [cfe 3] The type 'List<int>?' used in the 'for' loop must implement 'Iterable<dynamic>' because 'List<int>?' is nullable and 'Iterable<dynamic>' isn't.
+}
+
+forElementInMap(C1 c) {
+  if (c.bad == null) return;
+  <dynamic, dynamic>{for (var x in c.bad) null: null};
+  //                               ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //                                 ^
+  // [cfe 4] The type 'List<int>?' used in the 'for' loop must implement 'Iterable<dynamic>' because 'List<int>?' is nullable and 'Iterable<dynamic>' isn't.
+}
+
+forElementInAmbiguousSet_resolvableDuringParsing(C1 c) {
+  if (c.bad == null) return;
+  ({for (var x in c.bad) null});
+  //              ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //                ^
+  // [cfe 5] The type 'List<int>?' used in the 'for' loop must implement 'Iterable<dynamic>' because 'List<int>?' is nullable and 'Iterable<dynamic>' isn't.
+}
+
+forElementInAmbiguousMap_resolvableDuringParsing(C1 c) {
+  if (c.bad == null) return;
+  ({for (var x in c.bad) null: null});
+  //              ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //                ^
+  // [cfe 6] The type 'List<int>?' used in the 'for' loop must implement 'Iterable<dynamic>' because 'List<int>?' is nullable and 'Iterable<dynamic>' isn't.
+}
+
+forElementInAmbiguousSet_notResolvableDuringParsing(C1 c, List list) {
+  if (c.bad == null) return;
+  ({for (var x in c.bad) ...list});
+  //              ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //                ^
+  // [cfe 7] The type 'List<int>?' used in the 'for' loop must implement 'Iterable<dynamic>' because 'List<int>?' is nullable and 'Iterable<dynamic>' isn't.
+}
+
+forElementInAmbiguousMap_notResolvableDuringParsing(C1 c, Map map) {
+  if (c.bad == null) return;
+  ({for (var x in c.bad) ...map});
+  //              ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //                ^
+  // [cfe 8] The type 'List<int>?' used in the 'for' loop must implement 'Iterable<dynamic>' because 'List<int>?' is nullable and 'Iterable<dynamic>' isn't.
+}
diff --git a/tests/language/why_not_promoted/invalid_assignment_error_nullability_error_test.dart b/tests/language/why_not_promoted/invalid_assignment_error_nullability_error_test.dart
new file mode 100644
index 0000000..78da0e8
--- /dev/null
+++ b/tests/language/why_not_promoted/invalid_assignment_error_nullability_error_test.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This test contains a test case for each condition that can lead to the front
+// end's `InvalidAssignmentErrorNullability` or
+// `InvalidAssignmentErrorPartNullability` errors, for which we wish to report
+// "why not promoted" context information.
+
+class C1 {
+  List<int>? bad;
+  //         ^
+  // [context 1] 'bad' refers to a property so it couldn't be promoted.
+}
+
+test(C1 c) sync* {
+  if (c.bad == null) return;
+  yield* c.bad;
+  //     ^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  // [analyzer] COMPILE_TIME_ERROR.YIELD_OF_INVALID_TYPE
+  //       ^
+  // [cfe 1] A value of type 'List<int>?' can't be assigned to a variable of type 'Iterable<dynamic>' because 'List<int>?' is nullable and 'Iterable<dynamic>' isn't.
+}
diff --git a/tests/language/why_not_promoted/nullable_expression_call_error_test.dart b/tests/language/why_not_promoted/nullable_expression_call_error_test.dart
new file mode 100644
index 0000000..45c461f
--- /dev/null
+++ b/tests/language/why_not_promoted/nullable_expression_call_error_test.dart
@@ -0,0 +1,147 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This test contains a test case for each condition that can lead to the front
+// end's `NullableExpressionCallError`, for which we wish to report "why not
+// promoted" context information.
+
+class C1 {
+  C2? bad;
+  //  ^
+  // [context 1] 'bad' refers to a property so it couldn't be promoted.
+}
+
+class C2 {
+  void call() {}
+}
+
+instance_method_invocation(C1 c) {
+  if (c.bad == null) return;
+  c.bad();
+//^^^^^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+//     ^
+// [cfe 1] Can't use an expression of type 'C2?' as a function because it's potentially null.
+}
+
+class C3 {
+  C4? ok;
+  C5? bad;
+  //  ^
+  // [context 2] 'bad' refers to a property so it couldn't be promoted.
+}
+
+class C4 {}
+
+class C5 {}
+
+extension on C4? {
+  void call() {}
+}
+
+extension on C5 {
+  void call() {}
+}
+
+extension_invocation_method(C3 c) {
+  if (c.ok == null) return;
+  c.ok();
+  if (c.bad == null) return;
+  c.bad();
+//^^^^^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+//     ^
+// [cfe 2] Can't use an expression of type 'C5?' as a function because it's potentially null.
+}
+
+class C6 {
+  C7? bad;
+  //  ^
+  // [context 3] 'bad' refers to a property so it couldn't be promoted.
+}
+
+class C7 {
+  void Function() get call => () {};
+}
+
+instance_getter_invocation(C6 c) {
+  if (c.bad == null) return;
+  c.bad();
+//^^^^^
+// [analyzer] COMPILE_TIME_ERROR.INVOCATION_OF_NON_FUNCTION_EXPRESSION
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+//     ^
+// [cfe 3] Can't use an expression of type 'C7?' as a function because it's potentially null.
+}
+
+class C8 {
+  C9? ok;
+  C10? bad;
+  //   ^
+  // [context 4] 'bad' refers to a property so it couldn't be promoted.
+}
+
+class C9 {}
+
+class C10 {}
+
+extension on C9? {
+  void Function() get call => () {};
+}
+
+extension on C10 {
+  void Function() get call => () {};
+}
+
+extension_invocation_getter(C8 c) {
+  if (c.ok == null) return;
+  // Note: the analyzer produces an extraneous error on the line below due to
+  // https://github.com/dart-lang/sdk/issues/45551
+  c.ok();
+//^^^^
+// [analyzer] COMPILE_TIME_ERROR.INVOCATION_OF_NON_FUNCTION_EXPRESSION
+  if (c.bad == null) return;
+  c.bad();
+//^^^^^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+//     ^
+// [cfe 4] Can't use an expression of type 'C10?' as a function because it's potentially null.
+}
+
+class C11 {
+  void Function()? bad;
+  //               ^
+  // [context 5] 'bad' refers to a property so it couldn't be promoted.
+}
+
+function_invocation(C11 c) {
+  if (c.bad == null) return;
+  c.bad();
+//^^^^^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+//     ^
+// [cfe 5] Can't use an expression of type 'void Function()?' as a function because it's potentially null.
+}
+
+class C12 {
+  C13? bad;
+  //   ^
+  // [context 6] 'bad' refers to a property so it couldn't be promoted.
+}
+
+class C13 {
+  void Function() foo;
+  C13(this.foo);
+}
+
+instance_field_invocation(C12 c) {
+  if (c.bad == null) return;
+  // Note: the CFE error message is misleading here.  See
+  // https://github.com/dart-lang/sdk/issues/45552
+  c.bad.foo();
+//^^^^^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+//      ^
+// [cfe 6] Can't use an expression of type 'C13?' as a function because it's potentially null.
+}
diff --git a/tests/language/why_not_promoted/nullable_method_call_error_test.dart b/tests/language/why_not_promoted/nullable_method_call_error_test.dart
new file mode 100644
index 0000000..986436b
--- /dev/null
+++ b/tests/language/why_not_promoted/nullable_method_call_error_test.dart
@@ -0,0 +1,101 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This test contains a test case for each condition that can lead to the front
+// end's `NullableMethodCallError`, for which we wish to report "why not
+// promoted" context information.
+
+class C {
+  int? i;
+  //   ^
+  // [context 3] 'i' refers to a property so it couldn't be promoted.
+  // [context 4] 'i' refers to a property so it couldn't be promoted.
+  // [context 5] 'i' refers to a property so it couldn't be promoted.
+  // [context 6] 'i' refers to a property so it couldn't be promoted.
+  void Function()? f;
+  //               ^
+  // [context 7] 'f' refers to a property so it couldn't be promoted.
+}
+
+extension on int {
+  get propertyOnNonNullInt => null;
+  void methodOnNonNullInt() {}
+}
+
+extension on int? {
+  get propertyOnNullableInt => null;
+  void methodOnNullableInt() {}
+}
+
+property_get_of_variable(int? i, int? j) {
+  if (i == null) return;
+  i = j;
+//^
+// [context 1] Variable 'i' could be null due to an intervening write.
+  i.isEven;
+//^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+//  ^
+// [cfe 1] Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
+}
+
+extension_property_get_of_variable(int? i, int? j) {
+  if (i == null) return;
+  i = j;
+//^
+// [context 2] Variable 'i' could be null due to an intervening write.
+  i.propertyOnNullableInt;
+  i.propertyOnNonNullInt;
+//^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+//  ^
+// [cfe 2] Property 'propertyOnNonNullInt' cannot be accessed on 'int?' because it is potentially null.
+}
+
+property_get_of_expression(C c) {
+  if (c.i == null) return;
+  c.i.isEven;
+//^^^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+//    ^
+// [cfe 3] Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
+}
+
+extension_property_get_of_expression(C c) {
+  if (c.i == null) return;
+  c.i.propertyOnNullableInt;
+  c.i.propertyOnNonNullInt;
+//^^^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+//    ^
+// [cfe 4] Property 'propertyOnNonNullInt' cannot be accessed on 'int?' because it is potentially null.
+}
+
+method_invocation(C c) {
+  if (c.i == null) return;
+  c.i.abs();
+//^^^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+//    ^
+// [cfe 5] Method 'abs' cannot be called on 'int?' because it is potentially null.
+}
+
+extension_method_invocation(C c) {
+  if (c.i == null) return;
+  c.i.methodOnNullableInt();
+  c.i.methodOnNonNullInt();
+//^^^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+//    ^
+// [cfe 6] Method 'methodOnNonNullInt' cannot be called on 'int?' because it is potentially null.
+}
+
+call_invocation(C c) {
+  if (c.f == null) return;
+  c.f.call();
+//^^^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+//    ^
+// [cfe 7] Method 'call' cannot be called on 'void Function()?' because it is potentially null.
+}
diff --git a/tests/language/why_not_promoted/nullable_spread_error_test.dart b/tests/language/why_not_promoted/nullable_spread_error_test.dart
new file mode 100644
index 0000000..3d9e669
--- /dev/null
+++ b/tests/language/why_not_promoted/nullable_spread_error_test.dart
@@ -0,0 +1,199 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This test contains a test case for each condition that can lead to the front
+// end's `NullableSpreadError` error, for which we wish to report "why not
+// promoted" context information.
+
+class C {
+  List<int>? listQuestion;
+  //         ^
+  // [context 1] 'listQuestion' refers to a property so it couldn't be promoted.
+  // [context 5] 'listQuestion' refers to a property so it couldn't be promoted.
+  // [context 11] 'listQuestion' refers to a property so it couldn't be promoted.
+  Object? objectQuestion;
+  //      ^
+  // [context 4] 'objectQuestion' refers to a property so it couldn't be promoted.
+  // [context 8] 'objectQuestion' refers to a property so it couldn't be promoted.
+  // [context 9] 'objectQuestion' refers to a property so it couldn't be promoted.
+  // [context 10] 'objectQuestion' refers to a property so it couldn't be promoted.
+  // [context 14] 'objectQuestion' refers to a property so it couldn't be promoted.
+  // [context 15] 'objectQuestion' refers to a property so it couldn't be promoted.
+  Set<int>? setQuestion;
+  //        ^
+  // [context 2] 'setQuestion' refers to a property so it couldn't be promoted.
+  // [context 6] 'setQuestion' refers to a property so it couldn't be promoted.
+  // [context 12] 'setQuestion' refers to a property so it couldn't be promoted.
+  // [context 16] 'setQuestion' refers to a property so it couldn't be promoted.
+  Map<int, int>? mapQuestion;
+  //             ^
+  // [context 3] 'mapQuestion' refers to a property so it couldn't be promoted.
+  // [context 7] 'mapQuestion' refers to a property so it couldn't be promoted.
+  // [context 13] 'mapQuestion' refers to a property so it couldn't be promoted.
+}
+
+list_from_list_question(C c) {
+  if (c.listQuestion == null) return;
+  return [...c.listQuestion];
+  //         ^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //           ^
+  // [cfe 1] An expression whose value can be 'null' must be null-checked before it can be dereferenced.
+}
+
+list_from_set_question(C c) {
+  if (c.setQuestion == null) return;
+  return [...c.setQuestion];
+  //         ^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //           ^
+  // [cfe 2] An expression whose value can be 'null' must be null-checked before it can be dereferenced.
+}
+
+list_from_map_question(C c) {
+  if (c.mapQuestion == null) return;
+  return [...c.mapQuestion];
+  //         ^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.NOT_ITERABLE_SPREAD
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //           ^
+  // [cfe 3] An expression whose value can be 'null' must be null-checked before it can be dereferenced.
+  // [cfe] Unexpected type 'Map<int, int>?' of a spread.  Expected 'dynamic' or an Iterable.
+}
+
+list_from_object_question(C c) {
+  if (c.objectQuestion is! List<int>) return;
+  return [...c.objectQuestion];
+  //         ^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.NOT_ITERABLE_SPREAD
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //           ^
+  // [cfe 4] An expression whose value can be 'null' must be null-checked before it can be dereferenced.
+  // [cfe] Unexpected type 'Object?' of a spread.  Expected 'dynamic' or an Iterable.
+}
+
+set_from_list_question(C c) {
+  if (c.listQuestion == null) return;
+  return {...c.listQuestion};
+  //         ^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //           ^
+  // [cfe 5] An expression whose value can be 'null' must be null-checked before it can be dereferenced.
+}
+
+set_from_set_question(C c) {
+  if (c.setQuestion == null) return;
+  return {...c.setQuestion};
+  //         ^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //           ^
+  // [cfe 6] An expression whose value can be 'null' must be null-checked before it can be dereferenced.
+}
+
+set_from_map_question(C c) {
+  if (c.mapQuestion == null) return;
+  return {...c.mapQuestion};
+  //         ^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //           ^
+  // [cfe 7] An expression whose value can be 'null' must be null-checked before it can be dereferenced.
+}
+
+set_from_object_question_type_disambiguate_by_entry(C c) {
+  if (c.objectQuestion is! Set<int>) return;
+  return {null, ...c.objectQuestion};
+  //     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_SET_OR_MAP_LITERAL_EITHER
+  //               ^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //                 ^
+  // [cfe 8] An expression whose value can be 'null' must be null-checked before it can be dereferenced.
+  // [cfe] Unexpected type 'Object?' of a spread.  Expected 'dynamic' or an Iterable.
+}
+
+set_from_object_question_type_disambiguate_by_previous_spread(C c) {
+  if (c.objectQuestion is! Set<int>) return;
+  return {...<int>{}, ...c.objectQuestion};
+  //     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_SET_OR_MAP_LITERAL_EITHER
+  //                     ^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //                       ^
+  // [cfe 9] Unexpected type 'Object?' of a map spread entry.  Expected 'dynamic' or a Map.
+}
+
+set_from_object_question_type_disambiguate_by_literal_args(C c) {
+  if (c.objectQuestion is! Set<int>) return;
+  return <int>{...c.objectQuestion};
+  //              ^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.NOT_ITERABLE_SPREAD
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //                ^
+  // [cfe 10] An expression whose value can be 'null' must be null-checked before it can be dereferenced.
+  // [cfe] Unexpected type 'Object?' of a spread.  Expected 'dynamic' or an Iterable.
+}
+
+map_from_list_question(C c) {
+  if (c.listQuestion == null) return;
+  return {...c.listQuestion};
+  //         ^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //           ^
+  // [cfe 11] An expression whose value can be 'null' must be null-checked before it can be dereferenced.
+}
+
+map_from_set_question(C c) {
+  if (c.setQuestion == null) return;
+  return {...c.setQuestion};
+  //         ^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //           ^
+  // [cfe 12] An expression whose value can be 'null' must be null-checked before it can be dereferenced.
+}
+
+map_from_map_question(C c) {
+  if (c.mapQuestion == null) return;
+  return {...c.mapQuestion};
+  //         ^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //           ^
+  // [cfe 13] An expression whose value can be 'null' must be null-checked before it can be dereferenced.
+}
+
+map_from_object_question_type_disambiguate_by_key_value_pair(C c) {
+  if (c.objectQuestion is! Map<int, int>) return;
+  return {null: null, ...c.objectQuestion};
+  //     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_SET_OR_MAP_LITERAL_EITHER
+  //                     ^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //                       ^
+  // [cfe 14] Unexpected type 'Object?' of a map spread entry.  Expected 'dynamic' or a Map.
+}
+
+map_from_object_question_type_disambiguate_by_previous_spread(C c) {
+  if (c.objectQuestion is! Map<int, int>) return;
+  return {...<int, int>{}, ...c.objectQuestion};
+  //     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_SET_OR_MAP_LITERAL_EITHER
+  //                          ^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //                            ^
+  // [cfe 15] Unexpected type 'Object?' of a map spread entry.  Expected 'dynamic' or a Map.
+}
+
+map_from_set_question_type_disambiguate_by_literal_args(C c) {
+  // Note: analyzer shows "why not promoted" information here, but CFE doesn't.
+  // That's probably ok, since there are two problems here (set/map mismatch and
+  // null safety); it's a matter of interpretation whether to prioritize one or
+  // the other.
+  if (c.setQuestion == null) return;
+  return <int, int>{...c.setQuestion};
+  //                   ^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.NOT_MAP_SPREAD
+  // [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+  //                     ^
+  // [cfe 16] An expression whose value can be 'null' must be null-checked before it can be dereferenced.
+  // [cfe] Unexpected type 'Set<int>?' of a map spread entry.  Expected 'dynamic' or a Map.
+}
diff --git a/tests/language/why_not_promoted/property_error_test.dart b/tests/language/why_not_promoted/property_error_test.dart
new file mode 100644
index 0000000..87452be
--- /dev/null
+++ b/tests/language/why_not_promoted/property_error_test.dart
@@ -0,0 +1,93 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class C {
+  int? get i => null;
+  //       ^
+  // [context 1] 'i' refers to a property so it couldn't be promoted.
+  // [context 2] 'i' refers to a property so it couldn't be promoted.
+  // [context 3] 'i' refers to a property so it couldn't be promoted.
+  // [context 4] 'i' refers to a property so it couldn't be promoted.
+  // [context 5] 'i' refers to a property so it couldn't be promoted.
+  // [context 6] 'i' refers to a property so it couldn't be promoted.
+  int? get j => null;
+
+  get_property_via_explicit_this() {
+    if (this.i == null) return;
+    this.i.isEven;
+//  ^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+//         ^
+// [cfe 1] Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
+  }
+
+  get_property_via_explicit_this_parenthesized() {
+    if ((this).i == null) return;
+    (this).i.isEven;
+//  ^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+//           ^
+// [cfe 2] Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
+  }
+
+  get_property_by_implicit_this() {
+    if (i == null) return;
+    i.isEven;
+//  ^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+//    ^
+// [cfe 3] Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
+  }
+}
+
+class D extends C {
+  get_property_via_explicit_super() {
+    if (super.i == null) return;
+    super.i.isEven;
+//  ^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+//          ^
+// [cfe 4] Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
+  }
+
+  get_property_by_implicit_super() {
+    if (i == null) return;
+    i.isEven;
+//  ^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+//    ^
+// [cfe 5] Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
+  }
+}
+
+get_property_via_prefixed_identifier(C c) {
+  if (c.i == null) return;
+  c.i.isEven;
+//^^^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+//    ^
+// [cfe 6] Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
+}
+
+get_property_via_prefixed_identifier_mismatched_target(C c1, C c2) {
+  // Note: no context on this error because the property the user is attempting
+  // to promote is on c1, but the property the user is accessing is on c2.
+  if (c1.i == null) return;
+  c2.i.isEven;
+//^^^^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+//     ^
+// [cfe] Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
+}
+
+get_property_via_prefixed_identifier_mismatched_property(C c) {
+  // Note: no context on this error because the property the user is attempting
+  // to promote is C.i, but the property the user is accessing is C.j.
+  if (c.i == null) return;
+  c.j.isEven;
+//^^^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+//    ^
+// [cfe] Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
+}
diff --git a/tests/language/why_not_promoted/this_error_test.dart b/tests/language/why_not_promoted/this_error_test.dart
new file mode 100644
index 0000000..b9a770b
--- /dev/null
+++ b/tests/language/why_not_promoted/this_error_test.dart
@@ -0,0 +1,31 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This test validates integration of "why not promoted" when the user tries to
+// promote `this`.
+
+// TODO(paulberry): once we support adding "why not promoted" information to
+// errors that aren't related to null safety, test references to `this` in
+// classes and mixins.
+
+extension on int? {
+  extension_explicit_this() {
+    // TODO(paulberry): get this to work with the CFE.
+    if (this == null) return;
+    this.isEven;
+//  ^^^^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+//       ^
+// [cfe] Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
+  }
+
+  extension_implicit_this() {
+    // TODO(paulberry): get this to work with the CFE.
+    if (this == null) return;
+    isEven;
+//  ^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+// [cfe] Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
+  }
+}