blob: e0a69cc418b42bb04e6f2ea36e358287a2eaa9fc [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 /// []. /// @description Checks that instantiation to bounds works OK for non-function /// typedef with [typedef G = void Function()] type parameter: [typedef G = /// void Function(); class C; typedef A>> = C]. /// @author iarkh@unipro.ru /** * @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 * []. * @description Checks that instantiation to bounds works OK for non-function * typedef with [X Function()] type parameter: [typedef G = X Function(); * class C; typedef A>> = C]. * @author iarkh@unipro.ru */ import "../../../../Utils/expect.dart"; typedef G = void Function(); class C {} typedef A>> = C; void test(A source) { var fsource = toF(source); F>>> target1 = fsource; F>>> target2 = fsource; F>>> target3 = fsource; F>>> target4 = fsource; F>>> target5 = fsource; F> target6 = fsource; // ^^^^^^^ // [analyzer] unspecified // [cfe] unspecified F>> target7 = fsource; F>>>> target8 = fsource; F>>>>> target9 = fsource; F> target10 = fsource; // ^^^^^^^ // [analyzer] unspecified // [cfe] unspecified F>> target11 = fsource; F>>>> target12 = fsource; F>>>>> target13 = fsource; } void main() { A(); A a = throw "This is OK!"; }