Version 2.10.0-66.0.dev

Merge commit 'fd44ff7229b8a4fd13618f670cd896c5f11f9b99' into 'dev'
diff --git a/pkg/compiler/lib/src/inferrer/powersets/powerset_bits.dart b/pkg/compiler/lib/src/inferrer/powersets/powerset_bits.dart
index 193e37c..a7304ff 100644
--- a/pkg/compiler/lib/src/inferrer/powersets/powerset_bits.dart
+++ b/pkg/compiler/lib/src/inferrer/powersets/powerset_bits.dart
@@ -36,12 +36,15 @@
   static const int _otherIndex = 3;
 
   static const int _maxIndex = _otherIndex;
+
   static const List<int> _singletonIndices = [
     _trueIndex,
     _falseIndex,
     _nullIndex,
   ];
 
+  static const List<String> _bitNames = ['true', 'false', 'null', 'other'];
+
   PowersetBitsDomain(this._closedWorld);
 
   CommonElements get commonElements => _closedWorld.commonElements;
@@ -87,6 +90,33 @@
     return AbstractBool.Maybe;
   }
 
+  /// Returns a descriptive string for [bits]
+  static String toText(int bits, {bool omitIfTop = false}) {
+    int boolDomainMask = (1 << _maxIndex + 1) - 1;
+    return _toTextDomain(bits, boolDomainMask, omitIfTop);
+  }
+
+  /// Returns a descriptive string for a subset of [bits] defined by
+  /// [domainMask]. If [omitIfTop] is `true` and all the bits in the
+  /// [domainMask] are set, an empty string is returned.
+  static String _toTextDomain(int bits, int domainMask, bool omitIfTop) {
+    bits &= domainMask;
+    if (bits == domainMask && omitIfTop) return '';
+    final sb = StringBuffer();
+    sb.write('{');
+    String comma = '';
+    while (bits != 0) {
+      int lowestBit = bits & ~(bits - 1);
+      int index = lowestBit.bitLength - 1;
+      sb.write(comma);
+      sb.write(_bitNames[index]);
+      comma = ',';
+      bits &= ~lowestBit;
+    }
+    sb.write('}');
+    return '$sb';
+  }
+
   AbstractBool needsNoSuchMethodHandling(int receiver, Selector selector) =>
       AbstractBool.Maybe;
 
diff --git a/pkg/compiler/lib/src/inferrer/powersets/powersets.dart b/pkg/compiler/lib/src/inferrer/powersets/powersets.dart
index 9b1111d..5f2fb1e 100644
--- a/pkg/compiler/lib/src/inferrer/powersets/powersets.dart
+++ b/pkg/compiler/lib/src/inferrer/powersets/powersets.dart
@@ -40,7 +40,8 @@
 
   @override
   String toString() =>
