Initial support for classes in scripts and REPL

This commit is contained in:
Alexander Udalov
2014-07-07 03:53:02 +04:00
parent c873806b54
commit 415fe7a5e6
18 changed files with 177 additions and 5 deletions
@@ -26,8 +26,7 @@ import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
import org.jetbrains.jet.lang.descriptors.ScriptDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.psi.JetDeclaration;
import org.jetbrains.jet.lang.psi.JetScript;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.java.jvmSignature.JvmMethodSignature;
import org.jetbrains.org.objectweb.asm.MethodVisitor;
@@ -215,7 +214,12 @@ public class ScriptCodegen extends MemberCodegen<JetScript> {
private void genMembers() {
for (JetDeclaration declaration : scriptDeclaration.getDeclarations()) {
genFunctionOrProperty(declaration);
if (declaration instanceof JetProperty || declaration instanceof JetNamedFunction) {
genFunctionOrProperty(declaration);
}
else if (declaration instanceof JetClassOrObject) {
genClassOrObject((JetClassOrObject) declaration);
}
}
}
}
@@ -309,6 +309,11 @@ public class CodegenBinding {
return fqName.isRoot() ? shortName : fqName.asString().replace('.', '/') + '/' + shortName;
}
if (container instanceof ScriptDescriptor) {
Type scriptType = asmTypeForScriptDescriptor(bindingContext, (ScriptDescriptor) container);
return scriptType.getInternalName() + "$" + name.getIdentifier();
}
assert container instanceof ClassDescriptor : "Unexpected container: " + container + " for " + klass;
String containerInternalName = getAsmType(bindingContext, (ClassDescriptor) container).getInternalName();
@@ -77,6 +77,9 @@ public class OverloadResolver {
else if (containingDeclaration instanceof PackageFragmentDescriptor) {
inPackages.put(getFqName(klass), klass.getConstructors());
}
else if (containingDeclaration instanceof ScriptDescriptor) {
// TODO: check overload conflicts of functions with constructors in scripts
}
else if (!(containingDeclaration instanceof FunctionDescriptor)) {
throw new IllegalStateException("Illegal class container: " + containingDeclaration);
}
@@ -0,0 +1,7 @@
class SimpleClass(val s: String) {
fun foo() = s
}
SimpleClass("OK").foo()
// expected: rv: OK
@@ -0,0 +1,6 @@
>>> open class A(val result: String) {
... fun foo() = result
... }
>>> class B : A("OK")
>>> B().foo()
OK
@@ -0,0 +1,13 @@
>>> class A {
... fun foo() = "Old"
... }
>>> val oldA = A()
>>> class A {
... fun foo() = "New"
... }
>>> oldA.foo()
Old
>>> A().foo()
New
>>> oldA.javaClass == javaClass<A>()
false
@@ -0,0 +1,2 @@
>>> class A
>>> class B {}
@@ -0,0 +1,2 @@
>>> class A
>>> class A
@@ -0,0 +1,11 @@
>>> enum class E {
... FIRST {
... override fun foo() = "HELLO"
... }
... SECOND {
... override fun foo() = "WORLD"
... }
... open fun foo() = "E"
... }
>>> E.FIRST.foo() + " " + E.SECOND.foo()
HELLO WORLD
@@ -0,0 +1,5 @@
>>> import java.util.Collections
>>> Collections.emptyList<Nothing>()
[]
>>> Collections.singletonList(":|||:")
[:|||:]
@@ -0,0 +1,6 @@
>>> class A { override fun toString() = "A" }
>>> val a = A()
>>> a
A
>>> a.toString()
A
@@ -0,0 +1,8 @@
>>> enum class E {
... FIRST
... SECOND
... }
>>> E.values().toList()
[FIRST, SECOND]
>>> E.FIRST.javaClass == E.SECOND.javaClass // check that no artificial classes are generated for simple enum entries
true
@@ -0,0 +1,6 @@
>>> trait A
>>> trait B : A {
... fun foo() = 45
... }
>>> javaClass<A>().isAssignableFrom(javaClass<B>())
true
@@ -0,0 +1,3 @@
>>> object Empty
>>> "Empty" in Empty.toString()
true
@@ -0,0 +1,5 @@
>>> object Life {
... fun meaning() = 42
... }
>>> Life.meaning()
42
@@ -81,6 +81,11 @@ public class ScriptCodegenTestGenerated extends AbstractScriptCodegenTest {
doTest("compiler/testData/codegen/script/secondLevelVal.kts");
}
@TestMetadata("simpleClass.kts")
public void testSimpleClass() throws Exception {
doTest("compiler/testData/codegen/script/simpleClass.kts");
}
@TestMetadata("string.kts")
public void testString() throws Exception {
doTest("compiler/testData/codegen/script/string.kts");
@@ -31,6 +31,7 @@ import org.jetbrains.jet.repl.AbstractReplInterpreterTest;
/** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("compiler/testData/repl")
@InnerTestClasses({ReplInterpreterTestGenerated.Classes.class, ReplInterpreterTestGenerated.Objects.class})
public class ReplInterpreterTestGenerated extends AbstractReplInterpreterTest {
public void testAllFilesPresentInRepl() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/repl"), Pattern.compile("^(.+)\\.repl$"), true);
@@ -106,4 +107,82 @@ public class ReplInterpreterTestGenerated extends AbstractReplInterpreterTest {
doTest("compiler/testData/repl/twoClosures.repl");
}
@TestMetadata("compiler/testData/repl/classes")
public static class Classes extends AbstractReplInterpreterTest {
public void testAllFilesPresentInClasses() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/repl/classes"), Pattern.compile("^(.+)\\.repl$"), true);
}
@TestMetadata("classInheritance.repl")
public void testClassInheritance() throws Exception {
doTest("compiler/testData/repl/classes/classInheritance.repl");
}
@TestMetadata("classRedeclaration.repl")
public void testClassRedeclaration() throws Exception {
doTest("compiler/testData/repl/classes/classRedeclaration.repl");
}
@TestMetadata("emptyClass.repl")
public void testEmptyClass() throws Exception {
doTest("compiler/testData/repl/classes/emptyClass.repl");
}
@TestMetadata("emptyClassRedeclaration.repl")
public void testEmptyClassRedeclaration() throws Exception {
doTest("compiler/testData/repl/classes/emptyClassRedeclaration.repl");
}
@TestMetadata("enumEntrySubclass.repl")
public void testEnumEntrySubclass() throws Exception {
doTest("compiler/testData/repl/classes/enumEntrySubclass.repl");
}
@TestMetadata("import.repl")
public void testImport() throws Exception {
doTest("compiler/testData/repl/classes/import.repl");
}
@TestMetadata("simpleClass.repl")
public void testSimpleClass() throws Exception {
doTest("compiler/testData/repl/classes/simpleClass.repl");
}
@TestMetadata("simpleEnum.repl")
public void testSimpleEnum() throws Exception {
doTest("compiler/testData/repl/classes/simpleEnum.repl");
}
@TestMetadata("simpleTrait.repl")
public void testSimpleTrait() throws Exception {
doTest("compiler/testData/repl/classes/simpleTrait.repl");
}
}
@TestMetadata("compiler/testData/repl/objects")
public static class Objects extends AbstractReplInterpreterTest {
public void testAllFilesPresentInObjects() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/repl/objects"), Pattern.compile("^(.+)\\.repl$"), true);
}
@TestMetadata("emptyObject.repl")
public void testEmptyObject() throws Exception {
doTest("compiler/testData/repl/objects/emptyObject.repl");
}
@TestMetadata("simpleObjectDeclaration.repl")
public void testSimpleObjectDeclaration() throws Exception {
doTest("compiler/testData/repl/objects/simpleObjectDeclaration.repl");
}
}
public static Test suite() {
TestSuite suite = new TestSuite("ReplInterpreterTestGenerated");
suite.addTestSuite(ReplInterpreterTestGenerated.class);
suite.addTestSuite(Classes.class);
suite.addTestSuite(Objects.class);
return suite;
}
}
@@ -20,7 +20,6 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.name.Name;
import java.util.Collections;
@@ -71,7 +70,10 @@ public class ConstructorDescriptorImpl extends FunctionDescriptorImpl implements
@Nullable
private static ReceiverParameterDescriptor getExpectedThisObject(@NotNull ClassDescriptor descriptor) {
DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
return DescriptorUtils.getExpectedThisObjectIfNeeded(containingDeclaration);
if (containingDeclaration instanceof ClassDescriptor) {
return ((ClassDescriptor) containingDeclaration).getThisAsReceiverParameter();
}
return NO_RECEIVER_PARAMETER;
}
@NotNull