blob: a761ab2e67ea6b541ba4dbcc4e0dcaecbc6595df [file] [log] [blame]
// 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;
}
}