| Index: sdk/lib/_internal/compiler/implementation/resolution/members.dart
|
| diff --git a/sdk/lib/_internal/compiler/implementation/resolution/members.dart b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
|
| index 54fa2fdc75188fb613f131b380595c876b5240cf..823b75277fe34e7f47609300fe827fbb79c171c6 100644
|
| --- a/sdk/lib/_internal/compiler/implementation/resolution/members.dart
|
| +++ b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
|
| @@ -2668,19 +2668,34 @@ class ResolverVisitor extends MappingVisitor<Element> {
|
| compiler.backend.registerThrowNoSuchMethod(mapping);
|
| }
|
|
|
| - // TODO(ahe): Check that this doesn't lead to a cycle. For now,
|
| - // just make sure that the redirection target isn't itself a
|
| - // redirecting factory.
|
| - { // This entire block is temporary code per the above TODO.
|
| - FunctionElement targetImplementation = redirectionTarget.implementation;
|
| - FunctionExpression function = targetImplementation.parseNode(compiler);
|
| - if (function != null
|
| - && function.body != null
|
| - && function.body.asReturn() != null
|
| - && function.body.asReturn().isRedirectingFactoryBody) {
|
| - unimplemented(node.expression, 'redirecting to redirecting factory');
|
| + // Register a post process to check for cycles in the redirection chain and
|
| + // set the actual generative constructor at the end of the chain.
|
| + compiler.enqueuer.resolution.addPostProcessAction(constructor, () {
|
| + FunctionElementX current = constructor;
|
| + List<Element> seen = new List<Element>();
|
| + // Follow the chain of redirections and check for cycles.
|
| + while (current != current.defaultImplementation) {
|
| + if (current.internalRedirectionTarget != null) {
|
| + // We found a constructor that already has been processed.
|
| + current = current.internalRedirectionTarget;
|
| + break;
|
| + }
|
| + Element target = current.defaultImplementation;
|
| + if (seen.contains(target)) {
|
| + error(node, MessageKind.CYCLIC_REDIRECTING_FACTORY);
|
| + return;
|
| + }
|
| + seen.add(current);
|
| + current = target;
|
| }
|
| - }
|
| + // [current] is now the actual target of the redirections. Run through
|
| + // the constructors again and set their [redirectionTarget].
|
| + while (!seen.isEmpty) {
|
| + FunctionElementX factory = seen.removeLast();
|
| + factory.redirectionTarget = current;
|
| + }
|
| + });
|
| +
|
| world.registerStaticUse(redirectionTarget);
|
| world.registerInstantiatedClass(
|
| redirectionTarget.enclosingElement.declaration, mapping);
|
|
|