diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_styling/mixed_style_and_class/TEST_CASES.json b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_styling/mixed_style_and_class/TEST_CASES.json index ebc975bf3d5..c6e627a237b 100644 --- a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_styling/mixed_style_and_class/TEST_CASES.json +++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_styling/mixed_style_and_class/TEST_CASES.json @@ -33,8 +33,7 @@ "failureMessage": "Incorrect template", "files": ["pipe_bindings_slots.js"] } - ], - "skipForTemplatePipeline": true + ] }, { "description": "should always generate advance() statements before any styling instructions", diff --git a/packages/compiler/src/template/pipeline/src/emit.ts b/packages/compiler/src/template/pipeline/src/emit.ts index 934106152d7..79999ae08b5 100644 --- a/packages/compiler/src/template/pipeline/src/emit.ts +++ b/packages/compiler/src/template/pipeline/src/emit.ts @@ -88,6 +88,7 @@ const phases: Phase[] = [ {kind: Kind.Both, fn: phaseAttributeExtraction}, {kind: Kind.Both, fn: phaseParseExtractedStyles}, {kind: Kind.Tmpl, fn: phaseRemoveEmptyBindings}, + {kind: Kind.Both, fn: phaseOrdering}, {kind: Kind.Tmpl, fn: phaseConditionals}, {kind: Kind.Tmpl, fn: phasePipeCreation}, {kind: Kind.Tmpl, fn: phaseI18nTextExtraction}, @@ -127,7 +128,6 @@ const phases: Phase[] = [ {kind: Kind.Tmpl, fn: phaseEmptyElements}, {kind: Kind.Tmpl, fn: phaseNonbindable}, {kind: Kind.Both, fn: phasePureFunctionExtraction}, - {kind: Kind.Both, fn: phaseOrdering}, {kind: Kind.Both, fn: phaseReify}, {kind: Kind.Both, fn: phaseChaining}, ]; diff --git a/packages/compiler/src/template/pipeline/src/phases/ordering.ts b/packages/compiler/src/template/pipeline/src/phases/ordering.ts index 197abe31a19..a4cabc07ebd 100644 --- a/packages/compiler/src/template/pipeline/src/phases/ordering.ts +++ b/packages/compiler/src/template/pipeline/src/phases/ordering.ts @@ -58,34 +58,40 @@ export function phaseOrdering(job: CompilationJob) { // still have ops pulled at the end, put them back in the correct order. // Create mode: - let opsToOrder = []; - for (const op of unit.create) { - if (handledOpKinds.has(op.kind)) { - opsToOrder.push(op); - ir.OpList.remove(op); - } else { - ir.OpList.insertBefore(reorder(opsToOrder, CREATE_ORDERING), op); - opsToOrder = []; - } - } - unit.create.push(reorder(opsToOrder, CREATE_ORDERING)); + orderWithin(unit.create, CREATE_ORDERING as Array>); // Update mode: - opsToOrder = []; - for (const op of unit.update) { - if (handledOpKinds.has(op.kind)) { - opsToOrder.push(op); - ir.OpList.remove(op); - } else { - ir.OpList.insertBefore(reorder(opsToOrder, UPDATE_ORDERING), op); - opsToOrder = []; - } - } - unit.update.push(reorder(opsToOrder, UPDATE_ORDERING)); + orderWithin(unit.update, UPDATE_ORDERING as Array>); } } +/** + * Order all the ops within the specified group. + */ +function orderWithin( + opList: ir.OpList, ordering: Array>) { + let opsToOrder = []; + // Only reorder ops that target the same xref; do not mix ops that target different xrefs. + let firstTargetInGroup: ir.XrefId|null = null; + for (const op of opList) { + const currentTarget = ir.hasDependsOnSlotContextTrait(op) ? op.target : null; + if (!handledOpKinds.has(op.kind) || + (currentTarget !== firstTargetInGroup && + (firstTargetInGroup !== null && currentTarget !== null))) { + ir.OpList.insertBefore(reorder(opsToOrder, ordering), op); + opsToOrder = []; + firstTargetInGroup = null; + } + if (handledOpKinds.has(op.kind)) { + opsToOrder.push(op); + ir.OpList.remove(op); + firstTargetInGroup = currentTarget ?? firstTargetInGroup; + } + } + opList.push(reorder(opsToOrder, ordering)); +} + /** * Reorders the given list of ops according to the ordering defined by `ORDERING`. */