Skip to content

Commit

Permalink
#2275. Add noSuchMethod tests. Part 3 (#2294)
Browse files Browse the repository at this point in the history
Add `noSuchMethod` tests. Part 3
  • Loading branch information
sgrekhov authored Oct 11, 2023
1 parent 0690b19 commit 1de898c
Show file tree
Hide file tree
Showing 15 changed files with 1,481 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// Copyright (c) 2023, 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.

/// @assertion A noSuchMethod forwarder is a concrete member of C with the
/// signature taken from the interface of C, and with the same default value for
/// each optional parameter
///
/// @description Checks that `noSuchMethod` forwarder has the correct default
/// value for each optional parameter
/// @author [email protected]
/// @issue 53656
import "../../../../Utils/expect.dart";

String log = "";

class C {
int m1(int v, [String s = "s1"]);

int m2(int v, {String s = "s2"});

dynamic noSuchMethod(Invocation inv) {
for (int i = 0; i < inv.positionalArguments.length; i++) {
log += "${inv.positionalArguments[i]};";
}
for (int i = 0; i < inv.namedArguments.length; i++) {
log += "s=${inv.namedArguments[Symbol("s")]};";
}
return 42;
}
}

mixin M {
int m1(int v, [String s = "s1"]);

int m2(int v, {String s = "s2"});

dynamic noSuchMethod(Invocation inv) {
for (int i = 0; i < inv.positionalArguments.length; i++) {
log += "${inv.positionalArguments[i]};";
}
for (int i = 0; i < inv.namedArguments.length; i++) {
log += "s=${inv.namedArguments[Symbol("s")]};";
}
return 42;
}
}

class MA = Object with M;

enum E {
e1, e2;
int m1(int v, [String s = "s1"]);

int m2(int v, {String s = "s2"});

dynamic noSuchMethod(Invocation inv) {
for (int i = 0; i < inv.positionalArguments.length; i++) {
log += "${inv.positionalArguments[i]};";
}
for (int i = 0; i < inv.namedArguments.length; i++) {
log += "s=${inv.namedArguments[Symbol("s")]};";
}
return 42;
}
}

