blob: f70127dfdd67b72d2de85297ac3a6a6b7a730ddc [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";
// Test tearing off of constructors.
// Non-generic classes.
class NGen {
final int x;
const NGen(this.x);
const NGen.named(this.x);
}
class NGenRedir {
final int x;
const NGenRedir(int x) : this._(x);
const NGenRedir.named(int x) : this._(x);
const NGenRedir._(this.x);
}
class NFac implements NFacRedir {
final int x;
factory NFac(int x) => NFac._(x);
factory NFac.named(int x) => NFac._(x);
const NFac._(this.x);
}
class NFacRedir {
const factory NFacRedir(int x) = NFac._;
const factory NFacRedir.named(int x) = NFac._;
}
// Generic classes.
class GGen<T> {
final int x;
const GGen(this.x);
const GGen.named(this.x);
}
class GGenRedir<T> {
final int x;
const GGenRedir(int x) : this._(x);
const GGenRedir.named(int x) : this._(x);
const GGenRedir._(this.x);
}
class GFac<T> implements GFacRedir<T> {
final int x;
factory GFac(int x) => GFac._(x);
factory GFac.named(int x) => GFac._(x);
const GFac._(this.x);
}
class GFacRedir<T> {
const factory GFacRedir(int x) = GFac._;
const factory GFacRedir.named(int x) = GFac._;
}
class Optional<T> {
final int x;
final int y;
const Optional([this.x = 0, this.y = 0]);
const Optional.named({this.x = 0, this.y = 0});
}
void main() {
// Static types.
NGen.new.expectStaticType<Exactly<NGen Function(int)>>();
NGen.named.expectStaticType<Exactly<NGen Function(int)>>();
NGenRedir.new.expectStaticType<Exactly<NGenRedir Function(int)>>();
NGenRedir.named.expectStaticType<Exactly<NGenRedir Function(int)>>();
NFac.new.expectStaticType<Exactly<NFac Function(int)>>();
NFac.named.expectStaticType<Exactly<NFac Function(int)>>();
NFacRedir.new.expectStaticType<Exactly<NFacRedir Function(int)>>();
NFacRedir.named.expectStaticType<Exactly<NFacRedir Function(int)>>();
GGen.new.expectStaticType<Exactly<GGen<T> Function<T>(int)>>();
GGen.named.expectStaticType<Exactly<GGen<T> Function<T>(int)>>();
GGenRedir.new.expectStaticType<Exactly<GGenRedir<T> Function<T>(int)>>();
GGenRedir.named.expectStaticType<Exactly<GGenRedir<T> Function<T>(int)>>();
GFac.new.expectStaticType<Exactly<GFac<T> Function<T>(int)>>();
GFac.named.expectStaticType<Exactly<GFac<T> Function<T>(int)>>();
GFacRedir.new.expectStaticType<Exactly<GFacRedir<T> Function<T>(int)>>();
GFacRedir.named.expectStaticType<Exactly<GFacRedir<T> Function<T>(int)>>();
GGen<int>.new.expectStaticType<Exactly<GGen<int> Function(int)>>();
GGen<int>.named.expectStaticType<Exactly<GGen<int> Function(int)>>();
GGenRedir<int>.new
.expectStaticType<Exactly<GGenRedir<int> Function(int)>>();
GGenRedir<int>.named
.expectStaticType<Exactly<GGenRedir<int> Function(int)>>();
GFac<int>.new.expectStaticType<Exactly<GFac<int> Function(int)>>();
GFac<int>.named.expectStaticType<Exactly<GFac<int> Function(int)>>();
GFacRedir<int>.new
.expectStaticType<Exactly<GFacRedir<int> Function(int)>>();
GFacRedir<int>.named
.expectStaticType<Exactly<GFacRedir<int> Function(int)>>();
context<GGen<int> Function(int)>(
GGen.new..expectStaticType<Exactly<GGen<int> Function(int)>>());
context<GGen<int> Function(int)>(
GGen.named..expectStaticType<Exactly<GGen<int> Function(int)>>());
context<GGenRedir<int> Function(int)>(GGenRedir.new
..expectStaticType<Exactly<GGenRedir<int> Function(int)>>());
context<GGenRedir<int> Function(int)>(GGenRedir.named
..expectStaticType<Exactly<GGenRedir<int> Function(int)>>());
context<GFac<int> Function(int)>(
GFac.new..expectStaticType<Exactly<GFac<int> Function(int)>>());
context<GFac<int> Function(int)>(
GFac.named..expectStaticType<Exactly<GFac<int> Function(int)>>());
context<GFacRedir<int> Function(int)>(
GFacRedir.new..expectStaticType<Exactly<GFacRedir<int> Function(int)>>());
context<GFacRedir<int> Function(int)>(GFacRedir.named
..expectStaticType<Exactly<GFacRedir<int> Function(int)>>());
context<Optional<int> Function()>(Optional.new
..expectStaticType<Exactly<Optional<int> Function([int, int])>>());
context<Optional<int> Function()>(Optional.named
..expectStaticType<Exactly<Optional<int> Function({int x, int y})>>());
// Check that tear-offs are canonicalized where possible
// (where not instantiates with a non-constant type).
void test<T>(Object? f1, [Object? same, Object? notSame]) {
Expect.type<T>(f1);
if (same != null) Expect.identical(f1, same);
if (notSame != null) Expect.notEquals(f1, notSame);
}
test<NGen Function(int)>(NGen.new, NGen.new, NGen.named);
test<NGen Function(int)>(NGen.named, NGen.named);
test<NGenRedir Function(int)>(NGenRedir.new, NGenRedir.new, NGenRedir.named);
test<NGenRedir Function(int)>(NGenRedir.named, NGenRedir.named);
test<NFac Function(int)>(NFac.new, NFac.new, NFac.named);
test<NFac Function(int)>(NFac.named, NFac.named);
test<NFacRedir Function(int)>(NFacRedir.new, NFacRedir.new, NFacRedir.named);
test<NFacRedir Function(int)>(NFacRedir.named, NFacRedir.named);
// Generic class constructors torn off as generic functions.
test<GGen<T> Function<T>(int)>(GGen.new, GGen.new, GGen.named);
test<GGen<T> Function<T>(int)>(GGen.named, GGen.named);
test<GGenRedir<T> Function<T>(int)>(
GGenRedir.new, GGenRedir.new, GGenRedir.named);
test<GGenRedir<T> Function<T>(int)>(GGenRedir.named, GGenRedir.named);
test<GFac<T> Function<T>(int)>(GFac.new, GFac.new, GFac.named);
test<GFac<T> Function<T>(int)>(GFac.named, GFac.named);
test<GFacRedir<T> Function<T>(int)>(
GFacRedir.new, GFacRedir.new, GFacRedir.named);
test<GFacRedir<T> Function<T>(int)>(GFacRedir.named, GFacRedir.named);
// Generic class constructors torn off with explicit instantiation
// to constant type.
test<GGen<int> Function(int)>(
GGen<int>.new, GGen<int>.new, GGen<int>.named);
test<GGen<int> Function(int)>(GGen<int>.named, GGen<int>.named);
test<GGenRedir<int> Function(int)>(
GGenRedir<int>.new, GGenRedir<int>.new, GGenRedir<int>.named);
test<GGenRedir<int> Function(int)>(
GGenRedir<int>.named, GGenRedir<int>.named);
test<GFac<int> Function(int)>(
GFac<int>.new, GFac<int>.new, GFac<int>.named);
test<GFac<int> Function(int)>(GFac<int>.named, GFac<int>.named);
test<GFacRedir<int> Function(int)>(
GFacRedir<int>.new, GFacRedir<int>.new, GFacRedir<int>.named);
test<GFacRedir<int> Function(int)>(
GFacRedir<int>.named, GFacRedir<int>.named);
// Not equal if *different* instantiations.
Expect.notEquals(GGen<int>.new, GGen<num>.new);
Expect.notEquals(GGen<int>.named, GGen<num>.named);
Expect.notEquals(GGenRedir<int>.new, GGenRedir<num>.new);
Expect.notEquals(GGenRedir<int>.named, GGenRedir<num>.named);
Expect.notEquals(GFac<int>.new, GFac<num>.new);
Expect.notEquals(GFac<int>.named, GFac<num>.named);
Expect.notEquals(GFacRedir<int>.new, GFacRedir<num>.new);
Expect.notEquals(GFacRedir<int>.named, GFacRedir<num>.named);
// Tear off with implicit instantiation to the same constant type.
void testImplicit<T>(T f1, T f2) {
Expect.identical(f1, f2);
}
testImplicit<GGen<int> Function(int)>(GGen.new, GGen.new);
testImplicit<GGen<int> Function(int)>(GGen.named, GGen.named);
testImplicit<GGenRedir<int> Function(int)>(GGenRedir.new, GGenRedir.new);
testImplicit<GGenRedir<int> Function(int)>(GGenRedir.named, GGenRedir.named);
testImplicit<GFac<int> Function(int)>(GFac.new, GFac.new);
testImplicit<GFac<int> Function(int)>(GFac.named, GFac.named);
testImplicit<GFacRedir<int> Function(int)>(GFacRedir.new, GFacRedir.new);
testImplicit<GFacRedir<int> Function(int)>(GFacRedir.named, GFacRedir.named);
// Using a type variable, not a constant type expression.
// Canonicalization is unspecified, but equality holds.
(<T>() {
// Tear off with explicit instantation to the same non-constant type.
Expect.equals(GGen<T>.new, GGen<T>.new);
Expect.equals(GGen<T>.named, GGen<T>.named);
Expect.equals(GGenRedir<T>.new, GGenRedir<T>.new);
Expect.equals(GGenRedir<T>.named, GGenRedir<T>.named);
Expect.equals(GFac<T>.new, GFac<T>.new);
Expect.equals(GFac<T>.named, GFac<T>.named);
Expect.equals(GFacRedir<T>.new, GFacRedir<T>.new);
Expect.equals(GFacRedir<T>.named, GFacRedir<T>.named);
// Tear off with implicit instantiation to the same non-constant type.
void testImplicit2<T>(T f1, T f2) {
Expect.equals(f1, f2);
}
testImplicit2<GGen<T> Function(int)>(GGen.new, GGen.new);
testImplicit2<GGen<T> Function(int)>(GGen.named, GGen.named);
testImplicit2<GGenRedir<T> Function(int)>(GGenRedir.new, GGenRedir.new);
testImplicit2<GGenRedir<T> Function(int)>(GGenRedir.named, GGenRedir.named);
testImplicit2<GFac<T> Function(int)>(GFac.new, GFac.new);
testImplicit2<GFac<T> Function(int)>(GFac.named, GFac.named);
testImplicit2<GFacRedir<T> Function(int)>(GFacRedir.new, GFacRedir.new);
testImplicit2<GFacRedir<T> Function(int)>(GFacRedir.named, GFacRedir.named);
}<int>());
}