-
Notifications
You must be signed in to change notification settings - Fork 26.3k
Optimizations and fixes for @let declarations #60512
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
vars: 2, | ||
template: function MyApp_Template(rf, ctx) { | ||
if (rf & 1) { | ||
$r3$.ɵɵtext(0); | ||
$r3$.ɵɵdeclareLet(1)(2)(3)(4); | ||
$r3$.ɵɵtext(5); | ||
$r3$.ɵɵtext(1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note to self: we should also chain text
instructions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would we have cases where 2 text nodes are side-by-side?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the only case would be something like this where they were before/after a @let
that was optimized away.
3396a35
to
9eefeb9
Compare
function hasPipe(root: ir.StoreLetExpr): boolean { | ||
let result = false; | ||
|
||
ir.transformExpressionsInExpression( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(no action required) kind of odd that there's know way to walk this thing without "transforming" it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, but I think it's been like that since we switched to the pipeline.
target = updateOp.target; | ||
} else if ( | ||
// Some expressions may consume slots as well (e.g. `storeLet`). | ||
updateOp.kind === ir.OpKind.Statement || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This assumes an op can only have one slotful expression, is that true?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In theory it could, it practice it can't since the only case right now is storeLet
of which there can only be one per op. That being said, I've updated it to account for multiple so we don't get some subtle breakages if we introduce more expressions like that.
…the same view We have some code that avoids `storeLet` calls for declarations only used in the same view, however we didn't previously remove the corresponding `declareLet` calls, because of the following case: ``` @let foo = something$ | async; <!-- First in the template --> {{foo}} ``` Here we need a `TNode` (created by `declareLet`) in order for DI to work correctly. Since this is only required when using pipes, we can optimize away expressions that do not have pipes.
The compiler wasn't handling `@let` declarations placed inside i18n blocks. The problem is that `assignI18nSlotDependencies` phase assigns the `target` of i18n ops much earlier than the `@let` optimization. If the `@let` ends up getting optimized because it isn't used in any child views, the pointer in the i18n instruction becomes invalid. This hadn't surfaced so far, because we didn't optimize `declareLet` ops, however once we do, we start hitting assertions that the optimized `declareLet` isn't used anywhere. These changes resolve the issue by moving the i18n phases after the `@let` optimization.
This PR was merged into the repository by commit 8f2874e. The changes were merged into the following branches: main, 20.0.x |
…the same view (#60512) We have some code that avoids `storeLet` calls for declarations only used in the same view, however we didn't previously remove the corresponding `declareLet` calls, because of the following case: ``` @let foo = something$ | async; <!-- First in the template --> {{foo}} ``` Here we need a `TNode` (created by `declareLet`) in order for DI to work correctly. Since this is only required when using pipes, we can optimize away expressions that do not have pipes. PR Close #60512
) The compiler wasn't handling `@let` declarations placed inside i18n blocks. The problem is that `assignI18nSlotDependencies` phase assigns the `target` of i18n ops much earlier than the `@let` optimization. If the `@let` ends up getting optimized because it isn't used in any child views, the pointer in the i18n instruction becomes invalid. This hadn't surfaced so far, because we didn't optimize `declareLet` ops, however once we do, we start hitting assertions that the optimized `declareLet` isn't used anywhere. These changes resolve the issue by moving the i18n phases after the `@let` optimization. PR Close #60512
) The compiler wasn't handling `@let` declarations placed inside i18n blocks. The problem is that `assignI18nSlotDependencies` phase assigns the `target` of i18n ops much earlier than the `@let` optimization. If the `@let` ends up getting optimized because it isn't used in any child views, the pointer in the i18n instruction becomes invalid. This hadn't surfaced so far, because we didn't optimize `declareLet` ops, however once we do, we start hitting assertions that the optimized `declareLet` isn't used anywhere. These changes resolve the issue by moving the i18n phases after the `@let` optimization. PR Close #60512
Includes the following optimizations/fixes for how
@let
declarations are handled:perf(compiler): reduce allocations for let declarations only used in the same view
We have some code that avoids
storeLet
calls for declarations only used in the same view, however we didn't previously remove the correspondingdeclareLet
calls, because of the following case:Here we need a
TNode
(created bydeclareLet
) in order for DI to work correctly. Since this is only required when using pipes, we can optimize away expressions that do not have pipes.fix(compiler): incorrectly handling let declarations inside i18n
The compiler wasn't handling
@let
declarations placed inside i18n blocks. The problem is thatassignI18nSlotDependencies
phase assigns thetarget
of i18n ops much earlier than the@let
optimization. If the@let
ends up getting optimized because it isn't used in any child views, the pointer in the i18n instruction becomes invalid. This hadn't surfaced so far, because we didn't optimizedeclareLet
ops, however once we do, we start hitting assertions that the optimizeddeclareLet
isn't used anywhere.These changes resolve the issue by moving the i18n phases after the
@let
optimization.