[cfe] Update inference for redirecting factory constructors

Closes #34714.

Bug: https://github.com/dart-lang/sdk/issues/34714
Change-Id: Ia1f6845d2ae623ecba01fd5e60dcaed975471f6b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/147181
Commit-Queue: Dmitry Stefantsov <dmitryas@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
This commit is contained in:
Dmitry Stefantsov 2020-05-12 14:03:49 +00:00 committed by commit-bot@chromium.org
parent af99babc6c
commit 3b93b85aef
9 changed files with 230 additions and 54 deletions

View file

@ -4,12 +4,15 @@
import 'dart:core' hide MapEntry;
import 'package:front_end/src/fasta/dill/dill_member_builder.dart';
import 'package:front_end/src/fasta/kernel/kernel_api.dart';
import 'package:kernel/ast.dart';
import 'package:kernel/type_algebra.dart';
import '../kernel/class_hierarchy_builder.dart';
import '../kernel/forest.dart';
import '../kernel/internal_ast.dart';
import '../kernel/redirecting_factory_body.dart' show RedirectingFactoryBody;
import '../loader.dart' show Loader;
@ -21,6 +24,9 @@ import '../problems.dart' show unexpected, unhandled;
import '../source/source_library_builder.dart' show SourceLibraryBuilder;
import '../type_inference/type_inferrer.dart';
import '../type_inference/type_schema.dart';
import 'builder.dart';
import 'constructor_reference_builder.dart';
import 'extension_builder.dart';
@ -717,6 +723,79 @@ class RedirectingFactoryBuilder extends ProcedureBuilderImpl {
return _procedure;
}
@override
void buildOutlineExpressions(LibraryBuilder library, CoreTypes coreTypes) {
super.buildOutlineExpressions(library, coreTypes);
LibraryBuilder thisLibrary = this.library;
if (thisLibrary is SourceLibraryBuilder) {
RedirectingFactoryBody redirectingFactoryBody = member.function.body;
if (redirectingFactoryBody.typeArguments != null &&
redirectingFactoryBody.typeArguments.any((t) => t is UnknownType)) {
TypeInferrerImpl inferrer = thisLibrary.loader.typeInferenceEngine
.createLocalTypeInferrer(
fileUri, classBuilder.thisType, thisLibrary, null);
inferrer.helper = thisLibrary.loader
.createBodyBuilderForOutlineExpression(
this.library, classBuilder, this, classBuilder.scope, fileUri);
Builder targetBuilder = redirectionTarget.target;
Member target;
if (targetBuilder is FunctionBuilder) {
target = targetBuilder.member;
} else if (targetBuilder is DillMemberBuilder) {
target = targetBuilder.member;
} else {
unhandled("${targetBuilder.runtimeType}", "buildOutlineExpressions",
charOffset, fileUri);
}
Arguments targetInvocationArguments;
{
List<Expression> positionalArguments = <Expression>[];
for (VariableDeclaration parameter
in member.function.positionalParameters) {
positionalArguments.add(new VariableGetImpl(
parameter,
inferrer.typePromoter.getFactForAccess(parameter, 0),
inferrer.typePromoter.currentScope,
forNullGuardedAccess: false));
}
List<NamedExpression> namedArguments = <NamedExpression>[];
for (VariableDeclaration parameter
in member.function.namedParameters) {
namedArguments.add(new NamedExpression(
parameter.name,
new VariableGetImpl(
parameter,
inferrer.typePromoter.getFactForAccess(parameter, 0),
inferrer.typePromoter.currentScope,
forNullGuardedAccess: false)));
}
// If arguments are created using [Forest.createArguments], and the
// type arguments are omitted, they are to be inferred.
targetInvocationArguments = const Forest().createArguments(
member.fileOffset, positionalArguments,
named: namedArguments);
}
InvocationInferenceResult result = inferrer.inferInvocation(
function.returnType,
charOffset,
target.function.computeFunctionType(Nullability.nonNullable),
targetInvocationArguments);
List<DartType> typeArguments;
if (result.inferredType is InterfaceType) {
typeArguments = (result.inferredType as InterfaceType).typeArguments;
} else {
// Assume that the error is reported elsewhere, use 'dynamic' for
// recovery.
typeArguments = new List<DartType>.filled(
target.enclosingClass.typeParameters.length, const DynamicType(),
growable: true);
}
member.function.body =
new RedirectingFactoryBody(target, typeArguments);
}
}
}
@override
List<ClassMember> get localMembers =>
throw new UnsupportedError('${runtimeType}.localMembers');

