Skip to content

Commit

Permalink
#3054. Add generic method instantiation tests (#3062)
Browse files Browse the repository at this point in the history
Add generic method instantiation tests
  • Loading branch information
sgrekhov authored Feb 4, 2025
1 parent 4762701 commit d47946b
Show file tree
Hide file tree
Showing 9 changed files with 371 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright (c) 2025, 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 `i` be a property extraction expression of the form `e?.id`,
/// `e.id`, or `super.id`, which is statically resolved to denote an instance
/// method named `id`, and let `G` be the static type of `i`. Consider the
/// situation where `G` is a function type of the form
/// `T0 Function<X1 ◁B1, ..., Xs ◁Bs>(parameters)` with `s > 0` (that is, `G` is
/// a generic function type), and the context type is a non-generic function
/// type `F`. In this situation a compile-time error occurs, except when generic
/// function type instantiation succeeds, that is:
///
/// Type inference is applied to `G` with context type `F`, and it succeeds,
/// yielding the actual type argument list `T1, ..., Ts`.
///
/// @description Check that it is a compile-time error if a generic method
/// tear-off cannot be assigned to a non-generic function.
/// @author [email protected]
class C1 {
X foo<X extends num>(X x) => x;
}

class C2<T extends num> {
X foo<X extends T>(X x) => x;
}

