Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(217)

Side by Side Diff: pkg/front_end/lib/src/fasta/kernel/kernel_library_builder.dart

Issue 2862223002: Rewrite mixin application handling in Fasta. (Closed)
Patch Set: Update status file. Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library fasta.kernel_library_builder; 5 library fasta.kernel_library_builder;
6 6
7 import 'package:front_end/src/fasta/scanner/token.dart' show Token; 7 import 'package:front_end/src/fasta/scanner/token.dart' show Token;
8 8
9 import 'package:kernel/ast.dart'; 9 import 'package:kernel/ast.dart';
10 10
11 import 'package:kernel/clone.dart' show CloneVisitor; 11 import 'package:kernel/clone.dart' show CloneVisitor;
12 12
13 import '../errors.dart' show internalError; 13 import '../errors.dart' show internalError;
14 14
15 import '../loader.dart' show Loader; 15 import '../loader.dart' show Loader;
16 16
17 import '../modifier.dart' show abstractMask, staticMask; 17 import '../modifier.dart'
18 show abstractMask, namedMixinApplicationMask, staticMask;
18 19
19 import '../source/source_library_builder.dart' 20 import '../source/source_library_builder.dart'
20 show DeclarationBuilder, SourceLibraryBuilder; 21 show DeclarationBuilder, SourceLibraryBuilder;
21 22
22 import '../source/source_class_builder.dart' show SourceClassBuilder; 23 import '../source/source_class_builder.dart' show SourceClassBuilder;
23 24
24 import '../util/relativize.dart' show relativizeUri; 25 import '../util/relativize.dart' show relativizeUri;
25 26
26 import 'kernel_builder.dart' 27 import 'kernel_builder.dart'
27 show 28 show
28 AccessErrorBuilder, 29 AccessErrorBuilder,
29 Builder, 30 Builder,
30 BuiltinTypeBuilder, 31 BuiltinTypeBuilder,
31 ClassBuilder, 32 ClassBuilder,
32 ConstructorReferenceBuilder, 33 ConstructorReferenceBuilder,
33 FormalParameterBuilder, 34 FormalParameterBuilder,
34 FunctionTypeAliasBuilder, 35 FunctionTypeAliasBuilder,
35 InvalidTypeBuilder, 36 InvalidTypeBuilder,
36 KernelConstructorBuilder, 37 KernelConstructorBuilder,
37 KernelEnumBuilder, 38 KernelEnumBuilder,
38 KernelFieldBuilder, 39 KernelFieldBuilder,
39 KernelFormalParameterBuilder, 40 KernelFormalParameterBuilder,
40 KernelFunctionTypeAliasBuilder, 41 KernelFunctionTypeAliasBuilder,
41 KernelFunctionTypeBuilder, 42 KernelFunctionTypeBuilder,
42 KernelInvalidTypeBuilder, 43 KernelInvalidTypeBuilder,
43 KernelMixinApplicationBuilder, 44 KernelMixinApplicationBuilder,
44 KernelNamedMixinApplicationBuilder,
45 KernelNamedTypeBuilder, 45 KernelNamedTypeBuilder,
46 KernelProcedureBuilder, 46 KernelProcedureBuilder,
47 KernelTypeBuilder, 47 KernelTypeBuilder,
48 KernelTypeVariableBuilder, 48 KernelTypeVariableBuilder,
49 LibraryBuilder, 49 LibraryBuilder,
50 MemberBuilder, 50 MemberBuilder,
51 MetadataBuilder, 51 MetadataBuilder,
52 NamedMixinApplicationBuilder, 52 NamedTypeBuilder,
53 PrefixBuilder, 53 PrefixBuilder,
54 ProcedureBuilder, 54 ProcedureBuilder,
55 Scope, 55 Scope,
56 TypeBuilder, 56 TypeBuilder,
57 TypeVariableBuilder, 57 TypeVariableBuilder,
58 compareProcedures; 58 compareProcedures;
59 59
60 class KernelLibraryBuilder 60 class KernelLibraryBuilder
61 extends SourceLibraryBuilder<KernelTypeBuilder, Library> { 61 extends SourceLibraryBuilder<KernelTypeBuilder, Library> {
62 final Library library; 62 final Library library;
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
97 } 97 }
98 98
99 void addClass( 99 void addClass(
100 List<MetadataBuilder> metadata, 100 List<MetadataBuilder> metadata,
101 int modifiers, 101 int modifiers,
102 String className, 102 String className,
103 List<TypeVariableBuilder> typeVariables, 103 List<TypeVariableBuilder> typeVariables,
104 KernelTypeBuilder supertype, 104 KernelTypeBuilder supertype,
105 List<KernelTypeBuilder> interfaces, 105 List<KernelTypeBuilder> interfaces,
106 int charOffset) { 106 int charOffset) {
107 assert(currentDeclaration.parent == libraryDeclaration); 107 // Nested declaration began in `OutlineBuilder.beginClassDeclaration`.
108 Map<String, MemberBuilder> members = currentDeclaration.members; 108 var declaration = endNestedDeclaration()..resolveTypes(typeVariables, this);
109 Map<String, MemberBuilder> constructors = currentDeclaration.constructors; 109 assert(declaration.parent == libraryDeclaration);
110 Map<String, MemberBuilder> setters = currentDeclaration.setters; 110 Map<String, MemberBuilder> members = declaration.members;
111 Map<String, MemberBuilder> constructors = declaration.constructors;
112 Map<String, MemberBuilder> setters = declaration.setters;
111 113
112 Scope classScope = new Scope( 114 Scope classScope = new Scope(
113 members, setters, scope.withTypeVariables(typeVariables), 115 members, setters, scope.withTypeVariables(typeVariables),
114 isModifiable: false); 116 isModifiable: false);
115 117
116 // When looking up a constructor, we don't consider type variables or the 118 // When looking up a constructor, we don't consider type variables or the
117 // library scope. 119 // library scope.
118 Scope constructorScope = 120 Scope constructorScope =
119 new Scope(constructors, null, null, isModifiable: false); 121 new Scope(constructors, null, null, isModifiable: false);
120 ClassBuilder cls = new SourceClassBuilder( 122 ClassBuilder cls = new SourceClassBuilder(
121 metadata, 123 metadata,
122 modifiers, 124 modifiers,
123 className, 125 className,
124 typeVariables, 126 typeVariables,
125 supertype, 127 applyMixins(supertype,
128 subclassName: className, typeVariables: typeVariables),
126 interfaces, 129 interfaces,
127 classScope, 130 classScope,
128 constructorScope, 131 constructorScope,
129 this, 132 this,
130 new List<ConstructorReferenceBuilder>.from(constructorReferences), 133 new List<ConstructorReferenceBuilder>.from(constructorReferences),
131 charOffset); 134 charOffset);
132 constructorReferences.clear(); 135 constructorReferences.clear();
136 Map<String, TypeVariableBuilder> typeVariablesByName =
137 checkTypeVariables(typeVariables, cls);
133 void setParent(String name, MemberBuilder member) { 138 void setParent(String name, MemberBuilder member) {
134 while (member != null) { 139 while (member != null) {
135 member.parent = cls; 140 member.parent = cls;
136 member = member.next; 141 member = member.next;
137 } 142 }
138 } 143 }
139 144
140 members.forEach(setParent); 145 void setParentAndCheckConflicts(String name, MemberBuilder member) {
141 constructors.forEach(setParent); 146 if (typeVariablesByName != null) {
147 TypeVariableBuilder tv = typeVariablesByName[name];
148 if (tv != null) {
149 cls.addCompileTimeError(
150 member.charOffset, "Conflict with type variable '$name'.");
151 cls.addCompileTimeError(tv.charOffset, "This is the type variable.");
152 }
153 }
154 setParent(name, member);
155 }
156
157 members.forEach(setParentAndCheckConflicts);
158 constructors.forEach(setParentAndCheckConflicts);
159 // Formally, a setter has the name `id=`, so it can never conflict with a
160 // type variable.
142 setters.forEach(setParent); 161 setters.forEach(setParent);
143 // Nested declaration began in `OutlineBuilder.beginClassDeclaration`.
144 endNestedDeclaration().resolveTypes(typeVariables, this);
145 addBuilder(className, cls, charOffset); 162 addBuilder(className, cls, charOffset);
146 } 163 }
147 164
165 Map<String, TypeVariableBuilder> checkTypeVariables(
166 List<TypeVariableBuilder> typeVariables, Builder owner) {
167 if (typeVariables?.isEmpty ?? true) return null;
168 Map<String, TypeVariableBuilder> typeVariablesByName =
169 <String, TypeVariableBuilder>{};
170 for (TypeVariableBuilder tv in typeVariables) {
171 TypeVariableBuilder existing = typeVariablesByName[tv.name];
172 if (existing != null) {
173 addCompileTimeError(tv.charOffset,
174 "A type variable can't have the same name as another.");
175 addCompileTimeError(
176 existing.charOffset, "The other type variable named '${tv.name}'.");
177 } else {
178 typeVariablesByName[tv.name] = tv;
179 if (owner is ClassBuilder) {
180 // Only classes and type variables can't have the same name. See
181 // [#29555](https://github.com/dart-lang/sdk/issues/29555).
182 if (tv.name == owner.name) {
183 addCompileTimeError(
184 tv.charOffset,
185 "A type variable can't have the same name as its enclosing "
186 "declaration.");
187 }
188 }
189 }
190 }
191 return typeVariablesByName;
192 }
193
194 KernelTypeBuilder applyMixin(
195 KernelTypeBuilder supertype, KernelTypeBuilder mixin, String signature,
196 {List<MetadataBuilder> metadata,
197 String name,
198 List<TypeVariableBuilder> typeVariables,
199 int modifiers: abstractMask,
200 List<KernelTypeBuilder> interfaces,
201 int charOffset: -1}) {
202 var constructors = <String, MemberBuilder>{};
203 bool isNamed = name != null;
204 SourceClassBuilder builder;
205 if (isNamed) {
206 modifiers |= namedMixinApplicationMask;
207 } else {
208 name = supertype.name;
209 int index = name.indexOf("^");
210 if (index != -1) {
211 name = name.substring(0, index);
212 }
213 name = "$name&${mixin.name}$signature";
214 builder = mixinApplicationClasses[name];
215 }
216 if (builder == null) {
217 builder = new SourceClassBuilder(
218 metadata,
219 modifiers,
220 name,
221 typeVariables,
222 supertype,
223 interfaces,
224 new Scope(<String, MemberBuilder>{}, <String, MemberBuilder>{},
225 scope.withTypeVariables(typeVariables),
226 isModifiable: false),
227 new Scope(constructors, null, null, isModifiable: false),
228 this,
229 <ConstructorReferenceBuilder>[],
230 charOffset,
231 null,
232 mixin);
233 addBuilder(name, builder, charOffset);
234 if (!isNamed) {
235 mixinApplicationClasses[name] = builder;
236 }
237 }
238 return addNamedType(name, <KernelTypeBuilder>[], charOffset)
239 ..bind(isNamed ? builder : null);
240 }
241
242 KernelTypeBuilder applyMixins(KernelTypeBuilder type,
243 {List<MetadataBuilder> metadata,
244 String name,
245 String subclassName,
246 List<TypeVariableBuilder> typeVariables,
247 int modifiers: abstractMask,
248 List<KernelTypeBuilder> interfaces,
249 int charOffset: -1}) {
250 if (type is KernelMixinApplicationBuilder) {
251 subclassName ??= name;
252 List<List<String>> signatureParts = <List<String>>[];
253 Map<String, String> unresolved = <String, String>{};
254 Map<String, String> unresolvedReversed = <String, String>{};
255 int unresolvedCount = 0;
256 Map<String, TypeBuilder> freeTypes = <String, TypeBuilder>{};
257
258 if (name == null || type.mixins.length != 1) {
259 TypeBuilder last = type.mixins.last;
260
261 /// Compute a signature of the type arguments used by the supertype and
262 /// mixins. These types are free variables. At this point we can't
263 /// trust that the number of type arguments match the type parameters,
264 /// so we also need to be able to detect missing type arguments. To do
265 /// so, we separate each list of type arguments by `^` and type
266 /// arguments by `&`. For example, the mixin `C<S> with M<T, U>` would
267 /// look like this:
268 ///
269 /// ^#U0^#U1&#U2
270 ///
271 /// Where `#U0`, `#U1`, and `#U2` are the free variables arising from
272 /// `S`, `T`, and `U` respectively.
273 ///
274 /// As we can resolve any type parameters used at this point, those are
275 /// named `#T0` and so forth. This reduces the number of free variables
276 /// which is crucial for memory usage and the Dart VM's bootstrap
277 /// sequence.
278 ///
279 /// For example, consider this use of mixin applications:
280 ///
281 /// class _InternalLinkedHashMap<K, V> extends _HashVMBase
282 /// with
283 /// MapMixin<K, V>,
284 /// _LinkedHashMapMixin<K, V>,
285 /// _HashBase,
286 /// _OperatorEqualsAndHashCode {}
287 ///
288 /// In this case, only two variables are free, and we produce this
289 /// signature: `^^#T0&#T1^#T0&#T1^^`. Assume another class uses the
290 /// sames mixins but with missing type arguments for `MapMixin`, its
291 /// signature would be: `^^^#T0&#T1^^`.
292 ///
293 /// Note that we do not need to compute a signature for a named mixin
294 /// application with only one mixin as we don't have to invent a name
295 /// for any classes in this situation.
296 void analyzeArguments(TypeBuilder type) {
297 if (name != null && type == last) {
298 // The last mixin of a named mixin application doesn't contribute
299 // to free variables.
300 return;
301 }
302 if (type is NamedTypeBuilder) {
303 List<String> part = <String>[];
304 for (int i = 0; i < (type.arguments?.length ?? 0); i++) {
305 var argument = type.arguments[i];
306 String name;
307 if (argument is NamedTypeBuilder) {
308 if (argument.builder != null) {
309 int index = typeVariables?.indexOf(argument.builder) ?? -1;
310 if (index != -1) {
311 name = "#T${index}";
312 }
313 } else if (argument.arguments == null) {
314 name = unresolved[argument.name] ??= "#U${unresolvedCount++}";
315 }
316 }
317 name ??= "#U${unresolvedCount++}";
318 unresolvedReversed[name] = argument.name;
319 freeTypes[name] = argument;
320 part.add(name);
321 type.arguments[i] =
322 new KernelNamedTypeBuilder(name, null, -1, fileUri);
323 }
324 signatureParts.add(part);
325 }
326 }
327
328 analyzeArguments(type.supertype);
329 type.mixins.forEach(analyzeArguments);
330 }
331 KernelTypeBuilder supertype = type.supertype;
332 List<List<String>> currentSignatureParts = <List<String>>[];
333 int currentSignatureCount = 0;
334 String computeSignature() {
335 if (freeTypes.isEmpty) return "";
336 currentSignatureParts.add(signatureParts[currentSignatureCount++]);
337 if (currentSignatureParts.any((l) => l.isNotEmpty)) {
338 return "^${currentSignatureParts.map((l) => l.join('&')).join('^')}";
339 } else {
340 return "";
341 }
342 }
343
344 Map<String, TypeVariableBuilder> computeTypeVariables() {
345 Map<String, TypeVariableBuilder> variables =
346 <String, TypeVariableBuilder>{};
347 for (List<String> strings in currentSignatureParts) {
348 for (String name in strings) {
349 variables[name] ??= addTypeVariable(name, null, -1);
350 }
351 }
352 return variables;
353 }
354
355 checkArguments(t) {
356 for (var argument in t.arguments ?? const []) {
357 if (argument.builder == null && argument.name.startsWith("#")) {
358 throw "No builder on ${argument.name}";
359 }
360 }
361 }
362
363 computeSignature(); // This combines the supertype with the first mixin.
364 for (int i = 0; i < type.mixins.length - 1; i++) {
365 Set<String> supertypeArguments = new Set<String>();
366 for (var part in currentSignatureParts) {
367 supertypeArguments.addAll(part);
368 }
369 String signature = computeSignature();
370 var variables = computeTypeVariables();
371 if (supertypeArguments.isNotEmpty) {
372 supertype = addNamedType(
373 supertype.name,
374 supertypeArguments
375 .map((n) => addNamedType(n, null, -1)..bind(variables[n]))
376 .toList(),
377 -1);
378 }
379 KernelNamedTypeBuilder mixin = type.mixins[i];
380 for (var type in mixin.arguments ?? const []) {
381 type.bind(variables[type.name]);
382 }
383 checkArguments(supertype);
384 checkArguments(mixin);
385 supertype = applyMixin(supertype, mixin, signature,
386 typeVariables:
387 new List<TypeVariableBuilder>.from(variables.values));
388 }
389 KernelNamedTypeBuilder mixin = type.mixins.last;
390
391 Set<String> supertypeArguments = new Set<String>();
392 for (var part in currentSignatureParts) {
393 supertypeArguments.addAll(part);
394 }
395 String signature = name == null ? computeSignature() : "";
396 var variables;
397 if (name == null) {
398 variables = computeTypeVariables();
399 typeVariables = new List<TypeVariableBuilder>.from(variables.values);
400 if (supertypeArguments.isNotEmpty) {
401 supertype = addNamedType(
402 supertype.name,
403 supertypeArguments
404 .map((n) => addNamedType(n, null, -1)..bind(variables[n]))
405 .toList(),
406 -1);
407 }
408 } else {
409 if (supertypeArguments.isNotEmpty) {
410 supertype = addNamedType(supertype.name,
411 supertypeArguments.map((n) => freeTypes[n]).toList(), -1);
412 }
413 }
414
415 if (name == null) {
416 for (var type in mixin.arguments ?? const []) {
417 type.bind(variables[type.name]);
418 }
419 }
420 checkArguments(supertype);
421 checkArguments(mixin);
422
423 KernelNamedTypeBuilder t = applyMixin(supertype, mixin, signature,
424 metadata: metadata,
425 name: name,
426 typeVariables: typeVariables,
427 modifiers: modifiers,
428 interfaces: interfaces,
429 charOffset: charOffset);
430 if (name == null) {
431 var builder = t.builder;
432 t = addNamedType(
433 t.name, freeTypes.keys.map((k) => freeTypes[k]).toList(), -1);
434 if (builder != null) {
435 t.bind(builder);
436 }
437 }
438 return t;
439 } else {
440 return type;
441 }
442 }
443
148 void addNamedMixinApplication( 444 void addNamedMixinApplication(
149 List<MetadataBuilder> metadata, 445 List<MetadataBuilder> metadata,
150 String name, 446 String name,
151 List<TypeVariableBuilder> typeVariables, 447 List<TypeVariableBuilder> typeVariables,
152 int modifiers, 448 int modifiers,
153 KernelTypeBuilder mixinApplication, 449 KernelTypeBuilder mixinApplication,
154 List<KernelTypeBuilder> interfaces, 450 List<KernelTypeBuilder> interfaces,
155 int charOffset) { 451 int charOffset) {
156 NamedMixinApplicationBuilder builder =
157 new KernelNamedMixinApplicationBuilder(metadata, name, typeVariables,
158 modifiers, mixinApplication, interfaces, this, charOffset);
159 // Nested declaration began in `OutlineBuilder.beginNamedMixinApplication`. 452 // Nested declaration began in `OutlineBuilder.beginNamedMixinApplication`.
160 endNestedDeclaration().resolveTypes(typeVariables, this); 453 endNestedDeclaration().resolveTypes(typeVariables, this);
161 addBuilder(name, builder, charOffset); 454 KernelNamedTypeBuilder supertype = applyMixins(mixinApplication,
455 metadata: metadata,
456 name: name,
457 typeVariables: typeVariables,
458 modifiers: modifiers,
459 interfaces: interfaces,
460 charOffset: charOffset);
461 checkTypeVariables(typeVariables, supertype.builder);
162 } 462 }
163 463
164 void addField(List<MetadataBuilder> metadata, int modifiers, 464 void addField(List<MetadataBuilder> metadata, int modifiers,
165 KernelTypeBuilder type, String name, int charOffset, Token initializer) { 465 KernelTypeBuilder type, String name, int charOffset, Token initializer) {
166 addBuilder( 466 addBuilder(
167 name, 467 name,
168 new KernelFieldBuilder( 468 new KernelFieldBuilder(
169 metadata, type, name, modifiers, this, charOffset, initializer), 469 metadata, type, name, modifiers, this, charOffset, initializer),
170 charOffset); 470 charOffset);
171 } 471 }
(...skipping 363 matching lines...) Expand 10 before | Expand all | Expand 10 after
535 int count = boundlessTypeVariables.length; 835 int count = boundlessTypeVariables.length;
536 for (KernelTypeVariableBuilder builder in boundlessTypeVariables) { 836 for (KernelTypeVariableBuilder builder in boundlessTypeVariables) {
537 builder.finish(this, object); 837 builder.finish(this, object);
538 } 838 }
539 boundlessTypeVariables.clear(); 839 boundlessTypeVariables.clear();
540 return count; 840 return count;
541 } 841 }
542 842
543 @override 843 @override
544 void includePart(covariant KernelLibraryBuilder part) { 844 void includePart(covariant KernelLibraryBuilder part) {
845 part.mixinApplicationClasses
846 .forEach((String name, SourceClassBuilder builder) {
847 SourceClassBuilder existing =
848 mixinApplicationClasses.putIfAbsent(name, () => builder);
849 if (existing != builder) {
850 part.scope.local.remove(name);
851 }
852 });
545 super.includePart(part); 853 super.includePart(part);
546 nativeMethods.addAll(part.nativeMethods); 854 nativeMethods.addAll(part.nativeMethods);
547 boundlessTypeVariables.addAll(part.boundlessTypeVariables); 855 boundlessTypeVariables.addAll(part.boundlessTypeVariables);
548 assert(mixinApplicationClasses.isEmpty);
549 } 856 }
550 } 857 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698