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:
Dmitry Stefantsov
2018-02-14 22:03:23 +00:00
committed by commit-bot@chromium.org
parent 50db95f69b
commit ec9c927b18
34 changed files with 686 additions and 69 deletions
@@ -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
+2
View File
@@ -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
@@ -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;
@@ -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;
@@ -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;
@@ -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;
@@ -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");
}
+2
View File
@@ -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