[ddc-kernel] Fix how mock members for fields are generated

Bug:
Change-Id: I6b910c9faa741fd8c8121250fbce55e9a9d29c50
Reviewed-on: https://dart-review.googlesource.com/24121
Reviewed-by: Kevin Millikin <kmillikin@google.com>
Commit-Queue: Dmitry Stefantsov <dmitryas@google.com>
This commit is contained in:
Dmitry Stefantsov 2017-12-01 09:46:16 +00:00 committed by commit-bot@chromium.org
parent db383f64ad
commit 316bc2d96e
3 changed files with 108 additions and 96 deletions

View file

@ -1562,8 +1562,9 @@ class ProgramCompiler
}
}
jsMethods.addAll(_classProperties.mockMembers.values
.map((e) => _implementMockMember(e, c)));
for (Member m in _classProperties.mockMembers.values) {
_addMockMembers(m, c, jsMethods);
}
// 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
@ -1719,69 +1720,108 @@ class ProgramCompiler
/// return core.bool.as(this.noSuchMethod(
/// new dart.InvocationImpl.new('eatFood', args)));
/// }
JS.Method _implementMockMember(Procedure method, Class c) {
var invocationProps = <JS.Property>[];
addProperty(String name, JS.Expression value) {
invocationProps.add(new JS.Property(js.string(name), value));
}
///
/// Same technique is applied if interface I has fields, and C doesn't declare
/// neither the fields nor the corresponding getters and setters.
Iterable<JS.Method> _addMockMembers(
Member member, Class c, List<JS.Method> jsMethods) {
JS.Method implementMockMember(
List<TypeParameter> typeParameters,
List<VariableDeclaration> namedParameters,
ProcedureKind mockMemberKind,
DartType returnType) {
assert(mockMemberKind != ProcedureKind.Factory);
var args = new JS.TemporaryId('args');
var function = method.function;
var typeParams = _emitTypeFormals(function.typeParameters);
var fnArgs = new List<JS.Parameter>.from(typeParams);
JS.Expression positionalArgs;
if (function.namedParameters.isNotEmpty) {
addProperty('namedArguments', _callHelper('extractNamedArgs(#)', [args]));
}
if (!method.isAccessor) {
addProperty('isMethod', js.boolean(true));
fnArgs.add(new JS.RestParameter(args));
positionalArgs = args;
} else {
if (method.isGetter) {
addProperty('isGetter', js.boolean(true));
positionalArgs = new JS.ArrayInitializer([]);
} else if (method.isSetter) {
addProperty('isSetter', js.boolean(true));
fnArgs.add(args);
positionalArgs = new JS.ArrayInitializer([args]);
var invocationProps = <JS.Property>[];
addProperty(String name, JS.Expression value) {
invocationProps.add(new JS.Property(js.string(name), value));
}
var args = new JS.TemporaryId('args');
var typeParams = _emitTypeFormals(typeParameters);
var fnArgs = new List<JS.Parameter>.from(typeParams);
JS.Expression positionalArgs;
if (namedParameters.isNotEmpty) {
addProperty(
'namedArguments', _callHelper('extractNamedArgs(#)', [args]));
}
if (mockMemberKind != ProcedureKind.Getter &&
mockMemberKind != ProcedureKind.Setter) {
addProperty('isMethod', js.boolean(true));
fnArgs.add(new JS.RestParameter(args));
positionalArgs = args;
} else {
if (mockMemberKind == ProcedureKind.Getter) {
addProperty('isGetter', js.boolean(true));
positionalArgs = new JS.ArrayInitializer([]);
} else if (mockMemberKind == ProcedureKind.Setter) {
addProperty('isSetter', js.boolean(true));
fnArgs.add(args);
positionalArgs = new JS.ArrayInitializer([args]);
}
}
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)
]);
if (!types.isTop(returnType)) {
fnBody = js.call('#._check(#)', [_emitType(returnType), fnBody]);
}
var fn = new JS.Fun(fnArgs, js.statement('{ return #; }', [fnBody]),
typeParams: typeParams);
return new JS.Method(
_declareMemberName(member,
useExtension: _extensionTypes.isNativeClass(c)),
fn,
isGetter: mockMemberKind == ProcedureKind.Getter,
isSetter: mockMemberKind == ProcedureKind.Setter,
isStatic: false);
}
if (typeParams.isNotEmpty) {
addProperty('typeArguments', new JS.ArrayInitializer(typeParams));
if (member is Field) {
jsMethods.add(implementMockMember(
const <TypeParameter>[],
const <VariableDeclaration>[],
ProcedureKind.Getter,
Substitution
.fromSupertype(
hierarchy.getClassAsInstanceOf(c, member.enclosingClass))
.substituteType(member.type)));
if (!member.isFinal) {
jsMethods.add(implementMockMember(
const <TypeParameter>[],
const <VariableDeclaration>[],
ProcedureKind.Setter,
new DynamicType()));
}
} else {
Procedure procedure = member as Procedure;
FunctionNode function = procedure.function;
jsMethods.add(implementMockMember(
function.typeParameters,
function.namedParameters,
procedure.kind,
Substitution
.fromSupertype(
hierarchy.getClassAsInstanceOf(c, member.enclosingClass))
.substituteType(function.returnType)));
}
var fnBody =
js.call('this.noSuchMethod(new #.InvocationImpl.new(#, #, #))', [
_runtimeModule,
_declareMemberName(method),
positionalArgs,
new JS.ObjectInitializer(invocationProps)
]);
var returnType = Substitution
.fromSupertype(hierarchy.getClassAsInstanceOf(c, method.enclosingClass))
.substituteType(method.function.functionType);
if (!types.isTop(returnType)) {
fnBody = js.call('#._check(#)', [_emitType(returnType), fnBody]);
}
var fn = new JS.Fun(fnArgs, js.statement('{ return #; }', [fnBody]),
typeParams: typeParams);
return new JS.Method(
_declareMemberName(method,
useExtension: _extensionTypes.isNativeClass(c)),
fn,
isGetter: method.isGetter,
isSetter: method.isSetter,
isStatic: false);
}
/// This is called whenever a derived class needs to introduce a new field,

View file

@ -282,25 +282,12 @@ class ClassPropertyModel {
for (var m in c.members) {
if (m is Constructor) continue;
if (m is Procedure && m.isStatic) continue;
var isAbstract = classIsAbstract || m.isAbstract;
addMember(bool setter) {
var name = m.name.name;
if (setter) name += '=';
if (isAbstract) {
mockMembers[name] = m;
} else {
concreteMembers.add(name);
}
}
var name = m.name.name;
if (m is Field) {
addMember(false);
if (!m.isFinal) addMember(true);
if (classIsAbstract || m.isAbstract) {
mockMembers[m.name.name] = m;
} else {
var p = m as Procedure;
if (!p.isStatic) addMember(p.isSetter);
concreteMembers.add(m.name.name);
}
}
}

View file

@ -453,19 +453,6 @@ first_class_types_literals_test/07: MissingCompileTimeError
first_class_types_literals_test/10: MissingCompileTimeError
first_class_types_literals_test/11: MissingCompileTimeError
first_class_types_literals_test/12: MissingCompileTimeError
flatten_test/01: Crash
flatten_test/02: Crash
flatten_test/03: Crash
flatten_test/04: Crash
flatten_test/05: Crash
flatten_test/06: Crash
flatten_test/07: Crash
flatten_test/08: Crash
flatten_test/09: Crash
flatten_test/10: Crash
flatten_test/11: Crash
flatten_test/12: Crash
flatten_test/none: Crash
function_propagation_test: CompileTimeError
function_subtype_bound_closure7_test: CompileTimeError
function_type_parameter2_negative_test: Fail
@ -743,8 +730,6 @@ mixin_type_parameters_errors_test/02: MissingCompileTimeError
mixin_type_parameters_errors_test/03: MissingCompileTimeError
mixin_type_parameters_errors_test/04: MissingCompileTimeError
mixin_type_parameters_errors_test/05: MissingCompileTimeError
mock_writable_final_field_test: Crash
mock_writable_final_private_field_test: Crash
multiline_newline_test/06: MissingCompileTimeError
multiline_newline_test/06r: MissingCompileTimeError
named_constructor_test/01: MissingCompileTimeError
@ -1102,6 +1087,10 @@ expect_test: RuntimeError # Issue 29920; Expect.identical did not fail
f_bounded_quantification3_test: RuntimeError # Issue 29920; Uncaught Error: type arguments should not be null: (F1, F2) => {
field_increment_bailout_test: RuntimeError # Issue 29920; UnimplementedError: JsInstanceMirror.delegate unimplemented
field_initialization_order_test/none: RuntimeError # Expect.equals(expected: <b.a.ai.bi.>, actual: <b.bi.a.ai.>) fails.
flatten_test/05: MissingRuntimeError # Issue 29920
flatten_test/08: MissingRuntimeError # Issue 29920
flatten_test/09: MissingRuntimeError # Issue 29920
flatten_test/12: MissingRuntimeError # Issue 29920
for_variable_capture_test: RuntimeError # Issue 29920; Expect.equals(expected: <1>, actual: <0>) fails.
function_subtype_inline2_test: RuntimeError # Expect.fail('Missing type error: 'new C.c1(m2)'.')
function_type_alias6_test/none: RuntimeError # Expect.isTrue(false) fails.
@ -1175,10 +1164,6 @@ expect_test: RuntimeError # Issue 29920
f_bounded_quantification3_test: RuntimeError # Issue 29920
final_field_initialization_order_test: RuntimeError # Issue 31058
first_class_types_test: RuntimeError, OK # Strong mode reifies inferred type argument.
flatten_test/05: MissingRuntimeError # Issue 29920
flatten_test/08: MissingRuntimeError # Issue 29920
flatten_test/09: MissingRuntimeError # Issue 29920
flatten_test/12: MissingRuntimeError # Issue 29920
fuzzy_arrows_test/03: RuntimeError # Issue 29630
generic_method_types_test/02: RuntimeError
getter_closure_execution_order_test: RuntimeError # Issue 29920