Disable implicit casts but keep dynamic casts when NNBD enabled

Change-Id: Ia0a3271c9137bc8c7fa4cdbd469cf93d9453b69c
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/103405
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Paul Berry <paulberry@google.com>
Commit-Queue: Mike Fairhurst <mfairhurst@google.com>
diff --git a/pkg/analyzer/lib/src/dart/constant/evaluation.dart b/pkg/analyzer/lib/src/dart/constant/evaluation.dart
index 3c98239..53e8356 100644
--- a/pkg/analyzer/lib/src/dart/constant/evaluation.dart
+++ b/pkg/analyzer/lib/src/dart/constant/evaluation.dart
@@ -1606,6 +1606,7 @@
             typeSystem.isAssignableTo(staticType, _typeProvider.boolType)) {
           // If the static type is not assignable, then we will have already
           // reported this error.
+          // TODO(mfairhurst) get the FeatureSet to suppress this for nnbd too.
           _errorReporter.reportErrorForNode(
               CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION, condition);
         }
diff --git a/pkg/analyzer/lib/src/error/inheritance_override.dart b/pkg/analyzer/lib/src/error/inheritance_override.dart
index d120057..9602922 100644
--- a/pkg/analyzer/lib/src/error/inheritance_override.dart
+++ b/pkg/analyzer/lib/src/error/inheritance_override.dart
@@ -2,12 +2,14 @@
 // 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.
 
+import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/constant/value.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/error/error.dart';
 import 'package:analyzer/error/listener.dart';
+import 'package:analyzer/src/dart/ast/ast.dart';
 import 'package:analyzer/src/dart/constant/value.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/inheritance_manager2.dart';
@@ -37,6 +39,7 @@
           typeProvider: _typeProvider,
           inheritance: _inheritance,
           reporter: _reporter,
+          featureSet: unit.featureSet,
           library: library,
           classNameNode: declaration.name,
           implementsClause: declaration.implementsClause,
@@ -50,6 +53,7 @@
           typeProvider: _typeProvider,
           inheritance: _inheritance,
           reporter: _reporter,
+          featureSet: unit.featureSet,
           library: library,
           classNameNode: declaration.name,
           implementsClause: declaration.implementsClause,
@@ -62,6 +66,7 @@
           typeProvider: _typeProvider,
           inheritance: _inheritance,
           reporter: _reporter,
+          featureSet: unit.featureSet,
           library: library,
           classNameNode: declaration.name,
           implementsClause: declaration.implementsClause,
@@ -85,6 +90,7 @@
   final InheritanceManager2 inheritance;
   final ErrorReporter reporter;
 
+  final FeatureSet featureSet;
   final LibraryElement library;
   final Uri libraryUri;
   final ClassElementImpl classElement;
@@ -108,6 +114,7 @@
     this.typeProvider,
     this.inheritance,
     this.reporter,
+    this.featureSet,
     this.library,
     this.classNameNode,
     this.implementsClause,
