Version 2.12.0-249.0.dev

Merge commit '5569f10236f522e62adea480c1de4de244074359' into 'dev'
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/error_on_recompile_with_no_change.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/error_on_recompile_with_no_change.yaml
new file mode 100644
index 0000000..1f4e0da3
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/error_on_recompile_with_no_change.yaml
@@ -0,0 +1,56 @@
+# 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.md file.
+
+type: newworld
+target: VM
+worlds:
+  - entry: main.dart
+    sources:
+      .dart_tool/package_config.json: |
+        {
+          "configVersion": 2,
+          "packages": [
+            {
+              "name": "flutter",
+              "rootUri": "../flutter",
+              "languageVersion": "2.12"
+            }
+          ]
+        }
+      main.dart: |
+        import 'package:flutter/object.dart';
+        import 'lib.dart';
+        
+        class Adaptor extends RenderFoo with LibMixin {}
+
+        class AdaptorElement extends RenderObject {
+          Adaptor get renderObject => super.renderObject;
+          void foo() {
+            print(renderObject.constraints.axis);
+          }
+        }
+      lib.dart: |
+        import 'package:flutter/object.dart';
+        mixin LibMixin on RenderObject {}
+      flutter/object.dart: |
+        class RenderFoo extends RenderObject {
+          FooConstraints get constraints => super.constraints as FooConstraints;
+        }
+        class FooConstraints extends Constraints {
+          String get axis => "hello";
+        }
+        class Constraints {}
+        class RenderObject {
+          Constraints get constraints => new Constraints();
+          RenderObject get renderObject => this;
+        }
+    expectedLibraryCount: 3
+
+  - entry: main.dart
+    worldType: updated
+    errors: true
+    expectInitializeFromDill: false
+    invalidate:
+      - main.dart
+    expectedLibraryCount: 3
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/error_on_recompile_with_no_change.yaml.world.1.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/error_on_recompile_with_no_change.yaml.world.1.expect
new file mode 100644
index 0000000..03611f5
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/error_on_recompile_with_no_change.yaml.world.1.expect
@@ -0,0 +1,100 @@
+main = <No Member>;
+library from "package:flutter/object.dart" as obj {
+
+  class RenderFoo extends obj::RenderObject {
+    synthetic constructor •() → obj::RenderFoo
+      : super obj::RenderObject::•()
+      ;
+    get constraints() → obj::FooConstraints
+      return super.{obj::RenderObject::constraints} as{ForNonNullableByDefault} obj::FooConstraints;
+  }
+  class FooConstraints extends obj::Constraints {
+    synthetic constructor •() → obj::FooConstraints
+      : super obj::Constraints::•()
+      ;
+    get axis() → dart.core::String
+      return "hello";
+  }
+  class Constraints extends dart.core::Object {
+    synthetic constructor •() → obj::Constraints
+      : super dart.core::Object::•()
+      ;
+  }
+  class RenderObject extends dart.core::Object {
+    synthetic constructor •() → obj::RenderObject
+      : super dart.core::Object::•()
+      ;
+    get constraints() → obj::Constraints
+      return new obj::Constraints::•();
+    get renderObject() → obj::RenderObject
+      return this;
+  }
+}
+library from "org-dartlang-test:///lib.dart" as lib {
+
+  import "package:flutter/object.dart";
+
+  abstract class LibMixin extends obj::RenderObject /*isMixinDeclaration*/  {
+    abstract member-signature get constraints() → obj::Constraints*; -> obj::RenderObject::constraints
+    abstract member-signature get renderObject() → obj::RenderObject*; -> obj::RenderObject::renderObject
+    abstract member-signature get _identityHashCode() → dart.core::int*; -> dart.core::Object::_identityHashCode
+    abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → dart.core::bool*; -> dart.core::Object::_instanceOf
+    abstract member-signature method _simpleInstanceOf(dynamic type) → dart.core::bool*; -> dart.core::Object::_simpleInstanceOf
+    abstract member-signature method _simpleInstanceOfTrue(dynamic type) → dart.core::bool*; -> dart.core::Object::_simpleInstanceOfTrue
+    abstract member-signature method _simpleInstanceOfFalse(dynamic type) → dart.core::bool*; -> dart.core::Object::_simpleInstanceOfFalse
+    abstract member-signature operator ==(dynamic other) → dart.core::bool*; -> dart.core::Object::==
+    abstract member-signature get hashCode() → dart.core::int*; -> dart.core::Object::hashCode
+    abstract member-signature method toString() → dart.core::String*; -> dart.core::Object::toString
+    abstract member-signature method noSuchMethod(dart.core::Invocation* invocation) → dynamic; -> dart.core::Object::noSuchMethod
+    abstract member-signature get runtimeType() → dart.core::Type*; -> dart.core::Object::runtimeType
+  }
+}
+library from "org-dartlang-test:///main.dart" as main {
+
+  import "package:flutter/object.dart";
+  import "org-dartlang-test:///lib.dart";
+
+  abstract class _Adaptor&RenderFoo&LibMixin extends obj::RenderFoo implements lib::LibMixin /*isAnonymousMixin,isEliminatedMixin*/  {
+    synthetic constructor •() → main::_Adaptor&RenderFoo&LibMixin*
+      : super obj::RenderFoo::•()
+      ;
+    abstract member-signature get /* from org-dartlang-test:///lib.dart */ constraints() → obj::Constraints*; -> obj::RenderObject::constraints
+    abstract member-signature get /* from org-dartlang-test:///lib.dart */ renderObject() → obj::RenderObject*; -> obj::RenderObject::renderObject
+    abstract member-signature get /* from org-dartlang-test:///lib.dart */ _identityHashCode() → dart.core::int*; -> dart.core::Object::_identityHashCode
+    abstract member-signature method /* from org-dartlang-test:///lib.dart */ _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → dart.core::bool*; -> dart.core::Object::_instanceOf
+    abstract member-signature method /* from org-dartlang-test:///lib.dart */ _simpleInstanceOf(dynamic type) → dart.core::bool*; -> dart.core::Object::_simpleInstanceOf
+    abstract member-signature method /* from org-dartlang-test:///lib.dart */ _simpleInstanceOfTrue(dynamic type) → dart.core::bool*; -> dart.core::Object::_simpleInstanceOfTrue
+    abstract member-signature method /* from org-dartlang-test:///lib.dart */ _simpleInstanceOfFalse(dynamic type) → dart.core::bool*; -> dart.core::Object::_simpleInstanceOfFalse
+    abstract member-signature operator /* from org-dartlang-test:///lib.dart */ ==(dynamic other) → dart.core::bool*; -> dart.core::Object::==
+    abstract member-signature get /* from org-dartlang-test:///lib.dart */ hashCode() → dart.core::int*; -> dart.core::Object::hashCode
+    abstract member-signature method /* from org-dartlang-test:///lib.dart */ toString() → dart.core::String*; -> dart.core::Object::toString
+    abstract member-signature method /* from org-dartlang-test:///lib.dart */ noSuchMethod(dart.core::Invocation* invocation) → dynamic; -> dart.core::Object::noSuchMethod
+    abstract member-signature get /* from org-dartlang-test:///lib.dart */ runtimeType() → dart.core::Type*; -> dart.core::Object::runtimeType
+  }
+  class Adaptor extends main::_Adaptor&RenderFoo&LibMixin {
+    synthetic constructor •() → main::Adaptor*
+      : super main::_Adaptor&RenderFoo&LibMixin::•()
+      ;
+  }
+  class AdaptorElement extends obj::RenderObject {
+    synthetic constructor •() → main::AdaptorElement*
+      : super obj::RenderObject::•()
+      ;
+    get renderObject() → main::Adaptor*
+      return super.{obj::RenderObject::renderObject} as{TypeError} main::Adaptor*;
+    method foo() → void {
+      dart.core::print(this.{main::AdaptorElement::renderObject}.{main::_Adaptor&RenderFoo&LibMixin::constraints}.{obj::FooConstraints::axis});
+    }
+    abstract member-signature get constraints() → obj::Constraints*; -> obj::RenderObject::constraints
+    abstract member-signature get _identityHashCode() → dart.core::int*; -> dart.core::Object::_identityHashCode
+    abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → dart.core::bool*; -> dart.core::Object::_instanceOf
+    abstract member-signature method _simpleInstanceOf(dynamic type) → dart.core::bool*; -> dart.core::Object::_simpleInstanceOf
+    abstract member-signature method _simpleInstanceOfTrue(dynamic type) → dart.core::bool*; -> dart.core::Object::_simpleInstanceOfTrue
+    abstract member-signature method _simpleInstanceOfFalse(dynamic type) → dart.core::bool*; -> dart.core::Object::_simpleInstanceOfFalse
+    abstract member-signature operator ==(dynamic other) → dart.core::bool*; -> dart.core::Object::==
+    abstract member-signature get hashCode() → dart.core::int*; -> dart.core::Object::hashCode
+    abstract member-signature method toString() → dart.core::String*; -> dart.core::Object::toString
+    abstract member-signature method noSuchMethod(dart.core::Invocation* invocation) → dynamic; -> dart.core::Object::noSuchMethod
+    abstract member-signature get runtimeType() → dart.core::Type*; -> dart.core::Object::runtimeType
+  }
+}
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/error_on_recompile_with_no_change.yaml.world.2.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/error_on_recompile_with_no_change.yaml.world.2.expect
new file mode 100644
index 0000000..e251ab0
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/error_on_recompile_with_no_change.yaml.world.2.expect
@@ -0,0 +1,109 @@
+main = <No Member>;
+library from "package:flutter/object.dart" as obj {
+
+  class RenderFoo extends obj::RenderObject {
+    synthetic constructor •() → obj::RenderFoo
+      : super obj::RenderObject::•()
+      ;
+    get constraints() → obj::FooConstraints
+      return super.{obj::RenderObject::constraints} as{ForNonNullableByDefault} obj::FooConstraints;
+  }
+  class FooConstraints extends obj::Constraints {
+    synthetic constructor •() → obj::FooConstraints
+      : super obj::Constraints::•()
+      ;
+    get axis() → dart.core::String
+      return "hello";
+  }
+  class Constraints extends dart.core::Object {
+    synthetic constructor •() → obj::Constraints
+      : super dart.core::Object::•()
+      ;
+  }
+  class RenderObject extends dart.core::Object {
+    synthetic constructor •() → obj::RenderObject
+      : super dart.core::Object::•()
+      ;
+    get constraints() → obj::Constraints
+      return new obj::Constraints::•();
+    get renderObject() → obj::RenderObject
+      return this;
+  }
+}
+library from "org-dartlang-test:///lib.dart" as lib {
+
+  import "package:flutter/object.dart";
+
+  abstract class LibMixin extends obj::RenderObject /*isMixinDeclaration*/  {
+    abstract member-signature get constraints() → obj::Constraints*; -> obj::RenderObject::constraints
+    abstract member-signature get renderObject() → obj::RenderObject*; -> obj::RenderObject::renderObject
+    abstract member-signature get _identityHashCode() → dart.core::int*; -> dart.core::Object::_identityHashCode
+    abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → dart.core::bool*; -> dart.core::Object::_instanceOf
+    abstract member-signature method _simpleInstanceOf(dynamic type) → dart.core::bool*; -> dart.core::Object::_simpleInstanceOf
+    abstract member-signature method _simpleInstanceOfTrue(dynamic type) → dart.core::bool*; -> dart.core::Object::_simpleInstanceOfTrue
+    abstract member-signature method _simpleInstanceOfFalse(dynamic type) → dart.core::bool*; -> dart.core::Object::_simpleInstanceOfFalse
+    abstract member-signature operator ==(dynamic other) → dart.core::bool*; -> dart.core::Object::==
+    abstract member-signature get hashCode() → dart.core::int*; -> dart.core::Object::hashCode
+    abstract member-signature method toString() → dart.core::String*; -> dart.core::Object::toString
+    abstract member-signature method noSuchMethod(dart.core::Invocation* invocation) → dynamic; -> dart.core::Object::noSuchMethod
+    abstract member-signature get runtimeType() → dart.core::Type*; -> dart.core::Object::runtimeType
+  }
+}
+library from "org-dartlang-test:///main.dart" as main {
+//
+// Problems in library:
+//
+// org-dartlang-test:///main.dart:9:36: Error: The getter 'axis' isn't defined for the class 'Constraints'.
+//  - 'Constraints' is from 'package:flutter/object.dart' ('org-dartlang-test:///flutter/object.dart').
+// Try correcting the name to the name of an existing getter, or defining a getter or field named 'axis'.
+//     print(renderObject.constraints.axis);
+//                                    ^^^^
+//
+
+  import "package:flutter/object.dart";
+  import "org-dartlang-test:///lib.dart";
+
+  abstract class _Adaptor&RenderFoo&LibMixin extends obj::RenderFoo implements lib::LibMixin /*isAnonymousMixin,isEliminatedMixin*/  {
+    synthetic constructor •() → main::_Adaptor&RenderFoo&LibMixin*
+      : super obj::RenderFoo::•()
+      ;
+    abstract member-signature get /* from org-dartlang-test:///lib.dart */ constraints() → obj::Constraints*; -> obj::RenderObject::constraints
+    abstract member-signature get /* from org-dartlang-test:///lib.dart */ renderObject() → obj::RenderObject*; -> obj::RenderObject::renderObject
+    abstract member-signature get /* from org-dartlang-test:///lib.dart */ _identityHashCode() → dart.core::int*; -> dart.core::Object::_identityHashCode
+    abstract member-signature method /* from org-dartlang-test:///lib.dart */ _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → dart.core::bool*; -> dart.core::Object::_instanceOf
+    abstract member-signature method /* from org-dartlang-test:///lib.dart */ _simpleInstanceOf(dynamic type) → dart.core::bool*; -> dart.core::Object::_simpleInstanceOf
+    abstract member-signature method /* from org-dartlang-test:///lib.dart */ _simpleInstanceOfTrue(dynamic type) → dart.core::bool*; -> dart.core::Object::_simpleInstanceOfTrue
+    abstract member-signature method /* from org-dartlang-test:///lib.dart */ _simpleInstanceOfFalse(dynamic type) → dart.core::bool*; -> dart.core::Object::_simpleInstanceOfFalse
+    abstract member-signature operator /* from org-dartlang-test:///lib.dart */ ==(dynamic other) → dart.core::bool*; -> dart.core::Object::==
+    abstract member-signature get /* from org-dartlang-test:///lib.dart */ hashCode() → dart.core::int*; -> dart.core::Object::hashCode
+    abstract member-signature method /* from org-dartlang-test:///lib.dart */ toString() → dart.core::String*; -> dart.core::Object::toString
+    abstract member-signature method /* from org-dartlang-test:///lib.dart */ noSuchMethod(dart.core::Invocation* invocation) → dynamic; -> dart.core::Object::noSuchMethod
+    abstract member-signature get /* from org-dartlang-test:///lib.dart */ runtimeType() → dart.core::Type*; -> dart.core::Object::runtimeType
+  }
+  class Adaptor extends main::_Adaptor&RenderFoo&LibMixin {
+    synthetic constructor •() → main::Adaptor*
+      : super main::_Adaptor&RenderFoo&LibMixin::•()
+      ;
+  }
+  class AdaptorElement extends obj::RenderObject {
+    synthetic constructor •() → main::AdaptorElement*
+      : super obj::RenderObject::•()
+      ;
+    get renderObject() → main::Adaptor*
+      return super.{obj::RenderObject::renderObject} as{TypeError} main::Adaptor*;
+    method foo() → void {
+      dart.core::print(invalid-expression "org-dartlang-test:///main.dart:9:36: Error: The getter 'axis' isn't defined for the class 'Constraints'.\n - 'Constraints' is from 'package:flutter/object.dart' ('org-dartlang-test:///flutter/object.dart').\nTry correcting the name to the name of an existing getter, or defining a getter or field named 'axis'.\n    print(renderObject.constraints.axis);\n                                   ^^^^");
+    }
+    abstract member-signature get constraints() → obj::Constraints*; -> obj::RenderObject::constraints
+    abstract member-signature get _identityHashCode() → dart.core::int*; -> dart.core::Object::_identityHashCode
+    abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → dart.core::bool*; -> dart.core::Object::_instanceOf
+    abstract member-signature method _simpleInstanceOf(dynamic type) → dart.core::bool*; -> dart.core::Object::_simpleInstanceOf
+    abstract member-signature method _simpleInstanceOfTrue(dynamic type) → dart.core::bool*; -> dart.core::Object::_simpleInstanceOfTrue
+    abstract member-signature method _simpleInstanceOfFalse(dynamic type) → dart.core::bool*; -> dart.core::Object::_simpleInstanceOfFalse
+    abstract member-signature operator ==(dynamic other) → dart.core::bool*; -> dart.core::Object::==
+    abstract member-signature get hashCode() → dart.core::int*; -> dart.core::Object::hashCode
+    abstract member-signature method toString() → dart.core::String*; -> dart.core::Object::toString
+    abstract member-signature method noSuchMethod(dart.core::Invocation* invocation) → dynamic; -> dart.core::Object::noSuchMethod
+    abstract member-signature get runtimeType() → dart.core::Type*; -> dart.core::Object::runtimeType
+  }
+}
diff --git a/pkg/nnbd_migration/lib/instrumentation.dart b/pkg/nnbd_migration/lib/instrumentation.dart
index 5295242..a5fa5ce 100644
--- a/pkg/nnbd_migration/lib/instrumentation.dart
+++ b/pkg/nnbd_migration/lib/instrumentation.dart
@@ -274,6 +274,7 @@
   implicitMixinSuperCall,
   implicitNullInitializer,
   implicitNullReturn,
