Index: pkg/analyzer/lib/src/fasta/analyzer_diet_listener.dart |
diff --git a/pkg/analyzer/lib/src/fasta/analyzer_diet_listener.dart b/pkg/analyzer/lib/src/fasta/analyzer_diet_listener.dart |
index 5b687caf60324920e40905e9f557466ae95d7a09..99e2a7ce9e3143e7689a4a19ec8ba230942570ce 100644 |
--- a/pkg/analyzer/lib/src/fasta/analyzer_diet_listener.dart |
+++ b/pkg/analyzer/lib/src/fasta/analyzer_diet_listener.dart |
@@ -4,6 +4,26 @@ |
library fasta.analyzer_diet_listener; |
+import 'package:analyzer/dart/ast/ast.dart' as ast show AstNode; |
+ |
+import 'package:analyzer/dart/element/type.dart' as ast show DartType; |
+ |
+import 'package:analyzer/src/dart/element/type.dart'; |
+ |
+import 'package:analyzer/src/fasta/resolution_applier.dart' |
+ show ValidatingResolutionApplier; |
+ |
+import 'package:analyzer/src/fasta/resolution_storer.dart' |
+ show InstrumentedResolutionStorer; |
+ |
+import 'package:front_end/src/fasta/kernel/body_builder.dart' show BodyBuilder; |
+ |
+import 'package:front_end/src/fasta/type_inference/type_inference_engine.dart' |
+ show TypeInferenceEngine; |
+ |
+import 'package:front_end/src/fasta/type_inference/type_inference_listener.dart' |
+ show TypeInferenceListener; |
+ |
import 'package:kernel/ast.dart' show AsyncMarker; |
import 'package:front_end/src/fasta/source/stack_listener.dart' |
@@ -11,12 +31,22 @@ import 'package:front_end/src/fasta/source/stack_listener.dart' |
import 'package:front_end/src/fasta/builder/builder.dart'; |
+import 'package:front_end/src/fasta/parser/parser.dart' show MemberKind, Parser; |
+ |
+import 'package:front_end/src/scanner/token.dart' show Token; |
+ |
import 'package:front_end/src/fasta/source/source_library_builder.dart' |
show SourceLibraryBuilder; |
import 'package:front_end/src/fasta/source/diet_listener.dart' |
show DietListener; |
+import 'package:kernel/class_hierarchy.dart' show ClassHierarchy; |
+ |
+import 'package:kernel/core_types.dart' show CoreTypes; |
+ |
+import 'package:kernel/kernel.dart' as kernel show DartType; |
+ |
import 'element_store.dart' show ElementStore; |
import 'ast_builder.dart' show AstBuilder; |
@@ -24,16 +54,144 @@ import 'ast_builder.dart' show AstBuilder; |
class AnalyzerDietListener extends DietListener { |
final ElementStore elementStore; |
- AnalyzerDietListener(SourceLibraryBuilder library, this.elementStore) |
- : super(library, null, null, null); |
+ /// The body builder for the method currently being compiled, or `null` if no |
+ /// method is currently being compiled. |
+ /// |
+ /// Needed because it performs resolution and type inference. |
+ BodyBuilder _bodyBuilder; |
+ |
+ /// The list of types inferred by the body builder for the method currently |
+ /// being compiled, or `null` if no method is currently being compiled. |
+ List<kernel.DartType> _kernelTypes; |
+ |
+ /// File offsets corresponding to the types in [_kernelTypes]. |
+ /// |
+ /// These are used strictly for validation purposes. |
+ List<int> _typeOffsets; |
+ |
+ /// Indicates whether a kernel representation of the code should be generated. |
+ /// |
+ /// When `false`, an analyzer AST is generated, and type inference is copied |
+ /// over to it, but the result is not converted to a kernel representation. |
+ /// |
+ /// TODO(paulberry): remove this once "kompile" functionality is no longer |
+ /// needed. |
+ final bool generateKernel; |
+ |
+ /// Indicates whether a resolved AST should be generated. |
+ /// |
+ /// When `false`, an analyzer AST is generated, but none of the types or |
+ /// elements pointed to by the AST are guaranteed to be correct. |
+ /// |
+ /// This is needed in order to support the old "kompile" use case, since the |
+ /// tests of that functionality were based on the behavior prior to |
+ /// integrating resolution and type inference with analyzer. |
+ /// |
+ /// TODO(paulberry): remove this once "kompile" functionality is no longer |
+ /// needed. |
+ final bool doResolution; |
+ |
+ AnalyzerDietListener( |
+ SourceLibraryBuilder library, |
+ this.elementStore, |
+ ClassHierarchy hierarchy, |
+ CoreTypes coreTypes, |
+ TypeInferenceEngine typeInferenceEngine, |
+ this.generateKernel, |
+ this.doResolution) |
+ : super(library, hierarchy, coreTypes, typeInferenceEngine); |
+ |
+ @override |
+ void buildFunctionBody( |
+ Token token, ProcedureBuilder builder, MemberKind kind, Token metadata) { |
+ Scope typeParameterScope = builder.computeTypeParameterScope(memberScope); |
+ Scope formalParameterScope = |
+ builder.computeFormalParameterScope(typeParameterScope); |
+ assert(typeParameterScope != null); |
+ assert(formalParameterScope != null); |
+ // Create a body builder to do type inference, and a listener to record the |
+ // types that are inferred. |
+ _kernelTypes = <kernel.DartType>[]; |
+ _typeOffsets = <int>[]; |
+ var resolutionStorer = |
+ new InstrumentedResolutionStorer(_kernelTypes, _typeOffsets); |
+ _bodyBuilder = super.createListener(builder, memberScope, |
+ builder.isInstanceMember, formalParameterScope, resolutionStorer); |
+ // Parse the function body normally; this will build the analyzer AST, run |
+ // the body builder to do type inference, and then copy the inferred types |
+ // over to the analyzer AST. |
+ parseFunctionBody( |
+ createListener(builder, typeParameterScope, builder.isInstanceMember, |
+ formalParameterScope), |
+ token, |
+ metadata, |
+ kind); |
+ // The inferred types and the body builder are no longer needed. |
+ _bodyBuilder = null; |
+ _kernelTypes = null; |
+ _typeOffsets = null; |
+ } |
StackListener createListener( |
ModifierBuilder builder, Scope memberScope, bool isInstanceMember, |
- [Scope formalParameterScope]) { |
- return new AstBuilder( |
- null, library, builder, elementStore, memberScope, false, uri); |
+ [Scope formalParameterScope, TypeInferenceListener listener]) { |
+ return new AstBuilder(null, library, builder, elementStore, memberScope, |
+ false, generateKernel, uri); |
} |
@override |
AsyncMarker getAsyncMarker(StackListener listener) => null; |
+ |
+ @override |
+ void listenerFinishFunction( |
+ StackListener listener, |
+ Token token, |
+ Token metadata, |
+ MemberKind kind, |
+ List metadataConstants, |
+ dynamic formals, |
+ AsyncMarker asyncModifier, |
+ dynamic body) { |
+ // TODO(paulberry): this duplicates a lot of code from |
+ // DietListener.parseFunctionBody. |
+ if (doResolution) { |
+ // At this point the analyzer AST has been built, but it doesn't contain |
+ // resolution data or inferred types. Run the body builder and gather this |
ahe
2017/07/13 14:51:40
Long line.
Paul Berry
2017/07/13 15:54:46
Done.
|
+ // information. |
+ Parser parser = new Parser(_bodyBuilder); |
+ List bodyBuilderMetadataConstants; |
+ if (metadata != null) { |
+ parser.parseMetadataStar(metadata); |
+ bodyBuilderMetadataConstants = _bodyBuilder.pop(); |
+ } |
+ token = parser.parseFormalParametersOpt(token, kind); |
+ var bodyBuilderFormals = _bodyBuilder.pop(); |
+ _bodyBuilder.checkEmpty(token.charOffset); |
+ token = parser.parseInitializersOpt(token); |
+ bool isExpression = false; |
+ bool allowAbstract = asyncModifier == AsyncMarker.Sync; |
+ parser.parseFunctionBody(token, isExpression, allowAbstract); |
+ var bodyBuilderBody = _bodyBuilder.pop(); |
+ _bodyBuilder.checkEmpty(token.charOffset); |
+ _bodyBuilder.finishFunction(bodyBuilderMetadataConstants, |
+ bodyBuilderFormals, asyncModifier, bodyBuilderBody); |
+ |
+ // Now apply the resolution data and inferred types to the analyzer AST. |
+ var translatedTypes = _translateTypes(_kernelTypes); |
+ var resolutionApplier = |
+ new ValidatingResolutionApplier(translatedTypes, _typeOffsets); |
+ ast.AstNode bodyAsAstNode = body; |
+ bodyAsAstNode.accept(resolutionApplier); |
+ resolutionApplier.checkDone(); |
+ } |
+ listener.finishFunction(metadataConstants, formals, asyncModifier, body); |
+ } |
+ |
+ /// Translates the given kernel types into analyzer types. |
+ static List<ast.DartType> _translateTypes(List<kernel.DartType> kernelTypes) { |
+ // For now we just translate everything to `dynamic`. |
+ // TODO(paulberry): implement propert translation of types. |
+ return new List<ast.DartType>.filled( |
+ kernelTypes.length, DynamicTypeImpl.instance); |
+ } |
} |