diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart index ba36692330b..2946b5e5637 100644 --- a/pkg/dev_compiler/lib/src/kernel/compiler.dart +++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart @@ -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 = []; - 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 _addMockMembers( + Member member, Class c, List jsMethods) { + JS.Method implementMockMember( + List typeParameters, + List 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.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 = []; + 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.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 [], + const [], + ProcedureKind.Getter, + Substitution + .fromSupertype( + hierarchy.getClassAsInstanceOf(c, member.enclosingClass)) + .substituteType(member.type))); + if (!member.isFinal) { + jsMethods.add(implementMockMember( + const [], + const [], + 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, diff --git a/pkg/dev_compiler/lib/src/kernel/property_model.dart b/pkg/dev_compiler/lib/src/kernel/property_model.dart index 2e16ad0a084..b589cc1617a 100644 --- a/pkg/dev_compiler/lib/src/kernel/property_model.dart +++ b/pkg/dev_compiler/lib/src/kernel/property_model.dart @@ -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); } } } diff --git a/tests/language_2/language_2_dartdevc.status b/tests/language_2/language_2_dartdevc.status index a33980a18a2..82250d4fdc9 100644 --- a/tests/language_2/language_2_dartdevc.status +++ b/tests/language_2/language_2_dartdevc.status @@ -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: , actual: ) 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