blob: 65bcae66ce6c797b86c8b75a97240e6229f2892c [file] [log] [blame]
// 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
// ^
// [analyzer] STATIC_WARNING.INVALID_OVERRIDE_DIFFERENT_DEFAULT_VALUES_NAMED
}
// 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() {}