Skip to content

Commit

Permalink
MixinExtras Expressions: Recreate `ClassInfo#getCommonSuperClassOrInt…
Browse files Browse the repository at this point in the history
…erface`.

It's quite scuffed and often returns `Object` even when there is a suitable common interface, but what's important is that this matches the runtime logic.
  • Loading branch information
LlamaLad7 committed Jul 2, 2024
1 parent d8a9f83 commit c88fd70
Showing 1 changed file with 38 additions and 6 deletions.
44 changes: 38 additions & 6 deletions src/main/kotlin/platform/mixin/expression/MEExpressionService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,13 @@ package com.demonwav.mcdev.platform.mixin.expression

import com.demonwav.mcdev.platform.mixin.util.toPsiType
import com.demonwav.mcdev.util.descriptor
import com.intellij.psi.GenericsUtil
import com.intellij.openapi.project.Project
import com.intellij.psi.JavaPsiFacade
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiClassType
import com.intellij.psi.PsiElementFactory
import com.intellij.psi.PsiManager
import com.intellij.psi.PsiType
import com.llamalad7.mixinextras.expression.impl.ExpressionService
import com.llamalad7.mixinextras.expression.impl.flow.FlowContext
import org.objectweb.asm.Type
Expand All @@ -34,11 +38,39 @@ object MEExpressionService : ExpressionService() {
ctx as MEFlowContext
val elementFactory = JavaPsiFacade.getElementFactory(ctx.project)
return Type.getType(
GenericsUtil.getLeastUpperBound(
type1.toPsiType(elementFactory),
type2.toPsiType(elementFactory),
PsiManager.getInstance(ctx.project)
)?.descriptor ?: error("Failed to merge types $type1 and $type2!")
getCommonSuperClass(
ctx.project,
type1.toPsiType(elementFactory) as PsiClassType,
type2.toPsiType(elementFactory) as PsiClassType
)?.descriptor ?: error("Could not intersect types $type1 and $type2!")
)
}

// Copied from ClassInfo
private fun getCommonSuperClass(
project: Project,
type1: PsiType,
type2: PsiType
): PsiClassType? {
val left = (type1 as? PsiClassType)?.resolve() ?: return null
val right = (type2 as? PsiClassType)?.resolve() ?: return null

fun objectType() = PsiType.getJavaLangObject(PsiManager.getInstance(project), left.resolveScope)
fun PsiClass.type() = PsiElementFactory.getInstance(project).createType(this)

if (left.isInheritor(right, true)) {
return right.type()
}
if (right.isInheritor(left, true)) {
return left.type()
}
if (left.isInterface || right.isInterface) {
return objectType()
}

return generateSequence(left) { it.superClass }
.firstOrNull { right.isInheritor(it, true) }
?.type()
?: objectType()
}
}

0 comments on commit c88fd70

Please sign in to comment.