OLD | NEW |
---|---|
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 kernel.transformations.reify.transformation.transformer; | 5 library kernel.transformations.reify.transformation.transformer; |
6 | 6 |
7 import '../analysis/program_analysis.dart'; | 7 import '../analysis/program_analysis.dart'; |
8 import 'package:kernel/ast.dart'; | 8 import 'package:kernel/ast.dart'; |
9 import 'binding.dart' show RuntimeLibrary; | 9 import 'binding.dart' show RuntimeLibrary; |
10 import 'builder.dart' show RuntimeTypeSupportBuilder; | 10 import 'builder.dart' show RuntimeTypeSupportBuilder; |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
96 ReifyVisitor(this.rtiLibrary, this.builder, this.knowledge, | 96 ReifyVisitor(this.rtiLibrary, this.builder, this.knowledge, |
97 [this.libraryToTransform]); | 97 [this.libraryToTransform]); |
98 | 98 |
99 /// If not null, the transformation will only be applied to classes declared | 99 /// If not null, the transformation will only be applied to classes declared |
100 /// in this library. | 100 /// in this library. |
101 final Library libraryToTransform; | 101 final Library libraryToTransform; |
102 | 102 |
103 // TODO(karlklose): find a way to get rid of this state in the visitor. | 103 // TODO(karlklose): find a way to get rid of this state in the visitor. |
104 TransformationContext context; | 104 TransformationContext context; |
105 | 105 |
106 static const String genericMethodTypeParametersName = r"$typeParameters"; | |
107 | |
106 bool libraryShouldBeTransformed(Library library) { | 108 bool libraryShouldBeTransformed(Library library) { |
107 return libraryToTransform == null || libraryToTransform == library; | 109 return libraryToTransform == null || libraryToTransform == library; |
108 } | 110 } |
109 | 111 |
110 bool needsTypeInformation(Class cls) { | 112 bool needsTypeInformation(Class cls) { |
111 return !isObject(cls) && | 113 return !isObject(cls) && |
112 !rtiLibrary.contains(cls) && | 114 !rtiLibrary.contains(cls) && |
113 libraryShouldBeTransformed(cls.enclosingLibrary); | 115 libraryShouldBeTransformed(cls.enclosingLibrary); |
114 } | 116 } |
115 | 117 |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
173 | 175 |
174 Procedure target = invocation.target; | 176 Procedure target = invocation.target; |
175 if (target == rtiLibrary.reifyFunction) { | 177 if (target == rtiLibrary.reifyFunction) { |
176 /// Rewrite calls to reify(TypeLiteral) to a reified type. | 178 /// Rewrite calls to reify(TypeLiteral) to a reified type. |
177 TypeLiteral literal = invocation.arguments.positional.single; | 179 TypeLiteral literal = invocation.arguments.positional.single; |
178 return createRuntimeType(literal.type); | 180 return createRuntimeType(literal.type); |
179 } else if (target.kind == ProcedureKind.Factory) { | 181 } else if (target.kind == ProcedureKind.Factory) { |
180 // Intercept calls to factories of classes we do not transform | 182 // Intercept calls to factories of classes we do not transform |
181 return interceptInstantiation(invocation, target); | 183 return interceptInstantiation(invocation, target); |
182 } | 184 } |
185 | |
186 addTypeArgumentToGenericInvocation(invocation); | |
187 | |
183 return invocation; | 188 return invocation; |
184 } | 189 } |
185 | 190 |
186 Library visitLibrary(Library library) { | 191 Library visitLibrary(Library library) { |
187 trace(library); | 192 trace(library); |
188 | 193 |
189 if (libraryShouldBeTransformed(library)) { | 194 if (libraryShouldBeTransformed(library)) { |
190 library.transformChildren(this); | 195 library.transformChildren(this); |
191 } | 196 } |
192 return library; | 197 return library; |
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
412 | 417 |
413 RuntimeTypeStorage access = context.runtimeTypeStorage; | 418 RuntimeTypeStorage access = context.runtimeTypeStorage; |
414 assert(access != RuntimeTypeStorage.none); | 419 assert(access != RuntimeTypeStorage.none); |
415 return access == RuntimeTypeStorage.field || | 420 return access == RuntimeTypeStorage.field || |
416 access == RuntimeTypeStorage.inheritedField; | 421 access == RuntimeTypeStorage.inheritedField; |
417 } | 422 } |
418 | 423 |
419 FunctionNode visitFunctionNode(FunctionNode node) { | 424 FunctionNode visitFunctionNode(FunctionNode node) { |
420 trace(node); | 425 trace(node); |
421 | 426 |
427 addTypeArgumentToGenericDeclaration(node); | |
428 | |
422 // If we have a [TransformationContext] with a runtime type field and we | 429 // If we have a [TransformationContext] with a runtime type field and we |
423 // translate a constructor or factory, we need a parameter that the code of | 430 // translate a constructor or factory, we need a parameter that the code of |
424 // initializers or the factory body can use to access type arguments. | 431 // initializers or the factory body can use to access type arguments. |
425 // The parameter field in the context will be reset in the visit-method of | 432 // The parameter field in the context will be reset in the visit-method of |
426 // the parent. | 433 // the parent. |
427 if (context != null && needsParameterForRuntimeType(node.parent)) { | 434 if (context != null && needsParameterForRuntimeType(node.parent)) { |
428 assert(context.parameter == null); | 435 assert(context.parameter == null); |
429 // Create the parameter and insert it as the function's first parameter. | 436 // Create the parameter and insert it as the function's first parameter. |
430 context.parameter = new VariableDeclaration( | 437 context.parameter = new VariableDeclaration( |
431 rtiLibrary.runtimeTypeName.name, | 438 rtiLibrary.runtimeTypeName.name, |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
565 } | 572 } |
566 | 573 |
567 Expression visitMapLiteral(MapLiteral node) { | 574 Expression visitMapLiteral(MapLiteral node) { |
568 trace(node); | 575 trace(node); |
569 node.transformChildren(this); | 576 node.transformChildren(this); |
570 return builder.callAttachType( | 577 return builder.callAttachType( |
571 node, | 578 node, |
572 new InterfaceType(builder.coreTypes.mapClass, | 579 new InterfaceType(builder.coreTypes.mapClass, |
573 <DartType>[node.keyType, node.valueType])); | 580 <DartType>[node.keyType, node.valueType])); |
574 } | 581 } |
582 | |
583 Expression visitMethodInvocation(MethodInvocation node) { | |
584 node.transformChildren(this); | |
585 addTypeArgumentToGenericInvocation(node); | |
586 return node; | |
587 } | |
588 | |
589 bool isGenericMethod(FunctionNode node) { | |
590 if (node.parent is Constructor) { | |
karlklose
2017/03/15 15:20:22
If you stored `node.parent` in a local variable, t
Dmitry Stefantsov
2017/03/16 09:30:42
Yes, I agree with a small remark. The if-else oper
| |
591 return (node.parent as Member).enclosingClass.typeParameters.length < | |
592 node.typeParameters.length; | |
593 } | |
594 if (node.parent is Procedure && | |
595 (node.parent as Procedure).kind == ProcedureKind.Factory) { | |
596 return (node.parent as Member).enclosingClass.typeParameters.length < | |
597 node.typeParameters.length; | |
598 } | |
599 if (node.typeParameters.length > 0) { | |
600 return true; | |
601 } | |
602 return false; | |
603 } | |
604 | |
605 void addTypeArgumentToGenericInvocation(InvocationExpression expression) { | |
606 if (expression.arguments.types.length > 0) { | |
607 ListLiteral genericMethodTypeParameters = new ListLiteral( | |
608 expression.arguments.types | |
609 .map(createRuntimeType) | |
610 .toList(growable: false), | |
611 typeArgument: rtiLibrary.typeType); | |
612 expression.arguments.named.add(new NamedExpression( | |
613 genericMethodTypeParametersName, genericMethodTypeParameters) | |
614 ..parent = expression.arguments); | |
615 } | |
616 } | |
617 | |
618 void addTypeArgumentToGenericDeclaration(FunctionNode node) { | |
619 if (isGenericMethod(node)) { | |
620 VariableDeclaration genericMethodTypeParameters = new VariableDeclaration( | |
621 genericMethodTypeParametersName, | |
622 type: new InterfaceType( | |
623 builder.coreTypes.listClass, <DartType>[rtiLibrary.typeType])); | |
624 genericMethodTypeParameters.parent = node; | |
625 node.namedParameters.insert(0, genericMethodTypeParameters); | |
626 } | |
627 } | |
575 } | 628 } |
OLD | NEW |