"field": synthetic variable creation in accessors, codegen changed accordingly, a set of tests, relevant code fix (j2k)
This commit is contained in:
@@ -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);
|
||||
|
||||
+41
@@ -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) {
|
||||
|
||||
@@ -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");
|
||||
|
||||
+30
@@ -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");
|
||||
|
||||
+3
-2
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user