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

Side by Side Diff: pkg/kernel/lib/transformations/reify/transformation/builder.dart

Issue 2697873007: Merge the work on Generic Types Reification from 'dart-lang/reify' repo (Closed)
Patch Set: Get back parameter erroneously removed by previous commit Created 3 years, 10 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
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 library kernel.transformations.reify.transformation.builder;
6
7 import '../asts.dart';
8 import 'package:kernel/ast.dart';
9 import 'dart:collection' show LinkedHashMap;
10 import 'binding.dart' show RuntimeLibrary;
11 import 'package:kernel/core_types.dart' show CoreTypes;
12
13 class Scope {
14 final Map<String, TreeNode> names = <String, TreeNode>{};
15
16 bool nameAlreadyTaken(String name, TreeNode node) {
17 TreeNode existing = names[name];
18 return existing != null && existing == node;
19 }
20
21 void add(String name, TreeNode node) {
22 assert(!nameAlreadyTaken(name, node));
23 names[name] = node;
24 }
25 }
26
27 class Namer {
28 final Scope scope;
29 Namer([Scope scope]) : this.scope = scope ?? new Scope();
30
31 String _getProposal(TreeNode node) {
32 if (node is Class) {
33 return node.name;
34 }
35 throw 'unsupported node: $node';
36 }
37
38 String getNameFor(TreeNode node) {
39 String base = _getProposal(node);
40 int id = 0;
41 String proposal = base;
42 while (scope.nameAlreadyTaken(proposal, node)) {
43 proposal = "$base${++id}";
44 }
45 scope.add(proposal, node);
46 return proposal;
47 }
48 }
49
50 class RuntimeTypeSupportBuilder {
51 // TODO(karlklose): group this together with other information about what
52 // needs to be built.
53 final LinkedHashMap<Class, int> reifiedClassIds =
54 new LinkedHashMap<Class, int>();
55
56 int currentDeclarationId = 0;
57
58 final Field declarations;
59
60 final RuntimeLibrary rtiLibrary;
61
62 final CoreTypes coreTypes;
63
64 final DartType declarationType;
65
66 RuntimeTypeSupportBuilder(
67 RuntimeLibrary rtiLibrary, CoreTypes coreTypes, Library mainLibrary)
68 : declarations = new Field(new Name(r"$declarations"),
69 isFinal: true, isStatic: true, fileUri: mainLibrary.fileUri),
70 declarationType = new InterfaceType(coreTypes.listClass,
71 <DartType>[rtiLibrary.declarationClass.rawType]),
72 rtiLibrary = rtiLibrary,
73 coreTypes = coreTypes {
74 mainLibrary.addMember(declarations);
75 }
76
77 int addDeclaration(Class cls) {
78 return reifiedClassIds.putIfAbsent(cls, () {
79 return currentDeclarationId++;
80 });
81 }
82
83 final Name indexOperatorName = new Name("[]");
84
85 MethodInvocation createArrayAccess(Expression target, int index) {
86 return new MethodInvocation(target, indexOperatorName,
87 new Arguments(<Expression>[new IntLiteral(index)]));
88 }
89
90 Expression createAccessDeclaration(Class cls) {
91 return createArrayAccess(new StaticGet(declarations), addDeclaration(cls));
92 }
93
94 Name getTypeTestTagName(Class cls) {
95 return new Name('\$is\$${cls.name}');
96 }
97
98 Name typeVariableGetterName(TypeParameter parameter) {
99 Class cls = getEnclosingClass(parameter);
100 return new Name("\$${cls.name}\$${parameter.name}");
101 }
102
103 // A call to a constructor or factory of a class that we have not transformed
104 // is wrapped in a call to `attachType`.
105 Expression attachTypeToConstructorInvocation(
106 InvocationExpression invocation, Member member) {
107 assert(member is Procedure && member.kind == ProcedureKind.Factory ||
108 member is Constructor);
109 Class targetClass = member.parent;
110 assert(targetClass != null);
111 DartType type = new InterfaceType(targetClass, invocation.arguments.types);
112 return callAttachType(invocation, type);
113 }
114
115 Expression callAttachType(Expression expression, DartType type) {
116 return new StaticInvocation(rtiLibrary.attachTypeFunction,
117 new Arguments(<Expression>[expression, createRuntimeType(type)]));
118 }
119
120 Expression createGetType(Expression receiver, {needsInterceptor: true}) {
121 if (receiver is ThisExpression || !needsInterceptor) {
122 return new PropertyGet(receiver, rtiLibrary.runtimeTypeName);
123 }
124 return new StaticInvocation(
125 rtiLibrary.interceptorFunction, new Arguments(<Expression>[receiver]));
126 }
127
128 Expression createGetTypeArguments(Expression typeObject) {
129 return new StaticInvocation(rtiLibrary.typeArgumentsFunction,
130 new Arguments(<Expression>[typeObject]));
131 }
132
133 // TODO(karlklose): consider adding a unique identifier for each test site.
134 /// `receiver.[subtypeTestName]([type])`
135 StaticInvocation createIsSubtypeOf(
136 Expression receiver, Expression typeExpression,
137 {targetHasTypeProperty: false}) {
138 Expression receiverType =
139 createGetType(receiver, needsInterceptor: !targetHasTypeProperty);
140 return new StaticInvocation(rtiLibrary.isSubtypeOfFunction,
141 new Arguments(<Expression>[receiverType, typeExpression]));
142 }
143
144 int getTypeVariableIndex(TypeParameter variable) {
145 Class c = getEnclosingClass(variable);
146 List<TypeParameter> variables = c.typeParameters;
147 for (int i = 0; i < variables.length; ++i) {
148 if (variables[i].name == variable.name) {
149 return i;
150 }
151 }
152 throw new Exception(
153 "Type variable $variable not found in enclosing class $c");
154 }
155
156 Expression createNewInterface(
157 Expression declaration, Expression typeArgumentList) {
158 List<Expression> arguments = <Expression>[declaration];
159 if (typeArgumentList != null) {
160 arguments.add(typeArgumentList);
161 }
162 return new ConstructorInvocation(
163 rtiLibrary.interfaceTypeConstructor, new Arguments(arguments));
164 }
165
166 /// Returns `true` if [types] is a list of [TypeParameterType]s that exactly
167 /// match the [TypeParameters] of the class they are defined in, i.e.,
168 /// for all 0 <= i < cls.typeParameters.length.
169 /// types[i].parameter == cls.typeParameters[i].
170 bool matchesTypeParameters(List<DartType> types) {
171 List<TypeParameter> parameters;
172 for (int i = 0; i < types.length; ++i) {
173 var type = types[i];
174 if (type is TypeParameterType) {
175 if (parameters == null) {
176 Class cls = getEnclosingClass(type.parameter);
177 parameters = cls.typeParameters;
178 if (parameters.length != types.length) return false;
179 }
180 if (type.parameter != parameters[i]) {
181 return false;
182 }
183 } else {
184 return false;
185 }
186 }
187 return true;
188 }
189
190 // TODO(karlklose): Refactor into visitor.
191 // TODO(karlklose): split this method in different strategies.
192 /// Creates an expression to represent a runtime type instance of type [type].
193 Expression createRuntimeType(DartType type,
194 {reifyTypeVariable: false,
195 Expression createReference(Class cls),
196 VariableDeclaration typeContext}) {
197 Expression buildReifiedTypeVariable(TypeParameterType type) {
198 Expression typeVariables = new PropertyGet(
199 createReference(type.parameter.parent),
200 rtiLibrary.variablesFieldName);
201 return createArrayAccess(
202 typeVariables, getTypeVariableIndex(type.parameter));
203 }
204
205 Expression buildDirectTypeVariableAccess(TypeParameterType variable) {
206 Class cls = getEnclosingClass(variable.parameter);
207 return extractTypeVariable(
208 cls,
209 variable.parameter,
210 getTypeVariableIndex(variable.parameter),
211 new VariableGet(typeContext));
212 }
213
214 Expression buildGetterTypeVariableAccess(TypeParameterType type) {
215 return new PropertyGet(
216 new ThisExpression(), typeVariableGetterName(type.parameter));
217 }
218
219 Expression buildTypeVariable(TypeParameterType type) {
220 if (reifyTypeVariable) {
221 assert(typeContext == null);
222 return buildReifiedTypeVariable(type);
223 } else if (typeContext != null) {
224 return buildDirectTypeVariableAccess(type);
225 } else {
226 return buildGetterTypeVariableAccess(type);
227 }
228 }
229
230 createReference ??= createAccessDeclaration;
231
232 /// Helper to make recursive invocation more readable.
233 Expression createPart(DartType type) {
234 return createRuntimeType(type,
235 reifyTypeVariable: reifyTypeVariable,
236 createReference: createReference,
237 typeContext: typeContext);
238 }
239
240 if (type is InterfaceType || type is Supertype) {
241 InterfaceType interfaceType = null;
242 if (type is InterfaceType) {
243 interfaceType = type;
244 } else {
245 interfaceType = (type as Supertype).asInterfaceType;
246 }
247 Class cls = interfaceType.classNode;
248 Expression declaration = createReference(cls);
249 List<DartType> typeArguments = interfaceType.typeArguments;
250 Expression typeArgumentList;
251 if (typeArguments.isNotEmpty) {
252 if (!reifyTypeVariable && matchesTypeParameters(typeArguments)) {
253 // The type argument list corresponds to the list of type parameters
254 // and we are not in "declaration emitter" mode, we can reuse the
255 // type argument vector.
256 TypeParameterType parameterType = typeArguments[0];
257 Class cls = parameterType.parameter.parent;
258 Expression typeObject = typeContext != null
259 ? new VariableGet(typeContext)
260 : createGetType(new ThisExpression());
261 typeArgumentList =
262 createGetTypeArguments(createCallAsInstanceOf(typeObject, cls));
263 } else {
264 typeArgumentList =
265 new ListLiteral(typeArguments.map(createPart).toList());
266 }
267 }
268 return createNewInterface(declaration, typeArgumentList);
269 } else if (type is DynamicType) {
270 return new ConstructorInvocation(
271 rtiLibrary.dynamicTypeConstructor, new Arguments([]),
272 isConst: true);
273 } else if (type is TypeParameterType) {
274 return buildTypeVariable(type);
275 } else if (type is FunctionType) {
276 FunctionType functionType = type;
277 Expression returnType = createPart(functionType.returnType);
278 List<Expression> encodedParameterTypes =
279 functionType.positionalParameters.map(createPart).toList();
280 List<NamedType> namedParameters = functionType.namedParameters;
281 int data;
282 if (namedParameters.isNotEmpty) {
283 for (NamedType param in namedParameters) {
284 encodedParameterTypes.add(new StringLiteral(param.name));
285 encodedParameterTypes.add(createPart(param.type));
286 }
287 data = functionType.namedParameters.length << 1 | 1;
288 } else {
289 data = (functionType.positionalParameters.length -
290 functionType.requiredParameterCount) <<
291 1;
292 }
293 Expression functionTypeExpression = new ConstructorInvocation(
294 rtiLibrary.interfaceTypeConstructor,
295 new Arguments(
296 <Expression>[createReference(coreTypes.functionClass)]));
297 Arguments arguments = new Arguments(<Expression>[
298 functionTypeExpression,
299 returnType,
300 new IntLiteral(data),
301 new ListLiteral(encodedParameterTypes)
302 ]);
303 return new ConstructorInvocation(
304 rtiLibrary.functionTypeConstructor, arguments);
305 } else if (type is VoidType) {
306 return new ConstructorInvocation(
307 rtiLibrary.voidTypeConstructor, new Arguments(<Expression>[]));
308 }
309 return new InvalidExpression();
310 }
311
312 Expression createCallAsInstanceOf(Expression receiver, Class cls) {
313 return new StaticInvocation(rtiLibrary.asInstanceOfFunction,
314 new Arguments(<Expression>[receiver, createAccessDeclaration(cls)]));
315 }
316
317 /// `get get$<variable-name> => <get-type>.arguments[<variable-index>]`
318 Member createTypeVariableGetter(
319 Class cls, TypeParameter variable, int index) {
320 Expression type = createGetType(new ThisExpression());
321 Expression argument = extractTypeVariable(cls, variable, index, type);
322 return new Procedure(
323 typeVariableGetterName(variable),
324 ProcedureKind.Getter,
325 new FunctionNode(new ReturnStatement(argument),
326 returnType: rtiLibrary.typeType),
327 fileUri: cls.fileUri);
328 }
329
330 Expression extractTypeVariable(
331 Class cls, TypeParameter variable, int index, Expression typeObject) {
332 Expression type = createCallAsInstanceOf(typeObject, cls);
333 Expression arguments = new StaticInvocation(
334 rtiLibrary.typeArgumentsFunction, new Arguments(<Expression>[type]));
335 // TODO(karlklose): use the global index instead of the local one.
336 return createArrayAccess(arguments, index);
337 }
338
339 void insertAsFirstArgument(Arguments arguments, Expression expression) {
340 expression.parent = arguments;
341 arguments.positional.insert(0, expression);
342 }
343
344 /// Creates a call to the `init` function that completes the definition of a
345 /// class by setting its (direct) supertypes.
346 Expression createCallInit(
347 VariableDeclaration declarations,
348 int index,
349 InterfaceType supertype,
350 List<InterfaceType> interfaces,
351 FunctionType callableType) {
352 /// Helper to create a reference to the declaration in the declaration
353 /// list instead of the field to avoid cycles if that field's
354 /// initialization depends on the class we are currently initializing.
355 Expression createReference(Class declaration) {
356 int id = reifiedClassIds[declaration];
357 return createArrayAccess(new VariableGet(declarations), id);
358 }
359
360 bool isNotMarkerInterface(InterfaceType interface) {
361 return interface.classNode != rtiLibrary.markerClass;
362 }
363
364 Expression createLocalType(DartType type) {
365 if (type == null) return null;
366 return createRuntimeType(type,
367 reifyTypeVariable: true, createReference: createReference);
368 }
369
370 Expression supertypeExpression =
371 supertype == null ? new NullLiteral() : createLocalType(supertype);
372
373 List<Expression> interfaceTypes = interfaces
374 .where(isNotMarkerInterface)
375 .map(createLocalType)
376 .toList(growable: false);
377
378 Expression callableTypeExpression = createLocalType(callableType);
379
380 List<Expression> arguments = <Expression>[
381 new VariableGet(declarations),
382 new IntLiteral(index),
383 supertypeExpression,
384 ];
385
386 if (interfaceTypes.isNotEmpty || callableTypeExpression != null) {
387 arguments.add(new ListLiteral(interfaceTypes));
388 if (callableTypeExpression != null) {
389 arguments.add(callableTypeExpression);
390 }
391 }
392
393 return new StaticInvocation(
394 rtiLibrary.initFunction, new Arguments(arguments));
395 }
396
397 Expression createDeclarationsInitializer() {
398 List<Statement> statements = <Statement>[];
399 // Call function to allocate the class declarations given the names and
400 // number of type variables of the classes.
401 Namer classNamer = new Namer();
402 List<Expression> names = <Expression>[];
403 List<Expression> parameterCount = <Expression>[];
404 reifiedClassIds.keys.forEach((Class c) {
405 names.add(new StringLiteral(classNamer.getNameFor(c)));
406 parameterCount.add(new IntLiteral(c.typeParameters.length));
407 });
408 Expression namesList = new ListLiteral(names);
409 Expression parameterCountList = new ListLiteral(parameterCount);
410 StaticInvocation callAllocate = new StaticInvocation(
411 rtiLibrary.allocateDeclarationsFunction,
412 new Arguments(<Expression>[namesList, parameterCountList]));
413
414 VariableDeclaration parameter =
415 new VariableDeclaration("d", type: declarationType);
416
417 reifiedClassIds.forEach((Class cls, int id) {
418 if (cls == rtiLibrary.markerClass) return;
419
420 // If the class declares a `call` method, translate the signature to a
421 // reified type.
422 FunctionType callableType;
423 Procedure call = cls.procedures.firstWhere(
424 (Procedure p) => p.name.name == "call",
425 orElse: () => null);
426 if (call != null) {
427 FunctionNode function = call.function;
428
429 final namedParameters = new List<NamedType>();
430 for (VariableDeclaration v in function.namedParameters) {
431 namedParameters.add(new NamedType(v.name, v.type));
432 }
433
434 List<DartType> positionalArguments = function.positionalParameters
435 .map((VariableDeclaration v) => v.type)
436 .toList();
437 callableType = new FunctionType(
438 positionalArguments, function.returnType,
439 namedParameters: namedParameters,
440 requiredParameterCount: function.requiredParameterCount);
441 }
442 statements.add(new ExpressionStatement(createCallInit(
443 parameter,
444 id,
445 cls.supertype?.asInterfaceType,
446 cls.implementedTypes.map((Supertype type) => type?.asInterfaceType),
447 callableType)));
448 });
449
450 statements.add(new ReturnStatement(new VariableGet(parameter)));
451
452 Expression function = new FunctionExpression(new FunctionNode(
453 new Block(statements),
454 positionalParameters: <VariableDeclaration>[parameter],
455 returnType: declarationType));
456
457 return new MethodInvocation(
458 function, new Name("call"), new Arguments(<Expression>[callAllocate]));
459 }
460
461 void createDeclarations() {
462 /// Recursively find all referenced classes in [type].
463 void collectNewReferencedClasses(DartType type, Set<Class> newClasses) {
464 if (type is InterfaceType || type is Supertype) {
465 InterfaceType interfaceType = null;
466 if (type is InterfaceType) {
467 interfaceType = type;
468 } else {
469 interfaceType = (type as Supertype).asInterfaceType;
470 }
471 Class cls = interfaceType.classNode;
472 if (!reifiedClassIds.containsKey(cls) && !newClasses.contains(cls)) {
473 newClasses.add(cls);
474 }
475
476 interfaceType.typeArguments.forEach((DartType argument) {
477 collectNewReferencedClasses(argument, newClasses);
478 });
479 }
480 // TODO(karlklose): function types
481 }
482
483 Iterable<Class> classes = reifiedClassIds.keys;
484 while (classes.isNotEmpty) {
485 Set<Class> newClasses = new Set<Class>();
486 for (Class c in classes) {
487 collectNewReferencedClasses(c.supertype?.asInterfaceType, newClasses);
488 c.implementedTypes.forEach((Supertype supertype) {
489 collectNewReferencedClasses(supertype?.asInterfaceType, newClasses);
490 });
491 }
492 for (Class newClass in newClasses) {
493 // Make sure that there is a declaration field for the class and its
494 // library's declaration list is setup.
495 addDeclaration(newClass);
496 }
497 classes = newClasses;
498 }
499 Expression initializer = createDeclarationsInitializer();
500 initializer.parent = declarations;
501 declarations.initializer = initializer;
502 declarations.type = declarationType;
503 }
504
505 Procedure createGetter(
506 Name name, Expression expression, Class cls, DartType type) {
507 return new Procedure(name, ProcedureKind.Getter,
508 new FunctionNode(new ReturnStatement(expression), returnType: type),
509 fileUri: cls.fileUri);
510 }
511 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698