+  implicitThis,
   inferredTypeParameterInstantiation,
   instanceCreation,
   instantiateToBounds,
diff --git a/pkg/nnbd_migration/lib/src/edge_builder.dart b/pkg/nnbd_migration/lib/src/edge_builder.dart
index 2213ef3..5f30b51 100644
--- a/pkg/nnbd_migration/lib/src/edge_builder.dart
+++ b/pkg/nnbd_migration/lib/src/edge_builder.dart
@@ -10,6 +10,7 @@
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/dart/element/type_provider.dart';
 import 'package:analyzer/dart/element/type_system.dart';
+import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/type_system.dart' show TypeSystemImpl;
@@ -1268,6 +1269,7 @@
       }
     } else if (target == null && callee.enclosingElement is ClassElement) {
       targetType = _thisOrSuper(node);
+      _checkThisNotNull(targetType, node);
     }
     DecoratedType expressionType;
     DecoratedType calleeType;
@@ -1575,6 +1577,7 @@
 
   @override
   DecoratedType visitSimpleIdentifier(SimpleIdentifier node) {
+    DecoratedType targetType;
     DecoratedType result;
     var staticElement = getWriteOrReadElement(node);
     if (staticElement is PromotableElement) {
@@ -1594,15 +1597,16 @@
     } else if (staticElement is FunctionElement ||
         staticElement is MethodElement ||
         staticElement is ConstructorElement) {
-      result = getOrComputeElementType(staticElement,
-          targetType: staticElement.enclosingElement is ClassElement
-              ? _thisOrSuper(node)
-              : null);
+      if (staticElement.enclosingElement is ClassElement) {
+        targetType = _thisOrSuper(node);
+      }
+      result = getOrComputeElementType(staticElement, targetType: targetType);
     } else if (staticElement is PropertyAccessorElement) {
-      var elementType = getOrComputeElementType(staticElement,
-          targetType: staticElement.enclosingElement is ClassElement
-              ? _thisOrSuper(node)
-              : null);
+      if (staticElement.enclosingElement is ClassElement) {
+        targetType = _thisOrSuper(node);
+      }
+      var elementType =
+          getOrComputeElementType(staticElement, targetType: targetType);
       result = staticElement.isGetter
           ? elementType.returnType
           : elementType.positionalParameters[0];
@@ -1621,6 +1625,9 @@
       _unimplemented(node,
           'Simple identifier with a static element of type ${staticElement.runtimeType}');
     }
+    if (targetType != null) {
+      _checkThisNotNull(targetType, node);
+    }
     return result;
   }
 
