Support compilation with the trivial abstract value domain

Change-Id: I1b42ee48f440db9e424448e794a8f8cc9d8f5f3a
Reviewed-on: https://dart-review.googlesource.com/c/86921
Reviewed-by: Sigmund Cherem <sigmund@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/compiler/lib/src/commandline_options.dart b/pkg/compiler/lib/src/commandline_options.dart
index a3cf93f..eaeee62 100644
--- a/pkg/compiler/lib/src/commandline_options.dart
+++ b/pkg/compiler/lib/src/commandline_options.dart
@@ -13,6 +13,8 @@
   static const String disableDiagnosticColors = '--disable-diagnostic-colors';
   static const String disableNativeLiveTypeAnalysis =
       '--disable-native-live-type-analysis';
+  static const String useTrivialAbstractValueDomain =
+      '--use-trivial-abstract-value-domain';
   static const String disableTypeInference = '--disable-type-inference';
   static const String disableRtiOptimization = '--disable-rti-optimization';
   static const String dumpInfo = '--dump-info';
diff --git a/pkg/compiler/lib/src/common_elements.dart b/pkg/compiler/lib/src/common_elements.dart
index 48e63f6..e0b0c54 100644
--- a/pkg/compiler/lib/src/common_elements.dart
+++ b/pkg/compiler/lib/src/common_elements.dart
@@ -1238,7 +1238,7 @@
     return selector.applies(_jsStringSplit) &&
         (receiver == null ||
             abstractValueDomain
-                .isTargetingMember(receiver, jsStringSplit, selector)
+                .isTargetingMember(receiver, jsStringSplit, selector.memberName)
                 .isPotentiallyTrue);
   }
 
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index 818f565..96ac042 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -27,6 +27,7 @@
 import 'environment.dart';
 import 'frontend_strategy.dart';
 import 'inferrer/abstract_value_domain.dart' show AbstractValueStrategy;
+import 'inferrer/trivial.dart' show TrivialAbstractValueStrategy;
 import 'inferrer/typemasks/masks.dart' show TypeMaskStrategy;
 import 'inferrer/types.dart'
     show GlobalTypeInferenceResults, GlobalTypeInferenceTask;
@@ -105,7 +106,7 @@
   JavaScriptBackend backend;
   CodegenWorldBuilder _codegenWorldBuilder;
 
-  AbstractValueStrategy abstractValueStrategy = const TypeMaskStrategy();
+  AbstractValueStrategy abstractValueStrategy;
 
   GenericTask selfTask;
 
@@ -144,6 +145,10 @@
       : this.options = options {
     options.deriveOptions();
     options.validate();
+
+    abstractValueStrategy = options.useTrivialAbstractValueDomain
+        ? const TrivialAbstractValueStrategy()
+        : const TypeMaskStrategy();
     CompilerTask kernelFrontEndTask;
     selfTask = new GenericTask('self', measurer);
     _outputProvider = new _CompilerOutput(this, outputProvider);
diff --git a/pkg/compiler/lib/src/dart2js.dart b/pkg/compiler/lib/src/dart2js.dart
index 472aeac..9ad51d6 100644
--- a/pkg/compiler/lib/src/dart2js.dart
+++ b/pkg/compiler/lib/src/dart2js.dart
@@ -373,6 +373,7 @@
     new OptionHandler(Flags.disableInlining, passThrough),
     new OptionHandler(Flags.disableProgramSplit, passThrough),
     new OptionHandler(Flags.disableTypeInference, passThrough),
+    new OptionHandler(Flags.useTrivialAbstractValueDomain, passThrough),
     new OptionHandler(Flags.disableRtiOptimization, passThrough),
     new OptionHandler(Flags.terse, passThrough),
     new OptionHandler('--deferred-map=.+', passThrough),
diff --git a/pkg/compiler/lib/src/inferrer/abstract_value_domain.dart b/pkg/compiler/lib/src/inferrer/abstract_value_domain.dart
index ee075e1..784e018 100644
--- a/pkg/compiler/lib/src/inferrer/abstract_value_domain.dart
+++ b/pkg/compiler/lib/src/inferrer/abstract_value_domain.dart
@@ -6,6 +6,7 @@
 
 import '../constants/values.dart' show ConstantValue, PrimitiveConstantValue;
 import '../elements/entities.dart';
+import '../elements/names.dart';
 import '../serialization/serialization.dart';
 import '../universe/selector.dart';
 import '../universe/world_builder.dart';
@@ -466,10 +467,10 @@
   AbstractValue computeReceiver(Iterable<MemberEntity> members);
 
   /// Returns an [AbstractBool] that describes whether [member] is a potential
-  /// target when being invoked on a [receiver]. [selector] is used to ensure
+  /// target when being invoked on a [receiver]. [name] is used to ensure
   /// library privacy is taken into account.
   AbstractBool isTargetingMember(
-      AbstractValue receiver, MemberEntity member, Selector selector);
+      AbstractValue receiver, MemberEntity member, Name name);
 
   /// Returns an [AbstractBool] that describes whether [selector] invoked on a
   /// [receiver] can hit a [noSuchMethod].
diff --git a/pkg/compiler/lib/src/inferrer/trivial.dart b/pkg/compiler/lib/src/inferrer/trivial.dart
index c37d493..63d0b8e 100644
--- a/pkg/compiler/lib/src/inferrer/trivial.dart
+++ b/pkg/compiler/lib/src/inferrer/trivial.dart
@@ -4,12 +4,18 @@
 
 import '../constants/values.dart' show ConstantValue, PrimitiveConstantValue;
 import '../elements/entities.dart';
+import '../elements/names.dart';
 import '../serialization/serialization.dart';
 import '../universe/selector.dart';
+import '../universe/world_builder.dart';
+import '../universe/use.dart';
+import '../world.dart';
 import 'abstract_value_domain.dart';
 
 class TrivialAbstractValue implements AbstractValue {
   const TrivialAbstractValue();
+
+  String toString() => '?';
 }
 
 class TrivialAbstractValueDomain implements AbstractValueDomain {
@@ -58,7 +64,7 @@
 
   @override
   AbstractBool isTargetingMember(
-          AbstractValue receiver, MemberEntity member, Selector selector) =>
+          AbstractValue receiver, MemberEntity member, Name name) =>
       AbstractBool.Maybe;
 
   @override
