| Index: lib/src/info.dart
|
| diff --git a/lib/src/info.dart b/lib/src/info.dart
|
| index 6947db6dfa90fa709f61c1daede8885fe1e2f79c..f1cb2d71ea31cd995d9bce053c8620c966d69f96 100644
|
| --- a/lib/src/info.dart
|
| +++ b/lib/src/info.dart
|
| @@ -190,12 +190,11 @@ abstract class Conversion extends Expression with StaticInfo {
|
| Iterable get childEntities => new ChildEntities()..add(expression);
|
| }
|
|
|
| -// A down cast from a subtype to a supertype. This must be checked at
|
| -// runtime to recover soundness.
|
| -abstract class DownCastBase extends Conversion {
|
| +// Base class for all casts from base type to sub type.
|
| +abstract class DownCast extends Conversion {
|
| Cast _cast;
|
|
|
| - DownCastBase._internal(TypeRules rules, Expression expression, this._cast)
|
| + DownCast._internal(TypeRules rules, Expression expression, this._cast)
|
| : super(rules, expression) {
|
| assert(_cast.toType != baseType &&
|
| _cast.fromType == baseType &&
|
| @@ -212,28 +211,8 @@ abstract class DownCastBase extends Conversion {
|
| String get message => '$expression ($baseType) will need runtime check '
|
| 'to cast to type $convertedType';
|
|
|
| - // Differentiate between Function down cast and non-Function down cast? The
|
| - // former seems less likely to actually succeed.
|
| - Level get level =>
|
| - (_cast.toType is FunctionType) ? Level.WARNING : super.level;
|
| -
|
| - accept(AstVisitor visitor) {
|
| - if (visitor is ConversionVisitor) {
|
| - return visitor.visitDownCastBase(this);
|
| - } else {
|
| - return expression.accept(visitor);
|
| - }
|
| - }
|
| -}
|
| -
|
| -// Standard / unspecialized down cast.
|
| -class DownCast extends DownCastBase {
|
| - DownCast(TypeRules rules, Expression expression, Cast cast)
|
| - : super._internal(rules, expression, cast);
|
| -
|
| // Factory to create correct DownCast variant.
|
| - static DownCastBase create(
|
| - TypeRules rules, Expression expression, Cast cast) {
|
| + static StaticInfo create(TypeRules rules, Expression expression, Cast cast) {
|
| final fromT = cast.fromType;
|
| final toT = cast.toType;
|
|
|
| @@ -242,55 +221,148 @@ class DownCast extends DownCastBase {
|
| // types, but the function type is not assignable to the class
|
| assert(toT.isSubtypeOf(fromT) || fromT.isAssignableTo(toT));
|
|
|
| - // Specialized casts:
|
| + // Handle null call specially.
|
| + if (expression is NullLiteral) {
|
| + if (rules.isNonNullableType(toT)) {
|
| + return new StaticTypeError(rules, expression, toT);
|
| + } else {
|
| + // We should only get here if some coercion is required.
|
| + assert(rules.maybeNonNullableType(toT));
|
| + // 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 DownCastLiteral(rules, expression, cast);
|
| + return new InferableLiteral(rules, expression, cast);
|
| + }
|
| + if (expression is FunctionExpression) {
|
| + // fromT should be an exact type - this will almost certainly fail at
|
| + // runtime.
|
| + return new InferableClosure(rules, expression, cast);
|
| }
|
| if (expression is InstanceCreationExpression) {
|
| // fromT should be an exact type - this will almost certainly fail at
|
| // runtime.
|
| - return new DownCastExact(rules, expression, cast);
|
| + return new InferableAllocation(rules, expression, cast);
|
| }
|
| - if (fromT.isSubtypeOf(toT) && !fromT.isDynamic) {
|
| +
|
| + // 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 DownCastDynamic(rules, expression, cast);
|
| + return new DownCastComposite(rules, expression, cast);
|
| + }
|
| +
|
| + // Dynamic cast
|
| + if (fromT.isDynamic) {
|
| + return new DynamicCast(rules, expression, cast);
|
| }
|
| - return new DownCast(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);
|
| }
|
| +
|
| + accept(AstVisitor visitor) {
|
| + if (visitor is ConversionVisitor) {
|
| + return visitor.visitDownCast(this);
|
| + } else {
|
| + return expression.accept(visitor);
|
| + }
|
| + }
|
| +}
|
| +
|
| +//
|
| +// 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);
|
| +
|
| + final Level level = Level.INFO;
|
| +}
|
| +
|
| +// 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);
|
| +
|
| + final Level level = Level.INFO;
|
| }
|
|
|
| -// A down cast that would be "unnecessary" with standard Dart rules.
|
| -// E.g., the fromType <: toType in standard Dart but not in our restricted
|
| -// rules. These occur due to our stricter rules on dynamic type parameters in
|
| -// generics.
|
| -class DownCastDynamic extends DownCastBase {
|
| - DownCastDynamic(TypeRules rules, Expression expression, Cast cast)
|
| +//
|
| +// 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.
|
| +//
|
| +
|
| +// A "down cast" on a literal expression.
|
| +class InferableLiteral extends DownCast {
|
| + InferableLiteral(TypeRules rules, Literal expression, Cast cast)
|
| : super._internal(rules, expression, cast);
|
|
|
| final Level level = Level.WARNING;
|
| }
|
|
|
| -// A down cast on a literal expression. This should never succeed.
|
| -// TODO(vsm): Mark as severe / error?
|
| -class DownCastLiteral extends DownCastBase {
|
| - DownCastLiteral(TypeRules rules, Expression expression, Cast cast)
|
| +// A "down cast" on a closure literal.
|
| +class InferableClosure extends DownCast {
|
| + InferableClosure(TypeRules rules, FunctionExpression expression, Cast cast)
|
| : super._internal(rules, expression, cast);
|
|
|
| final Level level = Level.WARNING;
|
| }
|
|
|
| -// A down cast on a non-literal allocation site. This should never succeed.
|
| -// TODO(vsm): Mark as severe / error?
|
| -class DownCastExact extends DownCastBase {
|
| - DownCastExact(TypeRules rules, Expression expression, Cast cast)
|
| +// A "down cast" on a non-literal allocation site.
|
| +class InferableAllocation extends DownCast {
|
| + InferableAllocation(
|
| + TypeRules rules, InstanceCreationExpression expression, Cast cast)
|
| : super._internal(rules, expression, cast);
|
|
|
| final Level level = Level.WARNING;
|
| }
|
|
|
| +//
|
| +// 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);
|
| +
|
| + final Level level = Level.WARNING;
|
| +}
|
| +
|
| +// 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);
|
| +
|
| + final Level level = Level.WARNING;
|
| +}
|
| +
|
| +// TODO(vsm): Remove these.
|
| +
|
| // A wrapped closure coerces the underlying type to the desired type.
|
| class ClosureWrapBase extends Conversion {
|
| FunctionType _wrappedType;
|
| @@ -581,10 +653,7 @@ abstract class ConversionVisitor<R> implements AstVisitor<R> {
|
| R visitConversion(Conversion node) => visitNode(node);
|
|
|
| // Methods for conversion subtypes:
|
| - R visitDownCastBase(DownCastBase node) => visitConversion(node);
|
| - R visitDownCast(DownCast node) => visitDownCastBase(node);
|
| - R visitDownCastDynamic(DownCastDynamic node) => visitDownCastBase(node);
|
| - R visitDownCastExact(DownCastExact node) => visitDownCastBase(node);
|
| + R visitDownCast(DownCast node) => visitConversion(node);
|
| R visitClosureWrapBase(ClosureWrapBase node) => visitConversion(node);
|
| R visitClosureWrap(ClosureWrap node) => visitClosureWrapBase(node);
|
| R visitDynamicInvoke(DynamicInvoke node) => visitConversion(node);
|
|
|