View file

@ -419,7 +419,6 @@ class InferenceVisitor
node.target.function
.computeThisFunctionType(inferrer.library.nonNullable),
node.arguments,
node.name,
returnType:
computeConstructorReturnType(node.target, inferrer.coreTypes),
isConst: node.isConst);
@ -449,8 +448,8 @@ class InferenceVisitor
: new FunctionType(
[], const DynamicType(), inferrer.library.nonNullable);
TypeArgumentsInfo typeArgumentsInfo = getTypeArgumentsInfo(node.arguments);
InvocationInferenceResult result = inferrer.inferInvocation(typeContext,
node.fileOffset, calleeType, node.arguments, node.target.name);
InvocationInferenceResult result = inferrer.inferInvocation(
typeContext, node.fileOffset, calleeType, node.arguments);
Expression replacement = new StaticInvocation(node.target, node.arguments);
if (!inferrer.isTopLevel && node.target != null) {
inferrer.library.checkBoundsInStaticInvocation(
@ -702,7 +701,6 @@ class InferenceVisitor
node.target.function
.computeThisFunctionType(inferrer.library.nonNullable),
node.arguments,
node.name,
returnType:
computeConstructorReturnType(node.target, inferrer.coreTypes),
isConst: node.isConst);
@ -1061,7 +1059,6 @@ class InferenceVisitor
.computeThisFunctionType(inferrer.library.nonNullable)
.withoutTypeParameters),
node.argumentsJudgment,
node.target.name,
returnType: inferrer.thisType,
skipTypeArgumentInference: true);
}
@ -4850,7 +4847,6 @@ class InferenceVisitor
node.target.function
.computeThisFunctionType(inferrer.library.nonNullable),
node.arguments,
node.target.name,
returnType: inferrer.coreTypes.thisInterfaceType(
node.target.enclosingClass, inferrer.library.nonNullable),
skipTypeArgumentInference: true);
@ -5014,7 +5010,7 @@ class InferenceVisitor
[], const DynamicType(), inferrer.library.nonNullable);
TypeArgumentsInfo typeArgumentsInfo = getTypeArgumentsInfo(node.arguments);
InvocationInferenceResult result = inferrer.inferInvocation(
typeContext, node.fileOffset, calleeType, node.arguments, node.name);
typeContext, node.fileOffset, calleeType, node.arguments);
if (!inferrer.isTopLevel && node.target != null) {
inferrer.library.checkBoundsInStaticInvocation(
node,
@ -5061,7 +5057,6 @@ class InferenceVisitor
.computeThisFunctionType(inferrer.library.nonNullable)
.withoutTypeParameters),
node.arguments,
node.target.name,
returnType: inferrer.thisType,
skipTypeArgumentInference: true);
}
@ -5688,7 +5683,7 @@ class InferenceVisitor
FunctionType calleeType =
new FunctionType([], inferredType, inferrer.library.nonNullable);
inferrer.inferInvocation(
typeContext, node.fileOffset, calleeType, node.arguments, null);
typeContext, node.fileOffset, calleeType, node.arguments);
}
return new ExpressionInferenceResult(inferredType, node);
}

View file

