[dartdevc] implement set literal and enable-experiments support

Change-Id: Ibc45b1b1792d62a8f176e6c2f2f5c1e3134942f1
Reviewed-on: https://dart-review.googlesource.com/c/88400
Reviewed-by: Lasse R.H. Nielsen <lrn@google.com>
Reviewed-by: Vijay Menon <vsm@google.com>
Commit-Queue: Jenny Messerly <jmesserly@google.com>
diff --git a/pkg/dev_compiler/lib/src/analyzer/code_generator.dart b/pkg/dev_compiler/lib/src/analyzer/code_generator.dart
index fcc9651..15f4159 100644
--- a/pkg/dev_compiler/lib/src/analyzer/code_generator.dart
+++ b/pkg/dev_compiler/lib/src/analyzer/code_generator.dart
@@ -5727,8 +5727,21 @@
   }
 
   @override
-  JS.Expression visitSetLiteral(SetLiteral node) =>
-      throw new UnsupportedError('literal sets are not yet supported');
+  JS.Expression visitSetLiteral(SetLiteral node) {
+    var type = node.staticType as InterfaceType;
+    if (!node.isConst) {
+      var setType = _emitType(type);
+      if (node.elements.isEmpty) {
+        return js.call('#.new()', [setType]);
+      }
+      return js
+          .call('#.from([#])', [setType, _visitExpressionList(node.elements)]);
+    }
+    return _cacheConst(() => runtimeCall('constSet(#, [#])', [
+          _emitType((node.staticType as InterfaceType).typeArguments[0]),
+          _visitExpressionList(node.elements)
+        ]));
+  }
 
   JS.Expression _emitConstList(
       DartType elementType, List<JS.Expression> elements) {
diff --git a/pkg/dev_compiler/lib/src/analyzer/command.dart b/pkg/dev_compiler/lib/src/analyzer/command.dart
index 97188e1..2d32c8d 100644
--- a/pkg/dev_compiler/lib/src/analyzer/command.dart
+++ b/pkg/dev_compiler/lib/src/analyzer/command.dart
@@ -128,11 +128,12 @@
     ArgResults argResults, AnalyzerOptions analyzerOptions,
     {CompilerAnalysisDriver compilerDriver}) {
   var compilerOpts = CompilerOptions.fromArguments(argResults);
+
   var summaryPaths = compilerOpts.summaryModules.keys.toList();
   if (compilerDriver == null ||
       !compilerDriver.isCompatibleWith(analyzerOptions, summaryPaths)) {
-    compilerDriver =
-        CompilerAnalysisDriver(analyzerOptions, summaryPaths: summaryPaths);
+    compilerDriver = CompilerAnalysisDriver(analyzerOptions,
+        summaryPaths: summaryPaths, experiments: compilerOpts.experiments);
   }
   var outPaths = argResults['out'] as List<String>;
   var moduleFormats = compilerOpts.moduleFormats;
diff --git a/pkg/dev_compiler/lib/src/analyzer/driver.dart b/pkg/dev_compiler/lib/src/analyzer/driver.dart
index 5e1e76a..aa5d565 100644
--- a/pkg/dev_compiler/lib/src/analyzer/driver.dart
+++ b/pkg/dev_compiler/lib/src/analyzer/driver.dart
@@ -73,7 +73,9 @@
   ExtensionTypeSet get extensionTypes => _extensionTypes;
 
   factory CompilerAnalysisDriver(AnalyzerOptions options,
-      {SummaryDataStore summaryData, List<String> summaryPaths = const []}) {
+      {SummaryDataStore summaryData,
+      List<String> summaryPaths = const [],
+      Map<String, bool> experiments = const {}}) {
     AnalysisEngine.instance.processRequiredPlugins();
 
     var resourceProvider = options.resourceProvider;
@@ -81,6 +83,10 @@
 
     var analysisOptions =
         contextBuilder.getAnalysisOptions(options.analysisRoot);
+
+    (analysisOptions as AnalysisOptionsImpl).enabledExperiments =
+        experiments.entries.where((e) => e.value).map((e) => e.key).toList();
+
     var dartSdk = contextBuilder.findSdk(null, analysisOptions);
 
     // Read the summaries.
diff --git a/pkg/dev_compiler/lib/src/analyzer/module_compiler.dart b/pkg/dev_compiler/lib/src/analyzer/module_compiler.dart
index 868d50f..f62c54c 100644
--- a/pkg/dev_compiler/lib/src/analyzer/module_compiler.dart
+++ b/pkg/dev_compiler/lib/src/analyzer/module_compiler.dart
@@ -68,7 +68,6 @@
     }
     explicitSources.add(sourceUri);
   }
