| // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| /// This file declares a "shadow hierarchy" of concrete classes which extend |
| /// the kernel class hierarchy, adding methods and fields needed by the |
| /// BodyBuilder. |
| /// |
| /// Instances of these classes may be created using the factory methods in |
| /// `ast_factory.dart`. |
| /// |
| /// Note that these classes represent the Dart language prior to desugaring. |
| /// When a single Dart construct desugars to a tree containing multiple kernel |
| /// AST nodes, the shadow class extends the kernel object at the top of the |
| /// desugared tree. |
| /// |
| /// This means that in some cases multiple shadow classes may extend the same |
| /// kernel class, because multiple constructs in Dart may desugar to a tree |
| /// with the same kind of root node. |
| import 'package:front_end/src/base/instrumentation.dart'; |
| import 'package:front_end/src/fasta/type_inference/type_inferrer.dart'; |
| import 'package:kernel/ast.dart'; |
| |
| /// Concrete shadow object representing a statement block in kernel form. |
| class KernelBlock extends Block implements KernelStatement { |
| KernelBlock(List<Statement> statements) : super(statements); |
| |
| @override |
| void _inferStatement(KernelTypeInferrer inferrer) { |
| for (var statement in statements) { |
| inferrer.inferStatement(statement); |
| } |
| } |
| } |
| |
| /// Common base class for shadow objects representing expressions in kernel |
| /// form. |
| abstract class KernelExpression implements Expression { |
| /// Calls back to [inferrer] to perform type inference for whatever concrete |
| /// type of [KernelExpression] this is. |
| DartType _inferExpression( |
| KernelTypeInferrer inferrer, DartType typeContext, bool typeNeeded); |
| } |
| |
| /// Concrete shadow object representing a field in kernel form. |
| class KernelField extends Field { |
| bool _implicitlyTyped = true; |
| |
| FieldNode<KernelField> _fieldNode; |
| |
| bool _isInferred = false; |
| |
| KernelField(Name name, {String fileUri}) : super(name, fileUri: fileUri) {} |
| |
| @override |
| void set type(DartType value) { |
| _implicitlyTyped = false; |
| super.type = value; |
| } |
| |
| String get _fileUri { |
| // TODO(paulberry): This is a hack. We should use this.fileUri, because we |
| // want the URI of the compilation unit. But that gives a relative URI, |
| // and I don't know what it's relative to or how to convert it to an |
| // absolute URI. |
| return enclosingLibrary.importUri.toString(); |
| } |
| |
| void _setInferredType(DartType inferredType) { |
| _isInferred = true; |
| super.type = inferredType; |
| } |
| } |
| |
| /// Concrete shadow object representing a function expression in kernel form. |
| class KernelFunctionExpression extends FunctionExpression |
| implements KernelExpression { |
| KernelFunctionExpression(FunctionNode function) : super(function); |
| |
| @override |
| DartType _inferExpression( |
| KernelTypeInferrer inferrer, DartType typeContext, bool typeNeeded) { |
| // TODO(paulberry): implement. |
| return typeNeeded ? const DynamicType() : null; |
| } |
| } |
| |
| /// Concrete shadow object representing an integer literal in kernel form. |
| class KernelIntLiteral extends IntLiteral implements KernelExpression { |
| KernelIntLiteral(int value) : super(value); |
| |
| @override |
| DartType _inferExpression( |
| KernelTypeInferrer inferrer, DartType typeContext, bool typeNeeded) { |
| return inferrer.inferIntLiteral(typeContext, typeNeeded); |
| } |
| } |
| |
| /// Concrete shadow object representing a list literal in kernel form. |
| class KernelListLiteral extends ListLiteral implements KernelExpression { |
| KernelListLiteral(List<KernelExpression> expressions, |
| {DartType typeArgument, bool isConst: false}) |
| : super(expressions, typeArgument: typeArgument, isConst: isConst); |
| |
| @override |
| DartType _inferExpression( |
| KernelTypeInferrer inferrer, DartType typeContext, bool typeNeeded) { |
| // TODO(paulberry): implement. |
| return typeNeeded ? const DynamicType() : null; |
| } |
| } |
| |
| /// Concrete shadow object representing a null literal in kernel form. |
| class KernelNullLiteral extends NullLiteral implements KernelExpression { |
| @override |
| DartType _inferExpression( |
| KernelTypeInferrer inferrer, DartType typeContext, bool typeNeeded) { |
| // TODO(paulberry): implement. |
| return typeNeeded ? const DynamicType() : null; |
| } |
| } |
| |
| /// Concrete shadow object representing a return statement in kernel form. |
| class KernelReturnStatement extends ReturnStatement implements KernelStatement { |
| KernelReturnStatement([KernelExpression expression]) : super(expression); |
| |
| @override |
| void _inferStatement(KernelTypeInferrer inferrer) { |
| // TODO(paulberry): implement. |
| } |
| } |
| |
| /// Common base class for shadow objects representing statements in kernel |
| /// form. |
| abstract class KernelStatement extends Statement { |
| /// Calls back to [inferrer] to perform type inference for whatever concrete |
| /// type of [KernelStatement] this is. |
| void _inferStatement(KernelTypeInferrer inferrer); |
| } |
| |
| /// Concrete shadow object representing a read of a static variable in kernel |
| /// form. |
| class KernelStaticGet extends StaticGet implements KernelExpression { |
| KernelStaticGet(Member target) : super(target); |
| |
| @override |
| DartType _inferExpression( |
| KernelTypeInferrer inferrer, DartType typeContext, bool typeNeeded) { |
| return inferrer.inferStaticGet(typeContext, typeNeeded, target.getterType); |
| } |
| } |
| |
| /// Concrete implementation of [TypeInferrer] specialized to work with kernel |
| /// objects. |
| class KernelTypeInferrer extends TypeInferrer<Statement, Expression, |
| KernelVariableDeclaration, KernelField> { |
| KernelTypeInferrer(Instrumentation instrumentation, bool strongMode) |
| : super(instrumentation, strongMode); |
| |
| @override |
| void clearFieldInitializer(KernelField field) { |
| field.initializer = null; |
| } |
| |
| @override |
| FieldNode<KernelField> createFieldNode(KernelField field) { |
| FieldNode<KernelField> fieldNode = new FieldNode<KernelField>(this, field); |
| field._fieldNode = fieldNode; |
| return fieldNode; |
| } |
| |
| @override |
| DartType getFieldDeclaredType(KernelField field) { |
| return field._implicitlyTyped ? null : field.type; |
| } |
| |
| @override |
| List<FieldNode<KernelField>> getFieldDependencies(KernelField field) { |
| return field._fieldNode?.dependencies; |
| } |
| |
| @override |
| Expression getFieldInitializer(KernelField field) { |
| return field.initializer; |
| } |
| |
| @override |
| FieldNode<KernelField> getFieldNodeForReadTarget(Member readTarget) { |
| if (readTarget is KernelField) { |
| return readTarget._fieldNode; |
| } else { |
| return null; |
| } |
| } |
| |
| @override |
| int getFieldOffset(KernelField field) { |
| return field.fileOffset; |
| } |
| |
| @override |
| String getFieldUri(KernelField field) { |
| return field._fileUri; |
| } |
| |
| @override |
| DartType inferExpression( |
| Expression expression, DartType typeContext, bool typeNeeded) { |
| if (expression is KernelExpression) { |
| // Use polymorphic dispatch on [KernelExpression] to perform whatever kind |
| // of type inference is correct for this kind of statement. |
| // TODO(paulberry): experiment to see if dynamic dispatch would be better, |
| // so that the type hierarchy will be simpler (which may speed up "is" |
| // checks). |
| return expression._inferExpression(this, typeContext, typeNeeded); |
| } else { |
| // Encountered an expression type for which type inference is not yet |
| // implemented, so just infer dynamic for now. |
| // TODO(paulberry): once the BodyBuilder uses shadow classes for |
| // everything, this case should no longer be needed. |
| return typeNeeded ? const DynamicType() : null; |
| } |
| } |
| |
| @override |
| void inferStatement(Statement statement) { |
| if (statement is KernelStatement) { |
| // Use polymorphic dispatch on [KernelStatement] to perform whatever kind |
| // of type inference is correct for this kind of statement. |
| // TODO(paulberry): experiment to see if dynamic dispatch would be better, |
| // so that the type hierarchy will be simpler (which may speed up "is" |
| // checks). |
| return statement._inferStatement(this); |
| } else { |
| // Encountered a statement type for which type inference is not yet |
| // implemented, so just skip it for now. |
| // TODO(paulberry): once the BodyBuilder uses shadow classes for |
| // everything, this case should no longer be needed. |
| } |
| } |
| |
| @override |
| bool isFieldInferred(KernelField field) { |
| return field._isInferred; |
| } |
| |
| @override |
| void setFieldInferredType(KernelField field, DartType inferredType) { |
| field._setInferredType(inferredType); |
| } |
| } |
| |
| /// Concrete shadow object representing a variable declaration in kernel form. |
| class KernelVariableDeclaration extends VariableDeclaration |
| implements KernelStatement { |
| final bool _implicitlyTyped; |
| |
| KernelVariableDeclaration(String name, |
| {Expression initializer, |
| DartType type, |
| bool isFinal: false, |
| bool isConst: false}) |
| : _implicitlyTyped = type == null, |
| super(name, |
| initializer: initializer, |
| type: type ?? const DynamicType(), |
| isFinal: isFinal, |
| isConst: isConst); |
| |
| @override |
| void _inferStatement(KernelTypeInferrer inferrer) { |
| inferrer.inferVariableDeclaration( |
| _implicitlyTyped ? null : type, initializer, fileOffset, (type) { |
| this.type = type; |
| }); |
| } |
| } |
| |
| /// Concrete shadow object representing a read from a variable in kernel form. |
| class KernelVariableGet extends VariableGet implements KernelExpression { |
| KernelVariableGet(VariableDeclaration variable, [DartType promotedType]) |
| : super(variable, promotedType); |
| |
| @override |
| DartType _inferExpression( |
| KernelTypeInferrer inferrer, DartType typeContext, bool typeNeeded) { |
| // TODO(paulberry): implement. |
| return typeNeeded ? const DynamicType() : null; |
| } |
| } |