@@ -1986,6 +1993,18 @@
     return sourceType;
   }
 
+  /// Generates the appropriate edge to assert that the value of `this` is
+  /// non-null.
+  void _checkThisNotNull(DecoratedType thisType, AstNode node) {
+    // `this` can only be `null` in extensions, so if we're not in an extension,
+    // there's nothing to do.
+    if (_currentExtendedType == null) return;
+    var origin = ImplicitThisOrigin(source, node);
+    var hard =
+        _postDominatedLocals.isInScope(_postDominatedLocals.extensionThis);
+    _graph.makeNonNullable(thisType.node, origin, hard: hard, guards: _guards);
+  }
+
   @override
   void _connect(NullabilityNode source, NullabilityNode destination,
       EdgeOrigin origin, FixReasonTarget edgeTarget,
@@ -2397,9 +2416,10 @@
       }
     }
     if (destinationExpression != null) {
-      var element = _postDominatedLocals
-          .removeReferenceFromAllScopes(destinationExpression);
+      var element =
+          _postDominatedLocals.referencedElement(destinationExpression);
       if (element != null) {
+        _postDominatedLocals.removeFromAllScopes(element);
         _elementsWrittenToInLocalFunction?.add(element);
       }
     }
@@ -2451,6 +2471,9 @@
     _addParametersToFlowAnalysis(parameters);
     // Push a scope of post-dominated declarations on the stack.
     _postDominatedLocals.pushScope(elements: declaredElement.parameters);
