mirror of
https://github.com/dart-lang/sdk
synced 2024-09-15 23:49:47 +00:00
e5d5a0f345
https://github.com/dart-lang/language/pull/1389/files#diff-2f9dda5244b707ca3b6d5988c6e5257d6025a99a5fa08ce0dc171c94bdc8ce0dR665 Change-Id: Iccc90f8f9bb877da604d5a5774a931b71a185b91 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/178928 Reviewed-by: Samuel Rawlins <srawlins@google.com> Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
247 lines
6.1 KiB
Dart
247 lines
6.1 KiB
Dart
// Copyright (c) 2020, 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.
|
|
|
|
// ignore_for_file: unused_local_variable
|
|
|
|
// Static tests for inheriting types on overriding members.
|
|
|
|
// If a member `m` omits any parameter type, or the return type, and
|
|
// one or more of the immediate superinterfaces have a member named
|
|
// `m`: Find the combined member signature `s` for `m` in the immediate
|
|
// superinterfaces. A compile-time error occurs if it does not exist.
|
|
// Otherwise, each missing type annotation of a parameter is obtained
|
|
// from the corresponding parameter in `s`, and the return type, if
|
|
// missing, is obtained from `s`. If there is no corresponding
|
|
// parameter in `s`, the inferred type annotation is `dynamic`.
|
|
//
|
|
// Only types are inherited. Other modifiers and annotations are not.
|
|
// This includes `final`, `required` and any annotations
|
|
// or default values.
|
|
// (The `covariant` keyword is not inherited, but its semantics
|
|
// are so it's impossible to tell the difference).
|
|
//
|
|
// For getters and setters, if both are present, subclasses inherit the type of
|
|
// the corresponding superclass member.
|
|
// If the superclass has only a setter or a getter, subclasses inherit that type
|
|
// for both getters and setters.
|
|
|
|
// Incompatible `foo` signatures.
|
|
abstract class IIntInt {
|
|
int foo(int x);
|
|
}
|
|
|
|
abstract class IIntDouble {
|
|
double foo(int x);
|
|
}
|
|
|
|
abstract class IDoubleInt {
|
|
int foo(double x);
|
|
}
|
|
|
|
abstract class IDoubleDouble {
|
|
double foo(double x);
|
|
}
|
|
|
|
// If the superinterfaces do not have a most specific member signature,
|
|
// then omitting any parameter or return type is an error.
|
|
|
|
abstract class CInvalid1 implements IIntInt, IIntDouble {
|
|
/*indent*/ foo(x);
|
|
// ^^^
|
|
// [analyzer] unspecified
|
|
// [cfe] unspecified
|
|
}
|
|
|
|
abstract class CInvalid2 implements IIntInt, IDoubleInt {
|
|
/*indent*/ foo(x);
|
|
// ^^^
|
|
// [analyzer] unspecified
|
|
// [cfe] unspecified
|
|
}
|
|
|
|
abstract class CInvalid3 implements IIntInt, IDoubleDouble {
|
|
/*indent*/ foo(x);
|
|
// ^^^
|
|
// [analyzer] unspecified
|
|
// [cfe] unspecified
|
|
}
|
|
|
|
// Even if the conflicting super-parameter/return type is given a type.
|
|
abstract class CInvalid4 implements IIntInt, IIntDouble {
|
|
Never foo(x);
|
|
// ^^^
|
|
// [analyzer] unspecified
|
|
// [cfe] unspecified
|
|
}
|
|
|
|
abstract class CInvalid5 implements IIntInt, IDoubleInt {
|
|
/*indent*/ foo(num x);
|
|
// ^^^
|
|
// [analyzer] unspecified
|
|
// [cfe] unspecified
|
|
}
|
|
|
|
// Even if the omitted parameter doesn't exist in the super-interfaces.
|
|
abstract class CInvalid6 implements IIntInt, IDoubleInt {
|
|
Never foo(num x, [y]);
|
|
// ^^^
|
|
// [analyzer] unspecified
|
|
// [cfe] unspecified
|
|
}
|
|
|
|
// And even if there is no real conflict.
|
|
abstract class IOptx {
|
|
int foo({int x});
|
|
}
|
|
|
|
abstract class IOpty {
|
|
int foo({int y});
|
|
}
|
|
|
|
abstract class CInvalid7 implements IOptx, IOpty {
|
|
/*indent*/ foo({int x, int y});
|
|
// ^^^
|
|
// [analyzer] unspecified
|
|
// [cfe] unspecified
|
|
}
|
|
|
|
// The type of unconstrained omitted types is `dynamic`.
|
|
class CInherit1 implements IOptx {
|
|
foo({x = 0, y = 0}) {
|
|
// Type of `y` is `dynamic`.
|
|
Object? tmp;
|
|
y = tmp; // Top type.
|
|
Null tmp2 = y; // And implicit downcast.
|
|
y.arglebargle(); // And unsound member invocations.
|
|
|
|
// x is exactly int.
|
|
// Assignable to int and usable as int.
|
|
int intVar = x;
|
|
x = x.toRadixString(16).length;
|
|
// And not dynamic.
|
|
/*indent*/ x.arglebargle();
|
|
// ^^^^^^^^^^^
|
|
// [analyzer] unspecified
|
|
// [cfe] unspecified
|
|
|
|
// Return type is exactly int.
|
|
if (x == 0) {
|
|
num tmp3 = x;
|
|
return tmp3; // Does not allow returning a supertype of int.
|
|
// ^^^^
|
|
// [analyzer] unspecified
|
|
// [cfe] unspecified
|
|
}
|
|
// Allows returning int.
|
|
return intVar;
|
|
}
|
|
|
|
// No supertype signature, infer `dynamic` for every type.
|
|
bar(x) {
|
|
// x is Object?.
|
|
Object? tmp;
|
|
x = tmp; // A top type since Object? is assignable to it.
|
|
Null tmp2 = x; // Implicit downcast.
|
|
x.arglebargle(); // Unsafe invocations.
|
|
|
|
// Return type is `dynamic` when calling `bar`.
|
|
var ret = bar(x);
|
|
ret = tmp;
|
|
tmp2 = ret;
|
|
ret.arglebargle();
|
|
|
|
// And definitely a top type when returning.
|
|
return tmp;
|
|
}
|
|
}
|
|
|
|
/// Do not inherit `required`.
|
|
class IReq {
|
|
void foo({required int x}) {}
|
|
}
|
|
|
|
class CInvalid8 implements IReq {
|
|
// Do not inherit `required` if there is a type.
|
|
foo({num x}) {}
|
|
// ^
|
|
// [analyzer] COMPILE_TIME_ERROR.MISSING_DEFAULT_VALUE_FOR_PARAMETER
|
|
// [cfe] unspecified
|
|
}
|
|
|
|
class CInvalid9 implements IReq {
|
|
// Do not inherit `required` if there is no type.
|
|
void foo({x}) {}
|
|
// ^
|
|
// [analyzer] COMPILE_TIME_ERROR.MISSING_DEFAULT_VALUE_FOR_PARAMETER
|
|
// [cfe] unspecified
|
|
}
|
|
|
|
abstract class INonNullable {
|
|
foo({num x});
|
|
}
|
|
|
|
class CInvalid10 implements INonNullable {
|
|
// Inherit type even when it would be invalid in the supertype, if it had been
|
|
// non-abstract.
|
|
foo({x}) {}
|
|
// ^
|
|
// [analyzer] COMPILE_TIME_ERROR.MISSING_DEFAULT_VALUE_FOR_PARAMETER
|
|
// [cfe] unspecified
|
|
}
|
|
|
|
/// Do not inherit default value implicitly.
|
|
class IDefault {
|
|
int foo({int x = 0}) => x;
|
|
}
|
|
|
|
class CInvalid11 implements IDefault {
|
|
foo({x}) => x;
|
|
// ^
|
|
// [analyzer] COMPILE_TIME_ERROR.MISSING_DEFAULT_VALUE_FOR_PARAMETER
|
|
// [cfe] unspecified
|
|
}
|
|
|
|
// Inherits type variables, even with different names.
|
|
class CGeneric<T> {
|
|
T foo(T x) => x;
|
|
|
|
R bar<R>(R x) => x;
|
|
}
|
|
|
|
class CInheritGeneric<S> implements CGeneric<S> {
|
|
foo(x) {
|
|
// x has type exactly S.
|
|
// Assignable both ways.
|
|
S tmp = x;
|
|
x = tmp;
|
|
// And not dynamic.
|
|
/*indent*/ x.arglebargle();
|
|
// ^^^^^^^^^^^
|
|
// [analyzer] unspecified
|
|
// [cfe] unspecified
|
|
|
|
// Return type is S.
|
|
tmp = foo(x);
|
|
return tmp;
|
|
}
|
|
|
|
bar<Q>(x) {
|
|
// x has type exactly Q.
|
|
// Assignable both ways.
|
|
Q tmp = x;
|
|
x = tmp;
|
|
// And not dynamic.
|
|
/*indent*/ x.arglebargle();
|
|
// ^^^^^^^^^^^
|
|
// [analyzer] unspecified
|
|
// [cfe] unspecified
|
|
|
|
// Return type is Q.
|
|
tmp = bar<Q>(x);
|
|
return tmp;
|
|
}
|
|
}
|
|
|
|
main() {}
|