mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 03:27:43 +00:00
Support [AssumeDynamic] and [TrustTypeAnnotations] in the inferrer.
BUG= R=floitsch@google.com, johnniwinther@google.com Review URL: https://codereview.chromium.org//875163004 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@43550 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
parent
2b8950be87
commit
44541ff62b
|
@ -45,6 +45,7 @@ import '../util/util.dart'
|
|||
show ImmutableEmptySet,
|
||||
Setlet,
|
||||
Spannable;
|
||||
import '../js_backend/js_backend.dart' show Annotations, JavaScriptBackend;
|
||||
|
||||
import 'inferrer_visitor.dart'
|
||||
show ArgumentsTypes,
|
||||
|
@ -559,6 +560,9 @@ class TypeGraphInferrerEngine
|
|||
TypeGraphInferrerEngine(Compiler compiler, this.mainElement)
|
||||
: super(compiler, new TypeInformationSystem(compiler));
|
||||
|
||||
JavaScriptBackend get backend => compiler.backend;
|
||||
Annotations get annotations => backend.annotations;
|
||||
|
||||
/**
|
||||
* A set of selector names that [List] implements, that we know return
|
||||
* their element type.
|
||||
|
|
|
@ -392,8 +392,11 @@ class MemberTypeInformation extends ElementTypeInformation
|
|||
|
||||
TypeMask handleSpecialCases(TypeGraphInferrerEngine inferrer) {
|
||||
if (element.isField &&
|
||||
!inferrer.compiler.backend.canBeUsedForGlobalOptimizations(element)) {
|
||||
// Do not infer types for fields being assigned by synthesized calls.
|
||||
(!inferrer.backend.canBeUsedForGlobalOptimizations(element) ||
|
||||
inferrer.annotations.assumeDynamic(element))) {
|
||||
// Do not infer types for fields that have a corresponding annotation or
|
||||
// are assigned by synthesized calls
|
||||
|
||||
giveUp(inferrer);
|
||||
return safeType(inferrer);
|
||||
}
|
||||
|
@ -437,7 +440,9 @@ class MemberTypeInformation extends ElementTypeInformation
|
|||
TypeMask potentiallyNarrowType(TypeMask mask,
|
||||
TypeGraphInferrerEngine inferrer) {
|
||||
Compiler compiler = inferrer.compiler;
|
||||
if (!compiler.trustTypeAnnotations && !compiler.enableTypeAssertions) {
|
||||
if (!compiler.trustTypeAnnotations &&
|
||||
!compiler.enableTypeAssertions &&
|
||||
!inferrer.annotations.trustTypeAnnotations(element)) {
|
||||
return mask;
|
||||
}
|
||||
if (element.isGenerativeConstructor ||
|
||||
|
@ -496,6 +501,7 @@ class MemberTypeInformation extends ElementTypeInformation
|
|||
*/
|
||||
class ParameterTypeInformation extends ElementTypeInformation {
|
||||
ParameterElement get element => super.element;
|
||||
FunctionElement get declaration => element.functionDeclaration;
|
||||
|
||||
ParameterTypeInformation._internal(ParameterElement element,
|
||||
TypeInformationSystem types)
|
||||
|
@ -522,9 +528,10 @@ class ParameterTypeInformation extends ElementTypeInformation {
|
|||
|
||||
// TODO(herhut): Cleanup into one conditional.
|
||||
TypeMask handleSpecialCases(TypeGraphInferrerEngine inferrer) {
|
||||
if (!inferrer.compiler.backend.canBeUsedForGlobalOptimizations(element)) {
|
||||
// Do not infer types for fields and parameters being assigned
|
||||
// by synthesized calls.
|
||||
if (!inferrer.backend.canBeUsedForGlobalOptimizations(element) ||
|
||||
inferrer.annotations.assumeDynamic(declaration)) {
|
||||
// Do not infer types for parameters that have a correspondign annotation
|
||||
// or that are assigned by synthesized calls.
|
||||
giveUp(inferrer);
|
||||
return safeType(inferrer);
|
||||
}
|
||||
|
@ -567,7 +574,8 @@ class ParameterTypeInformation extends ElementTypeInformation {
|
|||
TypeMask potentiallyNarrowType(TypeMask mask,
|
||||
TypeGraphInferrerEngine inferrer) {
|
||||
Compiler compiler = inferrer.compiler;
|
||||
if (!compiler.trustTypeAnnotations) {
|
||||
if (!compiler.trustTypeAnnotations &&
|
||||
!inferrer.annotations.trustTypeAnnotations(declaration)) {
|
||||
return mask;
|
||||
}
|
||||
// When type assertions are enabled (aka checked mode), we have to always
|
||||
|
|
|
@ -406,14 +406,21 @@ class NoInlining {
|
|||
/// Annotation class for testing of dart2js. Use this as metadata on method
|
||||
/// declarations to make the type inferrer trust the parameter and return types,
|
||||
/// effectively asserting the runtime values will (at least) be subtypes of the
|
||||
/// annotated types.
|
||||
/// annotated types.
|
||||
///
|
||||
/// While the actually inferred type is guaranteed to be a subtype of the
|
||||
/// annotation, it often is more precise. In particular, if a method is only
|
||||
/// called with `null`, the inferrer will still infer null. To ensure that
|
||||
/// the annotated type is also the inferred type, additionally use
|
||||
/// [AssumeDynamic].
|
||||
class TrustTypeAnnotations {
|
||||
const TrustTypeAnnotations();
|
||||
}
|
||||
|
||||
/// Annotation class for testing of dart2js. Use this as metadata on method
|
||||
/// declarations to disable closed world assumptions on parameters, effectively
|
||||
/// assuming that the runtime arguments could be any value.
|
||||
/// assuming that the runtime arguments could be any value. Note that the
|
||||
/// constraints due to [TrustTypeAnnotations] still apply.
|
||||
class AssumeDynamic {
|
||||
const AssumeDynamic();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@ import 'package:async_helper/async_helper.dart';
|
|||
import 'package:compiler/src/dart2jslib.dart';
|
||||
import 'package:compiler/src/elements/elements.dart';
|
||||
import 'package:compiler/src/js_backend/js_backend.dart';
|
||||
import 'package:compiler/src/types/types.dart';
|
||||
import 'type_mask_test_helper.dart';
|
||||
import 'memory_compiler.dart';
|
||||
|
||||
const Map MEMORY_SOURCE_FILES = const {
|
||||
|
@ -28,12 +30,19 @@ int methodNoInlining(String arg) => arg.length;
|
|||
@NoInlining() @TrustTypeAnnotations()
|
||||
int methodNoInliningTrustTypeAnnotations(String arg) => arg.length;
|
||||
|
||||
@AssumeDynamic() @TrustTypeAnnotations()
|
||||
int methodAssumeDynamicTrustTypeAnnotations(String arg) => arg.length;
|
||||
|
||||
|
||||
void main(List<String> args) {
|
||||
print(method(args[0]));
|
||||
print(methodAssumeDynamic('foo'));
|
||||
print(methodTrustTypeAnnotations(null));
|
||||
print(methodTrustTypeAnnotations(42));
|
||||
print(methodTrustTypeAnnotations("fourtyTwo"));
|
||||
print(methodNoInlining('bar'));
|
||||
print(methodNoInliningTrustTypeAnnotations(null));
|
||||
print(methodNoInliningTrustTypeAnnotations(42));
|
||||
print(methodNoInliningTrustTypeAnnotations("fourtyTwo"));
|
||||
print(methodAssumeDynamicTrustTypeAnnotations(null));
|
||||
}
|
||||
"""
|
||||
};
|
||||
|
@ -50,9 +59,25 @@ main() {
|
|||
Expect.isNotNull(backend.annotations.expectAssumeDynamicClass,
|
||||
'AssumeDynamicClass is unresolved.');
|
||||
|
||||
void testTypeMatch(FunctionElement function, TypeMask expectedParameterType,
|
||||
TypeMask expectedReturnType, TypesInferrer inferrer) {
|
||||
for (ParameterElement parameter in function.parameters) {
|
||||
TypeMask type = inferrer.getTypeOfElement(parameter);
|
||||
Expect.equals(expectedParameterType, simplify(type, compiler),
|
||||
"$parameter");
|
||||
}
|
||||
if (expectedReturnType != null) {
|
||||
TypeMask type = inferrer.getReturnTypeOfElement(function);
|
||||
Expect.equals(expectedReturnType, simplify(type, compiler),
|
||||
"$function");
|
||||
}
|
||||
}
|
||||
|
||||
void test(String name,
|
||||
{bool expectNoInlining: false,
|
||||
bool expectTrustTypeAnnotations: false,
|
||||
TypeMask expectedParameterType: null,
|
||||
TypeMask expectedReturnType: null,
|
||||
bool expectAssumeDynamic: false}) {
|
||||
Element method = compiler.mainApp.find(name);
|
||||
Expect.isNotNull(method);
|
||||
|
@ -68,14 +93,35 @@ main() {
|
|||
expectAssumeDynamic,
|
||||
backend.annotations.assumeDynamic(method),
|
||||
"Unexpected annotation of @AssumeDynamic on '$method'.");
|
||||
TypesInferrer inferrer = compiler.typesTask.typesInferrer;
|
||||
if (expectTrustTypeAnnotations && expectedParameterType != null) {
|
||||
testTypeMatch(method, expectedParameterType, expectedReturnType,
|
||||
inferrer);
|
||||
} else if (expectAssumeDynamic) {
|
||||
testTypeMatch(method, compiler.typesTask.dynamicType, null, inferrer);
|
||||
}
|
||||
}
|
||||
|
||||
TypeMask jsStringType = compiler.typesTask.stringType;
|
||||
TypeMask jsIntType = compiler.typesTask.intType;
|
||||
TypeMask coreStringType = new TypeMask.subtype(compiler.stringClass,
|
||||
compiler.world);
|
||||
|
||||
test('method');
|
||||
test('methodAssumeDynamic', expectAssumeDynamic: true);
|
||||
test('methodTrustTypeAnnotations', expectTrustTypeAnnotations: true);
|
||||
test('methodTrustTypeAnnotations',
|
||||
expectTrustTypeAnnotations: true,
|
||||
expectedParameterType: jsStringType);
|
||||
test('methodNoInlining', expectNoInlining: true);
|
||||
test('methodNoInliningTrustTypeAnnotations',
|
||||
expectNoInlining: true,
|
||||
expectTrustTypeAnnotations: true);
|
||||
expectTrustTypeAnnotations: true,
|
||||
expectedParameterType: jsStringType,
|
||||
expectedReturnType: jsIntType);
|
||||
test('methodAssumeDynamicTrustTypeAnnotations',
|
||||
expectAssumeDynamic: true,
|
||||
expectTrustTypeAnnotations: true,
|
||||
expectedParameterType: coreStringType);
|
||||
|
||||
}));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue