mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 16:41:07 +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
|
||||
// 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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in a new issue