@@ -61,8 +61,6 @@ class ClosureRepresentation {
6161 /// The struct type for the context of an instantiated closure.
6262 final w.StructType ? instantiationContextStruct;
6363
64- final String exportSuffix;
65-
6664 /// Entry point functions for instantiations of this generic closure.
6765 final Map <w.ModuleBuilder , List <w.BaseFunction >> _instantiationTrampolines =
6866 {};
@@ -121,8 +119,7 @@ class ClosureRepresentation {
121119 this .vtableStruct,
122120 this .closureStruct,
123121 this ._indexOfCombination,
124- this .instantiationContextStruct,
125- this .exportSuffix);
122+ this .instantiationContextStruct);
126123
127124 bool get isGeneric => typeCount > 0 ;
128125
@@ -265,8 +262,8 @@ class ClosureLayouter extends RecursiveVisitor {
265262 late final w.StructType closureBaseStruct = _makeClosureStruct (
266263 "#ClosureBase" , _vtableBaseStructBare, translator.closureInfo.struct);
267264
268- late final w.RefType typeType =
269- translator.classInfo[translator.typeClass] ! .nonNullableType;
265+ w.RefType get typeType => translator.types.nonNullableTypeType;
266+
270267 late final w.RefType functionTypeType =
271268 translator.classInfo[translator.functionTypeClass]! .nonNullableType;
272269
@@ -469,8 +466,7 @@ class ClosureLayouter extends RecursiveVisitor {
469466 vtableStruct,
470467 closureStruct,
471468 indexOfCombination,
472- instantiationContextStruct,
473- nameTags.join ('-' ));
469+ instantiationContextStruct);
474470
475471 if (typeCount > 0 ) {
476472 // The instantiation trampolines and the instantiation function can't be
@@ -1073,10 +1069,15 @@ class Context {
10731069 Context (this .owner, this .parent, this .containsThis);
10741070}
10751071
1076- /// A captured variable.
1072+ /// A captured variable or type parameter .
10771073class Capture {
1074+ /// The captured [VariableDeclaration] or [TypeParameter] .
10781075 final TreeNode variable;
1076+
10791077 late final Context context;
1078+
1079+ /// The index of the captured variable or type parameter in its context
1080+ /// struct.
10801081 late final int fieldIndex;
10811082
10821083 /// Whether the captured variable is updated after initialization.
@@ -1086,39 +1087,76 @@ class Capture {
10861087 /// context.
10871088 bool written = false ;
10881089
1089- Capture (this .variable);
1090+ Capture (this .variable) {
1091+ assert (variable is VariableDeclaration || variable is TypeParameter );
1092+ }
10901093
10911094 w.ValueType get type => context.struct.fields[fieldIndex].type.unpacked;
10921095}
10931096
1094- /// Compiler passes to find all captured variables and construct the context
1095- /// tree for a member.
1097+ /// Information about contexts and closures of a member.
10961098class Closures {
10971099 final Translator translator;
1098- final Class ? enclosingClass;
1099- final Map < TreeNode , Capture > captures = {};
1100- bool isThisCaptured = false ;
1100+
1101+ /// Maps [FunctionDeclaration] s and [FunctionExpression] s in the member to
1102+ /// [Lambda] s.
11011103 final Map <FunctionNode , Lambda > lambdas = {};
1102- late final w.RefType ? nullableThisType;
11031104
1104- // This [TreeNode] is the context owner, and can be a [FunctionNode],
1105- // [Constructor], [ForStatement], [DoStatement] or a [WhileStatement].
1105+ /// Maps [VariableDeclaration] s and [TypeParameter] s in the member to
1106+ /// [Capture] s.
1107+ final Map <TreeNode , Capture > captures = {};
1108+
1109+ /// Maps AST nodes with contexts to their contexts.
1110+ ///
1111+ /// AST nodes that can have a context are:
1112+ ///
1113+ /// - [FunctionNode]
1114+ /// - [Constructor]
1115+ /// - [ForStatement]
1116+ /// - [DoStatement]
1117+ /// - [WhileStatement]
11061118 final Map <TreeNode , Context > contexts = {};
1119+
1120+ /// Set of function declarations in the member that need to be compiled as
1121+ /// closures. These functions are used as variables. Example:
1122+ /// ```
1123+ /// void f() {
1124+ /// void g () {}
1125+ /// print(g);
1126+ /// }
1127+ /// ```
1128+ /// In the `Closures` for `f` , `g` will be in this set.
11071129 final Set <FunctionDeclaration > closurizedFunctions = {};
11081130
1109- Closures (this .translator, Member member)
1110- : enclosingClass = member.enclosingClass {
1111- final hasThis = member is Constructor || member.isInstanceMember;
1112- nullableThisType = hasThis
1113- ? translator.preciseThisFor (member, nullable: true ) as w.RefType
1114- : null ;
1131+ final Member _member;
1132+
1133+ /// Whether the member captures `this` . Set by [_CaptureFinder] .
1134+ bool _isThisCaptured = false ;
1135+
1136+ /// When the member is a constructor or an instance member, nullable type of
1137+ /// `this` .
1138+ final w.RefType ? _nullableThisType;
1139+
1140+ /// When `findCaptures` is `false` , this does not analyze the member body and
1141+ /// does not populate [lambdas] , [contexts] , [captures] , and
1142+ /// [closurizedFunctions] . This mode is useful in the code generators that
1143+ /// always have direct access to variables (instead of via a context).
1144+ Closures (this .translator, this ._member, {bool findCaptures = true })
1145+ : _nullableThisType = _member is Constructor || _member.isInstanceMember
1146+ ? translator.preciseThisFor (_member, nullable: true ) as w.RefType
1147+ : null {
1148+ if (findCaptures) {
1149+ _findCaptures ();
1150+ _collectContexts ();
1151+ _buildContexts ();
1152+ }
11151153 }
11161154
1117- late final w.ValueType typeType =
1118- translator.classInfo[translator.typeClass]! .nonNullableType;
1155+ w.RefType get typeType => translator.types.nonNullableTypeType;
11191156
1120- void findCaptures (Member member) {
1121- var find = CaptureFinder (this , member);
1157+ void _findCaptures () {
1158+ final member = _member;
1159+ final find = _CaptureFinder (this , member);
11221160 if (member is Constructor ) {
11231161 Class cls = member.enclosingClass;
11241162 for (Field field in cls.fields) {
@@ -1130,62 +1168,63 @@ class Closures {
11301168 member.accept (find);
11311169 }
11321170
1133- void collectContexts ( TreeNode node ) {
1134- if (captures.isNotEmpty || isThisCaptured ) {
1135- node .accept (ContextCollector (this , translator.options.enableAsserts));
1171+ void _collectContexts ( ) {
1172+ if (captures.isNotEmpty || _isThisCaptured ) {
1173+ _member .accept (_ContextCollector (this , translator.options.enableAsserts));
11361174 }
11371175 }
11381176
1139- void buildContexts () {
1177+ void _buildContexts () {
11401178 // Make struct definitions
11411179 for (Context context in contexts.values) {
1142- if (! context.isEmpty) {
1143- if (context.owner is Constructor ) {
1144- Constructor constructor = context.owner as Constructor ;
1145- context.struct = translator.typesBuilder
1146- . defineStruct ( "<$ constructor -constructor-context>" );
1147- } else if (context. owner.parent is Constructor ) {
1148- Constructor constructor = context. owner.parent as Constructor ;
1149- context.struct = translator.typesBuilder
1150- . defineStruct ( "<$ constructor -constructor-body-context>" );
1151- } else {
1152- context.struct = translator.typesBuilder
1153- . defineStruct ( "< context ${ context . owner . location }>" );
1154- }
1180+ if (context.isEmpty) continue ;
1181+
1182+ final owner = context.owner;
1183+ if (owner is Constructor ) {
1184+ context.struct = translator.typesBuilder
1185+ . defineStruct ( "<$ owner -constructor-context>" );
1186+ } else if ( owner.parent is Constructor ) {
1187+ Constructor constructor = owner.parent as Constructor ;
1188+ context.struct = translator.typesBuilder
1189+ . defineStruct ( "<$ constructor -constructor-body-context>" );
1190+ } else {
1191+ context.struct =
1192+ translator.typesBuilder. defineStruct ( "<context ${ owner . location }>" );
11551193 }
11561194 }
11571195
11581196 // Build object layouts
11591197 for (Context context in contexts.values) {
1160- if (! context.isEmpty) {
1161- w.StructType struct = context.struct;
1162- if (context.parent != null ) {
1163- assert (! context.parent! .isEmpty);
1164- struct.fields.add (w.FieldType (
1165- w.RefType .def (context.parent! .struct, nullable: true )));
1166- }
1167- if (context.containsThis) {
1168- assert (enclosingClass != null );
1169- struct.fields.add (w.FieldType (nullableThisType! ));
1170- }
1171- for (VariableDeclaration variable in context.variables) {
1172- int index = struct.fields.length;
1173- struct.fields.add (w.FieldType (translator
1174- .translateTypeOfLocalVariable (variable)
1175- .withNullability (true )));
1176- captures[variable]! .fieldIndex = index;
1177- }
1178- for (TypeParameter parameter in context.typeParameters) {
1179- int index = struct.fields.length;
1180- struct.fields.add (w.FieldType (typeType.withNullability (true )));
1181- captures[parameter]! .fieldIndex = index;
1182- }
1198+ if (context.isEmpty) continue ;
1199+
1200+ w.StructType struct = context.struct;
1201+ final parent = context.parent;
1202+ if (parent != null ) {
1203+ assert (! parent.isEmpty);
1204+ struct.fields
1205+ .add (w.FieldType (w.RefType .def (parent.struct, nullable: true )));
1206+ }
1207+ if (context.containsThis) {
1208+ assert (_member.enclosingClass != null );
1209+ struct.fields.add (w.FieldType (_nullableThisType! ));
1210+ }
1211+ for (VariableDeclaration variable in context.variables) {
1212+ int index = struct.fields.length;
1213+ struct.fields.add (w.FieldType (translator
1214+ .translateTypeOfLocalVariable (variable)
1215+ .withNullability (true )));
1216+ captures[variable]! .fieldIndex = index;
1217+ }
1218+ for (TypeParameter parameter in context.typeParameters) {
1219+ int index = struct.fields.length;
1220+ struct.fields.add (w.FieldType (typeType.withNullability (true )));
1221+ captures[parameter]! .fieldIndex = index;
11831222 }
11841223 }
11851224 }
11861225}
11871226
1188- class CaptureFinder extends RecursiveVisitor {
1227+ class _CaptureFinder extends RecursiveVisitor {
11891228 final Closures closures;
11901229 final Member member;
11911230
@@ -1196,7 +1235,7 @@ class CaptureFinder extends RecursiveVisitor {
11961235
11971236 int get depth => functionIsSyncStarOrAsync.length - 1 ;
11981237
1199- CaptureFinder (this .closures, this .member)
1238+ _CaptureFinder (this .closures, this .member)
12001239 : _currentSource =
12011240 member.enclosingComponent! .uriToSource[member.fileUri]! ;
12021241
@@ -1259,6 +1298,8 @@ class CaptureFinder extends RecursiveVisitor {
12591298 if (functionIsSyncStarOrAsync[declDepth]) capture.written = true ;
12601299 } else if (variable is VariableDeclaration &&
12611300 variable.parent is FunctionDeclaration ) {
1301+ // Variable is for a function declaration, the function needs to be
1302+ // compiled as a closure.
12621303 closures.closurizedFunctions.add (variable.parent as FunctionDeclaration );
12631304 }
12641305 }
@@ -1277,7 +1318,7 @@ class CaptureFinder extends RecursiveVisitor {
12771318
12781319 void _visitThis () {
12791320 if (depth > 0 || functionIsSyncStarOrAsync[0 ]) {
1280- closures.isThisCaptured = true ;
1321+ closures._isThisCaptured = true ;
12811322 }
12821323 }
12831324
@@ -1365,12 +1406,12 @@ class CaptureFinder extends RecursiveVisitor {
13651406 }
13661407}
13671408
1368- class ContextCollector extends RecursiveVisitor {
1409+ class _ContextCollector extends RecursiveVisitor {
13691410 final Closures closures;
13701411 Context ? currentContext;
13711412 final bool enableAsserts;
13721413
1373- ContextCollector (this .closures, this .enableAsserts);
1414+ _ContextCollector (this .closures, this .enableAsserts);
13741415
13751416 @override
13761417 void visitAssertStatement (AssertStatement node) {
@@ -1393,7 +1434,7 @@ class ContextCollector extends RecursiveVisitor {
13931434 while (parent != null && parent.isEmpty) {
13941435 parent = parent.parent;
13951436 }
1396- bool containsThis = closures.isThisCaptured && outerMost;
1437+ bool containsThis = closures._isThisCaptured && outerMost;
13971438 currentContext = Context (node, parent, containsThis);
13981439 closures.contexts[node] = currentContext! ;
13991440 node.visitChildren (this );
@@ -1438,7 +1479,7 @@ class ContextCollector extends RecursiveVisitor {
14381479 // Some type arguments or variables have been captured by the
14391480 // initializer list.
14401481
1441- if (closures.isThisCaptured ) {
1482+ if (closures._isThisCaptured ) {
14421483 // In this case, we need two contexts: a constructor context to store
14431484 // the captured arguments/type parameters (shared by the initializer
14441485 // and constructor body, and a separate context just for the
@@ -1467,7 +1508,7 @@ class ContextCollector extends RecursiveVisitor {
14671508 // (node.function) for debugging purposes, and drop the
14681509 // constructor allocator context as it is not used.
14691510 final Context constructorBodyContext =
1470- Context (node.function, null , closures.isThisCaptured );
1511+ Context (node.function, null , closures._isThisCaptured );
14711512 currentContext = constructorBodyContext;
14721513
14731514 node.function.body? .accept (this );
0 commit comments