mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 12:24:24 +00:00
[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>
This commit is contained in:
parent
0213c9f9d2
commit
b58e8d7307
20 changed files with 192 additions and 90 deletions
|
@ -154,7 +154,8 @@ class _DirectInvocation extends _Invocation {
|
|||
//
|
||||
// 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 _ClassHierarchyCache implements TypeHierarchy {
|
|||
|
||||
Class get futureOrClass => environment.coreTypes.futureOrClass;
|
||||
Class get futureClass => environment.coreTypes.futureClass;
|
||||
Class get functionClass => environment.coreTypes.functionClass;
|
||||
}
|
||||
|
||||
class _WorkList {
|
||||
|
@ -1395,10 +1397,16 @@ class TypeFlowAnalysis implements EntryPointsListener, CallHandler {
|
|||
|
||||
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.
|
||||
|
|
|
@ -413,9 +413,30 @@ class TypeCheck extends Statement {
|
|||
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 @@ class TypeCheck extends Statement {
|
|||
@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 @@ class TypeCheck extends Statement {
|
|||
// 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 @@ class Summary {
|
|||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ class _SummaryNormalizer extends StatementVisitor {
|
|||
}
|
||||
|
||||
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 @@ class SummaryCollector extends RecursiveVisitor<TypeExpr> {
|
|||
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 @@ class SummaryCollector extends RecursiveVisitor<TypeExpr> {
|
|||
} 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 @@ class SummaryCollector extends RecursiveVisitor<TypeExpr> {
|
|||
}
|
||||
|
||||
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 @@ class SummaryCollector extends RecursiveVisitor<TypeExpr> {
|
|||
|
||||
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 @@ class SummaryCollector extends RecursiveVisitor<TypeExpr> {
|
|||
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 @@ class SummaryCollector extends RecursiveVisitor<TypeExpr> {
|
|||
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 @@ class SummaryCollector extends RecursiveVisitor<TypeExpr> {
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ import 'package:kernel/type_environment.dart';
|
|||
|
||||
import 'analysis.dart';
|
||||
import 'calls.dart';
|
||||
import 'summary.dart';
|
||||
import 'summary_collector.dart';
|
||||
import 'types.dart';
|
||||
import 'utils.dart';
|
||||
|
@ -208,6 +209,8 @@ class AnnotateKernel extends RecursiveVisitor<Null> {
|
|||
_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 @@ class AnnotateKernel extends RecursiveVisitor<Null> {
|
|||
|
||||
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 @@ class AnnotateKernel extends RecursiveVisitor<Null> {
|
|||
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 @@ class _TreeShakerTypeVisitor extends RecursiveVisitor<Null> {
|
|||
/// transforms unreachable calls into 'throw' expressions.
|
||||
class _TreeShakerPass1 extends Transformer {
|
||||
final TreeShaker shaker;
|
||||
Procedure _unsafeCast;
|
||||
|
||||
_TreeShakerPass1(this.shaker);
|
||||
|
||||
|
@ -813,6 +819,24 @@ class _TreeShakerPass1 extends Transformer {
|
|||
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
|
||||
|
|
|
@ -45,6 +45,7 @@ abstract class TypeHierarchy implements GenericInterfacesInfo {
|
|||
|
||||
Class get futureOrClass;
|
||||
Class get futureClass;
|
||||
Class get functionClass;
|
||||
}
|
||||
|
||||
/// Basic normalization of Dart types.
|
||||
|
@ -615,6 +616,15 @@ class ConcreteType extends Type implements Comparable<ConcreteType> {
|
|||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -39,6 +39,8 @@ class TestTypeHierarchy implements TypeHierarchy {
|
|||
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() {
|
||||
|
|
|
@ -6,21 +6,24 @@ RESULT: _T {}?
|
|||
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 ------------
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ RESULT: _T {}?
|
|||
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)
|
||||
|
|
|
@ -12,13 +12,13 @@ RESULT: t2
|
|||
%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 @@ RESULT: _T {}?
|
|||
%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 @@ RESULT: t4
|
|||
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>))
|
||||
|
|
|
@ -17,9 +17,9 @@ RESULT: _T {}?
|
|||
%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)+]
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ class C<T extends core::Object = dynamic> extends core::Object {
|
|||
;
|
||||
[@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 @@ class C2<T extends core::Object = dynamic> extends core::Object {
|
|||
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 {
|
||||
|
|
|
@ -7,14 +7,14 @@ class C<T extends core::Object = dynamic> extends core::Object {
|
|||
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 {}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ class Q<T extends core::Object = dynamic> extends core::Object {
|
|||
;
|
||||
}
|
||||
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::•());
|
||||
|
|
|
@ -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 @@ class B extends self::A {
|
|||
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 @@ class D extends self::C implements self::A {
|
|||
: 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 @@ class E extends core::Object implements self::A {
|
|||
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
|
||||
|
|
|
@ -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 @@ class A1 extends core::Object {
|
|||
: 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 {
|
||||
|
|
|
@ -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 @@ class B extends self::A {
|
|||
: 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;
|
||||
}
|
||||
|
|
|
@ -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 @@ class B extends self::A {
|
|||
: 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;
|
||||
}
|
||||
|
|
|
@ -49,6 +49,11 @@ C getC() {
|
|||
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);
|
||||
|
|
|
@ -1473,6 +1473,13 @@ void ScopeBuilder::AddVariableDeclarationParameter(
|
|||
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);
|
||||
|
|
Loading…
Reference in a new issue