From 318a4b182e92ed4b54cddd8806770db03c2a96d2 Mon Sep 17 00:00:00 2001 From: e5l Date: Wed, 10 Aug 2016 18:06:04 +0300 Subject: [PATCH] translator: fix complex nested name resolving --- .../kotlinnative/translator/BlockCodegen.kt | 59 ++++++++++++------- .../translator/FunctionCodegen.kt | 4 ++ .../kotlin/tests/kotlin/companion_object_1.kt | 1 - 3 files changed, 43 insertions(+), 21 deletions(-) diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/BlockCodegen.kt b/translator/src/main/kotlin/org/kotlinnative/translator/BlockCodegen.kt index 06c7defc39b..eae1db0949e 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/BlockCodegen.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/BlockCodegen.kt @@ -4,6 +4,7 @@ import com.intellij.psi.PsiElement import com.intellij.psi.PsiWhiteSpace import com.intellij.psi.impl.source.tree.LeafPsiElement import com.intellij.psi.tree.IElementType +import org.jetbrains.kotlin.cfg.pseudocode.getSubtypesPredicate import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* @@ -16,6 +17,7 @@ import org.jetbrains.kotlin.resolve.constants.TypedCompileTimeConstant import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver import org.kotlinnative.translator.llvm.* import org.kotlinnative.translator.llvm.types.* +import java.rmi.UnexpectedException import java.util.* @@ -176,7 +178,6 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va is KtDotQualifiedExpression -> evaluateExpression(receiverExpr, scopeDepth) as LLVMVariable is KtNameReferenceExpression -> { val referenceContext = state.bindingContext.get(BindingContext.REFERENCE_TARGET, receiverExpr) - variableManager[receiverName] when (referenceContext) { is PropertyDescriptorImpl -> { val receiverThis = variableManager["this"]!! @@ -198,8 +199,13 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va } } - val clazz = state.classes[receiverName] ?: return evaluateExtensionExpression(receiverExpr, selectorExpr as KtCallExpression, scopeDepth) + val location = receiverExpr.getType(state.bindingContext)?.getSubtypesPredicate()?.toString()?.split(".") + val classReference = LLVMReferenceType(location?.last() ?: receiverName, "class") + if (location != null) { + classReference.location.addAll(location.dropLast(1)) + } + val clazz = resolveClassOrObjectLocation(classReference) ?: return evaluateExtensionExpression(receiverExpr, selectorExpr as KtCallExpression, scopeDepth) return evaluateClassScopedDotExpression(clazz, selectorExpr, scopeDepth) } @@ -209,7 +215,7 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va val function = selector.firstChild.firstChild.text val names = parseArgList(selector, scopeDepth) val type = if (names.size > 0) "_${names.joinToString(separator = "_", transform = { it.type!!.mangle() })}" else "" - val extensionCodegen = state.extensionFunctions[standardType.toString()]!!["$function$type"]!! + val extensionCodegen = state.extensionFunctions[standardType.toString()]?.get("$function$type") ?: throw UnexpectedException("$standardType:$function$type") val receiverExpression = evaluateExpression(receiver, scopeDepth + 1)!! val typeThisArgument = when (standardType) { @@ -222,13 +228,13 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va return evaluateFunctionCallExpression(LLVMVariable(extensionCodegen.fullName, extensionCodegen.returnType!!.type, scope = LLVMVariableScope()), args) } - private fun evaluateClassScopedDotExpression(clazz: ClassCodegen, selector: KtExpression, scopeDepth: Int): LLVMSingleValue? = when (selector) { + private fun evaluateClassScopedDotExpression(clazz: StructCodegen, selector: KtExpression, scopeDepth: Int): LLVMSingleValue? = when (selector) { is KtCallExpression -> evaluateCallExpression(selector, scopeDepth, clazz) is KtReferenceExpression -> evaluateReferenceExpression(selector, scopeDepth, clazz) else -> throw UnsupportedOperationException() } - private fun evaluateNameReferenceExpression(expr: KtNameReferenceExpression, classScope: ClassCodegen? = null): LLVMSingleValue? { + private fun evaluateNameReferenceExpression(expr: KtNameReferenceExpression, classScope: StructCodegen? = null): LLVMSingleValue? { val fieldName = state.bindingContext.get(BindingContext.REFERENCE_TARGET, expr)!!.name.toString() val field = classScope!!.companionFieldsIndex[fieldName] val companionObject = classScope.companionFieldsSource[fieldName] @@ -241,7 +247,7 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va fun evaluateMemberMethodOrField(receiver: LLVMVariable, selectorName: String, scopeDepth: Int, call: PsiElement? = null): LLVMSingleValue? { val type = receiver.type as LLVMReferenceType - val clazz = resolveClassOrObjectLocation(type) + val clazz = resolveClassOrObjectLocation(type) ?: throw UnexpectedException(type.toString()) val field = clazz.fieldsIndex[selectorName] if (field != null) { @@ -255,7 +261,7 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va val types = if (names.size > 0) "_${names.joinToString(separator = "_", transform = { it.type!!.mangle() })}" else "" val methodName = "${if (typePath.length > 0) "$typePath." else ""}${clazz.structName}.${selectorName.substringBefore('(')}$types" - val method = clazz.methods[methodName]!! + val method = clazz.methods[methodName] ?: throw UnexpectedException(methodName) val returnType = clazz.methods[methodName]!!.returnType!!.type val loadedArgs = loadArgsIfRequired(names, method.args) @@ -265,19 +271,23 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va return evaluateFunctionCallExpression(LLVMVariable(methodName, returnType, scope = LLVMVariableScope()), callArgs) } - private fun resolveClassOrObjectLocation(type: LLVMReferenceType): StructCodegen { + private fun resolveClassOrObjectLocation(type: LLVMReferenceType): StructCodegen? { if (type.location.size == 0) { - return state.classes[type.type] ?: state.objects[type.type]!! + return state.classes[type.type] ?: state.objects[type.type] } - var codegen = state.classes[type.location[0]]!! + var codegen = state.classes[type.location[0]] var i = 1 while (i < type.location.size) { - codegen = codegen.nestedClasses[type.location[i]]!! + codegen = codegen?.nestedClasses?.get(type.location[i]) i++ } - return codegen.nestedClasses[type.type]!! + if (codegen?.companionObjectCodegen != null && type.type == codegen?.companionObjectCodegen?.structName) { + return codegen?.companionObjectCodegen!! + } + + return codegen?.nestedClasses?.get(type.type) } fun evaluateArrayAccessExpression(expr: KtArrayAccessExpression, scope: Int): LLVMSingleValue? { @@ -300,7 +310,7 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va val names = parseValueArguments(callMaker.valueArguments, scope) val methodName = "$targetClassName.$arrayActionType${if (names.size > 0) "_${names.joinToString(separator = "_", transform = { it.type!!.mangle() })}" else ""}" val type = receiver.type as LLVMReferenceType - val clazz = resolveClassOrObjectLocation(type) + val clazz = resolveClassOrObjectLocation(type) ?: throw UnexpectedException(type.toString()) val method = clazz.methods[methodName]!! val returnType = clazz.methods[methodName]!!.returnType!!.type @@ -325,10 +335,10 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va } } - private fun evaluateReferenceExpression(expr: KtReferenceExpression, scopeDepth: Int, classScope: ClassCodegen? = null): LLVMSingleValue? = when { + private fun evaluateReferenceExpression(expr: KtReferenceExpression, scopeDepth: Int, classScope: StructCodegen? = null): LLVMSingleValue? = when { expr is KtArrayAccessExpression -> evaluateArrayAccessExpression(expr, scopeDepth + 1) isEnumClassField(expr) -> resolveEnumClassField(expr) - (expr is KtNameReferenceExpression) && (classScope != null) -> evaluateNameReferenceExpression(expr, classScope) + (expr is KtNameReferenceExpression) && (classScope != null) -> evaluateNameReferenceExpression(expr, classScope.parentCodegen) resolveContainingClass(expr) != null -> evaluateMemberMethodOrField(variableManager["this"]!!, expr.firstChild.text, topLevel) else -> variableManager[expr.firstChild.text] } @@ -370,9 +380,9 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va } if (classScope != null) { - val classDescriptor = state.classes[classScope.structName] ?: state.objects[classScope.structName] ?: return null - val methodShortName = classScope.structName + "." + function - if (classDescriptor.companionMethods.containsKey(methodShortName)) { + val classDescriptor = classScope.parentCodegen + val methodShortName = classDescriptor?.structName + "." + function + if (classDescriptor != null && classDescriptor.companionMethods.containsKey(methodShortName)) { val descriptor = classDescriptor.companionMethods[methodShortName] ?: return null val parentDescriptor = descriptor.parentCodegen!! val receiver = variableManager[parentDescriptor.fullName]!! @@ -409,6 +419,15 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va private fun resolveContainingClass(expr: KtElement): StructCodegen? { val name = expr.getResolvedCallWithAssert(state.bindingContext).dispatchReceiver?.type?.toString() ?: return null + val location = expr.getResolvedCallWithAssert(state.bindingContext).dispatchReceiver!!.type.getSubtypesPredicate().toString().split(".").dropLast(1) + + if (location.size > 0) { + val type = LLVMReferenceType(name, prefix = "class") + type.location.addAll(location) + + return resolveClassOrObjectLocation(type) + } + return state.classes[name] ?: state.objects[name] } @@ -508,15 +527,15 @@ abstract class BlockCodegen(val state: TranslationState, val variableManager: Va if (operator == KtTokens.ELVIS) { return evaluateElvisOperator(expr, scopeDepth) } + val left = evaluateExpression(expr.firstChild, scopeDepth) if (expr.firstChild is KtArrayAccessExpression) { return null } else { - left ?: throw UnsupportedOperationException("Wrong binary exception") + left ?: throw UnsupportedOperationException("Wrong binary exception: ${expr.text}") } val right = evaluateExpression(expr.lastChild, scopeDepth) ?: throw UnsupportedOperationException("Wrong binary exception: ${expr.text}") - return executeBinaryExpression(operator, expr.operationReference, left, right) } diff --git a/translator/src/main/kotlin/org/kotlinnative/translator/FunctionCodegen.kt b/translator/src/main/kotlin/org/kotlinnative/translator/FunctionCodegen.kt index 52597d113b5..ac18751721a 100644 --- a/translator/src/main/kotlin/org/kotlinnative/translator/FunctionCodegen.kt +++ b/translator/src/main/kotlin/org/kotlinnative/translator/FunctionCodegen.kt @@ -1,5 +1,6 @@ package org.kotlinnative.translator +import org.jetbrains.kotlin.cfg.pseudocode.getSubtypesPredicate import org.jetbrains.kotlin.psi.KtNamedFunction import org.jetbrains.kotlin.psi.psiUtil.getNextSiblingIgnoringWhitespaceAndComments import org.jetbrains.kotlin.psi.psiUtil.isExtensionDeclaration @@ -34,6 +35,9 @@ class FunctionCodegen(state: TranslationState, }) returnType = LLVMInstanceOfStandardType("instance", descriptor.returnType!!) + if (returnType!!.type is LLVMReferenceType) { + (returnType!!.type as LLVMReferenceType).location.addAll(descriptor.returnType!!.getSubtypesPredicate().toString().split(".").dropLast(1)) + } external = isExternal() name = "${function.fqName}${if (args.size > 0 && !external) "_${args.joinToString(separator = "_", transform = { it.type.mangle() })}" else ""}" diff --git a/translator/src/test/kotlin/tests/kotlin/companion_object_1.kt b/translator/src/test/kotlin/tests/kotlin/companion_object_1.kt index b029625bc10..8e59c06d16a 100644 --- a/translator/src/test/kotlin/tests/kotlin/companion_object_1.kt +++ b/translator/src/test/kotlin/tests/kotlin/companion_object_1.kt @@ -8,7 +8,6 @@ class companion_object_1 { } } - fun companion_object_1_test(): Int { return companion_object_1.create() } \ No newline at end of file