Skip to content

Commit

Permalink
fix(compiler): ignore empty switch blocks (#53776)
Browse files Browse the repository at this point in the history
Adds some code to the compiler so that it ignores empty `@switch` blocks instead of trying to generate code for them.

Fixes #53773.

PR Close #53776
  • Loading branch information
crisbeto authored and atscott committed Jan 3, 2024
1 parent d315e2c commit e5f0205
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 0 deletions.
Expand Up @@ -1534,6 +1534,10 @@ describe('type check blocks', () => {
'else if ((_t2()) === "two") { "" + ((this).two()); } ' +
'else { "" + ((this).default()); } }');
});

it('should handle an empty switch block', () => {
expect(tcb('@switch (expr) {}')).toContain('if (true) { ((this).expr); }');
});
});

describe('for loop blocks', () => {
Expand Down
Expand Up @@ -290,6 +290,47 @@ export declare class MyApp {
static ɵcmp: i0.ɵɵComponentDeclaration<MyApp, "ng-component", never, {}, {}, never, never, true, never>;
}

/****************************************************************************************************
* PARTIAL FILE: empty_switch.js
****************************************************************************************************/
import { Component } from '@angular/core';
import * as i0 from "@angular/core";
export class MyApp {
constructor() {
this.message = 'hello';
}
}
MyApp.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyApp, deps: [], target: i0.ɵɵFactoryTarget.Component });
MyApp.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "0.0.0-PLACEHOLDER", type: MyApp, selector: "ng-component", ngImport: i0, template: `
<div>
{{message}}
@switch (message) {}
{{message}}
</div>
`, isInline: true });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyApp, decorators: [{
type: Component,
args: [{
template: `
<div>
{{message}}
@switch (message) {}
{{message}}
</div>
`,
}]
}] });

/****************************************************************************************************
* PARTIAL FILE: empty_switch.d.ts
****************************************************************************************************/
import * as i0 from "@angular/core";
export declare class MyApp {
message: string;
static ɵfac: i0.ɵɵFactoryDeclaration<MyApp, never>;
static ɵcmp: i0.ɵɵComponentDeclaration<MyApp, "ng-component", never, {}, {}, never, never, false, never>;
}

/****************************************************************************************************
* PARTIAL FILE: basic_if.js
****************************************************************************************************/
Expand Down
Expand Up @@ -70,6 +70,23 @@
}
]
},
{
"description": "should not generate code for empty switch blocks",
"inputFiles": [
"empty_switch.ts"
],
"expectations": [
{
"files": [
{
"expected": "empty_switch_template.js",
"generated": "empty_switch.js"
}
],
"failureMessage": "Incorrect template"
}
]
},
{
"description": "should generate a basic if block",
"inputFiles": [
Expand Down
@@ -0,0 +1,14 @@
import {Component} from '@angular/core';

@Component({
template: `
<div>
{{message}}
@switch (message) {}
{{message}}
</div>
`,
})
export class MyApp {
message = 'hello';
}
@@ -0,0 +1,14 @@
function MyApp_Template(rf, ctx) {
if (rf & 1) {
$r3$.ɵɵelementStart(0, "div");
$r3$.ɵɵtext(1);
$r3$.ɵɵtext(2);
$r3$.ɵɵelementEnd();
}
if (rf & 2) {
$r3$.ɵɵadvance(1);
$r3$.ɵɵtextInterpolate1(" ", ctx.message, " ");
$r3$.ɵɵadvance(1);
$r3$.ɵɵtextInterpolate1(" ", ctx.message, " ");
}
}
4 changes: 4 additions & 0 deletions packages/compiler/src/render3/view/template.ts
Expand Up @@ -1249,6 +1249,10 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
}

visitSwitchBlock(block: t.SwitchBlock): void {
if (block.cases.length === 0) {
return;
}

// We have to process the block in two steps: once here and again in the update instruction
// callback in order to generate the correct expressions when pipes or pure functions are used.
const caseData = block.cases.map(currentCase => {
Expand Down
5 changes: 5 additions & 0 deletions packages/compiler/src/template/pipeline/src/ingest.ts
Expand Up @@ -383,6 +383,11 @@ function ingestIfBlock(unit: ViewCompilationUnit, ifBlock: t.IfBlock): void {
* Ingest an `@switch` block into the given `ViewCompilation`.
*/
function ingestSwitchBlock(unit: ViewCompilationUnit, switchBlock: t.SwitchBlock): void {
// Don't ingest empty switches since they won't render anything.
if (switchBlock.cases.length === 0) {
return;
}

let firstXref: ir.XrefId|null = null;
let firstSlotHandle: ir.SlotHandle|null = null;
let conditions: Array<ir.ConditionalCaseExpr> = [];
Expand Down

0 comments on commit e5f0205

Please sign in to comment.