blob: 1875784578f7574ff56e82c641212983e9acea75 [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.
/// @assertion Instantiate to bound then computes an actual type argument list
/// for [G] as follows:
///
/// Let [Ui],[1] be [Si], for all [i] in [1 .. k]. (This is the "current value"
/// of the bound for type variable [i], at step [1]; in general we will
/// consider the current step, [m], and use data for that step, e.g., the bound
/// [Ui],[m], to compute the data for step [m + 1]).
///
/// Let [-->m] be a relation among the type variables [X1 .. Xk] such that
/// [Xp -->m Xq] iff [Xq] occurs in [Up],[m] (so each type variable is related
/// to, that is, depends on, every type variable in its bound, possibly
/// including itself). Let [==>m] be the transitive closure of [-->m]. For each
/// [m], let [Ui],[m+1], for [i] in [1 .. k], be determined by the following
/// iterative process:
///
/// 1. If there exists a [j] in [1 .. k] such that [Xj ==>m X0j] (that is, if
/// the dependency graph has a cycle) let [M1 .. Mp] be the strongly connected
/// components (SCCs) with respect to [-->m] (that is, the maximal subsets of
/// [X1 .. Xk] where every pair of variables in each subset are related in both
/// directions by [==>m]; note that the SCCs are pairwise disjoint; also, they
/// are uniquely defined up to reordering, and the order does not matter). Let
/// [M] be the union of [M1 .. Mp] (that is, all variables that participate in
/// a dependency cycle). Let [i] be in [1 .. k]. If [Xi] does not belong to [M]
/// then [Ui,m+1 = Ui,m]. Otherwise there exists a [q] such that [Xi] belongs
/// to [Mq]; [Ui,m+1] is then obtained from [Ui,m] by replacing every covariant
/// occurrence of a variable in [Mq] by [dynamic], and replacing every
/// contravariant occurrence of a variable in [Mq] by [Null].
///
/// 2. Otherwise, (if no dependency cycle exists) let [j] be the lowest number
/// such that [Xj] occurs in [Up,m] for some [p] and [Xj -/->m Xq] for all [q]
/// in [1..k] (that is, [Uj,m] is closed, that is, the current bound of [Xj]
/// does not contain any type variables; but [Xj] is being depended on by the
/// bound of some other type variable). Then, for all [i] in [1 .. k], [Ui,m+1]
/// is obtained from [Ui,m] by replacing every covariant occurrence of [Xj] by
/// [Uj,m], and replacing every contravariant occurrence of [Xj] by [Null].
///
/// 3. Otherwise, (when no dependencies exist) terminate with the result
/// [<U1,m ..., Uk,m>].
/// @description Checks that instantiation to bounds works OK for non-function
/// typedef with [typedef G<X> = Function(X)] type parameter: [typedef G<X> =
/// void Function(X); class C<X>; typedef A<X extends G<C<X>>> = C<X>].
/// @Issue 44223, 45658
/// @author iarkh@unipro.ru
import "../../../../Utils/expect.dart";
typedef G<X> = void Function(X);
class C<X> {}
typedef A<X extends G<C<X>>> = C<X>;
test(A source) {
var fsource = toF(source);
F<A<G<C<Never>>>> target1 = fsource;
F<C<G<C<Never>>>> target2 = fsource;
F<A<G<C<Null>>>> target3 = fsource;
// ^^^^^^^
// [analyzer] unspecified
// [cfe] unspecified
F<A<dynamic>> target4 = fsource;
// ^^^^^^^
// [analyzer] unspecified
// [cfe] unspecified
F<A<G<dynamic>>> target5 = fsource;
// ^^^^^^^
// [analyzer] unspecified
// [cfe] unspecified
F<A<G<C<G<dynamic>>>>> target6 = fsource;
// ^^^^^^^
// [analyzer] unspecified
// [cfe] unspecified
F<A<G<C<G<C<dynamic>>>>>> target7 = fsource;
// ^^^^^^^
// [analyzer] unspecified
// [cfe] unspecified
F<A<Never>> target8 = fsource;
// ^^^^^^^
// [analyzer] unspecified
// [cfe] unspecified
F<A<G<Never>>> target9 = fsource;
// ^^^^^^^
// [analyzer] unspecified
// [cfe] unspecified
F<A<G<C<G<Never>>>>> target10 = fsource;
// ^^^^^^^
// [analyzer] unspecified
// [cfe] unspecified
F<A<G<C<G<C<Never>>>>>> target11 = fsource;
// ^^^^^^^
// [analyzer] unspecified
// [cfe] unspecified
}
main() {
A();
//^
// [analyzer] unspecified
// [cfe] unspecified
A a = throw "Should not reach here";
}