@@ -382,7 +389,8 @@
         if (setter != null && setter.parameters.length == 1) {
           var getterType = getter.returnType;
           var setterType = setter.parameters[0].type;
-          if (!typeSystem.isAssignableTo(getterType, setterType)) {
+          if (!typeSystem.isAssignableTo(getterType, setterType,
+              featureSet: featureSet)) {
             var getterElement = getter.element;
             var setterElement = setter.element;
 
diff --git a/pkg/analyzer/lib/src/error/literal_element_verifier.dart b/pkg/analyzer/lib/src/error/literal_element_verifier.dart
index 89dcdce..ba32987 100644
--- a/pkg/analyzer/lib/src/error/literal_element_verifier.dart
+++ b/pkg/analyzer/lib/src/error/literal_element_verifier.dart
@@ -2,6 +2,7 @@
 // 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.
 
+import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/type.dart';
@@ -15,6 +16,7 @@
   final TypeProvider typeProvider;
   final TypeSystem typeSystem;
   final ErrorReporter errorReporter;
+  final FeatureSet featureSet;
   final bool Function(Expression) checkForUseOfVoidResult;
 
   final bool forList;
@@ -36,6 +38,7 @@
     this.forMap = false,
     this.mapKeyType,
     this.mapValueType,
+    this.featureSet,
   });
 
   void verify(CollectionElement element) {
@@ -45,7 +48,7 @@
   /// Check that the given [type] is assignable to the [elementType], otherwise
   /// report the list or set error on the [errorNode].
   void _checkAssignableToElementType(DartType type, AstNode errorNode) {
-    if (!typeSystem.isAssignableTo(type, elementType)) {
+    if (!typeSystem.isAssignableTo(type, elementType, featureSet: featureSet)) {
       var errorCode = forList
           ? StaticWarningCode.LIST_ELEMENT_TYPE_NOT_ASSIGNABLE
           : StaticWarningCode.SET_ELEMENT_TYPE_NOT_ASSIGNABLE;
@@ -106,7 +109,8 @@
     }
 
     var keyType = entry.key.staticType;
-    if (!typeSystem.isAssignableTo(keyType, mapKeyType)) {
+    if (!typeSystem.isAssignableTo(keyType, mapKeyType,
+        featureSet: featureSet)) {
       errorReporter.reportTypeErrorForNode(
         StaticWarningCode.MAP_KEY_TYPE_NOT_ASSIGNABLE,
         entry.key,
@@ -115,7 +119,8 @@
     }
 
     var valueType = entry.value.staticType;
-    if (!typeSystem.isAssignableTo(valueType, mapValueType)) {
+    if (!typeSystem.isAssignableTo(valueType, mapValueType,
+        featureSet: featureSet)) {
       errorReporter.reportTypeErrorForNode(
         StaticWarningCode.MAP_VALUE_TYPE_NOT_ASSIGNABLE,
         entry.value,
@@ -157,7 +162,8 @@
     }
 
     var iterableElementType = iterableType.typeArguments[0];
-    if (!typeSystem.isAssignableTo(iterableElementType, elementType)) {
+    if (!typeSystem.isAssignableTo(iterableElementType, elementType,
+        featureSet: featureSet)) {
       var errorCode = forList
           ? StaticWarningCode.LIST_ELEMENT_TYPE_NOT_ASSIGNABLE
           : StaticWarningCode.SET_ELEMENT_TYPE_NOT_ASSIGNABLE;
@@ -200,7 +206,8 @@
     }
 
     var keyType = mapType.typeArguments[0];
-    if (!typeSystem.isAssignableTo(keyType, mapKeyType)) {
+    if (!typeSystem.isAssignableTo(keyType, mapKeyType,
+        featureSet: featureSet)) {
       errorReporter.reportTypeErrorForNode(
         StaticWarningCode.MAP_KEY_TYPE_NOT_ASSIGNABLE,
         expression,
@@ -209,7 +216,8 @@
     }
 
     var valueType = mapType.typeArguments[1];
-    if (!typeSystem.isAssignableTo(valueType, mapValueType)) {
+    if (!typeSystem.isAssignableTo(valueType, mapValueType,
+        featureSet: featureSet)) {
       errorReporter.reportTypeErrorForNode(
         StaticWarningCode.MAP_VALUE_TYPE_NOT_ASSIGNABLE,
         expression,
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index 1ea57d9..84d247d 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -291,7 +291,8 @@
   /// fixed.
   final bool disableConflictingGenericsCheck;
 
-  bool _isNonNullable = false;
+  /// The features enabled in the unit currently being checked for errors.
+  FeatureSet _featureSet;
 
   /**
    * Initialize a newly created error verifier.
@@ -343,6 +344,9 @@
     _enclosingClass = classElement;
   }
 
+  bool get _isNonNullable =>
+      _featureSet?.isEnabled(Feature.non_nullable) ?? false;
+
   @override
   void visitAnnotation(Annotation node) {
     _checkForInvalidAnnotationFromDeferredLibrary(node);
@@ -558,11 +562,11 @@
 
   @override
   void visitCompilationUnit(CompilationUnit node) {
-    _isNonNullable = node.featureSet.isEnabled(Feature.non_nullable);
+    _featureSet = node.featureSet;
     _checkDuplicateUnitMembers(node);
     _checkForDeferredPrefixCollisions(node);
     super.visitCompilationUnit(node);
-    _isNonNullable = false;
+    _featureSet = null;
   }
 
   @override
@@ -2103,8 +2107,8 @@
     FunctionType constructorType =
         resolutionMap.elementDeclaredByConstructorDeclaration(declaration).type;
     DartType constructorReturnType = constructorType.returnType;
-    if (!_typeSystem.isAssignableTo(
-        redirectedReturnType, constructorReturnType)) {
+    if (!_typeSystem.isAssignableTo(redirectedReturnType, constructorReturnType,
+        featureSet: _featureSet)) {
       _errorReporter.reportErrorForNode(
           StaticWarningCode.REDIRECT_TO_INVALID_RETURN_TYPE,
           redirectedConstructor,
@@ -2323,7 +2327,8 @@
     if (expressionType == null) {
       return;
     }
-    if (_typeSystem.isAssignableTo(expressionType, type)) {
+    if (_typeSystem.isAssignableTo(expressionType, type,
+        featureSet: _featureSet)) {
       return;
     }
     _errorReporter.reportErrorForNode(errorCode, expression, arguments);
@@ -2342,7 +2347,8 @@
       DartType actualStaticType,
       DartType expectedStaticType,
       ErrorCode errorCode) {
-    if (!_typeSystem.isAssignableTo(actualStaticType, expectedStaticType)) {
+    if (!_typeSystem.isAssignableTo(actualStaticType, expectedStaticType,
+        featureSet: _featureSet)) {
       _errorReporter.reportTypeErrorForNode(
           errorCode, expression, [actualStaticType, expectedStaticType]);
       return false;
@@ -3049,7 +3055,8 @@
           StaticTypeWarningCode.FOR_IN_OF_INVALID_TYPE,
           node.iterable,
           [iterableType, loopTypeName]);
-    } else if (!_typeSystem.isAssignableTo(bestIterableType, variableType)) {
+    } else if (!_typeSystem.isAssignableTo(bestIterableType, variableType,
+        featureSet: _featureSet)) {
       _errorReporter.reportTypeErrorForNode(
           StaticTypeWarningCode.FOR_IN_OF_INVALID_ELEMENT_TYPE,
           node.iterable,
@@ -3223,7 +3230,8 @@
     if (staticType == null) {
       return;
     }
-    if (_typeSystem.isAssignableTo(staticType, fieldType)) {
+    if (_typeSystem.isAssignableTo(staticType, fieldType,
+        featureSet: _featureSet)) {
       return;
     }
     // report problem
@@ -3847,7 +3855,8 @@
     }
     DartType leftType = getStaticType(lhs);
     DartType rightType = getStaticType(assignment);
-    if (!_typeSystem.isAssignableTo(rightType, leftType)) {
+    if (!_typeSystem.isAssignableTo(rightType, leftType,
+        featureSet: _featureSet)) {
       _errorReporter.reportTypeErrorForNode(
           StaticTypeWarningCode.INVALID_ASSIGNMENT, rhs, [rightType, leftType]);
     }
@@ -3960,6 +3969,7 @@
       _checkForUseOfVoidResult,
       forList: true,
       elementType: listElementType,
+      featureSet: _featureSet,
     );
     for (CollectionElement element in literal.elements) {
       verifier.verify(element);
@@ -3995,6 +4005,7 @@
         forMap: true,
         mapKeyType: keyType,
         mapValueType: valueType,
+        featureSet: _featureSet,
       );
       for (CollectionElement element in literal.elements) {
         verifier.verify(element);
@@ -4069,7 +4080,8 @@
       // (if the getter is null, it is dynamic which is assignable to everything).
       if (setterType != null &&
           getterType != null &&
-          !_typeSystem.isAssignableTo(getterType, setterType)) {
+          !_typeSystem.isAssignableTo(getterType, setterType,
+              featureSet: _featureSet)) {
         _errorReporter.reportTypeErrorForNode(
             StaticWarningCode.MISMATCHED_GETTER_AND_SETTER_TYPES,
             accessorDeclaration,
@@ -4539,7 +4551,8 @@
     if (!_checkForNullableDereference(condition) &&
         !_checkForUseOfVoidResult(condition) &&
         conditionType != null &&
-        !_typeSystem.isAssignableTo(conditionType, _boolType)) {
+        !_typeSystem.isAssignableTo(conditionType, _boolType,
+            featureSet: _featureSet)) {
       _errorReporter.reportErrorForNode(
           StaticTypeWarningCode.NON_BOOL_CONDITION, condition);
     }
@@ -4555,7 +4568,8 @@
     Expression expression = assertion.condition;
     DartType type = getStaticType(expression);
     if (type is InterfaceType) {
-      if (!_typeSystem.isAssignableTo(type, _boolType)) {
+      if (!_typeSystem.isAssignableTo(type, _boolType,
+          featureSet: _featureSet)) {
         _errorReporter.reportErrorForNode(
             StaticTypeWarningCode.NON_BOOL_EXPRESSION, expression);
       }
@@ -4573,7 +4587,8 @@
   void _checkForNonBoolNegationExpression(Expression expression) {
     DartType conditionType = getStaticType(expression);
     if (conditionType != null &&
-        !_typeSystem.isAssignableTo(conditionType, _boolType)) {
+        !_typeSystem.isAssignableTo(conditionType, _boolType,
+            featureSet: _featureSet)) {
       _errorReporter.reportErrorForNode(
           StaticTypeWarningCode.NON_BOOL_NEGATION_EXPRESSION, expression);
     }
@@ -5162,7 +5177,8 @@
       var checkWithType = (!_inAsync)
           ? fromType
           : _typeProvider.futureType.instantiate(<DartType>[fromType]);
-      if (_typeSystem.isAssignableTo(checkWithType, expectedType)) {
+      if (_typeSystem.isAssignableTo(checkWithType, expectedType,
+          featureSet: _featureSet)) {
         return;
       }
     }
@@ -5200,6 +5216,7 @@
         _checkForUseOfVoidResult,
         forSet: true,
         elementType: setElementType,
+        featureSet: _featureSet,
       );
       for (CollectionElement element in literal.elements) {
         verifier.verify(element);
@@ -5266,7 +5283,8 @@
     DartType caseType = getStaticType(caseExpression);
 
     // check types
-    if (!_typeSystem.isAssignableTo(expressionType, caseType)) {
+    if (!_typeSystem.isAssignableTo(expressionType, caseType,
+        featureSet: _featureSet)) {
       _errorReporter.reportErrorForNode(
           StaticWarningCode.SWITCH_EXPRESSION_NOT_ASSIGNABLE,
           expression,
@@ -5592,7 +5610,8 @@
                 [parameter.identifier.name]);
           } else if (declaredType != null &&
               fieldType != null &&
-              !_typeSystem.isAssignableTo(declaredType, fieldType)) {
+              !_typeSystem.isAssignableTo(declaredType, fieldType,
+                  featureSet: _featureSet)) {
             _errorReporter.reportTypeErrorForNode(
                 StaticWarningCode.FIELD_INITIALIZING_FORMAL_NOT_ASSIGNABLE,
                 parameter,
@@ -5741,7 +5760,8 @@
       } else {
         requiredReturnType = _typeProvider.iterableDynamicType;
       }
-      if (!_typeSystem.isAssignableTo(impliedReturnType, requiredReturnType)) {
+      if (!_typeSystem.isAssignableTo(impliedReturnType, requiredReturnType,
+          featureSet: _featureSet)) {
         _errorReporter.reportTypeErrorForNode(
             StaticTypeWarningCode.YIELD_OF_INVALID_TYPE,
             yieldExpression,
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index dc2e4ce..5749304 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -602,8 +602,10 @@
     var context = InferenceContext.getContext(
         (node as IntegerLiteralImpl).immediatelyNegated ? node.parent : node);
     if (context == null ||
-        _typeSystem.isAssignableTo(_typeProvider.intType, context) ||
-        !_typeSystem.isAssignableTo(_typeProvider.doubleType, context)) {
+        _typeSystem.isAssignableTo(_typeProvider.intType, context,
+            featureSet: _featureSet) ||
+        !_typeSystem.isAssignableTo(_typeProvider.doubleType, context,
+            featureSet: _featureSet)) {
       _recordStaticType(node, _nonNullable(_typeProvider.intType));
     } else {
       _recordStaticType(node, _nonNullable(_typeProvider.doubleType));
@@ -1165,7 +1167,8 @@
   void _checkForInvalidAssignmentIncDec(
       AstNode node, Expression operand, DartType type) {
     var operandWriteType = _getStaticType(operand);
-    if (!_typeSystem.isAssignableTo(type, operandWriteType)) {
+    if (!_typeSystem.isAssignableTo(type, operandWriteType,
+        featureSet: _featureSet)) {
       _resolver.errorReporter.reportTypeErrorForNode(
         StaticTypeWarningCode.INVALID_ASSIGNMENT,
         node,
diff --git a/pkg/analyzer/lib/src/generated/type_system.dart b/pkg/analyzer/lib/src/generated/type_system.dart
index 4ef1a61..6b28896 100644
--- a/pkg/analyzer/lib/src/generated/type_system.dart
+++ b/pkg/analyzer/lib/src/generated/type_system.dart
@@ -75,7 +75,8 @@
       new HashSet<TypeComparison>();
 
   /**
-   * True if implicit casts should be allowed, otherwise false.
+   * False if implicit casts should always be disallowed, otherwise the
+   * [FeatureSet] will be used.
    *
    * This affects the behavior of [isAssignableTo].
    */
@@ -448,7 +449,8 @@
   }
 
   @override
-  bool isAssignableTo(DartType fromType, DartType toType) {
+  bool isAssignableTo(DartType fromType, DartType toType,
+      {FeatureSet featureSet}) {
     // An actual subtype
     if (isSubtypeOf(fromType, toType)) {
       return true;
@@ -457,15 +459,23 @@
     // A call method tearoff
     if (fromType is InterfaceType && acceptsFunctionType(toType)) {
       var callMethodType = getCallMethodType(fromType);
-      if (callMethodType != null && isAssignableTo(callMethodType, toType)) {
+      if (callMethodType != null &&
+          isAssignableTo(callMethodType, toType, featureSet: featureSet)) {
         return true;
       }
     }
 
+    // First make sure --no-implicit-casts disables all downcasts, including
+    // dynamic casts.
     if (!implicitCasts) {
       return false;
     }
 
+    // Now handle NNBD default behavior, where we disable non-dynamic downcasts.
+    if (featureSet != null && featureSet.isEnabled(Feature.non_nullable)) {
+      return fromType.isDynamic;
+    }
+
     // Don't allow implicit downcasts between function types
     // and call method objects, as these will almost always fail.
     if (fromType is FunctionType && getCallMethodType(toType) != null) {
@@ -484,8 +494,7 @@
       return false;
     }
 
-    // If the subtype relation goes the other way, allow the implicit
-    // downcast.
+    // If the subtype relation goes the other way, allow the implicit downcast.
     if (isSubtypeOf(toType, fromType)) {
       // TODO(leafp,jmesserly): we emit warnings/hints for these in
       // src/task/strong/checker.dart, which is a bit inconsistent. That
@@ -1978,9 +1987,11 @@
 
   /**
    * Return `true` if the [leftType] is assignable to the [rightType] (that is,
-   * if leftType <==> rightType).
+   * if leftType <==> rightType). Accepts a [FeatureSet] to correctly handle
+   * NNBD implicit downcasts.
    */
-  bool isAssignableTo(DartType leftType, DartType rightType);
+  bool isAssignableTo(DartType leftType, DartType rightType,
+      {FeatureSet featureSet});
 
   /**
    * Return `true` if the [leftType] is more specific than the [rightType]
diff --git a/pkg/analyzer/lib/src/task/strong/checker.dart b/pkg/analyzer/lib/src/task/strong/checker.dart
index e451ec6..2ca6313 100644
--- a/pkg/analyzer/lib/src/task/strong/checker.dart
+++ b/pkg/analyzer/lib/src/task/strong/checker.dart
@@ -1118,7 +1118,7 @@
     }
 
     // Down cast or legal sideways cast, coercion needed.
-    if (rules.isAssignableTo(from, to)) {
+    if (rules.isAssignableTo(from, to, featureSet: _featureSet)) {
       return true;
     }
 
diff --git a/pkg/analyzer/test/src/diagnostics/argument_type_not_assignable_test.dart b/pkg/analyzer/test/src/diagnostics/argument_type_not_assignable_test.dart
index 28b285e..06192b0 100644
--- a/pkg/analyzer/test/src/diagnostics/argument_type_not_assignable_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/argument_type_not_assignable_test.dart
@@ -2,7 +2,9 @@
 // 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.
 
+import 'package:analyzer/src/dart/analysis/experiments.dart';
 import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/engine.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import '../dart/resolution/driver_resolution.dart';
@@ -10,6 +12,7 @@
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(ArgumentTypeNotAssignableTest);
+    defineReflectiveTests(ArgumentTypeNotAssignableTest_NNBD);
   });
 }
 
@@ -41,3 +44,45 @@
     ]);
   }
 }
+
+@reflectiveTest
+class ArgumentTypeNotAssignableTest_NNBD extends ArgumentTypeNotAssignableTest {
+  @override
+  AnalysisOptionsImpl get analysisOptions =>
+      AnalysisOptionsImpl()..enabledExperiments = [EnableString.non_nullable];
+
+  test_downcast() async {
+    await assertErrorsInCode(r'''
+m() {
+  num y = 1;
+  n(y);
+}
+n(int x) {}
+''', [
+      error(StaticWarningCode.ARGUMENT_TYPE_NOT_ASSIGNABLE, 23, 1),
+    ]);
+  }
+
+  @failingTest
+  test_downcast_nullableNonNullable() async {
+    await assertErrorsInCode(r'''
+m() {
+  int? y;
+  n(y);
+}
+n(int x) {}
+''', [
+      error(StaticWarningCode.ARGUMENT_TYPE_NOT_ASSIGNABLE, 24, 1),
+    ]);
+  }
+
+  test_dynamicCast() async {
+    await assertNoErrorsInCode(r'''
+m() {
+  dynamic i;
+  n(i);
+}
+n(int i) {}
+''');
+  }
+}
diff --git a/tests/language_2/nnbd/static_errors/implicit_downcasts.dart b/tests/language_2/nnbd/static_errors/implicit_downcasts.dart
new file mode 100644
index 0000000..6d8b7b4
--- /dev/null
+++ b/tests/language_2/nnbd/static_errors/implicit_downcasts.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2019, 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.
+
+// SharedOptions=--enable-experiment=non-nullable
+
+// Test that it is an error to do what was once allowed as an "implicit
+// downcast."
+main() {
+  num asNum = 1;
+  Object asObject = 1;
+  dynamic asDynamic = 1;
+  int asInt1 = asNum; //# 01: compile-time error
+  double asDouble1 = asNum; //# 02: compile-time error
+  int asInt2 = asObject; //# 03: compile-time error
+  double asDouble2 = asObject; //# 04: compile-time error
+  String asString1 = asObject; //# 05: compile-time error
+  int asInt3 = asDynamic; //# 06: ok
+}