Handle generic factory constructors in kernel_impact

R=het@google.com

Review URL: https://codereview.chromium.org/2341263002 .
This commit is contained in:
Johnni Winther 2016-09-19 11:35:56 +02:00
parent 9f3b5d8680
commit e24939f8d6
6 changed files with 80 additions and 8 deletions

View file

@ -619,7 +619,9 @@ class ConstructorResolver extends CommonResolverVisitor<ConstructorResult> {
// This is not really resolving a type-annotation, but the name of the
// constructor. Therefore we allow deferred types.
DartType type = resolver.resolveTypeAnnotation(node,
malformedIsError: inConstContext, deferredIsMalformed: false);
malformedIsError: inConstContext,
deferredIsMalformed: false,
registerCheckedModeCheck: false);
Send send = node.typeName.asSend();
PrefixElement prefix;
if (send != null) {

View file

@ -4063,11 +4063,13 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
}
DartType resolveTypeAnnotation(TypeAnnotation node,
{bool malformedIsError: false, bool deferredIsMalformed: true}) {
{bool malformedIsError: false,
bool deferredIsMalformed: true,
bool registerCheckedModeCheck: true}) {
DartType type = typeResolver.resolveTypeAnnotation(this, node,
malformedIsError: malformedIsError,
deferredIsMalformed: deferredIsMalformed);
if (!type.isDynamic) {
if (registerCheckedModeCheck && !type.isDynamic) {
registry.registerTypeUse(new TypeUse.checkedModeCheck(type));
}
return type;

View file

@ -176,7 +176,8 @@ class TypeResolver {
} else {
type = new InterfaceType(
cls.declaration, arguments.toList(growable: false));
addTypeVariableBoundsCheck = true;
addTypeVariableBoundsCheck =
arguments.any((DartType type) => !type.isDynamic);
}
}
} else if (element.isTypedef) {
@ -195,7 +196,8 @@ class TypeResolver {
type = typdef.rawType;
} else {
type = new TypedefType(typdef, arguments.toList(growable: false));
addTypeVariableBoundsCheck = true;
addTypeVariableBoundsCheck =
arguments.any((DartType type) => !type.isDynamic);
}
}
} else if (element.isTypeVariable) {

View file

@ -173,6 +173,10 @@ class KernelAstAdapter {
DartType getDartType(ir.DartType type) {
return type.accept(_typeConverter);
}
List<DartType> getDartTypes(List<ir.DartType> types) {
return types.map(getDartType).toList();
}
}
class DartTypeConverter extends ir.DartTypeVisitor<DartType> {

View file

@ -195,8 +195,44 @@ class KernelImpactBuilder extends ir.Visitor {
void visitStaticInvocation(ir.StaticInvocation invocation) {
_visitArguments(invocation.arguments);
Element target = astAdapter.getElement(invocation.target).declaration;
impactBuilder.registerStaticUse(new StaticUse.staticInvoke(
target, astAdapter.getCallStructure(invocation.arguments)));
if (target.isFactoryConstructor) {
impactBuilder.registerStaticUse(new StaticUse.constructorInvoke(
target, astAdapter.getCallStructure(invocation.arguments)));
// TODO(johnniwinther): We should not mark the type as instantiated but
// rather follow the type arguments directly.
//
// Consider this:
//
// abstract class A<T> {
// factory A.regular() => new B<T>();
// factory A.redirect() = B<T>;
// }
//
// class B<T> implements A<T> {}
//
// main() {
// print(new A<int>.regular() is B<int>);
// print(new A<String>.redirect() is B<String>);
// }
//
// To track that B is actually instantiated as B<int> and B<String> we
// need to follow the type arguments passed to A.regular and A.redirect
// to B. Currently, we only do this soundly if we register A<int> and
// A<String> as instantiated. We should instead register that A.T is
// instantiated as int and String.
ClassElement cls =
astAdapter.getElement(invocation.target.enclosingClass);
List<DartType> typeArguments =
astAdapter.getDartTypes(invocation.arguments.types);
impactBuilder.registerTypeUse(
new TypeUse.instantiation(new InterfaceType(cls, typeArguments)));
if (typeArguments.any((DartType type) => !type.isDynamic)) {
impactBuilder.registerFeature(Feature.TYPE_VARIABLE_BOUNDS_CHECK);
}
} else {
impactBuilder.registerStaticUse(new StaticUse.staticInvoke(
target, astAdapter.getCallStructure(invocation.arguments)));
}
}
@override

View file

@ -18,6 +18,8 @@ import '../serialization/test_helper.dart';
const Map<String, String> SOURCE = const <String, String>{
'main.dart': '''
import 'helper.dart';
main() {
testEmpty();
testNull();
@ -58,6 +60,10 @@ main() {
testInvokeIndexSet(null);
testAssert();
testAssertWithMessage();
testFactoryInvoke();
testFactoryInvokeGeneric();
testFactoryInvokeGenericRaw();
testFactoryInvokeGenericDynamic();
}
testEmpty() {}
@ -154,7 +160,27 @@ testAssert() {
testAssertWithMessage() {
assert(true, 'ok');
}
'''
testFactoryInvoke() {
new Class.fact();
}
testFactoryInvokeGeneric() {
new GenericClass<int, String>.fact();
}
testFactoryInvokeGenericRaw() {
new GenericClass.fact();
}
testFactoryInvokeGenericDynamic() {
new GenericClass<dynamic, dynamic>.fact();
}
''',
'helper.dart': '''
class Class {
factory Class.fact() => null;
}
class GenericClass<X, Y> {
factory GenericClass.fact() => null;
}
''',
};
main(List<String> args) {