mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 03:36:59 +00:00
Handle generic factory constructors in kernel_impact
R=het@google.com Review URL: https://codereview.chromium.org/2341263002 .
This commit is contained in:
parent
9f3b5d8680
commit
e24939f8d6
|
@ -619,7 +619,9 @@ class ConstructorResolver extends CommonResolverVisitor<ConstructorResult> {
|
||||||
// This is not really resolving a type-annotation, but the name of the
|
// This is not really resolving a type-annotation, but the name of the
|
||||||
// constructor. Therefore we allow deferred types.
|
// constructor. Therefore we allow deferred types.
|
||||||
DartType type = resolver.resolveTypeAnnotation(node,
|
DartType type = resolver.resolveTypeAnnotation(node,
|
||||||
malformedIsError: inConstContext, deferredIsMalformed: false);
|
malformedIsError: inConstContext,
|
||||||
|
deferredIsMalformed: false,
|
||||||
|
registerCheckedModeCheck: false);
|
||||||
Send send = node.typeName.asSend();
|
Send send = node.typeName.asSend();
|
||||||
PrefixElement prefix;
|
PrefixElement prefix;
|
||||||
if (send != null) {
|
if (send != null) {
|
||||||
|
|
|
@ -4063,11 +4063,13 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
|
||||||
}
|
}
|
||||||
|
|
||||||
DartType resolveTypeAnnotation(TypeAnnotation node,
|
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,
|
DartType type = typeResolver.resolveTypeAnnotation(this, node,
|
||||||
malformedIsError: malformedIsError,
|
malformedIsError: malformedIsError,
|
||||||
deferredIsMalformed: deferredIsMalformed);
|
deferredIsMalformed: deferredIsMalformed);
|
||||||
if (!type.isDynamic) {
|
if (registerCheckedModeCheck && !type.isDynamic) {
|
||||||
registry.registerTypeUse(new TypeUse.checkedModeCheck(type));
|
registry.registerTypeUse(new TypeUse.checkedModeCheck(type));
|
||||||
}
|
}
|
||||||
return type;
|
return type;
|
||||||
|
|
|
@ -176,7 +176,8 @@ class TypeResolver {
|
||||||
} else {
|
} else {
|
||||||
type = new InterfaceType(
|
type = new InterfaceType(
|
||||||
cls.declaration, arguments.toList(growable: false));
|
cls.declaration, arguments.toList(growable: false));
|
||||||
addTypeVariableBoundsCheck = true;
|
addTypeVariableBoundsCheck =
|
||||||
|
arguments.any((DartType type) => !type.isDynamic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (element.isTypedef) {
|
} else if (element.isTypedef) {
|
||||||
|
@ -195,7 +196,8 @@ class TypeResolver {
|
||||||
type = typdef.rawType;
|
type = typdef.rawType;
|
||||||
} else {
|
} else {
|
||||||
type = new TypedefType(typdef, arguments.toList(growable: false));
|
type = new TypedefType(typdef, arguments.toList(growable: false));
|
||||||
addTypeVariableBoundsCheck = true;
|
addTypeVariableBoundsCheck =
|
||||||
|
arguments.any((DartType type) => !type.isDynamic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (element.isTypeVariable) {
|
} else if (element.isTypeVariable) {
|
||||||
|
|
|
@ -173,6 +173,10 @@ class KernelAstAdapter {
|
||||||
DartType getDartType(ir.DartType type) {
|
DartType getDartType(ir.DartType type) {
|
||||||
return type.accept(_typeConverter);
|
return type.accept(_typeConverter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<DartType> getDartTypes(List<ir.DartType> types) {
|
||||||
|
return types.map(getDartType).toList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DartTypeConverter extends ir.DartTypeVisitor<DartType> {
|
class DartTypeConverter extends ir.DartTypeVisitor<DartType> {
|
||||||
|
|
|
@ -195,8 +195,44 @@ class KernelImpactBuilder extends ir.Visitor {
|
||||||
void visitStaticInvocation(ir.StaticInvocation invocation) {
|
void visitStaticInvocation(ir.StaticInvocation invocation) {
|
||||||
_visitArguments(invocation.arguments);
|
_visitArguments(invocation.arguments);
|
||||||
Element target = astAdapter.getElement(invocation.target).declaration;
|
Element target = astAdapter.getElement(invocation.target).declaration;
|
||||||
impactBuilder.registerStaticUse(new StaticUse.staticInvoke(
|
if (target.isFactoryConstructor) {
|
||||||
target, astAdapter.getCallStructure(invocation.arguments)));
|
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
|
@override
|
||||||
|
|
|
@ -18,6 +18,8 @@ import '../serialization/test_helper.dart';
|
||||||
|
|
||||||
const Map<String, String> SOURCE = const <String, String>{
|
const Map<String, String> SOURCE = const <String, String>{
|
||||||
'main.dart': '''
|
'main.dart': '''
|
||||||
|
import 'helper.dart';
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
testEmpty();
|
testEmpty();
|
||||||
testNull();
|
testNull();
|
||||||
|
@ -58,6 +60,10 @@ main() {
|
||||||
testInvokeIndexSet(null);
|
testInvokeIndexSet(null);
|
||||||
testAssert();
|
testAssert();
|
||||||
testAssertWithMessage();
|
testAssertWithMessage();
|
||||||
|
testFactoryInvoke();
|
||||||
|
testFactoryInvokeGeneric();
|
||||||
|
testFactoryInvokeGenericRaw();
|
||||||
|
testFactoryInvokeGenericDynamic();
|
||||||
}
|
}
|
||||||
|
|
||||||
testEmpty() {}
|
testEmpty() {}
|
||||||
|
@ -154,7 +160,27 @@ testAssert() {
|
||||||
testAssertWithMessage() {
|
testAssertWithMessage() {
|
||||||
assert(true, 'ok');
|
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) {
|
main(List<String> args) {
|
||||||
|
|
Loading…
Reference in a new issue