+    if (declaredElement.enclosingElement is ExtensionElement) {
+      _postDominatedLocals.add(_postDominatedLocals.extensionThis);
+    }
     try {
       _dispatchList(initializers);
       if (declaredElement is ConstructorElement &&
@@ -3658,23 +3681,23 @@
 ///
 /// Contains helpers for dealing with expressions as if they were elements.
 class _ScopedLocalSet extends ScopedSet<Element> {
+  /// The synthetic element we use as a stand-in for `this` when analyzing
+  /// extension methods.
+  Element get extensionThis => DynamicElementImpl.instance;
+
   bool isReferenceInScope(Expression expression) {
-    expression = expression.unParenthesized;
-    if (expression is SimpleIdentifier) {
-      var element = expression.staticElement;
-      return isInScope(element);
-    }
-    return false;
+    var element = referencedElement(expression);
+    return element != null && isInScope(element);
   }
 
-  /// If [expression] references an element, removes that element from all
-  /// scopes and returns it.  Otherwise returns `null`.
-  Element removeReferenceFromAllScopes(Expression expression) {
+  /// Returns the element referenced directly by [expression], if any; otherwise
+  /// returns `null`.
+  Element referencedElement(Expression expression) {
     expression = expression.unParenthesized;
     if (expression is SimpleIdentifier) {
-      var element = expression.staticElement;
-      removeFromAllScopes(element);
-      return element;
+      return expression.staticElement;
+    } else if (expression is ThisExpression || expression is SuperExpression) {
+      return extensionThis;
     } else {
       return null;
     }
diff --git a/pkg/nnbd_migration/lib/src/edge_origin.dart b/pkg/nnbd_migration/lib/src/edge_origin.dart
index 5b42111..cff0b7b 100644
--- a/pkg/nnbd_migration/lib/src/edge_origin.dart
+++ b/pkg/nnbd_migration/lib/src/edge_origin.dart
@@ -85,6 +85,18 @@
   EdgeOriginKind get kind => EdgeOriginKind.argumentErrorCheckNotNull;
 }
 
+/// An edge origin used for edges that originated because of a tear-off of
+/// `call` on a function type.
+class CallTearOffOrigin extends EdgeOrigin {
+  CallTearOffOrigin(Source source, AstNode node) : super(source, node);
+
+  @override
+  String get description => 'tear-off of .call';
+
+  @override
+  EdgeOriginKind get kind => EdgeOriginKind.callTearOff;
+}
+
 /// Edge origin resulting from the use of a value on the LHS of a compound
 /// assignment.
 class CompoundAssignmentOrigin extends EdgeOrigin {
@@ -312,6 +324,18 @@
   ReturnStatement get node => super.node as ReturnStatement;
 }
 
+/// Edge origin used for edges that arise from an implicit use of `this`, e.g.
+/// during a method call from an extension.
+class ImplicitThisOrigin extends EdgeOrigin {
+  ImplicitThisOrigin(Source source, AstNode node) : super(source, node);
+
+  @override
+  String get description => 'implicit use of `this`';
+
+  @override
+  EdgeOriginKind get kind => EdgeOriginKind.implicitThis;
+}
+
 /// Edge origin resulting from the inference of a type parameter, which
 /// can affects the nullability of that type parameter's bound.
 class InferredTypeParameterInstantiationOrigin extends EdgeOrigin {
@@ -397,18 +421,6 @@
   EdgeOriginKind get kind => EdgeOriginKind.listLengthConstructor;
 }
 
-/// An edge origin used for edges that originated because of a tear-off of
-/// `call` on a function type.
-class CallTearOffOrigin extends EdgeOrigin {
-  CallTearOffOrigin(Source source, AstNode node) : super(source, node);
-
-  @override
-  String get description => 'tear-off of .call';
-
-  @override
-  EdgeOriginKind get kind => EdgeOriginKind.callTearOff;
-}
-
 /// An edge origin used for edges that originated because a literal expression
 /// has a known nullability.
 class LiteralOrigin extends EdgeOrigin {
diff --git a/pkg/nnbd_migration/lib/src/fix_builder.dart b/pkg/nnbd_migration/lib/src/fix_builder.dart
index 1d4748f..687b07b 100644
--- a/pkg/nnbd_migration/lib/src/fix_builder.dart
+++ b/pkg/nnbd_migration/lib/src/fix_builder.dart
@@ -495,6 +495,20 @@
         (_shouldStayNullAware[node] ??= _fixBuilder._shouldStayNullAware(node));
   }
 
+  /// Indicates whether the given [element] is a member of an extension on a
+  /// potentially nullable type (and hence the extension member can be invoked
+  /// on a nullable type without introducing a null check).
+  bool isNullableExtensionMember(Element element) {
+    if (element != null) {
+      var enclosingElement = element.enclosingElement;
+      if (enclosingElement is ExtensionElement) {
+        return _fixBuilder._typeSystem
+            .isPotentiallyNullable(enclosingElement.extendedType);
+      }
+    }
+    return false;
+  }
+
   @override
   bool isPropertyAccessNullAware(PropertyAccess node) {
     return node.isNullAware &&
@@ -705,38 +719,49 @@
             operatorType == TokenType.BANG_EQ) {
           return false;
         } else {
-          return true;
+          return !isNullableExtensionMember(parent.staticElement);
         }
       }
     } else if (parent is PrefixedIdentifier) {
-      if (isDeclaredOnObject(parent.identifier.name)) {
+      if (isDeclaredOnObject(parent.identifier.name) ||
+          isNullableExtensionMember(parent.identifier.staticElement)) {
         return false;
       }
       return identical(node, parent.prefix);
     } else if (parent is PropertyAccess) {
-      if (isDeclaredOnObject(parent.propertyName.name)) {
+      if (isDeclaredOnObject(parent.propertyName.name) ||
+          isNullableExtensionMember(parent.propertyName.staticElement)) {
         return false;
       }
       // TODO(paulberry): what about cascaded?
       return parent.operator.type == TokenType.PERIOD &&
           identical(node, parent.target);
     } else if (parent is MethodInvocation) {
-      if (isDeclaredOnObject(parent.methodName.name)) {
+      if (isDeclaredOnObject(parent.methodName.name) ||
+          isNullableExtensionMember(parent.methodName.staticElement)) {
         return false;
       }
       // TODO(paulberry): what about cascaded?
       return parent.operator.type == TokenType.PERIOD &&
           identical(node, parent.target);
     } else if (parent is IndexExpression) {
-      return identical(node, parent.target);
+      if (identical(node, parent.target)) {
+        return !isNullableExtensionMember(parent.staticElement);
+      } else {
+        return false;
+      }
     } else if (parent is ConditionalExpression) {
       return identical(node, parent.condition);
     } else if (parent is FunctionExpressionInvocation) {
-      return identical(node, parent.function);
+      if (identical(node, parent.function)) {
+        return !isNullableExtensionMember(parent.staticElement);
+      } else {
+        return false;
+      }
     } else if (parent is PrefixExpression) {
       // TODO(paulberry): for prefix increment/decrement, inserting a null check
       // isn't sufficient.
-      return true;
+      return !isNullableExtensionMember(parent.staticElement);
     } else if (parent is ThrowExpression) {
       return true;
     }
diff --git a/pkg/nnbd_migration/test/api_test.dart b/pkg/nnbd_migration/test/api_test.dart
index 2ff78bf..7089d06 100644
--- a/pkg/nnbd_migration/test/api_test.dart
+++ b/pkg/nnbd_migration/test/api_test.dart
@@ -2116,6 +2116,163 @@
     await _checkSingleFileChanges(content, expected, removeViaComments: true);
   }
 
+  Future<void> test_extension_extended_type_nullability_intent() async {
+    var content = '''
+extension E on C {
+  String foo() => this.bar();
+}
+
+class C {
+  String bar() => null;
+}
+
+void test(C c, bool b) {
+  if (b) {
+    c.foo();
+  }
+}
+
+main() {
+  test(null, false);
+}
+''';
+    // The call to `bar` from `foo` should be taken as a demonstration that the
+    // extension E is not intended to apply to nullable types, so the call to
+    // `foo` should be null checked.
+    var expected = '''
+extension E on C {
+  String? foo() => this.bar();
+}
+
+class C {
+  String? bar() => null;
+}
+
+void test(C? c, bool b) {
+  if (b) {
+    c!.foo();
+  }
+}
+
+main() {
+  test(null, false);
+}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
+  Future<void> test_extension_null_check_non_nullable() async {
+    var content = '''
+class C {}
+extension E on C/*!*/ {
+  void m() {}
+}
+void f(C c, bool b) {
+  if (b) {
+    c.m();
+  }
+}
+void g() => f(null, false);
+''';
+    var expected = '''
+class C {}
+extension E on C {
+  void m() {}
+}
+void f(C? c, bool b) {
+  if (b) {
+    c!.m();
+  }
+}
+void g() => f(null, false);
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
+  Future<void> test_extension_null_check_non_nullable_generic() async {
+    var content = '''
+class C {}
+extension E<T extends Object/*!*/> on T/*!*/ {
+  void m() {}
+}
+void f(C c, bool b) {
+  if (b) {
+    c.m();
+  }
+}
+void g() => f(null, false);
+''';
+    var expected = '''
+class C {}
+extension E<T extends Object> on T {
+  void m() {}
+}
+void f(C? c, bool b) {
+  if (b) {
+    c!.m();
+  }
+}
+void g() => f(null, false);
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
+  Future<void> test_extension_null_check_nullable() async {
+    var content = '''
+class C {}
+extension E on C/*?*/ {
+  void m() {}
+}
+void f(C c, bool b) {
+  if (b) {
+    c.m();
+  }
+}
+void g() => f(null, false);
+''';
+    var expected = '''
+class C {}
+extension E on C? {
+  void m() {}
+}
+void f(C? c, bool b) {
+  if (b) {
+    c.m();
+  }
+}
+void g() => f(null, false);
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
+  Future<void> test_extension_null_check_nullable_generic() async {
+    var content = '''
+class C {}
+extension E<T extends Object/*?*/> on T/*!*/ {
+  void m() {}
+}
+void f(C c, bool b) {
+  if (b) {
+    c.m();
+  }
+}
+void g() => f(null, false);
+''';
+    var expected = '''
+class C {}
+extension E<T extends Object?> on T {
+  void m() {}
+}
+void f(C? c, bool b) {
+  if (b) {
+    c.m();
+  }
+}
+void g() => f(null, false);
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
   Future<void> test_extension_null_check_target() async {
     var content = '''
 extension E on int/*!*/ {
@@ -2218,7 +2375,6 @@
     await _checkSingleFileChanges(content, expected);
   }
 
-  @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/40023')
   Future<void> test_extension_nullableOnType_viaImplicitInvocation() async {
     var content = '''
 class C {}
diff --git a/pkg/nnbd_migration/test/edge_builder_test.dart b/pkg/nnbd_migration/test/edge_builder_test.dart
index e943de9..9558d4e 100644
--- a/pkg/nnbd_migration/test/edge_builder_test.dart
+++ b/pkg/nnbd_migration/test/edge_builder_test.dart
@@ -2952,6 +2952,87 @@
     // adding assertion(s).
   }
 
+  Future<void> test_extension_this_non_null_intent_explicit_direct() async {
+    await analyze('''
+extension on int {
+  f() => g(this);
+}
+void g(int i) {}
+''');
+    assertEdge(decoratedTypeAnnotation('int {').node,
+        decoratedTypeAnnotation('int i').node,
+        hard: true);
+  }
+
+  Future<void> test_extension_this_non_null_intent_explicit_method() async {
+    await analyze('''
+extension on int {
+  f() => this.abs();
+}
+''');
+    assertEdge(decoratedTypeAnnotation('int').node, never, hard: true);
+  }
+
+  Future<void>
+      test_extension_this_non_null_intent_explicit_property_get() async {
+    await analyze('''
+extension on int {
+  f() => this.isEven;
+}
+''');
+    assertEdge(decoratedTypeAnnotation('int').node, never, hard: true);
+  }
+
+  Future<void>
+      test_extension_this_non_null_intent_explicit_property_set() async {
+    await analyze('''
+class C {
+  int x;
+}
+extension on C /*reference*/ {
+  f() {
+    this.x = 0;
+  }
+}
+''');
+    assertEdge(decoratedTypeAnnotation('C /*reference*/').node, never,
+        hard: true);
+  }
+
+  Future<void> test_extension_this_non_null_intent_implicit_method() async {
+    await analyze('''
+extension on int {
+  f() => abs();
+}
+''');
+    assertEdge(decoratedTypeAnnotation('int').node, never, hard: true);
+  }
+
+  Future<void> test_extension_this_non_null_intent_implicit_property() async {
+    await analyze('''
+extension on int {
+  f() => isEven;
+}
+''');
+    assertEdge(decoratedTypeAnnotation('int').node, never, hard: true);
+  }
+
+  Future<void>
+      test_extension_this_non_null_intent_implicit_property_set() async {
+    await analyze('''
+class C {
+  int x;
+}
+extension on C /*reference*/ {
+  f() {
+    x = 0;
+  }
+}
+''');
+    assertEdge(decoratedTypeAnnotation('C /*reference*/').node, never,
+        hard: true);
+  }
+
   Future<void> test_field_final_does_not_override_setter() async {
     await analyze('''
 abstract class A {
@@ -7712,11 +7793,11 @@
 }
 ''');
     expect(
-        assertEdge(anyNode, decoratedTypeAnnotation('int f1').node, hard: false)
+        assertEdge(anyNode, decoratedTypeAnnotation('int f1').node, hard: true)
             .sourceNode,
         isNot(never));
     expect(
-        assertEdge(anyNode, decoratedTypeAnnotation('int f2').node, hard: false)
+        assertEdge(anyNode, decoratedTypeAnnotation('int f2').node, hard: true)
             .sourceNode,
         never);
     expect(hasNullCheckHint(findNode.this_('this/*!*/')), isTrue);
diff --git a/pkg/nnbd_migration/test/fix_builder_test.dart b/pkg/nnbd_migration/test/fix_builder_test.dart
index 7989905..3d11cdf 100644
--- a/pkg/nnbd_migration/test/fix_builder_test.dart
+++ b/pkg/nnbd_migration/test/fix_builder_test.dart
@@ -946,6 +946,32 @@
     visitSubexpression(findNode.binary('=='), 'bool');
   }
 
+  Future<void> test_binaryExpression_extensionMember_allowsNull() async {
+    await analyze('''
+class C {}
+extension E on C/*?*/ {
+  void operator+(C/*!*/ other) {}
+}
+f(C/*?*/ c) => c + c;
+''');
+    var binaryExpression = findNode.binary('c + c');
+    visitSubexpression(binaryExpression, 'void',
+        changes: {binaryExpression.rightOperand: isNullCheck});
+  }
+
+  Future<void> test_binaryExpression_extensionMember_disallowsNull() async {
+    await analyze('''
+class C {}
+extension E on C/*!*/ {
+  void operator+(C/*!*/ other) {}
+}
+f(C/*?*/ c) => c + c;
+''');
+    var binaryExpression = findNode.binary('c + c');
+    visitSubexpression(binaryExpression, 'void',
+        changes: {binaryExpression.leftOperand: isNullCheck});
+  }
+
   Future<void> test_binaryExpression_question_question() async {
     await analyze('''
 _f(int/*?*/ x, double/*?*/ y) {
@@ -1390,6 +1416,35 @@
     visitSubexpression(findNode.functionExpressionInvocation('d('), 'dynamic');
   }
 
+  Future<void>
+      test_functionExpressionInvocation_extensionMember_allowsNull() async {
+    await analyze('''
+class C {}
+extension E on C/*?*/ {
+  void call() {}
+}
+f(C/*?*/ c) => c();
+''');
+    var functoinExpressionInvocation =
+        findNode.functionExpressionInvocation('c()');
+    visitSubexpression(functoinExpressionInvocation, 'void');
+  }
+
+  Future<void>
+      test_functionExpressionInvocation_extensionMember_disallowsNull() async {
+    await analyze('''
+class C {}
+extension E on C/*!*/ {
+  void call() {}
+}
+f(C/*?*/ c) => c();
+''');
+    var functionExpressionInvocation =
+        findNode.functionExpressionInvocation('c()');
+    visitSubexpression(functionExpressionInvocation, 'void',
+        changes: {functionExpressionInvocation.function: isNullCheck});
+  }
+
   Future<void> test_functionExpressionInvocation_function_checked() async {
     await analyze('''
 _f(Function/*?*/ func) => func();
@@ -1660,6 +1715,31 @@
     visitSubexpression(findNode.index('d[i]'), 'dynamic');
   }
 
+  Future<void> test_indexExpression_extensionMember_allowsNull() async {
+    await analyze('''
+class C {}
+extension E on C/*?*/ {
+  int operator[](int index) => 0;
+}
+f(C/*?*/ c) => c[0];
+''');
+    var indexExpression = findNode.index('c[0]');
+    visitSubexpression(indexExpression, 'int');
+  }
+
+  Future<void> test_indexExpression_extensionMember_disallowsNull() async {
+    await analyze('''
+class C {}
+extension E on C/*!*/ {
+  int operator[](int index) => 0;
+}
+f(C/*?*/ c) => c[0];
+''');
+    var indexExpression = findNode.index('c[0]');
+    visitSubexpression(indexExpression, 'int',
+        changes: {indexExpression.target: isNullCheck});
+  }
+
   Future<void> test_indexExpression_simple() async {
     await analyze('''
 class _C {
@@ -1931,6 +2011,40 @@
     visitSubexpression(findNode.methodInvocation('d.f'), 'dynamic');
   }
 
+  Future<void> test_methodInvocation_extensionMember_allowsNull() async {
+    await analyze('''
+class C {}
+extension E on C/*?*/ {
+  void foo() {}
+}
+f(C/*?*/ c) => c.foo();
+''');
+    var methodInvocation = findNode.methodInvocation('c.foo');
+    visitSubexpression(methodInvocation, 'void');
+  }
+
+  Future<void> test_methodInvocation_extensionMember_disallowsNull() async {
+    await analyze('''
+class C {}
+extension E on C/*!*/ {
+  void foo() {}
+}
+f(C/*?*/ c) => c.foo();
+''');
+    var methodInvocation = findNode.methodInvocation('c.foo');
+    visitSubexpression(methodInvocation, 'void',
+        changes: {methodInvocation.target: isNullCheck});
+  }
+
+  Future<void> test_methodInvocation_function_call_nullCheck() async {
+    await analyze('''
+f(void Function()/*?*/ x) => x.call();
+''');
+    var methodInvocation = findNode.methodInvocation('x.call');
+    visitSubexpression(methodInvocation, 'void',
+        changes: {methodInvocation.target: isNullCheck});
+  }
+
   Future<void> test_methodInvocation_namedParameter() async {
     await analyze('''
 abstract class _C {
@@ -2474,6 +2588,31 @@
     visitSubexpression(findNode.prefixed('d.x'), 'dynamic');
   }
 
+  Future<void> test_prefixedIdentifier_extensionMember_allowsNull() async {
+    await analyze('''
+class C {}
+extension E on C/*?*/ {
+  int get foo => 0;
+}
+f(C/*?*/ c) => c.foo;
+''');
+    var prefixedIdentifier = findNode.prefixed('c.foo');
+    visitSubexpression(prefixedIdentifier, 'int');
+  }
+
+  Future<void> test_prefixedIdentifier_extensionMember_disallowsNull() async {
+    await analyze('''
+class C {}
+extension E on C/*!*/ {
+  int get foo => 0;
+}
+f(C/*?*/ c) => c.foo;
+''');
+    var prefixedIdentifier = findNode.prefixed('c.foo');
+    visitSubexpression(prefixedIdentifier, 'int',
+        changes: {prefixedIdentifier.prefix: isNullCheck});
+  }
+
   Future<void> test_prefixedIdentifier_field_nonNullable() async {
     await analyze('''
 class _C {
@@ -2643,6 +2782,31 @@
         changes: {findNode.simple('c);'): isNullCheck});
   }
 
+  Future<void> test_prefixExpression_extensionMember_allowsNull() async {
+    await analyze('''
+class C {}
+extension E on C/*?*/ {
+  C operator-() => C();
+}
+f(C/*?*/ c) => -c;
+''');
+    var prefixExpression = findNode.prefix('-c');
+    visitSubexpression(prefixExpression, 'C');
+  }
+
+  Future<void> test_prefixExpression_extensionMember_disallowsNull() async {
+    await analyze('''
+class C {}
+extension E on C/*!*/ {
+  C operator-() => C();
+}
+f(C/*?*/ c) => -c;
+''');
+    var prefixExpression = findNode.prefix('-c');
+    visitSubexpression(prefixExpression, 'C',
+        changes: {prefixExpression.operand: isNullCheck});
+  }
+
   Future<void> test_prefixExpression_increment_undoes_promotion() async {
     await analyze('''
 abstract class _C {
@@ -2768,6 +2932,31 @@
     visitSubexpression(findNode.propertyAccess('(d).x'), 'dynamic');
   }
 
+  Future<void> test_propertyAccess_extensionMember_allowsNull() async {
+    await analyze('''
+class C {}
+extension E on C/*?*/ {
+  int get foo => 0;
+}
+f(C/*?*/ Function() g) => g().foo;
+''');
+    var propertyAccess = findNode.propertyAccess('g().foo');
+    visitSubexpression(propertyAccess, 'int');
+  }
+
+  Future<void> test_propertyAccess_extensionMember_disallowsNull() async {
+    await analyze('''
+class C {}
+extension E on C/*!*/ {
+  int get foo => 0;
+}
+f(C/*?*/ Function() g) => g().foo;
+''');
+    var propertyAccess = findNode.propertyAccess('g().foo');
+    visitSubexpression(propertyAccess, 'int',
+        changes: {propertyAccess.target: isNullCheck});
+  }
+
   Future<void> test_propertyAccess_field_nonNullable() async {
     await analyze('''
 class _C {
diff --git a/tools/VERSION b/tools/VERSION
index 6e464de..fc35def 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 12
 PATCH 0
-PRERELEASE 248
+PRERELEASE 249
 PRERELEASE_PATCH 0
\ No newline at end of file