The template pipeline can now generate track functions, and extract them into the constant pool (or optimize them if needed). Additionally, context variables such as `$index` can be used inside track functions and for loop bodies.
PR Close#52001
Add support for `repeaterCreate` and `repeater` instructions. Correctly count decls and vars, and support primary and empty blocks.
`track` functions are not yet extracted.
PR Close#52001
In #52110 the compiler was changed to produce `if` statements when type checking `@switch` in order to avoid a bug in the TypeScript compiler. In order to avoid duplicate diagnostics, the main `@switch` expression was ignored in each of the `@case` comparisons. This appears to have caused a regression where comparing incompatible types wasn't being reported anymore.
These changes resolve the issue by wrapping the expression in parentheses which allows the compiler to report comparison diagnostics while ignoring diagnostics in the expression itself.
Fixes#52315.
PR Close#52322
Now the method `getConstructorDependencies` no longer needs to do any post analysis, and can rely on the reflection host's result to generate ctor params. This will automatically include invalid factories which fix the issue.
PR Close#52215
Currently the reflection host's `getConstructorParameters` method is not aware of the compilation mode, and it generates result mainly assuming the compilation mode is full and we have access to global type info. As a result, its result is not very suitable for local compilation usage, particularly for deciding if a symbol is imported as type or not. This change plumbs a flag `isLocalCompilation` into reflection host to make it aware of the compilation mode.
Also changes made to the logic in the method `getConstructorParameters` so that in local compilation mode:
- returns NO_VALUE_DECLARATION type value ref only if the type is a type parameter
- returns local type value ref for any imported symbol, unless the import is type only in which case returns TYPE_ONLY_IMPORT type value ref
PR Close#52215
The commit adds messaging to the control flow template diagnostic to direct developers to the new
built-in control flow syntax in Angular.
PR Close#52268
ICUs can be used outside of an i18n block. In this case the ICU should
be automatically wrapped in a new i18n block. This commit adds a new
phase to handle wrapping these bare ICUs.
PR Close#52250
ICU params in i18n messages are now resolved in the post-processing call
rather than in the initial message creation. This matches the output
generated by TemplateDefinitionBuilder.
PR Close#52250
ICUs are now ingested by adding ops to both the creation and update IR.
Both of these ops are ultimately removed before reification, but they
are needed to coordinate and link data between the creation and update
ops. This is done in a new ICU extraction phase that removes both ICU
ops and adds an i18nExpr op to the update IR.
PR Close#52250
This commit extracts the API reference info for generic parameters for
classes, methods, interfaces, and functions. It includes any constraints
and the default type if present.
PR Close#52204
Placing a structural directive on an element with an `i18n` attribute
was generating too many i18n blocks. This was due to both the element
and the template generating their own i18n block. To fix the issue, we
no longer generate top-level i18n blocks for structural directive
templates.
PR Close#52202
Structural directives on an ng-template (e.g. <ng-template *ngIf>) were
being assigned the wrong tag name ('ng-template' instead of null).
PR Close#52202
Fixes handling of placeholders for self-closing tags. Self-closing tags
set a combined value for the start tag placeholder, rather than separate
values for the start and close placeholders.
This commit also enables a number of now passing tests. For some of
these tests I had create a separate golden file due to the different
ordering of the const array. In the template pipeline, i18n and
attribute const collection happen in different pahses and we therefore
get a different order than TemplateDefinitionBuilder, which collected
everything in one pass. The order should not affect the overall behavior.
PR Close#52195
The way we were propagating params up to parent i18n ops didn't account
for the fact that a parent and child could both have a value for the
same placeholder. In order to properly merge the value for these cases,
we need to propagate the params up *before* serialization. Therefore I
removed the standalone param propagation phase and folded the logic into
the placeholder resolution phase.
PR Close#52195
Currently the compiler allocates a variable slot to the `@for` loop expression which ends up unused since we don't store the result on the `LView`.
PR Close#52158
A new flag added to the component's debug info to determine whether to throw runtime error (in dev mode) if component is being rendered without its NgModule. This flag is only set for non-standalone components.
PR Close#52061
Orphan component is an anti-pattern in Angular where a component is rendered while the NgModule declaring it is not installed. It is not easy to capture this scenario, specially in compile time. But it is possible to capture a special case in runtime where the component is being rendered without its NgModule even loaded into the browser. This change adds a flag in cli compiler option to enable such checking, and throwing a runtime exception if it happens. Note that such check is only done in dev mode.
Currently the check requires some generated code that is behind ngJitMode flag (i.e., call to ɵɵsetNgModuleScope), and the new flag can be set only if JIT mode is enabled (i.e., supportJitMode=true) otherwise an error will be thrown.
The orphan component is a main blocker for rolling out local compilation in g3. This option is needed for identifying and isolating such cases.
PR Close#52061
Based on recent discussions, these changes remove the Windows CI check because it has been too flaky for too long. Furthermore, we've concluded that the simulated file system in the compiler tests already catches the same set of bugs as running the tests on a real Windows system.
PR Close#52140
This commit adds support for extracting type alises. It currently
extracts the raw written type from the source without performing any
resolution, such as for resolving `typeof` queries, as current Angular
public APIs do not rely on this.
PR Close#52118
Fixes that the new block syntax was generating instructions in the wrong order which meant that pipes were being declared too early. This meant that if the block is first in the template, any pipes used in it won't be able to inject things like `ChangeDetectorRef`.
These changes update the compiler and add a bunch of tests to ensure that pipes work as expected.
Fixes#52102.
PR Close#52112
Since expressions in event listener are added inside of a callback, type narrowing won't apply to them anymore. These changes add the logic to create a guard expression that will re-narrow the expression in the callback.
Fixes#52052.
PR Close#52069
Since expressions in event listener are added inside of a callback, type narrowing won't apply to them anymore. These changes add the logic to create a guard expression that will re-narrow the expression in the callback.
Fixes#52052.
PR Close#52069
This commit updates `@defer` logic related to handling `after` and `minimum` parameters tree-shakable.
If `after` or `minimum` was used on a `@loading` or `@placeholder` blocks, compiler generates an extra argument for the `ɵɵdefer` instruction. This extra argument is a reference to a function that brings timer-related code.
PR Close#52042
A new statement will be generated for components which will attach some useful debug info to them to be used in runtime error handling. Currently this only happens in full and local compilation modes.
PR Close#51919
The current implementation assumes a qualified name consists of just two identifier, e.g., Foo.Bar. However it can be more nested, like Foo.Bar.Baz.XX.YY. While such nested patterns are quite uncommon and devs mostly just use two identifier here, the TS compiler seems to throw error if we make such assumption and it broke quite a lot of targets in g3 when compiled in local mode. So here we handle this nested property of qualified names.
PR Close#51947
The custom logic in the generate advance phase for i18n expressions did
not work in all cases. Instead we add a new phase to update the
expression's target op, and then allow the standard advance generation
code to determine the number of advance instructions needed.
Co-authored-by: Dylan Hunn <dylhunn@users.noreply.github.com>
PR Close#51988
This commit adds support for extracting function overloads. Interestingly, this worked in an earlier version when the code was extracting all statements in every source file, but the existing compiler API for extracting all exported declarations from an entry-point only returns the first function declaration in cases when there are overloads.
This also marks abstract classes as abstract, required inputs as required, and filters out Angular-private APIs.
PR Close#52040
We type check `@switch` blocks by generating identical TS `switch` statements in the TCB, however TS currently has a bug where parenthesized `switch` block expressions don't narrow their types. Since we use parenthesized expressions to wrap AST nodes for diagnostics, this will bug will affect all Angular-generated `switch` statements.
These changes work around the issue by generating `if`/`else if`/`else` statements that represent the `switch`.
Some alternatives that were considered:
1. Moving the `switch` expression to a constant - this is fairly simple to implement, but it won't fully resolve the narrowing issue since the same constant will have to be used in expressions inside the different cases.
2. Removing the outer-most parenthesis from the switch expression - this works and allows us to continue using switch statements, but because we use parenthesized expressions to map diagnostics to their template locations, I wasn't sure if it won't lead to worse template dignostics.
Fixes#52077.
PR Close#52110
Fixes that the compiler wasn't picking up pipes used inside defer block triggers as dependencies. We had implemented the `visitDeferredTrigger` visitor method, but it wasn't being called, because we weren't going through the `visitAll` method of the deferred block. We don't use `visitAll`, because child nodes have to be processed differently than the connected blocks and triggers.
Fixes#52068.
PR Close#52071
The `_enabledBlockTypes` config option was removed recently, since we've enabled @-syntax by default. This commit removes `_enabledBlockTypes` references from the `compiler-cli` test cases.
PR Close#52066
Adds an `UnknownBlock` node to the Ivy AST to represent blocks that haven't been recognized by the compiler. This will make it easier to integrate blocks into the language service.
PR Close#52047
This adds API doc extraction for interfaces, largely using the same code paths for classes. The primary difference between classes and interfaces is that classes have member _declarations_ while interfaces have member _signatures_. This largely doesn't matter for the purposes of extraction, but the types are distinct with no common base types, so we have to do a fair amount of type unioning and aliasing.
PR Close#52006
A couple tests were already passing, and just needed to be enabled. This includes tests pertaining to:
* ng-template
* host binding styling slots
* and host animation bindings
* some literal tests (which were missing some $foo$ escaped names)
We add pipeline-specific versions of the following tests, and enable them:
* A local refs test. The consts for the element attributes and the consts for local reference are collected in the reverse order, but the emitted template is functionally the same.
* A safe accesstest. Consider the expression `$any(val)?.foo`. `TemplateDefinitionBuilder` extracts a temporary variable: `($tmp_0_0$ = $ctx$.val) == null ? null : $tmp_0_0$.foo`. It presumably does this because it considers the `$any(...)` to be a function call. However, this is not a real call, so Template Pipeline safely ignores it and declines to generate a temporary.
* Another local refs test. AttributeMarker.Template is emitted at the end of the const array (instead of the middle)
PR Close#51950
Consider an `ng-template` which is generated as a result of a structural directive:
```
<div *ngFor="let inner of items"
(click)="onClick(inner)"
[title]="getTitle()"
>
```
This should logically expand into something like the following:
```
<ng-template [ngForOf]="..." >
<div (click)="..." [title]="..."></div>
</ng-template>
```
Note that the `(click)` handler and the `[title]` property are only present on the inner div, *not* on the enclosing generated `ng-template`.
Previously, Template Pipeline would place these bindings on *both* the tempate and the inner element.
However, we can't just remove them completely, because these bindings should still be matchable on the generated `ng-template` (which is very surprising, but nonetheless true).
We resolve this issue with two improvements:
(1) The ingestion step is now much smarter about determining not only if a binding is on a template element, but whether it actually targets that template element.
(2) We use `ExtractedAttributeOp` directly, rather than going through `BindingOp`, to cause the `ng-template` to still receive these bindings in its `consts` array for matching purposes.
PR Close#51950
For components, the parser already extracts the `important` property (and it is later disregarded). However, because host bindings use a totally separate parsing code path, this was never happing for host bindings.
Here, we add some code to the host style parsing phase to drop the `!important` suffix.
We could solve this category of problems for good by parsing host bindings with the same code as template bindings.
PR Close#51950
Previously, we always generated temporary variable declarations at the beginning of each view's update block. This is wrong, for two reasons:
1. Temporaries can be used in the create block
2. When listeners use temporaries, we should declare them inside the listener.
Now, we always place temporaries at the beginning of the enclosing OpList, and recursively try to generate them when we find a listener.
PR Close#51950
Currently the TCB for aliased `if` blocks looks something like this:
```
// Markup: `@if (expr; as alias) { {{alias}} }
if (block.condition) {
var alias = block.condition;
"" + alias;
}
```
The problem with this approach is that the type of `alias` won't be narrowed. This is something that `NgIf` currently supports.
These changes resolve the issue by emitting the variable outside the `if` block and using the variable reference instead:
```
// Markup: `@if (expr; as alias) { {{alias}} }
var alias = block.condition;
if (alias) {
"" + alias;
}
```
PR Close#51952
Reworks a few more places to output arrow functions instead of function declarations in order to reduce the amount of code we generate. Some of these places include:
* Factories in injectable definitions.
* Forward references.
* `dependencies` function in the component definition.
* `consts` function in the component definition.
PR Close#52010