Avoid exponential complexity in LexicalScope::findLocalVariable
There was an exponential complexity in case we have a chain of nested LexicalScopeWrapper instances: we were walking through the chain and on each step running the algorithm recursively. Such a case is possible in scripts where each line contains LexicalScopeWrapper The fix looks safe to me because delegate was used there for checking !is ImportingScope && !is LexicalChainedScope In all other means, being recursively run the algorithm does the same job. #KT-22740 Fixed
This commit is contained in:
@@ -64,14 +64,19 @@ fun HierarchicalScope.collectDescriptorsFiltered(
|
||||
|
||||
@Deprecated("Use getContributedProperties instead")
|
||||
fun LexicalScope.findLocalVariable(name: Name): VariableDescriptor? {
|
||||
return findFirstFromMeAndParent {
|
||||
when {
|
||||
it is LexicalScopeWrapper -> it.delegate.findLocalVariable(name)
|
||||
return findFirstFromMeAndParent { originalScope ->
|
||||
// Unpacking LexicalScopeWrapper may be important to check that it is not ImportingScope
|
||||
val possiblyUnpackedScope = when (originalScope) {
|
||||
is LexicalScopeWrapper -> originalScope.delegate
|
||||
else -> originalScope
|
||||
}
|
||||
|
||||
it !is ImportingScope && it !is LexicalChainedScope -> it.getContributedVariables(
|
||||
name,
|
||||
NoLookupLocation.WHEN_GET_LOCAL_VARIABLE
|
||||
).singleOrNull() /* todo check this*/
|
||||
when {
|
||||
possiblyUnpackedScope !is ImportingScope && possiblyUnpackedScope !is LexicalChainedScope ->
|
||||
possiblyUnpackedScope.getContributedVariables(
|
||||
name,
|
||||
NoLookupLocation.WHEN_GET_LOCAL_VARIABLE
|
||||
).singleOrNull() /* todo check this*/
|
||||
|
||||
else -> null
|
||||
}
|
||||
|
||||
@@ -157,6 +157,19 @@ class GenericReplTest : KtUsefulTestCase() {
|
||||
assertEquals(res.second.toString(), evals, (res.second as? ReplEvalResult.ValueResult)?.value)
|
||||
}
|
||||
}
|
||||
|
||||
fun testReplSlowdownKt22740() {
|
||||
TestRepl().use { repl ->
|
||||
val state = repl.createState()
|
||||
|
||||
repl.compileAndEval(state, ReplCodeLine(0, 0, "class Test<T>(val x: T) { fun <R> map(f: (T) -> R): R = f(x) }".trimIndent()))
|
||||
|
||||
// We expect that analysis time is not exponential
|
||||
for (i in 1..60) {
|
||||
repl.compileAndEval(state, ReplCodeLine(i, 0, "fun <T> Test<T>.map(f: (T) -> Double): List<Double> = listOf(f(this.x))"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user