| Index: pkg/front_end/lib/src/fasta/kernel/redirecting_factory_body.dart
|
| diff --git a/pkg/front_end/lib/src/fasta/kernel/redirecting_factory_body.dart b/pkg/front_end/lib/src/fasta/kernel/redirecting_factory_body.dart
|
| index 1fa7dd80fbc534085ebc48ef3453523d81fadbc0..205db064e47f64e17aa2d61affb4f1eef3d8050c 100644
|
| --- a/pkg/front_end/lib/src/fasta/kernel/redirecting_factory_body.dart
|
| +++ b/pkg/front_end/lib/src/fasta/kernel/redirecting_factory_body.dart
|
| @@ -6,46 +6,74 @@ library fasta.redirecting_factory_body;
|
|
|
| import 'package:kernel/ast.dart'
|
| show
|
| + DartType,
|
| Expression,
|
| ExpressionStatement,
|
| FunctionNode,
|
| + InterfaceType,
|
| InvalidExpression,
|
| + InvalidType,
|
| Let,
|
| Member,
|
| 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)
|
| - : super(new Let(new VariableDeclaration(letName, initializer: value),
|
| + Member cachedRedirectionTarget;
|
| +
|
| + DartType cachedReturnType;
|
| +
|
| + RedirectingFactoryBody.internal(Expression value, DartType type)
|
| + : super(new Let(
|
| + new VariableDeclaration(letName, initializer: value, type: type),
|
| new InvalidExpression()));
|
|
|
| - RedirectingFactoryBody(Member target) : this.internal(new StaticGet(target));
|
| + RedirectingFactoryBody(Member intermediateTarget, InterfaceType type)
|
| + : this.internal(new StaticGet(intermediateTarget), type);
|
|
|
| RedirectingFactoryBody.unresolved(String name)
|
| - : this.internal(new StringLiteral(name));
|
| + : this.internal(new StringLiteral(name), new InvalidType());
|
|
|
| - Member get target {
|
| - var value = getValue(expression);
|
| + Member get intermediateTarget {
|
| + var value = getVariable(expression)?.initializer;
|
| return value is StaticGet ? value.target : null;
|
| }
|
|
|
| + DartType get intermediateReturnType => getVariable(expression)?.type;
|
| +
|
| String get unresolvedName {
|
| - var value = getValue(expression);
|
| + var value = getVariable(expression)?.initializer;
|
| return value is StringLiteral ? value.value : null;
|
| }
|
|
|
| bool get isUnresolved => unresolvedName != null;
|
|
|
| - static getValue(Expression expression) {
|
| + Member get target {
|
| + if (cachedReturnType == null) {
|
| + computeRedirectionTarget(this.parent.parent, this);
|
| + }
|
| + return cachedRedirectionTarget;
|
| + }
|
| +
|
| + DartType get returnType {
|
| + if (cachedReturnType == null) {
|
| + computeRedirectionTarget(this.parent.parent, this);
|
| + }
|
| + return cachedReturnType;
|
| + }
|
| +
|
| + static VariableDeclaration getVariable(Expression expression) {
|
| if (expression is Let) {
|
| VariableDeclaration variable = expression.variable;
|
| if (variable.name == letName) {
|
| - return variable.initializer;
|
| + return variable;
|
| }
|
| }
|
| return null;
|
| @@ -57,32 +85,73 @@ class RedirectingFactoryBody extends ExpressionStatement {
|
| // [kernel_class_builder.dart](kernel_class_builder.dart).
|
| FunctionNode function = factory.function;
|
| ExpressionStatement statement = function.body;
|
| + VariableDeclaration variable = getVariable(statement.expression);
|
| function.body =
|
| - new RedirectingFactoryBody.internal(getValue(statement.expression))
|
| + new RedirectingFactoryBody.internal(variable.initializer, variable.type)
|
| ..parent = function;
|
| }
|
| -}
|
|
|
| -RedirectingFactoryBody getRedirectingFactoryBody(Member member) {
|
| - return member is Procedure && member.function.body is RedirectingFactoryBody
|
| - ? member.function.body
|
| - : null;
|
| -}
|
| + static RedirectingFactoryBody getRedirectingFactoryBody(Member member) {
|
| + return member is Procedure && member.function.body is RedirectingFactoryBody
|
| + ? member.function.body
|
| + : null;
|
| + }
|
| +
|
| + /// Iterate redirections from [factoryMethod].
|
| + static void iterateRedirections(
|
| + Member factoryMethod,
|
| + bool f(Member member, RedirectingFactoryBody body),
|
| + void onCycle(Member member, RedirectingFactoryBody body)) {
|
| + // We use the [tortoise and hare algorithm]
|
| + // (https://en.wikipedia.org/wiki/Cycle_detection#Tortoise_and_hare) to
|
| + // handle cycles.
|
|
|
| -Member getRedirectionTarget(Procedure member) {
|
| - // We use the [tortoise and hare algorithm]
|
| - // (https://en.wikipedia.org/wiki/Cycle_detection#Tortoise_and_hare) to
|
| - // handle cycles.
|
| - Member tortoise = member;
|
| - RedirectingFactoryBody tortoiseBody = getRedirectingFactoryBody(tortoise);
|
| - Member hare = tortoiseBody?.target;
|
| - RedirectingFactoryBody hareBody = getRedirectingFactoryBody(hare);
|
| - while (tortoise != hare) {
|
| - if (tortoiseBody?.isUnresolved ?? true) return tortoise;
|
| - tortoise = tortoiseBody.target;
|
| - tortoiseBody = getRedirectingFactoryBody(tortoise);
|
| - hare = getRedirectingFactoryBody(hareBody?.target)?.target;
|
| - hareBody = getRedirectingFactoryBody(hare);
|
| + Member tortoise = factoryMethod;
|
| + RedirectingFactoryBody tortoiseBody = getRedirectingFactoryBody(tortoise);
|
| + Member hare = tortoiseBody?.intermediateTarget;
|
| + RedirectingFactoryBody hareBody = getRedirectingFactoryBody(hare);
|
| + while (tortoise != hare) {
|
| + if (tortoiseBody == null) return;
|
| + if (!f(tortoise, tortoiseBody)) return;
|
| + tortoise = tortoiseBody.intermediateTarget;
|
| + tortoiseBody = getRedirectingFactoryBody(tortoise);
|
| + hare = getRedirectingFactoryBody(hareBody?.intermediateTarget)
|
| + ?.intermediateTarget;
|
| + hareBody = getRedirectingFactoryBody(hare);
|
| + }
|
| + onCycle(tortoise, tortoiseBody);
|
| + }
|
| +
|
| + static void computeRedirectionTarget(
|
| + Member factoryMethod, RedirectingFactoryBody body) {
|
| + DartType returnType = new InterfaceType(
|
| + factoryMethod.enclosingClass,
|
| + factoryMethod.function.typeParameters
|
| + .map((t) => new TypeParameterType(t))
|
| + .toList());
|
| + Member target;
|
| + iterateRedirections(factoryMethod,
|
| + (Member member, RedirectingFactoryBody body) {
|
| + if (body.isUnresolved) {
|
| + target = member;
|
| + returnType = const InvalidType();
|
| + return false; // Stop iterating.
|
| + }
|
| + target = body.intermediateTarget;
|
| + if (returnType is InterfaceType) {
|
| + InterfaceType interfaceType = returnType;
|
| + returnType = Substitution
|
| + .fromPairs(
|
| + member.function.typeParameters, interfaceType.typeArguments)
|
| + .substituteType(body.intermediateReturnType);
|
| + }
|
| + return true; // Continue iterating.
|
| + }, (Member member, RedirectingFactoryBody body) {
|
| + returnType = const InvalidType();
|
| + target = null;
|
| + });
|
| + body
|
| + ..cachedRedirectionTarget = target
|
| + ..cachedReturnType = returnType;
|
| }
|
| - return null;
|
| }
|
|
|