Allow top-level local delegated properties in scripts

This commit is contained in:
Mikhael Bogdanov
2016-05-10 10:36:44 +03:00
parent 6ece2b41d6
commit c06b51c1d1
10 changed files with 60 additions and 14 deletions
@@ -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);
}
@@ -69,6 +69,7 @@ public class ScriptCodegen extends MemberCodegen<KtScript> {
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<KtScript> {
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<KtScript> {
context.intoFunction(scriptDescriptor.getUnsubstitutedPrimaryConstructor()));
}
@Override
protected void generateSyntheticParts() {
generatePropertyMetadataArrayFieldIfNeeded(classAsmType);
}
@Override
protected void generateKotlinMetadataAnnotation() {
// TODO
@@ -385,7 +385,6 @@ public interface Errors {
DiagnosticFactory0<KtPropertyDelegate> ABSTRACT_DELEGATED_PROPERTY = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtPropertyAccessor> ACCESSOR_FOR_DELEGATED_PROPERTY = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtPropertyDelegate> DELEGATED_PROPERTY_IN_INTERFACE = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtPropertyDelegate> SCRIPT_TOP_LEVEL_LOCAL_VARIABLE_WITH_DELEGATE = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtProperty> PROPERTY_WITH_NO_TYPE_NO_INITIALIZER = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
@@ -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);
@@ -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) {
@@ -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
@@ -8,7 +8,7 @@ class Delegate {
}
}
val a: Int <!SCRIPT_TOP_LEVEL_LOCAL_VARIABLE_WITH_DELEGATE!>by Delegate()<!>
val a: Int by Delegate()
class Foo {
val a: Int by Delegate()
@@ -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
@@ -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");
@@ -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");