blob: d54b522ccf24e9dec87df69f02254f6fffd16e97 [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.
/// Test that downwards inference uses the promoted type of the variable in an
/// assignment as the context, but still considers the assignment as a valid
/// promotion/demotion point.
/// A generic class to serve as the base type.
class C<S> {
S cMethod(S x) => x;
}
/// An inference context C<S> constrains the first type variable of D but not
/// the second.
class D<S, T> extends C<S> {
S dMethod1(S x) => x;
T dMethod2(T x) => x;
}
/// Generic function which if inferred in a context C<A> with argument type B,
/// should infer to mkD<A, B>
D<S, T> mkD<S, T>(T x) => D();
/// Generic function which if inferred in a context D<S0, S1> with argument type
/// D<T0, T1>, should infer to useD<T0>.
C<T> useD<T>(D<T, int> d) => d;
void main() {
{
C<String> x = C();
// Inference uses C<String> as a downwards context, constraining S from
// mkD<S,T> to String. Upwards inference constrains T to int. D<String,
// int> is not a type of interest so no promotion should happen.
{
// y has the type of the RHS of the assignment
var y = x = mkD(3);
// x still has type C<String>
x.dMethod1("hello");
//^^^^^^^^
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_METHOD
// [cfe] The method 'dMethod1' isn't defined for the class 'C<String>'.
x.dMethod2(3);
//^^^^^^^^
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_METHOD
// [cfe] The method 'dMethod2' isn't defined for the class 'C<String>'.
var t0 = x.cMethod("hello");
t0.length;
t0.arglebargle; // t0 is not dynamic
// ^^^^^^^^^^^
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
// [cfe] The getter 'arglebargle' isn't defined for the class 'String'.
// y has type D<String, int>
var t1 = y.dMethod1("hello");
t1.length;
t1.arglebargle; // t1 is not dynamic
// ^^^^^^^^^^^
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
// [cfe] The getter 'arglebargle' isn't defined for the class 'String'.
var t2 = y.dMethod2(3);
t2.isEven;
t2.arglebargle; // t2 is not dynamic
// ^^^^^^^^^^^
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
// [cfe] The getter 'arglebargle' isn't defined for the class 'int'.
}
// Establish D<String, int> as a type of interest
if (x is D<String, int>) {}
// Inference uses C<String> as a downwards context, constraining S from
// mkD<S,T> to String. Upwards inference constrains T to int. D<String,
// int> is a type of interest so promotion should happen.
{
// y has the type of the RHS of the assignment
var y = x = mkD(3);
// x has type D<String, int>
var t0 = x.dMethod1("hello");
t0.length;
t0.arglebargle; // t0 is not dynamic
// ^^^^^^^^^^^
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
// [cfe] The getter 'arglebargle' isn't defined for the class 'String'.
var t1 = x.dMethod2(3);
t1.isEven;
t1.arglebargle; // t1 is not dynamic
// ^^^^^^^^^^^
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
// [cfe] The getter 'arglebargle' isn't defined for the class 'int'.
// y has type D<String, int>
var t2 = y.dMethod1("hello");
t2.length;
t2.arglebargle; // t2 is not dynamic
// ^^^^^^^^^^^
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
// [cfe] The getter 'arglebargle' isn't defined for the class 'String'.
var t3 = y.dMethod2(3);
t3.isEven;
t3.arglebargle; // t3 is not dynamic
// ^^^^^^^^^^^
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
// [cfe] The getter 'arglebargle' isn't defined for the class 'int'.
}
// Inference should use D<String, int> as a downwards context, T from
// useD<T> to int. The variable x as an argument has type D<String, int>
// which is assignable to D<String, int> so the call should have no error.
// C<String> is a type of interest, so x should be demoted after the call.
{
// y has the type of the RHS of the assignment
var y = x = useD(x);
// x has type C<String>, and not D<String, int>
x.dMethod1("hello");
//^^^^^^^^
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_METHOD
// [cfe] The method 'dMethod1' isn't defined for the class 'C<String>'.
x.dMethod2(3);
//^^^^^^^^
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_METHOD
// [cfe] The method 'dMethod2' isn't defined for the class 'C<String>'.
var t0 = x.cMethod("hello");
t0.length;
t0.arglebargle; // t0 is not dynamic
// ^^^^^^^^^^^
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
// [cfe] The getter 'arglebargle' isn't defined for the class 'String'.
// C<String>, and not D<String, int>
y.dMethod1("hello");
//^^^^^^^^
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_METHOD
// [cfe] The method 'dMethod1' isn't defined for the class 'C<String>'.
y.dMethod2(3);
//^^^^^^^^
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_METHOD
// [cfe] The method 'dMethod2' isn't defined for the class 'C<String>'.
var t1 = y.cMethod("hello");
t1.length;
t1.arglebargle; // t0 is not dynamic
// ^^^^^^^^^^^
// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
// [cfe] The getter 'arglebargle' isn't defined for the class 'String'.
}
}
}