blob: 60ae8b72313f353cc32be0261fcba58d2e503ceb [file] [log] [blame]
// Copyright (c) 2019, 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.
// Tests bounds checking for extension methods
extension E1<T extends num> on T {
int get e1 => 1;
}
extension E2<T extends S, S extends num> on T {
int get e2 => 2;
}
extension E3<T> on T {
S f3<S extends T>(S x) => x;
}
extension E4<T extends Rec<T>> on T {
int get e4 => 4;
}
class Rec<T extends Rec<T>> {}
class RecSolution extends Rec<RecSolution> {}
void main() {
String s = "s";
int i = 0;
double d = 1.0;
// Inferred type of String does not satisfy the bound.
s.e1;
// ^^
// [analyzer] COMPILE_TIME_ERROR.UNDEFINED_GETTER
// [cfe] The getter 'e1' isn't defined for the class 'String'.
E1(s).e1;
//^^
// [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER
// [cfe] Inferred type argument 'String' doesn't conform to the bound 'num' of the type variable 'T' on 'E1|get#e1'.
E1<String>(s).e1;
//^
// [cfe] Type argument 'String' doesn't conform to the bound 'num' of the type variable 'T' on 'E1|get#e1'.
// ^^^^^^
// [analyzer] COMPILE_TIME_ERROR.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS
// Inferred types of int and double are ok
i.e1;
E1(i).e1;
E1<int>(i).e1;
d.e1;
E1(d).e1;
E1<double>(d).e1;
// Inferred type of String does not satisfy the bound.
s.e2;
// ^^
// [analyzer] COMPILE_TIME_ERROR.UNDEFINED_GETTER
// [cfe] The getter 'e2' isn't defined for the class 'String'.
E2(s).e2;
//^^
// [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER
// [cfe] Inferred type argument 'String' doesn't conform to the bound 'S' of the type variable 'T' on 'E2|get#e2'.
E2<String, num>(s).e2;
//^
// [cfe] Type argument 'String' doesn't conform to the bound 'S' of the type variable 'T' on 'E2|get#e2'.
// ^^^^^^
// [analyzer] COMPILE_TIME_ERROR.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS
// Inferred types of int and double are ok
i.e2;
E2(i).e2;
E2<int, num>(i).e2;
d.e2;
E2(d).e2;
E2<double, num>(d).e2;
// Inferred type int for method type parameter doesn't match the inferred
// bound of String
s.f3(3);
// ^^
// [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER
// [cfe] Inferred type argument 'int' doesn't conform to the bound 'T' of the type variable 'S' on 'E3|f3'.
E3(s).f3(3);
// ^^
// [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER
// [cfe] Inferred type argument 'int' doesn't conform to the bound 'T' of the type variable 'S' on 'E3|f3'.
E3<String>(s).f3(3);
// ^^
// [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER
// [cfe] Inferred type argument 'int' doesn't conform to the bound 'T' of the type variable 'S' on 'E3|f3'.
// Inferred type int for method type parameter is ok
i.f3(3);
E3(i).f3(3);
E3<int>(i).f3(3);
// Inferred type int for method type parameter doesn't match the inferred
// bound of double
d.f3(3);
// ^^
// [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER
// [cfe] Inferred type argument 'int' doesn't conform to the bound 'T' of the type variable 'S' on 'E3|f3'.
E3(d).f3(3);
// ^^
// [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER
// [cfe] Inferred type argument 'int' doesn't conform to the bound 'T' of the type variable 'S' on 'E3|f3'.
E3<double>(d).f3(3);
// ^^
// [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER
// [cfe] Inferred type argument 'int' doesn't conform to the bound 'T' of the type variable 'S' on 'E3|f3'.
RecSolution recs = RecSolution();
Rec<dynamic> superRec = RecSolution(); // Super-bounded type.
// Inferred type of RecSolution is ok
recs.e4;
E4(recs).e4;
E4<RecSolution>(recs).e4;
// Inferred super-bounded type is invalid as type argument
superRec.e4;
// ^^
// [analyzer] COMPILE_TIME_ERROR.UNDEFINED_GETTER
// [cfe] The getter 'e4' isn't defined for the class 'Rec<dynamic>'.
E4(superRec).e4;
//^^
// [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER
// [cfe] Inferred type argument 'Rec<dynamic>' doesn't conform to the bound 'Rec<T>' of the type variable 'T' on 'E4|get#e4'.
E4<Rec<dynamic>>(superRec).e4;
//^
// [cfe] Type argument 'Rec<dynamic>' doesn't conform to the bound 'Rec<T>' of the type variable 'T' on 'E4|get#e4'.
// ^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS
}