Skip to content

Commit

Permalink
Enable hotswapping for 2 transpilation passes.
Browse files Browse the repository at this point in the history
These passes should always have been enabled for hot swapping.
This fixes a bug that prevented async function transpilation from happening
during dynamic debug loading.

Also added definitions to the DEFAULT_EXTERNS used for testing and used them in
hotswap tests. These are needed for transpiling advanced features like async
functions.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=173687156
  • Loading branch information
brad4d authored and blickly committed Oct 27, 2017
1 parent 922346a commit 07abeac
Show file tree
Hide file tree
Showing 6 changed files with 247 additions and 87 deletions.
8 changes: 4 additions & 4 deletions src/com/google/javascript/jscomp/TranspilationPasses.java
Expand Up @@ -114,9 +114,9 @@ protected FeatureSet featureSet() {
};

private static final PassFactory rewriteAsyncFunctions =
new PassFactory("rewriteAsyncFunctions", true) {
new HotSwapPassFactory("rewriteAsyncFunctions") {
@Override
protected CompilerPass create(final AbstractCompiler compiler) {
protected HotSwapCompilerPass create(final AbstractCompiler compiler) {
return new RewriteAsyncFunctions(compiler);
}

Expand All @@ -127,9 +127,9 @@ protected FeatureSet featureSet() {
};

private static final PassFactory convertEs7ToEs6 =
new PassFactory("convertEs7ToEs6", true) {
new HotSwapPassFactory("convertEs7ToEs6") {
@Override
protected CompilerPass create(final AbstractCompiler compiler) {
protected HotSwapCompilerPass create(final AbstractCompiler compiler) {
return new Es7ToEs6Converter(compiler);
}

Expand Down
26 changes: 24 additions & 2 deletions test/com/google/javascript/jscomp/BaseReplaceScriptTestCase.java
Expand Up @@ -36,9 +36,31 @@ public abstract class BaseReplaceScriptTestCase extends TestCase {
"goog.require = function(x) {};",
"goog.provide = function(x) {};");

protected static final ImmutableList<SourceFile> EXTERNS =
/** Externs used by most test cases and containing only a single definition. */
protected static final ImmutableList<SourceFile> EXTVAR_EXTERNS =
ImmutableList.of(SourceFile.fromCode("externs", "var extVar = 3;"));

/**
* Default externs containing definitions needed for transpilation of async functions and other
* post-ES5 features.
*/
protected static final ImmutableList<SourceFile> DEFAULT_EXTERNS =
ImmutableList.of(SourceFile.fromCode("default_externs", CompilerTestCase.DEFAULT_EXTERNS));

/**
* Test methods may set this variable to control the externs passed to the compiler.
*
* <p>Most test cases don't need externs at all or only need the one `extVar` variable defined in
* the EXTVAR_EXTERNS used here.
*/
protected ImmutableList<SourceFile> testExterns = EXTVAR_EXTERNS;

@Override
protected void setUp() throws Exception {
super.setUp();
testExterns = EXTVAR_EXTERNS;
}

/**
* In addition to the passed parameter adds a few options necessary options for
* {@code replaceScript} and creates a {@code CompilerOptions}.
Expand Down Expand Up @@ -145,7 +167,7 @@ protected Compiler runFullCompile(
}
Compiler compiler = new Compiler();
Compiler.setLoggingLevel(Level.INFO);
Result result = compiler.compile(EXTERNS, inputs, options);
Result result = compiler.compile(testExterns, inputs, options);
if (expectedCompileErrors == 0) {
assertThat(compiler.getErrors()).isEmpty();
assertThat(result.success).isTrue();
Expand Down
103 changes: 103 additions & 0 deletions test/com/google/javascript/jscomp/CompilerTestCase.java
Expand Up @@ -420,6 +420,109 @@ public abstract class CompilerTestCase extends TestCase {
" * @override",
" */",
"Generator.prototype.next = function(opt_value) {};",
"/**",
" * @typedef {{then: ?}}",
" */",
"var Thenable;",
"/**",
" * @interface",
" * @template TYPE",
" */",
"function IThenable() {}",
"/**",
" * @param {?(function(TYPE):VALUE)=} opt_onFulfilled",
" * @param {?(function(*): *)=} opt_onRejected",
" * @return {RESULT}",
" * @template VALUE",
" * @template RESULT := type('IThenable',",
" * cond(isUnknown(VALUE), unknown(),",
" * mapunion(VALUE, (V) =>",
" * cond(isTemplatized(V) && sub(rawTypeOf(V), 'IThenable'),",
" * templateTypeOf(V, 0),",
" * cond(sub(V, 'Thenable'),",
" * unknown(),",
" * V)))))",
" * =:",
" */",
"IThenable.prototype.then = function(opt_onFulfilled, opt_onRejected) {};",
"/**",
" * @param {function(",
" * function((TYPE|IThenable<TYPE>|Thenable|null)=),",
" * function(*=))} resolver",
" * @constructor",
" * @implements {IThenable<TYPE>}",
" * @template TYPE",
" */",
"function Promise(resolver) {}",
"/**",
" * @param {VALUE=} opt_value",
" * @return {RESULT}",
" * @template VALUE",
" * @template RESULT := type('Promise',",
" * cond(isUnknown(VALUE), unknown(),",
" * mapunion(VALUE, (V) =>",
" * cond(isTemplatized(V) && sub(rawTypeOf(V), 'IThenable'),",
" * templateTypeOf(V, 0),",
" * cond(sub(V, 'Thenable'),",
" * unknown(),",
" * V)))))",
" * =:",
" */",
"Promise.resolve = function(opt_value) {};",
"/**",
" * @param {*=} opt_error",
" * @return {!Promise<?>}",
" */",
"Promise.reject = function(opt_error) {};",
"/**",
" * @param {!Iterable<VALUE>} iterable",
" * @return {!Promise<!Array<RESULT>>}",
" * @template VALUE",
" * @template RESULT := mapunion(VALUE, (V) =>",
" * cond(isUnknown(V),",
" * unknown(),",
" * cond(isTemplatized(V) && sub(rawTypeOf(V), 'IThenable'),",
" * templateTypeOf(V, 0),",
" * cond(sub(V, 'Thenable'), unknown(), V))))",
" * =:",
" */",
"Promise.all = function(iterable) {};",
"/**",
" * @param {!Iterable<VALUE>} iterable",
" * @return {!Promise<RESULT>}",
" * @template VALUE",
" * @template RESULT := mapunion(VALUE, (V) =>",
" * cond(isUnknown(V),",
" * unknown(),",
" * cond(isTemplatized(V) && sub(rawTypeOf(V), 'IThenable'),",
" * templateTypeOf(V, 0),",
" * cond(sub(V, 'Thenable'), unknown(), V))))",
" * =:",
" */",
"Promise.race = function(iterable) {};",
"/**",
" * @param {?(function(this:void, TYPE):VALUE)=} opt_onFulfilled",
" * @param {?(function(this:void, *): *)=} opt_onRejected",
" * @return {RESULT}",
" * @template VALUE",
" * @template RESULT := type('Promise',",
" * cond(isUnknown(VALUE), unknown(),",
" * mapunion(VALUE, (V) =>",
" * cond(isTemplatized(V) && sub(rawTypeOf(V), 'IThenable'),",
" * templateTypeOf(V, 0),",
" * cond(sub(V, 'Thenable'),",
" * unknown(),",
" * V)))))",
" * =:",
" * @override",
" */",
"Promise.prototype.then = function(opt_onFulfilled, opt_onRejected) {};",
"/**",
" * @param {function(*): RESULT} onRejected",
" * @return {!Promise<RESULT>}",
" * @template RESULT",
" */",
"Promise.prototype.catch = function(onRejected) {};",
ACTIVE_X_OBJECT_DEF);

/**
Expand Down
21 changes: 0 additions & 21 deletions test/com/google/javascript/jscomp/NewTypeInferenceTestBase.java
Expand Up @@ -135,27 +135,6 @@ boolean checkTranspiled() {
" * @return {!Array.<?>}",
" */",
"Array.prototype.concat = function(var_args) {};",
"/** @interface */",
"function IThenable () {}",
"IThenable.prototype.then = function(onFulfilled) {};",
"/**",
" * @template T",
" * @constructor",
" * @implements {IThenable}",
" */",
"function Promise(resolver) {};",
"/**",
" * @param {VALUE} value",
" * @return {!Promise<VALUE>}",
" * @template VALUE",
" */",
"Promise.resolve = function(value) {};",
"/**",
" * @template RESULT",
" * @param {function(): RESULT} onFulfilled",
" * @return {RESULT}",
" */",
"Promise.prototype.then = function(onFulfilled) {};",
"/**",
" * @constructor",
" * @param {*=} opt_message",
Expand Down
22 changes: 19 additions & 3 deletions test/com/google/javascript/jscomp/SimpleReplaceScriptTest.java
Expand Up @@ -58,7 +58,7 @@ public void testInferWithModules() {
List<SourceFile> inputs = ImmutableList.of(
SourceFile.fromCode("in", ""));

Result result = compiler.compile(EXTERNS, inputs, options);
Result result = compiler.compile(EXTVAR_EXTERNS, inputs, options);
assertTrue(result.success);

CompilerInput oldInput = compiler.getInput(new InputId("in"));
Expand All @@ -83,7 +83,7 @@ public void testreplaceScript() {
+ "temp(10);\n";
List<SourceFile> inputs = ImmutableList.of(
SourceFile.fromCode("in", source));
Result result = compiler.compile(EXTERNS, inputs, options);
Result result = compiler.compile(EXTVAR_EXTERNS, inputs, options);
assertTrue(result.success);

// Now try to re-infer with a modified version of source
Expand Down Expand Up @@ -257,7 +257,7 @@ public void testParseErrorDoesntCrashCompilation() {
List<SourceFile> inputs = ImmutableList.of(
SourceFile.fromCode("in", "bad!()"));
try {
compiler.compile(EXTERNS, inputs, options);
compiler.compile(EXTVAR_EXTERNS, inputs, options);
} catch (RuntimeException e) {
fail("replaceScript threw a RuntimeException on a parse error.");
}
Expand Down Expand Up @@ -995,6 +995,22 @@ public void testNoErrorOnGoogProvide() {
assertThat(result.warnings).isEmpty();
}

/** Check async functionality on replaceScript */
public void testAsyncReplaceScript() {
CompilerOptions options = getOptions();
options.setLanguageIn(CompilerOptions.LanguageMode.ECMASCRIPT_2017);
options.setLanguageOut(CompilerOptions.LanguageMode.ECMASCRIPT5_STRICT);
// async functions require iterables and Symbols from the default externs
testExterns = DEFAULT_EXTERNS;
String src0 = "async function foo() {}";
Result result =
this.runReplaceScript(options, ImmutableList.of(src0), 0, 0, src0, 0, false).getResult();
assertTrue(result.success);

assertThat(result.errors).isEmpty();
assertThat(result.warnings).isEmpty();
}

public void testAddSimpleScript() {
CompilerOptions options = getOptions();
options.setClosurePass(false);
Expand Down

0 comments on commit 07abeac

Please sign in to comment.