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:
herhut@google.com 2015-02-06 11:38:46 +00:00
parent 2b8950be87
commit 44541ff62b
4 changed files with 79 additions and 14 deletions

View file

@ -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.

View file

@ -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

View file

@ -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();
}
}

View file

@ -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);
}));
}