From c06b51c1d13ec86ce1554a9ca0d1b594fa865539 Mon Sep 17 00:00:00 2001 From: Mikhael Bogdanov Date: Tue, 10 May 2016 10:36:44 +0300 Subject: [PATCH] Allow top-level local delegated properties in scripts --- .../kotlin/codegen/PropertyCodegen.java | 4 ++++ .../kotlin/codegen/ScriptCodegen.java | 11 ++++++--- .../jetbrains/kotlin/diagnostics/Errors.java | 1 - .../rendering/DefaultErrorMessages.java | 1 - .../kotlin/resolve/DeclarationsChecker.kt | 8 ------- .../script/topLevelLocalDelegatedProperty.kts | 12 ++++++++++ .../tests/script/topLevelVariable.kts | 2 +- .../repl/topLevelLocalDelegatedProperty.repl | 23 +++++++++++++++++++ .../codegen/ScriptCodegenTestGenerated.java | 6 +++++ .../repl/ReplInterpreterTestGenerated.java | 6 +++++ 10 files changed, 60 insertions(+), 14 deletions(-) create mode 100644 compiler/testData/codegen/script/topLevelLocalDelegatedProperty.kts create mode 100644 compiler/testData/repl/topLevelLocalDelegatedProperty.repl diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java index 1a0f27750a2..865642018e5 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java @@ -445,6 +445,10 @@ public class PropertyCodegen { else if (parent instanceof KtFile) { container = (KtFile) parent; } + else if (KtPsiUtil.isScriptDeclaration(property)) { + container = KtPsiUtil.getScript(property); + assert container != null : "Script declaration for property '" + property.getText() + "' should be not null!"; + } else { throw new UnsupportedOperationException("Unknown delegated property container: " + parent); } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ScriptCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ScriptCodegen.java index cdc2b76be6d..2d2a342f380 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ScriptCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ScriptCodegen.java @@ -69,6 +69,7 @@ public class ScriptCodegen extends MemberCodegen { private final KtScript scriptDeclaration; private final ScriptContext context; private final ScriptDescriptor scriptDescriptor; + private final Type classAsmType; private ScriptCodegen( @NotNull KtScript scriptDeclaration, @@ -80,16 +81,15 @@ public class ScriptCodegen extends MemberCodegen { this.scriptDeclaration = scriptDeclaration; this.context = context; this.scriptDescriptor = context.getScriptDescriptor(); + classAsmType = typeMapper.mapClass(context.getContextDescriptor()); } @Override protected void generateDeclaration() { - Type classType = typeMapper.mapClass(context.getContextDescriptor()); - v.defineClass(scriptDeclaration, V1_6, ACC_PUBLIC | ACC_SUPER, - classType.getInternalName(), + classAsmType.getInternalName(), null, "java/lang/Object", ArrayUtil.EMPTY_STRING_ARRAY); @@ -103,6 +103,11 @@ public class ScriptCodegen extends MemberCodegen { context.intoFunction(scriptDescriptor.getUnsubstitutedPrimaryConstructor())); } + @Override + protected void generateSyntheticParts() { + generatePropertyMetadataArrayFieldIfNeeded(classAsmType); + } + @Override protected void generateKotlinMetadataAnnotation() { // TODO diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index eba6d9a6476..bd7c513e8c3 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -385,7 +385,6 @@ public interface Errors { DiagnosticFactory0 ABSTRACT_DELEGATED_PROPERTY = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 ACCESSOR_FOR_DELEGATED_PROPERTY = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 DELEGATED_PROPERTY_IN_INTERFACE = DiagnosticFactory0.create(ERROR); - DiagnosticFactory0 SCRIPT_TOP_LEVEL_LOCAL_VARIABLE_WITH_DELEGATE = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 PROPERTY_WITH_NO_TYPE_NO_INITIALIZER = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index 1e193b6f735..49a2c3edcfc 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -214,7 +214,6 @@ public class DefaultErrorMessages { MAP.put(ABSTRACT_DELEGATED_PROPERTY, "Delegated property cannot be abstract"); MAP.put(ACCESSOR_FOR_DELEGATED_PROPERTY, "Delegated property cannot have accessors with non-default implementations"); MAP.put(DELEGATED_PROPERTY_IN_INTERFACE, "Delegated properties are not allowed in interfaces"); - MAP.put(SCRIPT_TOP_LEVEL_LOCAL_VARIABLE_WITH_DELEGATE, "Top-level local variables in scripts are not allowed to have delegates"); MAP.put(INAPPLICABLE_LATEINIT_MODIFIER, "''lateinit'' modifier {0}", STRING); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt index cf28f3db7f8..0e8198d44e1 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt @@ -400,14 +400,6 @@ class DeclarationsChecker( exposedChecker.checkProperty(property, propertyDescriptor) checkPropertyTypeParametersAreUsedInReceiverType(propertyDescriptor) checkImplicitCallableType(property, propertyDescriptor) - checkDelegatedPropertyInScript(property) - } - - private fun checkDelegatedPropertyInScript(property: KtProperty) { - val delegate = property.delegate - if (delegate != null && KtPsiUtil.isScriptDeclaration(property)) { - trace.report(SCRIPT_TOP_LEVEL_LOCAL_VARIABLE_WITH_DELEGATE.on(delegate)) - } } private fun checkPropertyTypeParametersAreUsedInReceiverType(descriptor: PropertyDescriptor) { diff --git a/compiler/testData/codegen/script/topLevelLocalDelegatedProperty.kts b/compiler/testData/codegen/script/topLevelLocalDelegatedProperty.kts new file mode 100644 index 00000000000..762e319e745 --- /dev/null +++ b/compiler/testData/codegen/script/topLevelLocalDelegatedProperty.kts @@ -0,0 +1,12 @@ +import kotlin.reflect.KProperty + +class Delegate { + operator fun getValue(t: Any?, p: KProperty<*>): Int = 3 +} + + +val prop: Int by Delegate() + +val x = prop + +// expected: x: 3 diff --git a/compiler/testData/diagnostics/tests/script/topLevelVariable.kts b/compiler/testData/diagnostics/tests/script/topLevelVariable.kts index 556786af7ed..4ae32022375 100644 --- a/compiler/testData/diagnostics/tests/script/topLevelVariable.kts +++ b/compiler/testData/diagnostics/tests/script/topLevelVariable.kts @@ -8,7 +8,7 @@ class Delegate { } } -val a: Int by Delegate() +val a: Int by Delegate() class Foo { val a: Int by Delegate() diff --git a/compiler/testData/repl/topLevelLocalDelegatedProperty.repl b/compiler/testData/repl/topLevelLocalDelegatedProperty.repl new file mode 100644 index 00000000000..672f1ee266d --- /dev/null +++ b/compiler/testData/repl/topLevelLocalDelegatedProperty.repl @@ -0,0 +1,23 @@ +>>> import kotlin.reflect.KProperty; +>>> class Delegate { +... var inner = 1 +... operator fun getValue(t: Any?, p: KProperty<*>): Int = inner +... operator fun setValue(t: Any?, p: KProperty<*>, i: Int) { +... inner = i +... } +...} + +>>> var prop1: Int = 1 +>>> prop1 +1 +>>> prop1 = 2 +>>> prop1 +2 +>>> var prop2: Int = 100 +>>> prop2 +100 +>>> prop2 = prop2 + 2 +>>> prop2 +102 +>>> prop1 +2 \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ScriptCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ScriptCodegenTestGenerated.java index 5fe2a56c019..f8faa794531 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ScriptCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ScriptCodegenTestGenerated.java @@ -149,6 +149,12 @@ public class ScriptCodegenTestGenerated extends AbstractScriptCodegenTest { doTest(fileName); } + @TestMetadata("topLevelLocalDelegatedProperty.kts") + public void testTopLevelLocalDelegatedProperty() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/script/topLevelLocalDelegatedProperty.kts"); + doTest(fileName); + } + @TestMetadata("topLevelProperty.kts") public void testTopLevelProperty() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/script/topLevelProperty.kts"); diff --git a/compiler/tests/org/jetbrains/kotlin/repl/ReplInterpreterTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/repl/ReplInterpreterTestGenerated.java index ff961054757..09ef5ee579e 100644 --- a/compiler/tests/org/jetbrains/kotlin/repl/ReplInterpreterTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/repl/ReplInterpreterTestGenerated.java @@ -107,6 +107,12 @@ public class ReplInterpreterTestGenerated extends AbstractReplInterpreterTest { doTest(fileName); } + @TestMetadata("topLevelLocalDelegatedProperty.repl") + public void testTopLevelLocalDelegatedProperty() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/repl/topLevelLocalDelegatedProperty.repl"); + doTest(fileName); + } + @TestMetadata("twoClosures.repl") public void testTwoClosures() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/repl/twoClosures.repl");