| // Copyright (c) 2022, 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. |
| |
| import 'package:_fe_analyzer_shared/src/deferred_function_literal_heuristic.dart'; |
| import 'package:test/test.dart'; |
| |
| main() { |
| test('single', () { |
| // If there is just a single function literal and no type variables, it is |
| // selected. |
| var f = Param('f'); |
| expect( |
| _TestFunctionLiteralDeps(typeVars: [], functionLiterals: [f]) |
| .planReconciliationStages(), |
| [ |
| [f] |
| ]); |
| }); |
| |
| test('simple dependency', () { |
| // If f depends on g, then g is selected first, and then f. |
| var f = Param('f', argTypes: ['T']); |
| var g = Param('g', retTypes: ['T']); |
| expect( |
| _TestFunctionLiteralDeps(typeVars: ['T'], functionLiterals: [f, g]) |
| .planReconciliationStages(), |
| [ |
| [g], |
| [f] |
| ]); |
| }); |
| |
| test('long chain', () { |
| // If f depends on g and g depends on h, then we do three separate stages: |
| // h, then g, then f. |
| var f = Param('f', argTypes: ['T']); |
| var g = Param('g', argTypes: ['U'], retTypes: ['T']); |
| var h = Param('h', retTypes: ['U']); |
| expect( |
| _TestFunctionLiteralDeps( |
| typeVars: ['T', 'U'], |
| functionLiterals: [f, g, h]).planReconciliationStages(), |
| [ |
| [h], |
| [g], |
| [f] |
| ]); |
| }); |
| |
| test('unrelated function literal', () { |
| // Function literals that are independent of all the others are inferred |
| // during the first stage. |
| var f = Param('f', argTypes: ['T']); |
| var g = Param('g', retTypes: ['T']); |
| var h = Param('h'); |
| expect( |
| _TestFunctionLiteralDeps( |
| typeVars: ['T', 'U'], |
| functionLiterals: [f, g, h]).planReconciliationStages(), |
| [ |
| [g, h], |
| [f] |
| ]); |
| }); |
| |
| test('independent chains', () { |
| // If f depends on g, and h depends on i, then g and i are selected first, |
| // and then f and h. |
| var f = Param('f', argTypes: ['T']); |
| var g = Param('g', retTypes: ['T']); |
| var h = Param('h', argTypes: ['U']); |
| var i = Param('i', retTypes: ['U']); |
| expect( |
| _TestFunctionLiteralDeps( |
| typeVars: ['T', 'U'], |
| functionLiterals: [f, g, h, i]).planReconciliationStages(), |
| [ |
| [g, i], |
| [f, h] |
| ]); |
| }); |
| |
| test('diamond', () { |
| // Test a diamond dependency shape: f depends on g and h; g and h both |
| // depend on i. |
| var f = Param('f', argTypes: ['T', 'U']); |
| var g = Param('g', argTypes: ['V'], retTypes: ['T']); |
| var h = Param('h', argTypes: ['V'], retTypes: ['U']); |
| var i = Param('i', retTypes: ['V']); |
| expect( |
| _TestFunctionLiteralDeps( |
| typeVars: ['T', 'U', 'V'], |
| functionLiterals: [f, g, h, i]).planReconciliationStages(), |
| [ |
| [i], |
| [g, h], |
| [f] |
| ]); |
| }); |
| |
| test('cycle', () { |
| // A dependency cycle is inferred all at once. |
| var f = Param('f', argTypes: ['T']); |
| var g = Param('g', argTypes: ['U']); |
| var h = Param('h', argTypes: ['U'], retTypes: ['T']); |
| var i = Param('i', argTypes: ['T'], retTypes: ['U']); |
| expect( |
| _TestFunctionLiteralDeps( |
| typeVars: ['T', 'U'], |
| functionLiterals: [f, g, h, i]).planReconciliationStages(), |
| [ |
| [h, i], |
| [f, g] |
| ]); |
| }); |
| |
| test('dependency on undeferred param', () { |
| var f = Param('f', argTypes: ['T']); |
| var x = Param('x', retTypes: ['T']); |
| expect( |
| _TestFunctionLiteralDeps( |
| typeVars: ['T'], |
| functionLiterals: [f], |
| undeferredParams: [x]).planReconciliationStages(), |
| [ |
| <Param>[], |
| [f] |
| ]); |
| }); |
| } |
| |
| class Param { |
| final String name; |
| final List<String> argTypes; |
| final List<String> retTypes; |
| |
| Param(this.name, {this.argTypes = const [], this.retTypes = const []}); |
| |
| @override |
| String toString() => name; |
| } |
| |
| class _TestFunctionLiteralDeps |
| extends FunctionLiteralDependencies<String, Param, Param> { |
| final List<String> typeVars; |
| final List<Param> functionLiterals; |
| final List<Param> undeferredParams; |
| |
| _TestFunctionLiteralDeps( |
| {required this.typeVars, |
| required this.functionLiterals, |
| this.undeferredParams = const []}) |
| : super(functionLiterals, typeVars, undeferredParams); |
| |
| @override |
| Set<String> typeVarsFreeInParamParams(Param param) => param.argTypes.toSet(); |
| |
| @override |
| Set<String> typeVarsFreeInParamReturns(Param param) => param.retTypes.toSet(); |
| } |