Commit graph

1790 commits

Author SHA1 Message Date
Kristiyan Kostadinov
c0788200e2 fix(compiler): capture data bindings for content projection purposes in blocks (#54876)
Fixes a regression in the template pipeline where data bindings weren't being captured for content projection purposes.

Fixes #54872.

PR Close #54876
2024-03-15 15:11:19 -07:00
Kristiyan Kostadinov
f386a04c9d fix(compiler): handle two-way bindings to signal-based template variables in instruction generation (#54714)
Updates the instruction generation for two-way bindings to only emit the `twoWayBindingSet` call when writing to template variables. Since template variables are constants, it's only allowed to write to them when they're signals. Non-signal values are flagged during template type checking.

Fixes #54670.

PR Close #54714
2024-03-11 11:01:43 -07:00
Kristiyan Kostadinov
1f129f114e fix(compiler): not catching for loop empty tracking expressions (#54772)
Fixes that the template parser wasn't catching empty expressions in the `track` parameter of for loops.

Fixes #54763.

PR Close #54772
2024-03-11 09:17:43 -07:00
Dylan Hunn
b40f1e5b86 refactor(compiler): Remove deep imports in the language service (#54695)
Previously, the language service relied on deep imports such as `@angular/compiler/render3/...`. This is bad form, because that creates a dependency on the package's internal structure. Additionally, this is not compatible with google3.

In this PR, I replace all the deep imports with shallow imports, in some cases adding the missing symbol to the `compiler.ts` exports.

PR Close #54695
2024-03-05 10:28:45 +01:00
cexbrayat
5e32a775d9 refactor(compiler): cleanup unused code in template builder pipeline (#54654)
This removes some unused code and fixes a few typos across the pipeline code.

PR Close #54654
2024-03-04 18:15:54 +01:00
Dylan Hunn
1a6beae8a2 feat(compiler): Enable template pipeline by default. (#54571)
Template pipeline is now the default template compiler.

A pair of source map tests is failing, related to DI in JIT mode; I will fix and re-enable these during the preview period.

PR Close #54571
2024-02-23 11:15:36 -08:00
Kristiyan Kostadinov
badda0c389 fix(compiler-cli): correctly detect deferred dependencies across scoped nodes (#54499)
This is based on an internal issue report.

An earlier change introduced a diagnostic to report cases where a symbol is in the `deferredImports` array, but is used eagerly. The check worked by looking through the deferred blocks in a scope, resolving the scope for each and checking if the element is within the scope. The problem is that resolving the scope won't work across scoped node boundaries. For example, if there's a control flow statement around the block or within the block but around the deferred dependency, it won't be able to resolve the scope since it isn't a direct child, e.g.

```
@if (true) {
  @defer {
   <deferred-dep/>
  }
}
```

To fix this the case where the deferred block is inside a scoped node, I've changed the `R3BoundTarget.deferBlocks` to be a `Map` holding both the deferred block and its corresponding scope. Then to resolve the case where the dependency is within a scoped node inside the deferred block, I've added a depth-first traversal through the scopes within the deferred block.

PR Close #54499
2024-02-21 15:22:36 -08:00
Dmitry Ivanitskiy
dba3e0b5aa fix(compiler): adding the inert property to the "SCHEMA" array (#53148)
This change allows template binding "inert" attribute with the following syntax: [inert]="isInert"

Fixes #51879

fixup! fix(compiler): adding the inert property to the "SCHEMA" array

revert: "fixup! fix(compiler): adding the inert property to the "SCHEMA" array"

This reverts commit b637b7ce646e8bab2f585339028a84018e8ea982.

This commit is being reverted because the inert property is safe as a boolean attribute

PR Close #53148
2024-02-21 15:13:48 -08:00
Dylan Hunn
6c2d4b650b refactor(compiler): Enable Template Pipeline globally in 1P. (#54435)
The switch/index.ts file only affects g3; externally, it is replaced with a Blaze genrule.

PR Close #54435
2024-02-15 09:24:18 -08:00
Kristiyan Kostadinov
e921e108e1 refactor(core): correctly distinguish getter functions from writable signals (#54252)
Fixes that `ɵunwrapWritableSignal` inferring getter functions as not matching the interface of `WritableSignal` instead of preserving them.

PR Close #54252
2024-02-07 16:36:15 +00:00
Kristiyan Kostadinov
243b94c6e1 refactor(compiler-cli): fix regression in two-way bindings to inputs with different getter/setter types (#54252)
In a previous commit the TCB was changed to cast the assignment to an input in order to widen its type to allow `WritableSignal`. This ended up breaking existing inputs whose setter has a wider type than its getter. These changes switch to unwrapping the value on the binding side.

PR Close #54252
2024-02-07 16:36:13 +00:00
Kristiyan Kostadinov
a17f6cb2d0 refactor(compiler-cli): rework TCB for two-way bindings (#54252)
Reworks the TCB for two-way bindings to make them simpler and to avoid regressions for two-way bindings to generic inputs. The new TCB looks as follows:

```
var _t1: Dir;
var _t2 = _t1.input;
(_t1 as typeof _t2 | WritableSignal<typeof _t2>) = expression;
```

PR Close #54252
2024-02-07 16:36:11 +00:00
Kristiyan Kostadinov
67b977ea97 refactor(compiler-cli): allow writable signals in two-way bindings (#54252)
Updates the TCB generation logic to allow for `WritableSignal` to be assigned in two-way bindings.

PR Close #54252
2024-02-07 16:36:07 +00:00
Paul Gschwendtner
bfbb30618b fix(compiler-cli): do not error due to multiple components named equally (#54273)
Currently, when two components are named `TestComponent`, and both would
use e.g. control flow. Templates would be generated by the compiler and
those would conflict at runtime because the names for the template
functions are not ensured to be unique.

This seems like a more general problem that could be tackled in the
future in the template pipeline by always using the `ConstantPool`, but
for now, we should be good already, given us ensuring the `baseName`'s are
always unique.

PR Close #54273
2024-02-06 17:33:23 +00:00
Dylan Hunn
f600f0fb27 refactor(compiler): Show an error when a property binding duplicates an i18n attribute (#54063)
Consider the following very quirky Angular template, which has both an i18n attribute binding and a property binding to `in`:
```
<cmp [in]="foo" in="bar" i18n-in />
```

What would you expect the above template to do? `TemplateDefinitionBuilder` will emit the following Ivy instructions:
```
// Element constant attributes
consts: () => {
    __i18nMsg__('bar', [], {}, {})
    return [["in", i18n_0, __AttributeMarker.I18n__, "in"]];
}
// ...
function MyComponent_Template(rf, ctx) {
    if (rf & 1) {
        // Create mode
        i0.ɵɵelement(0, "cmp", 0);
    }
}
```

This makes some sense -- we create a single element, and attach an i18n message to the `in` attribute. But is this actually correct? Notice that the property binding is completely missing!

Indeed, Template Pipeline actually produces this code:
```
// Element constant attributes
consts: () => {
    __i18nMsg__('bar', [], {}, {})
    return [["in", i18n_0, __AttributeMarker.I18n__, "in"]];
}
// ...
function MyComponent_Template(rf, ctx) {
    if (rf & 1) {
        // Create mode
        i0.ɵɵelement(0, "cmp", 0);
    } else if (rf & 2) {
        // Update mode
        i0.ɵɵproperty("in", ctx.foo);
    }
}
```

Aha! There's the property binding! Arguably, this is a bug in `TemplateDefinitionBuilder`, but after some discussion on Slack, we have decided to ban this practice in a future Angular version.

For now, we allow Template Pipeline to have slightly different output, but print an error to warn the user of the issue.

PR Close #54063
2024-02-02 20:52:39 +00:00
Mateusz Daniluk
de777afbc5 refactor: standardize doctype declaration to <!DOCTYPE html> (#51052)
This commit standardizes the doctype declaration across all HTML files in the project to use `<!DOCTYPE html>`

PR Close #51052
2024-02-01 19:29:46 +00:00
Kristiyan Kostadinov
95dcf5fafa fix(compiler-cli): handle default imports in defer blocks (#53695)
Fixes that `@defer` blocks weren't recognizing default imports and generating the proper code for them. Default symbols need to be accessed through the `default` property in the `import` statement, rather than by their name.

PR Close #53695
2024-02-01 15:58:21 +00:00
Kristiyan Kostadinov
3b892e98b0 refactor(compiler): update ordering in template pipeline (#54154)
Updates the instruction ordering logic in the template pipeline.

PR Close #54154
2024-02-01 14:39:32 +00:00
Kristiyan Kostadinov
ec8e8ab5d5 refactor(compiler): maintain order between two-way and one-way properties (#54154)
One of the earlier commits separated one-way and two-way bindings which ended up breaking some internal targets, because it changed the assignment order. These changes bring back the old order.

PR Close #54154
2024-02-01 14:39:32 +00:00
Kristiyan Kostadinov
cbe6e1ffcf refactor(compiler): allow some invalid expressions in two-way bindings that previously worked by accident (#54154)
In one of the earlier commits, the logic that appends `=$event` before parsing two-way bindings was removed and some validation was added to prevent unassignable expressions from being used. This ended up being problematic, because previously the parser was incorrectly allowing some invalid expressions which users came to depend on. For example, it transformed `[(value)]="a && a.b"` to `a && (a.b = $event)`.

These changes add some special cases for the common breakages that came up during the TGP.

PR Close #54154
2024-02-01 14:39:32 +00:00
Kristiyan Kostadinov
cbdfc88b24 refactor(compiler): implement new two-way listener shape in pipeline (#54154)
Implements the new shape of two-way listener instructions in the template pipeline.

PR Close #54154
2024-02-01 14:39:32 +00:00
Kristiyan Kostadinov
4babc47b31 refactor(compiler): update two-way listener emit in definition builder (#54154)
Updates the template definition builder to emit the new format for the listener side of two-way bindings.

```js
// Before
listener("ngModelChange", function($event) {
  return ctx.name = $event;
});

// After
ɵɵtwoWayListener("ngModelChange", function($event) {
  ɵɵtwoWayBindingSet(ctx.name, $event) || (ctx.name = $event);
  return $event;
});
```

PR Close #54154
2024-02-01 14:39:32 +00:00
Kristiyan Kostadinov
a436e2d5ea refactor(compiler): preserve expression in two-way listeners (#54154)
Currently the listener side two-way listeners are parsed by appending `=$event` to the raw expression. This is problematic, because:
1. It can interfere with other expressions (see #37809).
2. It can lead to confusing error messages because users will see code that they didn't write.
3. It doesn't allow us to further manipulate the expression.

These changes remove the logic that appends `=$event` to resolve the issue. There's also some new logic that checks the expression after it has been parsed to ensure that the result is an assignable expression.

Subsequent commits will update the code that emits the expression to add back the `$event` assignment where it's needed.

PR Close #54154
2024-02-01 14:39:32 +00:00
Kristiyan Kostadinov
e7a75d3ec2 refactor(core): introduce two-way listener instructions (#54154)
Adds the following new instructions:
* `twoWayBindingSet` - used to assign values inside of the listener side of a two-way binding. Currently a noop, but will come into play later.
* `twoWayListener` - used to bind a two-way listener. Currently calls directly into `listener`, but it may be useful in the future.

PR Close #54154
2024-02-01 14:39:32 +00:00
Kristiyan Kostadinov
a22d765cca refactor(compiler): update access of members in expression parser (#54154)
Currently all the members of `_ParseAST` are public, even though they're all used only within the class. This change marks them as private so that it's explicit which ones are intended to be used outside the class.

PR Close #54154
2024-02-01 14:39:32 +00:00
Kristiyan Kostadinov
ea7d1b363f refactor(compiler): implement two-way property instruction (#54154)
Reworks the compiler so that it generates a `twoWayProperty` instruction, instead of `property`, for the property side of a two-way binding. Currently the new instruction passes through to `property`, but it'll have some two-way-binding-specific logic in subsequent PRs.

PR Close #54154
2024-02-01 14:39:32 +00:00
Kristiyan Kostadinov
93188cb439 refactor(compiler): distinguish two-way bindings in the AST (#54065)
During the template parsing stage two-way bindings are split up into a property and event binding. All the downstream code treats these binding the same as their one-way equivalents. For some future work we'll have to distinguish between the two so these changes update the `BoundElementProperty.type` and `ParsedEvent.type` to include a `TwoWay` type. All existing call-sites have been updated to treat `TwoWay` the same as `Property`/`Regular`, but more specialized logic will be added in the future.

PR Close #54065
2024-01-25 16:31:57 +00:00
Dylan Hunn
c3bb00a2eb refactor(compiler): Fix defer deps fn duplicate names in Template Pipeline (#54060)
Previously, defer deps fns names were only prefixed with the component name, meaning that distinct deps fns in the same component would produce a name collision. Now, we take into account the entire template function name when naming inner deps fns.

PR Close #54060
2024-01-25 16:31:01 +00:00
Andrew Scott
eddf5dae5e fix(compiler): Update type check block to fix control flow source mappings (#53980)
The source mappings and types for various pieces of the control flow
were not quite right and prevented the language service from providing
accurate information.

fixes https://github.com/angular/vscode-ng-language-service/issues/1988

PR Close #53980
2024-01-24 18:37:58 -05:00
Dylan Hunn
47e6e84101 feat(compiler): Add a TSConfig option useTemplatePipeline (#54057)
The Template Pipeline is a brand new backend for the Angular compiler, replacing `TemplateDefinitionBuilder`. It generates the Ivy instructions corresponding to an input template (or host binding). The Template Pipeline has an all-new design based on an intermediate representation compiled over many phases, which will allow us to experiment with compiler changes more easily in the future.

With this commit, the template pipeline can now be enabled in any project via the `useTemplatePipeline` TSConfig option. However, it is still disabled by default.

PR Close #54057
2024-01-24 18:36:23 -05:00
Dylan Hunn
0f5f45c0fa refactor(compiler): Support externally provided defer deps fns (#54043)
In #53591, Andrew added local compliation support for defer blocks. However, this requires the ability to emit pre-generated static defer deps functions. We now also support that feature in Template Pipeline.

PR Close #54043
2024-01-24 18:35:24 -05:00
Paul Gschwendtner
77516450c8 refactor(compiler): support JIT for signal-based queries (#54019)
Similar to signal-based inputs, we support signal-based queries in JIT
by expecting a decorator to be added. This is a consequence of the
design, given that JIT requires query declaration information before
the class is initialized- but ironically there is no way to collect this
information without instantiating the class.

A JIT transform in the Angular CLI will automatically generate these
decorators for testing.

PR Close #54019
2024-01-24 16:13:31 +01:00
Paul Gschwendtner
3b6f636edf refactor(compiler-cli): collapse multiple query advance statements (#54019)
Collapses multiple sibling query advance statements into single
query advance invocations. This will help reducing generated code
for directives/components with many queries.

PR Close #54019
2024-01-24 16:13:31 +01:00
Paul Gschwendtner
998af3276f refactor(compiler-cli): move more query generation logic to dedicated file (#54019)
Without any modifications, this commit moves more of the the query
generation logic into its dedicated file.

PR Close #54019
2024-01-24 16:13:31 +01:00
Dylan Hunn
d99bc8aeb6 refactor(compiler): ICUs should roll up to the root i18n block for application (#54026)
Previously, if an ICU was inside a nested i18n root, it would use the nested root to calculate whether it should be applied. Now, we use the root i18n block.

PR Close #54026
2024-01-23 15:09:36 +01:00
Paul Gschwendtner
d4c84a97e8 refactor(compiler-cli): generate partial compilation output for signal-based queries (#53978)
This commit ensures that libraries can use signal-based queries, and the
partial compilation output will capture their metadata.

The linker is updated to support parsing this.

Two notes:

1. Older linker versions are not capable of parsing this, so the minimum
   version for signal-based queries is adjusted when such are used.
2. We only emit `isSignal` metadata for queries when signal queries are
   used. This enables libraries to continue supporting older linker
   versions, if signal-based queries are not used.

PR Close #53978
2024-01-23 10:24:36 +01:00
Paul Gschwendtner
8f936a4111 refactor(compiler-cli): recognize signal-based queries in class initializers (#53978)
This commit uses the initializer API recognition that we built for
signal-based inputs, and teaches the compiler to recognize class members
that refer to `viewChild`, `viewChildren`, `contentChild` or
`contentChildren`. Those will declare signal-based view or content queries.

PR Close #53978
2024-01-23 10:24:36 +01:00
Paul Gschwendtner
35ee10e357 refactor(compiler-cli): support generation of signal-based queries (#53978)
This commit introduces the compiler output generation for signal-based
queries. Signal-based queries will have new creation-mode instructions
and update instructions to advance the current query indices in the
global shared context.

An output like the following is the expected output for signal-based
queries:

```
i0.ɵɵdefineComponent({
  viewQuery: function App_Query(rf, ctx) {
      if (rf & 1) {
          i0.ɵɵviewQuery(ctx.d, _c0, 5);
          i0.ɵɵviewQuerySignal(ctx.ds1, _c0, 5);
          i0.ɵɵviewQuerySignal(ctx.ds2, _c0, 5);
      }
      if (rf & 2) {
          let _t;
          // only change-detected queries need explicit refresh
          i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.d = _t.first);
          // we bump up current query index by 2 positions since there are 2 signal-based queries
          i0.ɵɵqueryAdvance(2);
      }
      …
  },
  …
});

```

Note: For now, the collapsing of multiple advance instructions is not
implemented. This will be a follow-up.

Note 2: A couple of query helpers are now in their own file. This makes
it easier to focus on query-specific compiler code. The new function is
called `createQueryCreateCall`, which is a modified variant of the
existing function that previously only generated query parameters.

PR Close #53978
2024-01-23 10:24:36 +01:00
Matthieu Riegler
7dd56736e8 refactor(compiler): remove mentions of unused compiler options. (#53746)
Those options where removed in #49672.

PR Close #53746
2024-01-17 16:41:35 -08:00
Andrew Kushnir
b0e0f0014e refactor(compiler): extra diagnostics for @defer in local compilation mode (#53899)
This commit adds extra logic to produce a diagnostic in case `@Component.deferredImports` contain types from imports that also bring eager symbols. This would result in retaining a regular import and generating a dynamic import, which would not allow to defer-load dependencies.

PR Close #53899
2024-01-17 10:46:15 -08:00
Daniel Puckowski
66e940aebf feat(compiler): scope selectors in @starting-style (#53943)
make sure selectors inside @starting-style queries are correctly scoped

PR Close #53943
2024-01-17 09:14:11 -08:00
Andrew Kushnir
8ca0b0515d refactor(compiler): update TemplateDefinitionBuilder to support local compilation (#53591)
This commit updates the logic of the `TemplateDefinitionBuilder` to support local compilation and generate a single dependency function for all explicitly deferred deps within a component.

PR Close #53591
2024-01-10 15:28:58 -08:00
Andrew Kushnir
a2aa23d8b5 refactor(compiler): add support for internal deferredImports field (#53591)
This commit updates the logic to add support for internal `deferredImports` field in compiler.

PR Close #53591
2024-01-10 15:28:58 -08:00
Andrew Kushnir
6eb5e37d6f refactor(compiler): add an internal API to check is an element is inside a defer block (#53591)
This commit updates the logic to expose an internal API on the `R3BoundTarget` to check if an element belongs to any defer block.

PR Close #53591
2024-01-10 15:28:58 -08:00
Paul Gschwendtner
d7147507e4 refactor(core): properly emit input flags using bitwise or (#53808)
As part of testing we did accidentally use `bitwiseAnd` for the input
flags, given we started without an extra flag for `HasTransform`.

This commit teaches the compiler to support emitting bitwise OR
and uses it when combining input flags, fully re-enabling transforms
for signal components after the new flag mechanism was introduced in
previous commits.

PR Close #53808
2024-01-10 12:21:04 +00:00
Paul Gschwendtner
cfab5a59d6 refactor(core): detect signal input transforms independently of flag (#53808)
This commit changes the `HasTransform` flag to be only concerned with
decorator inputs. This allows us to automatically detect signal input
transforms without reliance on the flag, resulting in less complexity in
the compiler (as outlined in the design doc) and various  other places,
while it also allows us to simplify JIT support for signal inputs
because there would be no need to capture the "hasTransform" state in
the decorator so that JIT can generate the according input flags.

`isSignal` will still persist as an input flag to allow for monomorphic
and highly efficient distinguishing at runtime, whether an input is
signal based or not. JIT transform will also need to propagate this
information to the runtime somehow.

PR Close #53808
2024-01-10 12:21:04 +00:00
Paul Gschwendtner
eee0af0599 refactor(core): add internal signal input support for @Input decorator (#53808)
We are adding internal support for declaring signal inputs via the
`@Input` decorator. This is needed for JIT unit testing, or JIT
applications.

In JIT, Angular is not able to recognize signal inputs due to the
lack of static reflection metadata. Decorators attach their information
on the class- without it needing to be instantiated. This allows Angular
to know inputs when preparing/generating the directive definition. With
signal inputs this is not possible- so we need a way to tell Angular
about inputs for JIT applications. We've decided that this is not
something users should have to deal with, so a transform will be added
in a follow-up that will automatically derive/and add the decorators
for signal inputs when requested in JIT environments.

PR Close #53808
2024-01-10 12:21:04 +00:00
Kristiyan Kostadinov
2dedc4a969 fix(compiler): generate less code for advance instructions (#53845)
We generate `advance` instructions before most update instructions and the majority of `advance` calls are advancing by one. We can save some bytes for the most common case by omitting the parameter for `advance(1)` altogether.

PR Close #53845
2024-01-09 12:27:58 -08:00
Paul Gschwendtner
36318dbd41 refactor(compiler-cli): reference InputFlags enum directly for full compiler output (#53571)
Instead of computing the bit input flags at compile-time and inling
the final bit flag number, we will use the `InputFlags` enum directly.
This is a little more code in the compiler side, but will allow us to
have better debuggable development code, and also prevents problems
where runtime flag bitmasks differ from the compiler flag bitmasks.

This is in practice a noop for optimized applications as the enum values
would be inlined anyway. This matches existing compiler emit for e.g.
change detection strategy, or view encapsulation enums.

PR Close #53571
2024-01-04 12:07:13 -08:00
Paul Gschwendtner
1d95a832e3 refactor(core): detect signal inputs at runtime using input flags (#53571)
This commit introduces a new enum for capturing additional metadata
about inputs. Called `InputFlags`. These will be built up at compile
time and then propagated into the runtime logic, in a way that does
not require additional lookup dictionaries data structures, or
additional memory allocations for "common inputs" that do not have any flags.

The flags will incorporate information on whether an input is signal
based. This can then be used to avoid megamorphic accesses when such
input is set- as we'd not need to check the input field value. This also
avoids cases where an input signal may be used as initial value for an
input (as we'd not incorrectly detect the input as a signal input then).

The new metadata emit will be useful for incorporating additional
metadata for inputs, such as whether they are required etc (although
required inputs are a build-time only construct right now- but this is a
good illustration of why input flags can be useful). An alternative
could have been to have an additional boolean entry for signal inputs,
but allocating a number with more flexible input flags seems more future
proof and more reasonable andreadable.

More information on the megamorphic access when updating an input
signal
https://docs.google.com/document/d/1FpnFruviKb6BFTQfMAP2AMEqEB0FI7z-3mT_qm7lzX8/edit.

PR Close #53571
2024-01-04 12:07:13 -08:00