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

Unified Diff: packages/analyzer/lib/src/task/strong/info.dart

Issue 1521693002: Roll Observatory deps (charted -> ^0.3.0) (Closed) Base URL: https://chromium.googlesource.com/external/github.com/dart-lang/observatory_pub_packages.git@master
Patch Set: Created 5 years 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 side-by-side diff with in-line comments
Download patch
Index: packages/analyzer/lib/src/task/strong/info.dart
diff --git a/packages/analyzer/lib/src/task/strong/info.dart b/packages/analyzer/lib/src/task/strong/info.dart
new file mode 100644
index 0000000000000000000000000000000000000000..a18f76fe36f45b3b82d84d70e6ed8d7196461b05
--- /dev/null
+++ b/packages/analyzer/lib/src/task/strong/info.dart
@@ -0,0 +1,472 @@
+// Copyright (c) 2015, 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.
+
+/// Defines static information collected by the type checker and used later by
+/// emitters to generate code.
+// TODO(jmesserly): this was ported from package:dev_compiler, and needs to be
+// refactored to fit into analyzer.
+library analyzer.src.task.strong.info;
+
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/element.dart';
+import 'package:analyzer/src/generated/error.dart';
+
+import 'rules.dart';
+
+// The abstract type of coercions mapping one type to another.
+// This class also exposes static builder functions which
+// check for errors and reduce redundant coercions to the identity.
+abstract class Coercion {
+ final DartType fromType;
+ final DartType toType;
+ Coercion(this.fromType, this.toType);
+ static Coercion cast(DartType fromT, DartType toT) => new Cast(fromT, toT);
+ static Coercion identity(DartType type) => new Identity(type);
+ static Coercion error() => new CoercionError();
+}
+
+// Coercion which casts one type to another
+class Cast extends Coercion {
+ Cast(DartType fromType, DartType toType) : super(fromType, toType);
+}
+
+// The identity coercion
+class Identity extends Coercion {
+ Identity(DartType fromType) : super(fromType, fromType);
+}
+
+// The error coercion. This coercion signals that a coercion
+// could not be generated. The code generator should not see
+// these.
+class CoercionError extends Coercion {
+ CoercionError() : super(null, null);
+}
+
+// TODO(jmesserly): this could use some refactoring. These are essentially
+// like ErrorCodes in analyzer, but we're including some details in our message.
+// Analyzer instead has template strings, and replaces '{0}' with the first
+// argument.
+abstract class StaticInfo {
+ /// AST Node this info is attached to.
+ AstNode get node;
+
+ // TODO(jmesserly): review the usage of error codes. We probably want our own,
+ // as well as some DDC specific [ErrorType]s.
+ ErrorCode toErrorCode();
+
+ // TODO(jmesserly): what convention to use here?
+ String get name => 'dev_compiler.$runtimeType';
+
+ List<Object> get arguments => [node];
+
+ AnalysisError toAnalysisError() {
+ int begin = node is AnnotatedNode
+ ? (node as AnnotatedNode).firstTokenAfterCommentAndMetadata.offset
+ : node.offset;
+ int length = node.end - begin;
+ var source = (node.root as CompilationUnit).element.source;
+ return new AnalysisError(source, begin, length, toErrorCode(), arguments);
+ }
+}
+
+/// Implicitly injected expression conversion.
+abstract class CoercionInfo extends StaticInfo {
+ final TypeRules rules;
+
+ final Expression node;
+
+ DartType get convertedType;
+
+ CoercionInfo(this.rules, this.node);
+
+ DartType get baseType => rules.getStaticType(node);
+ DartType get staticType => convertedType;
+
+ String get message;
+ toErrorCode() => new HintCode(name, message);
+
+ static const String _propertyName = 'dev_compiler.src.info.CoercionInfo';
+
+ /// Gets the coercion info associated with this node.
+ static CoercionInfo get(AstNode node) => node.getProperty(_propertyName);
+
+ /// Sets the coercion info associated with this node.
+ static CoercionInfo set(AstNode node, CoercionInfo info) {
+ node.setProperty(_propertyName, info);
+ return info;
+ }
+}
+
+// Base class for all casts from base type to sub type.
+abstract class DownCast extends CoercionInfo {
+ Cast _cast;
+
+ DownCast._internal(TypeRules rules, Expression expression, this._cast)
+ : super(rules, expression) {
+ assert(_cast.toType != baseType &&
+ _cast.fromType == baseType &&
+ (baseType.isDynamic ||
+ // Call methods make the following non-redundant
+ _cast.toType.isSubtypeOf(baseType) ||
+ baseType.isAssignableTo(_cast.toType)));
+ }
+
+ Cast get cast => _cast;
+
+ DartType get convertedType => _cast.toType;
+
+ @override List<Object> get arguments => [node, baseType, convertedType];
+ @override String get message => '{0} ({1}) will need runtime check '
+ 'to cast to type {2}';
+
+ // Factory to create correct DownCast variant.
+ static StaticInfo create(TypeRules rules, Expression expression, Cast cast,
+ {String reason}) {
+ final fromT = cast.fromType;
+ final toT = cast.toType;
+
+ // toT <:_R fromT => to <: fromT
+ // NB: classes with call methods are subtypes of function
+ // types, but the function type is not assignable to the class
+ assert(toT.isSubtypeOf(fromT) || fromT.isAssignableTo(toT));
+
+ // Handle null call specially.
+ if (expression is NullLiteral) {
+ // TODO(vsm): Create a NullCast for this once we revisit nonnullability.
+ return new DownCastImplicit(rules, expression, cast);
+ }
+
+ // Inference "casts":
+ if (expression is Literal) {
+ // fromT should be an exact type - this will almost certainly fail at
+ // runtime.
+ return new StaticTypeError(rules, expression, toT, reason: reason);
+ }
+ if (expression is FunctionExpression) {
+ // fromT should be an exact type - this will almost certainly fail at
+ // runtime.
+ return new UninferredClosure(rules, expression, cast);
+ }
+ if (expression is InstanceCreationExpression) {
+ // fromT should be an exact type - this will almost certainly fail at
+ // runtime.
+ return new StaticTypeError(rules, expression, toT, reason: reason);
+ }
+
+ // Composite cast: these are more likely to fail.
+ if (!rules.isGroundType(toT)) {
+ // This cast is (probably) due to our different treatment of dynamic.
+ // It may be more likely to fail at runtime.
+ return new DownCastComposite(rules, expression, cast);
+ }
+
+ // Dynamic cast
+ if (fromT.isDynamic) {
+ return new DynamicCast(rules, expression, cast);
+ }
+
+ // Assignment cast
+ var parent = expression.parent;
+ if (parent is VariableDeclaration && (parent.initializer == expression)) {
+ return new AssignmentCast(rules, expression, cast);
+ }
+
+ // Other casts
+ return new DownCastImplicit(rules, expression, cast);
+ }
+}
+
+//
+// Standard down casts. These casts are implicitly injected by the compiler.
+//
+
+// A down cast from dynamic to T.
+class DynamicCast extends DownCast {
+ DynamicCast(TypeRules rules, Expression expression, Cast cast)
+ : super._internal(rules, expression, cast);
+
+ toErrorCode() => new HintCode(name, message);
+}
+
+// A down cast due to a variable declaration to a ground type. E.g.,
+// T x = expr;
+// where T is ground. We exclude non-ground types as these behave differently
+// compared to standard Dart.
+class AssignmentCast extends DownCast {
+ AssignmentCast(TypeRules rules, Expression expression, Cast cast)
+ : super._internal(rules, expression, cast);
+
+ toErrorCode() => new HintCode(name, message);
+}
+
+//
+// Temporary "casts" of allocation sites - literals, constructor invocations,
+// and closures. These should be handled by contextual inference. In most
+// cases, inference will be sufficient, though in some it may unmask an actual
+// error: e.g.,
+// List<int> l = [1, 2, 3]; // Inference succeeds
+// List<String> l = [1, 2, 3]; // Inference reveals static type error
+// We're marking all as warnings for now.
+//
+// TODO(vsm,leafp): Remove this.
+class UninferredClosure extends DownCast {
+ UninferredClosure(TypeRules rules, FunctionExpression expression, Cast cast)
+ : super._internal(rules, expression, cast);
+
+ toErrorCode() => new StaticTypeWarningCode(name, message);
+}
+
+//
+// Implicit down casts. These are only injected by the compiler by flag.
+//
+
+// A down cast to a non-ground type. These behave differently from standard
+// Dart and may be more likely to fail at runtime.
+class DownCastComposite extends DownCast {
+ DownCastComposite(TypeRules rules, Expression expression, Cast cast)
+ : super._internal(rules, expression, cast);
+
+ toErrorCode() => new StaticTypeWarningCode(name, message);
+}
+
+// A down cast to a non-ground type. These behave differently from standard
+// Dart and may be more likely to fail at runtime.
+class DownCastImplicit extends DownCast {
+ DownCastImplicit(TypeRules rules, Expression expression, Cast cast)
+ : super._internal(rules, expression, cast);
+
+ toErrorCode() => new HintCode(name, message);
+}
+
+// An inferred type for the wrapped expression, which may need to be
+// reified into the term
+abstract class InferredTypeBase extends CoercionInfo {
+ final DartType _type;
+
+ InferredTypeBase._internal(TypeRules rules, Expression expression, this._type)
+ : super(rules, expression);
+
+ DartType get type => _type;
+ DartType get convertedType => type;
+ @override String get message => '{0} has inferred type {1}';
+ @override List get arguments => [node, type];
+
+ toErrorCode() => new HintCode(name, message);
+}
+
+// Standard / unspecialized inferred type
+class InferredType extends InferredTypeBase {
+ InferredType(TypeRules rules, Expression expression, DartType type)
+ : super._internal(rules, expression, type);
+
+ // Factory to create correct InferredType variant.
+ static InferredTypeBase create(
+ TypeRules rules, Expression expression, DartType type) {
+ // Specialized inference:
+ if (expression is Literal) {
+ return new InferredTypeLiteral(rules, expression, type);
+ }
+ if (expression is InstanceCreationExpression) {
+ return new InferredTypeAllocation(rules, expression, type);
+ }
+ if (expression is FunctionExpression) {
+ return new InferredTypeClosure(rules, expression, type);
+ }
+ return new InferredType(rules, expression, type);
+ }
+}
+
+// An infered type for a literal expression.
+class InferredTypeLiteral extends InferredTypeBase {
+ InferredTypeLiteral(TypeRules rules, Expression expression, DartType type)
+ : super._internal(rules, expression, type);
+}
+
+// An inferred type for a non-literal allocation site.
+class InferredTypeAllocation extends InferredTypeBase {
+ InferredTypeAllocation(TypeRules rules, Expression expression, DartType type)
+ : super._internal(rules, expression, type);
+}
+
+// An inferred type for a closure expression
+class InferredTypeClosure extends InferredTypeBase {
+ InferredTypeClosure(TypeRules rules, Expression expression, DartType type)
+ : super._internal(rules, expression, type);
+}
+
+class DynamicInvoke extends CoercionInfo {
+ DynamicInvoke(TypeRules rules, Expression expression)
+ : super(rules, expression);
+
+ DartType get convertedType => rules.provider.dynamicType;
+ String get message => '{0} requires dynamic invoke';
+ toErrorCode() => new HintCode(name, message);
+
+ static const String _propertyName = 'dev_compiler.src.info.DynamicInvoke';
+
+ /// Whether this [node] is the target of a dynamic operation.
+ static bool get(AstNode node) {
+ var value = node.getProperty(_propertyName);
+ return value != null ? value : false;
+ }
+
+ /// Sets whether this node is the target of a dynamic operation.
+ static bool set(AstNode node, bool value) {
+ // Free the storage for things that aren't dynamic.
+ if (value == false) value = null;
+ node.setProperty(_propertyName, value);
+ return value;
+ }
+}
+
+abstract class StaticError extends StaticInfo {
+ final AstNode node;
+
+ StaticError(this.node);
+
+ String get message;
+
+ toErrorCode() => new CompileTimeErrorCode(name, message);
+}
+
+class StaticTypeError extends StaticError {
+ final DartType baseType;
+ final DartType expectedType;
+ String reason = null;
+
+ StaticTypeError(TypeRules rules, Expression expression, this.expectedType,
+ {this.reason})
+ : baseType = rules.getStaticType(expression),
+ super(expression);
+
+ @override List<Object> get arguments => [node, baseType, expectedType];
+ @override String get message =>
+ 'Type check failed: {0} ({1}) is not of type {2}' +
+ ((reason == null) ? '' : ' because $reason');
+}
+
+class InvalidVariableDeclaration extends StaticError {
+ final DartType expectedType;
+
+ InvalidVariableDeclaration(
+ TypeRules rules, AstNode declaration, this.expectedType)
+ : super(declaration);
+
+ @override List<Object> get arguments => [expectedType];
+ @override String get message => 'Type check failed: null is not of type {0}';
+}
+
+class InvalidParameterDeclaration extends StaticError {
+ final DartType expectedType;
+
+ InvalidParameterDeclaration(
+ TypeRules rules, FormalParameter declaration, this.expectedType)
+ : super(declaration);
+
+ @override List<Object> get arguments => [node, expectedType];
+ @override String get message => 'Type check failed: {0} is not of type {1}';
+}
+
+class NonGroundTypeCheckInfo extends StaticInfo {
+ final DartType type;
+ final AstNode node;
+
+ NonGroundTypeCheckInfo(this.node, this.type) {
+ assert(node is IsExpression || node is AsExpression);
+ }
+
+ @override List<Object> get arguments => [type];
+ String get message =>
+ "Runtime check on non-ground type {0} may throw StrongModeError";
+
+ toErrorCode() => new HintCode(name, message);
+}
+
+// Invalid override of an instance member of a class.
+abstract class InvalidOverride extends StaticError {
+ /// Member declaration with the invalid override.
+ final ExecutableElement element;
+
+ /// Type (class or interface) that provides the base declaration.
+ final InterfaceType base;
+
+ /// Actual type of the overridden member.
+ final DartType subType;
+
+ /// Actual type of the base member.
+ final DartType baseType;
+
+ /// Whether the error comes from combining a base class and an interface
+ final bool fromBaseClass;
+
+ /// Whether the error comes from a mixin (either overriding a base class or an
+ /// interface declaration).
+ final bool fromMixin;
+
+ InvalidOverride(
+ AstNode node, this.element, this.base, this.subType, this.baseType)
+ : fromBaseClass = node is ExtendsClause,
+ fromMixin = node.parent is WithClause,
+ super(node);
+
+ ClassElement get parent => element.enclosingElement;
+
+ @override List<Object> get arguments =>
+ [parent.name, element.name, subType, base, baseType];
+
+ String _messageHelper(String errorName) {
+ var lcErrorName = errorName.toLowerCase();
+ var intro = fromBaseClass
+ ? 'Base class introduces an $lcErrorName'
+ : (fromMixin ? 'Mixin introduces an $lcErrorName' : errorName);
+ return '$intro. The type of {0}.{1} ({2}) is not a '
+ 'subtype of {3}.{1} ({4}).';
+ }
+}
+
+// Invalid override due to incompatible type. I.e., the overridden signature
+// is not compatible with the original.
+class InvalidMethodOverride extends InvalidOverride {
+ InvalidMethodOverride(AstNode node, ExecutableElement element,
+ InterfaceType base, FunctionType subType, FunctionType baseType)
+ : super(node, element, base, subType, baseType);
+
+ String get message => _messageHelper('Invalid override');
+}
+
+/// Dart constructors have one weird quirk, illustrated with this example:
+///
+/// class Base {
+/// var x;
+/// Base() : x = print('Base.1') {
+/// print('Base.2');
+/// }
+/// }
+///
+/// class Derived extends Base {
+/// var y, z;
+/// Derived()
+/// : y = print('Derived.1'),
+/// super(),
+/// z = print('Derived.2') {
+/// print('Derived.3');
+/// }
+/// }
+///
+/// The order will be Derived.1, Base.1, Derived.2, Base.2, Derived.3; this
+/// ordering preserves the invariant that code can't observe uninitialized
+/// state, however it results in super constructor body not being run
+/// immediately after super initializers. Normally this isn't observable, but it
+/// could be if initializers have side effects.
+///
+/// Better to have `super` at the end, as required by the Dart style guide:
+/// <http://goo.gl/q1T4BB>
+///
+/// For now this is the only pattern we support.
+class InvalidSuperInvocation extends StaticError {
+ InvalidSuperInvocation(SuperConstructorInvocation node) : super(node);
+
+ @override String get message => "super call must be last in an initializer "
+ "list (see http://goo.gl/q1T4BB): {0}";
+}
« no previous file with comments | « packages/analyzer/lib/src/task/strong/checker.dart ('k') | packages/analyzer/lib/src/task/strong/rules.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698