Add --strong-mode flag to dart2js

+ move generic methods tests into a subfolder.

Change-Id: I00cde6a7dc7d6ff1677a8ca60f3a243f065e3765
Reviewed-on: https://dart-review.googlesource.com/31782
Reviewed-by: Sigmund Cherem <sigmund@google.com>
diff --git a/pkg/compiler/lib/src/commandline_options.dart b/pkg/compiler/lib/src/commandline_options.dart
index c9319e4..7cbc7e7 100644
--- a/pkg/compiler/lib/src/commandline_options.dart
+++ b/pkg/compiler/lib/src/commandline_options.dart
@@ -37,6 +37,7 @@
   /// using the kernel representation.
   /// See [CompilerOptions.useKernel] for details.
   static const String useKernel = '--use-kernel';
+  static const String strongMode = '--strong';
   static const String platformBinaries = '--platform-binaries=.+';
 
   static const String minify = '--minify';
diff --git a/pkg/compiler/lib/src/dart2js.dart b/pkg/compiler/lib/src/dart2js.dart
index 2fa6522..b016904 100644
--- a/pkg/compiler/lib/src/dart2js.dart
+++ b/pkg/compiler/lib/src/dart2js.dart
@@ -399,6 +399,7 @@
     new OptionHandler(Flags.useContentSecurityPolicy, passThrough),
     new OptionHandler(Flags.enableExperimentalMirrors, passThrough),
     new OptionHandler(Flags.enableAssertMessage, passThrough),
+    new OptionHandler(Flags.strongMode, passThrough),
 
     // TODO(floitsch): remove conditional directives flag.
     // We don't provide the info-message yet, since we haven't publicly
