Use semantic equality in Create From Usage
This commit is contained in:
+21
-9
@@ -55,10 +55,10 @@ import com.intellij.util.ArrayUtil
|
|||||||
import com.intellij.psi.PsiWhiteSpace
|
import com.intellij.psi.PsiWhiteSpace
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import org.jetbrains.jet.lexer.JetTokens
|
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.util.application.runWriteAction
|
||||||
import org.jetbrains.jet.plugin.refactoring.isMultiLine
|
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 TYPE_PARAMETER_LIST_VARIABLE_NAME = "typeParameterList"
|
||||||
private val TEMPLATE_FROM_USAGE_FUNCTION_BODY = "New Kotlin Function Body.kt"
|
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();
|
typeParameters = getTypeParameterNamesNotInScope(typeParametersInType, scope).copyToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun toString() = theType.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
class CallableBuilderConfiguration(
|
class CallableBuilderConfiguration(
|
||||||
@@ -130,22 +132,29 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
return typeCandidates.getOrPut(typeInfo) {
|
return typeCandidates.getOrPut(typeInfo) {
|
||||||
val types = typeInfo.getPossibleTypes(this).reverse()
|
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) {
|
for (substitution in substitutions) {
|
||||||
// each substitution can be applied or not, so we offer all options
|
// 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
|
// 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)
|
newTypes.removeAll(toRemove)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newTypes.empty) {
|
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 {
|
val substitutions = ownerTypeArguments.zip(classTypeParameters).map {
|
||||||
JetTypeSubstitution(it.first.getType(), it.second.getType())
|
JetTypeSubstitution(it.first.getType(), it.second.getType())
|
||||||
}.copyToArray()
|
}.copyToArray()
|
||||||
config.callableInfo.parameterInfos.forEach { parameter -> computeTypeCandidates(parameter.typeInfo, substitutions, scope) }
|
config.callableInfo.parameterInfos.forEach {
|
||||||
|
parameter ->
|
||||||
|
computeTypeCandidates(parameter.typeInfo, substitutions, scope)
|
||||||
|
}
|
||||||
if (!isUnit) {
|
if (!isUnit) {
|
||||||
computeTypeCandidates(config.callableInfo.returnTypeInfo, substitutions, scope)
|
computeTypeCandidates(config.callableInfo.returnTypeInfo, substitutions, scope)
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -25,7 +25,7 @@ import org.jetbrains.jet.lang.types.JetTypeImpl
|
|||||||
import org.jetbrains.jet.lang.psi.psiUtil.getAssignmentByLHS
|
import org.jetbrains.jet.lang.psi.psiUtil.getAssignmentByLHS
|
||||||
|
|
||||||
private fun JetType.contains(inner: JetType): Boolean {
|
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(
|
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 {
|
private fun JetType.substitute(substitution: JetTypeSubstitution, variance: Variance): JetType {
|
||||||
if (when (variance) {
|
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.IN_VARIANCE -> JetTypeChecker.DEFAULT.isSubtypeOf(this, substitution.forType)
|
||||||
Variance.OUT_VARIANCE -> JetTypeChecker.DEFAULT.isSubtypeOf(substitution.forType, this)
|
Variance.OUT_VARIANCE -> JetTypeChecker.DEFAULT.isSubtypeOf(substitution.forType, this)
|
||||||
}) {
|
}) {
|
||||||
|
|||||||
Reference in New Issue
Block a user