-      '[Powerset of ${_abstractValue.toString()} with bits ${_powersetBits}]';
+      '${PowersetBitsDomain.toText(_powersetBits, omitIfTop: true)}'
+      '${_abstractValue}';
 }
 
 AbstractValue unwrapOrNull(PowersetValue powerset) {
@@ -99,7 +100,7 @@
   AbstractBool isJsIndexableAndIterable(covariant PowersetValue value) =>
       _powersetBitsDomain.isOther(value._powersetBits).isDefinitelyFalse
           ? AbstractBool.False
-          : _abstractValueDomain.isJsIndexableAndIterable(unwrapOrNull(value));
+          : _abstractValueDomain.isJsIndexableAndIterable(value._abstractValue);
 
   @override
   AbstractBool isJsIndexable(covariant PowersetValue value) =>
diff --git a/pkg/compiler/lib/src/inferrer/powersets/wrapped.dart b/pkg/compiler/lib/src/inferrer/powersets/wrapped.dart
index c30f196..8cdbaa3 100644
--- a/pkg/compiler/lib/src/inferrer/powersets/wrapped.dart
+++ b/pkg/compiler/lib/src/inferrer/powersets/wrapped.dart
@@ -74,7 +74,7 @@
 
   @override
   AbstractBool isJsIndexableAndIterable(covariant WrappedAbstractValue value) =>
-      _abstractValueDomain.isJsIndexableAndIterable(unwrapOrNull(value));
+      _abstractValueDomain.isJsIndexableAndIterable(value._abstractValue);
 
   @override
   AbstractBool isJsIndexable(covariant WrappedAbstractValue value) =>
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/masks.dart b/pkg/compiler/lib/src/inferrer/typemasks/masks.dart
index 5c25132..d6c6122 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/masks.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/masks.dart
@@ -798,8 +798,7 @@
 
   @override
   AbstractBool isJsIndexableAndIterable(covariant TypeMask mask) {
-    return AbstractBool.trueOrMaybe(mask != null &&
-        mask.satisfies(
+    return AbstractBool.trueOrMaybe(mask.satisfies(
             _closedWorld.commonElements.jsIndexableClass, _closedWorld) &&
         // String is indexable but not iterable.
         !mask.satisfies(
diff --git a/pkg/compiler/lib/src/js_model/js_strategy.dart b/pkg/compiler/lib/src/js_model/js_strategy.dart
index bd11e25..b8614dd 100644
--- a/pkg/compiler/lib/src/js_model/js_strategy.dart
+++ b/pkg/compiler/lib/src/js_model/js_strategy.dart
@@ -569,6 +569,8 @@
   bool isJsIndexableIterator(
       ir.ForInStatement node, AbstractValueDomain abstractValueDomain) {
     AbstractValue mask = typeOfIterator(node);
+    // TODO(sra): Investigate why mask is sometimes null.
+    if (mask == null) return false;
     return abstractValueDomain.isJsIndexableAndIterable(mask).isDefinitelyTrue;
   }
 
diff --git a/pkg/nnbd_migration/lib/migration_cli.dart b/pkg/nnbd_migration/lib/migration_cli.dart
index 2e99d54..a8efa5e 100644
--- a/pkg/nnbd_migration/lib/migration_cli.dart
+++ b/pkg/nnbd_migration/lib/migration_cli.dart
@@ -381,23 +381,7 @@
   }
 
   static void _defineOptions(ArgParser parser, bool hide) {
-    parser.addFlag(CommandLineOptions.applyChangesFlag,
-        defaultsTo: false,
-        negatable: false,
-        help: 'Apply the proposed null safety changes to the files on disk.');
-    parser.addFlag(
-      CommandLineOptions.ignoreErrorsFlag,
-      defaultsTo: false,
-      negatable: false,
-      help: 'Attempt to perform null safety analysis even if there are '
-          'analysis errors in the project.',
-    );
-    parser.addFlag(CommandLineOptions.ignoreExceptionsFlag,
-        defaultsTo: false,
-        negatable: false,
-        help:
-            'Attempt to perform null safety analysis even if exceptions occur.',
-        hide: hide);
+    addCoreOptions(parser, hide);
     parser.addFlag(
       CommandLineOptions.skipPubOutdatedFlag,
       defaultsTo: false,
@@ -417,6 +401,26 @@
     parser.addOption(CommandLineOptions.summaryOption,
         help:
             'Output path for a machine-readable summary of migration changes');
+  }
+
+  static void addCoreOptions(ArgParser parser, bool hide) {
+    parser.addFlag(CommandLineOptions.applyChangesFlag,
+        defaultsTo: false,
+        negatable: false,
+        help: 'Apply the proposed null safety changes to the files on disk.');
+    parser.addFlag(
+      CommandLineOptions.ignoreErrorsFlag,
+      defaultsTo: false,
+      negatable: false,
+      help: 'Attempt to perform null safety analysis even if there are '
+          'analysis errors in the project.',
+    );
+    parser.addFlag(CommandLineOptions.ignoreExceptionsFlag,
+        defaultsTo: false,
+        negatable: false,
+        help:
+            'Attempt to perform null safety analysis even if exceptions occur.',
+        hide: hide);
     parser.addFlag(CommandLineOptions.verboseFlag,
         abbr: 'v',
         defaultsTo: false,
diff --git a/tools/VERSION b/tools/VERSION
index 6e94838..b2725de 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 10
 PATCH 0
-PRERELEASE 65
+PRERELEASE 66
 PRERELEASE_PATCH 0
\ No newline at end of file