void main() {
C1 c1 = C1();
String Function(int) f1 = c1.foo;
// ^^^^^^
// [analyzer] unspecified
// [cfe] unspecified
int Function(num) f2 = c1.foo;
// ^^^^^^
// [analyzer] unspecified
// [cfe] unspecified

var c2 = C2<int>();
String Function(int) f3 = c2.foo;
// ^^^^^^
// [analyzer] unspecified
// [cfe] unspecified
int Function(num) f4 = c2.foo;
// ^^^^^^
// [analyzer] unspecified
// [cfe] unspecified
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright (c) 2025, 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 `i` be a property extraction expression of the form `e?.id`,
/// `e.id`, or `super.id`, which is statically resolved to denote an instance
/// method named `id`, and let `G` be the static type of `i`. Consider the
/// situation where `G` is a function type of the form
/// `T0 Function<X1 ◁B1, ..., Xs ◁Bs>(parameters)` with `s > 0` (that is, `G` is
/// a generic function type), and the context type is a non-generic function
/// type `F`. In this situation a compile-time error occurs, except when generic
/// function type instantiation succeeds, that is:
///
/// Type inference is applied to `G` with context type `F`, and it succeeds,
/// yielding the actual type argument list `T1, ..., Ts`.
///
/// @description Check that it is a run-time error if a generic method
/// tear-off cannot be assigned to a non-generic function.
/// @author [email protected]
import '../../../../Utils/expect.dart';

class C<T extends num> {
X foo<X extends T>(X x) => x;
}

void main() {
C<num> c = C<int>();
Expect.throws(() {
num Function(num) f = c.foo;
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright (c) 2025, 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 `i` be a property extraction expression of the form `e?.id`,
/// `e.id`, or `super.id`, which is statically resolved to denote an instance
/// method named `id`, and let `G` be the static type of `i`. Consider the
/// situation where `G` is a function type of the form
/// `T0 Function<X1 ◁B1, ..., Xs ◁Bs>(parameters)` with `s > 0` (that is, `G` is
/// a generic function type), and the context type is a non-generic function
/// type `F`. In this situation a compile-time error occurs, except when generic
/// function type instantiation succeeds, that is:
///
/// Type inference is applied to `G` with context type `F`, and it succeeds,
/// yielding the actual type argument list `T1, ..., Ts`.
///
/// @description Check that it is not an error if a type inference is applied to
/// `G` with context type `F`, and it succeeds
/// @author [email protected]
import '../../../../Utils/expect.dart';

class A {
X fi<X extends num>(X x) => x;
}

class B extends A {
X fi<X extends num>(X x, [List<X>? xs]) => x;
}

void main() {
A a = B();
int Function(int) f = a.fi;
Expect.equals(42, f(42));
Expect.equals(42, (f as dynamic)(42, [0]));
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright (c) 2025, 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 `i` be a property extraction expression of the form `e?.id`,
/// `e.id`, or `super.id`, which is statically resolved to denote an instance
/// method named `id`, and let `G` be the static type of `i`. Consider the
/// situation where `G` is a function type of the form
/// `T0 Function<X1 ◁B1, ..., Xs ◁Bs>(parameters)` with `s > 0` (that is, `G` is
/// a generic function type), and the context type is a non-generic function
/// type `F`.
/// ...
/// Consider the situation where generic function type instantiation succeeded.
/// Let `gmiNameid` be a fresh name which is associated with `id`, which is
/// private `if` and only if id is private.
/// ...
/// The program is then modified as follows:
/// • When `i` is `e?.id`: Replace `i` by `e?.gmiNameid<T1, ..., Ts>()`.
/// • When `i` is `e.id`: Replace `i` by `e.gmiNameid<T1, ..., Ts>()`.
/// • When `i` is `super.id`: Replace `i` by `super.gmiNameid<T1, ..., Ts>()`.
///
/// @description Check that generic method instantiation may have a form `e?.id`
/// @author [email protected]
import '../../../../Utils/expect.dart';

class C {
int v;
C(this.v);
X foo<X extends num>(X x) => x + v as X;
}

void main() {
C? c1 = 2 > 1 ? C(1) : null;
int Function(int)? f1 = c1?.foo;
Expect.equals(c1?.foo(42), f1?.call(42));

C? c2 = 1 > 2 ? C(1) : null;
double Function(double)? f2 = c2?.foo;
Expect.isNull(f2);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright (c) 2025, 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 `i` be a property extraction expression of the form `e?.id`,
/// `e.id`, or `super.id`, which is statically resolved to denote an instance
/// method named `id`, and let `G` be the static type of `i`. Consider the
/// situation where `G` is a function type of the form
/// `T0 Function<X1 ◁B1, ..., Xs ◁Bs>(parameters)` with `s > 0` (that is, `G` is
/// a generic function type), and the context type is a non-generic function
/// type `F`.
/// ...
/// Consider the situation where generic function type instantiation succeeded.
/// Let `gmiNameid` be a fresh name which is associated with `id`, which is
/// private `if` and only if id is private.
/// ...
/// The program is then modified as follows:
/// • When `i` is `e?.id`: Replace `i` by `e?.gmiNameid<T1, ..., Ts>()`.
/// • When `i` is `e.id`: Replace `i` by `e.gmiNameid<T1, ..., Ts>()`.
/// • When `i` is `super.id`: Replace `i` by `super.gmiNameid<T1, ..., Ts>()`.
///
/// @description Check that generic method instantiation may have a form `e.id`.
/// @author [email protected]
import '../../../../Utils/expect.dart';

class C<T extends num> {
int v;
C(this.v);
X foo<X extends T>(X x) => x + v as X;
}

void main() {
C c1 = C(1);
int Function(int) f1 = c1.foo;
Expect.equals(c1.foo(42), f1(42));
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright (c) 2025, 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 `i` be a property extraction expression of the form `e?.id`,
/// `e.id`, or `super.id`, which is statically resolved to denote an instance
/// method named `id`, and let `G` be the static type of `i`. Consider the
/// situation where `G` is a function type of the form
/// `T0 Function<X1 ◁B1, ..., Xs ◁Bs>(parameters)` with `s > 0` (that is, `G` is
/// a generic function type), and the context type is a non-generic function
/// type `F`.
/// ...
/// Consider the situation where generic function type instantiation succeeded.
/// Let `gmiNameid` be a fresh name which is associated with `id`, which is
/// private `if` and only if id is private.
/// ...
/// The program is then modified as follows:
/// • When `i` is `e?.id`: Replace `i` by `e?.gmiNameid<T1, ..., Ts>()`.
/// • When `i` is `e.id`: Replace `i` by `e.gmiNameid<T1, ..., Ts>()`.
/// • When `i` is `super.id`: Replace `i` by `super.gmiNameid<T1, ..., Ts>()`.
///
/// @description Check that generic method instantiation may have a form
/// `super.id`.
/// @author [email protected]
import '../../../../Utils/expect.dart';

class A {
String foo<X>(X x) => "A:$X";
}

class C extends A {
int v;
C(this.v);
String foo<X>(X x) => "C:$X";

test() {
String Function(int) f1 = super.foo;
Expect.equals("A:int", f1(42));
}
}

void main() {
C(1).test();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright (c) 2025, 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 Consider the situation where generic function type instantiation
/// succeeded. Let `gmiNameid` be a fresh name which is associated with `id`,
/// which is private `if` and only if id is private.
/// ...
/// Let `o` be an instance of a class which contains an implicitly induced
/// declaration of `gmiNameid` as described above. Consider the situation where
/// the program evaluates two invocations of this method with the same receiver
/// `o`, and with actual type arguments whose actual values are the same types
/// `t1, ..., ts` for both invocations, and assume that the invocations returned
/// the instances `o1` respectively `o2`. It is then guaranteed that `o1` and
/// `o2` are equal according to operator ‘==’.
///
/// @description Check that two generic method instantiation of the same method
/// of a form `e?.id` are equal according to the `==` operator.
/// @author [email protected]
import '../../../../Utils/expect.dart';

class C1 {
int v;
C1(this.v);
X foo<X extends num>(X x) => x + v as X;
}

class C2<T extends num> {
T v;
C2(this.v);
X foo<X extends T>(X x) => x + v as X;
}

void main() {
C1? c1 = 2 > 1 ? C1(1) : null;
int Function(int)? f1 = c1?.foo;
int Function(int)? f2 = c1?.foo;
Expect.isTrue(f1 == f2);

C2<num>? c2 = 2 > 1 ? C2(2) : null;
int Function(int)? f3 = c2?.foo;
int Function(int)? f4 = c2?.foo;
Expect.isTrue(f3 == f4);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright (c) 2025, 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 Consider the situation where generic function type instantiation
/// succeeded. Let `gmiNameid` be a fresh name which is associated with `id`,
/// which is private `if` and only if id is private.
/// ...
/// Let `o` be an instance of a class which contains an implicitly induced
/// declaration of `gmiNameid` as described above. Consider the situation where
/// the program evaluates two invocations of this method with the same receiver
/// `o`, and with actual type arguments whose actual values are the same types
/// `t1, ..., ts` for both invocations, and assume that the invocations returned
/// the instances `o1` respectively `o2`. It is then guaranteed that `o1` and
/// `o2` are equal according to operator ‘==’.
///
/// @description Check that two generic method instantiation of the same method
/// of a form `e.id` are equal according to the `==` operator.
/// @author [email protected]
import '../../../../Utils/expect.dart';

class C1 {
int v;
C1(this.v);
X foo<X extends num>(X x) => x + v as X;
}

class C2<T extends num> {
T v;
C2(this.v);
X foo<X extends T>(X x) => x + v as X;
}

void main() {
var c1 = C1(1);
int Function(int) f1 = c1.foo;
int Function(int) f2 = c1.foo;
Expect.isTrue(f1 == f2);

var c2 = C2<num>(2);
int Function(int) f3 = c2.foo;
int Function(int) f4 = c2.foo;
Expect.isTrue(f3 == f4);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright (c) 2025, 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 Consider the situation where generic function type instantiation
/// succeeded. Let `gmiNameid` be a fresh name which is associated with `id`,
/// which is private `if` and only if id is private.
/// ...
/// Let `o` be an instance of a class which contains an implicitly induced
/// declaration of `gmiNameid` as described above. Consider the situation where
/// the program evaluates two invocations of this method with the same receiver
/// `o`, and with actual type arguments whose actual values are the same types
/// `t1, ..., ts` for both invocations, and assume that the invocations returned
/// the instances `o1` respectively `o2`. It is then guaranteed that `o1` and
/// `o2` are equal according to operator ‘==’.
///
/// @description Check that two generic method instantiation of the same method
/// of a form `super.id` are equal according to the `==` operator.
/// @author [email protected]
import '../../../../Utils/expect.dart';

class A {
X foo<X extends num>(X x) => x;
}

class C extends A {
int v;
C(this.v);
X foo<X extends num>(X x) => x + v as X;

void test() {
int Function(int) f1 = super.foo;
int Function(int) f2 = super.foo;
Expect.isTrue(f1 == f2);
}
}

void main() {
C(1).test();
}

0 comments on commit d47946b

Please sign in to comment.