-
   var driver = compilerDriver.linkLibraries(explicitSources, analyzerOptions);
 
   for (var libraryUri in driver.libraryUris) {
diff --git a/pkg/dev_compiler/lib/src/compiler/shared_command.dart b/pkg/dev_compiler/lib/src/compiler/shared_command.dart
index 4458f59..39c4759 100644
--- a/pkg/dev_compiler/lib/src/compiler/shared_command.dart
+++ b/pkg/dev_compiler/lib/src/compiler/shared_command.dart
@@ -81,6 +81,11 @@
 
   final List<ModuleFormat> moduleFormats;
 
+  /// Experimental language features that are enabled/disabled, see
+  /// [the spec](https://github.com/dart-lang/sdk/blob/master/docs/process/experimental-flags.md)
+  /// for more details.
+  final Map<String, bool> experiments;
+
   /// The name of the module.
   ///
   /// This used when to support file concatenation. The JS module will contain
@@ -97,6 +102,7 @@
       this.bazelMapping = const {},
       this.summaryModules = const {},
       this.moduleFormats = const [],
+      this.experiments = const {},
       this.moduleName});
 
   SharedCompilerOptions.fromArguments(ArgResults args,
@@ -106,6 +112,8 @@
             summarizeApi: args['summarize'] as bool,
             emitMetadata: args['emit-metadata'] as bool,
             enableAsserts: args['enable-asserts'] as bool,
+            experiments:
+                _parseExperiments(args['enable-experiment'] as List<String>),
             bazelMapping:
                 _parseBazelMappings(args['bazel-mapping'] as List<String>),
             summaryModules: _parseCustomSummaryModules(
@@ -121,6 +129,9 @@
           abbr: 's',
           help: 'summary file(s) of imported libraries, optionally\n'
               'with module import path: -s path.sum=js/import/path')
+      ..addMultiOption('enable-experiment',
+          help: 'used to enable/disable experimental language features',
+          hide: hide)
       ..addFlag('summarize',
           help: 'emit an API summary file', defaultsTo: true, hide: hide)
       ..addFlag('source-map',
@@ -204,6 +215,20 @@
   return pathToModule;
 }
 
+Map<String, bool> _parseExperiments(List<String> arguments) {
+  var result = <String, bool>{};
+  for (var argument in arguments) {
+    for (var feature in argument.split(',')) {
+      if (feature.startsWith('no-')) {
+        result[feature.substring(3)] = false;
+      } else {
+        result[feature] = true;
+      }
+    }
+  }
+  return result;
+}
+
 Map<String, String> _parseBazelMappings(List<String> argument) {
   var mappings = <String, String>{};
   for (var mapping in argument) {
diff --git a/pkg/dev_compiler/lib/src/kernel/command.dart b/pkg/dev_compiler/lib/src/kernel/command.dart
index 60ce102..15dd91c 100644
--- a/pkg/dev_compiler/lib/src/kernel/command.dart
+++ b/pkg/dev_compiler/lib/src/kernel/command.dart
@@ -10,7 +10,7 @@
 import 'package:build_integration/file_system/multi_root.dart';
 import 'package:cli_util/cli_util.dart' show getSdkPath;
 import 'package:front_end/src/api_unstable/ddc.dart' as fe;
-import 'package:kernel/kernel.dart';
+import 'package:kernel/kernel.dart' hide MapEntry;
 import 'package:kernel/text/ast_to_text.dart' as kernel show Printer;
 import 'package:kernel/binary/ast_to_binary.dart' as kernel show BinaryPrinter;
 import 'package:path/path.dart' as path;
@@ -177,6 +177,16 @@
     fe.printDiagnosticMessage(message, print);
   }
 
+  var experiments = <fe.ExperimentalFlag, bool>{};
+  for (var name in options.experiments.keys) {
+    var flag = fe.parseExperimentalFlag(name);
+    if (flag != null) {
+      experiments[flag] = options.experiments[name];
+    } else {
+      stderr.writeln("Unknown experiment flag '$name'.");
+    }
+  }
+
   var oldCompilerState = compilerState;
   compilerState = await fe.initializeCompiler(
       oldCompilerState,
@@ -185,7 +195,8 @@
       sourcePathToUri(librarySpecPath),
       summaryModules.keys.toList(),
       DevCompilerTarget(),
-      fileSystem: fileSystem);
+      fileSystem: fileSystem,
+      experiments: experiments);
 
   var output = argResults['out'] as String;
   // TODO(jmesserly): is there a cleaner way to do this?
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index f034d66..3a2c138 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -183,6 +183,7 @@
   final Class privateSymbolClass;
   final Class linkedHashMapImplClass;
   final Class identityHashMapImplClass;
+  final Class linkedHashSetClass;
   final Class linkedHashSetImplClass;
   final Class identityHashSetImplClass;
   final Class syncIterableClass;
@@ -222,6 +223,7 @@
         linkedHashMapImplClass = sdk.getClass('dart:_js_helper', 'LinkedMap'),
         identityHashMapImplClass =
             sdk.getClass('dart:_js_helper', 'IdentityMap'),
+        linkedHashSetClass = sdk.getClass('dart:collection', 'LinkedHashSet'),
         linkedHashSetImplClass = sdk.getClass('dart:collection', '_HashSet'),
         identityHashSetImplClass =
             sdk.getClass('dart:collection', '_IdentityHashSet'),
@@ -4887,7 +4889,19 @@
 
   @override
   visitSetLiteral(SetLiteral node) {
-    throw UnsupportedError("SetLiteral");
+    if (!node.isConst) {
+      var setType = visitInterfaceType(
+          InterfaceType(linkedHashSetClass, [node.typeArgument]));
+      if (node.expressions.isEmpty) {
+        return js.call('#.new()', [setType]);
+      }
+      return js.call(
+          '#.from([#])', [setType, _visitExpressionList(node.expressions)]);
+    }
+    return _cacheConst(() => runtimeCall('constSet(#, [#])', [
+          _emitType(node.typeArgument),
+          _visitExpressionList(node.expressions)
+        ]));
   }
 
   JS.Expression _emitConstList(
diff --git a/pkg/dev_compiler/test/nullable_inference_test.dart b/pkg/dev_compiler/test/nullable_inference_test.dart
index d14a0ee..73981f7 100644
--- a/pkg/dev_compiler/test/nullable_inference_test.dart
+++ b/pkg/dev_compiler/test/nullable_inference_test.dart
@@ -572,9 +572,11 @@
 
   var mainUri = Uri.file('/memory/test.dart');
   _fileSystem.entityForUri(mainUri).writeAsStringSync(code);
+  var oldCompilerState = _compilerState;
   _compilerState = await fe.initializeCompiler(
-      _compilerState, sdkUri, packagesUri, null, [], DevCompilerTarget(),
-      fileSystem: _fileSystem);
+      oldCompilerState, sdkUri, packagesUri, null, [], DevCompilerTarget(),
+      fileSystem: _fileSystem, experiments: const {});
+  if (!identical(oldCompilerState, _compilerState)) inference = null;
   fe.DdcResult result =
       await fe.compile(_compilerState, [mainUri], diagnosticMessageHandler);
   expect(succeeded, true);
diff --git a/pkg/dev_compiler/tool/input_sdk/patch/collection_patch.dart b/pkg/dev_compiler/tool/input_sdk/patch/collection_patch.dart
index 5b8d733..ab94a36 100644
--- a/pkg/dev_compiler/tool/input_sdk/patch/collection_patch.dart
+++ b/pkg/dev_compiler/tool/input_sdk/patch/collection_patch.dart
@@ -5,6 +5,7 @@
 // Patch file for dart:collection classes.
 import 'dart:_foreign_helper' show JS, JSExportName;
 import 'dart:_runtime' as dart;
+import 'dart:_interceptors' show JSArray;
 import 'dart:_js_helper'
     show
         NoInline,
@@ -248,7 +249,7 @@
     int length = JS('', '#.size', map);
     for (E key in objects) {
       if (key == null) {
-        key = null;
+        key = null; // converts undefined to null, if needed.
       } else if (JS('bool', '#[#] !== #', key, dart.extensionSymbol('_equals'),
           dart.identityEquals)) {
         key = putLinkedMapKey(key, _keyMap);
@@ -302,6 +303,29 @@
   }
 }
 
+class ImmutableSet<E> extends _HashSet<E> {
+  ImmutableSet.from(JSArray entries) {
+    var map = _map;
+    for (Object key in entries) {
+      if (key == null) {
+        key = null; // converts undefined to null, if needed.
+      } else if (JS('bool', '#[#] !== #', key, dart.extensionSymbol('_equals'),
+          dart.identityEquals)) {
+        key = putLinkedMapKey(key, _keyMap);
+      }
+      JS('', '#.add(#)', map, key);
+    }
+  }
+
+  bool add(Object other) => throw _unsupported();
+  void addAll(Object other) => throw _unsupported();
+  void clear() => throw _unsupported();
+  bool remove(Object key) => throw _unsupported();
+
+  static Error _unsupported() =>
+      UnsupportedError("Cannot modify unmodifiable map");
+}
+
 class _IdentityHashSet<E> extends _InternalSet<E>
     implements HashSet<E>, LinkedHashSet<E> {
   /// The backing store for this set.
diff --git a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart
index 5aed9a6..b3865c1 100644
--- a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart
+++ b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart
@@ -502,19 +502,24 @@
 /// The global constant map table.
 final constantMaps = JS('', 'new Map()');
 
-constMap<K, V>(JSArray elements) {
-  Function(Object, Object) lookupNonTerminal = JS('', '''function(map, key) {
-    let result = map.get(key);
-    if (result != null) return result;
-    map.set(key, result = new Map());
-    return result;
-  }''');
+// TODO(leafp): This table gets quite large in apps.
+// Keeping the paths is probably expensive.  It would probably
+// be more space efficient to just use a direct hash table with
+// an appropriately defined structural equality function.
+Object _lookupNonTerminal(Object map, Object key) {
+  var result = JS('', '#.get(#)', map, key);
+  if (result != null) return result;
+  JS('', '#.set(#, # = new Map())', map, key, result);
+  return result;
+}
+
+Map<K, V> constMap<K, V>(JSArray elements) {
   var count = elements.length;
-  var map = lookupNonTerminal(constantMaps, count);
+  var map = _lookupNonTerminal(constantMaps, count);
   for (var i = 0; i < count; i++) {
-    map = lookupNonTerminal(map, JS('', '#[#]', elements, i));
+    map = _lookupNonTerminal(map, JS('', '#[#]', elements, i));
   }
-  map = lookupNonTerminal(map, K);
+  map = _lookupNonTerminal(map, K);
   var result = JS('', '#.get(#)', map, V);
   if (result != null) return result;
   result = ImmutableMap<K, V>.from(elements);
@@ -522,6 +527,21 @@
   return result;
 }
 
+final constantSets = JS('', 'new Map()');
+
+Set<E> constSet<E>(JSArray<E> elements) {
+  var count = elements.length;
+  var map = _lookupNonTerminal(constantSets, count);
+  for (var i = 0; i < count; i++) {
+    map = _lookupNonTerminal(map, JS('', '#[#]', elements, i));
+  }
+  var result = JS('', '#.get(#)', map, E);
+  if (result != null) return result;
+  result = ImmutableSet<E>.from(elements);
+  JS('', '#.set(#, #)', map, E, result);
+  return result;
+}
+
 bool dassert(value) {
   if (JS('!', '# != null && #[#] instanceof #', value, value, _runtimeType,
       AbstractFunctionType)) {
@@ -576,22 +596,12 @@
 /// - nested values of the object are themselves already canonicalized.
 ///
 @JSExportName('const')
-const_(obj) => JS('', '''(() => {
-  // TODO(leafp): This table gets quite large in apps.
-  // Keeping the paths is probably expensive.  It would probably
-  // be more space efficient to just use a direct hash table with
-  // an appropriately defined structural equality function.
-  function lookupNonTerminal(map, key) {
-    let result = map.get(key);
-    if (result !== void 0) return result;
-    map.set(key, result = new Map());
-    return result;
-  };
+const_(obj) => JS('', '''(() => {  
   let names = $getOwnNamesAndSymbols($obj);
   let count = names.length;
   // Index by count.  All of the paths through this map
   // will have 2*count length.
-  let map = lookupNonTerminal($constants, count);
+  let map = $_lookupNonTerminal($constants, count);
   // TODO(jmesserly): there's no guarantee in JS that names/symbols are
   // returned in the same order.
   //
@@ -606,8 +616,8 @@
   // See issue https://github.com/dart-lang/sdk/issues/30876
   for (let i = 0; i < count; i++) {
     let name = names[i];
-    map = lookupNonTerminal(map, name);
-    map = lookupNonTerminal(map, $obj[name]);
+    map = $_lookupNonTerminal(map, name);
+    map = $_lookupNonTerminal(map, $obj[name]);
   }
   // TODO(leafp): It may be the case that the reified type
   // is always one of the keys already used above?
@@ -627,16 +637,10 @@
 
 /// Canonicalize a constant list
 constList(elements, elementType) => JS('', '''(() => {
-  function lookupNonTerminal(map, key) {
-    let result = map.get(key);
-    if (result !== void 0) return result;
-    map.set(key, result = new Map());
-    return result;
-  };
   let count = $elements.length;
-  let map = lookupNonTerminal($constantLists, count);
+  let map = $_lookupNonTerminal($constantLists, count);
   for (let i = 0; i < count; i++) {
-    map = lookupNonTerminal(map, elements[i]);
+    map = $_lookupNonTerminal(map, elements[i]);
   }
   let value = map.get($elementType);
   if (value) return value;
diff --git a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/types.dart b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/types.dart
index 4602bc2..13d6f88 100644
--- a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/types.dart
+++ b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/types.dart
@@ -306,13 +306,6 @@
   return $_memoizeArray($map, key, () => $named);
 })()''');
 
-_lookupNonTerminal(map, key) => JS('', '''(() => {
-  let result = $map.get($key);
-  if (result !== void 0) return result;
-  $map.set($key, result = new Map());
-  return result;
-})()''');
-
 // TODO(leafp): This handles some low hanging fruit, but
 // really we should make all of this faster, and also
 // handle more cases here.
diff --git a/pkg/front_end/lib/src/api_unstable/ddc.dart b/pkg/front_end/lib/src/api_unstable/ddc.dart
index 1a85b55..0a129d8 100644
--- a/pkg/front_end/lib/src/api_unstable/ddc.dart
+++ b/pkg/front_end/lib/src/api_unstable/ddc.dart
@@ -12,6 +12,8 @@
 
 import '../api_prototype/diagnostic_message.dart' show DiagnosticMessageHandler;
 
+import '../api_prototype/experimental_flags.dart' show ExperimentalFlag;
+
 import '../api_prototype/file_system.dart' show FileSystem;
 
 import '../api_prototype/standard_file_system.dart' show StandardFileSystem;
@@ -26,6 +28,9 @@
 
 export '../api_prototype/diagnostic_message.dart' show DiagnosticMessage;
 
+export '../api_prototype/experimental_flags.dart'
+    show ExperimentalFlag, parseExperimentalFlag;
+
 export '../api_prototype/kernel_generator.dart' show kernelForComponent;
 
 export '../api_prototype/memory_file_system.dart' show MemoryFileSystem;
@@ -59,7 +64,8 @@
     Uri librariesSpecificationUri,
     List<Uri> inputSummaries,
     Target target,
-    {FileSystem fileSystem}) async {
+    {FileSystem fileSystem,
+    Map<ExperimentalFlag, bool> experiments}) async {
   inputSummaries.sort((a, b) => a.toString().compareTo(b.toString()));
   bool listEqual(List<Uri> a, List<Uri> b) {
     if (a.length != b.length) return false;
@@ -69,11 +75,21 @@
     return true;
   }
 
+  bool mapEqual(Map<ExperimentalFlag, bool> a, Map<ExperimentalFlag, bool> b) {
+    if (a == null || b == null) return a == b;
+    if (a.length != b.length) return false;
+    for (var flag in a.keys) {
+      if (!b.containsKey(flag) || a[flag] != b[flag]) return false;
+    }
+    return true;
+  }
+
   if (oldState != null &&
       oldState.options.sdkSummary == sdkSummary &&
       oldState.options.packagesFileUri == packagesFile &&
       oldState.options.librariesSpecificationUri == librariesSpecificationUri &&
-      listEqual(oldState.options.inputSummaries, inputSummaries)) {
+      listEqual(oldState.options.inputSummaries, inputSummaries) &&
+      mapEqual(oldState.options.experimentalFlags, experiments)) {
     // Reuse old state.
 
     // These libraries are marked external when compiling. If not un-marking
@@ -96,6 +112,7 @@
     ..librariesSpecificationUri = librariesSpecificationUri
     ..target = target
     ..fileSystem = fileSystem ?? StandardFileSystem.instance;
+  if (experiments != null) options.experimentalFlags = experiments;
 
   ProcessedOptions processedOpts = new ProcessedOptions(options: options);
 
diff --git a/tests/language_2/language_2_dartdevc.status b/tests/language_2/language_2_dartdevc.status
index 1228430..310f9a1 100644
--- a/tests/language_2/language_2_dartdevc.status
+++ b/tests/language_2/language_2_dartdevc.status
@@ -122,7 +122,6 @@
 regress_29784_test/02: MissingCompileTimeError
 regress_30339_test: CompileTimeError # As expected. Should we make this a multi test?
 regress_33479_test/01: Crash # Issue #33479
-set_literals/*: Skip
 setter3_test/01: CompileTimeError # Invalid test, see https://github.com/dart-lang/sdk/issues/33837
 setter3_test/02: CompileTimeError # Invalid test, see https://github.com/dart-lang/sdk/issues/33837
 stacktrace_test: RuntimeError # Issue 29920
@@ -275,7 +274,6 @@
 regress_29405_test: CompileTimeError # Issue 31402 Error: A value of type '#lib2::Foo' can't be assigned to a variable of type '(#lib2::Foo) → void'.
 regress_30339_test: RuntimeError # Uncaught Expect.isTrue(false) fails.
 regress_30339_test: CompileTimeError
-set_literals/*: Skip
 setter_no_getter_test/01: CompileTimeError
 super_bound_closure_test/none: CompileTimeError # Issue 31533
 super_call4_test/01: MissingCompileTimeError
diff --git a/tests/language_2/set_literals/set_literal_test.dart b/tests/language_2/set_literals/set_literal_test.dart
index 6ea5fee..cc17fae 100644
--- a/tests/language_2/set_literals/set_literal_test.dart
+++ b/tests/language_2/set_literals/set_literal_test.dart
@@ -87,27 +87,29 @@
 
   // Nested literals.
   Object o = {{2}};
-  Expect.type<LinkedHashSet<LinkedHashSet<int>>>(o);
+  Expect.type<LinkedHashSet<Set<int>>>(o);
+  Expect.type<LinkedHashSet<int>>((o as Set).first);
   Set<Set<int>> set = o;
   Expect.equals(1, set.length);
   Expect.equals(1, set.first.length);
   Expect.equals(2, set.first.first);
 
   o = {{2}, <int>{}};
-  Expect.type<LinkedHashSet<LinkedHashSet<int>>>(o);
+  Expect.type<LinkedHashSet<Set<int>>>(o);
+  Expect.type<LinkedHashSet<int>>((o as Set).first);
   set = o;
   Expect.equals(2, set.length);
   Expect.equals(1, set.first.length);
   Expect.equals(2, set.first.first);
 
-  set = {{}};
-  Expect.type<Set<Map<dynamic, dynamic>>>(set);
-  Expect.equals(1, set.length);
-  Expect.equals(0, set.first.length);
+  var set2 = {{}};
+  Expect.type<Set<Map<dynamic, dynamic>>>(set2);
+  Expect.equals(1, set2.length);
+  Expect.equals(0, set2.first.length);
 
-  set = {{1}, {}};  // Set<Object>
-  Expect.type<Set<Object>>(set);
-  Expect.notType<Set<Set<Object>>>(set);
+  var set3 = {{1}, {}};  // Set<Object>
+  Expect.type<Set<Object>>(set3);
+  Expect.notType<Set<Set<Object>>>(set3);
 
   // Trailing comma.
   Iterable<Object> i;
@@ -117,8 +119,8 @@
 
   o = {1, 2, 3,};
   Expect.type<Set<int>>(o);
-  set = o;
-  Expect.equals(3, set.length);
+  Set<Object> set4 = o;
+  Expect.equals(3, set4.length);
 }
 
 class Equality {