fix #33103, switch dartdevk to use Kernel nSM stubs
Change-Id: I383b36809b1e8b43f9f7a36ca84d8db5da7cef67
Reviewed-on: https://dart-review.googlesource.com/55266
Commit-Queue: Jenny Messerly <jmesserly@google.com>
Reviewed-by: Vijay Menon <vsm@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 4888f4b..c53371c 100644
--- a/pkg/dev_compiler/lib/src/analyzer/code_generator.dart
+++ b/pkg/dev_compiler/lib/src/analyzer/code_generator.dart
@@ -77,7 +77,7 @@
ClosureAnnotator,
JSTypeRefCodegen,
NullableTypeInference,
- SharedCompiler
+ SharedCompiler<LibraryElement>
implements AstVisitor<JS.Node> {
final AnalysisContext context;
final SummaryDataStore summaryData;
@@ -100,9 +100,6 @@
/// in the SDK to be generated before anything else.
final _internalSdkFunctions = <JS.ModuleItem>[];
- /// The list of output module items, in the order they need to be emitted in.
- final _moduleItems = <JS.ModuleItem>[];
-
/// Table of named and possibly hoisted types.
TypeTable _typeTable;
@@ -121,9 +118,6 @@
/// In an async* function, this represents the stream controller parameter.
JS.TemporaryId _asyncStarController;
- // TODO(jmesserly): fuse this with notNull check.
- final _privateNames =
- new HashMap<LibraryElement, HashMap<String, JS.TemporaryId>>();
final _initializingFormalTemps =
new HashMap<ParameterElement, JS.TemporaryId>();
@@ -320,7 +314,7 @@
}
JS.Program _emitModule(List<CompilationUnit> compilationUnits, String name) {
- if (_moduleItems.isNotEmpty) {
+ if (moduleItems.isNotEmpty) {
throw new StateError('Can only call emitModule once.');
}
@@ -424,7 +418,7 @@
items.addAll(_internalSdkFunctions);
// Add the module's code (produced by visiting compilation units, above)
- _copyAndFlattenBlocks(items, _moduleItems);
+ _copyAndFlattenBlocks(items, moduleItems);
// Build the module.
return new JS.Program(items, name: _buildUnit.name);
@@ -442,7 +436,7 @@
// Track the module name for each library in the module.
// This data is only required for debugging.
- _moduleItems.add(js
+ moduleItems.add(js
.statement('#.trackLibraries(#, #, ${JSModuleFile.sourceMapHoleID});', [
runtimeModule,
js.string(name),
@@ -604,7 +598,7 @@
// only run this on the outermost function, and not any closures.
inferNullableTypes(node);
- _moduleItems.add(node.accept(this) as JS.ModuleItem);
+ moduleItems.add(node.accept(this) as JS.ModuleItem);
_currentElement = savedElement;
}
@@ -667,7 +661,7 @@
if (isInternalSdk && element is FunctionElement) {
_internalSdkFunctions.add(item);
} else {
- _moduleItems.add(item);
+ moduleItems.add(item);
}
}
@@ -728,7 +722,7 @@
if (currentNames.containsKey(export.name)) return null;
var name = _emitTopLevelName(export);
- _moduleItems.add(js.statement(
+ moduleItems.add(js.statement(
'#.# = #;', [emitLibraryName(currentLibrary), name.selector, name]));
}
}
@@ -1187,7 +1181,7 @@
// TODO(jmesserly): we could export these symbols, if we want to mark
// implemented interfaces for user-defined classes.
var id = new JS.TemporaryId("_is_${classElem.name}_default");
- _moduleItems.add(
+ moduleItems.add(
js.statement('const # = Symbol(#);', [id, js.string(id.name, "'")]));
isClassSymbol = id;
}
@@ -4284,7 +4278,7 @@
/// Emits a list of top-level field.
void _emitTopLevelFields(List<VariableDeclaration> fields) {
- _moduleItems.add(_emitLazyFields(
+ moduleItems.add(_emitLazyFields(
emitLibraryName(currentLibrary), fields, _emitTopLevelMemberName));
}
@@ -4304,7 +4298,7 @@
_isJSInvocation(init) ||
init is InstanceCreationExpression &&
isSdkInternalRuntime(init.staticElement.library)) {
- _moduleItems.add(closureAnnotate(
+ moduleItems.add(closureAnnotate(
js.statement('# = #;', [
_emitTopLevelName(field.element),
_visitInitializer(field.initializer, field.element)
@@ -4986,7 +4980,7 @@
if (_currentFunction == null || usesTypeParams) return jsExpr;
var temp = new JS.TemporaryId('const');
- _moduleItems.add(js.statement('let #;', [temp]));
+ moduleItems.add(js.statement('let #;', [temp]));
return js.call('# || (# = #)', [temp, temp, jsExpr]);
}
@@ -5726,7 +5720,7 @@
var last = name.substring(name.lastIndexOf('.') + 1);
var jsName = js.string(name, "'");
if (last.startsWith('_')) {
- var nativeSymbol = _emitPrivateNameSymbol(currentLibrary, last);
+ var nativeSymbol = emitPrivateNameSymbol(currentLibrary, last);
return js.call('new #.new(#, #)', [
_emitConstructorAccess(privateSymbolClass.type),
jsName,
@@ -6083,7 +6077,7 @@
}
if (name.startsWith('_')) {
- return _emitPrivateNameSymbol(currentLibrary, name);
+ return emitPrivateNameSymbol(currentLibrary, name);
}
useExtension ??= _isSymbolizedMember(type, name);
@@ -6205,17 +6199,6 @@
return false;
}
- JS.TemporaryId _emitPrivateNameSymbol(LibraryElement library, String name) {
- return _privateNames
- .putIfAbsent(library, () => new HashMap())
- .putIfAbsent(name, () {
- var id = new JS.TemporaryId(name);
- _moduleItems.add(
- js.statement('const # = Symbol(#);', [id, js.string(id.name, "'")]));
- return id;
- });
- }
-
/// Returns the canonical name to refer to the Dart library.
JS.Identifier emitLibraryName(LibraryElement library) {
// It's either one of the libraries in this module, or it's an import.
diff --git a/pkg/dev_compiler/lib/src/compiler/shared_compiler.dart b/pkg/dev_compiler/lib/src/compiler/shared_compiler.dart
index 10e9782..d2fa9c5 100644
--- a/pkg/dev_compiler/lib/src/compiler/shared_compiler.dart
+++ b/pkg/dev_compiler/lib/src/compiler/shared_compiler.dart
@@ -2,6 +2,7 @@
// 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 'dart:collection';
import '../compiler/js_metalet.dart' as JS;
import '../compiler/js_names.dart' as JS;
import '../compiler/js_utils.dart' as JS;
@@ -12,7 +13,7 @@
///
/// This class should only implement functionality that depends purely on JS
/// classes, rather than on Analyzer/Kernel types.
-abstract class SharedCompiler {
+abstract class SharedCompiler<Library> {
/// When inside a `[]=` operator, this will be a non-null value that should be
/// returned by any `return;` statement.
///
@@ -22,6 +23,11 @@
JS.Identifier runtimeModule;
final namedArgumentTemp = new JS.TemporaryId('opts');
+ final _privateNames = new HashMap<Library, HashMap<String, JS.TemporaryId>>();
+
+ /// The list of output module items, in the order they need to be emitted in.
+ final moduleItems = <JS.ModuleItem>[];
+
/// When compiling the body of a `operator []=` method, this will be non-null
/// and will indicate the the value that should be returned from any `return;`
/// statements.
@@ -122,4 +128,19 @@
JS.Statement runtimeStatement(String code, [args]) {
return runtimeCall(code, args).toStatement();
}
+
+ JS.TemporaryId emitPrivateNameSymbol(Library library, String name) {
+ return _privateNames
+ .putIfAbsent(library, () => new HashMap())
+ .putIfAbsent(name, () {
+ var idName = name;
+ if (idName.endsWith('=')) {
+ idName = idName.replaceAll('=', '_');
+ }
+ var id = new JS.TemporaryId(idName);
+ moduleItems.add(
+ js.statement('const # = Symbol(#);', [id, js.string(name, "'")]));
+ return id;
+ });
+ }
}
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index 141ffcf..0a66690 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -31,15 +31,12 @@
import 'type_table.dart';
class ProgramCompiler extends Object
- with SharedCompiler
+ with SharedCompiler<Library>
implements
StatementVisitor<JS.Statement>,
ExpressionVisitor<JS.Expression>,
DartTypeVisitor<JS.Expression>,
ConstantVisitor<JS.Expression> {
- /// The list of output module items, in the order they need to be emitted in.
- final _moduleItems = <JS.ModuleItem>[];
-
/// The set of libraries we are currently compiling, and the temporaries used
/// to refer to them.
///
@@ -63,9 +60,6 @@
/// In an async* function, this represents the stream controller parameter.
JS.TemporaryId _asyncStarController;
- // TODO(jmesserly): fuse this with notNull check.
- final _privateNames = new HashMap<Library, HashMap<String, JS.TemporaryId>>();
-
JS.Identifier _extensionSymbolsModule;
final _extensionSymbols = new Map<String, JS.TemporaryId>();
@@ -246,7 +240,7 @@
JS.Program emitModule(
Component buildUnit, List<Component> summaries, List<Uri> summaryUris) {
- if (_moduleItems.isNotEmpty) {
+ if (moduleItems.isNotEmpty) {
throw new StateError('Can only call emitModule once.');
}
_component = buildUnit;
@@ -341,7 +335,7 @@
items.addAll(_typeTable.discharge());
// Add the module's code (produced by visiting compilation units, above)
- _copyAndFlattenBlocks(items, _moduleItems);
+ _copyAndFlattenBlocks(items, moduleItems);
// Build the module.
return new JS.Program(items, name: buildUnit.root.name);
@@ -480,7 +474,7 @@
if (node is Procedure && node.name.name == 'main') {
// Don't allow redefining names from this library.
var name = _emitTopLevelName(export.node);
- _moduleItems.add(js.statement(
+ moduleItems.add(js.statement(
'#.# = #;', [emitLibraryName(library), name.selector, name]));
}
}
@@ -504,7 +498,7 @@
_currentLibrary = c.enclosingLibrary;
_currentUri = c.fileUri;
- _moduleItems.add(_emitClassDeclaration(c));
+ moduleItems.add(_emitClassDeclaration(c));
_currentClass = savedClass;
types.thisType = savedClass?.thisType;
@@ -1051,7 +1045,7 @@
// TODO(jmesserly): we could export these symbols, if we want to mark
// implemented interfaces for user-defined classes.
var id = new JS.TemporaryId("_is_${getLocalClassName(c)}_default");
- _moduleItems.add(
+ moduleItems.add(
js.statement('const # = Symbol(#);', [id, js.string(id.name, "'")]));
isClassSymbol = id;
}
@@ -1211,9 +1205,6 @@
}
var classProcedures = c.procedures.where((p) => !p.isAbstract).toList();
- for (var m in _classProperties.mockMembers.values) {
- if (m is Procedure) classProcedures.add(m);
- }
for (var member in classProcedures) {
// Static getters/setters/methods cannot be called with dynamic dispatch,
// nor can they be torn off.
@@ -1268,9 +1259,6 @@
var staticFields = <JS.Property>[];
var classFields = c.fields.toList();
- for (var m in _classProperties.mockMembers.values) {
- if (m is Field) classFields.add(m);
- }
for (var field in classFields) {
// Only instance fields need to be saved for dynamic dispatch.
var isStatic = field.isStatic;
@@ -1636,11 +1624,6 @@
}
_currentUri = savedUri;
- _classProperties.mockMembers.forEach((String name, Member member) {
- jsMethods
- .add(_implementMockMember(member, c, isSetter: name.endsWith('=')));
- });
-
// If the type doesn't have an `iterator`, but claims to implement Iterable,
// we inject the adaptor method here, as it's less code size to put the
// helper on a parent class. This pattern is common in the core libraries
@@ -1666,7 +1649,7 @@
}
JS.Fun fn;
- if (member.isExternal) {
+ if (member.isExternal && !member.isNoSuchMethodForwarder) {
if (member.isStatic) {
// TODO(vsm): Do we need to handle this case?
return null;
@@ -1812,122 +1795,6 @@
return _emitJSInterop(type.classNode) ?? visitInterfaceType(type);
}
- /// Given a class C that implements method M from interface I, but does not
- /// declare M, this will generate an implementation that forwards to
- /// noSuchMethod.
- ///
- /// For example:
- ///
- /// class Cat {
- /// bool eatFood(String food) => true;
- /// }
- /// class MockCat implements Cat {
- /// noSuchMethod(Invocation invocation) => 3;
- /// }
- ///
- /// It will generate an `eatFood` that looks like:
- ///
- /// eatFood(...args) {
- /// return core.bool.as(this.noSuchMethod(
- /// new dart.InvocationImpl.new('eatFood', args)));
- /// }
- ///
- /// Same technique is applied if interface I has fields, and C doesn't declare
- /// neither the fields nor the corresponding getters and setters.
- JS.Method _implementMockMember(Member member, Class c, {bool isSetter}) {
- JS.Method implementMockMember(
- ProcedureKind procedureKind, DartType returnType,
- [List<TypeParameter> typeParameters,
- List<JS.Parameter> positionalParameters,
- List<VariableDeclaration> namedParameters]) {
- assert(procedureKind != ProcedureKind.Factory);
-
- var invocationProps = <JS.Property>[];
- addProperty(String name, JS.Expression value) {
- invocationProps.add(new JS.Property(js.string(name), value));
- }
-
- var typeParams = _emitTypeFormals(typeParameters ?? []);
- var fnArgs = new List<JS.Parameter>.from(typeParams);
- JS.Expression positionalArgs;
- if (procedureKind == ProcedureKind.Getter) {
- addProperty('isGetter', js.boolean(true));
- positionalArgs = new JS.ArrayInitializer([]);
- } else if (procedureKind == ProcedureKind.Setter) {
- addProperty('isSetter', js.boolean(true));
- var valueArg = new JS.TemporaryId('value');
- positionalArgs = new JS.ArrayInitializer([valueArg]);
- fnArgs.add(valueArg);
- } else {
- addProperty('isMethod', js.boolean(true));
- if (namedParameters.isNotEmpty) {
- // Named parameters need to be emitted in the correct position (after
- // positional arguments) so we can detect them reliably.
- addProperty('namedArguments', namedArgumentTemp);
- positionalArgs = new JS.ArrayInitializer(positionalParameters);
- fnArgs.addAll(positionalParameters);
- fnArgs.add(namedArgumentTemp);
- } else {
- // In case we have optional parameters, we need to use rest args,
- // because sometimes mocks want to detect whether optional arguments
- // were passed, and this does not work reliably with undefined (should
- // not normally appear in DDC, but it can result from JS interop).
- //
- // TODO(jmesserly): perhaps we need to use rest args or destructuring
- // to get reliable optional argument passing in other scenarios? It
- // doesn't seem to occur outside of tests, perhaps due to the
- // combination of mockito and protobufs.
- positionalArgs = new JS.TemporaryId('args');
- fnArgs.add(new JS.RestParameter(positionalArgs));
- }
- }
-
- if (typeParams.isNotEmpty) {
- addProperty('typeArguments', new JS.ArrayInitializer(typeParams));
- }
-
- var fnBody =
- js.call('this.noSuchMethod(new #.InvocationImpl.new(#, #, #))', [
- runtimeModule,
- _declareMemberName(member),
- positionalArgs,
- new JS.ObjectInitializer(invocationProps)
- ]);
-
- returnType = _getTypeFromClass(returnType, member.enclosingClass, c);
- fnBody = _emitImplicitCast(fnBody, returnType);
-
- var fn = new JS.Fun(fnArgs, fnBody.toReturn().toBlock(),
- typeParams: typeParams);
-
- return new JS.Method(
- _declareMemberName(member,
- useExtension: _extensionTypes.isNativeClass(c)),
- fn,
- isGetter: procedureKind == ProcedureKind.Getter,
- isSetter: procedureKind == ProcedureKind.Setter,
- isStatic: false);
- }
-
- if (member is Field) {
- if (isSetter) {
- return implementMockMember(ProcedureKind.Setter, new VoidType());
- } else {
- return implementMockMember(ProcedureKind.Getter, member.type);
- }
- } else {
- var procedure = member as Procedure;
- var f = procedure.function;
- assert(procedure.isSetter == isSetter);
- return implementMockMember(
- procedure.kind,
- f.returnType,
- f.typeParameters,
- f.positionalParameters.map(_emitVariableRef).toList(),
- f.namedParameters);
- }
- }
-
/// This is called whenever a derived class needs to introduce a new field,
/// shadowing a field or getter/setter pair on its parent.
///
@@ -1937,34 +1804,27 @@
/// wrong behavior if a new field was declared.
List<JS.Method> _emitVirtualFieldAccessor(Field field) {
var virtualField = _classProperties.virtualFields[field];
- var result = <JS.Method>[];
var name = _declareMemberName(field);
- var mocks = _classProperties.mockMembers;
- if (!mocks.containsKey(field.name.name)) {
- var getter = js.fun('function() { return this[#]; }', [virtualField]);
- result.add(new JS.Method(name, getter, isGetter: true)
- ..sourceInformation = _nodeStart(field));
+ var getter = js.fun('function() { return this[#]; }', [virtualField]);
+ var jsGetter = new JS.Method(name, getter, isGetter: true)
+ ..sourceInformation = _nodeStart(field);
+
+ var args =
+ field.isFinal ? [new JS.Super(), name] : [new JS.This(), virtualField];
+
+ JS.Expression value = new JS.Identifier('value');
+ if (!field.isFinal && field.isGenericCovariantImpl) {
+ value = _emitImplicitCast(value, field.type);
}
+ args.add(value);
- if (!mocks.containsKey(field.name.name + '=')) {
- var args = field.isFinal
- ? [new JS.Super(), name]
- : [new JS.This(), virtualField];
+ var jsSetter = new JS.Method(
+ name, js.fun('function(value) { #[#] = #; }', args),
+ isSetter: true)
+ ..sourceInformation = _nodeStart(field);
- JS.Expression value = new JS.Identifier('value');
- if (!field.isFinal && field.isGenericCovariantImpl) {
- value = _emitImplicitCast(value, field.type);
- }
- args.add(value);
-
- result.add(new JS.Method(
- name, js.fun('function(value) { #[#] = #; }', args),
- isSetter: true)
- ..sourceInformation = _nodeStart(field));
- }
-
- return result;
+ return [jsGetter, jsSetter];
}
/// Provide Dart getters and setters that forward to the underlying native
@@ -2103,7 +1963,7 @@
}
_currentUri = savedUri;
- _moduleItems.add(result);
+ moduleItems.add(result);
}
void _emitTopLevelFields(List<Field> fields) {
@@ -2121,7 +1981,7 @@
init is BasicLiteral ||
init is StaticInvocation && isInlineJS(init.target)) {
_currentUri = field.fileUri;
- _moduleItems.add(js.statement('# = #;', [
+ moduleItems.add(js.statement('# = #;', [
_emitTopLevelName(field),
_visitInitializer(init, field.annotations)
]));
@@ -2135,7 +1995,7 @@
}
if (fields.isEmpty) return;
- _moduleItems.add(_emitLazyFields(
+ moduleItems.add(_emitLazyFields(
emitLibraryName(_currentLibrary), fields, _emitTopLevelMemberName));
}
@@ -2283,7 +2143,7 @@
}
if (name.startsWith('_')) {
- return _emitPrivateNameSymbol(_currentLibrary, name);
+ return emitPrivateNameSymbol(_currentLibrary, name);
}
useExtension ??= _isSymbolizedMember(type, name);
@@ -2364,17 +2224,6 @@
hierarchy.getDispatchTarget(c, new Name(name), setter: true));
}
- JS.TemporaryId _emitPrivateNameSymbol(Library library, String name) {
- return _privateNames
- .putIfAbsent(library, () => new HashMap())
- .putIfAbsent(name, () {
- var id = new JS.TemporaryId(name);
- _moduleItems.add(
- js.statement('const # = Symbol(#);', [id, js.string(id.name, "'")]));
- return id;
- });
- }
-
JS.Expression _emitStaticMemberName(String name, [NamedNode member]) {
if (member != null) {
var jsName = _emitJSInteropStaticMemberName(member);
@@ -2466,7 +2315,7 @@
var procedures = library.procedures
.where((p) => !p.isExternal && !p.isAbstract)
.toList();
- _moduleItems.addAll(procedures
+ moduleItems.addAll(procedures
.where((p) => !p.isAccessor)
.map(_emitLibraryFunction)
.toList());
@@ -2475,7 +2324,7 @@
void _emitLibraryAccessors(Iterable<Procedure> accessors) {
if (accessors.isEmpty) return;
- _moduleItems.add(runtimeStatement('copyProperties(#, { # })', [
+ moduleItems.add(runtimeStatement('copyProperties(#, { # })', [
emitLibraryName(_currentLibrary),
accessors.map(_emitLibraryAccessor).toList()
]));
@@ -4864,7 +4713,7 @@
var last = node.value.split('.').last;
var name = js.escapedString(node.value, "'");
if (last.startsWith('_')) {
- var nativeSymbol = _emitPrivateNameSymbol(_currentLibrary, last);
+ var nativeSymbol = emitPrivateNameSymbol(_currentLibrary, last);
return js.call('new #.new(#, #)', [
_emitConstructorAccess(privateSymbolClass.rawType),
name,
@@ -4894,7 +4743,7 @@
if (_currentFunction == null || usesTypeParams) return jsExpr;
var temp = new JS.TemporaryId('const');
- _moduleItems.add(js.statement('let #;', [temp]));
+ moduleItems.add(js.statement('let #;', [temp]));
return js.call('# || (# = #)', [temp, temp, jsExpr]);
}
diff --git a/pkg/dev_compiler/lib/src/kernel/property_model.dart b/pkg/dev_compiler/lib/src/kernel/property_model.dart
index 51cad84..e630821 100644
--- a/pkg/dev_compiler/lib/src/kernel/property_model.dart
+++ b/pkg/dev_compiler/lib/src/kernel/property_model.dart
@@ -196,8 +196,6 @@
/// super.
final inheritedSetters = new HashSet<String>();
- final mockMembers = <String, Member>{};
-
final extensionMethods = new Set<String>();
final extensionAccessors = new Set<String>();
@@ -231,14 +229,12 @@
}
}
- _collectMockMembers(class_);
_collectExtensionMembers(class_);
var virtualAccessorNames = new HashSet<String>()
..addAll(inheritedGetters)
..addAll(inheritedSetters)
- ..addAll(extensionAccessors)
- ..addAll(mockMembers.values.map((m) => m.name.name));
+ ..addAll(extensionAccessors);
// Visit accessors in the current class, and see if they need to be
// generated differently based on the inherited fields/accessors.
@@ -258,62 +254,6 @@
CoreTypes get coreTypes => extensionTypes.coreTypes;
- void _collectMockMembers(Class class_) {
- // TODO(jmesserly): every type with nSM will generate new stubs for all
- // abstract members. For example:
- //
- // class C { m(); noSuchMethod(...) { ... } }
- // class D extends C { m(); noSuchMethod(...) { ... } }
- //
- // We'll generate D.m even though it is not necessary.
- //
- // Doing better is a bit tricky, as our current codegen strategy for the
- // mock methods encodes information about the number of arguments (and type
- // arguments) that D expects.
- if (!_hasNoSuchMethod(class_)) return;
-
- // Collect all unimplemented members.
- //
- // Initially, we track abstract and concrete members separately, then
- // remove concrete from the abstract set. This is done because abstract
- // members are allowed to "override" concrete ones in Dart.
- // (In that case, it will still be treated as a concrete member and can be
- // called at runtime.)
- var concreteMembers = new HashSet<String>();
-
- void addMember(Member m, bool classIsAbstract, {bool isSetter: false}) {
- var name = m.name.name;
- if (isSetter) name += '=';
- if (classIsAbstract || m.isAbstract) {
- mockMembers[name] = m;
- } else {
- concreteMembers.add(name);
- }
- }
-
- void visit(Class c, bool classIsAbstract) {
- if (c == null) return;
- visit(c.superclass, classIsAbstract);
- visit(c.mixedInClass, classIsAbstract);
- for (var i in c.implementedTypes) visit(i.classNode, true);
-
- for (var m in c.members) {
- if (m is Field) {
- if (m.isStatic) continue;
- addMember(m, classIsAbstract);
- if (m.hasSetter) addMember(m, classIsAbstract, isSetter: true);
- } else if (m is Procedure) {
- if (m.isStatic) continue;
- addMember(m, classIsAbstract, isSetter: m.isSetter);
- }
- }
- }
-
- visit(class_, false);
-
- concreteMembers.forEach(mockMembers.remove);
- }
-
void _collectExtensionMembers(Class class_) {
if (extensionTypes.isNativeClass(class_)) return;
@@ -327,17 +267,6 @@
// For members on this class, check them against all generic interfaces.
var seenConcreteMembers = new HashSet<String>();
_findExtensionMembers(class_, seenConcreteMembers, allNatives);
- // Add mock members. These are compiler-generated concrete members that
- // forward to `noSuchMethod`.
- for (var m in mockMembers.values) {
- var name = m.name.name;
- if (seenConcreteMembers.add(name) && allNatives.contains(name)) {
- var extMembers = m is Procedure && !m.isAccessor
- ? extensionMethods
- : extensionAccessors;
- extMembers.add(name);
- }
- }
// For members of the superclass, we may need to add checks because this
// class adds a new unsafe interface. Collect those checks.
@@ -421,17 +350,4 @@
var s = c.superclass;
if (s != null) _collectNativeMembers(s, members);
}
-
- /// Return `true` if the given [classElement] has a noSuchMethod() method
- /// distinct from the one declared in class Object, as per the Dart Language
- /// Specification (section 10.4).
- // TODO(jmesserly): this was taken from error_verifier.dart
- bool _hasNoSuchMethod(Class c) {
- // TODO(jmesserly): is this lookup fast in Kernel?
- // TODO(jmesserly): our old code may have matched an abstract nSM, but
- // that seems incorrect. So we now look for a dispatch target.
- var method = types.hierarchy.getDispatchTarget(c, new Name('noSuchMethod'));
- var definingClass = method?.enclosingClass;
- return definingClass != null && definingClass != coreTypes.objectClass;
- }
}
diff --git a/pkg/dev_compiler/lib/src/kernel/target.dart b/pkg/dev_compiler/lib/src/kernel/target.dart
index b1888c6..26dbc21 100644
--- a/pkg/dev_compiler/lib/src/kernel/target.dart
+++ b/pkg/dev_compiler/lib/src/kernel/target.dart
@@ -2,6 +2,7 @@
// 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 'dart:core' hide MapEntry;
import 'package:kernel/kernel.dart';
import 'package:kernel/core_types.dart';
import 'package:kernel/class_hierarchy.dart';
@@ -57,6 +58,9 @@
bool get nativeExtensionExpectsString => false;
@override
+ bool get enableNoSuchMethodForwarders => true;
+
+ @override
void performModularTransformationsOnLibraries(
CoreTypes coreTypes, ClassHierarchy hierarchy, List<Library> libraries,
{void logger(String msg)}) {}
@@ -68,8 +72,40 @@
@override
Expression instantiateInvocation(CoreTypes coreTypes, Expression receiver,
String name, Arguments arguments, int offset, bool isSuper) {
- // TODO(sigmund): implement;
- return new InvalidExpression(null);
+ // TODO(jmesserly): preserve source information?
+ // (These method are synthetic. Also unclear if the offset will correspond
+ // to the file where the class resides, or the file where the method we're
+ // mocking resides).
+ Expression createInvocation(String name, List<Expression> positional) {
+ var ctor = coreTypes.invocationClass.procedures
+ .firstWhere((c) => c.name.name == name);
+ return new StaticInvocation(ctor, new Arguments(positional));
+ }
+
+ if (name.startsWith('get:')) {
+ return createInvocation('getter', [new SymbolLiteral(name.substring(4))]);
+ }
+ if (name.startsWith('set:')) {
+ return createInvocation('setter', [
+ new SymbolLiteral(name.substring(4) + '='),
+ arguments.positional.single
+ ]);
+ }
+ var ctorArgs = <Expression>[new SymbolLiteral(name)];
+ bool isGeneric = arguments.types.isNotEmpty;
+ if (isGeneric) {
+ ctorArgs.add(new ListLiteral(
+ arguments.types.map((t) => new TypeLiteral(t)).toList()));
+ }
+ ctorArgs.add(new ListLiteral(arguments.positional));
+ if (arguments.named.isNotEmpty) {
+ ctorArgs.add(new MapLiteral(
+ arguments.named
+ .map((n) => new MapEntry(new SymbolLiteral(n.name), n.value))
+ .toList(),
+ keyType: coreTypes.symbolClass.rawType));
+ }
+ return createInvocation(isGeneric ? 'genericMethod' : 'method', ctorArgs);
}
@override
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 ca353ba..b8b88e2 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
@@ -6,6 +6,7 @@
/// generator.
part of dart._runtime;
+// TODO(jmesserly): remove this in favor of _Invocation.
class InvocationImpl extends Invocation {
final Symbol memberName;
final List positionalArguments;
diff --git a/tests/language_2/language_2_dartdevc.status b/tests/language_2/language_2_dartdevc.status
index 51b502e..2bfb404 100644
--- a/tests/language_2/language_2_dartdevc.status
+++ b/tests/language_2/language_2_dartdevc.status
@@ -521,12 +521,13 @@
mixin_supertype_subclass_test/05: MissingCompileTimeError
mixin_type_parameters_errors_test/03: MissingCompileTimeError
mixin_type_parameters_errors_test/04: MissingCompileTimeError
+mock_writable_final_field_test: RuntimeError # Issue 30847
mock_writable_final_private_field_test: RuntimeError
multiline_newline_test/06: MissingCompileTimeError
multiline_newline_test/06r: MissingCompileTimeError
named_constructor_test/01: MissingCompileTimeError
named_parameters_default_eq_test/02: MissingCompileTimeError
-no_such_method_mock_test: RuntimeError # Issue 33103, switch DDK to kernel stubs
+no_such_method_mock_test: RuntimeError # Issue 31426 - Kernel does not introduce nSM for implemented fields.
null2_test: RuntimeError # Issue 32194
null_method_test: RuntimeError # Issue 32194
null_no_such_method_test: CompileTimeError # Issue 31533
@@ -617,7 +618,6 @@
void_type_usage_test/conditional3_return_to_void: MissingCompileTimeError, Crash
void_type_usage_test/conditional_return_to_void: MissingCompileTimeError, Crash
wrong_number_type_arguments_test/01: MissingCompileTimeError
-nosuchmethod_forwarding/nosuchmethod_forwarding_arguments_test: RuntimeError
[ $compiler == dartdevk && $checked ]
assertion_initializer_const_error2_test/*: MissingCompileTimeError