diff --git a/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart b/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart index 0885714ecc0e..ec6d37e01d82 100644 --- a/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart +++ b/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart @@ -606,9 +606,17 @@ class ClassHierarchyBuilder implements ClassHierarchyBase { } Member getDispatchTargetKernel(Class cls, Name name, bool isSetter) { - return getNodeFromClass(cls) - .getDispatchTarget(name, isSetter) - ?.getMember(this); + ClassMember classMember = + getNodeFromClass(cls).getDispatchTarget(name, isSetter); + Member member = classMember?.getMember(this); + if (member != null && member.isAbstract) { + if (cls.superclass != null) { + return getDispatchTargetKernel(cls.superclass, name, isSetter); + } else { + return null; + } + } + return member; } Member getCombinedMemberSignatureKernel(Class cls, Name name, bool isSetter, diff --git a/pkg/front_end/lib/src/fasta/kernel/forwarding_node.dart b/pkg/front_end/lib/src/fasta/kernel/forwarding_node.dart index 53f6b2d6597d..0b4a1660c6a3 100644 --- a/pkg/front_end/lib/src/fasta/kernel/forwarding_node.dart +++ b/pkg/front_end/lib/src/fasta/kernel/forwarding_node.dart @@ -162,6 +162,12 @@ class ForwardingNode { Arguments arguments = new Arguments(positionalArguments, types: typeArguments, named: namedArguments); Expression superCall; + assert(superTarget != null, + "No super target found for '${name}' in ${enclosingClass}."); + assert( + !superTarget.isAbstract, + "Abstract super target $superTarget found for '${name}' in " + "${enclosingClass}."); switch (kind) { case ProcedureKind.Method: case ProcedureKind.Operator: diff --git a/pkg/front_end/lib/src/fasta/kernel/member_covariance.dart b/pkg/front_end/lib/src/fasta/kernel/member_covariance.dart index 956f0fdfdc80..5d1d77fd0eef 100644 --- a/pkg/front_end/lib/src/fasta/kernel/member_covariance.dart +++ b/pkg/front_end/lib/src/fasta/kernel/member_covariance.dart @@ -61,14 +61,25 @@ class Covariance { /// If no type parameters are generic-covariant-impl, this is `null`. final List _typeParameters; - const Covariance.internal( - this._positionalParameters, this._namedParameters, this._typeParameters); + Covariance.internal( + this._positionalParameters, this._namedParameters, this._typeParameters) { + assert(_positionalParameters == null || + _positionalParameters.any((element) => element != 0)); + assert(_namedParameters == null || + _namedParameters.values.isNotEmpty && + _namedParameters.values.every((element) => element != 0)); + assert( + _typeParameters == null || _typeParameters.any((element) => element)); + } /// The empty covariance. /// /// This is used for all members that do not use any covariance, regardless /// of parameter structure. - const Covariance.empty() : this.internal(null, null, null); + const Covariance.empty() + : _positionalParameters = null, + _namedParameters = null, + _typeParameters = null; /// Computes the covariance for the setter aspect of [field]. /// @@ -287,7 +298,7 @@ class Covariance { int hash = 0; if (_positionalParameters != null) { for (int covariance in _positionalParameters) { - hash = hash * 13 + covariance.hashCode * 17; + hash += covariance.hashCode * 17; } } if (_namedParameters != null) { @@ -297,7 +308,9 @@ class Covariance { } if (_typeParameters != null) { for (bool covariance in _typeParameters) { - hash = hash * 29 + covariance.hashCode * 31; + if (covariance) { + hash += covariance.hashCode * 31; + } } } return hash; @@ -312,12 +325,10 @@ class Covariance { other._positionalParameters == null) { return false; } - if (_positionalParameters.length != - other._positionalParameters.length) { - return false; - } - for (int i = 0; i < _positionalParameters.length; i++) { - if (_positionalParameters[i] != other._positionalParameters[i]) { + int positionalParameterCount = max( + _positionalParameters.length, other._positionalParameters.length); + for (int i = 0; i < positionalParameterCount; i++) { + if (getPositionalVariance(i) != other.getPositionalVariance(i)) { return false; } } @@ -326,13 +337,12 @@ class Covariance { if (_namedParameters == null || other._namedParameters == null) { return false; } - if (_namedParameters.length != other._namedParameters.length) { - return false; - } - for (String name in _namedParameters.keys) { - int covariance = _namedParameters[name]; - int otherCovariance = other._namedParameters[name]; - if (covariance != otherCovariance) { + Set names = { + ..._namedParameters.keys, + ...other._namedParameters.keys + }; + for (String name in names) { + if (getNamedVariance(name) != other.getNamedVariance(name)) { return false; } } @@ -341,11 +351,11 @@ class Covariance { if (_typeParameters == null || other._typeParameters == null) { return false; } - if (_typeParameters.length != other._typeParameters.length) { - return false; - } - for (int i = 0; i < _typeParameters.length; i++) { - if (_typeParameters[i] != other._typeParameters[i]) { + int typeParameterCount = + max(_typeParameters.length, other._typeParameters.length); + for (int i = 0; i < typeParameterCount; i++) { + if (isTypeParameterGenericCovariantImpl(i) != + other.isTypeParameterGenericCovariantImpl(i)) { return false; } } @@ -354,4 +364,71 @@ class Covariance { } return false; } + + @override + String toString() { + StringBuffer sb = new StringBuffer(); + if (isEmpty) { + sb.write('Covariance.empty()'); + } else { + sb.write('Covariance('); + String comma = ''; + if (_positionalParameters != null) { + for (int index = 0; index < _positionalParameters.length; index++) { + if (_positionalParameters[index] != 0) { + sb.write(comma); + sb.write('$index:'); + switch (_positionalParameters[index]) { + case GenericCovariantImpl: + sb.write('GenericCovariantImpl'); + break; + case Covariant: + sb.write('Covariant'); + break; + default: + sb.write('GenericCovariantImpl+Covariant'); + break; + } + comma = ','; + } + } + } + if (_namedParameters != null) { + for (String name in _namedParameters.keys) { + int covariance = _namedParameters[name]; + if (covariance != 0) { + sb.write(comma); + sb.write('$name:'); + + switch (covariance) { + case GenericCovariantImpl: + sb.write('GenericCovariantImpl'); + break; + case Covariant: + sb.write('Covariant'); + break; + default: + sb.write('GenericCovariantImpl+Covariant'); + break; + } + comma = ','; + } + } + } + if (_typeParameters != null) { + sb.write(comma); + sb.write('types:'); + comma = ''; + for (int index = 0; index < _typeParameters.length; index++) { + if (_typeParameters[index]) { + sb.write(comma); + sb.write('$index'); + comma = ','; + } + } + } + sb.write(')'); + } + return sb.toString(); + } } diff --git a/pkg/front_end/test/member_covariance_test.dart b/pkg/front_end/test/member_covariance_test.dart new file mode 100644 index 000000000000..6f541df4906f --- /dev/null +++ b/pkg/front_end/test/member_covariance_test.dart @@ -0,0 +1,214 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// 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 'package:expect/expect.dart'; +import 'package:front_end/src/fasta/kernel/kernel_ast_api.dart'; +import 'package:front_end/src/fasta/kernel/member_covariance.dart'; + +main() { + void checkEquals(Covariance a, Covariance b) { + Expect.equals(a, b); + Expect.equals(a.hashCode, b.hashCode); + } + + checkEquals(const Covariance.empty(), new Covariance.empty()); + + Expect.isTrue(const Covariance.empty().isEmpty); + Expect.isTrue(new Covariance.empty().isEmpty); + Expect.isTrue(new Covariance.internal(null, null, null).isEmpty); + + checkEquals( + const Covariance.empty(), new Covariance.internal(null, null, null)); + + Expect.throws(() => new Covariance.internal([], null, null)); + Expect.throws(() => new Covariance.internal([0], null, null)); + + checkEquals( + new Covariance.internal([Covariance.GenericCovariantImpl], null, null), + new Covariance.internal( + [Covariance.GenericCovariantImpl, 0], null, null)); + + checkEquals(new Covariance.internal([Covariance.Covariant], null, null), + new Covariance.internal([Covariance.Covariant, 0], null, null)); + + checkEquals(new Covariance.internal([0, Covariance.Covariant], null, null), + new Covariance.internal([0, Covariance.Covariant, 0], null, null)); + + Expect.throws(() => new Covariance.internal(null, {}, null)); + Expect.throws(() => new Covariance.internal(null, {'a': 0}, null)); + + checkEquals(new Covariance.internal(null, {'a': Covariance.Covariant}, null), + new Covariance.internal(null, {'a': Covariance.Covariant}, null)); + + Expect.throws(() => new Covariance.internal(null, null, [])); + + Expect.throws(() => new Covariance.internal(null, null, [false])); + + checkEquals(new Covariance.internal(null, null, [true]), + new Covariance.internal(null, null, [true, false])); + + Covariance covariance = new Covariance.internal([ + Covariance.Covariant, + Covariance.GenericCovariantImpl, + 0, + Covariance.Covariant | Covariance.GenericCovariantImpl + ], { + 'a': Covariance.Covariant, + 'b': Covariance.GenericCovariantImpl, + 'd': Covariance.Covariant | Covariance.GenericCovariantImpl + }, [ + false, + true + ]); + + Expect.equals(Covariance.Covariant, covariance.getPositionalVariance(0)); + Expect.equals( + Covariance.GenericCovariantImpl, covariance.getPositionalVariance(1)); + Expect.equals(0, covariance.getPositionalVariance(2)); + Expect.equals(Covariance.Covariant | Covariance.GenericCovariantImpl, + covariance.getPositionalVariance(3)); + Expect.equals(0, covariance.getPositionalVariance(4)); + + Expect.equals(Covariance.Covariant, covariance.getNamedVariance('a')); + Expect.equals( + Covariance.GenericCovariantImpl, covariance.getNamedVariance('b')); + Expect.equals(0, covariance.getNamedVariance('c')); + Expect.equals(Covariance.Covariant | Covariance.GenericCovariantImpl, + covariance.getNamedVariance('d')); + Expect.equals(0, covariance.getNamedVariance('e')); + + Expect.isFalse(covariance.isTypeParameterGenericCovariantImpl(0)); + Expect.isTrue(covariance.isTypeParameterGenericCovariantImpl(1)); + Expect.isFalse(covariance.isTypeParameterGenericCovariantImpl(0)); + + Expect.stringEquals( + 'Covariance(' + '0:Covariant,1:GenericCovariantImpl,3:GenericCovariantImpl+Covariant,' + 'a:Covariant,b:GenericCovariantImpl,d:GenericCovariantImpl+Covariant,' + 'types:1)', + covariance.toString()); + + Procedure noParameterProcedure = + new Procedure(null, ProcedureKind.Method, new FunctionNode(null)); + Covariance noParameterProcedureCovariance = + new Covariance.fromMember(noParameterProcedure, forSetter: false); + Expect.isTrue(noParameterProcedureCovariance.isEmpty); + + covariance.applyCovariance(noParameterProcedure); + noParameterProcedureCovariance = + new Covariance.fromMember(noParameterProcedure, forSetter: false); + Expect.isTrue(noParameterProcedureCovariance.isEmpty); + + Procedure oneParameterProcedure = new Procedure( + null, + ProcedureKind.Method, + new FunctionNode(null, + positionalParameters: [new VariableDeclaration(null)])); + Covariance oneParameterProcedureCovariance = + new Covariance.fromMember(oneParameterProcedure, forSetter: false); + Expect.isTrue(oneParameterProcedureCovariance.isEmpty); + + covariance.applyCovariance(oneParameterProcedure); + oneParameterProcedureCovariance = + new Covariance.fromMember(oneParameterProcedure, forSetter: false); + Expect.isFalse(oneParameterProcedureCovariance.isEmpty); + Expect.equals(new Covariance.internal([Covariance.Covariant], null, null), + oneParameterProcedureCovariance); + + Procedure positionalParametersProcedure = new Procedure( + null, + ProcedureKind.Method, + new FunctionNode(null, positionalParameters: [ + new VariableDeclaration(null), + new VariableDeclaration(null), + new VariableDeclaration(null), + new VariableDeclaration(null), + new VariableDeclaration(null) + ])); + Covariance positionalParametersProcedureCovariance = + new Covariance.fromMember(positionalParametersProcedure, + forSetter: false); + Expect.isTrue(positionalParametersProcedureCovariance.isEmpty); + + covariance.applyCovariance(positionalParametersProcedure); + positionalParametersProcedureCovariance = new Covariance.fromMember( + positionalParametersProcedure, + forSetter: false); + Expect.isFalse(positionalParametersProcedureCovariance.isEmpty); + checkEquals( + new Covariance.internal([ + Covariance.Covariant, + Covariance.GenericCovariantImpl, + 0, + Covariance.Covariant | Covariance.GenericCovariantImpl + ], null, null), + positionalParametersProcedureCovariance); + + Procedure namedParametersProcedure = new Procedure( + null, + ProcedureKind.Method, + new FunctionNode(null, namedParameters: [ + new VariableDeclaration('a'), + new VariableDeclaration('b'), + new VariableDeclaration('c'), + new VariableDeclaration('d'), + new VariableDeclaration('e') + ])); + Covariance namedParametersProcedureCovariance = + new Covariance.fromMember(namedParametersProcedure, forSetter: false); + Expect.isTrue(namedParametersProcedureCovariance.isEmpty); + + covariance.applyCovariance(namedParametersProcedure); + namedParametersProcedureCovariance = + new Covariance.fromMember(namedParametersProcedure, forSetter: false); + Expect.isFalse(namedParametersProcedureCovariance.isEmpty); + checkEquals( + new Covariance.internal( + null, + { + 'a': Covariance.Covariant, + 'b': Covariance.GenericCovariantImpl, + 'd': Covariance.Covariant | Covariance.GenericCovariantImpl + }, + null), + namedParametersProcedureCovariance); + + Procedure typeParametersProcedure = new Procedure( + null, + ProcedureKind.Method, + new FunctionNode(null, typeParameters: [ + new TypeParameter(null), + new TypeParameter(null), + new TypeParameter(null), + ])); + Covariance typeParametersProcedureCovariance = + new Covariance.fromMember(typeParametersProcedure, forSetter: false); + Expect.isTrue(typeParametersProcedureCovariance.isEmpty); + + covariance.applyCovariance(typeParametersProcedure); + typeParametersProcedureCovariance = + new Covariance.fromMember(typeParametersProcedure, forSetter: false); + Expect.isFalse(typeParametersProcedureCovariance.isEmpty); + checkEquals(new Covariance.internal(null, null, [false, true]), + typeParametersProcedureCovariance); + + Covariance merged = + const Covariance.empty().merge(positionalParametersProcedureCovariance); + checkEquals(positionalParametersProcedureCovariance, merged); + merged = merged.merge(namedParametersProcedureCovariance); + checkEquals( + new Covariance.internal([ + Covariance.Covariant, + Covariance.GenericCovariantImpl, + 0, + Covariance.GenericCovariantImpl | Covariance.Covariant + ], { + 'a': Covariance.Covariant, + 'b': Covariance.GenericCovariantImpl, + 'd': Covariance.Covariant | Covariance.GenericCovariantImpl + }, null), + merged); + merged = merged.merge(typeParametersProcedureCovariance); + checkEquals(covariance, merged); +} diff --git a/pkg/front_end/test/spell_checking_list_code.txt b/pkg/front_end/test/spell_checking_list_code.txt index 1b3dce825f3f..65dc5999f29e 100644 --- a/pkg/front_end/test/spell_checking_list_code.txt +++ b/pkg/front_end/test/spell_checking_list_code.txt @@ -514,6 +514,7 @@ il imitate immutability impl +impl+ implementers imply implying @@ -592,8 +593,8 @@ l lacks lang largest -launcher lattice +launcher layer layout lc diff --git a/pkg/front_end/testcases/nnbd_mixed/issue43988/main.dart b/pkg/front_end/testcases/nnbd_mixed/issue43988/main.dart new file mode 100644 index 000000000000..7f60cbd65852 --- /dev/null +++ b/pkg/front_end/testcases/nnbd_mixed/issue43988/main.dart @@ -0,0 +1,17 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// 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. + +// @dart=2.9 + +import 'main_lib.dart'; + +class E1 with A, D {} + +class E2 = Object with A, D; + +abstract class C6 extends C3 implements C4 {} + +abstract class C8 extends C5 implements C7 {} + +main() {} diff --git a/pkg/front_end/testcases/nnbd_mixed/issue43988/main.dart.textual_outline.expect b/pkg/front_end/testcases/nnbd_mixed/issue43988/main.dart.textual_outline.expect new file mode 100644 index 000000000000..1763bc0bb304 --- /dev/null +++ b/pkg/front_end/testcases/nnbd_mixed/issue43988/main.dart.textual_outline.expect @@ -0,0 +1,12 @@ +// @dart = 2.9 +import 'main_lib.dart'; + +class E1 with A, D {} + +class E2 = Object with A, D; + +abstract class C6 extends C3 implements C4 {} + +abstract class C8 extends C5 implements C7 {} + +main() {} diff --git a/pkg/front_end/testcases/nnbd_mixed/issue43988/main.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd_mixed/issue43988/main.dart.textual_outline_modelled.expect new file mode 100644 index 000000000000..9bd7263aa3b5 --- /dev/null +++ b/pkg/front_end/testcases/nnbd_mixed/issue43988/main.dart.textual_outline_modelled.expect @@ -0,0 +1,11 @@ +// @dart = 2.9 +import 'main_lib.dart'; + +abstract class C6 extends C3 implements C4 {} + +abstract class C8 extends C5 implements C7 {} + +class E1 with A, D {} + +class E2 = Object with A, D; +main() {} diff --git a/pkg/front_end/testcases/nnbd_mixed/issue43988/main.dart.weak.expect b/pkg/front_end/testcases/nnbd_mixed/issue43988/main.dart.weak.expect new file mode 100644 index 000000000000..1345fddd3196 --- /dev/null +++ b/pkg/front_end/testcases/nnbd_mixed/issue43988/main.dart.weak.expect @@ -0,0 +1,156 @@ +library; +import self as self; +import "dart:core" as core; +import "main_lib.dart" as mai; + +import "org-dartlang-testcase:///main_lib.dart"; + +abstract class _E1&Object&A = core::Object with mai::A /*isAnonymousMixin,hasConstConstructor*/ { + const synthetic constructor •() → self::_E1&Object&A* + : super core::Object::•() + ; + abstract member-signature get _identityHashCode() → core::int*; -> core::Object::_identityHashCode + abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*; -> core::Object::_instanceOf + abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOf + abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfTrue + abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfFalse + abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::== + abstract member-signature get hashCode() → core::int*; -> core::Object::hashCode + abstract member-signature method toString() → core::String*; -> core::Object::toString + abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod + abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType +} +abstract class _E1&Object&A&D = self::_E1&Object&A with mai::D /*isAnonymousMixin,hasConstConstructor*/ { + const synthetic constructor •() → self::_E1&Object&A&D* + : super self::_E1&Object&A::•() + ; + abstract forwarding-stub method method(covariant core::num* i, {core::String* s = #C1}) → core::String*; +} +class E1 extends self::_E1&Object&A&D { + synthetic constructor •() → self::E1* + : super self::_E1&Object&A&D::•() + ; + abstract member-signature method method(covariant core::num* i, {core::String* s = #C1}) → core::String*; -> self::_E1&Object&A&D::method +} +abstract class _E2&Object&A = core::Object with mai::A /*isAnonymousMixin,hasConstConstructor*/ { + const synthetic constructor •() → self::_E2&Object&A* + : super core::Object::•() + ; + abstract member-signature get _identityHashCode() → core::int*; -> core::Object::_identityHashCode + abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*; -> core::Object::_instanceOf + abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOf + abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfTrue + abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfFalse + abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::== + abstract member-signature get hashCode() → core::int*; -> core::Object::hashCode + abstract member-signature method toString() → core::String*; -> core::Object::toString + abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod + abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType +} +class E2 = self::_E2&Object&A with mai::D /*hasConstConstructor*/ { + const synthetic constructor •() → self::E2* + : super self::_E2&Object&A::•() + ; + abstract forwarding-stub method method(covariant core::num* i, {core::String* s = #C1}) → core::String*; +} +abstract class C6 extends mai::C3 implements mai::C4 { + synthetic constructor •() → self::C6* + : super mai::C3::•() + ; + abstract forwarding-stub method method2([covariant core::String* a = #C2]) → dynamic; + abstract member-signature get _identityHashCode() → core::int*; -> core::Object::_identityHashCode + abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*; -> core::Object::_instanceOf + abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOf + abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfTrue + abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfFalse + abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::== + abstract member-signature get hashCode() → core::int*; -> core::Object::hashCode + abstract member-signature method toString() → core::String*; -> core::Object::toString + abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod + abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType +} +abstract class C8 extends mai::C5 implements mai::C7 { + synthetic constructor •() → self::C8* + : super mai::C5::•() + ; + abstract forwarding-stub method method2([covariant core::String* a = #C2, core::num* b = #C2]) → dynamic; + abstract member-signature get _identityHashCode() → core::int*; -> core::Object::_identityHashCode + abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*; -> core::Object::_instanceOf + abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOf + abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfTrue + abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfFalse + abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::== + abstract member-signature get hashCode() → core::int*; -> core::Object::hashCode + abstract member-signature method toString() → core::String*; -> core::Object::toString + abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod + abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType +} +static method main() → dynamic {} + +library /*isNonNullableByDefault*/; +import self as mai; +import "dart:core" as core; + +abstract class Interface extends core::Object { + synthetic constructor •() → mai::Interface + : super core::Object::•() + ; + abstract method method(core::num i) → core::String; +} +abstract class Interface2 extends core::Object { + synthetic constructor •() → mai::Interface2 + : super core::Object::•() + ; + abstract method method(covariant core::int i) → core::String; +} +abstract class A extends core::Object implements mai::Interface /*isMixinDeclaration*/ { + method method(core::num i, {core::String s = #C1}) → core::String + return s; +} +abstract class D extends core::Object implements mai::Interface, mai::Interface2 { + synthetic constructor •() → mai::D + : super core::Object::•() + ; + abstract forwarding-stub method method(covariant core::num i) → core::String; +} +abstract class C1 extends core::Object { + synthetic constructor •() → mai::C1 + : super core::Object::•() + ; + abstract method method2() → dynamic; +} +abstract class C2 extends core::Object { + synthetic constructor •() → mai::C2 + : super core::Object::•() + ; + abstract method method2([core::String a = #C2]) → dynamic; +} +abstract class C3 extends core::Object implements mai::C1, mai::C2 { + synthetic constructor •() → mai::C3 + : super core::Object::•() + ; + abstract member-signature method method2([core::String a = #C2]) → dynamic; -> mai::C2::method2 +} +abstract class C4 extends core::Object { + synthetic constructor •() → mai::C4 + : super core::Object::•() + ; + abstract method method2([covariant core::String a = #C2]) → dynamic; +} +abstract class C5 extends mai::C3 implements mai::C4 { + synthetic constructor •() → mai::C5 + : super mai::C3::•() + ; + abstract forwarding-stub method method2([covariant core::String a = #C2]) → dynamic; +} +abstract class C7 extends core::Object { + synthetic constructor •() → mai::C7 + : super core::Object::•() + ; + abstract method method2([core::String a = #C2, core::num b = #C2]) → dynamic; +} + +constants { + #C1 = "hello" + #C2 = null +} diff --git a/pkg/front_end/testcases/nnbd_mixed/issue43988/main.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd_mixed/issue43988/main.dart.weak.transformed.expect new file mode 100644 index 000000000000..341bd9b9cf78 --- /dev/null +++ b/pkg/front_end/testcases/nnbd_mixed/issue43988/main.dart.weak.transformed.expect @@ -0,0 +1,160 @@ +library; +import self as self; +import "dart:core" as core; +import "main_lib.dart" as mai; + +import "org-dartlang-testcase:///main_lib.dart"; + +abstract class _E1&Object&A extends core::Object implements mai::A /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/ { + const synthetic constructor •() → self::_E1&Object&A* + : super core::Object::•() + ; + abstract member-signature get _identityHashCode() → core::int*; -> core::Object::_identityHashCode + abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*; -> core::Object::_instanceOf + abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOf + abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfTrue + abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfFalse + abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::== + abstract member-signature get hashCode() → core::int*; -> core::Object::hashCode + abstract member-signature method toString() → core::String*; -> core::Object::toString + abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod + abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType + method /*isNonNullableByDefault, from org-dartlang-testcase:///main_lib.dart */ method(core::num i, {core::String s = #C1}) → core::String + return s; +} +abstract class _E1&Object&A&D extends self::_E1&Object&A implements mai::D /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/ { + const synthetic constructor •() → self::_E1&Object&A&D* + : super self::_E1&Object&A::•() + ; + abstract forwarding-stub method method(covariant core::num* i, {core::String* s = #C1}) → core::String*; +} +class E1 extends self::_E1&Object&A&D { + synthetic constructor •() → self::E1* + : super self::_E1&Object&A&D::•() + ; + abstract member-signature method method(covariant core::num* i, {core::String* s = #C1}) → core::String*; -> self::_E1&Object&A&D::method +} +abstract class _E2&Object&A extends core::Object implements mai::A /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/ { + const synthetic constructor •() → self::_E2&Object&A* + : super core::Object::•() + ; + abstract member-signature get _identityHashCode() → core::int*; -> core::Object::_identityHashCode + abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*; -> core::Object::_instanceOf + abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOf + abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfTrue + abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfFalse + abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::== + abstract member-signature get hashCode() → core::int*; -> core::Object::hashCode + abstract member-signature method toString() → core::String*; -> core::Object::toString + abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod + abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType + method /*isNonNullableByDefault, from org-dartlang-testcase:///main_lib.dart */ method(core::num i, {core::String s = #C1}) → core::String + return s; +} +class E2 extends self::_E2&Object&A implements mai::D /*isEliminatedMixin,hasConstConstructor*/ { + const synthetic constructor •() → self::E2* + : super self::_E2&Object&A::•() + ; + abstract forwarding-stub method method(covariant core::num* i, {core::String* s = #C1}) → core::String*; +} +abstract class C6 extends mai::C3 implements mai::C4 { + synthetic constructor •() → self::C6* + : super mai::C3::•() + ; + abstract forwarding-stub method method2([covariant core::String* a = #C2]) → dynamic; + abstract member-signature get _identityHashCode() → core::int*; -> core::Object::_identityHashCode + abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*; -> core::Object::_instanceOf + abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOf + abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfTrue + abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfFalse + abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::== + abstract member-signature get hashCode() → core::int*; -> core::Object::hashCode + abstract member-signature method toString() → core::String*; -> core::Object::toString + abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod + abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType +} +abstract class C8 extends mai::C5 implements mai::C7 { + synthetic constructor •() → self::C8* + : super mai::C5::•() + ; + abstract forwarding-stub method method2([covariant core::String* a = #C2, core::num* b = #C2]) → dynamic; + abstract member-signature get _identityHashCode() → core::int*; -> core::Object::_identityHashCode + abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*; -> core::Object::_instanceOf + abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOf + abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfTrue + abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfFalse + abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::== + abstract member-signature get hashCode() → core::int*; -> core::Object::hashCode + abstract member-signature method toString() → core::String*; -> core::Object::toString + abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod + abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType +} +static method main() → dynamic {} + +library /*isNonNullableByDefault*/; +import self as mai; +import "dart:core" as core; + +abstract class Interface extends core::Object { + synthetic constructor •() → mai::Interface + : super core::Object::•() + ; + abstract method method(core::num i) → core::String; +} +abstract class Interface2 extends core::Object { + synthetic constructor •() → mai::Interface2 + : super core::Object::•() + ; + abstract method method(covariant core::int i) → core::String; +} +abstract class A extends core::Object implements mai::Interface /*isMixinDeclaration*/ { + method method(core::num i, {core::String s = #C1}) → core::String + return s; +} +abstract class D extends core::Object implements mai::Interface, mai::Interface2 { + synthetic constructor •() → mai::D + : super core::Object::•() + ; + abstract forwarding-stub method method(covariant core::num i) → core::String; +} +abstract class C1 extends core::Object { + synthetic constructor •() → mai::C1 + : super core::Object::•() + ; + abstract method method2() → dynamic; +} +abstract class C2 extends core::Object { + synthetic constructor •() → mai::C2 + : super core::Object::•() + ; + abstract method method2([core::String a = #C2]) → dynamic; +} +abstract class C3 extends core::Object implements mai::C1, mai::C2 { + synthetic constructor •() → mai::C3 + : super core::Object::•() + ; + abstract member-signature method method2([core::String a = #C2]) → dynamic; -> mai::C2::method2 +} +abstract class C4 extends core::Object { + synthetic constructor •() → mai::C4 + : super core::Object::•() + ; + abstract method method2([covariant core::String a = #C2]) → dynamic; +} +abstract class C5 extends mai::C3 implements mai::C4 { + synthetic constructor •() → mai::C5 + : super mai::C3::•() + ; + abstract forwarding-stub method method2([covariant core::String a = #C2]) → dynamic; +} +abstract class C7 extends core::Object { + synthetic constructor •() → mai::C7 + : super core::Object::•() + ; + abstract method method2([core::String a = #C2, core::num b = #C2]) → dynamic; +} + +constants { + #C1 = "hello" + #C2 = null +} diff --git a/pkg/front_end/testcases/nnbd_mixed/issue43988/main_lib.dart b/pkg/front_end/testcases/nnbd_mixed/issue43988/main_lib.dart new file mode 100644 index 000000000000..52914147048c --- /dev/null +++ b/pkg/front_end/testcases/nnbd_mixed/issue43988/main_lib.dart @@ -0,0 +1,37 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// 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. + +abstract class Interface { + String method(num i); +} + +abstract class Interface2 { + String method(covariant int i); +} + +mixin A implements Interface { + String method(num i, {String s = "hello"}) => s; +} + +abstract class D implements Interface, Interface2 {} + +abstract class C1 { + method2(); +} + +abstract class C2 { + method2([String a]); +} + +abstract class C3 implements C1, C2 {} + +abstract class C4 { + method2([covariant String a]); +} + +abstract class C5 extends C3 implements C4 {} + +abstract class C7 { + method2([String a, num b]); +} diff --git a/pkg/front_end/testcases/nnbd_mixed/issue43988/test.options b/pkg/front_end/testcases/nnbd_mixed/issue43988/test.options new file mode 100644 index 000000000000..bfe6dc8532c2 --- /dev/null +++ b/pkg/front_end/testcases/nnbd_mixed/issue43988/test.options @@ -0,0 +1 @@ +main_lib.dart \ No newline at end of file diff --git a/pkg/kernel/lib/class_hierarchy.dart b/pkg/kernel/lib/class_hierarchy.dart index 9f92ab0126ab..710baf7ec818 100644 --- a/pkg/kernel/lib/class_hierarchy.dart +++ b/pkg/kernel/lib/class_hierarchy.dart @@ -765,7 +765,12 @@ class ClosedWorldClassHierarchy implements ClassHierarchy { Member getDispatchTarget(Class class_, Name name, {bool setter: false}) { List list = _buildImplementedMembers(class_, infoFor(class_), setters: setter); - return ClassHierarchy.findMemberByName(list, name); + Member member = ClassHierarchy.findMemberByName(list, name); + assert( + member == null || !member.isAbstract, + "Abstract member $member found as dispatch target " + "for $name on $class_"); + return member; } @override