blob: 8028216dce8f74d76d1422ce715e295fcec328b6 [file] [log] [blame]
// Copyright (c) 2021, 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.
// SharedOptions=--enable-experiment=constructor-tearoffs
import "package:expect/expect.dart";
import "../static_type_helper.dart";
// Tests that generic methods can be torn off with explicit instantiation.
R toplevel<R, T>(T value, [T? other]) => value as R;
class C {
static R staticMethod<R, T>(T value, [T? other]) => value as R;
R instanceMethod<R, T>(T value, [T? other]) => value as R;
void tearOffsOnThis() {
const staticTearOff = staticMethod<int, String>;
staticMethod<int, String>
.expectStaticType<Exactly<int Function(String, [String?])>>();
instanceMethod<int, String>
.expectStaticType<Exactly<int Function(String, [String?])>>();
this.instanceMethod<int, String>
.expectStaticType<Exactly<int Function(String, [String?])>>();
Expect.identical(staticMethod<int, String>, staticTearOff);
Expect.equals(
instanceMethod<int, String>, this.instanceMethod<int, String>);
}
}
mixin M on C {
static R staticMethod<R, T>(T value, [T? other]) => value as R;
R mixinInstanceMethod<R, T>(T value, [T? other]) => value as R;
void mixinTearOffsOnThis() {
const staticTearOff = staticMethod<int, String>;
staticMethod<int, String>
.expectStaticType<Exactly<int Function(String, [String?])>>();
mixinInstanceMethod<int, String>
.expectStaticType<Exactly<int Function(String, [String?])>>();
this.mixinInstanceMethod<int, String>
.expectStaticType<Exactly<int Function(String, [String?])>>();
Expect.identical(staticMethod<int, String>, staticTearOff);
Expect.equals(
mixinInstanceMethod<int, String>,
this.mixinInstanceMethod<int, String>);
}
}
extension E on C {
static R staticMethod<R, T>(T value, [T? other]) => value as R;
R extInstanceMethod<R, T>(T value, [T? other]) => value as R;
void extensionTearOffsOnThis() {
const staticTearOff = staticMethod<int, String>;
staticMethod<int, String>
.expectStaticType<Exactly<int Function(String, [String?])>>();
extInstanceMethod<int, String>
.expectStaticType<Exactly<int Function(String, [String?])>>();
this.extInstanceMethod<int, String>
.expectStaticType<Exactly<int Function(String, [String?])>>();
Expect.identical(staticMethod<int, String>, staticTearOff);
// Extension instance methods do not specify equality.
}
}
class D extends C with M {
void tearOffsOnSuper() {
super.instanceMethod<int, String>
.expectStaticType<Exactly<int Function(String, [String?])>>();
Expect.equals(
super.instanceMethod<int, String>, super.instanceMethod<int, String>);
}
}
void main() {
var o = D();
R local<R, T>(T value, [T? other]) => value as R;
// Check that some tear-offs are constant.
const topTearOff = toplevel<int, String>;
const staticTearOff = C.staticMethod<int, String>;
const mixinStaticTearOff = M.staticMethod<int, String>;
const extensionStaticTearOff = E.staticMethod<int, String>;
// Check that the tear-offs have the correct static type.
toplevel<int, String>
.expectStaticType<Exactly<int Function(String, [String?])>>();
C
.staticMethod<int, String>
.expectStaticType<Exactly<int Function(String, [String?])>>();
M
.staticMethod<int, String>
.expectStaticType<Exactly<int Function(String, [String?])>>();
E
.staticMethod<int, String>
.expectStaticType<Exactly<int Function(String, [String?])>>();
o
.instanceMethod<int, String>
.expectStaticType<Exactly<int Function(String, [String?])>>();
o
.mixinInstanceMethod<int, String>
.expectStaticType<Exactly<int Function(String, [String?])>>();
o
.extInstanceMethod<int, String>
.expectStaticType<Exactly<int Function(String, [String?])>>();
local<int, String>
.expectStaticType<Exactly<int Function(String, [String?])>>();
// Check that the tear-offs are canonicalized where possible.
Expect.identical(toplevel<int, String>, topTearOff);
Expect.identical(C.staticMethod<int, String>, staticTearOff);
Expect.identical(M.staticMethod<int, String>, mixinStaticTearOff);
Expect.identical(E.staticMethod<int, String>, extensionStaticTearOff);
// Instantiated local methods may or may not be equal.
// (Specification makes no promise about equality.).
// But not for instance method tear-off.
// Specification requires equality.
Expect.equals(
o.instanceMethod<int, String>, o.instanceMethod<int, String>);
Expect.equals(
o.mixinInstanceMethod<int, String>, o.mixinInstanceMethod<int, String>);
// Instantiated extension methods do not specify equality.
// And not canonicalized where they shouldn't (different types).
Expect.notEquals(toplevel<int, String>, toplevel<num, String>);
Expect.notEquals(
C.staticMethod<int, String>, C.staticMethod<num, String>);
Expect.notEquals(local<int, String>, local<num, String>);
Expect.notEquals(
o.instanceMethod<int, String>, o.instanceMethod<num, String>);
(<T>() {
// Not canonicalized if any type is non-constant.
// Toplevel, static and instance members are still equal
// if types are "the same".
// (Current implementations do not implement that).
Expect.equals(toplevel<T, String>, toplevel<T, String>);
Expect.equals(C.staticMethod<T, String>, C.staticMethod<T, String>);
Expect.equals(M.staticMethod<T, String>, M.staticMethod<T, String>);
Expect.equals(E.staticMethod<T, String>, E.staticMethod<T, String>);
Expect.equals(toplevel<int, T>, toplevel<int, T>);
Expect.equals(C.staticMethod<int, T>, C.staticMethod<int, T>);
Expect.equals(M.staticMethod<int, T>, M.staticMethod<int, T>);
Expect.equals(E.staticMethod<int, T>, E.staticMethod<int, T>);
}<int>());
o.tearOffsOnThis();
o.tearOffsOnSuper();
o.mixinTearOffsOnThis();
o.extensionTearOffsOnThis();
}