@@ -395,3 +401,49 @@
   @override
   AbstractValue get typeType => const TrivialAbstractValue();
 }
+
+class TrivialAbstractValueStrategy implements AbstractValueStrategy {
+  const TrivialAbstractValueStrategy();
+
+  @override
+  AbstractValueDomain createDomain(JClosedWorld closedWorld) {
+    return const TrivialAbstractValueDomain();
+  }
+
+  @override
+  SelectorConstraintsStrategy createSelectorStrategy() {
+    return const TrivialSelectorStrategy();
+  }
+}
+
+class TrivialSelectorStrategy implements SelectorConstraintsStrategy {
+  const TrivialSelectorStrategy();
+
+  @override
+  UniverseSelectorConstraints createSelectorConstraints(
+      Selector selector, Object initialConstraint) {
+    return const TrivialUniverseSelectorConstraints();
+  }
+
+  @override
+  bool appliedUnnamed(DynamicUse dynamicUse, MemberEntity member,
+      covariant JClosedWorld world) {
+    return dynamicUse.selector.appliesUnnamed(member);
+  }
+}
+
+class TrivialUniverseSelectorConstraints
+    implements UniverseSelectorConstraints {
+  const TrivialUniverseSelectorConstraints();
+
+  @override
+  bool addReceiverConstraint(Object constraint) => false;
+
+  @override
+  bool needsNoSuchMethodHandling(Selector selector, World world) => true;
+
+  @override
+  bool canHit(MemberEntity element, Name name, World world) => true;
+
+  String toString() => 'TrivialUniverseSelectorConstraints:$hashCode';
+}
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/flat_type_mask.dart b/pkg/compiler/lib/src/inferrer/typemasks/flat_type_mask.dart
index c74600a..2dfe38a 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/flat_type_mask.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/flat_type_mask.dart
@@ -524,28 +524,27 @@
    * invoked on this type mask. [selector] is used to ensure library
    * privacy is taken into account.
    */
-  bool canHit(
-      MemberEntity element, Selector selector, JClosedWorld closedWorld) {
+  bool canHit(MemberEntity element, Name name, JClosedWorld closedWorld) {
     CommonElements commonElements = closedWorld.commonElements;
-    assert(element.name == selector.name);
+    assert(element.name == name.text);
     if (isEmpty) return false;
     if (isNull) {
       return closedWorld.hasElementIn(
-          commonElements.jsNullClass, selector, element);
+          commonElements.jsNullClass, name, element);
     }
 
     ClassEntity other = element.enclosingClass;
     if (other == commonElements.jsNullClass) {
       return isNullable;
     } else if (isExact) {
-      return closedWorld.hasElementIn(base, selector, element);
+      return closedWorld.hasElementIn(base, name, element);
     } else if (isSubclass) {
-      return closedWorld.hasElementIn(base, selector, element) ||
+      return closedWorld.hasElementIn(base, name, element) ||
           closedWorld.classHierarchy.isSubclassOf(other, base) ||
           closedWorld.hasAnySubclassThatMixes(base, other);
     } else {
       assert(isSubtype);
-      bool result = closedWorld.hasElementIn(base, selector, element) ||
+      bool result = closedWorld.hasElementIn(base, name, element) ||
           closedWorld.classHierarchy.isSubtypeOf(other, base) ||
           closedWorld.hasAnySubclassThatImplements(other, base) ||
           closedWorld.hasAnySubclassOfMixinUseThatImplements(other, base);
@@ -554,7 +553,7 @@
       // can be hit from any of the mixin applications.
       Iterable<ClassEntity> mixinUses = closedWorld.mixinUsesOf(base);
       return mixinUses.any((mixinApplication) =>
-          closedWorld.hasElementIn(mixinApplication, selector, element) ||
+          closedWorld.hasElementIn(mixinApplication, name, element) ||
           closedWorld.classHierarchy.isSubclassOf(other, mixinApplication) ||
           closedWorld.hasAnySubclassThatMixes(mixinApplication, other));
     }
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/forwarding_type_mask.dart b/pkg/compiler/lib/src/inferrer/typemasks/forwarding_type_mask.dart
index 82b6bd0..781a51e 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/forwarding_type_mask.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/forwarding_type_mask.dart
@@ -98,9 +98,8 @@
     return forwardTo.needsNoSuchMethodHandling(selector, closedWorld);
   }
 
-  bool canHit(
-      MemberEntity element, Selector selector, JClosedWorld closedWorld) {
-    return forwardTo.canHit(element, selector, closedWorld);
+  bool canHit(MemberEntity element, Name name, JClosedWorld closedWorld) {
+    return forwardTo.canHit(element, name, closedWorld);
   }
 
   MemberEntity locateSingleMember(Selector selector, JClosedWorld closedWorld) {
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/masks.dart b/pkg/compiler/lib/src/inferrer/typemasks/masks.dart
index 2960a7b..17794f1 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/masks.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/masks.dart
@@ -10,6 +10,7 @@
 import '../../common_elements.dart' show CommonElements;
 import '../../constants/values.dart';
 import '../../elements/entities.dart';
+import '../../elements/names.dart';
 import '../../serialization/serialization.dart';
 import '../../universe/class_hierarchy.dart';
 import '../../universe/selector.dart' show Selector;
@@ -628,9 +629,9 @@
 
   @override
   AbstractBool isTargetingMember(
-      covariant TypeMask receiver, MemberEntity member, Selector selector) {
+      covariant TypeMask receiver, MemberEntity member, Name name) {
     return AbstractBool.maybeOrFalse(
-        receiver.canHit(member, selector, _closedWorld));
+        receiver.canHit(member, name, _closedWorld));
   }
 
   @override
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/type_mask.dart b/pkg/compiler/lib/src/inferrer/typemasks/type_mask.dart
index a08d320..eb06347 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/type_mask.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/type_mask.dart
@@ -12,11 +12,11 @@
   Set<TypeMask> _masks;
 
   @override
-  bool applies(MemberEntity element, Selector selector, JClosedWorld world) {
+  bool canHit(MemberEntity element, Name name, JClosedWorld world) {
     if (isAll) return true;
     if (_masks == null) return false;
     for (TypeMask mask in _masks) {
-      if (mask.canHit(element, selector, world)) return true;
+      if (mask.canHit(element, name, world)) return true;
     }
     return false;
   }
@@ -77,8 +77,10 @@
   const TypeMaskSelectorStrategy();
 
   @override
-  UniverseSelectorConstraints createSelectorConstraints(Selector selector) {
-    return new IncreasingTypeMaskSet();
+  UniverseSelectorConstraints createSelectorConstraints(
+      Selector selector, Object initialConstraint) {
+    return new IncreasingTypeMaskSet()
+      ..addReceiverConstraint(initialConstraint);
   }
 
   @override
@@ -87,7 +89,7 @@
     Selector selector = dynamicUse.selector;
     TypeMask mask = dynamicUse.receiverConstraint;
     return selector.appliesUnnamed(member) &&
-        (mask == null || mask.canHit(member, selector, world));
+        (mask == null || mask.canHit(member, selector.memberName, world));
   }
 }
 
@@ -413,13 +415,9 @@
    */
   TypeMask intersection(TypeMask other, JClosedWorld closedWorld);
 
-  /**
-   * Returns whether [element] is a potential target when being
-   * invoked on this type mask. [selector] is used to ensure library
-   * privacy is taken into account.
-   */
-  bool canHit(
-      MemberEntity element, Selector selector, JClosedWorld closedWorld);
+  /// Returns whether [element] is a potential target when being invoked on this
+  /// type mask. [name] is used to ensure library privacy is taken into account.
+  bool canHit(MemberEntity element, Name name, JClosedWorld closedWorld);
 
   /// Returns whether this [TypeMask] applied to [selector] can hit a
   /// [noSuchMethod].
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/union_type_mask.dart b/pkg/compiler/lib/src/inferrer/typemasks/union_type_mask.dart
index c409d07..0d252f0 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/union_type_mask.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/union_type_mask.dart
@@ -357,9 +357,8 @@
         .any((e) => e.needsNoSuchMethodHandling(selector, closedWorld));
   }
 
