Version 2.6.0-dev.8.1

* Cherry-pick dee702264b4ab6f6b634b2e346de5ac7ea08b042 to dev
* Cherry-pick 9f1b0fe102c0ad4599b695974621530f07684290 to dev
* Cherry-pick 30719b37a9397cc38610e71a804236ec314535ec to dev
* Cherry-pick d2b39d1a07a18572bdafedb79ce68ef5bf9e64bf to dev
* Cherry-pick c19adc635542004d2c2cdac55b447e7175391bf8 to dev
* Cherry-pick 8d8faa7dea152cce83681bad4467dac87a30f7de to dev
* Cherry-pick a9fc9f7fd4bbd9c211fbe2b1329dce82e0c1d0a2 to dev
diff --git a/pkg/analyzer/lib/src/generated/ffi_verifier.dart b/pkg/analyzer/lib/src/generated/ffi_verifier.dart
index 9e6b40d..467f542 100644
--- a/pkg/analyzer/lib/src/generated/ffi_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/ffi_verifier.dart
@@ -488,7 +488,8 @@
       if (_isPointerInterfaceType(nativeType)) {
         final nativeArgumentType = nativeType.typeArguments.single;
         return _isValidFfiNativeType(nativeArgumentType, true) ||
-            _isStructClass(nativeArgumentType);
+            _isStructClass(nativeArgumentType) ||
+            _isNativeTypeInterfaceType(nativeArgumentType);
       }
     } else if (nativeType is FunctionType) {
       return _isValidFfiNativeFunctionType(nativeType);
@@ -539,6 +540,17 @@
     return false;
   }
 
+  // Returns `true` iff [nativeType] is a `ffi.NativeType` type.
+  bool _isNativeTypeInterfaceType(DartType nativeType) {
+    if (nativeType is InterfaceType) {
+      final element = nativeType.element;
+      if (element.library.name == 'dart.ffi') {
+        return element.name == 'NativeType';
+      }
+    }
+    return false;
+  }
+
   // Returns `true` iff [nativeType] is a struct type.
   _isStructClass(DartType nativeType) {
     if (nativeType is InterfaceType) {
diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
index 8f24710..b99e4e9 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -1496,53 +1496,73 @@
     if (optional(".", token) ||
         optional("..", token) ||
         optional("?..", token)) {
-      return doDotOrCascadeExpression(token);
+      doDotOrCascadeExpression(token);
+    } else if (optional("&&", token) || optional("||", token)) {
+      doLogicalExpression(token);
+    } else if (optional("??", token)) {
+      doIfNull(token);
+    } else if (optional("?.", token)) {
+      doIfNotNull(token);
+    } else {
+      doBinaryExpression(token);
     }
-    if (optional("&&", token) || optional("||", token)) {
-      return doLogicalExpression(token);
-    }
-    if (optional("??", token)) return doIfNull(token);
-    if (optional("?.", token)) return doIfNotNull(token);
-    Expression argument = popForValue();
-    Object receiver = pop();
-    bool isSuper = false;
-    if (receiver is ThisAccessGenerator && receiver.isSuper) {
-      ThisAccessGenerator thisAccessorReceiver = receiver;
-      isSuper = true;
-      receiver = forest.createThisExpression(thisAccessorReceiver.fileOffset);
-    }
-    push(buildBinaryOperator(toValue(receiver), token, argument, isSuper));
   }
 
-  Expression buildBinaryOperator(
-      Expression a, Token token, Expression b, bool isSuper) {
+  void doBinaryExpression(Token token) {
+    assert(checkState(token, <ValueKind>[
+      unionOfKinds([ValueKind.Expression, ValueKind.Generator]),
+      unionOfKinds([ValueKind.Expression, ValueKind.Generator]),
+    ]));
+    Expression right = popForValue();
+    Object left = pop();
     bool negate = false;
     String operator = token.stringValue;
     if (identical("!=", operator)) {
       operator = "==";
       negate = true;
     }
+    int fileOffset = offsetForToken(token);
+    Name name = new Name(operator);
     if (!isBinaryOperator(operator) && !isMinusOperator(operator)) {
       if (isUserDefinableOperator(operator)) {
-        return buildProblem(
-            fasta.templateNotBinaryOperator.withArguments(token),
-            token.charOffset,
-            token.length);
+        push(buildProblem(fasta.templateNotBinaryOperator.withArguments(token),
+            token.charOffset, token.length));
       } else {
-        return buildProblem(fasta.templateInvalidOperator.withArguments(token),
-            token.charOffset, token.length);
+        push(buildProblem(fasta.templateInvalidOperator.withArguments(token),
+            token.charOffset, token.length));
       }
+    } else if (left is ExplicitExtensionAccessGenerator) {
+      // TODO(johnniwinther): Use this code path for all generators. Currently
+      // TypeUseGenerator starts complaining about `Map<` not being a method
+      // instead of `<` not defined on `Type`.
+      Object result = left.buildPropertyAccess(
+          new SendAccessGenerator(this, token, name,
+              forest.createArguments(fileOffset, <Expression>[right]),
+              isPotentiallyConstant: true),
+          fileOffset,
+          false);
+      push(negate ? forest.createNot(fileOffset, toValue(result)) : result);
     } else {
+      bool isSuper = false;
+      Expression leftValue;
+      if (left is ThisAccessGenerator && left.isSuper) {
+        ThisAccessGenerator thisAccessorReceiver = left;
+        isSuper = true;
+        leftValue =
+            forest.createThisExpression(thisAccessorReceiver.fileOffset);
+      } else {
+        leftValue = toValue(left);
+      }
       Expression result = buildMethodInvocation(
-          a,
-          new Name(operator),
-          forest.createArguments(token.charOffset, <Expression>[b]),
+          leftValue,
+          name,
+          forest.createArguments(fileOffset, <Expression>[right]),
           token.charOffset,
           // This *could* be a constant expression, we can't know without
-          // evaluating [a] and [b].
+          // evaluating [left] and [right].
           isConstantExpression: !isSuper,
           isSuper: isSuper);
-      return negate ? forest.createNot(token.charOffset, result) : result;
+      push(negate ? forest.createNot(fileOffset, result) : result);
     }
   }
 
@@ -3341,29 +3361,51 @@
 
   @override
   void handleUnaryPrefixExpression(Token token) {
+    assert(checkState(token, <ValueKind>[
+      unionOfKinds(<ValueKind>[
+        ValueKind.Expression,
+        ValueKind.Generator,
+      ]),
+    ]));
     debugEvent("UnaryPrefixExpression");
     Object receiver = pop();
     if (optional("!", token)) {
       push(forest.createNot(offsetForToken(token), toValue(receiver)));
     } else {
       String operator = token.stringValue;
-      Expression receiverValue;
       if (optional("-", token)) {
         operator = "unary-";
       }
-      bool isSuper = false;
-      if (receiver is ThisAccessGenerator && receiver.isSuper) {
-        isSuper = true;
-        receiverValue = forest.createThisExpression(receiver.fileOffset);
+      int fileOffset = offsetForToken(token);
+      Name name = new Name(operator);
+      if (receiver is ExplicitExtensionAccessGenerator) {
+        // TODO(johnniwinther): Use this code path for all generators. Currently
+        // TypeUseGenerator starts complaining about `-Map` not being a method
+        // instead of `unary-` not defined on `Type`.
+        push(receiver.buildPropertyAccess(
+            new SendAccessGenerator(
+                this, token, name, forest.createArgumentsEmpty(fileOffset),
+                isPotentiallyConstant: true),
+            fileOffset,
+            false));
       } else {
-        receiverValue = toValue(receiver);
+        bool isSuper = false;
+        Expression receiverValue;
+        if (receiver is ThisAccessGenerator && receiver.isSuper) {
+          ThisAccessGenerator thisAccessorReceiver = receiver;
+          isSuper = true;
+          receiverValue =
+              forest.createThisExpression(thisAccessorReceiver.fileOffset);
+        } else {
+          receiverValue = toValue(receiver);
+        }
+        push(buildMethodInvocation(receiverValue, name,
+            forest.createArgumentsEmpty(fileOffset), fileOffset,
+            // This *could* be a constant expression, we can't know without
+            // evaluating [receiver].
+            isConstantExpression: !isSuper,
+            isSuper: isSuper));
       }
-      push(buildMethodInvocation(receiverValue, new Name(operator),
-          forest.createArgumentsEmpty(noLocation), token.charOffset,
-          // This *could* be a constant expression, we can't know without
-          // evaluating [receiver].
-          isConstantExpression: !isSuper,
-          isSuper: isSuper));
     }
   }
 
diff --git a/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart b/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
index 05fc8ed..9840652 100644
--- a/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
@@ -14,6 +14,7 @@
 import '../builder/builder.dart';
 import '../builder/declaration_builder.dart';
 import '../builder/extension_builder.dart';
+import '../builder/function_builder.dart';
 import '../builder/invalid_type_declaration_builder.dart';
 import '../builder/member_builder.dart';
 import '../builder/named_type_builder.dart';
@@ -230,7 +231,8 @@
     if (send is SendAccessGenerator) {
       return _helper.buildMethodInvocation(buildSimpleRead(), send.name,
           send.arguments, offsetForToken(send.token),
-          isNullAware: isNullAware);
+          isNullAware: isNullAware,
+          isConstantExpression: send.isPotentiallyConstant);
     } else {
       if (_helper.constantContext != ConstantContext.none &&
           send.name != lengthName) {
@@ -1645,7 +1647,8 @@
       this.extensionThis,
       this.extensionTypeParameters)
       : assert(targetName != null),
-        assert(readTarget != null || writeTarget != null),
+        assert(
+            readTarget != null || invokeTarget != null || writeTarget != null),
         assert(extensionThis != null),
         super(helper, token);
 
@@ -1682,6 +1685,9 @@
         MemberBuilder procedureBuilder = getterBuilder;
         readTarget = procedureBuilder.extensionTearOff;
         invokeTarget = procedureBuilder.procedure;
+      } else if (getterBuilder is FunctionBuilder && getterBuilder.isOperator) {
+        assert(!getterBuilder.isStatic);
+        invokeTarget = getterBuilder.target;
       }
     }
     Procedure writeTarget;
@@ -1956,7 +1962,8 @@
       this.extensionTypeParameterCount,
       {this.isNullAware})
       : assert(targetName != null),
