Use semantic equality in Create From Usage

This commit is contained in:
Andrey Breslav
2014-10-09 18:18:41 +04:00
parent 8eb57f5a75
commit 619df3a53e
2 changed files with 23 additions and 11 deletions
@@ -55,10 +55,10 @@ import com.intellij.util.ArrayUtil
import com.intellij.psi.PsiWhiteSpace
import com.intellij.psi.PsiElement
import org.jetbrains.jet.lexer.JetTokens
import org.jetbrains.jet.plugin.quickfix.createFromUsage.createFunction
import org.jetbrains.jet.plugin.util.application.runWriteAction
import org.jetbrains.jet.plugin.refactoring.isMultiLine
import org.jetbrains.jet.plugin.intentions.declarations.DeclarationUtils
import org.jetbrains.kotlin.util.printAndReturn
import org.jetbrains.jet.lang.types.checker.JetTypeChecker
private val TYPE_PARAMETER_LIST_VARIABLE_NAME = "typeParameterList"
private val TEMPLATE_FROM_USAGE_FUNCTION_BODY = "New Kotlin Function Body.kt"
@@ -89,6 +89,8 @@ class TypeCandidate(val theType: JetType, scope: JetScope? = null) {
typeParameters = getTypeParameterNamesNotInScope(typeParametersInType, scope).copyToArray();
}
}
override fun toString() = theType.toString()
}
class CallableBuilderConfiguration(
@@ -130,22 +132,29 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
return typeCandidates.getOrPut(typeInfo) {
val types = typeInfo.getPossibleTypes(this).reverse()
val newTypes = LinkedHashSet(types)
// We have to use semantic equality here
[data] class EqWrapper(val _type: JetType) {
override fun equals(other: Any?) = this === other
|| other is EqWrapper && JetTypeChecker.DEFAULT.equalTypes(_type, other._type)
override fun hashCode() = 0 // no good way to compute hashCode() that would agree with our equals()
}
val newTypes = LinkedHashSet(types.map { EqWrapper(it) })
for (substitution in substitutions) {
// each substitution can be applied or not, so we offer all options
val toAdd = newTypes.map { theType -> theType.substitute(substitution, typeInfo.variance) }
val toAdd = newTypes.map { it._type.substitute(substitution, typeInfo.variance) }
// substitution.byType are type arguments, but they cannot already occur in the type before substitution
val toRemove = newTypes.filter { theType -> substitution.byType in theType }
val toRemove = newTypes.filter { substitution.byType in it._type }
newTypes.addAll(toAdd)
newTypes.addAll(toAdd.map { EqWrapper(it) })
newTypes.removeAll(toRemove)
}
if (newTypes.empty) {
newTypes.add(KotlinBuiltIns.getInstance().getAnyType())
newTypes.add(EqWrapper(KotlinBuiltIns.getInstance().getAnyType()))
}
newTypes.map { TypeCandidate(it, scope) }.reverse()
newTypes.map { TypeCandidate(it._type, scope) }.reverse()
}
}
@@ -217,7 +226,10 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
val substitutions = ownerTypeArguments.zip(classTypeParameters).map {
JetTypeSubstitution(it.first.getType(), it.second.getType())
}.copyToArray()
config.callableInfo.parameterInfos.forEach { parameter -> computeTypeCandidates(parameter.typeInfo, substitutions, scope) }
config.callableInfo.parameterInfos.forEach {
parameter ->
computeTypeCandidates(parameter.typeInfo, substitutions, scope)
}
if (!isUnit) {
computeTypeCandidates(config.callableInfo.returnTypeInfo, substitutions, scope)
}
@@ -25,7 +25,7 @@ import org.jetbrains.jet.lang.types.JetTypeImpl
import org.jetbrains.jet.lang.psi.psiUtil.getAssignmentByLHS
private fun JetType.contains(inner: JetType): Boolean {
return this == inner || getArguments().any { inner in it.getType() }
return JetTypeChecker.DEFAULT.equalTypes(this, inner) || getArguments().any { inner in it.getType() }
}
private fun DeclarationDescriptor.render(
@@ -167,7 +167,7 @@ private class JetTypeSubstitution(public val forType: JetType, public val byType
private fun JetType.substitute(substitution: JetTypeSubstitution, variance: Variance): JetType {
if (when (variance) {
Variance.INVARIANT -> this == substitution.forType
Variance.INVARIANT -> JetTypeChecker.DEFAULT.equalTypes(this, substitution.forType)
Variance.IN_VARIANCE -> JetTypeChecker.DEFAULT.isSubtypeOf(this, substitution.forType)
Variance.OUT_VARIANCE -> JetTypeChecker.DEFAULT.isSubtypeOf(substitution.forType, this)
}) {