blob: 9ab680d697b27da1a263ffe573506f4835085b4d [file] [log] [blame]
// 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 b
// BSD-style license that can be found in the LICENSE file.
void main() {
checkClass();
checkExtensionType();
}
class AssertIdentical {
// The "message" of the assert is not a valid constant string expression,
// but it is only evaluated if the assertion fails,
// and the CFE helpfully prints a string representation of the value
// that can't be converted to a string by the potentially constant expression.
const AssertIdentical(Object? v1, Object? v2)
: assert(identical(v1, v2), "${(v1, v2)}");
const AssertIdentical.not(Object? v1, Object? v2)
: assert(!identical(v1, v2), "${(v1, v2)}");
}
class C<T> {
final T value;
C(this.value);
C.named(this.value);
C.redirect(T value) : this.named(value);
factory C.factory(T value) => C<T>(value);
factory C.factoryRedirect(T value) = C<T>;
}
// Non-generic (always instantiated) alias.
typedef ACI = C<int>;
// Renaming generic alias.
typedef ACR<T> = C<T>;
// Non-renaming generic alias.
typedef ACN<T extends num> = C<T>;
void checkClass() {
// Generic class constructor tear-offs are constant and canonicalized if:
// * Uninstantiated.
// * Instantiated with constant type.
const AssertIdentical(C.new, C.new);
const AssertIdentical(C.named, C.named);
const AssertIdentical(C.redirect, C.redirect);
const AssertIdentical(C.factory, C.factory);
const AssertIdentical(C.factoryRedirect, C.factoryRedirect);
const AssertIdentical(C<int>.new, C<int>.new);
const AssertIdentical(C<int>.named, C<int>.named);
const AssertIdentical(C<int>.redirect, C<int>.redirect);
const AssertIdentical(C<int>.factory, C<int>.factory);
const AssertIdentical(C<int>.factoryRedirect, C<int>.factoryRedirect);
// Generic class constructor tear-off through a non-generic or
// instantiated alias is canonicalized to same constructor
// as tear-off from the alias-expanded type.
const AssertIdentical(ACI.new, C<int>.new);
const AssertIdentical(ACI.named, C<int>.named);
const AssertIdentical(ACI.redirect, C<int>.redirect);
const AssertIdentical(ACI.factory, C<int>.factory);
const AssertIdentical(ACI.factoryRedirect, C<int>.factoryRedirect);
const AssertIdentical(ACR<int>.new, C<int>.new);
const AssertIdentical(ACR<int>.named, C<int>.named);
const AssertIdentical(ACR<int>.redirect, C<int>.redirect);
const AssertIdentical(ACR<int>.factory, C<int>.factory);
const AssertIdentical(ACR<int>.factoryRedirect, C<int>.factoryRedirect);
const AssertIdentical(ACN<int>.new, C<int>.new);
const AssertIdentical(ACN<int>.named, C<int>.named);
const AssertIdentical(ACN<int>.redirect, C<int>.redirect);
const AssertIdentical(ACN<int>.factory, C<int>.factory);
const AssertIdentical(ACN<int>.factoryRedirect, C<int>.factoryRedirect);
// Generic class constructor tear-off through uninstantiated
// alias is canonicalized to same constructor as tear-off from
// the uninitialized aliased class *if and only if* the alias is
// a "proper rename" for that class declaration:
// same type parameters, same order, same bounds, forwarded directly.
const AssertIdentical(ACR.new, C.new);
const AssertIdentical(ACR.named, C.named);
const AssertIdentical(ACR.redirect, C.redirect);
const AssertIdentical(ACR.factory, C.factory);
const AssertIdentical(ACR.factoryRedirect, C.factoryRedirect);
const AssertIdentical.not(ACN.new, C.new);
const AssertIdentical.not(ACN.named, C.named);
const AssertIdentical.not(ACN.redirect, C.redirect);
const AssertIdentical.not(ACN.factory, C.factory);
const AssertIdentical.not(ACN.factoryRedirect, C.factoryRedirect);
}
extension type E<T>(T value) {
E.named(this.value);
E.redirect(T value) : this.named(value);
factory E.factory(T value) => E<T>(value);
factory E.factoryRedirect(T value) = E<T>;
}
// Non-generic (always instantiated) alias.
typedef AEI = E<int>;
// Renaming generic alias.
typedef AER<T> = E<T>;
// Non-renaming generic alias.
typedef AEN<T extends num> = E<T>;
void checkExtensionType() {
// Extension type constructor-tear-offs should work the same as classes.
// Generic extension type tear-offs are constant and canonicalized if:
// * Uninstantiated.
// * Instantiated with constant type.
const AssertIdentical(E.new, E.new);
const AssertIdentical(E.named, E.named);
const AssertIdentical(E.redirect, E.redirect);
const AssertIdentical(E.factory, E.factory);
const AssertIdentical(E.factoryRedirect, E.factoryRedirect);
const AssertIdentical(E<int>.new, E<int>.new);
const AssertIdentical(E<int>.named, E<int>.named);
const AssertIdentical(E<int>.redirect, E<int>.redirect);
const AssertIdentical(E<int>.factory, E<int>.factory);
const AssertIdentical(E<int>.factoryRedirect, E<int>.factoryRedirect);
// Generic extension-type constructor tear-off through a non-generic or
// instantiated alias is canonicalized to same constructor
// as tear-off from the alias-expanded type.
const AssertIdentical(AEI.new, E<int>.new);
const AssertIdentical(AEI.named, E<int>.named);
const AssertIdentical(AEI.redirect, E<int>.redirect);
const AssertIdentical(AEI.factory, E<int>.factory);
const AssertIdentical(AEI.factoryRedirect, E<int>.factoryRedirect);
const AssertIdentical(AER<int>.new, E<int>.new);
const AssertIdentical(AER<int>.named, E<int>.named);
const AssertIdentical(AER<int>.redirect, E<int>.redirect);
const AssertIdentical(AER<int>.factory, E<int>.factory);
const AssertIdentical(AER<int>.factoryRedirect, E<int>.factoryRedirect);
const AssertIdentical(AEN<int>.new, E<int>.new);
const AssertIdentical(AEN<int>.named, E<int>.named);
const AssertIdentical(AEN<int>.redirect, E<int>.redirect);
const AssertIdentical(AEN<int>.factory, E<int>.factory);
const AssertIdentical(AEN<int>.factoryRedirect, E<int>.factoryRedirect);
// Generic extension type constructor tear-off through uninstantiated
// alias is canonicalized to same constructor as tear-off from
// the uninitialized aliased class *if and only if* the alias is
// a "proper rename" for that extension type declaration:
// same type parameters, same order, same bounds, forwarded directly.
const AssertIdentical(AER.new, E.new); // CFE Error
const AssertIdentical(AER.named, E.named); // CFE Error
const AssertIdentical(AER.redirect, E.redirect); // CFE Error
const AssertIdentical(AER.factory, E.factory); // CFE Error
const AssertIdentical(AER.factoryRedirect, E.factoryRedirect); // CFE Error
// Added to see if the non-identical value is itself consistent. (It is.)
// Redundant if the tests above were successful.
const AssertIdentical(AER.new, AER.new);
const AssertIdentical(AER.named, AER.named);
const AssertIdentical(AER.redirect, AER.redirect);
const AssertIdentical(AER.factory, AER.factory);
const AssertIdentical(AER.factoryRedirect, AER.factoryRedirect);
const AssertIdentical.not(AEN.new, E.new);
const AssertIdentical.not(AEN.named, E.named);
const AssertIdentical.not(AEN.redirect, E.redirect);
const AssertIdentical.not(AEN.factory, E.factory);
const AssertIdentical.not(AEN.factoryRedirect, E.factoryRedirect);
}