Fixed optimization in IterableTypesDetector which did not work from the beginning + make it work on FuzzyType

This commit is contained in:
Valentin Kipyatkov
2015-01-29 17:10:40 +03:00
parent b2275ae424
commit b03b96f202
4 changed files with 20 additions and 12 deletions
@@ -390,7 +390,7 @@ class SmartCompletion(
val scope = bindingContext.get(BindingContext.RESOLUTION_SCOPE, expressionWithType) val scope = bindingContext.get(BindingContext.RESOLUTION_SCOPE, expressionWithType)
val iterableDetector = IterableTypesDetector(project, moduleDescriptor, scope, loopVarType) val iterableDetector = IterableTypesDetector(project, moduleDescriptor, scope, loopVarType)
return buildResultByTypeFilter(expressionWithType, receiver, Tail.RPARENTH) { iterableDetector.isIterable(it.type) } return buildResultByTypeFilter(expressionWithType, receiver, Tail.RPARENTH) { iterableDetector.isIterable(it) }
} }
private fun buildForInOperatorArgument(expressionWithType: JetExpression, receiver: JetExpression?): Result? { private fun buildForInOperatorArgument(expressionWithType: JetExpression, receiver: JetExpression?): Result? {
@@ -18,10 +18,14 @@ package org.jetbrains.kotlin.idea.liveTemplates.macro;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor;
import org.jetbrains.kotlin.descriptors.VariableDescriptor; import org.jetbrains.kotlin.descriptors.VariableDescriptor;
import org.jetbrains.kotlin.idea.JetBundle; import org.jetbrains.kotlin.idea.JetBundle;
import org.jetbrains.kotlin.idea.util.FuzzyType;
import org.jetbrains.kotlin.idea.util.IterableTypesDetector; import org.jetbrains.kotlin.idea.util.IterableTypesDetector;
import java.util.Collections;
public class JetIterableVariableMacro extends BaseJetVariableMacro { public class JetIterableVariableMacro extends BaseJetVariableMacro {
@Override @Override
@@ -41,6 +45,6 @@ public class JetIterableVariableMacro extends BaseJetVariableMacro {
@NotNull IterableTypesDetector iterableTypesDetector @NotNull IterableTypesDetector iterableTypesDetector
) { ) {
//TODO: smart-casts //TODO: smart-casts
return iterableTypesDetector.isIterable(variableDescriptor.getType()); return iterableTypesDetector.isIterable(new FuzzyType(variableDescriptor.getType(), Collections.<TypeParameterDescriptor>emptyList()));
} }
} }
@@ -29,7 +29,6 @@ import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.resolve.scopes.JetScope import org.jetbrains.kotlin.resolve.scopes.JetScope
import java.util.HashMap import java.util.HashMap
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
public class IterableTypesDetector( public class IterableTypesDetector(
private val project: Project, private val project: Project,
@@ -39,7 +38,7 @@ public class IterableTypesDetector(
) { ) {
private val injector = InjectorForMacros(project, moduleDescriptor) private val injector = InjectorForMacros(project, moduleDescriptor)
private val cache = HashMap<JetType, Boolean>() private val cache = HashMap<FuzzyType, Boolean>()
private val iteratorName = Name.identifier("iterator") private val iteratorName = Name.identifier("iterator")
private val typesWithExtensionIterator: Collection<JetType> = scope.getFunctions(iteratorName) private val typesWithExtensionIterator: Collection<JetType> = scope.getFunctions(iteratorName)
@@ -47,23 +46,23 @@ public class IterableTypesDetector(
.filterNotNull() .filterNotNull()
.map { it.getType() } .map { it.getType() }
public fun isIterable(type: JetType): Boolean { public fun isIterable(type: FuzzyType): Boolean {
return cache.getOrPut(type, { isIterableNoCache(type) }) return cache.getOrPut(type, { isIterableNoCache(type) })
} }
private fun isIterableNoCache(type: JetType): Boolean { private fun isIterableNoCache(type: FuzzyType): Boolean {
// optimization // optimization
if (!canBeIterable(type)) return false if (!canBeIterable(type)) return false
val expression = JetPsiFactory(project).createExpression("fake") val expression = JetPsiFactory(project).createExpression("fake")
val expressionReceiver = ExpressionReceiver(expression, type) val expressionReceiver = ExpressionReceiver(expression, type.type)
val context = ExpressionTypingContext.newContext(injector.getExpressionTypingServices(), BindingTraceContext(), scope, DataFlowInfo.EMPTY, TypeUtils.NO_EXPECTED_TYPE) val context = ExpressionTypingContext.newContext(injector.getExpressionTypingServices(), BindingTraceContext(), scope, DataFlowInfo.EMPTY, TypeUtils.NO_EXPECTED_TYPE)
val elementType = injector.getExpressionTypingComponents().getForLoopConventionsChecker().checkIterableConvention(expressionReceiver, context) val elementType = injector.getExpressionTypingComponents().getForLoopConventionsChecker().checkIterableConvention(expressionReceiver, context)
if (elementType == null) return false if (elementType == null) return false
return loopVarType == null || elementType.isSubtypeOf(loopVarType) return loopVarType == null || FuzzyType(elementType, type.freeParameters).checkIsSubtypeOf(loopVarType) != null
} }
private fun canBeIterable(type: JetType): Boolean { private fun canBeIterable(type: FuzzyType): Boolean {
return type.getMemberScope().getFunctions(iteratorName).isEmpty() || typesWithExtensionIterator.any { type.isSubtypeOf(type) } return type.type.getMemberScope().getFunctions(iteratorName).isNotEmpty() || typesWithExtensionIterator.any { type.checkIsSubtypeOf(it) != null }
} }
} }
@@ -1,8 +1,13 @@
fun foo(p1: Collection<String>, p2: Collection<Int>, p3: Collection<String?>) { trait X
for (i: Any in <caret>) trait Y: X
trait Z
fun foo(p1: Collection<X>, p2: Collection<Y>, p3: Collection<Z>, p4: Collection<X?>) {
for (i: X in <caret>)
} }
// EXIST: p1 // EXIST: p1
// EXIST: p2 // EXIST: p2
// ABSENT: p3 // ABSENT: p3
// ABSENT: p4
// EXIST: { lookupString:"listOf", itemText: "listOf", tailText: "(vararg values: T) (kotlin)", typeText:"List<T>" } // EXIST: { lookupString:"listOf", itemText: "listOf", tailText: "(vararg values: T) (kotlin)", typeText:"List<T>" }