Chromium Code Reviews| 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..27f3364cf92dddf80ebfc1231b7c4a054bfec58c 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; |
| + } |
| + |
| + /// Iterterate redirections from [factoryMethod]. |
|
Johnni Winther
2017/08/30 12:18:46
Iterate
ahe
2017/08/30 15:07:22
Done.
|
| + 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; |
| } |