main() {
C().m1(1);
Expect.equals("1;s1;", log);
log = "";
C().m2(2);
Expect.equals("2;s=s2;", log);
log = "";

MA().m1(1);
Expect.equals("1;s1;", log);
log = "";
MA().m2(2);
Expect.equals("2;s=s2;", log);
log = "";

E.e1.m1(1);
Expect.equals("1;s1;", log);
log = "";
E.e2.m2(2);
Expect.equals("2;s=s2;", log);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// Copyright (c) 2023, 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.

/// @assertion A noSuchMethod forwarder is a concrete member of C with the
/// signature taken from the interface of C, and with the same default value for
/// each optional parameter
///
/// @description Checks that `noSuchMethod` forwarder has the correct default
/// value for each covariant optional parameter
/// @author [email protected]
/// @issue 53656
import "../../../../Utils/expect.dart";

String log = "";

class C {
int m1(int v, [covariant String s = "s1"]);

int m2(int v, {covariant String s = "s2"});

dynamic noSuchMethod(Invocation inv) {
for (int i = 0; i < inv.positionalArguments.length; i++) {
log += "${inv.positionalArguments[i]};";
}
for (int i = 0; i < inv.namedArguments.length; i++) {
log += "s=${inv.namedArguments[Symbol("s")]};";
}
return 42;
}
}

mixin M {
int m1(int v, [covariant String s = "s1"]);

int m2(int v, {covariant String s = "s2"});

dynamic noSuchMethod(Invocation inv) {
for (int i = 0; i < inv.positionalArguments.length; i++) {
log += "${inv.positionalArguments[i]};";
}
for (int i = 0; i < inv.namedArguments.length; i++) {
log += "s=${inv.namedArguments[Symbol("s")]};";
}
return 42;
}
}

class MA = Object with M;

enum E {
e1, e2;
int m1(int v, [covariant String s = "s1"]);

int m2(int v, {covariant String s = "s2"});

dynamic noSuchMethod(Invocation inv) {
for (int i = 0; i < inv.positionalArguments.length; i++) {
log += "${inv.positionalArguments[i]};";
}
for (int i = 0; i < inv.namedArguments.length; i++) {
log += "s=${inv.namedArguments[Symbol("s")]};";
}
return 42;
}
}

main() {
C().m1(1);
Expect.equals("1;s1;", log);
log = "";
C().m2(2);
Expect.equals("2;s=s2;", log);
log = "";

MA().m1(1);
Expect.equals("1;s1;", log);
log = "";
MA().m2(2);
Expect.equals("2;s=s2;", log);
log = "";

E.e1.m1(1);
Expect.equals("1;s1;", log);
log = "";
E.e2.m2(2);
Expect.equals("2;s=s2;", log);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright (c) 2023, 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.

/// @assertion We say that a class C has a non-trivial `noSuchMethod` if C has a
/// concrete member named noSuchMethod which is distinct from the one declared
/// in the built-in class [Object]
///
/// Note that it must be a method that accepts one positional argument, in order
/// to correctly override noSuchMethod in Object. For instance, it can have
/// signature noSuchMethod(Invocation i) or
/// noSuchMethod(Object i, [String s = ”]), but not
/// noSuchMethod(Invocation i, String s). This implies that the situation where
/// noSuchMethod is invoked (explicitly or implicitly) with one actual argument
/// cannot fail for the reason that “there is no such method”, such that we
/// would enter an infinite loop trying to invoke noSuchMethod. It is possible,
/// however, to encounter a dynamic error during an invocation of noSuchMethod
/// because the actual argument fails to satisfy a type check, but that
/// situation will give rise to a dynamic type error rather than a repeated
/// attempt to invoke noSuchMethod
///
/// @description Checks that there is no `noSuchMethod` forwarder if a class
/// doesn't declare a concrete member named `noSuchMethod`
/// @author [email protected]
class C1 {
int m1();
//^^^^^^^^
// [analyzer] unspecified
// [cfe] unspecified
dynamic noSuchMethod(Invocation inv);
}

abstract class A {
int a();
dynamic noSuchMethod(Invocation inv);
}

class C2 extends A {}
// ^^
// [analyzer] unspecified
// [cfe] unspecified

main() {
print(C1);
print(C2);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// Copyright (c) 2023, 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.

/// @assertion Let C be a concrete class, let L be the library that contains the
/// declaration of C, and let m be a name. Then m is noSuchMethod forwarded in C
/// iff one of the following is true:
///
/// • Requested in program: C has a non-trivial noSuchMethod, the interface of C
/// contains a member signature S named m, and C has no concrete member named m
/// and accessible to L that correctly overrides S (that is, no member named m
/// is declared or inherited by C, or one is inherited, but it does not have the
/// required signature). In this case we also say that S is noSuchMethod
/// forwarded.
///
/// • Forced by privacy: There exists a direct or indirect superinterface D of C
/// which is declared in a library L2 different from L, the interface of D
/// contains a member signature S named m, m is a private name, and no
/// superclass of C has a concrete member named m accessible to L2 that
/// correctly overrides S. In this case we also say that S is noSuchMethod
/// forwarded.
///
/// For a concrete class C, a noSuchMethod forwarder is implicitly induced for
/// each member signature which is noSuchMethod forwarded.
///
/// @description Checks that for a concrete class, a `noSuchMethod` forwarder is
/// implicitly induced for each member signature which is `noSuchMethod`
/// forwarded. Test the case when forwarding is requested in program and `C` has
/// no concrete member named `m`. Test getters
/// @author [email protected]
import "../../../../Utils/expect.dart";

abstract mixin class A {
String get a;
}

class C1 {
String get m;
noSuchMethod(Invocation i) => "C1";
}

class C2 extends A {
dynamic noSuchMethod(Invocation i) => "C2";
}

class C3 implements A {
dynamic noSuchMethod(Invocation i) => "C3";
}

class C4 with A {
dynamic noSuchMethod(Invocation i) => "C4";
}

mixin M1 {
String get m;
noSuchMethod(Invocation i) => "M1";
}

mixin M2 on A {
dynamic noSuchMethod(Invocation i) => "M2";
}

mixin M3 implements A {
dynamic noSuchMethod(Invocation i) => "M3";
}

class MA1 = Object with M1;
class MA2 = A with M2;
class MA3 = A with M3;

enum E1 {
e1,
e2;

String get m;
noSuchMethod(Invocation i) => "E1";
}

enum E2 implements A {
e1,
e2;

dynamic noSuchMethod(Invocation i) => "E2";
}

enum E3 with A {
e1,
e2;

dynamic noSuchMethod(Invocation i) => "E3";
}

main() {
Expect.equals("C1", C1().m);
Expect.equals("C2", C2().a);
Expect.equals("C3", C3().a);
Expect.equals("C4", C4().a);
Expect.equals("M1", MA1().m);
Expect.equals("M2", MA2().a);
Expect.equals("M3", MA3().a);
Expect.equals("E1", E1.e1.m);
Expect.equals("E2", E2.e1.a);
Expect.equals("E3", E3.e1.a);
}
Loading

0 comments on commit 1de898c

Please sign in to comment.