-  bool canHit(
-      MemberEntity element, Selector selector, JClosedWorld closedWorld) {
-    return disjointMasks.any((e) => e.canHit(element, selector, closedWorld));
+  bool canHit(MemberEntity element, Name name, JClosedWorld closedWorld) {
+    return disjointMasks.any((e) => e.canHit(element, name, closedWorld));
   }
 
   MemberEntity locateSingleMember(Selector selector, JClosedWorld closedWorld) {
diff --git a/pkg/compiler/lib/src/js_backend/interceptor_data.dart b/pkg/compiler/lib/src/js_backend/interceptor_data.dart
index 0e364c0..06c66ae 100644
--- a/pkg/compiler/lib/src/js_backend/interceptor_data.dart
+++ b/pkg/compiler/lib/src/js_backend/interceptor_data.dart
@@ -183,7 +183,7 @@
       return selector.applies(element) &&
           (mask == null ||
               closedWorld.abstractValueDomain
-                  .isTargetingMember(mask, element, selector)
+                  .isTargetingMember(mask, element, selector.memberName)
                   .isPotentiallyTrue);
     });
   }
diff --git a/pkg/compiler/lib/src/js_emitter/class_stub_generator.dart b/pkg/compiler/lib/src/js_emitter/class_stub_generator.dart
index e088e03..73a5d1c 100644
--- a/pkg/compiler/lib/src/js_emitter/class_stub_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/class_stub_generator.dart
@@ -4,7 +4,7 @@
 
 library dart2js.js_emitter.class_stub_generator;
 
-import '../common/names.dart' show Identifiers;
+import '../common/names.dart' show Identifiers, Selectors;
 import '../common_elements.dart' show CommonElements;
 import '../elements/entities.dart';
 import '../js/js.dart' as jsAst;
