Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#3054. Add generic method instantiation tests #3062

Merged
merged 3 commits into from
Feb 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 sgrekhov22@gmail.com

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 sgrekhov22@gmail.com

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 sgrekhov22@gmail.com

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 sgrekhov22@gmail.com

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 sgrekhov22@gmail.com

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 sgrekhov22@gmail.com

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 sgrekhov22@gmail.com

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 sgrekhov22@gmail.com

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 sgrekhov22@gmail.com

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();
}