// 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 foo(T x) => x; R bar(R x) => x; } class CInheritGeneric implements CGeneric { 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(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(x); return tmp; } } main() {}