@ -321,10 +321,10 @@ class KernelTarget extends TargetImplementation {
loader.checkTypes();
loader.checkOverrides(myClasses);
loader.checkAbstractMembers(myClasses);
loader.checkRedirectingFactories(myClasses);
loader.addNoSuchMethodForwarders(myClasses);
loader.checkMixins(myClasses);
loader.buildOutlineExpressions(loader.coreTypes);
loader.checkRedirectingFactories(myClasses);
_updateDelayedParameterTypes();
installAllComponentProblems(loader.allComponentProblems);
loader.allComponentProblems.clear();

View file

@ -35,10 +35,10 @@ import '../dill/dill_member_builder.dart' show DillMemberBuilder;
import '../fasta_codes.dart';
import '../kernel/redirecting_factory_body.dart' show redirectingName;
import '../kernel/kernel_builder.dart' show compareProcedures;
import '../kernel/kernel_target.dart' show KernelTarget;
import '../kernel/redirecting_factory_body.dart' show RedirectingFactoryBody;
import '../kernel/redirecting_factory_body.dart' show redirectingName;
import '../kernel/type_algorithms.dart'
show Variance, computeTypeVariableBuilderVariance;
@ -48,6 +48,8 @@ import '../problems.dart' show unexpected, unhandled;
import '../scope.dart';
import '../type_inference/type_schema.dart';
import 'source_library_builder.dart' show SourceLibraryBuilder;
Class initializeClass(
@ -1054,29 +1056,19 @@ class SourceClassBuilder extends ClassBuilderImpl
addRedirectingConstructor(declaration, library, referenceFrom);
}
if (targetBuilder is FunctionBuilder) {
List<DartType> typeArguments = declaration.typeArguments;
if (typeArguments == null) {
// TODO(32049) If type arguments aren't specified, they should
// be inferred. Currently, the inference is not performed.
// The code below is a workaround.
typeArguments = new List<DartType>.filled(
targetBuilder.member.enclosingClass.typeParameters.length,
const DynamicType(),
growable: true);
}
List<DartType> typeArguments = declaration.typeArguments ??
new List<DartType>.filled(
targetBuilder
.member.enclosingClass.typeParameters.length,
const UnknownType());
declaration.setRedirectingFactoryBody(
targetBuilder.member, typeArguments);
} else if (targetBuilder is DillMemberBuilder) {
List<DartType> typeArguments = declaration.typeArguments;
if (typeArguments == null) {
// TODO(32049) If type arguments aren't specified, they should
// be inferred. Currently, the inference is not performed.
// The code below is a workaround.
typeArguments = new List<DartType>.filled(
targetBuilder.member.enclosingClass.typeParameters.length,
const DynamicType(),
growable: true);
}
List<DartType> typeArguments = declaration.typeArguments ??
new List<DartType>.filled(
targetBuilder
.member.enclosingClass.typeParameters.length,
const UnknownType());
declaration.setRedirectingFactoryBody(
targetBuilder.member, typeArguments);
} else if (targetBuilder is AmbiguousBuilder) {

View file

@ -2005,7 +2005,7 @@ class TypeInferrerImpl implements TypeInferrer {
}
InvocationInferenceResult inferInvocation(DartType typeContext, int offset,
FunctionType calleeType, Arguments arguments, Name targetName,
FunctionType calleeType, Arguments arguments,
{List<VariableDeclaration> hoistedExpressions,
bool isOverloadedArithmeticOperator: false,
DartType returnType,
@ -2022,22 +2022,16 @@ class TypeInferrerImpl implements TypeInferrer {
if (extensionTypeParameterCount != 0) {
assert(returnType == null,
"Unexpected explicit return type for extension method invocation.");
return _inferGenericExtensionMethodInvocation(
extensionTypeParameterCount,
typeContext,
offset,
calleeType,
arguments,
targetName,
hoistedExpressions,
return _inferGenericExtensionMethodInvocation(extensionTypeParameterCount,
typeContext, offset, calleeType, arguments, hoistedExpressions,
isOverloadedArithmeticOperator: isOverloadedArithmeticOperator,
receiverType: receiverType,
skipTypeArgumentInference: skipTypeArgumentInference,
isConst: isConst,
isImplicitExtensionMember: isImplicitExtensionMember);
}
return _inferInvocation(typeContext, offset, calleeType, arguments,
targetName, hoistedExpressions,
return _inferInvocation(
typeContext, offset, calleeType, arguments, hoistedExpressions,
isOverloadedArithmeticOperator: isOverloadedArithmeticOperator,
receiverType: receiverType,
returnType: returnType,
@ -2053,7 +2047,6 @@ class TypeInferrerImpl implements TypeInferrer {
int offset,
FunctionType calleeType,
Arguments arguments,
Name targetName,
List<VariableDeclaration> hoistedExpressions,
{bool isOverloadedArithmeticOperator: false,
DartType receiverType,
@ -2073,7 +2066,7 @@ class TypeInferrerImpl implements TypeInferrer {
arguments.fileOffset, [arguments.positional.first],
types: getExplicitExtensionTypeArguments(arguments));
_inferInvocation(const UnknownType(), offset, extensionFunctionType,
extensionArguments, targetName, hoistedExpressions,
extensionArguments, hoistedExpressions,
skipTypeArgumentInference: skipTypeArgumentInference,
receiverType: receiverType,
isImplicitExtensionMember: isImplicitExtensionMember,
@ -2099,7 +2092,7 @@ class TypeInferrerImpl implements TypeInferrer {
arguments.fileOffset, arguments.positional.skip(1).toList(),
named: arguments.named, types: getExplicitTypeArguments(arguments));
InvocationInferenceResult result = _inferInvocation(typeContext, offset,
targetFunctionType, targetArguments, targetName, hoistedExpressions,
targetFunctionType, targetArguments, hoistedExpressions,
isOverloadedArithmeticOperator: isOverloadedArithmeticOperator,
skipTypeArgumentInference: skipTypeArgumentInference,
isConst: isConst,
@ -2124,7 +2117,6 @@ class TypeInferrerImpl implements TypeInferrer {
int offset,
FunctionType calleeType,
Arguments arguments,
Name targetName,
List<VariableDeclaration> hoistedExpressions,
{bool isOverloadedArithmeticOperator: false,
bool isBinaryOperator: false,
@ -2636,7 +2628,7 @@ class TypeInferrerImpl implements TypeInferrer {
{bool isImplicitCall}) {
assert(isImplicitCall != null);
InvocationInferenceResult result = inferInvocation(
typeContext, fileOffset, unknownFunction, arguments, name,
typeContext, fileOffset, unknownFunction, arguments,
hoistedExpressions: hoistedExpressions,
receiverType: const DynamicType(),
isImplicitCall: isImplicitCall);
@ -2660,7 +2652,7 @@ class TypeInferrerImpl implements TypeInferrer {
{bool isImplicitCall}) {
assert(isImplicitCall != null);
InvocationInferenceResult result = inferInvocation(
typeContext, fileOffset, unknownFunction, arguments, name,
typeContext, fileOffset, unknownFunction, arguments,
hoistedExpressions: hoistedExpressions,
receiverType: receiverType,
isImplicitCall: isImplicitCall);
@ -2694,7 +2686,7 @@ class TypeInferrerImpl implements TypeInferrer {
implicitInvocationPropertyName: implicitInvocationPropertyName,
extensionAccessCandidates:
target.isAmbiguous ? target.candidates : null);
inferInvocation(typeContext, fileOffset, unknownFunction, arguments, name,
inferInvocation(typeContext, fileOffset, unknownFunction, arguments,
hoistedExpressions: hoistedExpressions,
receiverType: receiverType,
isImplicitCall: isExpressionInvocation || isImplicitCall);
@ -2749,8 +2741,8 @@ class TypeInferrerImpl implements TypeInferrer {
} else {
StaticInvocation staticInvocation = transformExtensionMethodInvocation(
fileOffset, target, receiver, arguments);
InvocationInferenceResult result = inferInvocation(typeContext,
fileOffset, functionType, staticInvocation.arguments, name,
InvocationInferenceResult result = inferInvocation(
typeContext, fileOffset, functionType, staticInvocation.arguments,
hoistedExpressions: hoistedExpressions,
receiverType: receiverType,
isImplicitExtensionMember: true,
@ -2797,7 +2789,7 @@ class TypeInferrerImpl implements TypeInferrer {
assert(target.isCallFunction || target.isNullableCallFunction);
FunctionType functionType = getFunctionType(target, receiverType);
InvocationInferenceResult result = inferInvocation(
typeContext, fileOffset, functionType, arguments, callName,
typeContext, fileOffset, functionType, arguments,
hoistedExpressions: hoistedExpressions,
receiverType: receiverType,
isImplicitCall: isImplicitCall);
@ -2874,7 +2866,7 @@ class TypeInferrerImpl implements TypeInferrer {
contravariantCheck = true;
}
InvocationInferenceResult result = inferInvocation(
typeContext, fileOffset, functionType, arguments, target.member?.name,
typeContext, fileOffset, functionType, arguments,
hoistedExpressions: hoistedExpressions,
receiverType: receiverType,
isImplicitCall: isImplicitCall);
@ -3349,7 +3341,7 @@ class TypeInferrerImpl implements TypeInferrer {
FunctionType functionType = getFunctionType(target, receiverType);
InvocationInferenceResult result = inferInvocation(
typeContext, fileOffset, functionType, arguments, target.member?.name,
typeContext, fileOffset, functionType, arguments,
isOverloadedArithmeticOperator: isOverloadedArithmeticOperator,
receiverType: receiverType,
isImplicitExtensionMember: target.isExtensionMember);

View file

@ -0,0 +1,13 @@
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
class A<T> {
factory A() = B; // Should infer B<T>.
}
class B<T> implements A<T> {
B();
}
main() {}

View file

@ -0,0 +1,35 @@
library;
import self as self;
import "dart:core" as core;
class A<T extends core::Object* = dynamic> extends core::Object {
static field dynamic _redirecting# = <dynamic>[self::A::•];
static factory •<T extends core::Object* = dynamic>() → self::A<self::A::•::T*>*
let dynamic #redirecting_factory = self::B::• in let self::A::•::T* #typeArg0 = null in invalid-expression;
abstract member-signature get _identityHashCode() → core::int*;
abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*;
abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*;
abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*;
abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*;
abstract member-signature operator ==(dynamic other) → core::bool*;
abstract member-signature get hashCode() → core::int*;
abstract member-signature method toString() → core::String*;
abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic;
abstract member-signature get runtimeType() → core::Type*;
}
class B<T extends core::Object* = dynamic> extends core::Object implements self::A<self::B::T*> {
constructor •() → self::B<self::B::T*>*
;
abstract member-signature get _identityHashCode() → core::int*;
abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*;
abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*;
abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*;
abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*;
abstract member-signature operator ==(dynamic other) → core::bool*;
abstract member-signature get hashCode() → core::int*;
abstract member-signature method toString() → core::String*;
abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic;
abstract member-signature get runtimeType() → core::Type*;
}
static method main() → dynamic
;

View file

@ -0,0 +1,35 @@
library;
import self as self;
import "dart:core" as core;
class A<T extends core::Object* = dynamic> extends core::Object {
static field dynamic _redirecting# = <dynamic>[self::A::•];
static factory •<T extends core::Object* = dynamic>() → self::A<self::A::•::T*>*
let dynamic #redirecting_factory = self::B::• in let self::A::•::T* #typeArg0 = null in invalid-expression;
abstract member-signature get _identityHashCode() → core::int*;
abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*;
abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*;
abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*;
abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*;
abstract member-signature operator ==(dynamic other) → core::bool*;
abstract member-signature get hashCode() → core::int*;
abstract member-signature method toString() → core::String*;
abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic;
abstract member-signature get runtimeType() → core::Type*;
}
class B<T extends core::Object* = dynamic> extends core::Object implements self::A<self::B::T*> {
constructor •() → self::B<self::B::T*>*
: super core::Object::•()
;
abstract member-signature get _identityHashCode() → core::int*;
abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*;
abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*;
abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*;
abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*;
abstract member-signature operator ==(dynamic other) → core::bool*;
abstract member-signature get hashCode() → core::int*;
abstract member-signature method toString() → core::String*;
abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic;
abstract member-signature get runtimeType() → core::Type*;
}
static method main() → dynamic {}

View file

@ -0,0 +1,35 @@
library;
import self as self;
import "dart:core" as core;
class A<T extends core::Object* = dynamic> extends core::Object {
static field dynamic _redirecting# = <dynamic>[self::A::•];
static factory •<T extends core::Object* = dynamic>() → self::A<self::A::•::T*>*
let<BottomType> #redirecting_factory = self::B::• in let self::A::•::T* #typeArg0 = null in invalid-expression;
abstract member-signature get _identityHashCode() → core::int*;
abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*;
abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*;
abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*;
abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*;
abstract member-signature operator ==(dynamic other) → core::bool*;
abstract member-signature get hashCode() → core::int*;
abstract member-signature method toString() → core::String*;
abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic;
abstract member-signature get runtimeType() → core::Type*;
}
class B<T extends core::Object* = dynamic> extends core::Object implements self::A<self::B::T*> {
constructor •() → self::B<self::B::T*>*
: super core::Object::•()
;
abstract member-signature get _identityHashCode() → core::int*;
abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*;
abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*;
abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*;
abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*;
abstract member-signature operator ==(dynamic other) → core::bool*;
abstract member-signature get hashCode() → core::int*;
abstract member-signature method toString() → core::String*;
abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic;
abstract member-signature get runtimeType() → core::Type*;
}
static method main() → dynamic {}