JS: Inlined local declarations should be positioned after imports

This commit is contained in:
Anton Bannykh
2019-02-12 21:31:11 +03:00
parent 0bfd332580
commit 4e298ae5cb
4 changed files with 78 additions and 29 deletions
@@ -33,8 +33,6 @@ sealed class InliningScope {
protected open fun preprocess(statement: JsStatement) {}
abstract fun update()
private val publicFunctionCache = mutableMapOf<String, JsFunction>()
private val localFunctionCache = mutableMapOf<JsFunction, JsFunction>()
@@ -167,21 +165,6 @@ class ImportInfoFragmentInliningScope private constructor(
private val additionalDeclarations = mutableListOf<JsStatement>()
override fun update() {
// TODO fix the order?
fragment.declarationBlock.statements.addAll(0, additionalDeclarations)
// post-processing
// If run separately `private inline suspend fun`'s local declarations get inlined twice.
InlineSuspendFunctionSplitter(this).accept(allCode)
simplifyWrappedFunctions(allCode)
removeUnusedFunctionDefinitions(allCode, collectNamedFunctions(allCode))
removeUnusedImports(fragment, allCode)
renameLabels(allCode)
}
override fun hasImport(name: JsName, tag: String): JsName? {
return name.localAlias?.let { (name, tag) ->
if (tag != null) {
@@ -251,7 +234,21 @@ class ImportInfoFragmentInliningScope private constructor(
fun process(fragment: JsProgramFragment, fn: (ImportInfoFragmentInliningScope) -> Unit) {
val scope = ImportInfoFragmentInliningScope(fragment)
fn(scope)
scope.update()
scope.apply {
// TODO fix the order?
fragment.declarationBlock.statements.addAll(0, additionalDeclarations)
// post-processing
// If run separately `private inline suspend fun`'s local declarations get inlined twice.
InlineSuspendFunctionSplitter(this).accept(allCode)
simplifyWrappedFunctions(allCode)
removeUnusedFunctionDefinitions(allCode, collectNamedFunctions(allCode))
removeUnusedImports(fragment, allCode)
renameLabels(allCode)
}
}
}
}
@@ -260,13 +257,24 @@ class ImportIntoWrapperInliningScope private constructor(
private val wrapperBody: JsBlock,
override val fragment: JsProgramFragment
) : InliningScope() {
private val existingImports = mutableMapOf<String, JsName>().also { map ->
private val importList = mutableListOf<JsVars>()
private val otherLocalStatements = mutableListOf<JsStatement>()
private val existingImports = mutableMapOf<String, JsName>()
init {
for (s in wrapperBody.statements) {
if (s !is JsVars) continue
if (s is JsVars) {
val tag = getImportTag(s)
if (tag != null) {
importList.add(s)
existingImports[tag] = s.vars[0].name
continue
}
}
val tag = getImportTag(s) ?: continue
map[tag] = s.vars[0].name
otherLocalStatements.add(s)
}
}
@@ -280,18 +288,19 @@ class ImportIntoWrapperInliningScope private constructor(
override fun addImport(tag: String, vars: JsVars) {
existingImports[tag] = vars.vars[0].name
additionalStatements.add(vars)
}
override fun update() {
wrapperBody.statements.addAll(0, additionalStatements)
importList.add(vars)
}
companion object {
fun process(wrapperBody: JsBlock, fragment: JsProgramFragment, fn: (ImportIntoWrapperInliningScope) -> Unit) {
val scope = ImportIntoWrapperInliningScope(wrapperBody, fragment)
fn(scope)
scope.update()
wrapperBody.statements.apply {
clear()
addAll(scope.importList)
addAll(scope.additionalStatements)
addAll(scope.otherLocalStatements)
}
}
}
}
@@ -4005,6 +4005,11 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
runTest("js/js.translator/testData/box/inline/inlineSimpleAssignment.kt");
}
@TestMetadata("inlinedObjectLiteralIsCheck.kt")
public void testInlinedObjectLiteralIsCheck() throws Exception {
runTest("js/js.translator/testData/box/inline/inlinedObjectLiteralIsCheck.kt");
}
@TestMetadata("innerOuterThis.kt")
public void testInnerOuterThis() throws Exception {
runTest("js/js.translator/testData/box/inline/innerOuterThis.kt");
@@ -4005,6 +4005,11 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest {
runTest("js/js.translator/testData/box/inline/inlineSimpleAssignment.kt");
}
@TestMetadata("inlinedObjectLiteralIsCheck.kt")
public void testInlinedObjectLiteralIsCheck() throws Exception {
runTest("js/js.translator/testData/box/inline/inlinedObjectLiteralIsCheck.kt");
}
@TestMetadata("innerOuterThis.kt")
public void testInnerOuterThis() throws Exception {
runTest("js/js.translator/testData/box/inline/innerOuterThis.kt");
@@ -0,0 +1,30 @@
// EXPECTED_REACHABLE_NODES: 1282
// IGNORE_BACKEND: JS_IR
interface I {
fun ok(): String
}
inline fun ok(): I {
return object : I {
override fun ok() = "OK"
}
}
@JsName("convolutedOk")
inline fun convolutedOk(): I {
val fail = object : I {
override fun ok() = "fail"
}.ok()
println(fail)
return ok()
}
fun box(): String {
val ok = js("_").convolutedOk()
if (ok !is I) return "fail"
return ok.ok()
}