-        assert(readTarget != null || writeTarget != null),
+        assert(
+            readTarget != null || invokeTarget != null || writeTarget != null),
         assert(receiver != null),
         assert(isNullAware != null),
         super(helper, token);
@@ -1995,6 +2002,11 @@
         readTarget = procedureBuilder.extensionTearOff;
         invokeTarget = procedureBuilder.procedure;
         targetName = procedureBuilder.name;
+      } else if (getterBuilder is FunctionBuilder && getterBuilder.isOperator) {
+        assert(!getterBuilder.isStatic);
+        MemberBuilder memberBuilder = getterBuilder;
+        invokeTarget = memberBuilder.member;
+        targetName = memberBuilder.name;
       } else {
         return unhandled(
             "${getterBuilder.runtimeType}",
@@ -4386,8 +4398,11 @@
   @override
   final Arguments arguments;
 
+  final bool isPotentiallyConstant;
+
   SendAccessGenerator(
-      ExpressionGeneratorHelper helper, Token token, this.name, this.arguments)
+      ExpressionGeneratorHelper helper, Token token, this.name, this.arguments,
+      {this.isPotentiallyConstant: false})
       : super(helper, token) {
     assert(arguments != null);
   }
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
index 35f613a..af09eba 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
@@ -1838,7 +1838,7 @@
             receiverType != null,
             "No receiver type provided for implicit extension member "
             "invocation.");
