|
| 1 | +<?php declare(strict_types = 1); |
| 2 | + |
| 3 | +namespace PHPStan\Analyser\Generator; |
| 4 | + |
| 5 | +/** |
| 6 | + * Work In Progress. |
| 7 | + * |
| 8 | + * This is next-get NodeScopeResolver. It aims to solve several problems: |
| 9 | + * |
| 10 | + * 1) Many expressions are processed multiple times. For example, resolving type |
| 11 | + * of BooleanAnd has to process left side in order to accurately get the type |
| 12 | + * of the right side. For things like MethodCall, even dynamic return type extensions |
| 13 | + * and ParametersAcceptorSelector are called multiple times. |
| 14 | + * 2) For complicated scope-changing expressions like assigns happening inside other expressions, |
| 15 | + * the current type inference is imprecise. Take $foo->doFoo($a = 1, $a); |
| 16 | + * When a rule hooks onto MethodCall and iterates over its args, the type of `$a` |
| 17 | + * in the second argument should be `int`, but currently it's often `mixed` because |
| 18 | + * the assignment in the first argument hasn't been processed yet in the context |
| 19 | + * where the rule is checking. |
| 20 | + * |
| 21 | + * This class (I will refer to it as GNSR from now on) aims to merge the tasks currently handled |
| 22 | + * by NodeScopeResolver, MutatingScope and TypeSpecifier all into one, because they are very similar |
| 23 | + * and their work should happen all at once without duplicit processing. |
| 24 | + * |
| 25 | + * This rewrite should fix 1) to improve performance and 2) to improve type inference precision. |
| 26 | + * |
| 27 | + * Architecture: |
| 28 | + * - Uses generators (with `yield`) for internal analysis code to handle recursive traversal |
| 29 | + * without deep call stacks and to explicitly manage when sub-expressions are analyzed |
| 30 | + * - Uses Fibers when calling custom extension code (rules, dynamic return type extensions, etc.) |
| 31 | + * to preserve backward compatibility |
| 32 | + * - Calls to `$scope->getType()` in custom extensions do not need to be preceded with `yield`. |
| 33 | + * Instead, if the type is not yet available, the call will transparently suspend the current |
| 34 | + * Fiber and resume once the type has been computed |
| 35 | + * - All computed types and analysis results are stored during traversal so that subsequent |
| 36 | + * lookups (from rules or other extensions) hit cached values with no duplicate work |
| 37 | + * - Synthetic/virtual expressions (e.g., a rule constructing `new MethodCall(...)` to query |
| 38 | + * a hypothetical method call) are analyzed on-demand when requested, with the Fiber |
| 39 | + * suspending until analysis completes |
| 40 | + */ |
| 41 | +final class GeneratorNodeScopeResolver |
| 42 | +{ |
| 43 | + |
| 44 | +} |
0 commit comments