Rewrite script declarations in sections
commit5758715f28d3dfff94866f19823331a78ed9a37e
authorThomas Jiang <thomasjiang@fb.com>
Mon, 20 Nov 2017 19:51:02 +0000 (20 11:51 -0800)
committerHhvm Bot <hhvm-bot@users.noreply.github.com>
Tue, 21 Nov 2017 16:56:34 +0000 (21 08:56 -0800)
treea47a1e17195a8b578d1b1830ac30410de99cf988
parent69460f9646039c7c4b1c78bb4633e4597d6b7a4f
Rewrite script declarations in sections

Summary:
Currently, coroutines in a script are lowered at once and all the closure classes generated from rewriting all the coroutines in a script are gathered together. Then the closures are sandwiched between all the types and nontypes in the script. This causes some problems with the way we lower scripts with namespaces and use statements, which rely on ordering to maintain correctness.
```
namespace PPL\testNS {
  class testNS_A {
    public function foo():int {
      return 1;
    }
  }
}

use PPL\testNS\testNS_A as testNS_A;

class A {
  public coroutine function test(testNS_A $a): void {
    print("Do nothing");
  }
}
```
will not work correctly. The lowered file becomes:
```
class A {
  public function test(
    InternalCoroutineContinuation<CoroutineUnit>
      $coroutineContinuation_generated,
    testNS_A $a,
  ): CoroutineResult<CoroutineUnit> {
    print ("Do nothing");
    return new ActualCoroutineResult(CoroutineUnit::create());
  }
}
namespace PPL\testNS {
  class testNS_A {
    public function foo(): int {
      return 1;
    }
  }
}

use PPL\testNS\testNS_A as testNS_A;
```

Note that the lowered class, A, is placed at the TOP of the lowered file before the alias declaration.

As there's no testNS_A in the global namespace, this code breaks.

HHVM returns this error:
```
Catchable fatal error: Argument 2 passed to A::test() must be an instance of testNS_A, PPL\testNS\testNS_A given
```
Instead, the diff will rewrite each declaration in a script and appends the closures generated from rewriting that single declaration either before or after that declaration. This maintains the ordering of declarations in a script and a namespaced body.

Additionally, since many classes referenced in the autogen are globally scoped, they need to be called as such in namespaced code. i.e. \ClosureBase or \exception or \suspendCoroutineResult. Thus, we prepend all such generated instances (regardless of whether they are in a named namespace or not) with a backslash.

Reviewed By: michaeltingley

Differential Revision: D6350392

fbshipit-source-id: 0ff29811b0cd9a23d747ed22b55b161e7d608e07
hphp/hack/src/parser/coroutine/coroutine_lowerer.ml
hphp/hack/src/parser/coroutine/coroutine_suspend_rewriter.ml
hphp/hack/src/parser/coroutine/coroutine_syntax.ml