JS: add boxing/unboxing to default accessors of non-simple properties

See KT-21421
This commit is contained in:
Alexey Andreev
2017-11-23 19:36:19 +03:00
parent be4e2f96c2
commit 7bee2ceac7
3 changed files with 46 additions and 3 deletions
@@ -833,6 +833,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
doTest(fileName);
}
@TestMetadata("defaultAccessors.kt")
public void testDefaultAccessors() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/coercion/defaultAccessors.kt");
doTest(fileName);
}
@TestMetadata("derivedFunctionReturningChar.kt")
public void testDerivedFunctionReturningChar() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/coercion/derivedFunctionReturningChar.kt");
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.descriptors.impl.LocalVariableAccessorDescriptor
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
import org.jetbrains.kotlin.js.backend.ast.*
import org.jetbrains.kotlin.js.backend.ast.metadata.synthetic
import org.jetbrains.kotlin.js.backend.ast.metadata.type
import org.jetbrains.kotlin.js.translate.callTranslator.CallTranslator
import org.jetbrains.kotlin.js.translate.context.Namer
import org.jetbrains.kotlin.js.translate.context.Namer.getReceiverParameterName
@@ -94,13 +95,14 @@ class DefaultPropertyTranslator(
assert(!descriptor.isExtension) { "Unexpected extension property $descriptor}" }
assert(descriptor is PropertyDescriptor) { "Property descriptor expected: $descriptor" }
val result = backingFieldReference(context(), descriptor as PropertyDescriptor)
var result: JsExpression = backingFieldReference(context(), descriptor as PropertyDescriptor)
if (getterDescriptor is PropertyAccessorDescriptor && getterDescriptor.correspondingProperty.isLateInit) {
val throwFunction = context().getReferenceToIntrinsic(Namer.THROW_UNINITIALIZED_PROPERTY_ACCESS_EXCEPTION)
function.body.statements += JsIf(JsBinaryOperation(JsBinaryOperator.EQ, result, JsNullLiteral()),
JsReturn(JsInvocation(throwFunction,
JsStringLiteral(getterDescriptor.correspondingProperty.name.asString()))))
}
result = TranslationUtils.coerce(context(), result, TranslationUtils.getReturnTypeForCoercion(getterDescriptor))
function.body.statements += JsReturn(result).apply { source = descriptor.source.getPsi() }
}
@@ -126,7 +128,8 @@ class DefaultPropertyTranslator(
assert(setterDescriptor.valueParameters.size == 1) { "Setter must have 1 parameter" }
val correspondingPropertyName = setterDescriptor.correspondingVariable.name.asString()
val valueParameter = function.addParameter(correspondingPropertyName).name
val withAliased = context().innerContextWithAliased(setterDescriptor.valueParameters[0], valueParameter.makeRef())
val parameter = setterDescriptor.valueParameters[0]
val withAliased = context().innerContextWithAliased(parameter, valueParameter.makeRef())
val delegatedCall = bindingContext()[BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, setterDescriptor]
if (delegatedCall != null) {
@@ -142,7 +145,12 @@ class DefaultPropertyTranslator(
else {
assert(!descriptor.isExtension) { "Unexpected extension property $descriptor}" }
assert(descriptor is PropertyDescriptor) { "Property descriptor expected: $descriptor" }
val assignment = assignmentToBackingField(withAliased, descriptor as PropertyDescriptor, valueParameter.makeRef())
var value: JsExpression = valueParameter.makeRef().apply {
type = TranslationUtils.getReturnTypeForCoercion(setterDescriptor.correspondingVariable)
}
value = TranslationUtils.coerce(
context(), value, TranslationUtils.getReturnTypeForCoercion(setterDescriptor.correspondingVariable, true))
val assignment = assignmentToBackingField(withAliased, descriptor as PropertyDescriptor, value)
function.addStatement(assignment.apply { source = descriptor.source.getPsi() }.makeStmt())
}
}
@@ -0,0 +1,29 @@
// EXPECTED_REACHABLE_NODES: 1140
interface I {
val a: Char
}
object X : I {
override var a = '#'
}
var result = ""
object Y : I {
override var a = '#'
get() {
result = jsTypeOf(field.asDynamic())
return field
}
}
fun box(): String {
val t = jsTypeOf(X.asDynamic().a)
if (t != "object") return "fail1: $t"
Y.a = '@'
Y.a
if (result != "number") return "fail2: $result"
return "OK"
}