"field": synthetic variable creation in accessors, codegen changed accordingly, a set of tests, relevant code fix (j2k)

This commit is contained in:
Mikhail Glukhikh
2015-09-16 11:12:33 +03:00
parent 6282a16013
commit 9f640b00d9
26 changed files with 315 additions and 8 deletions
@@ -47,6 +47,7 @@ import org.jetbrains.kotlin.codegen.when.SwitchCodegen;
import org.jetbrains.kotlin.codegen.when.SwitchCodegenUtil;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.impl.ScriptCodeDescriptor;
import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor;
import org.jetbrains.kotlin.diagnostics.DiagnosticUtils;
import org.jetbrains.kotlin.diagnostics.Errors;
import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
@@ -58,10 +59,7 @@ import org.jetbrains.kotlin.load.java.descriptors.SamConstructorDescriptor;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.renderer.DescriptorRenderer;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.BindingContextUtils;
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.*;
import org.jetbrains.kotlin.resolve.annotations.AnnotationsPackage;
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.CallResolverUtilPackage;
import org.jetbrains.kotlin.resolve.calls.model.*;
@@ -1981,6 +1979,10 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
assert descriptor != null : "Couldn't find descriptor for '" + expression.getText() + "'";
descriptor = descriptor.getOriginal();
boolean isSyntheticField = descriptor instanceof SyntheticFieldDescriptor;
if (isSyntheticField) {
descriptor = ((SyntheticFieldDescriptor) descriptor).getPropertyDescriptor();
}
if (descriptor instanceof CallableMemberDescriptor) {
CallableMemberDescriptor memberDescriptor = DescriptorUtils.unwrapFakeOverride((CallableMemberDescriptor) descriptor);
@@ -2009,7 +2011,8 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
}
boolean directToField =
expression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER && contextKind() != OwnerKind.TRAIT_IMPL;
(expression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER || isSyntheticField)
&& contextKind() != OwnerKind.TRAIT_IMPL;
JetSuperExpression superExpression =
resolvedCall == null ? null : CallResolverUtilPackage.getSuperCallExpression(resolvedCall.getCall());
propertyDescriptor = context.accessibleDescriptor(propertyDescriptor, superExpression);
@@ -0,0 +1,41 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.descriptors.impl
import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.JetProperty
import org.jetbrains.kotlin.resolve.source.toSourceElement
class SyntheticFieldDescriptor private constructor(
val propertyDescriptor: PropertyDescriptor,
accessorDescriptor: PropertyAccessorDescriptor,
property: JetProperty
): LocalVariableDescriptor(accessorDescriptor, Annotations.EMPTY, SyntheticFieldDescriptor.NAME,
propertyDescriptor.type, propertyDescriptor.isVar, property.toSourceElement()) {
constructor(accessorDescriptor: PropertyAccessorDescriptor,
property: JetProperty): this(accessorDescriptor.correspondingProperty, accessorDescriptor, property)
override fun getDispatchReceiverParameter() = propertyDescriptor.dispatchReceiverParameter
companion object {
val NAME = Name.identifier("field")
}
}
@@ -25,7 +25,11 @@ import kotlin.jvm.functions.Function1;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor;
import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor;
import org.jetbrains.kotlin.lexer.JetTokens;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.psi.psiUtil.PsiUtilPackage;
import org.jetbrains.kotlin.resolve.calls.CallResolver;
@@ -37,6 +41,7 @@ import org.jetbrains.kotlin.resolve.calls.util.CallMaker;
import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil;
import org.jetbrains.kotlin.resolve.scopes.*;
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
import org.jetbrains.kotlin.resolve.source.KotlinSourceElementKt;
import org.jetbrains.kotlin.types.*;
import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext;
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices;
@@ -649,6 +654,9 @@ public class BodyResolver {
trace.record(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor); // TODO: this trace?
}
}
if (descriptor instanceof SyntheticFieldDescriptor) {
trace.record(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor);
}
}
}
});
@@ -766,6 +774,16 @@ public class BodyResolver {
trace, innerScope, outerDataFlowInfo, NO_EXPECTED_TYPE, callChecker)
);
// Synthetic "field" creation
if (functionDescriptor instanceof PropertyAccessorDescriptor) {
assert innerScope instanceof WritableScopeStorage : "Expected innerScope as WritableScopeStorage but got " + innerScope;
PropertyAccessorDescriptor accessorDescriptor = (PropertyAccessorDescriptor) functionDescriptor;
JetProperty property = (JetProperty) function.getParent();
SyntheticFieldDescriptor fieldDescriptor = new SyntheticFieldDescriptor(accessorDescriptor, property);
WritableScopeStorage innerScopeStorage = (WritableScopeStorage) innerScope;
innerScopeStorage.addVariableOrClassDescriptor(fieldDescriptor);
}
DataFlowInfo dataFlowInfo = null;
if (beforeBlockBody != null) {
+10
View File
@@ -0,0 +1,10 @@
var my: String = ""
get() = field + "K"
set(arg) {
field = arg
}
fun box(): String {
my = "O"
return my
}
@@ -0,0 +1,6 @@
class My {
val my: String = "O"
get() = field + "K"
}
fun box() = My().my
@@ -0,0 +1,13 @@
abstract class Your {
abstract val your: String
fun foo() = your
}
val my: String = "O"
get() = field + object: Your() {
override val your = "K"
get() = field
}.foo()
fun box() = my
@@ -0,0 +1,12 @@
abstract class Your {
abstract val your: String
fun foo() = your
}
val my: String = "O"
get() = object: Your() {
override val your = field
}.foo() + "K"
fun box() = my
@@ -0,0 +1,4 @@
val x: String = "OK"
get() = field
fun box() = x
@@ -0,0 +1,9 @@
class My(val field: Int) {
// Backing field, initializer
val second: Int = 0
get() = field
// No backing field, no initializer
val third: Int
get() = this.field
}
@@ -0,0 +1,11 @@
package
public final class My {
public constructor My(/*0*/ field: kotlin.Int)
public final val field: kotlin.Int
public final val second: kotlin.Int = 0
public final val third: kotlin.Int
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,18 @@
open class Base {
open val x: Int = 1
get() = field - 1
}
class Other: Base() {
override val x = 2
}
class Another: Base() {
override val x = 3
get() = field + 1
}
class NoBackingField: Base() {
override val x: Int
get() = 5
}
@@ -0,0 +1,33 @@
package
public final class Another : Base {
public constructor Another()
public open override /*1*/ val x: kotlin.Int = 3
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public open class Base {
public constructor Base()
public open val x: kotlin.Int = 1
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class NoBackingField : Base {
public constructor NoBackingField()
public open override /*1*/ val x: kotlin.Int
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class Other : Base {
public constructor Other()
public open override /*1*/ val x: kotlin.Int = 2
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,4 @@
interface My {
<!BACKING_FIELD_IN_TRAIT!>val x: Int<!> = <!PROPERTY_INITIALIZER_IN_TRAIT!>0<!>
get() = field
}
@@ -0,0 +1,8 @@
package
public interface My {
public open val x: kotlin.Int = 0
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,11 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE
fun foo() {
open class Local {
val my: Int = 2
get() = field
}
val your = object: Local() {
val your: Int = 3
get() = field
}
}
@@ -0,0 +1,3 @@
package
public fun foo(): kotlin.Unit
@@ -0,0 +1,2 @@
val my: Int = 21
get() = field * 2
@@ -0,0 +1,3 @@
package
public val my: kotlin.Int = 21
@@ -0,0 +1,5 @@
var my: Int = 0
get() = -field
set(arg) {
field = arg
}
@@ -0,0 +1,3 @@
package
public var my: kotlin.Int
@@ -0,0 +1,8 @@
class My {
// No initialization needed because no backing field
val two: Int
get() {
val <!NAME_SHADOWING!>field<!> = 2
return field
}
}
@@ -0,0 +1,9 @@
package
public final class My {
public constructor My()
public final val two: kotlin.Int
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -1326,6 +1326,48 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
doTest(fileName);
}
@TestMetadata("FieldAsProperty.kt")
public void testFieldAsProperty() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/backingField/FieldAsProperty.kt");
doTest(fileName);
}
@TestMetadata("FieldDerived.kt")
public void testFieldDerived() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/backingField/FieldDerived.kt");
doTest(fileName);
}
@TestMetadata("FieldInInterface.kt")
public void testFieldInInterface() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/backingField/FieldInInterface.kt");
doTest(fileName);
}
@TestMetadata("FieldInLocal.kt")
public void testFieldInLocal() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/backingField/FieldInLocal.kt");
doTest(fileName);
}
@TestMetadata("FieldOnVal.kt")
public void testFieldOnVal() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/backingField/FieldOnVal.kt");
doTest(fileName);
}
@TestMetadata("FieldOnVar.kt")
public void testFieldOnVar() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/backingField/FieldOnVar.kt");
doTest(fileName);
}
@TestMetadata("FieldShadow.kt")
public void testFieldShadow() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/backingField/FieldShadow.kt");
doTest(fileName);
}
@TestMetadata("kt462BackingFieldsResolve.kt")
public void testKt462BackingFieldsResolve() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/backingField/kt462BackingFieldsResolve.kt");
@@ -6337,6 +6337,36 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName);
}
@TestMetadata("field.kt")
public void testField() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/properties/field.kt");
doTest(fileName);
}
@TestMetadata("fieldInClass.kt")
public void testFieldInClass() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/properties/fieldInClass.kt");
doTest(fileName);
}
@TestMetadata("fieldInsideField.kt")
public void testFieldInsideField() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/properties/fieldInsideField.kt");
doTest(fileName);
}
@TestMetadata("fieldInsideNested.kt")
public void testFieldInsideNested() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/properties/fieldInsideNested.kt");
doTest(fileName);
}
@TestMetadata("fieldSimple.kt")
public void testFieldSimple() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/properties/fieldSimple.kt");
doTest(fileName);
}
@TestMetadata("generalAccess.kt")
public void testGeneralAccess() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/properties/generalAccess.kt");
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.resolve.frontendService
import org.jetbrains.kotlin.idea.util.CallType
@@ -156,7 +157,7 @@ public class ReferenceVariantsHelper(
// process non-instance members
for (descriptor in resolutionScope.getDescriptorsFiltered(kindFilter, nameFilter)) {
if (descriptor is CallableDescriptor) {
assert(descriptor.dispatchReceiverParameter == null) {
assert(descriptor is SyntheticFieldDescriptor || descriptor.dispatchReceiverParameter == null) {
"Resolution scope with member descriptor: $descriptor. Scope structure: ${JetScopeUtils.printStructure(resolutionScope)}"
}
}
@@ -270,7 +271,7 @@ public class ReferenceVariantsHelper(
}
for (descriptor in resolutionScope.getDescriptors(kindFilter exclude DescriptorKindExclude.NonExtensions, nameFilter)) {
assert(descriptor !is CallableDescriptor || descriptor.dispatchReceiverParameter == null) {
assert(descriptor !is CallableDescriptor || descriptor is SyntheticFieldDescriptor || descriptor.dispatchReceiverParameter == null) {
"Resolution scope with member descriptor: $descriptor. Scope structure: ${JetScopeUtils.printStructure(resolutionScope)}"
}
if (descriptor.isExtension) {
@@ -25,7 +25,7 @@ import org.jetbrains.kotlin.psi.JetPsiFactory
import org.jetbrains.kotlin.psi.JetSimpleNameExpression
class FieldToPropertyProcessing(val field: PsiField, val propertyName: String, val isNullable: Boolean) : UsageProcessing {
override val targetElement: PsiElement get() = field
override val targetElement: PsiElement get() = this.field
override val convertedCodeProcessor = if (field.getName() != propertyName) MyConvertedCodeProcessor() else null