Skip to content

Commit 9fe35ec

Browse files
authored
mustachio: Separate out the context stack LUB type calculation (#3730)
1 parent 7be9e24 commit 9fe35ec

File tree

3 files changed

+48
-27
lines changed

3 files changed

+48
-27
lines changed

lib/src/generator/templates.aot_renderers_for_html.dart

+1-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@
33
// To change the contents of this library, make changes to the builder source
44
// files in the tool/mustachio/ directory.
55

6-
// There are a few deduplicated render functions which are generated but not
7-
// used.
6+
// Some deduplicated render functions are generated but not used.
87
// TODO(srawlins): Detect these and do not write them.
98
// ignore_for_file: unused_element
109
// Sometimes we enter a new section which triggers creating a new variable, but

test/mustachio/foo.aot_renderers_for_html.dart

+1-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@
33
// To change the contents of this library, make changes to the builder source
44
// files in the tool/mustachio/ directory.
55

6-
// There are a few deduplicated render functions which are generated but not
7-
// used.
6+
// Some deduplicated render functions are generated but not used.
87
// TODO(srawlins): Detect these and do not write them.
98
// ignore_for_file: unused_element
109
// Sometimes we enter a new section which triggers creating a new variable, but

tool/mustachio/codegen_aot_compiler.dart

+46-23
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ import 'package:dartdoc/src/type_utils.dart';
1717
import 'package:meta/meta.dart';
1818
import 'package:path/path.dart' as path;
1919

20+
/// A list of [_VariableLookup]s used by a renderer constitutes a "context
21+
/// stack".
22+
typedef ContextStack = List<_VariableLookup>;
23+
2024
/// Compiles all templates specified in [specs] into a Dart library containing
2125
/// a renderer for each template.
2226
Future<String> compileTemplatesToRenderers(
@@ -62,8 +66,7 @@ Future<String> compileTemplatesToRenderers(
6266
// To change the contents of this library, make changes to the builder source
6367
// files in the tool/mustachio/ directory.
6468
65-
// There are a few deduplicated render functions which are generated but not
66-
// used.
69+
// Some deduplicated render functions are generated but not used.
6770
// TODO(srawlins): Detect these and do not write them.
6871
// ignore_for_file: unused_element
6972
// Sometimes we enter a new section which triggers creating a new variable, but
@@ -116,27 +119,23 @@ Future<Map<_AotCompiler, String>> _deduplicateRenderers(
116119
continue;
117120
}
118121
var firstCompiler = compilers.first;
119-
var contextStacksLength = firstCompiler._usedContexts.length;
120-
if (compilers.any((c) => c._usedContexts.length != contextStacksLength)) {
121-
// The stack lengths are different, it is impossible to deduplicate such
122-
// partial renderers.
122+
var contextStacks = compilers.map((c) => c._usedContextStack).toList();
123+
var contextStackTypes = typeSystem.contextStackLub(contextStacks);
124+
if (contextStackTypes == null) {
125+
// The stack lengths are different; it is impossible to fully deduplicate
126+
// such partial renderers.
123127
continue;
124128
}
125-
// The new list of context types, each of which is the LUB of the associated
126-
// context type of each of the compilers.
127-
var contextStackTypes = <InterfaceType>[];
128-
for (var i = 0; i < contextStacksLength; i++) {
129-
var types = compilers.map((c) => c._usedContextStack[i].type);
130-
var lubType = types.fold<DartType>(types.first,
131-
(value, type) => typeSystem.leastUpperBound(value, type))
132-
as InterfaceType;
133-
contextStackTypes.add(lubType);
134-
}
135129

136130
// Each of the render functions generated by a compiler for this asset can
137131
// be replaced by a more generic renderer which accepts the LUB types. The
138-
// body of each replaced renderer can perform a simple redirect.
132+
// body of each replaced renderer can perform a simple redirect to the more
133+
// generic renderer.
139134
var rendererName = filePath.replaceAll('.', '_').replaceAll('/', '_');
135+
136+
// The names of the renderers which are being replaced all include some
137+
// reference to the template/partial which referred to them; we must create
138+
// a new renderer name from scratch.
140139
var lubCompiler = _AotCompiler._(
141140
contextStackTypes.first,
142141
'_deduplicated_$rendererName',
@@ -250,12 +249,12 @@ class _AotCompiler {
250249
final Map<_AotCompiler, String> _compiledPartials = {};
251250

252251
/// The current stack of context objects (as variable lookups).
253-
final List<_VariableLookup> _contextStack;
252+
final ContextStack _contextStack;
254253

255254
/// The set of context objects which are ultimately used by this compiler.
256255
final Set<_VariableLookup> _usedContexts = {};
257256

258-
List<_VariableLookup> get _usedContextStack =>
257+
ContextStack get _usedContextStack =>
259258
[..._contextStack.where(_usedContexts.contains)];
260259

261260
/// A counter for naming partial render functions.
@@ -276,7 +275,7 @@ class _AotCompiler {
276275
String rendererName,
277276
String templatePath,
278277
_BuildData buildData, {
279-
List<_VariableLookup> contextStack = const [],
278+
ContextStack contextStack = const [],
280279
}) async {
281280
var template =
282281
await File(path.join(buildData._root, templatePath)).readAsString();
@@ -292,7 +291,7 @@ class _AotCompiler {
292291
this._templatePath,
293292
this._syntaxTree,
294293
this._buildData, {
295-
required List<_VariableLookup> contextStack,
294+
required ContextStack contextStack,
296295
}) : _contextStack = _rename(contextStack),
297296
_contextNameCounter = contextStack.length;
298297

@@ -301,7 +300,7 @@ class _AotCompiler {
301300
///
302301
/// This ensures that each renderer accepts a simple list of context objects
303302
/// with predictable names.
304-
static List<_VariableLookup> _rename(List<_VariableLookup> original) {
303+
static ContextStack _rename(ContextStack original) {
305304
var result = <_VariableLookup>[];
306305
var index = original.length - 1;
307306
for (var variable in original) {
@@ -391,7 +390,7 @@ class _AotCompiler {
391390
class _BlockCompiler {
392391
final _AotCompiler _templateCompiler;
393392

394-
final List<_VariableLookup> _contextStack;
393+
final ContextStack _contextStack;
395394

396395
final Set<_VariableLookup> _usedContextTypes = {};
397396

@@ -756,3 +755,27 @@ extension on StringBuffer {
756755
return referencedElements;
757756
}
758757
}
758+
759+
extension on TypeSystem {
760+
/// Returns a list of types which represents the LUB of each of the types in
761+
/// the corresponding positions in [contextStacks].
762+
List<InterfaceType>? contextStackLub(List<ContextStack> contextStacks) {
763+
// The length of each and every context stack.
764+
var contextStacksLength = contextStacks.first.length;
765+
if (contextStacks.any((s) => s.length != contextStacksLength)) {
766+
return null;
767+
}
768+
769+
// The new list of context types, each of which is the LUB of the associated
770+
// context type of each of the compilers.
771+
var contextStackTypes = <InterfaceType>[];
772+
for (var i = 0; i < contextStacksLength; i++) {
773+
var types = contextStacks.map((s) => s[i].type);
774+
var lubType =
775+
types.fold<DartType>(types.first, leastUpperBound) as InterfaceType;
776+
contextStackTypes.add(lubType);
777+
}
778+
779+
return contextStackTypes;
780+
}
781+
}

0 commit comments

Comments
 (0)