diff --git a/pkg/compiler/lib/src/kernel/element_map_impl.dart b/pkg/compiler/lib/src/kernel/element_map_impl.dart
index 55e8285..92e71cd 100644
--- a/pkg/compiler/lib/src/kernel/element_map_impl.dart
+++ b/pkg/compiler/lib/src/kernel/element_map_impl.dart
@@ -71,6 +71,7 @@
 }
 
 abstract class KernelToElementMapBase extends KernelToElementMapBaseMixin {
+  final CompilerOptions options;
   final DiagnosticReporter reporter;
   CommonElements _commonElements;
   ElementEnvironment _elementEnvironment;
@@ -92,7 +93,7 @@
   final EntityDataMap<IndexedTypedef, TypedefData> _typedefs =
       new EntityDataMap<IndexedTypedef, TypedefData>();
 
-  KernelToElementMapBase(this.reporter, Environment environment) {
+  KernelToElementMapBase(this.options, this.reporter, Environment environment) {
     _elementEnvironment = new KernelElementEnvironment(this);
     _commonElements = new CommonElements(_elementEnvironment);
     _constantEnvironment = new KernelConstantEnvironment(this, environment);
@@ -438,8 +439,7 @@
       namedParameterTypes.add(getDartType(variable.type));
     }
     List<FunctionTypeVariable> typeVariables;
-    if (node.typeParameters.isNotEmpty &&
-        DartTypeConverter.enableFunctionTypeVariables) {
+    if (node.typeParameters.isNotEmpty && options.strongMode) {
       List<DartType> typeParameters = <DartType>[];
       for (ir.TypeParameter typeParameter in node.typeParameters) {
         typeParameters
@@ -793,7 +793,7 @@
 }
 
 /// Mixin that implements the abstract methods in [KernelToElementMapBase].
-abstract class ElementCreatorMixin {
+abstract class ElementCreatorMixin implements KernelToElementMapBase {
   ProgramEnv get _env;
   EntityDataEnvMap<IndexedLibrary, LibraryData, LibraryEnv> get _libraries;
   EntityDataEnvMap<IndexedClass, ClassData, ClassEnv> get _classes;
@@ -1015,11 +1015,8 @@
     int typeParameters = node.typeParameters.length;
     List<String> namedParameters =
         node.namedParameters.map((p) => p.name).toList()..sort();
-    return new ParameterStructure(
-        requiredParameters,
-        positionalParameters,
-        namedParameters,
-        DartTypeConverter.enableFunctionTypeVariables ? typeParameters : 0);
+    return new ParameterStructure(requiredParameters, positionalParameters,
+        namedParameters, options.strongMode ? typeParameters : 0);
   }
 
   IndexedLibrary createLibrary(String name, Uri canonicalUri);
@@ -1145,11 +1142,10 @@
         KElementCreatorMixin {
   native.BehaviorBuilder _nativeBehaviorBuilder;
   FrontendStrategy _frontendStrategy;
-  CompilerOptions _options;
 
   KernelToElementMapForImpactImpl(DiagnosticReporter reporter,
-      Environment environment, this._frontendStrategy, this._options)
-      : super(reporter, environment);
+      Environment environment, this._frontendStrategy, CompilerOptions options)
+      : super(options, reporter, environment);
 
   @override
   bool checkFamily(Entity entity) {
@@ -1181,7 +1177,7 @@
   @override
   native.BehaviorBuilder get nativeBehaviorBuilder =>
       _nativeBehaviorBuilder ??= new KernelBehaviorBuilder(elementEnvironment,
-          commonElements, nativeBasicData, reporter, _options);
+          commonElements, nativeBasicData, reporter, options);
 
   ResolutionImpact computeWorldImpact(KMember member) {
     return buildKernelImpact(
@@ -1190,7 +1186,7 @@
 
   ScopeModel computeScopeModel(KMember member) {
     ir.Member node = _members.getData(member).definition.node;
-    return KernelClosureAnalysis.computeScopeModel(member, node, _options);
+    return KernelClosureAnalysis.computeScopeModel(member, node, options);
   }
 
   /// Returns the kernel [ir.Procedure] node for the [method].
@@ -1548,8 +1544,6 @@
 
 /// Visitor that converts kernel dart types into [DartType].
 class DartTypeConverter extends ir.DartTypeVisitor<DartType> {
-  static bool enableFunctionTypeVariables = false;
-
   final KernelToElementMapBase elementMap;
   final Map<ir.TypeParameter, DartType> currentFunctionTypeParameters =
       <ir.TypeParameter, DartType>{};
@@ -1602,7 +1596,7 @@
     int index = 0;
     List<FunctionTypeVariable> typeVariables;
     for (ir.TypeParameter typeParameter in node.typeParameters) {
-      if (enableFunctionTypeVariables) {
+      if (elementMap.options.strongMode) {
         // TODO(johnniwinther): Support recursive type variable bounds, like
         // `void Function<T extends Foo<T>>(T t)` when #31531 is fixed.
         DartType bound = typeParameter.bound.accept(this);
@@ -2068,7 +2062,7 @@
 
   JsKernelToElementMap(DiagnosticReporter reporter, Environment environment,
       KernelToElementMapForImpactImpl _elementMap)
-      : super(reporter, environment) {
+      : super(_elementMap.options, reporter, environment) {
     _env = _elementMap._env;
     for (int libraryIndex = 0;
         libraryIndex < _elementMap._libraries.length;
diff --git a/pkg/compiler/lib/src/kernel/element_map_mixins.dart b/pkg/compiler/lib/src/kernel/element_map_mixins.dart
index aa25d5e..9117831 100644
--- a/pkg/compiler/lib/src/kernel/element_map_mixins.dart
+++ b/pkg/compiler/lib/src/kernel/element_map_mixins.dart
@@ -20,13 +20,14 @@
 import '../js_backend/namer.dart';
 import '../js_emitter/code_emitter_task.dart';
 import '../native/native.dart' as native;
+import '../options.dart';
 import '../universe/call_structure.dart';
 import '../universe/selector.dart';
 import 'element_map.dart';
-import 'element_map_impl.dart';
 import 'kernel_debug.dart';
 
 abstract class KernelToElementMapBaseMixin implements KernelToElementMap {
+  CompilerOptions get options;
   DiagnosticReporter get reporter;
   ElementEnvironment get elementEnvironment;
   LibraryEntity getLibrary(ir.Library node);
@@ -44,12 +45,8 @@
   CallStructure getCallStructure(ir.Arguments arguments) {
     int argumentCount = arguments.positional.length + arguments.named.length;
     List<String> namedArguments = arguments.named.map((e) => e.name).toList();
-    return new CallStructure(
-        argumentCount,
-        namedArguments,
-        DartTypeConverter.enableFunctionTypeVariables
-            ? arguments.types.length
-            : 0);
+    return new CallStructure(argumentCount, namedArguments,
+        options.strongMode ? arguments.types.length : 0);
   }
 
   @override
diff --git a/pkg/compiler/lib/src/library_loader.dart b/pkg/compiler/lib/src/library_loader.dart
index b4d108f..b0e0610 100644
--- a/pkg/compiler/lib/src/library_loader.dart
+++ b/pkg/compiler/lib/src/library_loader.dart
@@ -863,7 +863,8 @@
       } else {
         initializedCompilerState = fe.initializeCompiler(
             initializedCompilerState,
-            new Dart2jsTarget(new TargetFlags()),
+            new Dart2jsTarget(
+                new TargetFlags(strongMode: _elementMap.options.strongMode)),
             platformBinaries.resolve("dart2js_platform.dill"),
             _packageConfig);
         program = await fe.compile(
diff --git a/pkg/compiler/lib/src/options.dart b/pkg/compiler/lib/src/options.dart
index 466e63a..73650f6 100644
--- a/pkg/compiler/lib/src/options.dart
+++ b/pkg/compiler/lib/src/options.dart
@@ -213,11 +213,16 @@
   /// sources to kernel, and then continue compilation from the kernel
   /// representation.
   ///
-  /// When this flag is on, the compiler also acccepts reading .dill files from
+  /// When this flag is on, the compiler also accepts reading .dill files from
   /// disk. The compiler reads the sources differently depending on the
   /// extension format.
   final bool useKernel;
 
+  /// Enables strong mode in dart2js.
+  ///
+  /// This is work-in-progress and will only be supported for [useKernel].
+  final bool strongMode;
+
   /// When obfuscating for minification, whether to use the frequency of a name
   /// as an heuristic to pick shorter names.
   final bool useFrequencyNamer;
@@ -325,6 +330,7 @@
         resolveOnly: _hasOption(options, Flags.resolveOnly),
         sourceMapUri: _extractUriOption(options, '--source-map='),
         strips: _extractCsvOption(options, '--force-strip='),
+        strongMode: _hasOption(options, Flags.strongMode),
         testMode: _hasOption(options, Flags.testMode),
         trustJSInteropTypeAnnotations:
             _hasOption(options, Flags.trustJSInteropTypeAnnotations),
@@ -390,6 +396,7 @@
       bool resolveOnly: false,
       Uri sourceMapUri: null,
       List<String> strips: const [],
+      bool strongMode: false,
       bool testMode: false,
       bool trustJSInteropTypeAnnotations: false,
       bool trustPrimitives: false,
@@ -470,6 +477,7 @@
         resolveOnly: resolveOnly,
         sourceMapUri: sourceMapUri,
         strips: strips,
+        strongMode: strongMode,
         testMode: testMode,
         trustJSInteropTypeAnnotations: trustJSInteropTypeAnnotations,
         trustPrimitives: trustPrimitives,
@@ -522,6 +530,7 @@
       this.compileOnly: false,
       this.sourceMapUri: null,
       this.strips: const [],
+      this.strongMode: false,
       this.testMode: false,
       this.trustJSInteropTypeAnnotations: false,
       this.trustPrimitives: false,
@@ -582,6 +591,7 @@
       compileOnly,
       sourceMapUri,
       strips,
+      strongMode,
       testMode,
       trustJSInteropTypeAnnotations,
       trustPrimitives,
@@ -649,6 +659,7 @@
         compileOnly: compileOnly ?? options.compileOnly,
         sourceMapUri: sourceMapUri ?? options.sourceMapUri,
         strips: strips ?? options.strips,
+        strongMode: strongMode ?? options.strongMode,
         testMode: testMode ?? options.testMode,
         trustJSInteropTypeAnnotations: trustJSInteropTypeAnnotations ??
             options.trustJSInteropTypeAnnotations,
diff --git a/pkg/front_end/lib/src/api_unstable/dart2js.dart b/pkg/front_end/lib/src/api_unstable/dart2js.dart
index fc92b87..a7adc1f 100644
--- a/pkg/front_end/lib/src/api_unstable/dart2js.dart
+++ b/pkg/front_end/lib/src/api_unstable/dart2js.dart
@@ -30,7 +30,7 @@
 
   CompilerOptions options = new CompilerOptions()
     ..target = target
-    ..strongMode = false
+    ..strongMode = target.strongMode
     ..linkedDependencies = [sdkUri]
     ..packagesFileUri = packagesFileUri;
 
diff --git a/tests/compiler/dart2js/function_type_variable_test.dart b/tests/compiler/dart2js/generic_methods/function_type_variable_test.dart
similarity index 96%
rename from tests/compiler/dart2js/function_type_variable_test.dart
rename to tests/compiler/dart2js/generic_methods/function_type_variable_test.dart
index ba64289..c302094 100644
--- a/tests/compiler/dart2js/function_type_variable_test.dart
+++ b/tests/compiler/dart2js/generic_methods/function_type_variable_test.dart
@@ -3,10 +3,10 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:async_helper/async_helper.dart';
+import 'package:compiler/src/commandline_options.dart';
 import 'package:compiler/src/elements/types.dart';
-import 'package:compiler/src/kernel/element_map_impl.dart';
 import 'package:expect/expect.dart';
-import 'type_test_helper.dart';
+import '../type_test_helper.dart';
 
 const List<FunctionTypeData> existentialTypeData = const <FunctionTypeData>[
   // TODO(johnniwinther): Test generic bounds when #31531 is fixed.
@@ -21,13 +21,12 @@
 ];
 
 main() {
-  DartTypeConverter.enableFunctionTypeVariables = true;
   asyncTest(() async {
     var env = await TypeEnvironment
         .create(createTypedefs(existentialTypeData, additionalData: """
     class C1 {}
     class C2 {}
-  """), compileMode: CompileMode.kernel);
+  """), compileMode: CompileMode.kernel, options: [Flags.strongMode]);
 
     testToString(FunctionType type, String expectedToString) {
       Expect.equals(expectedToString, type.toString());
diff --git a/tests/compiler/dart2js/generic_method_test.dart b/tests/compiler/dart2js/generic_methods/generic_method_type_test.dart
similarity index 89%
rename from tests/compiler/dart2js/generic_method_test.dart
rename to tests/compiler/dart2js/generic_methods/generic_method_type_test.dart
index 8f01ba3..0357757 100644
--- a/tests/compiler/dart2js/generic_method_test.dart
+++ b/tests/compiler/dart2js/generic_methods/generic_method_type_test.dart
@@ -3,12 +3,12 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:async_helper/async_helper.dart';
+import 'package:compiler/src/commandline_options.dart';
 import 'package:compiler/src/elements/entities.dart';
 import 'package:compiler/src/elements/types.dart';
-import 'package:compiler/src/kernel/element_map_impl.dart';
 import 'package:compiler/src/universe/call_structure.dart';
 import 'package:expect/expect.dart';
-import 'type_test_helper.dart';
+import '../type_test_helper.dart';
 
 List<FunctionTypeData> signatures = const <FunctionTypeData>[
   const FunctionTypeData("void", "0", "()"),
@@ -21,13 +21,14 @@
 ];
 
 main() {
-  DartTypeConverter.enableFunctionTypeVariables = true;
-
   asyncTest(() async {
-    TypeEnvironment env = await TypeEnvironment.create("""
+    TypeEnvironment env = await TypeEnvironment.create(
+        """
       ${createTypedefs(signatures, prefix: 't')}
       ${createMethods(signatures, prefix: 'm')}
-    """, compileMode: CompileMode.kernel);
+    """,
+        compileMode: CompileMode.kernel,
+        options: [Flags.strongMode]);
 
     for (FunctionTypeData data in signatures) {
       FunctionType functionType = env.getElementType('t${data.name}');
diff --git a/tests/compiler/dart2js/type_test_helper.dart b/tests/compiler/dart2js/type_test_helper.dart
index 29234ed..7a064ab 100644
--- a/tests/compiler/dart2js/type_test_helper.dart
+++ b/tests/compiler/dart2js/type_test_helper.dart
@@ -49,6 +49,7 @@
       bool stopAfterTypeInference: false,
       String mainSource,
       bool testBackendWorld: false,
+      List<String> options: const <String>[],
       Map<String, String> fieldTypeMap: const <String, String>{}}) async {
     Uri uri;
     Compiler compiler;
@@ -75,12 +76,12 @@
           memorySourceFiles: {'main.dart': source},
           diagnosticHandler: collector,
           options: stopAfterTypeInference
-              ? [Flags.disableTypeInference]
-              : [
+              ? ([Flags.disableTypeInference]..addAll(options))
+              : ([
                   Flags.disableTypeInference,
                   Flags.analyzeAll,
                   Flags.analyzeOnly
-                ],
+                ]..addAll(options)),
           beforeRun: (Compiler compiler) {
             compiler.stopAfterTypeInference = stopAfterTypeInference;
           });
@@ -104,8 +105,8 @@
             memorySourceFiles: {'main.dart': source},
             diagnosticHandler: collector,
             options: stopAfterTypeInference
-                ? []
-                : [Flags.analyzeAll, Flags.analyzeOnly],
+                ? options
+                : ([Flags.analyzeAll, Flags.analyzeOnly]..addAll(options)),
             beforeRun: (compiler) {
               compiler.stopAfterTypeInference = stopAfterTypeInference;
             });