Resolve type arguments of redirecting factories invocations
Fixes #32068 Change-Id: Ifc2c832d5a761ae51b7f93084543aa04902a9529 Reviewed-on: https://dart-review.googlesource.com/40280 Commit-Queue: Dmitry Stefantsov <dmitryas@google.com> Reviewed-by: Kevin Millikin <kmillikin@google.com>
This commit is contained in:
committed by
commit-bot@chromium.org
parent
50db95f69b
commit
ec9c927b18
@@ -79,6 +79,7 @@ import 'frontend_accessors.dart' show buildIsNull;
|
||||
import 'redirecting_factory_body.dart'
|
||||
show
|
||||
RedirectingFactoryBody,
|
||||
RedirectionTarget,
|
||||
getRedirectingFactoryBody,
|
||||
getRedirectionTarget;
|
||||
|
||||
@@ -2370,6 +2371,7 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
|
||||
{bool isConst: false,
|
||||
int charOffset: -1,
|
||||
Member initialTarget,
|
||||
List<DartType> targetTypeArguments,
|
||||
String prefixName,
|
||||
int targetOffset: -1,
|
||||
Class targetClass}) {
|
||||
@@ -2390,7 +2392,7 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
|
||||
"Not a const constructor.", charOffset);
|
||||
}
|
||||
return new ShadowConstructorInvocation(
|
||||
prefixName, target, initialTarget, arguments,
|
||||
prefixName, target, targetTypeArguments, initialTarget, arguments,
|
||||
isConst: isConst)
|
||||
..fileOffset = charOffset;
|
||||
} else {
|
||||
@@ -2400,7 +2402,7 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
|
||||
"Not a const factory.", charOffset);
|
||||
} else if (procedure.isFactory) {
|
||||
return new ShadowFactoryConstructorInvocation(
|
||||
prefixName, target, initialTarget, arguments,
|
||||
prefixName, target, targetTypeArguments, initialTarget, arguments,
|
||||
isConst: isConst)
|
||||
..fileOffset = charOffset;
|
||||
} else {
|
||||
@@ -2561,6 +2563,7 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
|
||||
Builder b = type.findConstructorOrFactory(name, charOffset, uri, library);
|
||||
Member target;
|
||||
Member initialTarget;
|
||||
List<DartType> targetTypeArguments;
|
||||
if (b == null) {
|
||||
// Not found. Reported below.
|
||||
} else if (b.isConstructor) {
|
||||
@@ -2578,7 +2581,11 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
|
||||
}
|
||||
} else if (b.isFactory) {
|
||||
initialTarget = b.target;
|
||||
target = getRedirectionTarget(initialTarget);
|
||||
RedirectionTarget redirectionTarget = getRedirectionTarget(
|
||||
initialTarget,
|
||||
strongMode: library.loader.target.strongMode);
|
||||
target = redirectionTarget?.target;
|
||||
targetTypeArguments = redirectionTarget?.typeArguments;
|
||||
if (target == null) {
|
||||
return deprecated_buildCompileTimeError(
|
||||
"Cyclic definition of factory '${name}'.", nameToken.charOffset);
|
||||
@@ -2608,7 +2615,8 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
|
||||
isConst: isConst,
|
||||
charOffset: nameToken.charOffset,
|
||||
prefixName: prefixName,
|
||||
initialTarget: initialTarget);
|
||||
initialTarget: initialTarget,
|
||||
targetTypeArguments: targetTypeArguments);
|
||||
} else {
|
||||
errorName ??= debugName(type.name, name);
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ export 'kernel_procedure_builder.dart'
|
||||
show
|
||||
KernelConstructorBuilder,
|
||||
KernelFunctionBuilder,
|
||||
KernelRedirectingFactoryBuilder,
|
||||
KernelProcedureBuilder;
|
||||
|
||||
export 'kernel_type_builder.dart' show KernelTypeBuilder;
|
||||
|
||||
@@ -10,6 +10,7 @@ import 'package:kernel/ast.dart'
|
||||
Class,
|
||||
Constructor,
|
||||
DartType,
|
||||
DynamicType,
|
||||
Expression,
|
||||
Field,
|
||||
FunctionNode,
|
||||
@@ -58,6 +59,7 @@ import 'kernel_builder.dart'
|
||||
ConstructorReferenceBuilder,
|
||||
KernelLibraryBuilder,
|
||||
KernelProcedureBuilder,
|
||||
KernelRedirectingFactoryBuilder,
|
||||
KernelTypeBuilder,
|
||||
KernelTypeVariableBuilder,
|
||||
LibraryBuilder,
|
||||
@@ -156,7 +158,7 @@ abstract class KernelClassBuilder
|
||||
unexpected(
|
||||
"$fileUri", "${builder.parent.fileUri}", charOffset, fileUri);
|
||||
}
|
||||
if (builder is KernelProcedureBuilder && builder.isFactory) {
|
||||
if (builder is KernelRedirectingFactoryBuilder) {
|
||||
// Compute the immediate redirection target, not the effective.
|
||||
ConstructorReferenceBuilder redirectionTarget =
|
||||
builder.redirectionTarget;
|
||||
@@ -164,9 +166,29 @@ abstract class KernelClassBuilder
|
||||
Builder targetBuilder = redirectionTarget.target;
|
||||
addRedirectingConstructor(builder, library);
|
||||
if (targetBuilder is ProcedureBuilder) {
|
||||
builder.setRedirectingFactoryBody(targetBuilder.target);
|
||||
List<DartType> typeArguments = builder.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.filled(
|
||||
targetBuilder.target.enclosingClass.typeParameters.length,
|
||||
const DynamicType());
|
||||
}
|
||||
builder.setRedirectingFactoryBody(
|
||||
targetBuilder.target, typeArguments);
|
||||
} else if (targetBuilder is DillMemberBuilder) {
|
||||
builder.setRedirectingFactoryBody(targetBuilder.member);
|
||||
List<DartType> typeArguments = builder.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.filled(
|
||||
targetBuilder.target.enclosingClass.typeParameters.length,
|
||||
const DynamicType());
|
||||
}
|
||||
builder.setRedirectingFactoryBody(
|
||||
targetBuilder.member, typeArguments);
|
||||
} else {
|
||||
var message = templateRedirectionTargetNotFound
|
||||
.withArguments(redirectionTarget.fullNameForErrors);
|
||||
|
||||
@@ -65,6 +65,7 @@ import 'kernel_builder.dart'
|
||||
KernelMixinApplicationBuilder,
|
||||
KernelNamedTypeBuilder,
|
||||
KernelProcedureBuilder,
|
||||
KernelRedirectingFactoryBuilder,
|
||||
KernelTypeBuilder,
|
||||
KernelTypeVariableBuilder,
|
||||
LibraryBuilder,
|
||||
@@ -674,22 +675,40 @@ class KernelLibraryBuilder
|
||||
}
|
||||
|
||||
assert(constructorNameReference.suffix == null);
|
||||
KernelProcedureBuilder procedure = new KernelProcedureBuilder(
|
||||
metadata,
|
||||
staticMask | modifiers,
|
||||
returnType,
|
||||
procedureName,
|
||||
copyTypeVariables(
|
||||
currentDeclaration.typeVariables ?? <TypeVariableBuilder>[],
|
||||
factoryDeclaration),
|
||||
formals,
|
||||
ProcedureKind.Factory,
|
||||
this,
|
||||
charOffset,
|
||||
charOpenParenOffset,
|
||||
charEndOffset,
|
||||
nativeMethodName,
|
||||
redirectionTarget);
|
||||
KernelProcedureBuilder procedure;
|
||||
if (redirectionTarget != null) {
|
||||
procedure = new KernelRedirectingFactoryBuilder(
|
||||
metadata,
|
||||
staticMask | modifiers,
|
||||
returnType,
|
||||
procedureName,
|
||||
copyTypeVariables(
|
||||
currentDeclaration.typeVariables ?? <TypeVariableBuilder>[],
|
||||
factoryDeclaration),
|
||||
formals,
|
||||
this,
|
||||
charOffset,
|
||||
charOpenParenOffset,
|
||||
charEndOffset,
|
||||
nativeMethodName,
|
||||
redirectionTarget);
|
||||
} else {
|
||||
procedure = new KernelProcedureBuilder(
|
||||
metadata,
|
||||
staticMask | modifiers,
|
||||
returnType,
|
||||
procedureName,
|
||||
copyTypeVariables(
|
||||
currentDeclaration.typeVariables ?? <TypeVariableBuilder>[],
|
||||
factoryDeclaration),
|
||||
formals,
|
||||
ProcedureKind.Factory,
|
||||
this,
|
||||
charOffset,
|
||||
charOpenParenOffset,
|
||||
charEndOffset,
|
||||
nativeMethodName);
|
||||
}
|
||||
|
||||
var metadataCollector = loader.target.metadataCollector;
|
||||
metadataCollector?.setDocumentationComment(
|
||||
|
||||
@@ -128,7 +128,7 @@ abstract class KernelFunctionBuilder
|
||||
}
|
||||
}
|
||||
|
||||
void setRedirectingFactoryBody(Member target) {
|
||||
void setRedirectingFactoryBody(Member target, List<DartType> typeArguments) {
|
||||
if (actualBody != null) {
|
||||
unexpected("null", "${actualBody.runtimeType}", charOffset, fileUri);
|
||||
}
|
||||
@@ -136,7 +136,7 @@ abstract class KernelFunctionBuilder
|
||||
function.body = actualBody;
|
||||
actualBody?.parent = function;
|
||||
if (isPatch) {
|
||||
actualOrigin.setRedirectingFactoryBody(target);
|
||||
actualOrigin.setRedirectingFactoryBody(target, typeArguments);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,8 +259,6 @@ class KernelProcedureBuilder extends KernelFunctionBuilder {
|
||||
|
||||
AsyncMarker actualAsyncModifier = AsyncMarker.Sync;
|
||||
|
||||
final ConstructorReferenceBuilder redirectionTarget;
|
||||
|
||||
@override
|
||||
KernelProcedureBuilder actualOrigin;
|
||||
|
||||
@@ -276,8 +274,7 @@ class KernelProcedureBuilder extends KernelFunctionBuilder {
|
||||
int charOffset,
|
||||
this.charOpenParenOffset,
|
||||
int charEndOffset,
|
||||
[String nativeMethodName,
|
||||
this.redirectionTarget])
|
||||
[String nativeMethodName])
|
||||
: procedure = new ShadowProcedure(null, kind, null, returnType == null,
|
||||
fileUri: compilationUnit?.fileUri)
|
||||
..fileOffset = charOffset
|
||||
@@ -293,10 +290,7 @@ class KernelProcedureBuilder extends KernelFunctionBuilder {
|
||||
AsyncMarker get asyncModifier => actualAsyncModifier;
|
||||
|
||||
Statement get body {
|
||||
if (actualBody == null &&
|
||||
redirectionTarget == null &&
|
||||
!isAbstract &&
|
||||
!isExternal) {
|
||||
if (actualBody == null && !isAbstract && !isExternal) {
|
||||
actualBody = new EmptyStatement();
|
||||
}
|
||||
return actualBody;
|
||||
@@ -573,3 +567,78 @@ class KernelConstructorBuilder extends KernelFunctionBuilder {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class KernelRedirectingFactoryBuilder extends KernelProcedureBuilder {
|
||||
final ConstructorReferenceBuilder redirectionTarget;
|
||||
List<DartType> typeArguments;
|
||||
|
||||
KernelRedirectingFactoryBuilder(
|
||||
List<MetadataBuilder> metadata,
|
||||
int modifiers,
|
||||
KernelTypeBuilder returnType,
|
||||
String name,
|
||||
List<TypeVariableBuilder> typeVariables,
|
||||
List<FormalParameterBuilder> formals,
|
||||
KernelLibraryBuilder compilationUnit,
|
||||
int charOffset,
|
||||
int charOpenParenOffset,
|
||||
int charEndOffset,
|
||||
[String nativeMethodName,
|
||||
this.redirectionTarget])
|
||||
: super(
|
||||
metadata,
|
||||
modifiers,
|
||||
returnType,
|
||||
name,
|
||||
typeVariables,
|
||||
formals,
|
||||
ProcedureKind.Factory,
|
||||
compilationUnit,
|
||||
charOffset,
|
||||
charOpenParenOffset,
|
||||
charEndOffset,
|
||||
nativeMethodName);
|
||||
|
||||
@override
|
||||
Statement get body => actualBody;
|
||||
|
||||
@override
|
||||
void setRedirectingFactoryBody(Member target, List<DartType> typeArguments) {
|
||||
if (actualBody != null) {
|
||||
unexpected("null", "${actualBody.runtimeType}", charOffset, fileUri);
|
||||
}
|
||||
actualBody = new RedirectingFactoryBody(target, typeArguments);
|
||||
function.body = actualBody;
|
||||
actualBody?.parent = function;
|
||||
if (isPatch) {
|
||||
actualOrigin.setRedirectingFactoryBody(target, typeArguments);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Procedure build(SourceLibraryBuilder library) {
|
||||
Procedure result = super.build(library);
|
||||
if (redirectionTarget.typeArguments != null) {
|
||||
typeArguments =
|
||||
new List<DartType>(redirectionTarget.typeArguments.length);
|
||||
for (int i = 0; i < typeArguments.length; i++) {
|
||||
typeArguments[i] = redirectionTarget.typeArguments[i].build(library);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@override
|
||||
int finishPatch() {
|
||||
if (!isPatch) return 0;
|
||||
|
||||
super.finishPatch();
|
||||
|
||||
if (origin is KernelRedirectingFactoryBuilder) {
|
||||
KernelRedirectingFactoryBuilder redirectingOrigin = origin;
|
||||
redirectingOrigin.typeArguments = typeArguments;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -569,8 +569,24 @@ class ShadowConstructorInvocation extends ConstructorInvocation
|
||||
|
||||
final Member _initialTarget;
|
||||
|
||||
/// If the constructor invocation points to a redirected constructor, the type
|
||||
/// arguments to be supplied to redirected constructor, in terms of those
|
||||
/// supplied to the original constructor.
|
||||
///
|
||||
/// For example, in the code below:
|
||||
///
|
||||
/// class C<T> {
|
||||
/// C() = D<List<T>>;
|
||||
/// }
|
||||
/// main() {
|
||||
/// new C<int>();
|
||||
/// }
|
||||
///
|
||||
/// [targetTypeArguments] is a list containing the type `List<T>`.
|
||||
final List<DartType> targetTypeArguments;
|
||||
|
||||
ShadowConstructorInvocation(this._prefixName, Constructor target,
|
||||
this._initialTarget, Arguments arguments,
|
||||
this.targetTypeArguments, this._initialTarget, Arguments arguments,
|
||||
{bool isConst: false})
|
||||
: super(target, arguments, isConst: isConst);
|
||||
|
||||
@@ -595,6 +611,31 @@ class ShadowConstructorInvocation extends ConstructorInvocation
|
||||
.message);
|
||||
}
|
||||
inferrer.listener.constructorInvocationExit(this, inferredType);
|
||||
|
||||
if (isRedirected(this)) {
|
||||
InterfaceType returnType = inferredType;
|
||||
List<DartType> initialTypeArguments;
|
||||
if (inferrer.strongMode) {
|
||||
initialTypeArguments = returnType.typeArguments;
|
||||
} else {
|
||||
int requiredTypeArgumentsCount = returnType.typeArguments.length;
|
||||
int suppliedTypeArgumentsCount = arguments.types.length;
|
||||
initialTypeArguments = arguments.types.toList(growable: true)
|
||||
..length = requiredTypeArgumentsCount;
|
||||
for (int i = suppliedTypeArgumentsCount;
|
||||
i < requiredTypeArgumentsCount;
|
||||
i++) {
|
||||
initialTypeArguments[i] = const DynamicType();
|
||||
}
|
||||
}
|
||||
Substitution substitution = Substitution.fromPairs(
|
||||
_initialTarget.function.typeParameters, initialTypeArguments);
|
||||
arguments.types.clear();
|
||||
for (DartType argument in targetTypeArguments) {
|
||||
arguments.types.add(substitution.substituteType(argument));
|
||||
}
|
||||
}
|
||||
|
||||
return inferredType;
|
||||
}
|
||||
|
||||
@@ -700,8 +741,24 @@ class ShadowFactoryConstructorInvocation extends StaticInvocation
|
||||
|
||||
final Member _initialTarget;
|
||||
|
||||
/// If the factory invocation points to a redirected factory, the type
|
||||
/// arguments to be supplied to redirected constructor, in terms of those
|
||||
/// supplied to the original constructor.
|
||||
///
|
||||
/// For example, in the code below:
|
||||
///
|
||||
/// class C<T> {
|
||||
/// C() = D<List<T>>;
|
||||
/// }
|
||||
/// main() {
|
||||
/// new C<int>();
|
||||
/// }
|
||||
///
|
||||
/// [targetTypeArguments] is a list containing the type `List<T>`.
|
||||
final List<DartType> targetTypeArguments;
|
||||
|
||||
ShadowFactoryConstructorInvocation(this._prefixName, Procedure target,
|
||||
this._initialTarget, Arguments arguments,
|
||||
this.targetTypeArguments, this._initialTarget, Arguments arguments,
|
||||
{bool isConst: false})
|
||||
: super(target, arguments, isConst: isConst);
|
||||
|
||||
@@ -716,8 +773,42 @@ class ShadowFactoryConstructorInvocation extends StaticInvocation
|
||||
computeConstructorReturnType(_initialTarget),
|
||||
arguments);
|
||||
inferrer.listener.constructorInvocationExit(this, inferredType);
|
||||
|
||||
if (isRedirected(this)) {
|
||||
InterfaceType returnType = inferredType;
|
||||
List<DartType> initialTypeArguments;
|
||||
if (inferrer.strongMode) {
|
||||
initialTypeArguments = returnType.typeArguments;
|
||||
} else {
|
||||
int requiredTypeArgumentsCount = returnType.typeArguments.length;
|
||||
int suppliedTypeArgumentsCount = arguments.types.length;
|
||||
initialTypeArguments = arguments.types.toList(growable: true)
|
||||
..length = requiredTypeArgumentsCount;
|
||||
for (int i = suppliedTypeArgumentsCount;
|
||||
i < requiredTypeArgumentsCount;
|
||||
i++) {
|
||||
initialTypeArguments[i] = const DynamicType();
|
||||
}
|
||||
}
|
||||
Substitution substitution = Substitution.fromPairs(
|
||||
_initialTarget.function.typeParameters, initialTypeArguments);
|
||||
arguments.types.clear();
|
||||
for (DartType argument in targetTypeArguments) {
|
||||
arguments.types.add(substitution.substituteType(argument));
|
||||
}
|
||||
}
|
||||
|
||||
return inferredType;
|
||||
}
|
||||
|
||||
/// Determines whether the given [ShadowConstructorInvocation] represents an
|
||||
/// invocation of a redirected factory constructor.
|
||||
///
|
||||
/// This is static to avoid introducing a method that would be visible to the
|
||||
/// kernel.
|
||||
static bool isRedirected(ShadowFactoryConstructorInvocation expression) {
|
||||
return !identical(expression._initialTarget, expression.target);
|
||||
}
|
||||
}
|
||||
|
||||
/// Concrete shadow object representing a field in kernel form.
|
||||
|
||||
@@ -6,25 +6,33 @@ library fasta.redirecting_factory_body;
|
||||
|
||||
import 'package:kernel/ast.dart'
|
||||
show
|
||||
DartType,
|
||||
DynamicType,
|
||||
Expression,
|
||||
ExpressionStatement,
|
||||
FunctionNode,
|
||||
InvalidExpression,
|
||||
Let,
|
||||
Member,
|
||||
NullLiteral,
|
||||
Procedure,
|
||||
StaticGet,
|
||||
StringLiteral,
|
||||
TypeParameterType,
|
||||
VariableDeclaration;
|
||||
|
||||
import 'package:kernel/type_algebra.dart' show Substitution;
|
||||
|
||||
const String letName = "#redirecting_factory";
|
||||
|
||||
class RedirectingFactoryBody extends ExpressionStatement {
|
||||
RedirectingFactoryBody.internal(Expression value)
|
||||
RedirectingFactoryBody.internal(Expression value,
|
||||
[List<DartType> typeArguments])
|
||||
: super(new Let(new VariableDeclaration(letName, initializer: value),
|
||||
new InvalidExpression(null)));
|
||||
encodeTypeArguments(typeArguments)));
|
||||
|
||||
RedirectingFactoryBody(Member target) : this.internal(new StaticGet(target));
|
||||
RedirectingFactoryBody(Member target, [List<DartType> typeArguments])
|
||||
: this.internal(new StaticGet(target), typeArguments);
|
||||
|
||||
RedirectingFactoryBody.unresolved(String name)
|
||||
: this.internal(new StringLiteral(name));
|
||||
@@ -41,6 +49,16 @@ class RedirectingFactoryBody extends ExpressionStatement {
|
||||
|
||||
bool get isUnresolved => unresolvedName != null;
|
||||
|
||||
List<DartType> get typeArguments {
|
||||
if (expression is Let) {
|
||||
Let bodyExpression = expression;
|
||||
if (bodyExpression.variable.name == letName) {
|
||||
return decodeTypeArguments(bodyExpression.body);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static getValue(Expression expression) {
|
||||
if (expression is Let) {
|
||||
VariableDeclaration variable = expression.variable;
|
||||
@@ -57,9 +75,42 @@ class RedirectingFactoryBody extends ExpressionStatement {
|
||||
// [kernel_class_builder.dart](kernel_class_builder.dart).
|
||||
FunctionNode function = factory.function;
|
||||
ExpressionStatement statement = function.body;
|
||||
function.body =
|
||||
new RedirectingFactoryBody.internal(getValue(statement.expression))
|
||||
..parent = function;
|
||||
List<DartType> typeArguments;
|
||||
if (statement.expression is Let) {
|
||||
Let expression = statement.expression;
|
||||
typeArguments = decodeTypeArguments(expression.body);
|
||||
}
|
||||
function.body = new RedirectingFactoryBody.internal(
|
||||
getValue(statement.expression), typeArguments)
|
||||
..parent = function;
|
||||
}
|
||||
|
||||
static Expression encodeTypeArguments(List<DartType> typeArguments) {
|
||||
String varNamePrefix = "#typeArg";
|
||||
Expression result = new InvalidExpression(null);
|
||||
if (typeArguments == null) {
|
||||
return result;
|
||||
}
|
||||
for (int i = typeArguments.length - 1; i >= 0; i--) {
|
||||
result = new Let(
|
||||
new VariableDeclaration("$varNamePrefix$i",
|
||||
type: typeArguments[i], initializer: new NullLiteral()),
|
||||
result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static List<DartType> decodeTypeArguments(Expression encoded) {
|
||||
if (encoded is InvalidExpression) {
|
||||
return null;
|
||||
}
|
||||
List<DartType> result = <DartType>[];
|
||||
while (encoded is Let) {
|
||||
Let head = encoded;
|
||||
result.add(head.variable.type);
|
||||
encoded = head.body;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +120,20 @@ RedirectingFactoryBody getRedirectingFactoryBody(Member member) {
|
||||
: null;
|
||||
}
|
||||
|
||||
Member getRedirectionTarget(Procedure member) {
|
||||
class RedirectionTarget {
|
||||
final Member target;
|
||||
final List<DartType> typeArguments;
|
||||
|
||||
RedirectionTarget(this.target, this.typeArguments);
|
||||
}
|
||||
|
||||
RedirectionTarget getRedirectionTarget(Procedure member, {bool strongMode}) {
|
||||
List<DartType> typeArguments = <DartType>[]..length =
|
||||
member.function.typeParameters.length;
|
||||
for (int i = 0; i < typeArguments.length; i++) {
|
||||
typeArguments[i] = new TypeParameterType(member.function.typeParameters[i]);
|
||||
}
|
||||
|
||||
// We use the [tortoise and hare algorithm]
|
||||
// (https://en.wikipedia.org/wiki/Cycle_detection#Tortoise_and_hare) to
|
||||
// handle cycles.
|
||||
@@ -78,8 +142,34 @@ Member getRedirectionTarget(Procedure member) {
|
||||
Member hare = tortoiseBody?.target;
|
||||
RedirectingFactoryBody hareBody = getRedirectingFactoryBody(hare);
|
||||
while (tortoise != hare) {
|
||||
if (tortoiseBody?.isUnresolved ?? true) return tortoise;
|
||||
tortoise = tortoiseBody.target;
|
||||
if (tortoiseBody?.isUnresolved ?? true)
|
||||
return new RedirectionTarget(tortoise, typeArguments);
|
||||
Member nextTortoise = tortoiseBody.target;
|
||||
List<DartType> nextTypeArguments = tortoiseBody.typeArguments;
|
||||
if (strongMode && nextTypeArguments == null) {
|
||||
nextTypeArguments = <DartType>[];
|
||||
}
|
||||
|
||||
if (strongMode || nextTypeArguments != null) {
|
||||
Substitution sub = Substitution.fromPairs(
|
||||
tortoise.function.typeParameters, typeArguments);
|
||||
typeArguments = <DartType>[]..length = nextTypeArguments.length;
|
||||
for (int i = 0; i < typeArguments.length; i++) {
|
||||
typeArguments[i] = sub.substituteType(nextTypeArguments[i]);
|
||||
}
|
||||
} else {
|
||||
// In Dart 1, we need to throw away the extra type arguments and use
|
||||
// `dynamic` in place of the missing ones.
|
||||
int typeArgumentCount = typeArguments.length;
|
||||
int nextTypeArgumentCount =
|
||||
nextTortoise.enclosingClass.typeParameters.length;
|
||||
typeArguments.length = nextTypeArgumentCount;
|
||||
for (int i = typeArgumentCount; i < nextTypeArgumentCount; i++) {
|
||||
typeArguments[i] = const DynamicType();
|
||||
}
|
||||
}
|
||||
|
||||
tortoise = nextTortoise;
|
||||
tortoiseBody = getRedirectingFactoryBody(tortoise);
|
||||
hare = getRedirectingFactoryBody(hareBody?.target)?.target;
|
||||
hareBody = getRedirectingFactoryBody(hare);
|
||||
|
||||
@@ -130,6 +130,9 @@ rasta/unresolved: Crash
|
||||
rasta/unresolved_constructor: Crash
|
||||
rasta/unresolved_for_in: Crash
|
||||
rasta/unresolved_recovery: Crash
|
||||
redirection_chain_type_arguments: Crash
|
||||
redirection_chain_type_arguments_subst: Crash
|
||||
redirection_type_arguments: Crash
|
||||
regress/issue_29937: Crash
|
||||
regress/issue_29941: Crash
|
||||
regress/issue_29942: Crash
|
||||
|
||||
@@ -23,6 +23,8 @@ redirecting_factory_simple_test: Fail # Missing support for RedirectingFactoryCo
|
||||
redirecting_factory_typeargs_test: Fail # Missing support for RedirectingFactoryConstructor.
|
||||
redirecting_factory_typeparam_test: Fail # Missing support for RedirectingFactoryConstructor.
|
||||
redirecting_factory_typeparambounds_test: Fail # Missing support for RedirectingFactoryConstructor.
|
||||
redirection_chain_type_arguments: Fail # Issue 32130
|
||||
redirection_chain_type_arguments_subst: Fail # Issue 32130
|
||||
statements: Fail # Make async tranformer optional for golden file testing.
|
||||
type_variable_as_super: Fail
|
||||
uninitialized_fields: Fail # Fasta and dartk disagree on static initializers
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ abstract class C<T extends core::Object> extends core::Object {
|
||||
abstract get t() → self::C::T;
|
||||
abstract set t(self::C::T x) → void;
|
||||
static factory •<T extends core::Object>(self::C::•::T t) → self::C<self::C::•::T>
|
||||
let dynamic #redirecting_factory = self::CImpl::• in invalid-expression;
|
||||
let dynamic #redirecting_factory = self::CImpl::• in let self::C::•::T #typeArg0 = null in invalid-expression;
|
||||
}
|
||||
class CImpl<T extends core::Object> extends core::Object implements self::C<self::CImpl::T> {
|
||||
field self::CImpl::T t;
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ abstract class C<T extends core::Object> extends core::Object {
|
||||
abstract get t() → self::C::T;
|
||||
abstract set t(generic-covariant-impl generic-covariant-interface self::C::T x) → void;
|
||||
static factory •<T extends core::Object>(self::C::•::T t) → self::C<self::C::•::T>
|
||||
let dynamic #redirecting_factory = self::CImpl::• in invalid-expression;
|
||||
let dynamic #redirecting_factory = self::CImpl::• in let self::C::•::T #typeArg0 = null in invalid-expression;
|
||||
}
|
||||
class CImpl<T extends core::Object> extends core::Object implements self::C<self::CImpl::T> {
|
||||
generic-covariant-impl generic-covariant-interface field self::CImpl::T t;
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ abstract class C<T extends core::Object> extends core::Object {
|
||||
abstract get t() → self::C::T;
|
||||
abstract set t(self::C::T x) → void;
|
||||
static factory •<T extends core::Object>(self::C::•::T t) → self::C<self::C::•::T>
|
||||
let dynamic #redirecting_factory = self::CImpl::• in invalid-expression;
|
||||
let dynamic #redirecting_factory = self::CImpl::• in let self::C::•::T #typeArg0 = null in invalid-expression;
|
||||
}
|
||||
class CImpl<T extends core::Object> extends core::Object implements self::C<self::CImpl::T> {
|
||||
field self::CImpl::T t;
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ abstract class C<T extends core::Object> extends core::Object {
|
||||
abstract get t() → self::C::T;
|
||||
abstract set t(self::C::T x) → void;
|
||||
static factory •<T extends core::Object>(self::C::•::T t) → self::C<self::C::•::T>
|
||||
let dynamic #redirecting_factory = self::CImpl::• in invalid-expression;
|
||||
let dynamic #redirecting_factory = self::CImpl::• in let self::C::•::T #typeArg0 = null in invalid-expression;
|
||||
}
|
||||
class CImpl<T extends core::Object> extends core::Object implements self::C<self::CImpl::T> {
|
||||
field self::CImpl::T t;
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ abstract class C<T extends core::Object> extends core::Object {
|
||||
abstract get t() → self::C::T;
|
||||
abstract set t(generic-covariant-impl generic-covariant-interface self::C::T x) → void;
|
||||
static factory •<T extends core::Object>(self::C::•::T t) → self::C<self::C::•::T>
|
||||
let dynamic #redirecting_factory = self::CImpl::• in invalid-expression;
|
||||
let dynamic #redirecting_factory = self::CImpl::• in let self::C::•::T #typeArg0 = null in invalid-expression;
|
||||
}
|
||||
class CImpl<T extends core::Object> extends core::Object implements self::C<self::CImpl::T> {
|
||||
generic-covariant-impl generic-covariant-interface field self::CImpl::T t;
|
||||
|
||||
@@ -23,7 +23,7 @@ class C<T extends core::Object> extends core::Object { // from org-dartlang-test
|
||||
: super core::Object::•()
|
||||
;
|
||||
static factory b<T extends core::Object>() → self::C<self::C::b::T>
|
||||
let dynamic #redirecting_factory = lib::C::b in invalid-expression;
|
||||
let dynamic #redirecting_factory = lib::C::b in let self::C::b::T #typeArg0 = null in invalid-expression;
|
||||
}
|
||||
static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/qualified.dart:11:7: Error: The type 'lib.Missing' can't be used as supertype.\nclass Bad extends lib.Missing {\n ^"]/* from null */;
|
||||
static method main() → dynamic {
|
||||
|
||||
@@ -22,7 +22,7 @@ class C<T extends core::Object> extends core::Object { // from org-dartlang-test
|
||||
constructor a() → void
|
||||
;
|
||||
static factory b<T extends core::Object>() → self::C<self::C::b::T>
|
||||
let dynamic #redirecting_factory = lib::C::b in invalid-expression;
|
||||
let dynamic #redirecting_factory = lib::C::b in let self::C::b::T #typeArg0 = null in invalid-expression;
|
||||
}
|
||||
static method main() → dynamic
|
||||
;
|
||||
|
||||
@@ -23,7 +23,7 @@ class C<T extends core::Object> extends core::Object { // from org-dartlang-test
|
||||
: super core::Object::•()
|
||||
;
|
||||
static factory b<T extends core::Object>() → self::C<self::C::b::T>
|
||||
let dynamic #redirecting_factory = lib::C::b in invalid-expression;
|
||||
let dynamic #redirecting_factory = lib::C::b in let self::C::b::T #typeArg0 = null in invalid-expression;
|
||||
}
|
||||
static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/qualified.dart:12:3: Error: Type 'lib.Missing' not found.\n lib.Missing method() {}\n ^", "pkg/front_end/testcases/qualified.dart:11:7: Error: The type 'lib.Missing' can't be used as supertype.\nclass Bad extends lib.Missing {\n ^", "pkg/front_end/testcases/qualified.dart: Error: Couldn't find constructor 'WrongName'."]/* from null */;
|
||||
static method main() → dynamic {
|
||||
|
||||
@@ -19,9 +19,9 @@ class A<T extends core::Object> extends core::Object {
|
||||
constructor internal() → void
|
||||
;
|
||||
static factory a<T extends core::Object>() → self::A<self::A::a::T>
|
||||
let dynamic #redirecting_factory = self::B::a in invalid-expression;
|
||||
let dynamic #redirecting_factory = self::B::a in let self::A::a::T #typeArg0 = null in invalid-expression;
|
||||
static factory b<T extends core::Object>() → self::A<self::A::b::T>
|
||||
let dynamic #redirecting_factory = self::B::a in invalid-expression;
|
||||
let dynamic #redirecting_factory = self::B::a in let self::C1 #typeArg0 = null in invalid-expression;
|
||||
static factory c<T extends core::Object>() → self::A<self::A::c::T>
|
||||
let dynamic #redirecting_factory = "Missing" in invalid-expression;
|
||||
}
|
||||
@@ -30,9 +30,9 @@ class B<S extends core::Object> extends self::A<self::B::S> {
|
||||
constructor internal() → void
|
||||
;
|
||||
static factory a<S extends core::Object>() → self::B<self::B::a::S>
|
||||
let dynamic #redirecting_factory = self::C::• in invalid-expression;
|
||||
let dynamic #redirecting_factory = self::C::• in let self::B::a::S #typeArg0 = null in invalid-expression;
|
||||
static factory b<S extends core::Object>() → self::B<self::B::b::S>
|
||||
let dynamic #redirecting_factory = self::C::• in invalid-expression;
|
||||
let dynamic #redirecting_factory = self::C::• in let self::C2 #typeArg0 = null in invalid-expression;
|
||||
}
|
||||
class C<U extends core::Object> extends self::B<self::C::U> {
|
||||
constructor •() → void
|
||||
|
||||
@@ -6,12 +6,12 @@ abstract class FooBase<Tf extends core::Object> extends core::Object {
|
||||
static field dynamic _redirecting# = <dynamic>[self::FooBase::•];
|
||||
abstract get x() → core::int;
|
||||
static factory •<Tf extends core::Object>(core::int x) → self::FooBase<self::FooBase::•::Tf>
|
||||
let dynamic #redirecting_factory = self::Foo::• in invalid-expression;
|
||||
let dynamic #redirecting_factory = self::Foo::• in let self::FooBase::•::Tf #typeArg0 = null in invalid-expression;
|
||||
}
|
||||
abstract class Foo<T extends core::Object> extends core::Object implements self::FooBase<dynamic> {
|
||||
static field dynamic _redirecting# = <dynamic>[self::Foo::•];
|
||||
static factory •<T extends core::Object>(core::int x) → self::Foo<self::Foo::•::T>
|
||||
let dynamic #redirecting_factory = self::Bar::• in invalid-expression;
|
||||
let dynamic #redirecting_factory = self::Bar::• in let core::String #typeArg0 = null in let self::Foo::•::T #typeArg1 = null in invalid-expression;
|
||||
}
|
||||
class Bar<Sb extends core::Object, Tb extends core::Object> extends core::Object implements self::Foo<self::Bar::Tb> {
|
||||
field core::int x;
|
||||
@@ -27,12 +27,12 @@ class Builder<X extends core::Object> extends core::Object {
|
||||
class SimpleCase<A extends core::Object, B extends core::Object> extends core::Object {
|
||||
static field dynamic _redirecting# = <dynamic>[self::SimpleCase::•];
|
||||
static factory •<A extends core::Object, B extends core::Object>() → self::SimpleCase<self::SimpleCase::•::A, self::SimpleCase::•::B>
|
||||
let dynamic #redirecting_factory = self::SimpleCaseImpl::• in invalid-expression;
|
||||
let dynamic #redirecting_factory = self::SimpleCaseImpl::• in let self::SimpleCase::•::A #typeArg0 = null in let self::SimpleCase::•::B #typeArg1 = null in invalid-expression;
|
||||
}
|
||||
class SimpleCaseImpl<Ai extends core::Object, Bi extends core::Object> extends core::Object implements self::SimpleCase<self::SimpleCaseImpl::Ai, self::SimpleCaseImpl::Bi> {
|
||||
static field dynamic _redirecting# = <dynamic>[self::SimpleCaseImpl::•];
|
||||
static factory •<Ai extends core::Object, Bi extends core::Object>() → self::SimpleCaseImpl<self::SimpleCaseImpl::•::Ai, self::SimpleCaseImpl::•::Bi>
|
||||
let dynamic #redirecting_factory = self::SimpleCaseImpl2::• in invalid-expression;
|
||||
let dynamic #redirecting_factory = self::SimpleCaseImpl2::• in let self::SimpleCaseImpl::•::Ai #typeArg0 = null in let self::SimpleCaseImpl::•::Bi #typeArg1 = null in invalid-expression;
|
||||
}
|
||||
class SimpleCaseImpl2<Ai2 extends core::Object, Bi2 extends core::Object> extends core::Object implements self::SimpleCaseImpl<self::SimpleCaseImpl2::Ai2, self::SimpleCaseImpl2::Bi2> {
|
||||
synthetic constructor •() → void
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright (c) 2018, 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.md file.
|
||||
|
||||
// The test checks that type arguments of the target of redirection factory
|
||||
// constructors are preserved throughout the chain of redirections.
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
class A<T> {
|
||||
factory A() = B<T, num>;
|
||||
A.empty();
|
||||
}
|
||||
|
||||
class B<U, W> extends A<U> {
|
||||
factory B() = C<U, W, String>;
|
||||
B.empty() : super.empty();
|
||||
}
|
||||
|
||||
class C<V, S, R> extends B<V, S> {
|
||||
C() : super.empty();
|
||||
toString() => "${V},${S},${R}";
|
||||
}
|
||||
|
||||
main() {
|
||||
Expect.equals("${new A<int>()}", "int,num,String");
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
library;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
import "package:expect/expect.dart" as exp;
|
||||
|
||||
class A<T extends core::Object> extends core::Object {
|
||||
static field dynamic _redirecting# = <dynamic>[self::A::•];
|
||||
constructor empty() → void
|
||||
: super core::Object::•()
|
||||
;
|
||||
static factory •<T extends core::Object>() → self::A<self::A::•::T>
|
||||
let dynamic #redirecting_factory = self::B::• in let self::A::•::T #typeArg0 = null in let core::num #typeArg1 = null in invalid-expression;
|
||||
}
|
||||
class B<U extends core::Object, W extends core::Object> extends self::A<self::B::U> {
|
||||
static field dynamic _redirecting# = <dynamic>[self::B::•];
|
||||
constructor empty() → void
|
||||
: super self::A::empty()
|
||||
;
|
||||
static factory •<U extends core::Object, W extends core::Object>() → self::B<self::B::•::U, self::B::•::W>
|
||||
let dynamic #redirecting_factory = self::C::• in let self::B::•::U #typeArg0 = null in let self::B::•::W #typeArg1 = null in let core::String #typeArg2 = null in invalid-expression;
|
||||
}
|
||||
class C<V extends core::Object, S extends core::Object, R extends core::Object> extends self::B<self::C::V, self::C::S> {
|
||||
constructor •() → void
|
||||
: super self::B::empty()
|
||||
;
|
||||
method toString() → dynamic
|
||||
return "${self::C::V},${self::C::S},${self::C::R}";
|
||||
}
|
||||
static method main() → dynamic {
|
||||
exp::Expect::equals("${new self::C::•<core::int, core::num, core::String>()}", "int,num,String");
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
library;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
class A<T extends core::Object> extends core::Object {
|
||||
static field dynamic _redirecting# = <dynamic>[self::A::•];
|
||||
constructor empty() → void
|
||||
;
|
||||
static factory •<T extends core::Object>() → self::A<self::A::•::T>
|
||||
let dynamic #redirecting_factory = self::B::• in let self::A::•::T #typeArg0 = null in let core::num #typeArg1 = null in invalid-expression;
|
||||
}
|
||||
class B<U extends core::Object, W extends core::Object> extends self::A<self::B::U> {
|
||||
static field dynamic _redirecting# = <dynamic>[self::B::•];
|
||||
constructor empty() → void
|
||||
;
|
||||
static factory •<U extends core::Object, W extends core::Object>() → self::B<self::B::•::U, self::B::•::W>
|
||||
let dynamic #redirecting_factory = self::C::• in let self::B::•::U #typeArg0 = null in let self::B::•::W #typeArg1 = null in let core::String #typeArg2 = null in invalid-expression;
|
||||
}
|
||||
class C<V extends core::Object, S extends core::Object, R extends core::Object> extends self::B<self::C::V, self::C::S> {
|
||||
constructor •() → void
|
||||
;
|
||||
method toString() → dynamic
|
||||
;
|
||||
}
|
||||
static method main() → dynamic
|
||||
;
|
||||
@@ -0,0 +1,31 @@
|
||||
library;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
import "package:expect/expect.dart" as exp;
|
||||
|
||||
class A<T extends core::Object> extends core::Object {
|
||||
static field dynamic _redirecting# = <dynamic>[self::A::•];
|
||||
constructor empty() → void
|
||||
: super core::Object::•()
|
||||
;
|
||||
static factory •<T extends core::Object>() → self::A<self::A::•::T>
|
||||
let dynamic #redirecting_factory = self::B::• in let self::A::•::T #typeArg0 = null in let core::num #typeArg1 = null in invalid-expression;
|
||||
}
|
||||
class B<U extends core::Object, W extends core::Object> extends self::A<self::B::U> {
|
||||
static field dynamic _redirecting# = <dynamic>[self::B::•];
|
||||
constructor empty() → void
|
||||
: super self::A::empty()
|
||||
;
|
||||
static factory •<U extends core::Object, W extends core::Object>() → self::B<self::B::•::U, self::B::•::W>
|
||||
let dynamic #redirecting_factory = self::C::• in let self::B::•::U #typeArg0 = null in let self::B::•::W #typeArg1 = null in let core::String #typeArg2 = null in invalid-expression;
|
||||
}
|
||||
class C<V extends core::Object, S extends core::Object, R extends core::Object> extends self::B<self::C::V, self::C::S> {
|
||||
constructor •() → void
|
||||
: super self::B::empty()
|
||||
;
|
||||
method toString() → core::String
|
||||
return "${self::C::V},${self::C::S},${self::C::R}";
|
||||
}
|
||||
static method main() → dynamic {
|
||||
exp::Expect::equals("${new self::C::•<core::int, core::num, core::String>()}", "int,num,String");
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) 2018, 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.md file.
|
||||
|
||||
// The test checks that dependencies of type arguments of targets of redirecting
|
||||
// factories on type parameters of the corresponding classes are respected in
|
||||
// the resulting type arguments of redirecting factories invocations.
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
abstract class A<T> {
|
||||
factory A() = B<T, List<T>>;
|
||||
A.empty();
|
||||
}
|
||||
|
||||
abstract class B<U, W> extends A<U> {
|
||||
factory B() = C<U, W, Map<U, W>>;
|
||||
B.empty() : super.empty();
|
||||
}
|
||||
|
||||
class C<V, S, R> extends B<V, S> {
|
||||
C() : super.empty();
|
||||
toString() => "${V},${S},${R}";
|
||||
}
|
||||
|
||||
main() {
|
||||
Expect.equals("${new A<int>()}", "int,List<int>,Map<int, List<int>>");
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
library;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
import "package:expect/expect.dart" as exp;
|
||||
|
||||
abstract class A<T extends core::Object> extends core::Object {
|
||||
static field dynamic _redirecting# = <dynamic>[self::A::•];
|
||||
constructor empty() → void
|
||||
: super core::Object::•()
|
||||
;
|
||||
static factory •<T extends core::Object>() → self::A<self::A::•::T>
|
||||
let dynamic #redirecting_factory = self::B::• in let self::A::•::T #typeArg0 = null in let core::List<self::A::•::T> #typeArg1 = null in invalid-expression;
|
||||
}
|
||||
abstract class B<U extends core::Object, W extends core::Object> extends self::A<self::B::U> {
|
||||
static field dynamic _redirecting# = <dynamic>[self::B::•];
|
||||
constructor empty() → void
|
||||
: super self::A::empty()
|
||||
;
|
||||
static factory •<U extends core::Object, W extends core::Object>() → self::B<self::B::•::U, self::B::•::W>
|
||||
let dynamic #redirecting_factory = self::C::• in let self::B::•::U #typeArg0 = null in let self::B::•::W #typeArg1 = null in let core::Map<self::B::•::U, self::B::•::W> #typeArg2 = null in invalid-expression;
|
||||
}
|
||||
class C<V extends core::Object, S extends core::Object, R extends core::Object> extends self::B<self::C::V, self::C::S> {
|
||||
constructor •() → void
|
||||
: super self::B::empty()
|
||||
;
|
||||
method toString() → dynamic
|
||||
return "${self::C::V},${self::C::S},${self::C::R}";
|
||||
}
|
||||
static method main() → dynamic {
|
||||
exp::Expect::equals("${new self::C::•<core::int, core::List<core::int>, core::Map<core::int, core::List<core::int>>>()}", "int,List<int>,Map<int, List<int>>");
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
library;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
abstract class A<T extends core::Object> extends core::Object {
|
||||
static field dynamic _redirecting# = <dynamic>[self::A::•];
|
||||
constructor empty() → void
|
||||
;
|
||||
static factory •<T extends core::Object>() → self::A<self::A::•::T>
|
||||
let dynamic #redirecting_factory = self::B::• in let self::A::•::T #typeArg0 = null in let core::List<self::A::•::T> #typeArg1 = null in invalid-expression;
|
||||
}
|
||||
abstract class B<U extends core::Object, W extends core::Object> extends self::A<self::B::U> {
|
||||
static field dynamic _redirecting# = <dynamic>[self::B::•];
|
||||
constructor empty() → void
|
||||
;
|
||||
static factory •<U extends core::Object, W extends core::Object>() → self::B<self::B::•::U, self::B::•::W>
|
||||
let dynamic #redirecting_factory = self::C::• in let self::B::•::U #typeArg0 = null in let self::B::•::W #typeArg1 = null in let core::Map<self::B::•::U, self::B::•::W> #typeArg2 = null in invalid-expression;
|
||||
}
|
||||
class C<V extends core::Object, S extends core::Object, R extends core::Object> extends self::B<self::C::V, self::C::S> {
|
||||
constructor •() → void
|
||||
;
|
||||
method toString() → dynamic
|
||||
;
|
||||
}
|
||||
static method main() → dynamic
|
||||
;
|
||||
@@ -0,0 +1,31 @@
|
||||
library;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
import "package:expect/expect.dart" as exp;
|
||||
|
||||
abstract class A<T extends core::Object> extends core::Object {
|
||||
static field dynamic _redirecting# = <dynamic>[self::A::•];
|
||||
constructor empty() → void
|
||||
: super core::Object::•()
|
||||
;
|
||||
static factory •<T extends core::Object>() → self::A<self::A::•::T>
|
||||
let dynamic #redirecting_factory = self::B::• in let self::A::•::T #typeArg0 = null in let core::List<self::A::•::T> #typeArg1 = null in invalid-expression;
|
||||
}
|
||||
abstract class B<U extends core::Object, W extends core::Object> extends self::A<self::B::U> {
|
||||
static field dynamic _redirecting# = <dynamic>[self::B::•];
|
||||
constructor empty() → void
|
||||
: super self::A::empty()
|
||||
;
|
||||
static factory •<U extends core::Object, W extends core::Object>() → self::B<self::B::•::U, self::B::•::W>
|
||||
let dynamic #redirecting_factory = self::C::• in let self::B::•::U #typeArg0 = null in let self::B::•::W #typeArg1 = null in let core::Map<self::B::•::U, self::B::•::W> #typeArg2 = null in invalid-expression;
|
||||
}
|
||||
class C<V extends core::Object, S extends core::Object, R extends core::Object> extends self::B<self::C::V, self::C::S> {
|
||||
constructor •() → void
|
||||
: super self::B::empty()
|
||||
;
|
||||
method toString() → core::String
|
||||
return "${self::C::V},${self::C::S},${self::C::R}";
|
||||
}
|
||||
static method main() → dynamic {
|
||||
exp::Expect::equals("${new self::C::•<core::int, core::List<core::int>, core::Map<core::int, core::List<core::int>>>()}", "int,List<int>,Map<int, List<int>>");
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright (c) 2018, 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.md file.
|
||||
|
||||
// The test checks that type arguments of the target of redirection factory
|
||||
// constructors are preserved.
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
class A {
|
||||
const factory A() = B<String>;
|
||||
const A.empty();
|
||||
}
|
||||
|
||||
class B<T> extends A {
|
||||
const B() : super.empty();
|
||||
|
||||
toString() => '${T}';
|
||||
}
|
||||
|
||||
void main() {
|
||||
Expect.equals("${const A()}", "String");
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
library;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
import "package:expect/expect.dart" as exp;
|
||||
|
||||
class A extends core::Object {
|
||||
static field dynamic _redirecting# = <dynamic>[self::A::•];
|
||||
const constructor empty() → void
|
||||
: super core::Object::•()
|
||||
;
|
||||
static factory •() → self::A
|
||||
let dynamic #redirecting_factory = self::B::• in let core::String #typeArg0 = null in invalid-expression;
|
||||
}
|
||||
class B<T extends core::Object> extends self::A {
|
||||
const constructor •() → void
|
||||
: super self::A::empty()
|
||||
;
|
||||
method toString() → dynamic
|
||||
return "${self::B::T}";
|
||||
}
|
||||
static method main() → void {
|
||||
exp::Expect::equals("${const self::B::•<core::String>()}", "String");
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
library;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
class A extends core::Object {
|
||||
static field dynamic _redirecting# = <dynamic>[self::A::•];
|
||||
const constructor empty() → void
|
||||
;
|
||||
static factory •() → self::A
|
||||
let dynamic #redirecting_factory = self::B::• in let core::String #typeArg0 = null in invalid-expression;
|
||||
}
|
||||
class B<T extends core::Object> extends self::A {
|
||||
const constructor •() → void
|
||||
;
|
||||
method toString() → dynamic
|
||||
;
|
||||
}
|
||||
static method main() → void
|
||||
;
|
||||
@@ -0,0 +1,23 @@
|
||||
library;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
import "package:expect/expect.dart" as exp;
|
||||
|
||||
class A extends core::Object {
|
||||
static field dynamic _redirecting# = <dynamic>[self::A::•];
|
||||
const constructor empty() → void
|
||||
: super core::Object::•()
|
||||
;
|
||||
static factory •() → self::A
|
||||
let dynamic #redirecting_factory = self::B::• in let core::String #typeArg0 = null in invalid-expression;
|
||||
}
|
||||
class B<T extends core::Object> extends self::A {
|
||||
const constructor •() → void
|
||||
: super self::A::empty()
|
||||
;
|
||||
method toString() → core::String
|
||||
return "${self::B::T}";
|
||||
}
|
||||
static method main() → void {
|
||||
exp::Expect::equals("${const self::B::•<core::String>()}", "String");
|
||||
}
|
||||
@@ -56,6 +56,8 @@ redirecting_factory_simple_test: Fail # Missing support for RedirectingFactoryCo
|
||||
redirecting_factory_typeargs_test: Fail # Missing support for RedirectingFactoryConstructor.
|
||||
redirecting_factory_typeparam_test: Fail # Missing support for RedirectingFactoryConstructor.
|
||||
redirecting_factory_typeparambounds_test: Fail # Missing support for RedirectingFactoryConstructor.
|
||||
redirection_chain_type_arguments: Fail # Issue 32130
|
||||
redirection_chain_type_arguments_subst: Fail # Issue 32130
|
||||
statements: Fail
|
||||
stringliteral: Fail
|
||||
super_rasta_copy: TypeCheckError
|
||||
|
||||
@@ -352,9 +352,7 @@ const_optional_args_test/01: MissingCompileTimeError
|
||||
const_switch2_test/01: MissingCompileTimeError
|
||||
const_syntax_test/05: MissingCompileTimeError
|
||||
const_types_test/34: MissingCompileTimeError
|
||||
const_types_test/35: MissingCompileTimeError
|
||||
const_types_test/39: MissingCompileTimeError
|
||||
const_types_test/40: MissingCompileTimeError
|
||||
constants_test/05: MissingCompileTimeError
|
||||
constructor_redirect1_negative_test/01: MissingCompileTimeError
|
||||
constructor_redirect2_negative_test: MissingCompileTimeError
|
||||
@@ -753,7 +751,6 @@ library_env_test/has_mirror_support: RuntimeError # Unsupported operation: bool.
|
||||
library_env_test/has_no_html_support: RuntimeError # Unsupported operation: bool.fromEnvironment can only be used as a const constructor
|
||||
mock_writable_final_field_test: RuntimeError # Expect.listEquals(list length, expected: <1>, actual: <0>) fails: Next element <123>
|
||||
mock_writable_final_private_field_test: RuntimeError
|
||||
redirecting_factory_long_test: RuntimeError # Expect.isTrue(false) fails.
|
||||
redirecting_factory_reflection_test: RuntimeError # UnimplementedError: node <InvalidExpression> `invalid-expression`
|
||||
regress_24283_test: RuntimeError # Expect.equals(expected: <-1>, actual: <4294967295>) fails.
|
||||
regress_30339_test: RuntimeError # Uncaught Expect.isTrue(false) fails.
|
||||
|
||||
@@ -82,9 +82,6 @@ closure_invoked_through_interface_target_field_test: MissingCompileTimeError
|
||||
closure_invoked_through_interface_target_getter_test: MissingCompileTimeError
|
||||
compile_time_constant_o_test/01: MissingCompileTimeError
|
||||
compile_time_constant_o_test/02: MissingCompileTimeError
|
||||
const_constructor2_test/20: MissingCompileTimeError
|
||||
const_constructor2_test/22: MissingCompileTimeError
|
||||
const_constructor2_test/24: MissingCompileTimeError
|
||||
const_dynamic_type_literal_test/02: MissingCompileTimeError
|
||||
const_factory_with_body_test/01: MissingCompileTimeError # Fasta bug: Const factory with body.
|
||||
const_instance_field_test/01: MissingCompileTimeError # Fasta bug: Const instance field.
|
||||
@@ -92,9 +89,7 @@ const_map2_test/00: MissingCompileTimeError # KernelVM bug: Constant evaluation.
|
||||
const_map3_test/00: MissingCompileTimeError # KernelVM bug: Constant evaluation.
|
||||
const_switch2_test/01: MissingCompileTimeError # KernelVM bug: Constant evaluation.
|
||||
const_types_test/34: MissingCompileTimeError
|
||||
const_types_test/35: MissingCompileTimeError
|
||||
const_types_test/39: MissingCompileTimeError
|
||||
const_types_test/40: MissingCompileTimeError
|
||||
constructor_redirect1_negative_test/01: MissingCompileTimeError
|
||||
constructor_redirect2_negative_test: MissingCompileTimeError
|
||||
constructor_redirect_test/01: MissingCompileTimeError # Fasta bug: Initializer refers to this.
|
||||
@@ -812,7 +807,6 @@ override_inheritance_method_test/29: CompileTimeError
|
||||
parser_quirks_test: CompileTimeError # Issue 31533
|
||||
redirecting_factory_default_values_test/03: MissingCompileTimeError
|
||||
redirecting_factory_infinite_steps_test/01: MissingCompileTimeError
|
||||
redirecting_factory_long_test: RuntimeError # Fasta bug: Bad compilation of type arguments for redirecting factory.
|
||||
redirecting_factory_malbounded_test/01: MissingCompileTimeError
|
||||
regress_22443_test: CompileTimeError # KernelVM bug: Deferred loading kernel issue 30273.
|
||||
regress_23089_test: Crash
|
||||
|
||||
Reference in New Issue
Block a user