-        inferredType = receiverType;
+        return;
       } else {
         ExpressionInferenceResult result = inferExpression(
             expression,
diff --git a/pkg/front_end/test/spell_checking_list_common.txt b/pkg/front_end/test/spell_checking_list_common.txt
index 58d08a6..188bf4d 100644
--- a/pkg/front_end/test/spell_checking_list_common.txt
+++ b/pkg/front_end/test/spell_checking_list_common.txt
@@ -484,6 +484,7 @@
 compiles
 compiling
 complain
+complaining
 complete
 completed
 completely
@@ -1168,6 +1169,7 @@
 generating
 generative
 generator
+generators
 generic
 generics
 get
diff --git a/pkg/front_end/testcases/extensions/issue38915.dart b/pkg/front_end/testcases/extensions/issue38915.dart
new file mode 100644
index 0000000..5d4752d
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/issue38915.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2019, 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 Class {}
+
+extension Extension on Class {
+  void method1({bool b = false, String s = ', '}) => null;
+  void method2([bool b = false, String s = ', ']) => null;
+  void method3(int i, {bool b = false, String s = ', '}) {}
+  void method4(int i, [bool b = false, String s = ', ']) {}
+}
+
+main() {
+  var c = new Class();
+  c.method1();
+  c.method1(s: 'foo');
+  c.method1(b: true);
+  c.method1(b: true, s: 'foo');
+  c.method1(s: 'foo', b: true);
+  c.method2();
+  c.method2(true);
+  c.method2(true, 'foo');
+  c.method3(42);
+  c.method3(42, s: 'foo');
+  c.method3(42, b: true);
+  c.method3(42, b: true, s: 'foo');
+  c.method3(42, s: 'foo', b: true);
+  c.method4(42);
+  c.method4(42, true);
+  c.method4(42, true, 'foo');
+}
diff --git a/pkg/front_end/testcases/extensions/issue38915.dart.outline.expect b/pkg/front_end/testcases/extensions/issue38915.dart.outline.expect
new file mode 100644
index 0000000..56b644e
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/issue38915.dart.outline.expect
@@ -0,0 +1,36 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  synthetic constructor •() → self::Class*
+    ;
+}
+extension Extension on self::Class* {
+  method method1 = self::Extension|method1;
+  tearoff method1 = self::Extension|get#method1;
+  method method2 = self::Extension|method2;
+  tearoff method2 = self::Extension|get#method2;
+  method method3 = self::Extension|method3;
+  tearoff method3 = self::Extension|get#method3;
+  method method4 = self::Extension|method4;
+  tearoff method4 = self::Extension|get#method4;
+}
+static method Extension|method1(final self::Class* #this, {core::bool* b, core::String* s}) → void
+  ;
+static method Extension|get#method1(final self::Class* #this) → ({b: core::bool*, s: core::String*}) →* void
+  return ({core::bool* b, core::String* s}) → void => self::Extension|method1(#this, b: b, s: s);
+static method Extension|method2(final self::Class* #this, [core::bool* b, core::String* s]) → void
+  ;
+static method Extension|get#method2(final self::Class* #this) → ([core::bool*, core::String*]) →* void
+  return ([core::bool* b, core::String* s]) → void => self::Extension|method2(#this, b, s);
+static method Extension|method3(final self::Class* #this, core::int* i, {core::bool* b, core::String* s}) → void
+  ;
+static method Extension|get#method3(final self::Class* #this) → (core::int*, {b: core::bool*, s: core::String*}) →* void
+  return (core::int* i, {core::bool* b, core::String* s}) → void => self::Extension|method3(#this, i, b: b, s: s);
+static method Extension|method4(final self::Class* #this, core::int* i, [core::bool* b, core::String* s]) → void
+  ;
+static method Extension|get#method4(final self::Class* #this) → (core::int*, [core::bool*, core::String*]) →* void
+  return (core::int* i, [core::bool* b, core::String* s]) → void => self::Extension|method4(#this, i, b, s);
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/extensions/issue38915.dart.strong.expect b/pkg/front_end/testcases/extensions/issue38915.dart.strong.expect
new file mode 100644
index 0000000..fdc8d05
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/issue38915.dart.strong.expect
@@ -0,0 +1,57 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  synthetic constructor •() → self::Class*
+    : super core::Object::•()
+    ;
+}
+extension Extension on self::Class* {
+  method method1 = self::Extension|method1;
+  tearoff method1 = self::Extension|get#method1;
+  method method2 = self::Extension|method2;
+  tearoff method2 = self::Extension|get#method2;
+  method method3 = self::Extension|method3;
+  tearoff method3 = self::Extension|get#method3;
+  method method4 = self::Extension|method4;
+  tearoff method4 = self::Extension|get#method4;
+}
+static method Extension|method1(final self::Class* #this, {core::bool* b = #C1, core::String* s = #C2}) → void
+  return null;
+static method Extension|get#method1(final self::Class* #this) → ({b: core::bool*, s: core::String*}) →* void
+  return ({core::bool* b = #C1, core::String* s = #C2}) → void => self::Extension|method1(#this, b: b, s: s);
+static method Extension|method2(final self::Class* #this, [core::bool* b = #C1, core::String* s = #C2]) → void
+  return null;
+static method Extension|get#method2(final self::Class* #this) → ([core::bool*, core::String*]) →* void
+  return ([core::bool* b = #C1, core::String* s = #C2]) → void => self::Extension|method2(#this, b, s);
+static method Extension|method3(final self::Class* #this, core::int* i, {core::bool* b = #C1, core::String* s = #C2}) → void {}
+static method Extension|get#method3(final self::Class* #this) → (core::int*, {b: core::bool*, s: core::String*}) →* void
+  return (core::int* i, {core::bool* b = #C1, core::String* s = #C2}) → void => self::Extension|method3(#this, i, b: b, s: s);
+static method Extension|method4(final self::Class* #this, core::int* i, [core::bool* b = #C1, core::String* s = #C2]) → void {}
+static method Extension|get#method4(final self::Class* #this) → (core::int*, [core::bool*, core::String*]) →* void
+  return (core::int* i, [core::bool* b = #C1, core::String* s = #C2]) → void => self::Extension|method4(#this, i, b, s);
+static method main() → dynamic {
+  self::Class* c = new self::Class::•();
+  self::Extension|method1(c);
+  self::Extension|method1(c, s: "foo");
+  self::Extension|method1(c, b: true);
+  self::Extension|method1(c, b: true, s: "foo");
+  self::Extension|method1(c, s: "foo", b: true);
+  self::Extension|method2(c);
+  self::Extension|method2(c, true);
+  self::Extension|method2(c, true, "foo");
+  self::Extension|method3(c, 42);
+  self::Extension|method3(c, 42, s: "foo");
+  self::Extension|method3(c, 42, b: true);
+  self::Extension|method3(c, 42, b: true, s: "foo");
+  self::Extension|method3(c, 42, s: "foo", b: true);
+  self::Extension|method4(c, 42);
+  self::Extension|method4(c, 42, true);
+  self::Extension|method4(c, 42, true, "foo");
+}
+
+constants  {
+  #C1 = false
+  #C2 = ", "
+}
diff --git a/pkg/front_end/testcases/extensions/issue38915.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/issue38915.dart.strong.transformed.expect
new file mode 100644
index 0000000..fdc8d05
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/issue38915.dart.strong.transformed.expect
@@ -0,0 +1,57 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  synthetic constructor •() → self::Class*
+    : super core::Object::•()
+    ;
+}
+extension Extension on self::Class* {
+  method method1 = self::Extension|method1;
+  tearoff method1 = self::Extension|get#method1;
+  method method2 = self::Extension|method2;
+  tearoff method2 = self::Extension|get#method2;
+  method method3 = self::Extension|method3;
+  tearoff method3 = self::Extension|get#method3;
+  method method4 = self::Extension|method4;
+  tearoff method4 = self::Extension|get#method4;
+}
+static method Extension|method1(final self::Class* #this, {core::bool* b = #C1, core::String* s = #C2}) → void
+  return null;
+static method Extension|get#method1(final self::Class* #this) → ({b: core::bool*, s: core::String*}) →* void
+  return ({core::bool* b = #C1, core::String* s = #C2}) → void => self::Extension|method1(#this, b: b, s: s);
+static method Extension|method2(final self::Class* #this, [core::bool* b = #C1, core::String* s = #C2]) → void
+  return null;
+static method Extension|get#method2(final self::Class* #this) → ([core::bool*, core::String*]) →* void
+  return ([core::bool* b = #C1, core::String* s = #C2]) → void => self::Extension|method2(#this, b, s);
+static method Extension|method3(final self::Class* #this, core::int* i, {core::bool* b = #C1, core::String* s = #C2}) → void {}
+static method Extension|get#method3(final self::Class* #this) → (core::int*, {b: core::bool*, s: core::String*}) →* void
+  return (core::int* i, {core::bool* b = #C1, core::String* s = #C2}) → void => self::Extension|method3(#this, i, b: b, s: s);
+static method Extension|method4(final self::Class* #this, core::int* i, [core::bool* b = #C1, core::String* s = #C2]) → void {}
+static method Extension|get#method4(final self::Class* #this) → (core::int*, [core::bool*, core::String*]) →* void
+  return (core::int* i, [core::bool* b = #C1, core::String* s = #C2]) → void => self::Extension|method4(#this, i, b, s);
+static method main() → dynamic {
+  self::Class* c = new self::Class::•();
+  self::Extension|method1(c);
+  self::Extension|method1(c, s: "foo");
+  self::Extension|method1(c, b: true);
+  self::Extension|method1(c, b: true, s: "foo");
+  self::Extension|method1(c, s: "foo", b: true);
+  self::Extension|method2(c);
+  self::Extension|method2(c, true);
+  self::Extension|method2(c, true, "foo");
+  self::Extension|method3(c, 42);
+  self::Extension|method3(c, 42, s: "foo");
+  self::Extension|method3(c, 42, b: true);
+  self::Extension|method3(c, 42, b: true, s: "foo");
+  self::Extension|method3(c, 42, s: "foo", b: true);
+  self::Extension|method4(c, 42);
+  self::Extension|method4(c, 42, true);
+  self::Extension|method4(c, 42, true, "foo");
+}
+
+constants  {
+  #C1 = false
+  #C2 = ", "
+}
diff --git a/pkg/front_end/testcases/extensions/operators.dart b/pkg/front_end/testcases/extensions/operators.dart
index cbb3b41..6927bfe 100644
--- a/pkg/front_end/testcases/extensions/operators.dart
+++ b/pkg/front_end/testcases/extensions/operators.dart
@@ -39,6 +39,11 @@
 }
 
 main() {
+  implicit();
+  explicit();
+}
+
+implicit() {
   Complex c_m2 = new Complex(-2, 2);
   Complex c_m1 = new Complex(-1, 1);
   Complex c0 = new Complex(0, 0);
@@ -77,8 +82,47 @@
   expect(c0, -c0);
 }
 
+explicit() {
+  Complex c_m2 = new Complex(-2, 2);
+  Complex c_m1 = new Complex(-1, 1);
+  Complex c0 = new Complex(0, 0);
+  Complex c1 = new Complex(1, -1);
+  Complex c2 = new Complex(2, -2);
+
+  expect(c_m2, Operators(c0) + c_m2);
+  expect(c_m2, Operators(c_m2) + c0);
+  expect(c_m2, Operators(c_m1) + c_m1);
+  expect(c_m1, Operators(c0) + c_m1);
+  expect(c_m1, Operators(c_m1) + c0);
+  expect(c0, Operators(c_m2) + c2);
+  expect(c0, Operators(c2) + c_m2);
+  expect(c0, Operators(c_m1) + c1);
+  expect(c0, Operators(c1) + c_m1);
+  expect(c0, Operators(c0) + c0);
+  expect(c1, Operators(c0) + c1);
+  expect(c1, Operators(c1) + c0);
+  expect(c2, Operators(c0) + c2);
+  expect(c2, Operators(c2) + c0);
+  expect(c2, Operators(c1) + c1);
+
+  expect(c_m2, Operators(c0) - c2);
+  expect(c2, Operators(c2) - c0);
+  expect(c_m2, -Operators(c2));
+  expect(c_m1, Operators(c1) - c2);
+  expect(c1, Operators(c2) - c1);
+  expect(c_m1, Operators(c0) - c1);
+  expect(c1, Operators(c1) - c0);
+  expect(c_m1, -Operators(c1));
+  expect(c0, Operators(c2) - c2);
+  expect(c0, Operators(c1) - c1);
+  expect(c0, Operators(c0) - c0);
+  expect(c0, Operators(c_m1) - c_m1);
+  expect(c0, Operators(c_m2) - c_m2);
+  expect(c0, -c0);
+}
+
 expect(expected, actual) {
   if (expected != actual) {
     throw 'Mismatch: expected=$expected, actual=$actual';
   }
-}
\ No newline at end of file
+}
diff --git a/pkg/front_end/testcases/extensions/operators.dart.outline.expect b/pkg/front_end/testcases/extensions/operators.dart.outline.expect
index bfa897a..c38c397 100644
--- a/pkg/front_end/testcases/extensions/operators.dart.outline.expect
+++ b/pkg/front_end/testcases/extensions/operators.dart.outline.expect
@@ -34,5 +34,9 @@
   ;
 static method main() → dynamic
   ;
+static method implicit() → dynamic
+  ;
+static method explicit() → dynamic
+  ;
 static method expect(dynamic expected, dynamic actual) → dynamic
   ;
diff --git a/pkg/front_end/testcases/extensions/operators.dart.strong.expect b/pkg/front_end/testcases/extensions/operators.dart.strong.expect
index 936cc18..3453a24 100644
--- a/pkg/front_end/testcases/extensions/operators.dart.strong.expect
+++ b/pkg/front_end/testcases/extensions/operators.dart.strong.expect
@@ -39,6 +39,46 @@
 static method Operators|unary-(final self::Complex* #this) → self::Complex*
   return #this.{self::Complex::negate}();
 static method main() → dynamic {
+  self::implicit();
+  self::explicit();
+}
+static method implicit() → dynamic {
+  self::Complex* c_m2 = new self::Complex::•(-2.0, 2.0);
+  self::Complex* c_m1 = new self::Complex::•(-1.0, 1.0);
+  self::Complex* c0 = new self::Complex::•(0.0, 0.0);
+  self::Complex* c1 = new self::Complex::•(1.0, -1.0);
+  self::Complex* c2 = new self::Complex::•(2.0, -2.0);
+  self::expect(c_m2, self::Operators|+(c0, c_m2));
+  self::expect(c_m2, self::Operators|+(c_m2, c0));
+  self::expect(c_m2, self::Operators|+(c_m1, c_m1));
+  self::expect(c_m1, self::Operators|+(c0, c_m1));
+  self::expect(c_m1, self::Operators|+(c_m1, c0));
+  self::expect(c0, self::Operators|+(c_m2, c2));
+  self::expect(c0, self::Operators|+(c2, c_m2));
+  self::expect(c0, self::Operators|+(c_m1, c1));
+  self::expect(c0, self::Operators|+(c1, c_m1));
+  self::expect(c0, self::Operators|+(c0, c0));
+  self::expect(c1, self::Operators|+(c0, c1));
+  self::expect(c1, self::Operators|+(c1, c0));
+  self::expect(c2, self::Operators|+(c0, c2));
+  self::expect(c2, self::Operators|+(c2, c0));
+  self::expect(c2, self::Operators|+(c1, c1));
+  self::expect(c_m2, self::Operators|-(c0, c2));
+  self::expect(c2, self::Operators|-(c2, c0));
+  self::expect(c_m2, self::Operators|unary-(c2));
+  self::expect(c_m1, self::Operators|-(c1, c2));
+  self::expect(c1, self::Operators|-(c2, c1));
+  self::expect(c_m1, self::Operators|-(c0, c1));
+  self::expect(c1, self::Operators|-(c1, c0));
+  self::expect(c_m1, self::Operators|unary-(c1));
+  self::expect(c0, self::Operators|-(c2, c2));
+  self::expect(c0, self::Operators|-(c1, c1));
+  self::expect(c0, self::Operators|-(c0, c0));
+  self::expect(c0, self::Operators|-(c_m1, c_m1));
+  self::expect(c0, self::Operators|-(c_m2, c_m2));
+  self::expect(c0, self::Operators|unary-(c0));
+}
+static method explicit() → dynamic {
   self::Complex* c_m2 = new self::Complex::•(-2.0, 2.0);
   self::Complex* c_m1 = new self::Complex::•(-1.0, 1.0);
   self::Complex* c0 = new self::Complex::•(0.0, 0.0);
diff --git a/pkg/front_end/testcases/extensions/operators.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/operators.dart.strong.transformed.expect
index 936cc18..3453a24 100644
--- a/pkg/front_end/testcases/extensions/operators.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/extensions/operators.dart.strong.transformed.expect
@@ -39,6 +39,46 @@
 static method Operators|unary-(final self::Complex* #this) → self::Complex*
   return #this.{self::Complex::negate}();
 static method main() → dynamic {
+  self::implicit();
+  self::explicit();
+}
+static method implicit() → dynamic {
+  self::Complex* c_m2 = new self::Complex::•(-2.0, 2.0);
+  self::Complex* c_m1 = new self::Complex::•(-1.0, 1.0);
+  self::Complex* c0 = new self::Complex::•(0.0, 0.0);
+  self::Complex* c1 = new self::Complex::•(1.0, -1.0);
+  self::Complex* c2 = new self::Complex::•(2.0, -2.0);
+  self::expect(c_m2, self::Operators|+(c0, c_m2));
+  self::expect(c_m2, self::Operators|+(c_m2, c0));
+  self::expect(c_m2, self::Operators|+(c_m1, c_m1));
+  self::expect(c_m1, self::Operators|+(c0, c_m1));
+  self::expect(c_m1, self::Operators|+(c_m1, c0));
+  self::expect(c0, self::Operators|+(c_m2, c2));
+  self::expect(c0, self::Operators|+(c2, c_m2));
+  self::expect(c0, self::Operators|+(c_m1, c1));
+  self::expect(c0, self::Operators|+(c1, c_m1));
+  self::expect(c0, self::Operators|+(c0, c0));
+  self::expect(c1, self::Operators|+(c0, c1));
+  self::expect(c1, self::Operators|+(c1, c0));
+  self::expect(c2, self::Operators|+(c0, c2));
+  self::expect(c2, self::Operators|+(c2, c0));
+  self::expect(c2, self::Operators|+(c1, c1));
+  self::expect(c_m2, self::Operators|-(c0, c2));
+  self::expect(c2, self::Operators|-(c2, c0));
+  self::expect(c_m2, self::Operators|unary-(c2));
+  self::expect(c_m1, self::Operators|-(c1, c2));
+  self::expect(c1, self::Operators|-(c2, c1));
+  self::expect(c_m1, self::Operators|-(c0, c1));
+  self::expect(c1, self::Operators|-(c1, c0));
+  self::expect(c_m1, self::Operators|unary-(c1));
+  self::expect(c0, self::Operators|-(c2, c2));
+  self::expect(c0, self::Operators|-(c1, c1));
+  self::expect(c0, self::Operators|-(c0, c0));
+  self::expect(c0, self::Operators|-(c_m1, c_m1));
+  self::expect(c0, self::Operators|-(c_m2, c_m2));
+  self::expect(c0, self::Operators|unary-(c0));
+}
+static method explicit() → dynamic {
   self::Complex* c_m2 = new self::Complex::•(-2.0, 2.0);
   self::Complex* c_m1 = new self::Complex::•(-1.0, 1.0);
   self::Complex* c0 = new self::Complex::•(0.0, 0.0);
diff --git a/pkg/front_end/testcases/text_serialization.status b/pkg/front_end/testcases/text_serialization.status
index c15719f..d617f89 100644
--- a/pkg/front_end/testcases/text_serialization.status
+++ b/pkg/front_end/testcases/text_serialization.status
@@ -47,6 +47,7 @@
 extensions/issue38745: TextSerializationFailure
 extensions/issue38750: TextSerializationFailure
 extensions/issue38755: TextSerializationFailure
+extensions/issue38915: TextSerializationFailure
 extensions/nested_on_types: TextSerializationFailure
 extensions/null_aware: TextSerializationFailure
 extensions/on_function_type: TextSerializationFailure
diff --git a/pkg/vm/lib/transformations/ffi_use_sites.dart b/pkg/vm/lib/transformations/ffi_use_sites.dart
index 3cb0dfc..4bf6586 100644
--- a/pkg/vm/lib/transformations/ffi_use_sites.dart
+++ b/pkg/vm/lib/transformations/ffi_use_sites.dart
@@ -344,17 +344,18 @@
   }
 
   void _ensureNativeTypeToDartType(
-      DartType containerTypeArg, DartType elementType, Expression node,
+      DartType nativeType, DartType dartType, Expression node,
       {bool allowStructs: false}) {
-    final DartType shouldBeElementType =
-        convertNativeTypeToDartType(containerTypeArg, allowStructs);
-    if (elementType == shouldBeElementType) return;
-    // We disable implicit downcasts, they will go away when NNBD lands.
-    if (env.isSubtypeOf(elementType, shouldBeElementType,
-        SubtypeCheckMode.ignoringNullabilities)) return;
+    final DartType correspondingDartType =
+        convertNativeTypeToDartType(nativeType, allowStructs);
+    if (dartType == correspondingDartType) return;
+    if (env.isSubtypeOf(correspondingDartType, dartType,
+        SubtypeCheckMode.ignoringNullabilities)) {
+      return;
+    }
     diagnosticReporter.report(
         templateFfiTypeMismatch.withArguments(
-            elementType, shouldBeElementType, containerTypeArg),
+            dartType, correspondingDartType, nativeType),
         node.fileOffset,
         1,
         node.location.file);
diff --git a/pkg/vm/lib/transformations/type_flow/transformer.dart b/pkg/vm/lib/transformations/type_flow/transformer.dart
index f634d26..bde9684 100644
--- a/pkg/vm/lib/transformations/type_flow/transformer.dart
+++ b/pkg/vm/lib/transformations/type_flow/transformer.dart
@@ -929,6 +929,8 @@
         return !shaker.isClassUsed(node);
       } else if (node is Typedef) {
         return !shaker.isTypedefUsed(node);
+      } else if (node is Extension) {
+        return !shaker.isExtensionUsed(node);
       } else {
         return !shaker.isMemberUsed(node as Member);
       }
diff --git a/runtime/bin/ffi_test/ffi_test_functions.cc b/runtime/bin/ffi_test/ffi_test_functions.cc
index 85145b1..784093e 100644
--- a/runtime/bin/ffi_test/ffi_test_functions.cc
+++ b/runtime/bin/ffi_test/ffi_test_functions.cc
@@ -855,4 +855,31 @@
 
 #endif  // defined(TARGET_OS_LINUX)
 
+// Receives some pointer (Pointer<NativeType> in Dart) and writes some bits.
+DART_EXPORT void NativeTypePointerParam(void* p) {
+  uint8_t* p2 = reinterpret_cast<uint8_t*>(p);
+  p2[0] = 42;
+}
+
+// Manufactures some pointer (Pointer<NativeType> in Dart) with a bogus address.
+DART_EXPORT void* NativeTypePointerReturn() {
+  uint64_t bogus_address = 0x13370000;
+  return reinterpret_cast<void*>(bogus_address);
+}
+
+// Passes some pointer (Pointer<NativeType> in Dart) to Dart as argument.
+DART_EXPORT void CallbackNativeTypePointerParam(void (*f)(void*)) {
+  void* pointer = malloc(sizeof(int64_t));
+  f(pointer);
+  free(pointer);
+}
+
+// Receives some pointer (Pointer<NativeType> in Dart) from Dart as return
+// value.
+DART_EXPORT void CallbackNativeTypePointerReturn(void* (*f)()) {
+  void* p = f();
+  uint8_t* p2 = reinterpret_cast<uint8_t*>(p);
+  p2[0] = 42;
+}
+
 }  // namespace dart
diff --git a/runtime/bin/file_android.cc b/runtime/bin/file_android.cc
index 6fa50ad..681c46f 100644
--- a/runtime/bin/file_android.cc
+++ b/runtime/bin/file_android.cc
@@ -597,11 +597,16 @@
     errno = ENOENT;
     return -1;
   }
-  const size_t target_size =
+  size_t target_size =
       TEMP_FAILURE_RETRY(readlink(pathname, result, result_size));
   if (target_size <= 0) {
     return -1;
   }
+  // readlink returns non-zero terminated strings. Append.
+  if (target_size < result_size) {
+    result[target_size] = '\0';
+    target_size++;
+  }
   return target_size;
 }
 
@@ -615,10 +620,9 @@
   if (target_size <= 0) {
     return NULL;
   }
-  char* target_name = DartUtils::ScopedCString(target_size + 1);
+  char* target_name = DartUtils::ScopedCString(target_size);
   ASSERT(target_name != NULL);
   memmove(target_name, target, target_size);
-  target_name[target_size] = '\0';
   return target_name;
 }
 
diff --git a/runtime/bin/file_linux.cc b/runtime/bin/file_linux.cc
index 190b195..e478173 100644
--- a/runtime/bin/file_linux.cc
+++ b/runtime/bin/file_linux.cc
@@ -590,11 +590,16 @@
     errno = ENOENT;
     return -1;
   }
-  const size_t target_size =
+  size_t target_size =
       TEMP_FAILURE_RETRY(readlink(pathname, result, result_size));
   if (target_size <= 0) {
     return -1;
   }
+  // readlink returns non-zero terminated strings. Append.
+  if (target_size < result_size) {
+    result[target_size] = '\0';
+    target_size++;
+  }
   return target_size;
 }
 
@@ -608,10 +613,9 @@
   if (target_size <= 0) {
     return NULL;
   }
-  char* target_name = DartUtils::ScopedCString(target_size + 1);
+  char* target_name = DartUtils::ScopedCString(target_size);
   ASSERT(target_name != NULL);
   memmove(target_name, target, target_size);
-  target_name[target_size] = '\0';
   return target_name;
 }
 
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index fbc69b3..8e76803 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -1088,16 +1088,21 @@
   // snapshot, load and run that.
   // Any arguments passed to such an executable are meant for the actual
   // application so skip all Dart VM flag parsing.
-  app_snapshot = Snapshot::TryReadAppendedAppSnapshotElf(argv[0]);
-  if (app_snapshot != nullptr) {
-    script_name = argv[0];
 
-    // Store the executable name.
-    Platform::SetExecutableName(argv[0]);
+  const size_t kPathBufSize = PATH_MAX + 1;
+  char executable_path[kPathBufSize];
+  if (Platform::ResolveExecutablePathInto(executable_path, kPathBufSize) > 0) {
+    app_snapshot = Snapshot::TryReadAppendedAppSnapshotElf(executable_path);
+    if (app_snapshot != nullptr) {
+      script_name = argv[0];
 
-    // Parse out options to be passed to dart main.
-    for (int i = 1; i < argc; i++) {
-      dart_options.AddArgument(argv[i]);
+      // Store the executable name.
+      Platform::SetExecutableName(argv[0]);
+
+      // Parse out options to be passed to dart main.
+      for (int i = 1; i < argc; i++) {
+        dart_options.AddArgument(argv[i]);
+      }
     }
   }
 #endif
diff --git a/runtime/bin/platform.h b/runtime/bin/platform.h
index b0b3aa2..50b9a10 100644
--- a/runtime/bin/platform.h
+++ b/runtime/bin/platform.h
@@ -64,13 +64,12 @@
 
   static const char* ResolveExecutablePath();
 
-  // On Linux and Android this has the same effect as calling
-  // ResolveExecutablePath except that Dart_ScopeAllocate is not called and that
-  // the result goes into the given parameters.
-  // On all other platforms it returns -1, i.e. doesn't work.
+  // This has the same effect as calling ResolveExecutablePath except that
+  // Dart_ScopeAllocate is not called and that the result goes into the given
+  // parameters.
+  // WARNING: On Fuchsia it returns -1, i.e. doesn't work.
   // Note that `result` should be pre-allocated with size `result_size`.
   // The return-value is the length read into `result` or -1 on failure.
-  // The content of `result` is not guranteed to be null-terminated.
   static intptr_t ResolveExecutablePathInto(char* result, size_t result_size);
 
   // Stores the executable name.
diff --git a/runtime/bin/platform_macos.cc b/runtime/bin/platform_macos.cc
index 2be3f30..bacb7a75 100644
--- a/runtime/bin/platform_macos.cc
+++ b/runtime/bin/platform_macos.cc
@@ -252,7 +252,18 @@
 }
 
 intptr_t Platform::ResolveExecutablePathInto(char* result, size_t result_size) {
-  return -1;
+  // Get the required length of the buffer.
+  uint32_t path_size = 0;
+  if (_NSGetExecutablePath(nullptr, &path_size) == 0) {
+    return -1;
+  }
+  if (path_size > result_size) {
+    return -1;
+  }
+  if (_NSGetExecutablePath(result, &path_size) != 0) {
+    return -1;
+  }
+  return path_size;
 }
 
 void Platform::Exit(int exit_code) {
diff --git a/runtime/bin/platform_win.cc b/runtime/bin/platform_win.cc
index e4f20a2..552e3c2 100644
--- a/runtime/bin/platform_win.cc
+++ b/runtime/bin/platform_win.cc
@@ -275,7 +275,7 @@
   // Ensure no last error before calling GetModuleFileNameW.
   SetLastError(ERROR_SUCCESS);
   // Get the required length of the buffer.
-  int path_length = GetModuleFileNameW(NULL, tmp_buffer, kTmpBufferSize);
+  GetModuleFileNameW(nullptr, tmp_buffer, kTmpBufferSize);
   if (GetLastError() != ERROR_SUCCESS) {
     return NULL;
   }
@@ -286,6 +286,20 @@
 }
 
 intptr_t Platform::ResolveExecutablePathInto(char* result, size_t result_size) {
+  // Ensure no last error before calling GetModuleFileNameW.
+  SetLastError(ERROR_SUCCESS);
+  const int kTmpBufferSize = 32768;
+  wchar_t tmp_buffer[kTmpBufferSize];
+  // Get the required length of the buffer.
+  GetModuleFileNameW(nullptr, tmp_buffer, kTmpBufferSize);
+  if (GetLastError() != ERROR_SUCCESS) {
+    return -1;
+  }
+  WideToUtf8Scope wide_to_utf8_scope(tmp_buffer);
+  if (wide_to_utf8_scope.length() <= result_size) {
+    strncpy(result, wide_to_utf8_scope.utf8(), result_size);
+    return wide_to_utf8_scope.length();
+  }
   return -1;
 }
 
diff --git a/runtime/platform/globals.h b/runtime/platform/globals.h
index 2dd7547..d754abf 100644
--- a/runtime/platform/globals.h
+++ b/runtime/platform/globals.h
@@ -722,6 +722,11 @@
 #define STDERR_FILENO 2
 #endif
 
+#ifndef PATH_MAX
+// Most platforms use PATH_MAX, but in Windows it's called MAX_PATH.
+#define PATH_MAX MAX_PATH
+#endif
+
 }  // namespace dart
 
 #endif  // RUNTIME_PLATFORM_GLOBALS_H_
diff --git a/runtime/tests/vm/dart/run_appended_aot_snapshot_test.dart b/runtime/tests/vm/dart/run_appended_aot_snapshot_test.dart
index 1594605..26b7a9c 100644
--- a/runtime/tests/vm/dart/run_appended_aot_snapshot_test.dart
+++ b/runtime/tests/vm/dart/run_appended_aot_snapshot_test.dart
@@ -22,9 +22,10 @@
       'runtime', 'tests', 'vm', 'dart', 'run_appended_aot_snapshot_test.dart');
 
   await withTempDir((String tmp) async {
+    final String exeName = 'test.exe';
     final String dillPath = path.join(tmp, 'test.dill');
     final String aotPath = path.join(tmp, 'test.aot');
-    final String exePath = path.join(tmp, 'test.exe');
+    final String exePath = path.join(tmp, exeName);
 
     {
       final result = await generateAotKernel(checkedInDartVM, genKernel,
@@ -51,8 +52,33 @@
       Expect.equals(result.stdout, '');
     }
 
-    final runResult =
-        await runBinary('run appended aot snapshot', exePath, ['--child']);
-    expectOutput('Hello, Appended AOT', runResult);
+    {
+      final runResult =
+          await runBinary('run appended aot snapshot', exePath, ['--child']);
+      expectOutput('Hello, Appended AOT', runResult);
+    }
+
+    {
+      // Test that it runs when invoked via PATH as well.
+      Map<String, String> environment = {'PATH': tmp};
+      final runResult = await runBinary(
+          'run appended aot snapshot from PATH', exeName, ['--child'],
+          environment: environment, runInShell: true);
+      expectOutput('Hello, Appended AOT', runResult);
+    }
+
+    // Windows allows leaving out .exe. Make sure we can load that as well.
+    if (Platform.isWindows) {
+      final String exeNameWithoutExt =
+          exeName.replaceFirst(new RegExp(r'.exe$'), '');
+      Map<String, String> environment = {'PATH': tmp};
+      final runResult = await runBinary(
+          'run appended aot snapshot without extension',
+          exeNameWithoutExt,
+          ['--child'],
+          environment: environment,
+          runInShell: true);
+      expectOutput('Hello, Appended AOT', runResult);
+    }
   });
 }
diff --git a/runtime/tests/vm/dart/snapshot_test_helper.dart b/runtime/tests/vm/dart/snapshot_test_helper.dart
index 6f42b07..8ffd309 100644
--- a/runtime/tests/vm/dart/snapshot_test_helper.dart
+++ b/runtime/tests/vm/dart/snapshot_test_helper.dart
@@ -72,10 +72,11 @@
   return runBinary(prefix, genSnapshot, arguments);
 }
 
-Future<Result> runBinary(
-    String prefix, String binary, List<String> arguments) async {
+Future<Result> runBinary(String prefix, String binary, List<String> arguments,
+    {Map<String, String> environment, bool runInShell: false}) async {
   print("+ $binary " + arguments.join(" "));
-  final processResult = await Process.run(binary, arguments);
+  final processResult = await Process.run(binary, arguments,
+      environment: environment, runInShell: runInShell);
   final result =
       new Result('[$prefix] ${binary} ${arguments.join(' ')}', processResult);
 
diff --git a/tests/ffi/function_test.dart b/tests/ffi/function_test.dart
index 51cc2fe..38c36a9 100644
--- a/tests/ffi/function_test.dart
+++ b/tests/ffi/function_test.dart
@@ -13,8 +13,6 @@
 // VMOptions=--write-protect-code --no-dual-map-code --stacktrace-every=100
 // SharedObjects=ffi_test_functions
 
-library FfiTest;
-
 import 'dart:ffi';
 
 import 'dylib_utils.dart';
@@ -44,6 +42,7 @@
     testVoidReturn();
     testNoArgs();
     testException();
+    testLookupFunctionPointerNativeType();
   }
 }
 
@@ -405,6 +404,17 @@
   Expect.approxEquals(1337.0, result);
 }
 
+typedef NativeTypeNFT = Pointer<NativeType> Function(
+    Pointer<Pointer<NativeType>>, Int8);
+typedef NativeTypeFT = Pointer<NativeType> Function(
+    Pointer<Pointer<NativeType>>, int);
+
+void testLookupFunctionPointerNativeType() {
+  // The function signature does not match up, but that does not matter since
+  // this test does not use the trampoline.
+  ffiTestFunctions.lookupFunction<NativeTypeNFT, NativeTypeFT>("LargePointer");
+}
+
 // Throw an exception from within the trampoline and collect a stacktrace
 // include its frame.
 void testException() {
diff --git a/tests/ffi/variance_function_checks_test.dart b/tests/ffi/variance_function_checks_test.dart
new file mode 100644
index 0000000..c17488c
--- /dev/null
+++ b/tests/ffi/variance_function_checks_test.dart
@@ -0,0 +1,67 @@
+// Copyright (c) 2019, 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.
+//
+// SharedObjects=ffi_test_functions
+
+import 'dart:ffi';
+
+import 'dylib_utils.dart';
+
+// ============================================
+// Tests checks on Dart to native (asFunction).
+// ============================================
+
+typedef Int64PointerParamOpDart = void Function(Pointer<Int64>);
+typedef Int64PointerParamOp = Void Function(Pointer<Int64>);
+typedef Int64PointerReturnOp = Pointer<Int64> Function();
+typedef NaTyPointerReturnOp = Pointer<NativeType> Function();
+
+final paramOpName = "NativeTypePointerParam";
+final returnOpName = "NativeTypePointerReturn";
+
+final DynamicLibrary ffiTestFunctions =
+    dlopenPlatformSpecific("ffi_test_functions");
+
+final p1 =
+    ffiTestFunctions.lookup<NativeFunction<Int64PointerParamOp>>(paramOpName);
+final nonInvariantBinding1 = //# 1:  compile-time error
+    p1.asFunction<NaTyPointerParamOpDart>(); //# 1:  continued
+
+final p2 =
+    ffiTestFunctions.lookup<NativeFunction<NaTyPointerReturnOp>>(returnOpName);
+final nonInvariantBinding2 = //# 2:  compile-time error
+    p2.asFunction<Int64PointerReturnOp>(); //# 2:  continued
+
+final p3 = Pointer<
+    NativeFunction<
+        Pointer<NativeFunction<Pointer<NativeType> Function()>>
+            Function()>>.fromAddress(0x1234);
+final f3 = p3 //# 10:  compile-time error
+    .asFunction< //# 10:  continued
+        Pointer< //# 10:  continued
+                NativeFunction< //# 10:  continued
+                    Pointer<Int8> Function()>> //# 10:  continued
+            Function()>(); //# 10:  continued
+
+// ===========================================================
+// Test check on callbacks from native to Dart (fromFunction).
+// ===========================================================
+
+void naTyPointerParamOp(Pointer<NativeType> p) {
+  final Pointer<Int8> asInt8 = p.cast();
+  asInt8.value = 42;
+}
+
+Pointer<Int64> int64PointerReturnOp() {
+  return Pointer.fromAddress(0x13370000);
+}
+
+final implictDowncast1 = //# 3:  compile-time error
+    Pointer.fromFunction<Int64PointerParamOp>(//# 3:  continued
+        naTyPointerParamOp); //# 3:  continued
+final implictDowncast2 = //# 4:  compile-time error
+    Pointer.fromFunction<NaTyPointerReturnOp>(//# 4:  continued
+        int64PointerReturnOp); //# 4:  continued
+
+void main() {}
diff --git a/tests/ffi/variance_function_test.dart b/tests/ffi/variance_function_test.dart
new file mode 100644
index 0000000..d6e6378
--- /dev/null
+++ b/tests/ffi/variance_function_test.dart
@@ -0,0 +1,238 @@
+// Copyright (c) 2019, 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.
+//
+// VMOptions=
+// VMOptions=--deterministic --optimization-counter-threshold=10
+// VMOptions=--use-slow-path
+// SharedObjects=ffi_test_functions
+//
+// This file tests subtyping relationships (at compile time and at runtime) of
+// parameters and return types of ffi trampolines and ffi callback trampolines.
+
+import 'dart:ffi';
+
+import 'dylib_utils.dart';
+
+import "package:expect/expect.dart";
+import "package:ffi/ffi.dart";
+
+typedef Int64PointerParamOpDart = void Function(Pointer<Int64>);
+typedef Int64PointerParamOp = Void Function(Pointer<Int64>);
+typedef NaTyPointerParamOpDart = void Function(Pointer<NativeType>);
+typedef NaTyPointerParamOp = Void Function(Pointer<NativeType>);
+typedef Int64PointerReturnOp = Pointer<Int64> Function();
+typedef NaTyPointerReturnOp = Pointer<NativeType> Function();
+
+final paramOpName = "NativeTypePointerParam";
+final returnOpName = "NativeTypePointerReturn";
+
+final DynamicLibrary ffiTestFunctions =
+    dlopenPlatformSpecific("ffi_test_functions");
+
+// =============================================
+// Tests calls from Dart to native (asFunction).
+// =============================================
+
+void paramInvariant1() {
+  final fp =
+      ffiTestFunctions.lookup<NativeFunction<Int64PointerParamOp>>(paramOpName);
+  final f = fp.asFunction<Int64PointerParamOpDart>();
+  final arg = allocate<Int64>();
+  f(arg);
+  free(arg);
+}
+
+void paramInvariant2() {
+  final fp =
+      ffiTestFunctions.lookup<NativeFunction<NaTyPointerParamOp>>(paramOpName);
+  final f = fp.asFunction<NaTyPointerParamOpDart>();
+  final arg = allocate<Int64>().cast<NativeType>();
+  Expect.type<Pointer<NativeType>>(arg);
+  f(arg);
+  free(arg);
+}
+
+// Pass a statically and dynamically subtyped argument.
+void paramSubtype1() {
+  final fp =
+      ffiTestFunctions.lookup<NativeFunction<NaTyPointerParamOp>>(paramOpName);
+  final f = fp.asFunction<NaTyPointerParamOpDart>();
+  final arg = allocate<Int64>();
+  Expect.type<Pointer<Int64>>(arg);
+  f(arg);
+  free(arg);
+}
+
+// Pass a statically subtyped but dynamically invariant argument.
+void paramSubtype2() {
+  final fp =
+      ffiTestFunctions.lookup<NativeFunction<NaTyPointerParamOp>>(paramOpName);
+  final f = fp.asFunction<NaTyPointerParamOpDart>();
+  final Pointer<NativeType> arg = allocate<Int64>();
+  Expect.type<Pointer<Int64>>(arg);
+  f(arg);
+  free(arg);
+}
+
+void returnInvariant1() {
+  final fp = ffiTestFunctions
+      .lookup<NativeFunction<Int64PointerReturnOp>>(returnOpName);
+  final f = fp.asFunction<Int64PointerReturnOp>();
+  final result = f();
+  Expect.type<Pointer<Int64>>(result);
+}
+
+void returnInvariant2() {
+  final fp = ffiTestFunctions
+      .lookup<NativeFunction<NaTyPointerReturnOp>>(returnOpName);
+  final f = fp.asFunction<NaTyPointerReturnOp>();
+  final result = f();
+  Expect.type<Pointer<NativeType>>(result);
+}
+
+void returnSubtype() {
+  final fp = ffiTestFunctions
+      .lookup<NativeFunction<Int64PointerReturnOp>>(returnOpName);
+  final f = fp.asFunction<Int64PointerReturnOp>();
+  final NaTyPointerReturnOp f2 = f;
+  Expect.type<Int64PointerReturnOp>(f2);
+  final result = f2();
+  Expect.type<Pointer<NativeType>>(result);
+}
+
+void functionArgumentVariance() {
+  final p = Pointer<
+      NativeFunction<
+          Pointer<NativeFunction<Pointer<Int8> Function(Pointer<NativeType>)>> Function(
+              Pointer<
+                  NativeFunction<
+                      Pointer<NativeType> Function(
+                          Pointer<Int8>)>>)>>.fromAddress(0x1234);
+  final f = p.asFunction<
+      Pointer<NativeFunction<Pointer<NativeType> Function(Pointer<Int8>)>> Function(
+          Pointer<
+              NativeFunction<Pointer<Int8> Function(Pointer<NativeType>)>>)>();
+}
+
+void asFunctionTests() {
+  for (int i = 0; i < 100; ++i) {
+    paramInvariant1(); // Parameter invariant: Pointer<Int64>.
+    paramInvariant2(); // Parameter invariant: Pointer<NativeType>.
+    paramSubtype1(); // Parameter statically and dynamically subtyped.
+    paramSubtype2(); // Parameter statically invariant, dynamically subtyped.
+    returnInvariant1(); // Return value invariant: Pointer<Int64>.
+    returnInvariant2(); // Return value invariant: Pointer<NativeType>.
+    returnSubtype(); // Return value static subtyped, dynamically invariant.
+    functionArgumentVariance(); // Check nested function signatures.
+  }
+}
+
+// =======================================================
+// Test with callbacks from native to Dart (fromFunction).
+// =======================================================
+
+typedef CallbackInt64PointerParamOpDart = void Function(
+    Pointer<NativeFunction<Int64PointerParamOp>>);
+typedef CallbackInt64PointerParamOp = Void Function(
+    Pointer<NativeFunction<Int64PointerParamOp>>);
+
+typedef CallbackNaTyPointerParamOpDart = void Function(
+    Pointer<NativeFunction<NaTyPointerParamOp>>);
+typedef CallbackNaTyPointerParamOp = Void Function(
+    Pointer<NativeFunction<NaTyPointerParamOp>>);
+
+typedef CallbackInt64PointerReturnOpDart = void Function(
+    Pointer<NativeFunction<Int64PointerReturnOp>>);
+typedef CallbackInt64PointerReturnOp = Void Function(
+    Pointer<NativeFunction<Int64PointerReturnOp>>);
+
+typedef CallbackNaTyPointerReturnOpDart = void Function(
+    Pointer<NativeFunction<NaTyPointerReturnOp>>);
+typedef CallbackNaTyPointerReturnOp = Void Function(
+    Pointer<NativeFunction<NaTyPointerReturnOp>>);
+
+final callbackParamOpName = "CallbackNativeTypePointerParam";
+final callbackReturnOpName = "CallbackNativeTypePointerReturn";
+
+void int64PointerParamOp(Pointer<Int64> p) {
+  p.value = 42;
+}
+
+void naTyPointerParamOp(Pointer<NativeType> p) {
+  final Pointer<Int8> asInt8 = p.cast();
+  asInt8.value = 42;
+}
+
+// Pointer to return to C when C calls back into Dart and asks for a Pointer.
+Pointer<Int64> data;
+
+Pointer<Int64> int64PointerReturnOp() {
+  return data;
+}
+
+Pointer<NativeType> naTyPointerReturnOp() {
+  return data;
+}
+
+void callbackParamInvariant1() {
+  final callback = ffiTestFunctions.lookupFunction<CallbackInt64PointerParamOp,
+      CallbackInt64PointerParamOpDart>(callbackParamOpName);
+  final fp = Pointer.fromFunction<Int64PointerParamOp>(int64PointerParamOp);
+  callback(fp);
+}
+
+void callbackParamInvariant2() {
+  final callback = ffiTestFunctions.lookupFunction<CallbackNaTyPointerParamOp,
+      CallbackNaTyPointerParamOpDart>(callbackParamOpName);
+  final fp = Pointer.fromFunction<NaTyPointerParamOp>(naTyPointerParamOp);
+  callback(fp);
+}
+
+void callbackParamImplictDowncast1() {
+  final callback = ffiTestFunctions.lookupFunction<CallbackNaTyPointerParamOp,
+      CallbackNaTyPointerParamOpDart>(callbackParamOpName);
+  final fp = Pointer.fromFunction<Int64PointerParamOp>(int64PointerParamOp);
+  Expect.throws(() {
+    callback(fp);
+  });
+}
+
+void callbackParamSubtype1() {
+  final callback = ffiTestFunctions.lookupFunction<CallbackNaTyPointerParamOp,
+      CallbackNaTyPointerParamOpDart>(callbackParamOpName);
+  final fp = Pointer.fromFunction<NaTyPointerParamOp>(int64PointerParamOp);
+  callback(fp);
+}
+
+void callbackReturnInvariant1() {
+  final callback = ffiTestFunctions.lookupFunction<CallbackInt64PointerReturnOp,
+      CallbackInt64PointerReturnOpDart>(callbackReturnOpName);
+  final fp = Pointer.fromFunction<Int64PointerReturnOp>(int64PointerReturnOp);
+  callback(fp);
+}
+
+void callbackReturnInvariant2() {
+  final callback = ffiTestFunctions.lookupFunction<CallbackNaTyPointerReturnOp,
+      CallbackNaTyPointerReturnOpDart>(callbackReturnOpName);
+  final fp = Pointer.fromFunction<NaTyPointerReturnOp>(naTyPointerReturnOp);
+  callback(fp);
+}
+
+void fromFunctionTests() {
+  data = allocate();
+  for (int i = 0; i < 100; ++i) {
+    callbackParamInvariant1(); // Pointer<Int64> invariant
+    callbackParamInvariant2(); // Pointer<NativeType> invariant
+    callbackParamImplictDowncast1(); // static and dynamically supertyped
+    callbackParamSubtype1(); // static and dynamically subtyped
+    callbackReturnInvariant1(); // Pointer<Int64> invariant
+    callbackReturnInvariant2(); // Pointer<NativeType> invariant
+  }
+  free(data);
+}
+
+void main() {
+  asFunctionTests();
+  fromFunctionTests();
+}
diff --git a/tests/language_2/vm/regress_flutter_42845_lib.dart b/tests/language_2/vm/regress_flutter_42845_lib.dart
new file mode 100644
index 0000000..f22d832
--- /dev/null
+++ b/tests/language_2/vm/regress_flutter_42845_lib.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2019, 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.
+
+extension TestExtension on int {
+  bool get isPositive => this > 0;
+  bool get isNegative => this < 0;
+}
+
+extension UnusedExtension on int {
+  bool get isReallyZero => this == 0;
+}
diff --git a/tests/language_2/vm/regress_flutter_42845_test.dart b/tests/language_2/vm/regress_flutter_42845_test.dart
new file mode 100644
index 0000000..ac05e97
--- /dev/null
+++ b/tests/language_2/vm/regress_flutter_42845_test.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2019, 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.
+
+// SharedOptions=--enable-experiment=extension-methods
+
+// Tests exported extensions.
+
+import "regress_flutter_42845_lib.dart";
+export "regress_flutter_42845_lib.dart" show TestExtension, UnusedExtension;
+
+import "package:expect/expect.dart";
+
+int i = 42;
+
+void main() {
+  Expect.isTrue(i.isPositive);
+  Expect.isFalse(i.isNegative);
+}
diff --git a/tools/VERSION b/tools/VERSION
index 528e6b2..3393977 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -34,6 +34,6 @@
 MINOR 6
 PATCH 0
 PRERELEASE 8
-PRERELEASE_PATCH 0
+PRERELEASE_PATCH 1
 ABI_VERSION 19
 OLDEST_SUPPORTED_ABI_VERSION 18