[vm] Use TFA to remove explicit type-checks (including keyword-covariant parameters).
- Also allow using the unchecked entry-point for invocations of generic functions where
there are no bounds or the bounds don't require dynamic checks.
Change-Id: I6ca1ebec777ecf2989c4fb77425d65d542d5adf2
Cq-Include-Trybots: luci.dart.try:vm-kernel-optcounter-threshold-linux-release-x64-try, vm-kernel-precomp-linux-debug-x64-try, vm-kernel-precomp-linux-release-simarm-try, vm-kernel-precomp-linux-release-simarm64-try, vm-kernel-precomp-linux-release-x64-try, vm-kernel-precomp-mac-release-simarm64-try, vm-kernel-precomp-win-release-x64-try
Reviewed-on: https://dart-review.googlesource.com/c/87181
Commit-Queue: Samir Jindel <sjindel@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
diff --git a/pkg/vm/lib/transformations/type_flow/analysis.dart b/pkg/vm/lib/transformations/type_flow/analysis.dart
index 9db07f3..71d48cb 100644
--- a/pkg/vm/lib/transformations/type_flow/analysis.dart
+++ b/pkg/vm/lib/transformations/type_flow/analysis.dart
@@ -154,7 +154,8 @@
//
// TODO(sjindel): Use [TypeCheck] to avoid bounds checks.
if (selector.member.function != null) {
- typeChecksNeeded = !selector.member.function.typeParameters.isEmpty;
+ typeChecksNeeded = selector.member.function.typeParameters
+ .any((t) => t.isGenericCovariantImpl);
}
}
@@ -1206,6 +1207,7 @@
Class get futureOrClass => environment.coreTypes.futureOrClass;
Class get futureClass => environment.coreTypes.futureClass;
+ Class get functionClass => environment.coreTypes.functionClass;
}
class _WorkList {
@@ -1395,10 +1397,16 @@
Call callSite(TreeNode node) => summaryCollector.callSites[node];
+ TypeCheck explicitCast(AsExpression cast) =>
+ summaryCollector.explicitCasts[cast];
+
Type fieldType(Field field) => _fieldValues[field]?.value;
Args<Type> argumentTypes(Member member) => _summaries[member]?.argumentTypes;
+ List<VariableDeclaration> uncheckedParameters(Member member) =>
+ _summaries[member]?.uncheckedParameters;
+
bool isTearOffTaken(Member member) => _tearOffTaken.contains(member);
/// Returns true if this member is called dynamically.
diff --git a/pkg/vm/lib/transformations/type_flow/summary.dart b/pkg/vm/lib/transformations/type_flow/summary.dart
index f914693..01529f7 100644
--- a/pkg/vm/lib/transformations/type_flow/summary.dart
+++ b/pkg/vm/lib/transformations/type_flow/summary.dart
@@ -413,9 +413,30 @@
TypeExpr arg;
TypeExpr type;
- final VariableDeclaration parameter;
+ // The Kernel which this TypeCheck corresponds to. Can be a
+ // VariableDeclaration, AsExpression or Field.
+ //
+ // VariableDeclaration is used for parameter type-checks.
+ // Field is used for type-checks of parameters to implicit setters.
+ final TreeNode node;
- TypeCheck(this.arg, this.type, this.parameter);
+ final Type staticType;
+
+ // 'isTestedOnlyOnCheckedEntryPoint' is whether or not this parameter's type-check will
+ // occur on the "checked" entrypoint in the VM but will be skipped on
+ // "unchecked" entrypoint.
+ bool isTestedOnlyOnCheckedEntryPoint;
+
+ VariableDeclaration get parameter =>
+ node is VariableDeclaration ? node : null;
+
+ bool canAlwaysSkip = true;
+
+ TypeCheck(this.arg, this.type, this.node, this.staticType) {
+ assertx(node != null);
+ isTestedOnlyOnCheckedEntryPoint =
+ parameter != null && !parameter.isCovariant;
+ }
@override
void accept(StatementVisitor visitor) => visitor.visitTypeCheck(this);
@@ -423,9 +444,7 @@
@override
String dump() {
String result = "$label = _TypeCheck ($arg against $type)";
- if (parameter != null) {
- result += " (for parameter ${parameter.name})";
- }
+ result += " (for ${node})";
return result;
}
@@ -437,33 +456,35 @@
// TODO(sjindel/tfa): Narrow the result if possible.
assertx(checkType is AnyType || checkType is RuntimeType);
+ bool canSkip = true; // Can this check be skipped on this invocation.
+
if (checkType is AnyType) {
// If we don't know what the RHS of the check is going to be, we can't
// guarantee that it will pass.
- callHandler.typeCheckTriggered();
- if (kPrintTrace) {
- tracePrint("TypeCheck failed, type is unknown");
- }
+ canSkip = false;
} else if (checkType is RuntimeType) {
- final bool canSkip =
- argType.isSubtypeOfRuntimeType(typeHierarchy, checkType);
- if (!canSkip) {
- callHandler.typeCheckTriggered();
- if (kPrintTrace) {
- tracePrint("TypeCheck of $argType against $checkType failed.");
- }
- }
+ canSkip = argType.isSubtypeOfRuntimeType(typeHierarchy, checkType);
argType = argType.intersection(
Type.fromStatic(checkType.representedTypeRaw), typeHierarchy);
} else {
assertx(false, details: "Cannot see $checkType on RHS of TypeCheck.");
}
- if (parameter != null) {
- argType =
- argType.intersection(Type.fromStatic(parameter.type), typeHierarchy);
+ // If this check might be skipped on an
+ // unchecked entry-point, we need to signal that the call-site must be
+ // checked.
+ if (!canSkip) {
+ canAlwaysSkip = false;
+ if (isTestedOnlyOnCheckedEntryPoint) {
+ callHandler.typeCheckTriggered();
+ }
+ if (kPrintTrace) {
+ tracePrint("TypeCheck of $argType against $checkType failed.");
+ }
}
+ argType = argType.intersection(staticType, typeHierarchy);
+
return argType;
}
}
@@ -602,4 +623,16 @@
}
return new Args<Type>(argTypes, names: argNames);
}
+
+ List<VariableDeclaration> get uncheckedParameters {
+ final params = List<VariableDeclaration>();
+ for (Statement statement in _statements) {
+ if (statement is TypeCheck &&
+ statement.canAlwaysSkip &&
+ statement.parameter != null) {
+ params.add(statement.parameter);
+ }
+ }
+ return params;
+ }
}
diff --git a/pkg/vm/lib/transformations/type_flow/summary_collector.dart b/pkg/vm/lib/transformations/type_flow/summary_collector.dart
index 483ca7f..af0e734 100644
--- a/pkg/vm/lib/transformations/type_flow/summary_collector.dart
+++ b/pkg/vm/lib/transformations/type_flow/summary_collector.dart
@@ -61,7 +61,7 @@
}
for (Statement st in statements) {
- if (st is Call) {
+ if (st is Call || st is TypeCheck) {
_normalizeExpr(st, false);
} else if (st is Use) {
_normalizeExpr(st.arg, true);
@@ -283,6 +283,8 @@
final GenericInterfacesInfo _genericInterfacesInfo;
final Map<TreeNode, Call> callSites = <TreeNode, Call>{};
+ final Map<AsExpression, TypeCheck> explicitCasts =
+ <AsExpression, TypeCheck>{};
final _FallthroughDetector _fallthroughDetector = new _FallthroughDetector();
Summary _summary;
@@ -338,7 +340,8 @@
} else {
Parameter valueParam = _declareParameter("value", member.type, null);
TypeExpr runtimeType = _translator.translate(member.type);
- final check = new TypeCheck(valueParam, runtimeType, null);
+ final check = new TypeCheck(
+ valueParam, runtimeType, member, Type.fromStatic(member.type));
_summary.add(check);
_summary.result = check;
}
@@ -393,17 +396,19 @@
}
for (int i = 0; i < function.positionalParameters.length; ++i) {
+ final decl = function.positionalParameters[i];
_declareParameter(
- function.positionalParameters[i].name,
- function.positionalParameters[i].isGenericCovariantImpl
+ decl.name,
+ _useTypeCheckForParameter(decl)
? null
: useTypesFrom.positionalParameters[i].type,
function.positionalParameters[i].initializer);
}
for (int i = 0; i < function.namedParameters.length; ++i) {
+ final decl = function.namedParameters[i];
_declareParameter(
- function.namedParameters[i].name,
- function.namedParameters[i].isGenericCovariantImpl
+ decl.name,
+ _useTypeCheckForParameter(decl)
? null
: useTypesFrom.namedParameters[i].type,
function.namedParameters[i].initializer);
@@ -411,15 +416,16 @@
int count = firstParamIndex;
for (int i = 0; i < function.positionalParameters.length; ++i) {
- Join v = _declareVariable(function.positionalParameters[i],
- useTypeCheck:
- function.positionalParameters[i].isGenericCovariantImpl,
+ final decl = function.positionalParameters[i];
+ Join v = _declareVariable(decl,
+ useTypeCheck: _useTypeCheckForParameter(decl),
checkType: useTypesFrom.positionalParameters[i].type);
v.values.add(_summary.statements[count++]);
}
for (int i = 0; i < function.namedParameters.length; ++i) {
- Join v = _declareVariable(function.namedParameters[i],
- useTypeCheck: function.namedParameters[i].isGenericCovariantImpl,
+ final decl = function.namedParameters[i];
+ Join v = _declareVariable(decl,
+ useTypeCheck: _useTypeCheckForParameter(decl),
checkType: useTypesFrom.namedParameters[i].type);
v.values.add(_summary.statements[count++]);
}
@@ -470,6 +476,10 @@
return _summary;
}
+ bool _useTypeCheckForParameter(VariableDeclaration decl) {
+ return decl.isCovariant || decl.isGenericCovariantImpl;
+ }
+
Args<Type> rawArguments(Selector selector) {
final member = selector.member;
assertx(member != null);
@@ -599,9 +609,9 @@
TypeExpr variable = join;
if (useTypeCheck) {
TypeExpr runtimeType = _translator.translate(type);
- variable = new TypeCheck(variable, runtimeType, decl);
+ variable = new TypeCheck(
+ variable, runtimeType, decl, Type.fromStatic(decl.type));
_summary.add(variable);
- _summary.add(new Use(variable));
}
_variables[decl] = variable;
@@ -729,15 +739,10 @@
TypeExpr visitAsExpression(AsExpression node) {
TypeExpr operand = _visit(node.operand);
Type type = new Type.fromStatic(node.type);
-
- TypeExpr result = _makeNarrow(operand, type);
-
TypeExpr runtimeType = _translator.translate(node.type);
- if (runtimeType is Statement) {
- result = new TypeCheck(operand, runtimeType, /*parameter=*/ null);
- _summary.add(result);
- }
-
+ TypeExpr result = new TypeCheck(operand, runtimeType, node, type);
+ explicitCasts[node] = result;
+ _summary.add(result);
return result;
}
diff --git a/pkg/vm/lib/transformations/type_flow/transformer.dart b/pkg/vm/lib/transformations/type_flow/transformer.dart
index 684e96a..837baeb 100644
--- a/pkg/vm/lib/transformations/type_flow/transformer.dart
+++ b/pkg/vm/lib/transformations/type_flow/transformer.dart
@@ -16,6 +16,7 @@
import 'analysis.dart';
import 'calls.dart';
+import 'summary.dart';
import 'summary_collector.dart';
import 'types.dart';
import 'utils.dart';
@@ -208,6 +209,8 @@
_setInferredType(member, _typeFlowAnalysis.fieldType(member));
} else {
Args<Type> argTypes = _typeFlowAnalysis.argumentTypes(member);
+ final uncheckedParameters =
+ _typeFlowAnalysis.uncheckedParameters(member);
assertx(argTypes != null);
final int firstParamIndex =
@@ -219,7 +222,8 @@
for (int i = 0; i < positionalParams.length; i++) {
_setInferredType(
- positionalParams[i], argTypes.values[firstParamIndex + i]);
+ positionalParams[i], argTypes.values[firstParamIndex + i],
+ skipCheck: uncheckedParameters.contains(positionalParams[i]));
}
// TODO(dartbug.com/32292): make sure parameters are sorted in kernel
@@ -229,7 +233,8 @@
final param = findNamedParameter(member.function, names[i]);
assertx(param != null);
_setInferredType(param,
- argTypes.values[firstParamIndex + positionalParams.length + i]);
+ argTypes.values[firstParamIndex + positionalParams.length + i],
+ skipCheck: uncheckedParameters.contains(param));
}
// TODO(alexmarkov): figure out how to pass receiver type.
@@ -484,6 +489,7 @@
/// transforms unreachable calls into 'throw' expressions.
class _TreeShakerPass1 extends Transformer {
final TreeShaker shaker;
+ Procedure _unsafeCast;
_TreeShakerPass1(this.shaker);
@@ -813,6 +819,24 @@
TreeNode visitAssertInitializer(AssertInitializer node) {
return _visitAssertNode(node);
}
+
+ @override
+ TreeNode visitAsExpression(AsExpression node) {
+ node.transformChildren(this);
+ TypeCheck check = shaker.typeFlowAnalysis.explicitCast(node);
+ if (check != null && check.canAlwaysSkip) {
+ return StaticInvocation(
+ unsafeCast, Arguments([node.operand], types: [node.type]));
+ }
+ return node;
+ }
+
+ Procedure get unsafeCast {
+ _unsafeCast ??= shaker.typeFlowAnalysis.environment.coreTypes.index
+ .getTopLevelMember('dart:_internal', 'unsafeCast');
+ assertx(_unsafeCast != null);
+ return _unsafeCast;
+ }
}
/// The second pass of [TreeShaker]. It is called after set of used
diff --git a/pkg/vm/lib/transformations/type_flow/types.dart b/pkg/vm/lib/transformations/type_flow/types.dart
index cf23ea8..9904fa7 100644
--- a/pkg/vm/lib/transformations/type_flow/types.dart
+++ b/pkg/vm/lib/transformations/type_flow/types.dart
@@ -45,6 +45,7 @@
Class get futureOrClass;
Class get futureClass;
+ Class get functionClass;
}
/// Basic normalization of Dart types.
@@ -615,6 +616,15 @@
bool isSubtypeOfRuntimeType(
TypeHierarchy typeHierarchy, RuntimeType runtimeType) {
+ if (runtimeType._type is InterfaceType &&
+ (runtimeType._type as InterfaceType).classNode ==
+ typeHierarchy.functionClass) {
+ // TODO(35573): "implements/extends Function" is not handled correctly by
+ // the CFE. By returning "false" we force an approximation -- that a type
+ // check against "Function" might fail, whatever the LHS is.
+ return false;
+ }
+
if (!typeHierarchy.isSubtype(this.classNode.rawType, runtimeType._type)) {
return false;
}
diff --git a/pkg/vm/test/transformations/type_flow/types_test.dart b/pkg/vm/test/transformations/type_flow/types_test.dart
index 213b6d9..b317843 100644
--- a/pkg/vm/test/transformations/type_flow/types_test.dart
+++ b/pkg/vm/test/transformations/type_flow/types_test.dart
@@ -39,6 +39,8 @@
Class get futureOrClass =>
throw "futureOrClass not supported in the types test.";
Class get futureClass => throw "futureClass not supported in the types test.";
+ Class get functionClass =>
+ throw "functionClass not supported in the types test.";
}
main() {
diff --git a/pkg/vm/testcases/transformations/type_flow/summary_collector/bool_expressions.dart.expect b/pkg/vm/testcases/transformations/type_flow/summary_collector/bool_expressions.dart.expect
index d4deb68..bf7dfc6 100644
--- a/pkg/vm/testcases/transformations/type_flow/summary_collector/bool_expressions.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/summary_collector/bool_expressions.dart.expect
@@ -6,21 +6,24 @@
RESULT: _T {}?
------------ #lib::bool_expressions ------------
t0* = _Call direct [#lib::foo] ()
-t1* = _Call direct [#lib::bar] ()
-t2* = _Call [dart.core::num::+] (_T (dart.core::int)+?, _T (dart.core::_Smi))
-i = _Join [dart.core::int] (_T (dart.core::_Smi), t2)
-t4* = _Call [dart.core::num::<] (i, _T (dart.core::_Smi))
-t5* = _Call direct [#lib::bar] ()
-x = _Join [dart.core::bool] (t5, _T (dart.core::bool)+)
-t7* = _Call direct [#lib::foo] ()
-t8* = _Call direct [#lib::bar] ()
-t9* = _Call direct [#lib::bar] ()
-t10* = _Call direct [#lib::foo] ()
-t11* = _Call direct [#lib::foo] ()
-t12 = _Join [dynamic] (_T (dart.core::bool)+, t7)
-t13 = _Narrow (t12 to _T ANY?)
-t14 = _Narrow (t13 to _T (dart.core::bool)+?)
-y = _Join [dart.core::bool] (_T (dart.core::bool)+, t14, _T (dart.core::bool)+, _T (dart.core::bool)+)
+t1 = _TypeCheck (t0 against dart.core::bool) (for #lib::foo() as{TypeError} dart.core::bool)
+t2* = _Call direct [#lib::bar] ()
+t3* = _Call [dart.core::num::+] (_T (dart.core::int)+?, _T (dart.core::_Smi))
+i = _Join [dart.core::int] (_T (dart.core::_Smi), t3)
+t5* = _Call [dart.core::num::<] (i, _T (dart.core::_Smi))
+t6* = _Call direct [#lib::bar] ()
+x = _Join [dart.core::bool] (t6, _T (dart.core::bool)+)
+t8* = _Call direct [#lib::foo] ()
+t9 = _Join [dynamic] (_T (dart.core::bool)+, t8)
+t10 = _Narrow (t9 to _T ANY?)
+t11 = _TypeCheck (t10 against dart.core::bool) (for (x{dart.core::bool} ?{dynamic} true : #lib::foo()) as{TypeError} dart.core::bool)
+t12* = _Call direct [#lib::bar] ()
+t13* = _Call direct [#lib::bar] ()
+t14* = _Call direct [#lib::foo] ()
+t15 = _TypeCheck (t14 against dart.core::bool) (for #lib::foo() as{TypeError} dart.core::bool)
+t16* = _Call direct [#lib::foo] ()
+t17 = _TypeCheck (t16 against dart.core::bool) (for #lib::foo() as{TypeError} dart.core::bool)
+y = _Join [dart.core::bool] (_T (dart.core::bool)+, t11, _T (dart.core::bool)+, _T (dart.core::bool)+)
RESULT: _T {}?
------------ #lib::main ------------
diff --git a/pkg/vm/testcases/transformations/type_flow/summary_collector/calls.dart.expect b/pkg/vm/testcases/transformations/type_flow/summary_collector/calls.dart.expect
index e5c30ed..9843dc5 100644
--- a/pkg/vm/testcases/transformations/type_flow/summary_collector/calls.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/summary_collector/calls.dart.expect
@@ -37,7 +37,7 @@
t5 = _Call direct [#lib::B::] (_T (#lib::B))
t6 = _Call [#lib::A::foo1] (%aa, _T (#lib::B))
t7* = _Call get [#lib::A::foo2] (%aa)
-t8 = _Narrow (t7 to _T (dart.core::int)+?)
+t8 = _TypeCheck (t7 against dart.core::int) (for aa.{#lib::A::foo2} as{TypeError} dart.core::int)
t9 = _Call set [#lib::A::foo3] (%aa, t8)
t10* = _Call get [#lib::A::foo1] (%aa)
t11* = _Call get [#lib::A::foo2] (%aa)
diff --git a/pkg/vm/testcases/transformations/type_flow/summary_collector/class_generics_basic.dart.expect b/pkg/vm/testcases/transformations/type_flow/summary_collector/class_generics_basic.dart.expect
index dcdc1f2..0163697 100644
--- a/pkg/vm/testcases/transformations/type_flow/summary_collector/class_generics_basic.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/summary_collector/class_generics_basic.dart.expect
@@ -12,13 +12,13 @@
%this = _Parameter #0 [_T (#lib::C<dynamic>)+]
%x = _Parameter #1
t2 = _Extract (%this[#lib::C/0])
-t3 = _TypeCheck (%x against t2) (for parameter x)
+t3 = _TypeCheck (%x against t2) (for x)
RESULT: t3
------------ #lib::C::id2 ------------
%this = _Parameter #0 [_T (#lib::C<dynamic>)+]
%x = _Parameter #1
t2 = _Extract (%this[#lib::C/0])
-t3 = _TypeCheck (%x against t2) (for parameter x)
+t3 = _TypeCheck (%x against t2) (for x)
RESULT: t3
------------ #lib::D:: ------------
%this = _Parameter #0 [_T (#lib::D<dynamic>)+]
@@ -77,7 +77,7 @@
%x = _Parameter #1
t2 = _Extract (%this[#lib::C2/0])
t3 = _CreateRuntimeType (dart.core::Comparable @ (t2))
-t4 = _TypeCheck (%x against t3) (for parameter x)
+t4 = _TypeCheck (%x against t3) (for x)
RESULT: t4
------------ #lib::C2::id4 ------------
%this = _Parameter #0 [_T (#lib::C2<dynamic>)+]
@@ -85,7 +85,7 @@
t2 = _Extract (%this[#lib::C2/0])
t3 = _CreateRuntimeType (#lib::I @ (t2))
t4 = _CreateRuntimeType (#lib::K @ (t3))
-t5 = _TypeCheck (%x against t4) (for parameter x)
+t5 = _TypeCheck (%x against t4) (for x)
RESULT: t5
------------ #lib::main ------------
t0 = _Call direct [#lib::C::] (_T (#lib::C<dart.core::int>))
diff --git a/pkg/vm/testcases/transformations/type_flow/summary_collector/class_generics_case1.dart.expect b/pkg/vm/testcases/transformations/type_flow/summary_collector/class_generics_case1.dart.expect
index f82c3ab..2095424 100644
--- a/pkg/vm/testcases/transformations/type_flow/summary_collector/class_generics_case1.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/summary_collector/class_generics_case1.dart.expect
@@ -17,9 +17,9 @@
%key = _Parameter #1
%value = _Parameter #2
t3 = _Extract (%this[#lib::_NotRealHashMap/0])
-t4 = _TypeCheck (%key against t3) (for parameter key)
+t4 = _TypeCheck (%key against t3) (for key)
t5 = _Extract (%this[#lib::_NotRealHashMap/1])
-t6 = _TypeCheck (%value against t5) (for parameter value)
+t6 = _TypeCheck (%value against t5) (for value)
RESULT: _T {}?
------------ #lib::InheritedElement:: ------------
%this = _Parameter #0 [_T (#lib::InheritedElement)+]
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/bench_is_prime.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/bench_is_prime.dart.expect
index e31b453..ffdd14f 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/bench_is_prime.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/bench_is_prime.dart.expect
@@ -1,11 +1,12 @@
library #lib;
import self as self;
import "dart:core" as core;
+import "dart:_internal" as _in;
static method isPrime([@vm.inferred-type.metadata=int?] dynamic n) → core::bool {
- if([@vm.direct-call.metadata=dart.core::_IntegerImplementation::<??] [@vm.inferred-type.metadata=dart.core::bool] n.<(2) as{TypeError} core::bool)
+ if(_in::unsafeCast<core::bool>([@vm.direct-call.metadata=dart.core::_IntegerImplementation::<??] [@vm.inferred-type.metadata=dart.core::bool] n.<(2)))
return false;
- for (core::int i = 2; [@vm.direct-call.metadata=dart.core::_IntegerImplementation::<=??] [@vm.inferred-type.metadata=dart.core::bool (skip check)] [@vm.direct-call.metadata=dart.core::_IntegerImplementation::*??] [@vm.inferred-type.metadata=int? (skip check)] i.{core::num::*}(i).{core::num::<=}(n as{TypeError} core::num); i = [@vm.direct-call.metadata=dart.core::_IntegerImplementation::+??] [@vm.inferred-type.metadata=int? (skip check)] i.{core::num::+}(1)) {
+ for (core::int i = 2; [@vm.direct-call.metadata=dart.core::_IntegerImplementation::<=??] [@vm.inferred-type.metadata=dart.core::bool (skip check)] [@vm.direct-call.metadata=dart.core::_IntegerImplementation::*??] [@vm.inferred-type.metadata=int? (skip check)] i.{core::num::*}(i).{core::num::<=}(_in::unsafeCast<core::num>(n)); i = [@vm.direct-call.metadata=dart.core::_IntegerImplementation::+??] [@vm.inferred-type.metadata=int? (skip check)] i.{core::num::+}(1)) {
if([@vm.inferred-type.metadata=dart.core::bool] [@vm.direct-call.metadata=dart.core::_IntegerImplementation::%??] [@vm.inferred-type.metadata=int?] n.%(i).{core::Object::==}(0))
return false;
}
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/class_generics_basic.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/class_generics_basic.dart.expect
index 3da6373..4acf3a3 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/class_generics_basic.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/class_generics_basic.dart.expect
@@ -8,7 +8,7 @@
;
[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasTearOffUses:false] method foo() → dynamic
return new self::D::•<self::C::T>();
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false] method id1([@vm.inferred-type.metadata=#lib::Y] generic-covariant-impl self::C::T x) → dynamic
+[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false] method id1([@vm.inferred-type.metadata=#lib::Y (skip check)] generic-covariant-impl self::C::T x) → dynamic
return x;
[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false] method id2([@vm.inferred-type.metadata=#lib::Z] generic-covariant-impl self::C::T x) → dynamic
return x;
@@ -57,9 +57,9 @@
synthetic constructor •() → self::C2<self::C2::T>
: super core::Object::•()
;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false] method id3([@vm.inferred-type.metadata=dart.core::_Double] generic-covariant-impl core::Comparable<self::C2::T> x) → dynamic
+[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false] method id3([@vm.inferred-type.metadata=dart.core::_Double (skip check)] generic-covariant-impl core::Comparable<self::C2::T> x) → dynamic
return x;
-[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false] method id4([@vm.inferred-type.metadata=#lib::K<#lib::J>] generic-covariant-impl self::K<self::I<self::C2::T>> x) → dynamic
+[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false] method id4([@vm.inferred-type.metadata=#lib::K<#lib::J> (skip check)] generic-covariant-impl self::K<self::I<self::C2::T>> x) → dynamic
return x;
}
static method main() → dynamic {
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/future.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/future.dart.expect
index 1a1fd6f..3998132 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/future.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/future.dart.expect
@@ -7,14 +7,14 @@
synthetic constructor •() → self::C<self::C::T>
: super core::Object::•()
;
-[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false] method test2c([@vm.inferred-type.metadata=dart.core::_Smi] generic-covariant-impl asy::FutureOr<self::C::T> x) → void {}
-[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false] method test3c([@vm.inferred-type.metadata=dart.async::_Future<dart.core::int>] generic-covariant-impl asy::Future<self::C::T> x) → void {}
-[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false] method test4c([@vm.inferred-type.metadata=dart.async::_Future<dart.core::int>] generic-covariant-impl asy::FutureOr<self::C::T> x) → void {}
-[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false] method test2r([@vm.inferred-type.metadata=#lib::C<dart.core::int>] generic-covariant-impl self::C<asy::FutureOr<self::C::T>> x) → void {}
-[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false] method test3r([@vm.inferred-type.metadata=#lib::C<dart.async::Future<dart.core::int>>] generic-covariant-impl self::C<asy::Future<self::C::T>> x) → void {}
-[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false] method test4r([@vm.inferred-type.metadata=#lib::C<dart.async::Future<dart.core::int>>] generic-covariant-impl self::C<asy::FutureOr<self::C::T>> x) → void {}
+[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false] method test2c([@vm.inferred-type.metadata=dart.core::_Smi (skip check)] generic-covariant-impl asy::FutureOr<self::C::T> x) → void {}
+[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false] method test3c([@vm.inferred-type.metadata=dart.async::_Future<dart.core::int> (skip check)] generic-covariant-impl asy::Future<self::C::T> x) → void {}
+[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false] method test4c([@vm.inferred-type.metadata=dart.async::_Future<dart.core::int> (skip check)] generic-covariant-impl asy::FutureOr<self::C::T> x) → void {}
+[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false] method test2r([@vm.inferred-type.metadata=#lib::C<dart.core::int> (skip check)] generic-covariant-impl self::C<asy::FutureOr<self::C::T>> x) → void {}
+[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false] method test3r([@vm.inferred-type.metadata=#lib::C<dart.async::Future<dart.core::int>> (skip check)] generic-covariant-impl self::C<asy::Future<self::C::T>> x) → void {}
+[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false] method test4r([@vm.inferred-type.metadata=#lib::C<dart.async::Future<dart.core::int>> (skip check)] generic-covariant-impl self::C<asy::FutureOr<self::C::T>> x) → void {}
[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false] method test5r([@vm.inferred-type.metadata=#lib::C<dart.async::FutureOr<dart.core::int>>] generic-covariant-impl self::C<asy::Future<self::C::T>> x) → void {}
-[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false] method test6r([@vm.inferred-type.metadata=#lib::C<dart.async::FutureOr<dart.core::int>>] generic-covariant-impl self::C<asy::FutureOr<self::C::T>> x) → void {}
+[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false] method test6r([@vm.inferred-type.metadata=#lib::C<dart.async::FutureOr<dart.core::int>> (skip check)] generic-covariant-impl self::C<asy::FutureOr<self::C::T>> x) → void {}
[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false] method test7r([@vm.inferred-type.metadata=#lib::C<dart.async::FutureOr<dart.core::int>>] generic-covariant-impl self::C<self::C::T> x) → void {}
[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false] method test8r([@vm.inferred-type.metadata=#lib::C<dart.async::Future<dart.core::int>>] generic-covariant-impl self::C<self::C::T> x) → void {}
}
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_set_field2.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_set_field2.dart.expect
index 761f166..925d3df 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_set_field2.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/invalidation_set_field2.dart.expect
@@ -29,7 +29,7 @@
;
}
static method foo1([@vm.inferred-type.metadata=dart.core::_GrowableList<#lib::T1>] core::List<self::T1> list) → dynamic {
- [@vm.direct-call.metadata=#lib::T3::run] [@vm.inferred-type.metadata=!? (skip check)] [@vm.direct-call.metadata=#lib::T1::go??] [@vm.inferred-type.metadata=#lib::T3 (skip check)] [@vm.direct-call.metadata=#lib::Q::result??] [@vm.direct-call.metadata=dart._internal::ListIterable::first] [@vm.direct-call.metadata=dart.collection::_ListBase&Object&ListMixin::map] [@vm.inferred-type.metadata=dart._internal::MappedListIterable<#lib::T1, ?>] list.{core::Iterable::map}<self::Q<self::T1>>((self::T1 t1) → self::Q<self::T1> => new self::Q::•<self::T1>(t1)).{core::Iterable::first}.{self::Q::result}.{self::T1::go}().{self::T3::run}();
+ [@vm.direct-call.metadata=#lib::T3::run] [@vm.inferred-type.metadata=!? (skip check)] [@vm.direct-call.metadata=#lib::T1::go??] [@vm.inferred-type.metadata=#lib::T3 (skip check)] [@vm.direct-call.metadata=#lib::Q::result??] [@vm.direct-call.metadata=dart._internal::ListIterable::first] [@vm.direct-call.metadata=dart.collection::_ListBase&Object&ListMixin::map] [@vm.inferred-type.metadata=dart._internal::MappedListIterable<#lib::T1, ?> (skip check)] list.{core::Iterable::map}<self::Q<self::T1>>((self::T1 t1) → self::Q<self::T1> => new self::Q::•<self::T1>(t1)).{core::Iterable::first}.{self::Q::result}.{self::T1::go}().{self::T3::run}();
}
static method foo2NewValue() → self::Q<dynamic>
return new self::Q::•<self::T2>(new self::T2::•());
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/no_such_method.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/no_such_method.dart.expect
index 54a1cd8..5c65020 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/no_such_method.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/no_such_method.dart.expect
@@ -1,6 +1,7 @@
library #lib;
import self as self;
import "dart:core" as core;
+import "dart:_internal" as _in;
class T1 extends core::Object {
synthetic constructor •() → self::T1
@@ -48,11 +49,11 @@
return new self::T1::•();
}
no-such-method-forwarder get bar() → dynamic
- return [@vm.direct-call.metadata=#lib::B::noSuchMethod] [@vm.inferred-type.metadata=#lib::T1 (skip check)] this.{self::B::noSuchMethod}(new core::_InvocationMirror::_withType(#bar, 1, const <core::Type>[], const <dynamic>[], [@vm.inferred-type.metadata=dart.collection::UnmodifiableMapView<dart.core::Symbol, dynamic>] core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}))) as{TypeError} dynamic;
+ return _in::unsafeCast<dynamic>([@vm.direct-call.metadata=#lib::B::noSuchMethod] [@vm.inferred-type.metadata=#lib::T1 (skip check)] this.{self::B::noSuchMethod}(new core::_InvocationMirror::_withType(#bar, 1, const <core::Type>[], const <dynamic>[], [@vm.inferred-type.metadata=dart.collection::UnmodifiableMapView<dart.core::Symbol, dynamic>] core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}))));
[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false] no-such-method-forwarder method foo() → dynamic
- return [@vm.direct-call.metadata=#lib::B::noSuchMethod] [@vm.inferred-type.metadata=#lib::T1 (skip check)] this.{self::B::noSuchMethod}(new core::_InvocationMirror::_withType(#foo, 0, const <core::Type>[], const <dynamic>[], [@vm.inferred-type.metadata=dart.collection::UnmodifiableMapView<dart.core::Symbol, dynamic>] core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}))) as{TypeError} dynamic;
+ return _in::unsafeCast<dynamic>([@vm.direct-call.metadata=#lib::B::noSuchMethod] [@vm.inferred-type.metadata=#lib::T1 (skip check)] this.{self::B::noSuchMethod}(new core::_InvocationMirror::_withType(#foo, 0, const <core::Type>[], const <dynamic>[], [@vm.inferred-type.metadata=dart.collection::UnmodifiableMapView<dart.core::Symbol, dynamic>] core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}))));
[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false] no-such-method-forwarder method bazz([@vm.inferred-type.metadata=dart.core::_Smi] dynamic a1, [@vm.inferred-type.metadata=dart.core::_Smi] dynamic a2, [@vm.inferred-type.metadata=dart.core::_Smi] dynamic a3, [[@vm.inferred-type.metadata=dart.core::_Smi] dynamic a4 = null, [@vm.inferred-type.metadata=dart.core::Null?] dynamic a5 = null]) → dynamic
- return [@vm.direct-call.metadata=#lib::B::noSuchMethod] [@vm.inferred-type.metadata=#lib::T1 (skip check)] this.{self::B::noSuchMethod}(new core::_InvocationMirror::_withType(#bazz, 0, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[a1, a2, a3, a4, a5]), [@vm.inferred-type.metadata=dart.collection::UnmodifiableMapView<dart.core::Symbol, dynamic>] core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}))) as{TypeError} dynamic;
+ return _in::unsafeCast<dynamic>([@vm.direct-call.metadata=#lib::B::noSuchMethod] [@vm.inferred-type.metadata=#lib::T1 (skip check)] this.{self::B::noSuchMethod}(new core::_InvocationMirror::_withType(#bazz, 0, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[a1, a2, a3, a4, a5]), [@vm.inferred-type.metadata=dart.collection::UnmodifiableMapView<dart.core::Symbol, dynamic>] core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}))));
}
abstract class C extends core::Object {
synthetic constructor •() → self::C
@@ -67,11 +68,11 @@
: super self::C::•()
;
no-such-method-forwarder get bar() → dynamic
- return [@vm.direct-call.metadata=#lib::C::noSuchMethod] [@vm.inferred-type.metadata=#lib::T2 (skip check)] this.{self::C::noSuchMethod}(new core::_InvocationMirror::_withType(#bar, 1, const <core::Type>[], const <dynamic>[], [@vm.inferred-type.metadata=dart.collection::UnmodifiableMapView<dart.core::Symbol, dynamic>] core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}))) as{TypeError} dynamic;
+ return _in::unsafeCast<dynamic>([@vm.direct-call.metadata=#lib::C::noSuchMethod] [@vm.inferred-type.metadata=#lib::T2 (skip check)] this.{self::C::noSuchMethod}(new core::_InvocationMirror::_withType(#bar, 1, const <core::Type>[], const <dynamic>[], [@vm.inferred-type.metadata=dart.collection::UnmodifiableMapView<dart.core::Symbol, dynamic>] core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}))));
[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false] no-such-method-forwarder method foo() → dynamic
- return [@vm.direct-call.metadata=#lib::C::noSuchMethod] [@vm.inferred-type.metadata=#lib::T2 (skip check)] this.{self::C::noSuchMethod}(new core::_InvocationMirror::_withType(#foo, 0, const <core::Type>[], const <dynamic>[], [@vm.inferred-type.metadata=dart.collection::UnmodifiableMapView<dart.core::Symbol, dynamic>] core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}))) as{TypeError} dynamic;
+ return _in::unsafeCast<dynamic>([@vm.direct-call.metadata=#lib::C::noSuchMethod] [@vm.inferred-type.metadata=#lib::T2 (skip check)] this.{self::C::noSuchMethod}(new core::_InvocationMirror::_withType(#foo, 0, const <core::Type>[], const <dynamic>[], [@vm.inferred-type.metadata=dart.collection::UnmodifiableMapView<dart.core::Symbol, dynamic>] core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}))));
[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasTearOffUses:false] no-such-method-forwarder method bazz([@vm.inferred-type.metadata=dart.core::_Smi] dynamic a1, [@vm.inferred-type.metadata=dart.core::_Smi] dynamic a2, [@vm.inferred-type.metadata=dart.core::_Smi] dynamic a3, [[@vm.inferred-type.metadata=dart.core::_Smi] dynamic a4 = null, [@vm.inferred-type.metadata=dart.core::Null?] dynamic a5 = null]) → dynamic
- return [@vm.direct-call.metadata=#lib::C::noSuchMethod] [@vm.inferred-type.metadata=#lib::T2 (skip check)] this.{self::C::noSuchMethod}(new core::_InvocationMirror::_withType(#bazz, 0, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[a1, a2, a3, a4, a5]), [@vm.inferred-type.metadata=dart.collection::UnmodifiableMapView<dart.core::Symbol, dynamic>] core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}))) as{TypeError} dynamic;
+ return _in::unsafeCast<dynamic>([@vm.direct-call.metadata=#lib::C::noSuchMethod] [@vm.inferred-type.metadata=#lib::T2 (skip check)] this.{self::C::noSuchMethod}(new core::_InvocationMirror::_withType(#bazz, 0, const <core::Type>[], core::List::unmodifiable<dynamic>(<dynamic>[a1, a2, a3, a4, a5]), [@vm.inferred-type.metadata=dart.collection::UnmodifiableMapView<dart.core::Symbol, dynamic>] core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}))));
}
class E extends core::Object implements self::A {
synthetic constructor •() → self::E
@@ -81,7 +82,7 @@
return new self::T4::•();
}
no-such-method-forwarder get bar() → dynamic
- return [@vm.direct-call.metadata=#lib::E::noSuchMethod] [@vm.inferred-type.metadata=#lib::T4 (skip check)] this.{self::E::noSuchMethod}(new core::_InvocationMirror::_withType(#bar, 1, const <core::Type>[], const <dynamic>[], [@vm.inferred-type.metadata=dart.collection::UnmodifiableMapView<dart.core::Symbol, dynamic>] core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}))) as{TypeError} dynamic;
+ return _in::unsafeCast<dynamic>([@vm.direct-call.metadata=#lib::E::noSuchMethod] [@vm.inferred-type.metadata=#lib::T4 (skip check)] this.{self::E::noSuchMethod}(new core::_InvocationMirror::_withType(#bar, 1, const <core::Type>[], const <dynamic>[], [@vm.inferred-type.metadata=dart.collection::UnmodifiableMapView<dart.core::Symbol, dynamic>] core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}))));
}
class F extends core::Object {
synthetic constructor •() → self::F
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/regress_flutter16182.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/regress_flutter16182.dart.expect
index d0dc0ad..feb28eb 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/regress_flutter16182.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/regress_flutter16182.dart.expect
@@ -1,6 +1,7 @@
library #lib;
import self as self;
import "dart:core" as core;
+import "dart:_internal" as _in;
import "package:expect/expect.dart" as exp;
class T1 extends core::Object {
@@ -17,7 +18,7 @@
: super core::Object::•()
;
[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false] method call([dynamic a1 = null, dynamic a2 = null, dynamic a3 = null, [@vm.inferred-type.metadata=dart.core::_Smi?] dynamic a4 = null, [@vm.inferred-type.metadata=#lib::T1?] dynamic a5 = null]) → void {
- [@vm.direct-call.metadata=#lib::A1::foo] this.{self::A1::foo} = a5 as{TypeError} self::T1;
+ [@vm.direct-call.metadata=#lib::A1::foo] this.{self::A1::foo} = _in::unsafeCast<self::T1>(a5);
}
}
class B1 extends core::Object {
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_interface_method.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_interface_method.dart.expect
index c05b7ff..66af620 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_interface_method.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_interface_method.dart.expect
@@ -1,6 +1,7 @@
library #lib;
import self as self;
import "dart:core" as core;
+import "dart:_internal" as _in;
abstract class A extends core::Object {
synthetic constructor •() → self::A
@@ -13,7 +14,7 @@
: super self::A::•()
;
[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasNonThisUses:false] method foo() → core::int
- return [@vm.direct-call.metadata=dart.core::_IntegerImplementation::+] [@vm.inferred-type.metadata=int? (skip check)] 1.{core::num::+}([@vm.direct-call.metadata=#lib::B::bar] [@vm.inferred-type.metadata=dart.core::_Smi] [@vm.inferred-type.metadata=#lib::B] self::knownResult().bar() as{TypeError} core::num) as{TypeError} core::int;
+ return _in::unsafeCast<core::int>([@vm.direct-call.metadata=dart.core::_IntegerImplementation::+] [@vm.inferred-type.metadata=int? (skip check)] 1.{core::num::+}(_in::unsafeCast<core::num>([@vm.direct-call.metadata=#lib::B::bar] [@vm.inferred-type.metadata=dart.core::_Smi] [@vm.inferred-type.metadata=#lib::B] self::knownResult().bar())));
[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false] method bar() → core::int
return 3;
}
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_super_method.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_super_method.dart.expect
index aa8ce21..950a81d 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_super_method.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_super_method.dart.expect
@@ -1,6 +1,7 @@
library #lib;
import self as self;
import "dart:core" as core;
+import "dart:_internal" as _in;
abstract class A extends core::Object {
synthetic constructor •() → self::A
@@ -13,14 +14,14 @@
: super self::A::•()
;
[@vm.procedure-attributes.metadata=hasThisUses:false,hasTearOffUses:false] method foo() → core::int
- return [@vm.direct-call.metadata=dart.core::_IntegerImplementation::+] [@vm.inferred-type.metadata=int? (skip check)] 1.{core::num::+}([@vm.direct-call.metadata=#lib::B::foo] [@vm.inferred-type.metadata=int?] [@vm.inferred-type.metadata=#lib::B] self::knownResult().foo() as{TypeError} core::num) as{TypeError} core::int;
+ return _in::unsafeCast<core::int>([@vm.direct-call.metadata=dart.core::_IntegerImplementation::+] [@vm.inferred-type.metadata=int? (skip check)] 1.{core::num::+}(_in::unsafeCast<core::num>([@vm.direct-call.metadata=#lib::B::foo] [@vm.inferred-type.metadata=int?] [@vm.inferred-type.metadata=#lib::B] self::knownResult().foo())));
}
abstract class Base extends core::Object {
synthetic constructor •() → self::Base
: super core::Object::•()
;
[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasThisUses:false,hasNonThisUses:false] method foo() → core::int
- return [@vm.direct-call.metadata=dart.core::_IntegerImplementation::+] [@vm.inferred-type.metadata=int? (skip check)] 3.{core::num::+}([@vm.direct-call.metadata=#lib::B::foo] [@vm.inferred-type.metadata=int?] [@vm.inferred-type.metadata=#lib::B] self::knownResult().foo() as{TypeError} core::num) as{TypeError} core::int;
+ return _in::unsafeCast<core::int>([@vm.direct-call.metadata=dart.core::_IntegerImplementation::+] [@vm.inferred-type.metadata=int? (skip check)] 3.{core::num::+}(_in::unsafeCast<core::num>([@vm.direct-call.metadata=#lib::B::foo] [@vm.inferred-type.metadata=int?] [@vm.inferred-type.metadata=#lib::B] self::knownResult().foo())));
[@vm.procedure-attributes.metadata=hasDynamicUses:false,hasNonThisUses:false,hasTearOffUses:false] method doCall(dynamic x) → core::int
return [@vm.call-site-attributes.metadata=receiverType:dynamic] x.call() as{TypeError} core::int;
}
diff --git a/runtime/tests/vm/dart/entrypoints/super.dart b/runtime/tests/vm/dart/entrypoints/super.dart
index 352c338..088b193 100644
--- a/runtime/tests/vm/dart/entrypoints/super.dart
+++ b/runtime/tests/vm/dart/entrypoints/super.dart
@@ -49,6 +49,11 @@
void testOneC(C x, int i) => x.target1(i);
test(List<String> args) {
+ // Make sure the check on target1.x is not completely eliminated.
+ if (args.length > 0) {
+ (C<int>() as C<num>).target1(1.0);
+ }
+
expectedEntryPoint = -1;
for (int i = 0; i < 100; ++i) {
testOneC(getC(), i);
diff --git a/runtime/vm/compiler/frontend/scope_builder.cc b/runtime/vm/compiler/frontend/scope_builder.cc
index 6811b6c..201c724 100644
--- a/runtime/vm/compiler/frontend/scope_builder.cc
+++ b/runtime/vm/compiler/frontend/scope_builder.cc
@@ -1473,6 +1473,13 @@
variable->set_type_check_mode(LocalVariable::kTypeCheckedByCaller);
break;
}
+
+ // TODO(sjindel): We can also skip these checks on dynamic invocations as
+ // well.
+ if (parameter_type.IsSkipCheck()) {
+ variable->set_type_check_mode(LocalVariable::kTypeCheckedByCaller);
+ }
+
scope_->InsertParameterAt(pos, variable);
result_->locals.Insert(helper_.data_program_offset_ + kernel_offset,
variable);