@@ -125,7 +125,8 @@
     for (Selector selector in selectors.keys) {
       if (generatedSelectors.contains(selector)) continue;
       if (!selector.appliesUnnamed(member)) continue;
-      if (selectors[selector].applies(member, selector, _closedWorld)) {
+      if (selectors[selector]
+          .canHit(member, selector.memberName, _closedWorld)) {
         generatedSelectors.add(selector);
 
         jsAst.Name invocationName = _namer.invocationName(selector);
@@ -165,6 +166,16 @@
     void addNoSuchMethodHandlers(
         String ignore, Map<Selector, SelectorConstraints> selectors) {
       for (Selector selector in selectors.keys) {
+        if (selector == Selectors.runtimeType_ ||
+            selector == Selectors.equals ||
+            selector == Selectors.toString_ ||
+            selector == Selectors.hashCode_ ||
+            selector == Selectors.noSuchMethod_) {
+          // Skip Object methods since these need no noSuchMethod handling
+          // regardless of the precision of the selector constraints.
+          continue;
+        }
+
         SelectorConstraints maskSet = selectors[selector];
         if (maskSet.needsNoSuchMethodHandling(selector, _closedWorld)) {
           jsAst.Name jsName = _namer.invocationMirrorInternalName(selector);
diff --git a/pkg/compiler/lib/src/js_emitter/parameter_stub_generator.dart b/pkg/compiler/lib/src/js_emitter/parameter_stub_generator.dart
index 7076c68..ac44280 100644
--- a/pkg/compiler/lib/src/js_emitter/parameter_stub_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/parameter_stub_generator.dart
@@ -378,7 +378,8 @@
     for (Selector selector in liveSelectors.keys) {
       if (renamedCallSelectors.contains(selector)) continue;
       if (!selector.appliesUnnamed(member)) continue;
-      if (!liveSelectors[selector].applies(member, selector, _closedWorld)) {
+      if (!liveSelectors[selector]
+          .canHit(member, selector.memberName, _closedWorld)) {
         continue;
       }
 
diff --git a/pkg/compiler/lib/src/js_emitter/program_builder/field_visitor.dart b/pkg/compiler/lib/src/js_emitter/program_builder/field_visitor.dart
index c5f8d9a..e1b0d46 100644
--- a/pkg/compiler/lib/src/js_emitter/program_builder/field_visitor.dart
+++ b/pkg/compiler/lib/src/js_emitter/program_builder/field_visitor.dart
@@ -146,7 +146,7 @@
     assert(field.isField);
     if (fieldAccessNeverThrows(field)) return false;
     return field.enclosingClass != null &&
-        _codegenWorldBuilder.hasInvokedGetter(field, _closedWorld);
+        _codegenWorldBuilder.hasInvokedGetter(field);
   }
 
   bool fieldNeedsSetter(FieldEntity field) {
@@ -154,7 +154,7 @@
     if (fieldAccessNeverThrows(field)) return false;
     if (!field.isAssignable) return false;
     return field.enclosingClass != null &&
-        _codegenWorldBuilder.hasInvokedSetter(field, _closedWorld);
+        _codegenWorldBuilder.hasInvokedSetter(field);
   }
 
   static bool fieldAccessNeverThrows(FieldEntity field) {
diff --git a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
index d4f6901..ea3c298 100644
--- a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
+++ b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
@@ -884,7 +884,7 @@
         isClosureCallMethod = true;
       } else {
         // Careful with operators.
-        canTearOff = _worldBuilder.hasInvokedGetter(element, _closedWorld);
+        canTearOff = _worldBuilder.hasInvokedGetter(element);
         assert(canTearOff ||
             !_worldBuilder.methodsNeedingSuperGetter.contains(element));
         tearOffName = _namer.getterForElement(element);
diff --git a/pkg/compiler/lib/src/js_model/js_world.dart b/pkg/compiler/lib/src/js_model/js_world.dart
index 4979d38..e277dd8 100644
--- a/pkg/compiler/lib/src/js_model/js_world.dart
+++ b/pkg/compiler/lib/src/js_model/js_world.dart
@@ -14,6 +14,7 @@
 import '../diagnostics/diagnostic_listener.dart';
 import '../elements/entities.dart';
 import '../elements/entity_utils.dart' as utils;
+import '../elements/names.dart';
 import '../elements/types.dart';
 import '../environment.dart';
 import '../inferrer/abstract_value_domain.dart';
@@ -498,15 +499,13 @@
   }
 
   @override
-  bool hasElementIn(ClassEntity cls, Selector selector, Entity element) {
+  bool hasElementIn(ClassEntity cls, Name name, Entity element) {
     while (cls != null) {
-      MemberEntity member = elementEnvironment.lookupLocalClassMember(
-          cls, selector.name,
-          setter: selector.isSetter);
+      MemberEntity member = elementEnvironment
+          .lookupLocalClassMember(cls, name.text, setter: name.isSetter);
       if (member != null &&
           !member.isAbstract &&
-          (!selector.memberName.isPrivate ||
-              member.library == selector.library)) {
+          (!name.isPrivate || member.library == name.library)) {
         return member == element;
       }
       cls = elementEnvironment.getSuperClass(cls);
@@ -529,7 +528,7 @@
       return _hasConcreteMatch(
           elementEnvironment.getSuperClass(enclosingClass), selector);
     }
-    return selector.appliesUntyped(element);
+    return selector.appliesUnnamed(element);
   }
 
   bool _isNamedMixinApplication(ClassEntity cls) {
diff --git a/pkg/compiler/lib/src/options.dart b/pkg/compiler/lib/src/options.dart
index 7b10c51..c3bbb08 100644
--- a/pkg/compiler/lib/src/options.dart
+++ b/pkg/compiler/lib/src/options.dart
@@ -143,6 +143,9 @@
   /// Whether to disable global type inference.
   bool disableTypeInference = false;
 
+  /// Whether to use the trivial abstract value domain.
+  bool useTrivialAbstractValueDomain = false;
+
   /// Whether to disable optimization for need runtime type information.
   bool disableRtiOptimization = false;
 
@@ -313,6 +316,8 @@
       ..disableInlining = _hasOption(options, Flags.disableInlining)
       ..disableProgramSplit = _hasOption(options, Flags.disableProgramSplit)
       ..disableTypeInference = _hasOption(options, Flags.disableTypeInference)
+      ..useTrivialAbstractValueDomain =
+          _hasOption(options, Flags.useTrivialAbstractValueDomain)
       ..disableRtiOptimization =
           _hasOption(options, Flags.disableRtiOptimization)
       ..dumpInfo = _hasOption(options, Flags.dumpInfo)
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index d5a20c0..8bcaf1d 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -3415,7 +3415,7 @@
       HInstruction lengthInput = arguments.first;
       if (lengthInput.isNumber(abstractValueDomain).isPotentiallyFalse) {
         HTypeConversion conversion = new HTypeConversion(
-            null,
+            commonElements.numType,
             HTypeConversion.ARGUMENT_TYPE_CHECK,
             abstractValueDomain.numType,
             lengthInput,
@@ -4971,7 +4971,7 @@
         if (!selector.applies(function)) return false;
         if (mask != null &&
             abstractValueDomain
-                .isTargetingMember(mask, function, selector)
+                .isTargetingMember(mask, function, selector.memberName)
                 .isDefinitelyFalse) {
           return false;
         }
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index d39b92a..fb80e88 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -3029,49 +3029,24 @@
   }
 
   js.Expression generateReceiverOrArgumentTypeTest(HTypeConversion node) {
+    DartType type = node.typeExpression;
     HInstruction input = node.checkedInput;
-    AbstractValue inputType = node.inputType ?? input.instructionType;
     AbstractValue checkedType = node.checkedType;
     // This path is no longer used for indexable primitive types.
     assert(_abstractValueDomain.isJsIndexable(checkedType).isPotentiallyFalse);
     // Figure out if it is beneficial to use a null check.  V8 generally prefers
     // 'typeof' checks, but for integers we cannot compile this test into a
     // single typeof check so the null check is cheaper.
-    bool isIntCheck =
-        _abstractValueDomain.isIntegerOrNull(checkedType).isDefinitelyTrue;
-    bool turnIntoNumCheck = isIntCheck &&
-        _abstractValueDomain.isIntegerOrNull(inputType).isDefinitelyTrue;
-    bool turnIntoNullCheck = !turnIntoNumCheck &&
-        (_abstractValueDomain.includeNull(checkedType) == inputType) &&
-        isIntCheck;
-
-    if (turnIntoNullCheck) {
-      use(input);
-      return new js.Binary("==", pop(), new js.LiteralNull())
-          .withSourceInformation(input.sourceInformation);
-    } else if (isIntCheck && !turnIntoNumCheck) {
-      // input is !int
-      checkBigInt(input, '!==', input.sourceInformation);
-      return pop();
-    } else if (turnIntoNumCheck ||
-        _abstractValueDomain.isNumberOrNull(checkedType).isDefinitelyTrue) {
+    if (type == _commonElements.numType) {
       // input is !num
       checkNum(input, '!==', input.sourceInformation);
       return pop();
-    } else if (_abstractValueDomain
-        .isBooleanOrNull(checkedType)
-        .isDefinitelyTrue) {
+    } else if (type == _commonElements.boolType) {
       // input is !bool
       checkBool(input, '!==', input.sourceInformation);
       return pop();
-    } else if (_abstractValueDomain
-        .isStringOrNull(checkedType)
-        .isDefinitelyTrue) {
-      // input is !string
-      checkString(input, '!==', input.sourceInformation);
-      return pop();
     }
-    throw failedAt(input, 'Unexpected check: $checkedType.');
+    throw failedAt(input, 'Unexpected check: $type.');
   }
 
   void visitTypeConversion(HTypeConversion node) {
diff --git a/pkg/compiler/lib/src/ssa/codegen_helpers.dart b/pkg/compiler/lib/src/ssa/codegen_helpers.dart
index 8a13587..db168fa 100644
--- a/pkg/compiler/lib/src/ssa/codegen_helpers.dart
+++ b/pkg/compiler/lib/src/ssa/codegen_helpers.dart
@@ -142,7 +142,12 @@
     return node;
   }
 
-  void tryReplaceInterceptorWithDummy(
+  HInstruction visitOneShotInterceptor(HOneShotInterceptor node) {
+    // The receiver parameter should never be replaced with a dummy constant.
+    return node;
+  }
+
+  bool tryReplaceInterceptorWithDummy(
       HInvoke node, Selector selector, AbstractValue mask) {
     // Calls of the form
     //
@@ -166,7 +171,7 @@
 
     // TODO(15933): Make automatically generated property extraction closures
     // work with the dummy receiver optimization.
-    if (selector.isGetter) return;
+    if (selector.isGetter) return false;
 
     // This assignment of inputs is uniform for HInvokeDynamic and HInvokeSuper.
     HInstruction interceptor = node.inputs[0];
@@ -183,8 +188,10 @@
         receiverArgument.usedBy.remove(node);
         node.inputs[1] = dummy;
         dummy.usedBy.add(node);
+        return true;
       }
     }
+    return false;
   }
 
   HInstruction visitFieldSet(HFieldSet setter) {
diff --git a/pkg/compiler/lib/src/ssa/nodes.dart b/pkg/compiler/lib/src/ssa/nodes.dart
index ed1be86..432eb78 100644
--- a/pkg/compiler/lib/src/ssa/nodes.dart
+++ b/pkg/compiler/lib/src/ssa/nodes.dart
@@ -2830,6 +2830,7 @@
 class HOneShotInterceptor extends HInvokeDynamic {
   List<DartType> typeArguments;
   Set<ClassEntity> interceptedClasses;
+
   HOneShotInterceptor(
       AbstractValueDomain domain,
       Selector selector,
@@ -2840,7 +2841,7 @@
       this.interceptedClasses)
       : super(selector, mask, null, inputs, true, type) {
     assert(inputs[0] is HConstant);
-    assert(inputs[0].isNull(domain).isDefinitelyTrue);
+    assert(inputs[0].instructionType == domain.nullType);
     assert(selector.callStructure.typeArgumentCount == typeArguments.length);
   }
   bool isCallOnInterceptor(JClosedWorld closedWorld) => true;
@@ -3128,6 +3129,7 @@
         super(<HInstruction>[input], type) {
     assert(!isReceiverTypeCheck || receiverTypeCheckSelector != null);
     assert(typeExpression == null || !typeExpression.isTypedef);
+    assert(!isControlFlow() || typeExpression != null);
     sourceElement = input.sourceElement;
     this.sourceInformation = sourceInformation;
   }
diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
index 822a583..c223dd6 100644
--- a/pkg/compiler/lib/src/ssa/optimize.dart
+++ b/pkg/compiler/lib/src/ssa/optimize.dart
@@ -550,7 +550,7 @@
       return selector.applies(element) &&
           (mask == null ||
               _abstractValueDomain
-                  .isTargetingMember(mask, element, selector)
+                  .isTargetingMember(mask, element, selector.memberName)
                   .isPotentiallyTrue);
     }
 
diff --git a/pkg/compiler/lib/src/ssa/types_propagation.dart b/pkg/compiler/lib/src/ssa/types_propagation.dart
index b95f1e0..492e6ea 100644
--- a/pkg/compiler/lib/src/ssa/types_propagation.dart
+++ b/pkg/compiler/lib/src/ssa/types_propagation.dart
@@ -4,6 +4,7 @@
 
 import '../common_elements.dart' show CommonElements;
 import '../elements/entities.dart';
+import '../elements/types.dart';
 import '../inferrer/abstract_value_domain.dart';
 import '../inferrer/types.dart';
 import '../options.dart';
@@ -270,12 +271,12 @@
   }
 
   void convertInput(HInvokeDynamic instruction, HInstruction input,
-      AbstractValue type, int kind) {
+      AbstractValue type, int kind, DartType typeExpression) {
     Selector selector = (kind == HTypeConversion.RECEIVER_TYPE_CHECK)
         ? instruction.selector
         : null;
     HTypeConversion converted = new HTypeConversion(
-        null, kind, type, input, instruction.sourceInformation,
+        typeExpression, kind, type, input, instruction.sourceInformation,
         receiverTypeCheckSelector: selector);
     instruction.block.addBefore(instruction, converted);
     input.replaceAllUsersDominatedBy(instruction, converted);
@@ -308,7 +309,8 @@
           instruction,
           receiver,
           abstractValueDomain.excludeNull(receiver.instructionType),
-          HTypeConversion.RECEIVER_TYPE_CHECK);
+          HTypeConversion.RECEIVER_TYPE_CHECK,
+          commonElements.numType);
       return true;
     } else if (instruction.element == null) {
       if (closedWorld.includesClosureCall(
@@ -322,14 +324,18 @@
         ClassEntity cls = target.enclosingClass;
         AbstractValue type = abstractValueDomain.createNonNullSubclass(cls);
         // We currently only optimize on some primitive types.
-        if (abstractValueDomain.isNumberOrNull(type).isPotentiallyFalse &&
-            abstractValueDomain.isBooleanOrNull(type).isPotentiallyFalse) {
+        DartType typeExpression;
+        if (abstractValueDomain.isNumberOrNull(type).isDefinitelyTrue) {
+          typeExpression = commonElements.numType;
+        } else if (abstractValueDomain.isBooleanOrNull(type).isDefinitelyTrue) {
+          typeExpression = commonElements.boolType;
+        } else {
           return false;
         }
         if (!isCheckEnoughForNsmOrAe(receiver, type)) return false;
         instruction.element = target;
-        convertInput(
-            instruction, receiver, type, HTypeConversion.RECEIVER_TYPE_CHECK);
+        convertInput(instruction, receiver, type,
+            HTypeConversion.RECEIVER_TYPE_CHECK, typeExpression);
         return true;
       }
     }
@@ -357,8 +363,8 @@
       // variant and will do the check in their method anyway. We
       // still add a check because it allows to GVN these operations,
       // but we should find a better way.
-      convertInput(
-          instruction, right, type, HTypeConversion.ARGUMENT_TYPE_CHECK);
+      convertInput(instruction, right, type,
+          HTypeConversion.ARGUMENT_TYPE_CHECK, commonElements.numType);
       return true;
     }
     return false;
diff --git a/pkg/compiler/lib/src/universe/codegen_world_builder.dart b/pkg/compiler/lib/src/universe/codegen_world_builder.dart
index 5a42501..395639e 100644
--- a/pkg/compiler/lib/src/universe/codegen_world_builder.dart
+++ b/pkg/compiler/lib/src/universe/codegen_world_builder.dart
@@ -71,9 +71,9 @@
   ConstantValue getConstantFieldInitializer(covariant FieldEntity field);
 
   /// Returns `true` if [member] is invoked as a setter.
-  bool hasInvokedSetter(MemberEntity member, JClosedWorld world);
+  bool hasInvokedSetter(MemberEntity member);
 
-  bool hasInvokedGetter(MemberEntity member, JClosedWorld world);
+  bool hasInvokedGetter(MemberEntity member);
 
   Map<Selector, SelectorConstraints> invocationsByName(String name);
 
@@ -260,7 +260,7 @@
     for (Selector selector in selectors.keys) {
       if (selector.appliesUnnamed(member)) {
         SelectorConstraints masks = selectors[selector];
-        if (masks.applies(member, selector, world)) {
+        if (masks.canHit(member, selector.memberName, world)) {
           return true;
         }
       }
@@ -268,17 +268,17 @@
     return false;
   }
 
-  bool hasInvocation(MemberEntity member, JClosedWorld world) {
-    return _hasMatchingSelector(_invokedNames[member.name], member, world);
+  bool hasInvocation(MemberEntity member) {
+    return _hasMatchingSelector(_invokedNames[member.name], member, _world);
   }
 
-  bool hasInvokedGetter(MemberEntity member, JClosedWorld world) {
-    return _hasMatchingSelector(_invokedGetters[member.name], member, world) ||
+  bool hasInvokedGetter(MemberEntity member) {
+    return _hasMatchingSelector(_invokedGetters[member.name], member, _world) ||
         member.isFunction && methodsNeedingSuperGetter.contains(member);
   }
 
-  bool hasInvokedSetter(MemberEntity member, JClosedWorld world) {
-    return _hasMatchingSelector(_invokedSetters[member.name], member, world);
+  bool hasInvokedSetter(MemberEntity member) {
+    return _hasMatchingSelector(_invokedSetters[member.name], member, _world);
   }
 
   bool registerDynamicUse(
@@ -289,8 +289,9 @@
     void _process(Map<String, Set<MemberUsage>> memberMap,
         EnumSet<MemberUse> action(MemberUsage usage)) {
       _processSet(memberMap, methodName, (MemberUsage usage) {
-        if (selectorConstraintsStrategy.appliedUnnamed(
-            dynamicUse, usage.entity, _world)) {
+        if (selector.appliesUnnamed(usage.entity) &&
+            selectorConstraintsStrategy.appliedUnnamed(
+                dynamicUse, usage.entity, _world)) {
           memberUsed(usage.entity, action(usage));
           return true;
         }
@@ -331,8 +332,12 @@
     Object constraint = dynamicUse.receiverConstraint;
     Map<Selector, SelectorConstraints> selectors =
         selectorMap[name] ??= new Maplet<Selector, SelectorConstraints>();
-    UniverseSelectorConstraints constraints = selectors[selector] ??=
-        selectorConstraintsStrategy.createSelectorConstraints(selector);
+    UniverseSelectorConstraints constraints = selectors[selector];
+    if (constraints == null) {
+      selectors[selector] = selectorConstraintsStrategy
+          .createSelectorConstraints(selector, constraint);
+      return true;
+    }
     return constraints.addReceiverConstraint(constraint);
   }
 
@@ -504,13 +509,13 @@
       MemberUsage usage = new MemberUsage(member, isNative: isNative);
       EnumSet<MemberUse> useSet = new EnumSet<MemberUse>();
       useSet.addAll(usage.appliedUse);
-      if (!usage.hasRead && hasInvokedGetter(member, _world)) {
+      if (!usage.hasRead && hasInvokedGetter(member)) {
         useSet.addAll(usage.read());
       }
-      if (!usage.hasWrite && hasInvokedSetter(member, _world)) {
+      if (!usage.hasWrite && hasInvokedSetter(member)) {
         useSet.addAll(usage.write());
       }
-      if (!usage.hasInvoke && hasInvocation(member, _world)) {
+      if (!usage.hasInvoke && hasInvocation(member)) {
         useSet.addAll(usage.invoke());
       }
 
diff --git a/pkg/compiler/lib/src/universe/function_set.dart b/pkg/compiler/lib/src/universe/function_set.dart
index f489158..e8edd4b 100644
--- a/pkg/compiler/lib/src/universe/function_set.dart
+++ b/pkg/compiler/lib/src/universe/function_set.dart
@@ -109,7 +109,7 @@
   bool applies(MemberEntity element, AbstractValueDomain domain) {
     if (!selector.appliesUnnamed(element)) return false;
     return domain
-        .isTargetingMember(receiver, element, selector)
+        .isTargetingMember(receiver, element, selector.memberName)
         .isPotentiallyTrue;
   }
 
diff --git a/pkg/compiler/lib/src/universe/resolution_world_builder.dart b/pkg/compiler/lib/src/universe/resolution_world_builder.dart
index 6e75f80..6119207 100644
--- a/pkg/compiler/lib/src/universe/resolution_world_builder.dart
+++ b/pkg/compiler/lib/src/universe/resolution_world_builder.dart
@@ -589,7 +589,7 @@
     for (Selector selector in selectors.keys) {
       if (selector.appliesUnnamed(member)) {
         SelectorConstraints masks = selectors[selector];
-        if (masks.applies(member, selector, this)) {
+        if (masks.canHit(member, selector.memberName, this)) {
           return true;
         }
       }
@@ -623,8 +623,9 @@
     void _process(Map<String, Set<MemberUsage>> memberMap,
         EnumSet<MemberUse> action(MemberUsage usage)) {
       _processSet(memberMap, methodName, (MemberUsage usage) {
-        if (_selectorConstraintsStrategy.appliedUnnamed(
-            dynamicUse, usage.entity, this)) {
+        if (selector.appliesUnnamed(usage.entity) &&
+            _selectorConstraintsStrategy.appliedUnnamed(
+                dynamicUse, usage.entity, this)) {
           memberUsed(usage.entity, action(usage));
           return true;
         }
@@ -661,10 +662,12 @@
     Object constraint = dynamicUse.receiverConstraint;
     Map<Selector, SelectorConstraints> selectors = selectorMap.putIfAbsent(
         name, () => new Maplet<Selector, SelectorConstraints>());
-    UniverseSelectorConstraints constraints =
-        selectors.putIfAbsent(selector, () {
-      return _selectorConstraintsStrategy.createSelectorConstraints(selector);
-    });
+    UniverseSelectorConstraints constraints = selectors[selector];
+    if (constraints == null) {
+      selectors[selector] = _selectorConstraintsStrategy
+          .createSelectorConstraints(selector, constraint);
+      return true;
+    }
     return constraints.addReceiverConstraint(constraint);
   }
 
diff --git a/pkg/compiler/lib/src/universe/selector.dart b/pkg/compiler/lib/src/universe/selector.dart
index 42cac09..47f974e 100644
--- a/pkg/compiler/lib/src/universe/selector.dart
+++ b/pkg/compiler/lib/src/universe/selector.dart
@@ -250,11 +250,6 @@
 
   bool appliesUnnamed(MemberEntity element) {
     assert(name == element.name);
-    return appliesUntyped(element);
-  }
-
-  bool appliesUntyped(MemberEntity element) {
-    assert(name == element.name);
     if (memberName.isPrivate && memberName.library != element.library) {
       // TODO(johnniwinther): Maybe this should be
       // `memberName != element.memberName`.
diff --git a/pkg/compiler/lib/src/universe/world_builder.dart b/pkg/compiler/lib/src/universe/world_builder.dart
index 9eb4560..e80c180 100644
--- a/pkg/compiler/lib/src/universe/world_builder.dart
+++ b/pkg/compiler/lib/src/universe/world_builder.dart
@@ -6,6 +6,7 @@
 
 import '../common_elements.dart';
 import '../elements/entities.dart';
+import '../elements/names.dart';
 import '../elements/types.dart';
 import '../ir/static_type.dart';
 import '../js_backend/native_data.dart' show NativeBasicData;
@@ -33,7 +34,7 @@
 /// the selector constraints for dynamic calls to 'foo' with two positional
 /// arguments could be 'receiver of exact instance `A` or `B`'.
 abstract class SelectorConstraints {
-  /// Returns `true` if [selector] applies to [element] under these constraints
+  /// Returns `true` if [name] applies to [element] under these constraints
   /// given the closed [world].
   ///
   /// Consider for instance in this world:
@@ -48,7 +49,7 @@
   ///
   /// Ideally the selector constraints for calls `foo` with two positional
   /// arguments apply to `A.foo` but `B.foo`.
-  bool applies(MemberEntity element, Selector selector, covariant World world);
+  bool canHit(MemberEntity element, Name name, covariant World world);
 
   /// Returns `true` if at least one of the receivers matching these constraints
   /// in the closed [world] have no implementation matching [selector].
@@ -76,7 +77,8 @@
 abstract class SelectorConstraintsStrategy {
   /// Create a [UniverseSelectorConstraints] to represent the global receiver
   /// constraints for dynamic call sites with [selector].
-  UniverseSelectorConstraints createSelectorConstraints(Selector selector);
+  UniverseSelectorConstraints createSelectorConstraints(
+      Selector selector, Object initialConstraint);
 
   /// Returns `true`  if [member] is a potential target of [dynamicUse].
   bool appliedUnnamed(DynamicUse dynamicUse, MemberEntity member, World world);
@@ -89,8 +91,10 @@
 class StrongModeWorldStrategy implements SelectorConstraintsStrategy {
   const StrongModeWorldStrategy();
 
-  StrongModeWorldConstraints createSelectorConstraints(Selector selector) {
-    return new StrongModeWorldConstraints();
+  StrongModeWorldConstraints createSelectorConstraints(
+      Selector selector, Object initialConstraint) {
+    return new StrongModeWorldConstraints()
+      ..addReceiverConstraint(initialConstraint);
   }
 
   @override
@@ -99,7 +103,8 @@
     Selector selector = dynamicUse.selector;
     StrongModeConstraint constraint = dynamicUse.receiverConstraint;
     return selector.appliesUnnamed(member) &&
-        (constraint == null || constraint.canHit(member, selector, world));
+        (constraint == null ||
+            constraint.canHit(member, selector.memberName, world));
   }
 }
 
@@ -108,11 +113,11 @@
   Set<StrongModeConstraint> _constraints;
 
   @override
-  bool applies(MemberEntity element, Selector selector, World world) {
+  bool canHit(MemberEntity element, Name name, World world) {
     if (isAll) return true;
     if (_constraints == null) return false;
     for (StrongModeConstraint constraint in _constraints) {
-      if (constraint.canHit(element, selector, world)) {
+      if (constraint.canHit(element, name, world)) {
         return true;
       }
     }
@@ -177,7 +182,7 @@
 
   bool needsNoSuchMethodHandling(Selector selector, World world) => true;
 
-  bool canHit(MemberEntity element, Selector selector, OpenWorld world) {
+  bool canHit(MemberEntity element, Name name, OpenWorld world) {
     return world.isInheritedIn(element, cls, relation);
   }
 
diff --git a/pkg/compiler/lib/src/world.dart b/pkg/compiler/lib/src/world.dart
index 73446b6..b2bcb10 100644
--- a/pkg/compiler/lib/src/world.dart
+++ b/pkg/compiler/lib/src/world.dart
@@ -16,6 +16,7 @@
 import 'deferred_load.dart';
 import 'diagnostics/diagnostic_listener.dart';
 import 'elements/entities.dart';
+import 'elements/names.dart';
 import 'elements/types.dart';
 import 'inferrer/abstract_value_domain.dart';
 import 'ir/static_type.dart';
@@ -166,10 +167,9 @@
   bool needsNoSuchMethod(ClassEntity cls, Selector selector, ClassQuery query);
 
   /// Returns whether [element] will be the one used at runtime when being
-  /// invoked on an instance of [cls]. [selector] is used to ensure library
+  /// invoked on an instance of [cls]. [name] is used to ensure library
   /// privacy is taken into account.
-  bool hasElementIn(
-      covariant ClassEntity cls, Selector selector, covariant Entity element);
+  bool hasElementIn(ClassEntity cls, Name name, MemberEntity element);
 
   /// Returns `true` if the field [element] is known to be effectively final.
   bool fieldNeverChanges(MemberEntity element);
diff --git a/tests/compiler/dart2js/inference/trivial_abstract_value_domain_test.dart b/tests/compiler/dart2js/inference/trivial_abstract_value_domain_test.dart
new file mode 100644
index 0000000..6a8f389
--- /dev/null
+++ b/tests/compiler/dart2js/inference/trivial_abstract_value_domain_test.dart
@@ -0,0 +1,28 @@
+// Copyright (c) 2018, 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.
+
+import 'package:args/args.dart';
+import 'package:async_helper/async_helper.dart';
+import 'package:compiler/src/commandline_options.dart';
+
+import '../helpers/args_helper.dart';
+import '../helpers/memory_compiler.dart';
+
+main(List<String> args) {
+  ArgParser argParser = createArgParser();
+
+  asyncTest(() async {
+    ArgResults argResults = argParser.parse(args);
+    Uri entryPoint = getEntryPoint(argResults) ??
+        Uri.base.resolve('samples-dev/swarm/swarm.dart');
+    Uri librariesSpecificationUri = getLibrariesSpec(argResults);
+    Uri packageConfig = getPackages(argResults);
+    List<String> options = getOptions(argResults);
+    await runCompiler(
+        entryPoint: entryPoint,
+        packageConfig: packageConfig,
+        librariesSpecificationUri: librariesSpecificationUri,
+        options: [Flags.useTrivialAbstractValueDomain]..addAll(options));
+  });
+}
diff --git a/tests/compiler/dart2js_native/native_method_inlining_test.dart b/tests/compiler/dart2js_native/native_method_inlining_test.dart
index 1dd30c1..f673eeb 100644
--- a/tests/compiler/dart2js_native/native_method_inlining_test.dart
+++ b/tests/compiler/dart2js_native/native_method_inlining_test.dart
@@ -82,13 +82,13 @@
 void match(String s, String pattern1) {
   var pattern2 = pattern1.replaceAll(' ', '');
   Expect.isTrue(s.contains(pattern1) || s.contains(pattern2),
-      "expected $pattern1 or $pattern2");
+      "expected $pattern1 or $pattern2 in '$s'");
 }
 
 void nomatch(String s, String pattern1) {
   var pattern2 = pattern1.replaceAll(' ', '');
   Expect.isFalse(s.contains(pattern1) || s.contains(pattern2),
-      "should not have $pattern1 or $pattern2");
+      "should not have $pattern1 or $pattern2 in '$s'");
 }
 
 test1() {
diff --git a/tests/compiler/dart2js_native/native_mixin_field2_test.dart b/tests/compiler/dart2js_native/native_mixin_field2_test.dart
new file mode 100644
index 0000000..408bdb6
--- /dev/null
+++ b/tests/compiler/dart2js_native/native_mixin_field2_test.dart
@@ -0,0 +1,87 @@
+// Copyright (c) 2013, 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.
+
+import "native_testing.dart";
+
+// Test that native classes can use ordinary Dart classes with fields
+// as mixins.
+
+@Native("A")
+class A {
+  var foo;
+}
+
+class A1 {
+  get foo => 42;
+  set foo(value) {}
+}
+
+@Native("B")
+class B extends A with M1, M2 {
+  var bar;
+}
+
+class B1 extends A1 with M1, M2 {
+  get bar => 42;
+  set bar(value) {}
+}
+
+class M1 {
+  var baz; // This field is not a native field, even when mixed in.
+}
+
+class M2 {
+  var bar;
+  var buz;
+}
+
+A makeA() native;
+B makeB() native;
+
+void setup() {
+  JS('', r"""
+(function(){
+  function A() {this.foo='A-foo';}
+  function B() {A.call(this);this.bar='B-bar';this.baz='M1-baz';}
+  makeA = function(){return new A()};
+  makeB = function(){return new B()};
+
+  self.nativeConstructor(A);
+  self.nativeConstructor(B);
+})()""");
+}
+
+@AssumeDynamic()
+confuse(x) => x;
+
+main() {
+  nativeTesting();
+  setup();
+  dynamic a = makeA();
+  a ??= new A1();
+  Expect.equals("A-foo", confuse(a).foo);
+  Expect.throws(() => confuse(a).bar, (e) => e is NoSuchMethodError);
+  Expect.throws(() => confuse(a).baz, (e) => e is NoSuchMethodError);
+  Expect.throws(() => confuse(a).buz, (e) => e is NoSuchMethodError);
+
+  dynamic b = makeB();
+  b ??= new B1();
+  Expect.equals("A-foo", confuse(b).foo);
+  Expect.equals("B-bar", confuse(b).bar);
+  // Expect.equals("M1-baz", b.baz);  // not true, see M1.
+  Expect.isNull(confuse(b).baz); // native b.baz is not the same as dart b.baz.
+  Expect.isNull(confuse(b).buz);
+
+  M1 m1 = new M1();
+  Expect.throws(() => confuse(m1).foo, (e) => e is NoSuchMethodError);
+  Expect.throws(() => confuse(m1).bar, (e) => e is NoSuchMethodError);
+  Expect.isNull(m1.baz);
+  Expect.throws(() => confuse(m1).buz, (e) => e is NoSuchMethodError);
+
+  M2 m2 = new M2();
+  Expect.throws(() => confuse(m2).foo, (e) => e is NoSuchMethodError);
+  Expect.isNull(confuse(m2).bar);
+  Expect.throws(() => confuse(m2).baz, (e) => e is NoSuchMethodError);
+  Expect.isNull(confuse(m2).buz);
+}