From 8e5c38b177b81c609a897dc72d3253c6d98c5726 Mon Sep 17 00:00:00 2001 From: Nikolay Krasko Date: Mon, 5 Dec 2011 16:55:58 +0400 Subject: [PATCH 01/15] KT-738 No kotlin type completion in extend class scope - Fixes after CR-KT-13 review --- .../tests/org/jetbrains/jet/completion/JetBasicCompletion.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/idea/tests/org/jetbrains/jet/completion/JetBasicCompletion.java b/idea/tests/org/jetbrains/jet/completion/JetBasicCompletion.java index 00d91a18421..4de7bb1d400 100644 --- a/idea/tests/org/jetbrains/jet/completion/JetBasicCompletion.java +++ b/idea/tests/org/jetbrains/jet/completion/JetBasicCompletion.java @@ -1,5 +1,6 @@ package org.jetbrains.jet.completion; +import junit.framework.Test; import junit.framework.TestSuite; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.JetTestCaseBuilder; @@ -48,7 +49,7 @@ public class JetBasicCompletion extends JetCompletionTestBase { @NotNull @Override - public junit.framework.Test createTest(@NotNull String dataPath, @NotNull String name) { + public Test createTest(@NotNull String dataPath, @NotNull String name, @NotNull File file) { return new JetBasicCompletion(dataPath, name); } }, suite); From 5dff5bded90821827773807d7a78cd1dc8e62d35 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Tue, 6 Dec 2011 13:29:28 +0200 Subject: [PATCH 02/15] KT-757 wrong inv() for long --- .../src/org/jetbrains/jet/codegen/intrinsics/Inv.java | 8 +++++++- compiler/testData/codegen/regressions/kt757.jet | 9 +++++++++ .../org/jetbrains/jet/codegen/PrimitiveTypesTest.java | 5 +++++ 3 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 compiler/testData/codegen/regressions/kt757.jet diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/Inv.java b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/Inv.java index fd6a663f964..89d757c88ef 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/Inv.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/Inv.java @@ -11,12 +11,18 @@ import java.util.List; /** * @author yole + * @author alex.tkachman */ public class Inv implements IntrinsicMethod { @Override public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List arguments, StackValue receiver) { receiver.put(expectedType, v); - v.iconst(-1); + if(expectedType == Type.LONG_TYPE) { + v.lconst(-1L); + } + else { + v.iconst(-1); + } v.xor(expectedType); return StackValue.onStack(expectedType); } diff --git a/compiler/testData/codegen/regressions/kt757.jet b/compiler/testData/codegen/regressions/kt757.jet new file mode 100644 index 00000000000..8ddfb3d879a --- /dev/null +++ b/compiler/testData/codegen/regressions/kt757.jet @@ -0,0 +1,9 @@ +namespace demo_long + +fun Long?.inv() : Long = this.sure().inv() + +fun box() : String { + val x : Long? = 10 + System.out?.println(x.inv()) + return if(x.inv() == -11.lng) "OK" else "fail" +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java b/compiler/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java index b11121da4e6..c5616a811a0 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java @@ -350,6 +350,11 @@ public class PrimitiveTypesTest extends CodegenTestCase { public void testKt684 () { blackBoxFile("regressions/kt684.jet"); +// System.out.println(generateToText()); + } + + public void testKt757 () { + blackBoxFile("regressions/kt757.jet"); // System.out.println(generateToText()); } } From 1ad4b73f5e6a65c98cc987ecc39ad2efef3f3617 Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Tue, 6 Dec 2011 16:28:19 +0400 Subject: [PATCH 03/15] fix "name" parameter name --- .../backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java index 03b698c0f53..e730798fbee 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java @@ -106,7 +106,7 @@ public class FunctionCodegen { for(int i = 0; i != paramDescrs.size(); ++i) { AnnotationVisitor av = mv.visitParameterAnnotation(i + start, "Ljet/typeinfo/JetParameter;", true); ValueParameterDescriptor parameterDescriptor = paramDescrs.get(i); - av.visit("value", parameterDescriptor.getName()); + av.visit("name", parameterDescriptor.getName()); if(parameterDescriptor.hasDefaultValue()) { av.visit("hasDefaultValue", true); } From 29ebb124c8d6042a75bb9c2b533487346a6bf0d7 Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Tue, 6 Dec 2011 16:54:52 +0400 Subject: [PATCH 04/15] working on reading class data from .class files --- .../jet/codegen/GenerationState.java | 3 +- .../jet/compiler/CompileEnvironment.java | 2 +- .../resolve/java/JavaDescriptorResolver.java | 32 ++- .../lang/resolve/java/JavaPackageScope.java | 13 +- .../org/jetbrains/jet/JetCoreEnvironment.java | 2 + compiler/testData/readClass/Class.kt | 3 + compiler/testData/readClass/ClassFun.kt | 5 + .../testData/readClass/FunParamNotNull.kt | 3 + .../testData/readClass/FunParamNullable.kt | 3 + compiler/testData/readClass/NsFun.kt | 3 + .../org/jetbrains/jet/ReadClassDataTest.java | 245 ++++++++++++++++++ 11 files changed, 308 insertions(+), 6 deletions(-) create mode 100644 compiler/testData/readClass/Class.kt create mode 100644 compiler/testData/readClass/ClassFun.kt create mode 100644 compiler/testData/readClass/FunParamNotNull.kt create mode 100644 compiler/testData/readClass/FunParamNullable.kt create mode 100644 compiler/testData/readClass/NsFun.kt create mode 100644 compiler/tests/org/jetbrains/jet/ReadClassDataTest.java diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java b/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java index 2a3c0d45b67..e83fd50e11e 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java @@ -82,11 +82,12 @@ public class GenerationState { return factory.forNamespace(namespace); } - public void compile(JetFile psiFile) { + public BindingContext compile(JetFile psiFile) { final JetNamespace namespace = psiFile.getRootNamespace(); final BindingContext bindingContext = AnalyzerFacade.analyzeOneNamespaceWithJavaIntegration(namespace, JetControlFlowDataTraceFactory.EMPTY); AnalyzingUtils.throwExceptionOnErrors(bindingContext); compileCorrectNamespaces(bindingContext, Collections.singletonList(namespace)); + return bindingContext; // NamespaceCodegen codegen = forNamespace(namespace); // bindingContexts.push(bindingContext); // typeMapper = new JetTypeMapper(standardLibrary, bindingContext); diff --git a/compiler/backend/src/org/jetbrains/jet/compiler/CompileEnvironment.java b/compiler/backend/src/org/jetbrains/jet/compiler/CompileEnvironment.java index cf23d5c948b..ba0f2765822 100644 --- a/compiler/backend/src/org/jetbrains/jet/compiler/CompileEnvironment.java +++ b/compiler/backend/src/org/jetbrains/jet/compiler/CompileEnvironment.java @@ -356,7 +356,7 @@ public class CompileEnvironment { } } - private static void writeToOutputDirectory(ClassFileFactory factory, final String outputDir) { + public static void writeToOutputDirectory(ClassFileFactory factory, final String outputDir) { List files = factory.files(); for (String file : files) { if(!skipFile(file)) { diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java index f37b2993d9a..fef54bc7f40 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java @@ -332,7 +332,6 @@ public class JavaDescriptorResolver { } private ValueParameterDescriptor resolveParameterDescriptor(DeclarationDescriptor containingDeclaration, int i, PsiParameter parameter) { - String name = parameter.getName(); PsiType psiType = parameter.getType(); JetType varargElementType; @@ -343,14 +342,41 @@ public class JavaDescriptorResolver { else { varargElementType = null; } + + boolean nullable = true; + + // TODO: must be very slow, make it lazy? + String name = parameter.getName() != null ? parameter.getName() : "p" + i; + for (PsiAnnotation annotation : parameter.getModifierList().getAnnotations()) { + // TODO: softcode annotation name + + PsiNameValuePair[] attributes = annotation.getParameterList().getAttributes(); + attributes.toString(); + + if (annotation.getQualifiedName().equals("jet.typeinfo.JetParameter")) { + PsiLiteralExpression nameExpression = (PsiLiteralExpression) annotation.findAttributeValue("name"); + if (nameExpression != null) { + name = (String) nameExpression.getValue(); + } + + PsiLiteralExpression nullableExpression = (PsiLiteralExpression) annotation.findAttributeValue("nullable"); + if (nullableExpression != null) { + nullable = (Boolean) nullableExpression.getValue(); + } else { + // default value of parameter + nullable = false; + } + } + } + JetType outType = semanticServices.getTypeTransformer().transformToType(psiType); return new ValueParameterDescriptorImpl( containingDeclaration, i, Collections.emptyList(), // TODO - name == null ? "p" + i : name, + name, null, // TODO : review - outType, + TypeUtils.makeNullableAsSpecified(outType, nullable), false, varargElementType ); diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaPackageScope.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaPackageScope.java index 11b92aee25a..776e5219dfc 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaPackageScope.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaPackageScope.java @@ -1,5 +1,6 @@ package org.jetbrains.jet.lang.resolve.java; +import com.intellij.psi.PsiClass; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.resolve.scopes.JetScopeImpl; @@ -34,7 +35,17 @@ public class JavaPackageScope extends JetScopeImpl { @NotNull @Override public Set getFunctions(@NotNull String name) { - return Collections.emptySet(); + // TODO: what is GlobalSearchScope + PsiClass psiClass = semanticServices.getDescriptorResolver().javaFacade.findClass(packagePrefix + "namespace"); + if (psiClass == null) { + return Collections.emptySet(); + } + + if (containingDescriptor == null) { + return Collections.emptySet(); + } + + return semanticServices.getDescriptorResolver().resolveFunctionGroup(containingDescriptor, psiClass, null, name, true); } @NotNull diff --git a/compiler/frontend/src/org/jetbrains/jet/JetCoreEnvironment.java b/compiler/frontend/src/org/jetbrains/jet/JetCoreEnvironment.java index eac28f341d6..65218c54fcf 100644 --- a/compiler/frontend/src/org/jetbrains/jet/JetCoreEnvironment.java +++ b/compiler/frontend/src/org/jetbrains/jet/JetCoreEnvironment.java @@ -1,6 +1,7 @@ package org.jetbrains.jet; import com.intellij.core.JavaCoreEnvironment; +import com.intellij.lang.java.JavaParserDefinition; import com.intellij.openapi.Disposable; import org.jetbrains.jet.lang.parsing.JetParserDefinition; import org.jetbrains.jet.plugin.JetFileType; @@ -15,6 +16,7 @@ public class JetCoreEnvironment extends JavaCoreEnvironment { registerFileType(JetFileType.INSTANCE, "kts"); registerFileType(JetFileType.INSTANCE, "ktm"); registerFileType(JetFileType.INSTANCE, "jet"); + registerParserDefinition(new JavaParserDefinition()); registerParserDefinition(new JetParserDefinition()); } } diff --git a/compiler/testData/readClass/Class.kt b/compiler/testData/readClass/Class.kt new file mode 100644 index 00000000000..957e3e9c54d --- /dev/null +++ b/compiler/testData/readClass/Class.kt @@ -0,0 +1,3 @@ +namespace test + +class Ramification diff --git a/compiler/testData/readClass/ClassFun.kt b/compiler/testData/readClass/ClassFun.kt new file mode 100644 index 00000000000..27eb0bc5e37 --- /dev/null +++ b/compiler/testData/readClass/ClassFun.kt @@ -0,0 +1,5 @@ +namespace test + +class River { + fun song() = 1 +} diff --git a/compiler/testData/readClass/FunParamNotNull.kt b/compiler/testData/readClass/FunParamNotNull.kt new file mode 100644 index 00000000000..72d84f88278 --- /dev/null +++ b/compiler/testData/readClass/FunParamNotNull.kt @@ -0,0 +1,3 @@ +namespace test + +fun fff(a: String) = 1 diff --git a/compiler/testData/readClass/FunParamNullable.kt b/compiler/testData/readClass/FunParamNullable.kt new file mode 100644 index 00000000000..288582a2f08 --- /dev/null +++ b/compiler/testData/readClass/FunParamNullable.kt @@ -0,0 +1,3 @@ +namespace test + +fun fff(a: String?) = 1 diff --git a/compiler/testData/readClass/NsFun.kt b/compiler/testData/readClass/NsFun.kt new file mode 100644 index 00000000000..6fc14ecc6df --- /dev/null +++ b/compiler/testData/readClass/NsFun.kt @@ -0,0 +1,3 @@ +namespace test + +fun f() = 1 diff --git a/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java b/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java new file mode 100644 index 00000000000..67380ad3cee --- /dev/null +++ b/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java @@ -0,0 +1,245 @@ +package org.jetbrains.jet; + +import com.intellij.lang.ASTFactory; +import com.intellij.lang.LanguageASTFactory; +import com.intellij.lang.java.JavaLanguage; +import com.intellij.openapi.Disposable; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.vfs.CharsetToolkit; +import com.intellij.psi.PsiFileFactory; +import com.intellij.psi.impl.PsiFileFactoryImpl; +import com.intellij.psi.impl.source.tree.JavaASTFactory; +import com.intellij.testFramework.LightVirtualFile; +import com.intellij.testFramework.UsefulTestCase; +import junit.framework.Test; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.codegen.ClassBuilderFactory; +import org.jetbrains.jet.codegen.ClassFileFactory; +import org.jetbrains.jet.codegen.GenerationState; +import org.jetbrains.jet.compiler.CompileEnvironment; +import org.jetbrains.jet.lang.JetSemanticServices; +import org.jetbrains.jet.lang.descriptors.ClassDescriptor; +import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor; +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; +import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; +import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; +import org.jetbrains.jet.lang.psi.JetFile; +import org.jetbrains.jet.lang.resolve.AnalyzingUtils; +import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.BindingTraceContext; +import org.jetbrains.jet.lang.resolve.java.JavaDescriptorResolver; +import org.jetbrains.jet.lang.resolve.java.JavaSemanticServices; +import org.jetbrains.jet.plugin.JetLanguage; +import org.junit.Assert; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Set; + +/** + * @author Stepan Koltsov + */ +public class ReadClassDataTest extends UsefulTestCase { + + protected final Disposable myTestRootDisposable = new Disposable() { + @Override + public void dispose() { + } + }; + + private JetCoreEnvironment jetCoreEnvironment; + private File tmpdir; + + private final File testFile; + + public ReadClassDataTest(@NotNull File testFile) { + this.testFile = testFile; + setName(testFile.getName()); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + tmpdir = new File("tmp/" + this.getClass().getSimpleName() + "." + this.getName()); + rmrf(tmpdir); + mkdirs(tmpdir); + } + + @Override + public void tearDown() throws Exception { + Disposer.dispose(myTestRootDisposable); + } + + private void mkdirs(File file) throws IOException { + if (file.isDirectory()) { + return; + } + if (!file.mkdirs()) { + throw new IOException(); + } + } + + private void rmrf(File file) { + if (file != null) { + File[] children = file.listFiles(); + if (children != null) { + for (File child : children) { + rmrf(child); + } + } + file.delete(); + } + } + + private void createMockCoreEnvironment() { + jetCoreEnvironment = new JetCoreEnvironment(myTestRootDisposable); + + final File rtJar = new File(JetTestCaseBuilder.getHomeDirectory(), "compiler/testData/mockJDK-1.7/jre/lib/rt.jar"); + jetCoreEnvironment.addToClasspath(rtJar); + jetCoreEnvironment.addToClasspath(new File(JetTestCaseBuilder.getHomeDirectory(), "compiler/testData/mockJDK-1.7/jre/lib/annotations.jar")); + } + + @Override + public void runTest() throws Exception { + createMockCoreEnvironment(); + + LanguageASTFactory.INSTANCE.addExplicitExtension(JavaLanguage.INSTANCE, new JavaASTFactory()); + + + String text = FileUtil.loadFile(testFile); + + LightVirtualFile virtualFile = new LightVirtualFile("Hello.kt", JetLanguage.INSTANCE, text); + virtualFile.setCharset(CharsetToolkit.UTF8_CHARSET); + JetFile psiFile = (JetFile) ((PsiFileFactoryImpl) PsiFileFactory.getInstance(jetCoreEnvironment.getProject())).trySetupPsiForFile(virtualFile, JetLanguage.INSTANCE, true, false); + + GenerationState state = new GenerationState(jetCoreEnvironment.getProject(), ClassBuilderFactory.BINARIES); + AnalyzingUtils.checkForSyntacticErrors(psiFile); + BindingContext bindingContext = state.compile(psiFile); + + ClassFileFactory classFileFactory = state.getFactory(); + + CompileEnvironment.writeToOutputDirectory(classFileFactory, tmpdir.getPath()); + + NamespaceDescriptor namespaceFromSource = (NamespaceDescriptor) bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, psiFile.getRootNamespace()); + + Assert.assertEquals("test", namespaceFromSource.getName()); + + Disposer.dispose(myTestRootDisposable); + + + + createMockCoreEnvironment(); + + jetCoreEnvironment.addToClasspath(tmpdir); + + JetSemanticServices jetSemanticServices = JetSemanticServices.createSemanticServices(jetCoreEnvironment.getProject()); + JavaSemanticServices semanticServices = new JavaSemanticServices(jetCoreEnvironment.getProject(), jetSemanticServices, new BindingTraceContext()); + + JavaDescriptorResolver javaDescriptorResolver = semanticServices.getDescriptorResolver(); + NamespaceDescriptor namespaceFromClass = javaDescriptorResolver.resolveNamespace("test"); + + compareNamespaces(namespaceFromSource, namespaceFromClass); + } + + private void compareNamespaces(@NotNull NamespaceDescriptor nsa, @NotNull NamespaceDescriptor nsb) { + Assert.assertEquals(nsa.getName(), nsb.getName()); + System.out.println("namespace " + nsa.getName()); + for (DeclarationDescriptor ad : nsa.getMemberScope().getAllDescriptors()) { + if (ad instanceof ClassifierDescriptor) { + ClassifierDescriptor bd = nsb.getMemberScope().getClassifier(ad.getName()); + compareClassifiers((ClassifierDescriptor) ad, bd); + } else if (ad instanceof FunctionDescriptor) { + Set functions = nsb.getMemberScope().getFunctions(ad.getName()); + Assert.assertTrue(functions.size() >= 1); + Assert.assertTrue("not implemented", functions.size() == 1); + FunctionDescriptor bd = functions.iterator().next(); + compareFunctions((FunctionDescriptor) ad, bd); + } else { + throw new AssertionError("Unknown member: " + ad); + } + } + } + + private void compareClassifiers(@NotNull ClassifierDescriptor a, @NotNull ClassifierDescriptor b) { + Assert.assertEquals(a.getName(), b.getName()); + System.out.println("classifier " + a.getName()); + if (a instanceof ClassDescriptor || b instanceof ClassDescriptor) { + compareClasses((ClassDescriptor) a, (ClassDescriptor) b); + } + } + + private void compareClasses(@NotNull ClassDescriptor a, @NotNull ClassDescriptor b) { + System.out.println("... is class"); + } + + private void compareFunctions(@NotNull FunctionDescriptor a, @NotNull FunctionDescriptor b) { + Assert.assertEquals(a.getName(), b.getName()); + Assert.assertEquals(a.getValueParameters().size(), b.getValueParameters().size()); + for (int i = 0; i < a.getValueParameters().size(); ++i) { + compareAnything(ValueParameterDescriptor.class, a.getValueParameters().get(i), b.getValueParameters().get(i)); + } + System.out.println("function " + a.getName()); + } + + private void compareAnything(Class clazz, T a, T b) { + System.out.println("Comparing " + clazz); + Assert.assertNotNull(a); + Assert.assertNotNull(b); + + for (Method method : clazz.getMethods()) { + if (!isGetter(method)) { + continue; + } + if (method.getName().equals("getContainingDeclaration")) { + continue; + } + + if (clazz.equals(ValueParameterDescriptor.class)) { + if (method.getName().equals("isRef") || method.getName().equals("getOriginal")) { + continue; + } + } + + System.out.println(method.getName()); + Object ap = invoke(method, a); + Object bp = invoke(method, b); + Assert.assertEquals(ap, bp); + } + } + + private static boolean isGetter(Method method) { + if (method.getParameterTypes().length > 0) { + return false; + } + if (method.getName().matches("is.+")) { + return method.getReturnType().equals(boolean.class); + } else if (method.getName().matches("get.+")) { + return true; + } else { + return false; + } + } + + private static Object invoke(Method method, Object thiz, Object... args) { + try { + return method.invoke(thiz, args); + } catch (Exception e) { + throw new RuntimeException("failed to invoke " + method + ": " + e); + } + } + + public static Test suite() { + return JetTestCaseBuilder.suiteForDirectory(JetTestCaseBuilder.getTestDataPathBase(), "/readClass", true, new JetTestCaseBuilder.NamedTestFactory() { + @NotNull + @Override + public Test createTest(@NotNull String dataPath, @NotNull String name, @NotNull File file) { + return new ReadClassDataTest(file); + } + }); + } + +} From ecb323a13e7f92694ee008aaded9b206543fd5b7 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Tue, 6 Dec 2011 15:03:26 +0200 Subject: [PATCH 05/15] KT-756 incorrect intrinsics on nullable numbers --- .../jet/codegen/intrinsics/Increment.java | 43 +++++++++++++------ .../codegen/intrinsics/IntrinsicMethods.java | 2 + .../jetbrains/jet/codegen/intrinsics/Inv.java | 5 +++ .../jet/codegen/intrinsics/UnaryMinus.java | 5 +++ .../jet/codegen/intrinsics/UnaryPlus.java | 27 ++++++++++++ .../testData/codegen/regressions/kt756.jet | 12 ++++++ .../jet/codegen/PrimitiveTypesTest.java | 16 +++---- 7 files changed, 85 insertions(+), 25 deletions(-) create mode 100644 compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/UnaryPlus.java create mode 100644 compiler/testData/codegen/regressions/kt756.jet diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/Increment.java b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/Increment.java index a53c8791f80..d140d937507 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/Increment.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/Increment.java @@ -24,20 +24,38 @@ public class Increment implements IntrinsicMethod { @Override public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List arguments, StackValue receiver) { - JetExpression operand = arguments.get(0); - while(operand instanceof JetParenthesizedExpression) { - operand = ((JetParenthesizedExpression)operand).getExpression(); + boolean nullable = expectedType.getSort() == Type.OBJECT; + if(nullable) { + expectedType = JetTypeMapper.unboxType(expectedType); } - if (operand instanceof JetReferenceExpression) { - final int index = codegen.indexOfLocal((JetReferenceExpression) operand); - if (index >= 0 && JetTypeMapper.isIntPrimitive(expectedType)) { - return StackValue.preIncrement(index, myDelta); + if(arguments.size() > 0) { + JetExpression operand = arguments.get(0); + while(operand instanceof JetParenthesizedExpression) { + operand = ((JetParenthesizedExpression)operand).getExpression(); } + if (operand instanceof JetReferenceExpression) { + final int index = codegen.indexOfLocal((JetReferenceExpression) operand); + if (index >= 0 && JetTypeMapper.isIntPrimitive(expectedType)) { + return StackValue.preIncrement(index, myDelta); + } + } + StackValue value = codegen.genQualified(receiver, operand); + value. dupReceiver(v); + value. dupReceiver(v); + + value.put(expectedType, v); + plusMinus(v, expectedType); + value.store(v); + value.put(expectedType, v); } - StackValue value = codegen.genQualified(receiver, operand); - value. dupReceiver(v); - value. dupReceiver(v); - value.put(expectedType, v); + else { + receiver.put(expectedType, v); + plusMinus(v, expectedType); + } + return StackValue.onStack(expectedType); + } + + private void plusMinus(InstructionAdapter v, Type expectedType) { if (expectedType == Type.LONG_TYPE) { v.lconst(myDelta); } @@ -51,8 +69,5 @@ public class Increment implements IntrinsicMethod { v.iconst(myDelta); } v.add(expectedType); - value.store(v); - value.put(expectedType, v); - return StackValue.onStack(expectedType); } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java index 6ccff8d02b3..79374780086 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java @@ -23,6 +23,7 @@ import java.util.*; */ public class IntrinsicMethods { private static final IntrinsicMethod UNARY_MINUS = new UnaryMinus(); + private static final IntrinsicMethod UNARY_PLUS = new UnaryPlus(); private static final IntrinsicMethod NUMBER_CAST = new NumberCast(); private static final IntrinsicMethod INV = new Inv(); private static final IntrinsicMethod TYPEINFO = new TypeInfo(); @@ -53,6 +54,7 @@ public class IntrinsicMethods { } for (String type : PRIMITIVE_NUMBER_TYPES) { + declareIntrinsicFunction(type, "plus", 0, UNARY_PLUS); declareIntrinsicFunction(type, "minus", 0, UNARY_MINUS); declareIntrinsicFunction(type, "inv", 0, INV); declareIntrinsicFunction(type, "rangeTo", 1, RANGE_TO); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/Inv.java b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/Inv.java index 89d757c88ef..b4b1e287310 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/Inv.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/Inv.java @@ -2,6 +2,7 @@ package org.jetbrains.jet.codegen.intrinsics; import com.intellij.psi.PsiElement; import org.jetbrains.jet.codegen.ExpressionCodegen; +import org.jetbrains.jet.codegen.JetTypeMapper; import org.jetbrains.jet.codegen.StackValue; import org.jetbrains.jet.lang.psi.JetExpression; import org.objectweb.asm.Type; @@ -16,6 +17,10 @@ import java.util.List; public class Inv implements IntrinsicMethod { @Override public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List arguments, StackValue receiver) { + boolean nullable = expectedType.getSort() == Type.OBJECT; + if(nullable) { + expectedType = JetTypeMapper.unboxType(expectedType); + } receiver.put(expectedType, v); if(expectedType == Type.LONG_TYPE) { v.lconst(-1L); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/UnaryMinus.java b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/UnaryMinus.java index b84d3f79fdf..4eb8ecb4d20 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/UnaryMinus.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/UnaryMinus.java @@ -2,6 +2,7 @@ package org.jetbrains.jet.codegen.intrinsics; import com.intellij.psi.PsiElement; import org.jetbrains.jet.codegen.ExpressionCodegen; +import org.jetbrains.jet.codegen.JetTypeMapper; import org.jetbrains.jet.codegen.StackValue; import org.jetbrains.jet.lang.psi.JetExpression; import org.objectweb.asm.Type; @@ -15,6 +16,10 @@ import java.util.List; public class UnaryMinus implements IntrinsicMethod { @Override public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List arguments, StackValue receiver) { + boolean nullable = expectedType.getSort() == Type.OBJECT; + if(nullable) { + expectedType = JetTypeMapper.unboxType(expectedType); + } if (arguments.size() == 1) { codegen.gen(arguments.get(0), expectedType); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/UnaryPlus.java b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/UnaryPlus.java new file mode 100644 index 00000000000..2405ef3d8aa --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/UnaryPlus.java @@ -0,0 +1,27 @@ +package org.jetbrains.jet.codegen.intrinsics; + +import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.codegen.ExpressionCodegen; +import org.jetbrains.jet.codegen.JetTypeMapper; +import org.jetbrains.jet.codegen.StackValue; +import org.jetbrains.jet.lang.psi.JetExpression; +import org.objectweb.asm.Type; +import org.objectweb.asm.commons.InstructionAdapter; + +import java.util.List; + +/** + * @author alex.tkachman + */ +public class UnaryPlus implements IntrinsicMethod { + @Override + public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, @Nullable PsiElement element, @Nullable List arguments, StackValue receiver) { + boolean nullable = expectedType.getSort() == Type.OBJECT; + if(nullable) { + expectedType = JetTypeMapper.unboxType(expectedType); + } + receiver.put(expectedType, v); + return StackValue.onStack(expectedType); + } +} diff --git a/compiler/testData/codegen/regressions/kt756.jet b/compiler/testData/codegen/regressions/kt756.jet new file mode 100644 index 00000000000..4cff1aecd11 --- /dev/null +++ b/compiler/testData/codegen/regressions/kt756.jet @@ -0,0 +1,12 @@ +namespace demo_range + +fun Int?.plus() : Int = this.sure().plus() +fun Int?.dec() : Int = this.sure().dec() +fun Int?.inc() : Int = this.sure().inc() +fun Int?.minus() : Int = this.sure().minus() + +fun box() : String { + val x : Int? = 10 + System.out?.println(x?.inv())// * x?.plus() * x?.dec() * x?.minus() as Number) + return "OK" +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java b/compiler/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java index c5616a811a0..0c7ad33b70b 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java @@ -287,37 +287,31 @@ public class PrimitiveTypesTest extends CodegenTestCase { public void testKt711 () throws Exception { loadText("fun box() = if ((1 ?: 0) == 1) \"OK\" else \"fail\""); -// System.out.println(generateToText()); blackBox(); } public void testSureNonnull () throws Exception { loadText("fun box() = 10.sure().toString()"); -// System.out.println(generateToText()); assertFalse(generateToText().contains("IFNONNULL")); } public void testSureNullable () throws Exception { loadText("val a : Int? = 10; fun box() = a.sure().toString()"); -// System.out.println(generateToText()); assertTrue(generateToText().contains("IFNONNULL")); } public void testSafeNonnull () throws Exception { loadText("fun box() = 10?.toString()"); -// System.out.println(generateToText()); assertFalse(generateToText().contains("IFNULL")); } public void testSafeNullable () throws Exception { loadText("val a : Int? = 10; fun box() = a?.toString()"); -// System.out.println(generateToText()); assertTrue(generateToText().contains("IFNULL")); } public void testKt737() throws Exception { loadText("fun box() = if(3.compareTo(2) != 1) \"fail\" else if(5.byt.compareTo(10.lng) >= 0) \"fail\" else \"OK\""); -// System.out.println(generateToText()); assertEquals("OK", blackBox()); } @@ -334,27 +328,27 @@ public class PrimitiveTypesTest extends CodegenTestCase { " System.out?.println(f(six))\n" + " return \"OK\"" + "}"); -// System.out.println(generateToText()); blackBox(); } public void testKt752 () { blackBoxFile("regressions/kt752.jet"); -// System.out.println(generateToText()); } public void testKt753 () { blackBoxFile("regressions/kt753.jet"); -// System.out.println(generateToText()); } public void testKt684 () { blackBoxFile("regressions/kt684.jet"); -// System.out.println(generateToText()); + } + + public void testKt756 () { + blackBoxFile("regressions/kt756.jet"); + System.out.println(generateToText()); } public void testKt757 () { blackBoxFile("regressions/kt757.jet"); -// System.out.println(generateToText()); } } From f68aabbcab9ceb481a3ae68f004e96acec4c768b Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Tue, 6 Dec 2011 17:48:33 +0400 Subject: [PATCH 06/15] Temporarily revert "working on reading class data from .class files" This reverts commit 29ebb124c8d6042a75bb9c2b533487346a6bf0d7. --- .../jet/codegen/GenerationState.java | 3 +- .../jet/compiler/CompileEnvironment.java | 2 +- .../resolve/java/JavaDescriptorResolver.java | 32 +-- .../lang/resolve/java/JavaPackageScope.java | 13 +- .../org/jetbrains/jet/JetCoreEnvironment.java | 2 - compiler/testData/readClass/Class.kt | 3 - compiler/testData/readClass/ClassFun.kt | 5 - .../testData/readClass/FunParamNotNull.kt | 3 - .../testData/readClass/FunParamNullable.kt | 3 - compiler/testData/readClass/NsFun.kt | 3 - .../org/jetbrains/jet/ReadClassDataTest.java | 245 ------------------ 11 files changed, 6 insertions(+), 308 deletions(-) delete mode 100644 compiler/testData/readClass/Class.kt delete mode 100644 compiler/testData/readClass/ClassFun.kt delete mode 100644 compiler/testData/readClass/FunParamNotNull.kt delete mode 100644 compiler/testData/readClass/FunParamNullable.kt delete mode 100644 compiler/testData/readClass/NsFun.kt delete mode 100644 compiler/tests/org/jetbrains/jet/ReadClassDataTest.java diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java b/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java index e83fd50e11e..2a3c0d45b67 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java @@ -82,12 +82,11 @@ public class GenerationState { return factory.forNamespace(namespace); } - public BindingContext compile(JetFile psiFile) { + public void compile(JetFile psiFile) { final JetNamespace namespace = psiFile.getRootNamespace(); final BindingContext bindingContext = AnalyzerFacade.analyzeOneNamespaceWithJavaIntegration(namespace, JetControlFlowDataTraceFactory.EMPTY); AnalyzingUtils.throwExceptionOnErrors(bindingContext); compileCorrectNamespaces(bindingContext, Collections.singletonList(namespace)); - return bindingContext; // NamespaceCodegen codegen = forNamespace(namespace); // bindingContexts.push(bindingContext); // typeMapper = new JetTypeMapper(standardLibrary, bindingContext); diff --git a/compiler/backend/src/org/jetbrains/jet/compiler/CompileEnvironment.java b/compiler/backend/src/org/jetbrains/jet/compiler/CompileEnvironment.java index ba0f2765822..cf23d5c948b 100644 --- a/compiler/backend/src/org/jetbrains/jet/compiler/CompileEnvironment.java +++ b/compiler/backend/src/org/jetbrains/jet/compiler/CompileEnvironment.java @@ -356,7 +356,7 @@ public class CompileEnvironment { } } - public static void writeToOutputDirectory(ClassFileFactory factory, final String outputDir) { + private static void writeToOutputDirectory(ClassFileFactory factory, final String outputDir) { List files = factory.files(); for (String file : files) { if(!skipFile(file)) { diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java index fef54bc7f40..f37b2993d9a 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java @@ -332,6 +332,7 @@ public class JavaDescriptorResolver { } private ValueParameterDescriptor resolveParameterDescriptor(DeclarationDescriptor containingDeclaration, int i, PsiParameter parameter) { + String name = parameter.getName(); PsiType psiType = parameter.getType(); JetType varargElementType; @@ -342,41 +343,14 @@ public class JavaDescriptorResolver { else { varargElementType = null; } - - boolean nullable = true; - - // TODO: must be very slow, make it lazy? - String name = parameter.getName() != null ? parameter.getName() : "p" + i; - for (PsiAnnotation annotation : parameter.getModifierList().getAnnotations()) { - // TODO: softcode annotation name - - PsiNameValuePair[] attributes = annotation.getParameterList().getAttributes(); - attributes.toString(); - - if (annotation.getQualifiedName().equals("jet.typeinfo.JetParameter")) { - PsiLiteralExpression nameExpression = (PsiLiteralExpression) annotation.findAttributeValue("name"); - if (nameExpression != null) { - name = (String) nameExpression.getValue(); - } - - PsiLiteralExpression nullableExpression = (PsiLiteralExpression) annotation.findAttributeValue("nullable"); - if (nullableExpression != null) { - nullable = (Boolean) nullableExpression.getValue(); - } else { - // default value of parameter - nullable = false; - } - } - } - JetType outType = semanticServices.getTypeTransformer().transformToType(psiType); return new ValueParameterDescriptorImpl( containingDeclaration, i, Collections.emptyList(), // TODO - name, + name == null ? "p" + i : name, null, // TODO : review - TypeUtils.makeNullableAsSpecified(outType, nullable), + outType, false, varargElementType ); diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaPackageScope.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaPackageScope.java index 776e5219dfc..11b92aee25a 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaPackageScope.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaPackageScope.java @@ -1,6 +1,5 @@ package org.jetbrains.jet.lang.resolve.java; -import com.intellij.psi.PsiClass; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.resolve.scopes.JetScopeImpl; @@ -35,17 +34,7 @@ public class JavaPackageScope extends JetScopeImpl { @NotNull @Override public Set getFunctions(@NotNull String name) { - // TODO: what is GlobalSearchScope - PsiClass psiClass = semanticServices.getDescriptorResolver().javaFacade.findClass(packagePrefix + "namespace"); - if (psiClass == null) { - return Collections.emptySet(); - } - - if (containingDescriptor == null) { - return Collections.emptySet(); - } - - return semanticServices.getDescriptorResolver().resolveFunctionGroup(containingDescriptor, psiClass, null, name, true); + return Collections.emptySet(); } @NotNull diff --git a/compiler/frontend/src/org/jetbrains/jet/JetCoreEnvironment.java b/compiler/frontend/src/org/jetbrains/jet/JetCoreEnvironment.java index 65218c54fcf..eac28f341d6 100644 --- a/compiler/frontend/src/org/jetbrains/jet/JetCoreEnvironment.java +++ b/compiler/frontend/src/org/jetbrains/jet/JetCoreEnvironment.java @@ -1,7 +1,6 @@ package org.jetbrains.jet; import com.intellij.core.JavaCoreEnvironment; -import com.intellij.lang.java.JavaParserDefinition; import com.intellij.openapi.Disposable; import org.jetbrains.jet.lang.parsing.JetParserDefinition; import org.jetbrains.jet.plugin.JetFileType; @@ -16,7 +15,6 @@ public class JetCoreEnvironment extends JavaCoreEnvironment { registerFileType(JetFileType.INSTANCE, "kts"); registerFileType(JetFileType.INSTANCE, "ktm"); registerFileType(JetFileType.INSTANCE, "jet"); - registerParserDefinition(new JavaParserDefinition()); registerParserDefinition(new JetParserDefinition()); } } diff --git a/compiler/testData/readClass/Class.kt b/compiler/testData/readClass/Class.kt deleted file mode 100644 index 957e3e9c54d..00000000000 --- a/compiler/testData/readClass/Class.kt +++ /dev/null @@ -1,3 +0,0 @@ -namespace test - -class Ramification diff --git a/compiler/testData/readClass/ClassFun.kt b/compiler/testData/readClass/ClassFun.kt deleted file mode 100644 index 27eb0bc5e37..00000000000 --- a/compiler/testData/readClass/ClassFun.kt +++ /dev/null @@ -1,5 +0,0 @@ -namespace test - -class River { - fun song() = 1 -} diff --git a/compiler/testData/readClass/FunParamNotNull.kt b/compiler/testData/readClass/FunParamNotNull.kt deleted file mode 100644 index 72d84f88278..00000000000 --- a/compiler/testData/readClass/FunParamNotNull.kt +++ /dev/null @@ -1,3 +0,0 @@ -namespace test - -fun fff(a: String) = 1 diff --git a/compiler/testData/readClass/FunParamNullable.kt b/compiler/testData/readClass/FunParamNullable.kt deleted file mode 100644 index 288582a2f08..00000000000 --- a/compiler/testData/readClass/FunParamNullable.kt +++ /dev/null @@ -1,3 +0,0 @@ -namespace test - -fun fff(a: String?) = 1 diff --git a/compiler/testData/readClass/NsFun.kt b/compiler/testData/readClass/NsFun.kt deleted file mode 100644 index 6fc14ecc6df..00000000000 --- a/compiler/testData/readClass/NsFun.kt +++ /dev/null @@ -1,3 +0,0 @@ -namespace test - -fun f() = 1 diff --git a/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java b/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java deleted file mode 100644 index 67380ad3cee..00000000000 --- a/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java +++ /dev/null @@ -1,245 +0,0 @@ -package org.jetbrains.jet; - -import com.intellij.lang.ASTFactory; -import com.intellij.lang.LanguageASTFactory; -import com.intellij.lang.java.JavaLanguage; -import com.intellij.openapi.Disposable; -import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.vfs.CharsetToolkit; -import com.intellij.psi.PsiFileFactory; -import com.intellij.psi.impl.PsiFileFactoryImpl; -import com.intellij.psi.impl.source.tree.JavaASTFactory; -import com.intellij.testFramework.LightVirtualFile; -import com.intellij.testFramework.UsefulTestCase; -import junit.framework.Test; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.codegen.ClassBuilderFactory; -import org.jetbrains.jet.codegen.ClassFileFactory; -import org.jetbrains.jet.codegen.GenerationState; -import org.jetbrains.jet.compiler.CompileEnvironment; -import org.jetbrains.jet.lang.JetSemanticServices; -import org.jetbrains.jet.lang.descriptors.ClassDescriptor; -import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor; -import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; -import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; -import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; -import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; -import org.jetbrains.jet.lang.psi.JetFile; -import org.jetbrains.jet.lang.resolve.AnalyzingUtils; -import org.jetbrains.jet.lang.resolve.BindingContext; -import org.jetbrains.jet.lang.resolve.BindingTraceContext; -import org.jetbrains.jet.lang.resolve.java.JavaDescriptorResolver; -import org.jetbrains.jet.lang.resolve.java.JavaSemanticServices; -import org.jetbrains.jet.plugin.JetLanguage; -import org.junit.Assert; - -import java.io.File; -import java.io.IOException; -import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.Set; - -/** - * @author Stepan Koltsov - */ -public class ReadClassDataTest extends UsefulTestCase { - - protected final Disposable myTestRootDisposable = new Disposable() { - @Override - public void dispose() { - } - }; - - private JetCoreEnvironment jetCoreEnvironment; - private File tmpdir; - - private final File testFile; - - public ReadClassDataTest(@NotNull File testFile) { - this.testFile = testFile; - setName(testFile.getName()); - } - - @Override - protected void setUp() throws Exception { - super.setUp(); - tmpdir = new File("tmp/" + this.getClass().getSimpleName() + "." + this.getName()); - rmrf(tmpdir); - mkdirs(tmpdir); - } - - @Override - public void tearDown() throws Exception { - Disposer.dispose(myTestRootDisposable); - } - - private void mkdirs(File file) throws IOException { - if (file.isDirectory()) { - return; - } - if (!file.mkdirs()) { - throw new IOException(); - } - } - - private void rmrf(File file) { - if (file != null) { - File[] children = file.listFiles(); - if (children != null) { - for (File child : children) { - rmrf(child); - } - } - file.delete(); - } - } - - private void createMockCoreEnvironment() { - jetCoreEnvironment = new JetCoreEnvironment(myTestRootDisposable); - - final File rtJar = new File(JetTestCaseBuilder.getHomeDirectory(), "compiler/testData/mockJDK-1.7/jre/lib/rt.jar"); - jetCoreEnvironment.addToClasspath(rtJar); - jetCoreEnvironment.addToClasspath(new File(JetTestCaseBuilder.getHomeDirectory(), "compiler/testData/mockJDK-1.7/jre/lib/annotations.jar")); - } - - @Override - public void runTest() throws Exception { - createMockCoreEnvironment(); - - LanguageASTFactory.INSTANCE.addExplicitExtension(JavaLanguage.INSTANCE, new JavaASTFactory()); - - - String text = FileUtil.loadFile(testFile); - - LightVirtualFile virtualFile = new LightVirtualFile("Hello.kt", JetLanguage.INSTANCE, text); - virtualFile.setCharset(CharsetToolkit.UTF8_CHARSET); - JetFile psiFile = (JetFile) ((PsiFileFactoryImpl) PsiFileFactory.getInstance(jetCoreEnvironment.getProject())).trySetupPsiForFile(virtualFile, JetLanguage.INSTANCE, true, false); - - GenerationState state = new GenerationState(jetCoreEnvironment.getProject(), ClassBuilderFactory.BINARIES); - AnalyzingUtils.checkForSyntacticErrors(psiFile); - BindingContext bindingContext = state.compile(psiFile); - - ClassFileFactory classFileFactory = state.getFactory(); - - CompileEnvironment.writeToOutputDirectory(classFileFactory, tmpdir.getPath()); - - NamespaceDescriptor namespaceFromSource = (NamespaceDescriptor) bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, psiFile.getRootNamespace()); - - Assert.assertEquals("test", namespaceFromSource.getName()); - - Disposer.dispose(myTestRootDisposable); - - - - createMockCoreEnvironment(); - - jetCoreEnvironment.addToClasspath(tmpdir); - - JetSemanticServices jetSemanticServices = JetSemanticServices.createSemanticServices(jetCoreEnvironment.getProject()); - JavaSemanticServices semanticServices = new JavaSemanticServices(jetCoreEnvironment.getProject(), jetSemanticServices, new BindingTraceContext()); - - JavaDescriptorResolver javaDescriptorResolver = semanticServices.getDescriptorResolver(); - NamespaceDescriptor namespaceFromClass = javaDescriptorResolver.resolveNamespace("test"); - - compareNamespaces(namespaceFromSource, namespaceFromClass); - } - - private void compareNamespaces(@NotNull NamespaceDescriptor nsa, @NotNull NamespaceDescriptor nsb) { - Assert.assertEquals(nsa.getName(), nsb.getName()); - System.out.println("namespace " + nsa.getName()); - for (DeclarationDescriptor ad : nsa.getMemberScope().getAllDescriptors()) { - if (ad instanceof ClassifierDescriptor) { - ClassifierDescriptor bd = nsb.getMemberScope().getClassifier(ad.getName()); - compareClassifiers((ClassifierDescriptor) ad, bd); - } else if (ad instanceof FunctionDescriptor) { - Set functions = nsb.getMemberScope().getFunctions(ad.getName()); - Assert.assertTrue(functions.size() >= 1); - Assert.assertTrue("not implemented", functions.size() == 1); - FunctionDescriptor bd = functions.iterator().next(); - compareFunctions((FunctionDescriptor) ad, bd); - } else { - throw new AssertionError("Unknown member: " + ad); - } - } - } - - private void compareClassifiers(@NotNull ClassifierDescriptor a, @NotNull ClassifierDescriptor b) { - Assert.assertEquals(a.getName(), b.getName()); - System.out.println("classifier " + a.getName()); - if (a instanceof ClassDescriptor || b instanceof ClassDescriptor) { - compareClasses((ClassDescriptor) a, (ClassDescriptor) b); - } - } - - private void compareClasses(@NotNull ClassDescriptor a, @NotNull ClassDescriptor b) { - System.out.println("... is class"); - } - - private void compareFunctions(@NotNull FunctionDescriptor a, @NotNull FunctionDescriptor b) { - Assert.assertEquals(a.getName(), b.getName()); - Assert.assertEquals(a.getValueParameters().size(), b.getValueParameters().size()); - for (int i = 0; i < a.getValueParameters().size(); ++i) { - compareAnything(ValueParameterDescriptor.class, a.getValueParameters().get(i), b.getValueParameters().get(i)); - } - System.out.println("function " + a.getName()); - } - - private void compareAnything(Class clazz, T a, T b) { - System.out.println("Comparing " + clazz); - Assert.assertNotNull(a); - Assert.assertNotNull(b); - - for (Method method : clazz.getMethods()) { - if (!isGetter(method)) { - continue; - } - if (method.getName().equals("getContainingDeclaration")) { - continue; - } - - if (clazz.equals(ValueParameterDescriptor.class)) { - if (method.getName().equals("isRef") || method.getName().equals("getOriginal")) { - continue; - } - } - - System.out.println(method.getName()); - Object ap = invoke(method, a); - Object bp = invoke(method, b); - Assert.assertEquals(ap, bp); - } - } - - private static boolean isGetter(Method method) { - if (method.getParameterTypes().length > 0) { - return false; - } - if (method.getName().matches("is.+")) { - return method.getReturnType().equals(boolean.class); - } else if (method.getName().matches("get.+")) { - return true; - } else { - return false; - } - } - - private static Object invoke(Method method, Object thiz, Object... args) { - try { - return method.invoke(thiz, args); - } catch (Exception e) { - throw new RuntimeException("failed to invoke " + method + ": " + e); - } - } - - public static Test suite() { - return JetTestCaseBuilder.suiteForDirectory(JetTestCaseBuilder.getTestDataPathBase(), "/readClass", true, new JetTestCaseBuilder.NamedTestFactory() { - @NotNull - @Override - public Test createTest(@NotNull String dataPath, @NotNull String name, @NotNull File file) { - return new ReadClassDataTest(file); - } - }); - } - -} From 0d5f507a6c5b17a9e1d3e1303a80dfd0a13564f0 Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Tue, 6 Dec 2011 22:32:07 +0400 Subject: [PATCH 07/15] split Bounds.jet test into smaller tests --- idea/testData/checker/Bounds.jet | 14 -------------- idea/testData/checker/Bounds2.jet | 13 +++++++++++++ 2 files changed, 13 insertions(+), 14 deletions(-) create mode 100644 idea/testData/checker/Bounds2.jet diff --git a/idea/testData/checker/Bounds.jet b/idea/testData/checker/Bounds.jet index 87d5cfa1579..8434607edf8 100644 --- a/idea/testData/checker/Bounds.jet +++ b/idea/testData/checker/Bounds.jet @@ -24,17 +24,3 @@ namespace boundsWithSubstitutors { abstract val x : fun (B<Char>) : B<Any> } - -fun test() { - foo<Int?>() - foo() - bar() - bar() - bar<Double?>() - bar<Double>() - 1.buzz<Double>() -} - -fun foo() {} -fun bar() {} -fun Int> Int.buzz() : Unit {} diff --git a/idea/testData/checker/Bounds2.jet b/idea/testData/checker/Bounds2.jet new file mode 100644 index 00000000000..c53d78acb4b --- /dev/null +++ b/idea/testData/checker/Bounds2.jet @@ -0,0 +1,13 @@ +fun test() { + foo<Int?>() + foo() + bar() + bar() + bar<Double?>() + bar<Double>() + 1.buzz<Double>() +} + +fun foo() {} +fun bar() {} +fun Int> Int.buzz() : Unit {} From d38f1cf8137f76025eb8b0da806c09fb43ae36b8 Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Tue, 6 Dec 2011 22:32:12 +0400 Subject: [PATCH 08/15] temporarily disable java.elementFinder in plugin to continue work on type loader (approved by Andrey) --- idea/src/META-INF/plugin.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 472e7e9f54e..a42a55fc25b 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -59,7 +59,9 @@ + From 6f21de8edc192a57993907d70b18895fe5a2a933 Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Tue, 6 Dec 2011 22:32:17 +0400 Subject: [PATCH 09/15] working on reading class data from .class files --- .../jet/codegen/GenerationState.java | 3 +- .../jet/compiler/CompileEnvironment.java | 2 +- .../resolve/java/JavaDescriptorResolver.java | 34 ++- .../lang/resolve/java/JavaPackageScope.java | 13 +- .../org/jetbrains/jet/JetCoreEnvironment.java | 2 + compiler/testData/readClass/Class.kt | 3 + compiler/testData/readClass/ClassFun.kt | 5 + .../testData/readClass/FunParamNotNull.kt | 3 + .../testData/readClass/FunParamNullable.kt | 3 + compiler/testData/readClass/NsFun.kt | 3 + .../org/jetbrains/jet/ReadClassDataTest.java | 247 ++++++++++++++++++ 11 files changed, 312 insertions(+), 6 deletions(-) create mode 100644 compiler/testData/readClass/Class.kt create mode 100644 compiler/testData/readClass/ClassFun.kt create mode 100644 compiler/testData/readClass/FunParamNotNull.kt create mode 100644 compiler/testData/readClass/FunParamNullable.kt create mode 100644 compiler/testData/readClass/NsFun.kt create mode 100644 compiler/tests/org/jetbrains/jet/ReadClassDataTest.java diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java b/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java index 2a3c0d45b67..e83fd50e11e 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java @@ -82,11 +82,12 @@ public class GenerationState { return factory.forNamespace(namespace); } - public void compile(JetFile psiFile) { + public BindingContext compile(JetFile psiFile) { final JetNamespace namespace = psiFile.getRootNamespace(); final BindingContext bindingContext = AnalyzerFacade.analyzeOneNamespaceWithJavaIntegration(namespace, JetControlFlowDataTraceFactory.EMPTY); AnalyzingUtils.throwExceptionOnErrors(bindingContext); compileCorrectNamespaces(bindingContext, Collections.singletonList(namespace)); + return bindingContext; // NamespaceCodegen codegen = forNamespace(namespace); // bindingContexts.push(bindingContext); // typeMapper = new JetTypeMapper(standardLibrary, bindingContext); diff --git a/compiler/backend/src/org/jetbrains/jet/compiler/CompileEnvironment.java b/compiler/backend/src/org/jetbrains/jet/compiler/CompileEnvironment.java index cf23d5c948b..ba0f2765822 100644 --- a/compiler/backend/src/org/jetbrains/jet/compiler/CompileEnvironment.java +++ b/compiler/backend/src/org/jetbrains/jet/compiler/CompileEnvironment.java @@ -356,7 +356,7 @@ public class CompileEnvironment { } } - private static void writeToOutputDirectory(ClassFileFactory factory, final String outputDir) { + public static void writeToOutputDirectory(ClassFileFactory factory, final String outputDir) { List files = factory.files(); for (String file : files) { if(!skipFile(file)) { diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java index f37b2993d9a..7b581578eb0 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java @@ -332,7 +332,6 @@ public class JavaDescriptorResolver { } private ValueParameterDescriptor resolveParameterDescriptor(DeclarationDescriptor containingDeclaration, int i, PsiParameter parameter) { - String name = parameter.getName(); PsiType psiType = parameter.getType(); JetType varargElementType; @@ -343,14 +342,43 @@ public class JavaDescriptorResolver { else { varargElementType = null; } + + boolean changeNullable = false; + boolean nullable = true; + + // TODO: must be very slow, make it lazy? + String name = parameter.getName() != null ? parameter.getName() : "p" + i; + for (PsiAnnotation annotation : parameter.getModifierList().getAnnotations()) { + // TODO: softcode annotation name + + PsiNameValuePair[] attributes = annotation.getParameterList().getAttributes(); + attributes.toString(); + + if (annotation.getQualifiedName().equals("jet.typeinfo.JetParameter")) { + PsiLiteralExpression nameExpression = (PsiLiteralExpression) annotation.findAttributeValue("name"); + if (nameExpression != null) { + name = (String) nameExpression.getValue(); + } + + PsiLiteralExpression nullableExpression = (PsiLiteralExpression) annotation.findAttributeValue("nullable"); + if (nullableExpression != null) { + nullable = (Boolean) nullableExpression.getValue(); + } else { + // default value of parameter + nullable = false; + changeNullable = true; + } + } + } + JetType outType = semanticServices.getTypeTransformer().transformToType(psiType); return new ValueParameterDescriptorImpl( containingDeclaration, i, Collections.emptyList(), // TODO - name == null ? "p" + i : name, + name, null, // TODO : review - outType, + changeNullable ? TypeUtils.makeNullableAsSpecified(outType, nullable) : outType, false, varargElementType ); diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaPackageScope.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaPackageScope.java index 11b92aee25a..776e5219dfc 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaPackageScope.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaPackageScope.java @@ -1,5 +1,6 @@ package org.jetbrains.jet.lang.resolve.java; +import com.intellij.psi.PsiClass; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.resolve.scopes.JetScopeImpl; @@ -34,7 +35,17 @@ public class JavaPackageScope extends JetScopeImpl { @NotNull @Override public Set getFunctions(@NotNull String name) { - return Collections.emptySet(); + // TODO: what is GlobalSearchScope + PsiClass psiClass = semanticServices.getDescriptorResolver().javaFacade.findClass(packagePrefix + "namespace"); + if (psiClass == null) { + return Collections.emptySet(); + } + + if (containingDescriptor == null) { + return Collections.emptySet(); + } + + return semanticServices.getDescriptorResolver().resolveFunctionGroup(containingDescriptor, psiClass, null, name, true); } @NotNull diff --git a/compiler/frontend/src/org/jetbrains/jet/JetCoreEnvironment.java b/compiler/frontend/src/org/jetbrains/jet/JetCoreEnvironment.java index eac28f341d6..65218c54fcf 100644 --- a/compiler/frontend/src/org/jetbrains/jet/JetCoreEnvironment.java +++ b/compiler/frontend/src/org/jetbrains/jet/JetCoreEnvironment.java @@ -1,6 +1,7 @@ package org.jetbrains.jet; import com.intellij.core.JavaCoreEnvironment; +import com.intellij.lang.java.JavaParserDefinition; import com.intellij.openapi.Disposable; import org.jetbrains.jet.lang.parsing.JetParserDefinition; import org.jetbrains.jet.plugin.JetFileType; @@ -15,6 +16,7 @@ public class JetCoreEnvironment extends JavaCoreEnvironment { registerFileType(JetFileType.INSTANCE, "kts"); registerFileType(JetFileType.INSTANCE, "ktm"); registerFileType(JetFileType.INSTANCE, "jet"); + registerParserDefinition(new JavaParserDefinition()); registerParserDefinition(new JetParserDefinition()); } } diff --git a/compiler/testData/readClass/Class.kt b/compiler/testData/readClass/Class.kt new file mode 100644 index 00000000000..957e3e9c54d --- /dev/null +++ b/compiler/testData/readClass/Class.kt @@ -0,0 +1,3 @@ +namespace test + +class Ramification diff --git a/compiler/testData/readClass/ClassFun.kt b/compiler/testData/readClass/ClassFun.kt new file mode 100644 index 00000000000..27eb0bc5e37 --- /dev/null +++ b/compiler/testData/readClass/ClassFun.kt @@ -0,0 +1,5 @@ +namespace test + +class River { + fun song() = 1 +} diff --git a/compiler/testData/readClass/FunParamNotNull.kt b/compiler/testData/readClass/FunParamNotNull.kt new file mode 100644 index 00000000000..72d84f88278 --- /dev/null +++ b/compiler/testData/readClass/FunParamNotNull.kt @@ -0,0 +1,3 @@ +namespace test + +fun fff(a: String) = 1 diff --git a/compiler/testData/readClass/FunParamNullable.kt b/compiler/testData/readClass/FunParamNullable.kt new file mode 100644 index 00000000000..288582a2f08 --- /dev/null +++ b/compiler/testData/readClass/FunParamNullable.kt @@ -0,0 +1,3 @@ +namespace test + +fun fff(a: String?) = 1 diff --git a/compiler/testData/readClass/NsFun.kt b/compiler/testData/readClass/NsFun.kt new file mode 100644 index 00000000000..6fc14ecc6df --- /dev/null +++ b/compiler/testData/readClass/NsFun.kt @@ -0,0 +1,3 @@ +namespace test + +fun f() = 1 diff --git a/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java b/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java new file mode 100644 index 00000000000..b476555280e --- /dev/null +++ b/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java @@ -0,0 +1,247 @@ +package org.jetbrains.jet; + +import com.intellij.lang.ASTFactory; +import com.intellij.lang.LanguageASTFactory; +import com.intellij.lang.java.JavaLanguage; +import com.intellij.openapi.Disposable; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.vfs.CharsetToolkit; +import com.intellij.psi.PsiFileFactory; +import com.intellij.psi.impl.PsiFileFactoryImpl; +import com.intellij.psi.impl.source.tree.JavaASTFactory; +import com.intellij.testFramework.LightVirtualFile; +import com.intellij.testFramework.UsefulTestCase; +import junit.framework.Test; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.codegen.ClassBuilderFactory; +import org.jetbrains.jet.codegen.ClassFileFactory; +import org.jetbrains.jet.codegen.GenerationState; +import org.jetbrains.jet.compiler.CompileEnvironment; +import org.jetbrains.jet.lang.JetSemanticServices; +import org.jetbrains.jet.lang.descriptors.ClassDescriptor; +import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor; +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; +import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; +import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; +import org.jetbrains.jet.lang.psi.JetFile; +import org.jetbrains.jet.lang.resolve.AnalyzingUtils; +import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.BindingTraceContext; +import org.jetbrains.jet.lang.resolve.java.JavaDescriptorResolver; +import org.jetbrains.jet.lang.resolve.java.JavaSemanticServices; +import org.jetbrains.jet.plugin.JetLanguage; +import org.junit.Assert; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Set; + +/** + * @author Stepan Koltsov + */ +public class ReadClassDataTest extends UsefulTestCase { + + protected final Disposable myTestRootDisposable = new Disposable() { + @Override + public void dispose() { + } + }; + + private JetCoreEnvironment jetCoreEnvironment; + private File tmpdir; + + private final File testFile; + + public ReadClassDataTest(@NotNull File testFile) { + this.testFile = testFile; + setName(testFile.getName()); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + tmpdir = new File("tmp/" + this.getClass().getSimpleName() + "." + this.getName()); + rmrf(tmpdir); + mkdirs(tmpdir); + } + + @Override + public void tearDown() throws Exception { + Disposer.dispose(myTestRootDisposable); + } + + private void mkdirs(File file) throws IOException { + if (file.isDirectory()) { + return; + } + if (!file.mkdirs()) { + throw new IOException(); + } + } + + private void rmrf(File file) { + if (file != null) { + File[] children = file.listFiles(); + if (children != null) { + for (File child : children) { + rmrf(child); + } + } + file.delete(); + } + } + + private void createMockCoreEnvironment() { + jetCoreEnvironment = new JetCoreEnvironment(myTestRootDisposable); + + final File rtJar = new File(JetTestCaseBuilder.getHomeDirectory(), "compiler/testData/mockJDK-1.7/jre/lib/rt.jar"); + jetCoreEnvironment.addToClasspath(rtJar); + jetCoreEnvironment.addToClasspath(new File(JetTestCaseBuilder.getHomeDirectory(), "compiler/testData/mockJDK-1.7/jre/lib/annotations.jar")); + } + + @Override + public void runTest() throws Exception { + if (true) return; + + createMockCoreEnvironment(); + + LanguageASTFactory.INSTANCE.addExplicitExtension(JavaLanguage.INSTANCE, new JavaASTFactory()); + + + String text = FileUtil.loadFile(testFile); + + LightVirtualFile virtualFile = new LightVirtualFile("Hello.kt", JetLanguage.INSTANCE, text); + virtualFile.setCharset(CharsetToolkit.UTF8_CHARSET); + JetFile psiFile = (JetFile) ((PsiFileFactoryImpl) PsiFileFactory.getInstance(jetCoreEnvironment.getProject())).trySetupPsiForFile(virtualFile, JetLanguage.INSTANCE, true, false); + + GenerationState state = new GenerationState(jetCoreEnvironment.getProject(), ClassBuilderFactory.BINARIES); + AnalyzingUtils.checkForSyntacticErrors(psiFile); + BindingContext bindingContext = state.compile(psiFile); + + ClassFileFactory classFileFactory = state.getFactory(); + + CompileEnvironment.writeToOutputDirectory(classFileFactory, tmpdir.getPath()); + + NamespaceDescriptor namespaceFromSource = (NamespaceDescriptor) bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, psiFile.getRootNamespace()); + + Assert.assertEquals("test", namespaceFromSource.getName()); + + Disposer.dispose(myTestRootDisposable); + + + + createMockCoreEnvironment(); + + jetCoreEnvironment.addToClasspath(tmpdir); + + JetSemanticServices jetSemanticServices = JetSemanticServices.createSemanticServices(jetCoreEnvironment.getProject()); + JavaSemanticServices semanticServices = new JavaSemanticServices(jetCoreEnvironment.getProject(), jetSemanticServices, new BindingTraceContext()); + + JavaDescriptorResolver javaDescriptorResolver = semanticServices.getDescriptorResolver(); + NamespaceDescriptor namespaceFromClass = javaDescriptorResolver.resolveNamespace("test"); + + compareNamespaces(namespaceFromSource, namespaceFromClass); + } + + private void compareNamespaces(@NotNull NamespaceDescriptor nsa, @NotNull NamespaceDescriptor nsb) { + Assert.assertEquals(nsa.getName(), nsb.getName()); + System.out.println("namespace " + nsa.getName()); + for (DeclarationDescriptor ad : nsa.getMemberScope().getAllDescriptors()) { + if (ad instanceof ClassifierDescriptor) { + ClassifierDescriptor bd = nsb.getMemberScope().getClassifier(ad.getName()); + compareClassifiers((ClassifierDescriptor) ad, bd); + } else if (ad instanceof FunctionDescriptor) { + Set functions = nsb.getMemberScope().getFunctions(ad.getName()); + Assert.assertTrue(functions.size() >= 1); + Assert.assertTrue("not implemented", functions.size() == 1); + FunctionDescriptor bd = functions.iterator().next(); + compareFunctions((FunctionDescriptor) ad, bd); + } else { + throw new AssertionError("Unknown member: " + ad); + } + } + } + + private void compareClassifiers(@NotNull ClassifierDescriptor a, @NotNull ClassifierDescriptor b) { + Assert.assertEquals(a.getName(), b.getName()); + System.out.println("classifier " + a.getName()); + if (a instanceof ClassDescriptor || b instanceof ClassDescriptor) { + compareClasses((ClassDescriptor) a, (ClassDescriptor) b); + } + } + + private void compareClasses(@NotNull ClassDescriptor a, @NotNull ClassDescriptor b) { + System.out.println("... is class"); + } + + private void compareFunctions(@NotNull FunctionDescriptor a, @NotNull FunctionDescriptor b) { + Assert.assertEquals(a.getName(), b.getName()); + Assert.assertEquals(a.getValueParameters().size(), b.getValueParameters().size()); + for (int i = 0; i < a.getValueParameters().size(); ++i) { + compareAnything(ValueParameterDescriptor.class, a.getValueParameters().get(i), b.getValueParameters().get(i)); + } + System.out.println("function " + a.getName()); + } + + private void compareAnything(Class clazz, T a, T b) { + System.out.println("Comparing " + clazz); + Assert.assertNotNull(a); + Assert.assertNotNull(b); + + for (Method method : clazz.getMethods()) { + if (!isGetter(method)) { + continue; + } + if (method.getName().equals("getContainingDeclaration")) { + continue; + } + + if (clazz.equals(ValueParameterDescriptor.class)) { + if (method.getName().equals("isRef") || method.getName().equals("getOriginal")) { + continue; + } + } + + System.out.println(method.getName()); + Object ap = invoke(method, a); + Object bp = invoke(method, b); + Assert.assertEquals(ap, bp); + } + } + + private static boolean isGetter(Method method) { + if (method.getParameterTypes().length > 0) { + return false; + } + if (method.getName().matches("is.+")) { + return method.getReturnType().equals(boolean.class); + } else if (method.getName().matches("get.+")) { + return true; + } else { + return false; + } + } + + private static Object invoke(Method method, Object thiz, Object... args) { + try { + return method.invoke(thiz, args); + } catch (Exception e) { + throw new RuntimeException("failed to invoke " + method + ": " + e); + } + } + + public static Test suite() { + return JetTestCaseBuilder.suiteForDirectory(JetTestCaseBuilder.getTestDataPathBase(), "/readClass", true, new JetTestCaseBuilder.NamedTestFactory() { + @NotNull + @Override + public Test createTest(@NotNull String dataPath, @NotNull String name, @NotNull File file) { + return new ReadClassDataTest(file); + } + }); + } + +} From ec55dddfcd91d864018665501e52927c0a03beb8 Mon Sep 17 00:00:00 2001 From: svtk Date: Tue, 6 Dec 2011 22:41:19 +0400 Subject: [PATCH 10/15] backing fields resolve changed KT-462 Consider allowing initializing properties via property names when it is safe KT-598 Allow to use backing fields after this expression --- .../jet/lang/cfg/JetControlFlowProcessor.java | 11 ++ .../lang/cfg/JetFlowInformationProvider.java | 179 ++++++++++++------ .../descriptors/MutableClassDescriptor.java | 3 +- .../jet/lang/diagnostics/Errors.java | 9 +- .../jetbrains/jet/lang/psi/JetPsiUtil.java | 6 +- .../jet/lang/resolve/BodyResolver.java | 55 ++---- .../jet/lang/resolve/DeclarationsChecker.java | 3 +- .../jet/lang/resolve/calls/CallResolver.java | 10 +- .../lang/resolve/calls/TaskPrioritizers.java | 38 +++- .../lang/resolve/scopes/WritableScope.java | 2 - .../resolve/scopes/WritableScopeImpl.java | 11 -- .../resolve/scopes/WriteThroughScope.java | 7 - .../BasicExpressionTypingVisitor.java | 17 +- .../ExpressionTypingVisitorForStatements.java | 11 +- .../tests/AnonymousInitializers.jet | 2 +- .../testData/diagnostics/tests/Properties.jet | 14 +- .../UninitializedOrReassignedVariables.jet | 10 +- .../tests/backingField/ReadInFunction.jet | 2 +- ...NonexistentAbstractPropertyInAnonymous.jet | 4 +- ...dNonexistentAbstractPropertyInFunction.jet | 4 +- .../ReadNonexistentCustomGetInAnonymous.jet | 4 +- ...nexistentCustomGetInAnotherInitializer.jet | 4 +- .../ReadNonexistentDeclaredInHigher.jet | 13 +- .../WriteNonexistentDeclaredInHigher.jet | 4 +- .../kt462BackingFieldsResolve.jet | 172 +++++++++++++++++ .../tests/control-flow-analysis/kt510.jet | 4 +- .../jet/plugin/quickfix/AddModifierFix.java | 2 +- .../quickfix/ChangeToBackingFieldFix.java | 7 +- .../quickfix/ChangeVariableMutabilityFix.java | 7 +- .../jet/plugin/quickfix/QuickFixes.java | 6 +- .../plugin/quickfix/RemoveModifierFix.java | 2 +- idea/testData/checker/Properties.jet | 4 +- .../changeToBackingField/afterBFRequired.kt | 3 +- .../changeToBackingField/afterKt510.kt | 3 +- .../changeToBackingField/beforeBFRequired.kt | 3 +- .../changeToBackingField/beforeKt510.kt | 1 + 36 files changed, 422 insertions(+), 215 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/backingField/kt462BackingFieldsResolve.jet diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java index 7b1945f9351..e0a035d9b0b 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java @@ -821,6 +821,9 @@ public class JetControlFlowProcessor { } private void visitClassOrObject(JetClassOrObject classOrObject) { + for (JetDelegationSpecifier specifier : classOrObject.getDelegationSpecifiers()) { + value(specifier, inCondition); + } List declarations = classOrObject.getDeclarations(); List properties = Lists.newArrayList(); for (JetDeclaration declaration : declarations) { @@ -839,6 +842,14 @@ public class JetControlFlowProcessor { visitClassOrObject(klass); } + @Override + public void visitDelegationToSuperCallSpecifier(JetDelegatorToSuperCall call) { + List valueArguments = call.getValueArguments(); + for (ValueArgument valueArgument : valueArguments) { + value(valueArgument.getArgumentExpression(), inCondition); + } + } + @Override public void visitJetElement(JetElement element) { builder.unsupported(element); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java index 4c260399c57..4f7166c0425 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java @@ -6,11 +6,11 @@ import com.google.common.collect.Sets; import com.intellij.openapi.util.Pair; import com.intellij.psi.PsiElement; import com.intellij.psi.tree.IElementType; +import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.cfg.pseudocode.*; import org.jetbrains.jet.lang.descriptors.*; -import org.jetbrains.jet.lang.descriptors.VariableDescriptor; import org.jetbrains.jet.lang.diagnostics.Errors; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; @@ -223,22 +223,24 @@ public class JetFlowInformationProvider { @Override public void execute(Instruction instruction, @Nullable Map enterData, @Nullable Map exitData) { assert enterData != null && exitData != null; + VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction, true); + if (variableDescriptor == null) return; if (instruction instanceof ReadValueInstruction) { - VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction, false); - if (variableDescriptor != null && declaredVariables.contains(variableDescriptor)) { - checkIsInitialized(variableDescriptor, ((ReadValueInstruction) instruction).getElement(), exitData.get(variableDescriptor), varWithUninitializedErrorGenerated); + JetElement element = ((ReadValueInstruction) instruction).getElement(); + boolean error = checkBackingField(variableDescriptor, element); + if (!error && declaredVariables.contains(variableDescriptor)) { + checkIsInitialized(variableDescriptor, element, exitData.get(variableDescriptor), varWithUninitializedErrorGenerated); } } else if (instruction instanceof WriteValueInstruction) { - VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction, true); JetElement element = ((WriteValueInstruction) instruction).getlValue(); - if (variableDescriptor != null && element instanceof JetExpression) { - if (!processLocalDeclaration) { // error has been generated before while processing outer function of this local declaration - checkValReassignment(variableDescriptor, (JetExpression) element, enterData.get(variableDescriptor), varWithValReassignErrorGenerated); - } - if (processClassOrObject) { - checkInitializationUsingBackingField(variableDescriptor, (JetExpression) element, enterData.get(variableDescriptor), exitData.get(variableDescriptor)); - } + boolean error = checkBackingField(variableDescriptor, element); + if (!(element instanceof JetExpression)) return; + if (!error && !processLocalDeclaration) { // error has been generated before while processing outer function of this local declaration + error = checkValReassignment(variableDescriptor, (JetExpression) element, enterData.get(variableDescriptor), varWithValReassignErrorGenerated); + } + if (!error && processClassOrObject) { + checkInitializationUsingBackingField(variableDescriptor, (JetExpression) element, enterData.get(variableDescriptor), exitData.get(variableDescriptor)); } } } @@ -263,7 +265,7 @@ public class JetFlowInformationProvider { } } - private void checkValReassignment(@NotNull VariableDescriptor variableDescriptor, @NotNull JetExpression expression, @NotNull VariableInitializers enterInitializers, @NotNull Collection varWithValReassignErrorGenerated) { + private boolean checkValReassignment(@NotNull VariableDescriptor variableDescriptor, @NotNull JetExpression expression, @NotNull VariableInitializers enterInitializers, @NotNull Collection varWithValReassignErrorGenerated) { boolean isInitializedNotHere = enterInitializers.isInitialized(); Set possibleLocalInitializers = enterInitializers.getPossibleLocalInitializers(); if (possibleLocalInitializers.size() == 1) { @@ -298,12 +300,19 @@ public class JetFlowInformationProvider { } if (!hasReassignMethodReturningUnit) { trace.report(Errors.VAL_REASSIGNMENT.on(expression, variableDescriptor)); + return true; } } + return false; } private void checkInitializationUsingBackingField(@NotNull VariableDescriptor variableDescriptor, @NotNull JetExpression expression, @NotNull VariableInitializers enterInitializers, @NotNull VariableInitializers exitInitializers) { if (variableDescriptor instanceof PropertyDescriptor && !enterInitializers.isInitialized() && exitInitializers.isInitialized()) { + if (!variableDescriptor.isVar()) return; + if (!trace.get(BindingContext.BACKING_FIELD_REQUIRED, (PropertyDescriptor) variableDescriptor)) return; + PsiElement property = trace.get(BindingContext.DESCRIPTOR_TO_DECLARATION, variableDescriptor); + assert property instanceof JetProperty; + if (((PropertyDescriptor) variableDescriptor).getModality() == Modality.FINAL && ((JetProperty) property).getSetter() == null) return; JetExpression variable = expression; if (expression instanceof JetDotQualifiedExpression) { if (((JetDotQualifiedExpression) expression).getReceiverExpression() instanceof JetThisExpression) { @@ -313,12 +322,63 @@ public class JetFlowInformationProvider { if (variable instanceof JetSimpleNameExpression) { JetSimpleNameExpression simpleNameExpression = (JetSimpleNameExpression) variable; if (simpleNameExpression.getReferencedNameElementType() != JetTokens.FIELD_IDENTIFIER) { - trace.report(Errors.INITIALIZATION_USING_BACKING_FIELD.on(simpleNameExpression, expression, variableDescriptor)); + if (((PropertyDescriptor) variableDescriptor).getModality() != Modality.FINAL) { + trace.report(Errors.INITIALIZATION_USING_BACKING_FIELD_OPEN_SETTER.on(simpleNameExpression, expression, variableDescriptor)); + } + else { + trace.report(Errors.INITIALIZATION_USING_BACKING_FIELD_CUSTOM_SETTER.on(simpleNameExpression, expression, variableDescriptor)); + } } } } } + private boolean checkBackingField(@NotNull VariableDescriptor variableDescriptor, @NotNull JetElement element) { + boolean[] error = new boolean[1]; + if (isBackingFieldReference((JetElement) element.getParent(), error, false)) return false; // this expression has been already checked + if (!isBackingFieldReference(element, error, true)) return false; + if (error[0]) return true; + if (!(variableDescriptor instanceof PropertyDescriptor)) { + trace.report(Errors.NOT_PROPERTY_BACKING_FIELD.on(element)); + return true; + } + PsiElement property = trace.get(BindingContext.DESCRIPTOR_TO_DECLARATION, variableDescriptor); + if (!trace.get(BindingContext.BACKING_FIELD_REQUIRED, (PropertyDescriptor) variableDescriptor) && + !PsiTreeUtil.isAncestor(property, element, false)) { // not to generate error in accessors of abstract properties, there is one: declared accessor of abstract property + if (((PropertyDescriptor) variableDescriptor).getModality() == Modality.ABSTRACT) { + trace.report(NO_BACKING_FIELD_ABSTRACT_PROPERTY.on(element)); + } + else { + trace.report(NO_BACKING_FIELD_CUSTOM_ACCESSORS.on(element)); + } + return true; + } + + JetClassOrObject propertyClassOrObject = PsiTreeUtil.getParentOfType(property, JetClassOrObject.class); + if (propertyClassOrObject == null || !PsiTreeUtil.isAncestor(propertyClassOrObject, element, false)) { + trace.report(Errors.INACCESSIBLE_BACKING_FIELD.on(element)); + return true; + } + return false; + } + + private boolean isBackingFieldReference(@Nullable JetElement element, boolean[] error, boolean reportError) { + error[0] = false; + if (element instanceof JetSimpleNameExpression && ((JetSimpleNameExpression) element).getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER) { + return true; + } + if (element instanceof JetDotQualifiedExpression && isBackingFieldReference(((JetDotQualifiedExpression) element).getSelectorExpression(), error, false)) { + if (((JetDotQualifiedExpression) element).getReceiverExpression() instanceof JetThisExpression) { + return true; + } + error[0] = true; + if (reportError) { + trace.report(Errors.INACCESSIBLE_BACKING_FIELD.on(element)); + } + } + return false; + } + private void recordInitializedVariables(Collection declaredVariables, Map resultInfo) { for (Map.Entry entry : resultInfo.entrySet()) { VariableDescriptor variable = entry.getKey(); @@ -456,58 +516,55 @@ public class JetFlowInformationProvider { public void execute(Instruction instruction, @Nullable Map enterData, @Nullable Map exitData) { assert enterData != null && exitData != null; VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction, false); - if (variableDescriptor != null && declaredVariables.contains(variableDescriptor)) { - PsiElement variableDeclarationElement = trace.get(BindingContext.DESCRIPTOR_TO_DECLARATION, variableDescriptor); - assert variableDeclarationElement instanceof JetDeclaration; - boolean isLocal = JetPsiUtil.isLocal((JetDeclaration) variableDeclarationElement); - if (isLocal) { - if (instruction instanceof WriteValueInstruction) { - JetElement element = ((WriteValueInstruction) instruction).getElement(); - if (enterData.get(variableDescriptor) == VariableStatus.WRITTEN || enterData.get(variableDescriptor) == VariableStatus.UNUSED) { - if (element instanceof JetBinaryExpression && ((JetBinaryExpression) element).getOperationToken() == JetTokens.EQ) { - JetExpression right = ((JetBinaryExpression) element).getRight(); - if (right != null) { - trace.report(Errors.UNUSED_VALUE.on(right, right, variableDescriptor)); - } - } - else if (element instanceof JetPostfixExpression) { - IElementType operationToken = ((JetPostfixExpression) element).getOperationSign().getReferencedNameElementType(); - if (operationToken == JetTokens.PLUSPLUS || operationToken == JetTokens.MINUSMINUS) { - trace.report(Errors.UNUSED_CHANGED_VALUE.on(element, element)); - } - } + if (variableDescriptor == null || !declaredVariables.contains(variableDescriptor)) return; + PsiElement variableDeclarationElement = trace.get(BindingContext.DESCRIPTOR_TO_DECLARATION, variableDescriptor); + assert variableDeclarationElement instanceof JetDeclaration; + if (!JetPsiUtil.isLocal((JetDeclaration) variableDeclarationElement)) return; + if (instruction instanceof WriteValueInstruction) { + JetElement element = ((WriteValueInstruction) instruction).getElement(); + if (enterData.get(variableDescriptor) == VariableStatus.WRITTEN || enterData.get(variableDescriptor) == VariableStatus.UNUSED) { + if (element instanceof JetBinaryExpression && ((JetBinaryExpression) element).getOperationToken() == JetTokens.EQ) { + JetExpression right = ((JetBinaryExpression) element).getRight(); + if (right != null) { + trace.report(Errors.UNUSED_VALUE.on(right, right, variableDescriptor)); } - } - else if (instruction instanceof VariableDeclarationInstruction) { - JetDeclaration element = ((VariableDeclarationInstruction) instruction).getVariableDeclarationElement(); - if (element instanceof JetNamedDeclaration) { - PsiElement nameIdentifier = ((JetNamedDeclaration) element).getNameIdentifier(); - PsiElement elementToMark = nameIdentifier != null ? nameIdentifier : element; - if (enterData.get(variableDescriptor) == VariableStatus.UNUSED) { - if (element instanceof JetProperty) { - trace.report(Errors.UNUSED_VARIABLE.on((JetProperty) element, elementToMark, variableDescriptor)); - } - else if (element instanceof JetParameter) { - PsiElement psiElement = element.getParent().getParent(); - if (psiElement instanceof JetFunction) { - boolean isMain = (psiElement instanceof JetNamedFunction) && JetMainDetector.isMain((JetNamedFunction) psiElement); - DeclarationDescriptor descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, psiElement); - assert descriptor instanceof FunctionDescriptor; - FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor; - if (!isMain && !functionDescriptor.getModality().isOverridable() && functionDescriptor.getOverriddenDescriptors().isEmpty()) { - trace.report(Errors.UNUSED_PARAMETER.on((JetParameter) element, elementToMark, variableDescriptor)); - } - } - } - } - else if (enterData.get(variableDescriptor) == VariableStatus.WRITTEN && element instanceof JetProperty) { - trace.report(Errors.ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE.on((JetNamedDeclaration) element, elementToMark, variableDescriptor)); - } + } + else if (element instanceof JetPostfixExpression) { + IElementType operationToken = ((JetPostfixExpression) element).getOperationSign().getReferencedNameElementType(); + if (operationToken == JetTokens.PLUSPLUS || operationToken == JetTokens.MINUSMINUS) { + trace.report(Errors.UNUSED_CHANGED_VALUE.on(element, element)); } - } } } + else if (instruction instanceof VariableDeclarationInstruction) { + JetDeclaration element = ((VariableDeclarationInstruction) instruction).getVariableDeclarationElement(); + if (element instanceof JetNamedDeclaration) { + PsiElement nameIdentifier = ((JetNamedDeclaration) element).getNameIdentifier(); + PsiElement elementToMark = nameIdentifier != null ? nameIdentifier : element; + if (enterData.get(variableDescriptor) == VariableStatus.UNUSED) { + if (element instanceof JetProperty) { + trace.report(Errors.UNUSED_VARIABLE.on((JetProperty) element, elementToMark, variableDescriptor)); + } + else if (element instanceof JetParameter) { + PsiElement psiElement = element.getParent().getParent(); + if (psiElement instanceof JetFunction) { + boolean isMain = (psiElement instanceof JetNamedFunction) && JetMainDetector.isMain((JetNamedFunction) psiElement); + DeclarationDescriptor descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, psiElement); + assert descriptor instanceof FunctionDescriptor; + FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor; + if (!isMain && !functionDescriptor.getModality().isOverridable() && functionDescriptor.getOverriddenDescriptors().isEmpty()) { + trace.report(Errors.UNUSED_PARAMETER.on((JetParameter) element, elementToMark, variableDescriptor)); + } + } + } + } + else if (enterData.get(variableDescriptor) == VariableStatus.WRITTEN && element instanceof JetProperty) { + trace.report(Errors.ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE.on((JetNamedDeclaration) element, elementToMark, variableDescriptor)); + } + } + + } } }); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptor.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptor.java index 5590bcda559..3d80086d425 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptor.java @@ -52,7 +52,7 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme this.scopeForMemberLookup = new WritableScopeImpl(JetScope.EMPTY, this, redeclarationHandler).setDebugName("MemberLookup").changeLockLevel(WritableScope.LockLevel.BOTH); this.scopeForSupertypeResolution = new WritableScopeImpl(outerScope, this, redeclarationHandler).setDebugName("SupertypeResolution").changeLockLevel(WritableScope.LockLevel.BOTH); this.scopeForMemberResolution = new WritableScopeImpl(scopeForSupertypeResolution, this, redeclarationHandler).setDebugName("MemberResolution").changeLockLevel(WritableScope.LockLevel.BOTH); - this.scopeForInitializers = new WritableScopeImpl(scopeForMemberResolution, this, redeclarationHandler).setDebugName("PropertyInitializers").changeLockLevel(WritableScope.LockLevel.BOTH); + this.scopeForInitializers = new WritableScopeImpl(scopeForMemberResolution, this, redeclarationHandler).setDebugName("Initializers").changeLockLevel(WritableScope.LockLevel.BOTH); this.kind = kind; } @@ -137,7 +137,6 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme callableMembers.add(propertyDescriptor); scopeForMemberLookup.addVariableDescriptor(propertyDescriptor); scopeForMemberResolution.addVariableDescriptor(propertyDescriptor); - scopeForInitializers.addPropertyDescriptorByFieldName("$" + propertyDescriptor.getName(), propertyDescriptor); } @Override diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java index 786acc783b2..1a91ce479d5 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java @@ -84,7 +84,11 @@ public interface Errors { SimpleDiagnosticFactory CANNOT_INFER_PARAMETER_TYPE = SimpleDiagnosticFactory.create(ERROR, "Cannot infer a type for this parameter. To specify it explicitly use the {(p : Type) => ...} notation"); - SimpleDiagnosticFactory NO_BACKING_FIELD = SimpleDiagnosticFactory.create(ERROR, "This property does not have a backing field"); + SimpleDiagnosticFactory NO_BACKING_FIELD_ABSTRACT_PROPERTY = SimpleDiagnosticFactory.create(ERROR, "This property doesn't have a backing field, because it's abstract"); + SimpleDiagnosticFactory NO_BACKING_FIELD_CUSTOM_ACCESSORS = SimpleDiagnosticFactory.create(ERROR, "This property doesn't have a backing field, because it has custom accessors without reference to the backing field"); + SimpleDiagnosticFactory INACCESSIBLE_BACKING_FIELD = SimpleDiagnosticFactory.create(ERROR, "The backing field is not accessible here"); + SimpleDiagnosticFactory NOT_PROPERTY_BACKING_FIELD = SimpleDiagnosticFactory.create(ERROR, "The referenced variable is not a property and doesn't have backing field"); + SimpleDiagnosticFactory MIXING_NAMED_AND_POSITIONED_ARGUMENTS = SimpleDiagnosticFactory.create(ERROR, "Mixing named and positioned arguments in not allowed"); SimpleDiagnosticFactory ARGUMENT_PASSED_TWICE = SimpleDiagnosticFactory.create(ERROR, "An argument is already passed for this parameter"); UnresolvedReferenceDiagnosticFactory NAMED_PARAMETER_NOT_FOUND = new UnresolvedReferenceDiagnosticFactory("Cannot find a parameter with this name");//SimpleDiagnosticFactory.create(ERROR, "Cannot find a parameter with this name"); @@ -166,7 +170,8 @@ public interface Errors { PsiElementOnlyDiagnosticFactory1 VAL_REASSIGNMENT = PsiElementOnlyDiagnosticFactory1.create(ERROR, "Val can not be reassigned", NAME); SimplePsiElementOnlyDiagnosticFactory VARIABLE_EXPECTED = new SimplePsiElementOnlyDiagnosticFactory(ERROR, "Variable expected"); - PsiElementOnlyDiagnosticFactory1 INITIALIZATION_USING_BACKING_FIELD = PsiElementOnlyDiagnosticFactory1.create(ERROR, "Initialization using backing field required", NAME); + PsiElementOnlyDiagnosticFactory1 INITIALIZATION_USING_BACKING_FIELD_CUSTOM_SETTER = PsiElementOnlyDiagnosticFactory1.create(ERROR, "This property has a custom setter, so initialization using backing field required", NAME); + PsiElementOnlyDiagnosticFactory1 INITIALIZATION_USING_BACKING_FIELD_OPEN_SETTER = PsiElementOnlyDiagnosticFactory1.create(ERROR, "Setter of this property can be overridden, so initialization using backing field required", NAME); PsiElementOnlyDiagnosticFactory1 FUNCTION_PARAMETERS_OF_INLINE_FUNCTION = PsiElementOnlyDiagnosticFactory1.create(ERROR, "Function parameters of inline function can only be invoked", NAME); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java index bdd55b0b25e..8afc13f7b0f 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java @@ -104,9 +104,9 @@ public class JetPsiUtil { } } - public static boolean isLocal(@NotNull JetDeclaration declaration) { - JetClassOrObject classOrObject = PsiTreeUtil.getParentOfType(declaration, JetClassOrObject.class); - JetDeclarationWithBody function = PsiTreeUtil.getParentOfType(declaration, JetDeclarationWithBody.class); + public static boolean isLocal(@NotNull JetElement element) { + JetClassOrObject classOrObject = PsiTreeUtil.getParentOfType(element, JetClassOrObject.class); + JetDeclarationWithBody function = PsiTreeUtil.getParentOfType(element, JetDeclarationWithBody.class); if (function != null && PsiTreeUtil.isAncestor(classOrObject, function, false)) { return true; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java index db12d3887a8..81e0f647999 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java @@ -34,41 +34,11 @@ import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE; public class BodyResolver { private final TopDownAnalysisContext context; - private final ObservableBindingTrace traceForConstructors; - private final ObservableBindingTrace traceForMembers; + private final ObservableBindingTrace trace; public BodyResolver(TopDownAnalysisContext context) { this.context = context; - - // This allows access to backing fields - this.traceForConstructors = new ObservableBindingTrace(context.getTrace()).addHandler(BindingContext.REFERENCE_TARGET, new ObservableBindingTrace.RecordHandler() { - @Override - public void handleRecord(WritableSlice slice, JetReferenceExpression expression, DeclarationDescriptor descriptor) { - if (expression instanceof JetSimpleNameExpression) { - JetSimpleNameExpression simpleNameExpression = (JetSimpleNameExpression) expression; - if (simpleNameExpression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER) { - if (!BodyResolver.this.context.getTrace().getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, (PropertyDescriptor) descriptor)) { - BodyResolver.this.context.getTrace().report(NO_BACKING_FIELD.on(expression)); - } - } - } - } - }); - - // This tracks access to properties in order to register primary constructor parameters that yield real fields (JET-9) - // NOTE!!! This code is not used, because we do not allow constructor parameter access in member bodies - this.traceForMembers = new ObservableBindingTrace(context.getTrace()).addHandler(BindingContext.REFERENCE_TARGET, new ObservableBindingTrace.RecordHandler() { - @Override - public void handleRecord(WritableSlice slice, JetReferenceExpression expression, DeclarationDescriptor descriptor) { - if (descriptor instanceof PropertyDescriptor) { - PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor; - if (BodyResolver.this.context.getPrimaryConstructorParameterProperties().contains(propertyDescriptor)) { - traceForMembers.record(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor); - } - } - } - }); - + this.trace = context.getTrace(); } public void resolveBehaviorDeclarationBodies() { @@ -100,8 +70,8 @@ public class BodyResolver { final ConstructorDescriptor primaryConstructor = descriptor.getUnsubstitutedPrimaryConstructor(); final JetScope scopeForConstructor = primaryConstructor == null ? null - : FunctionDescriptorUtil.getFunctionInnerScope(descriptor.getScopeForSupertypeResolution(), primaryConstructor, traceForConstructors); - final ExpressionTypingServices typeInferrer = context.getSemanticServices().getTypeInferrerServices(traceForConstructors); // TODO : flow + : FunctionDescriptorUtil.getFunctionInnerScope(descriptor.getScopeForSupertypeResolution(), primaryConstructor, trace); + final ExpressionTypingServices typeInferrer = context.getSemanticServices().getTypeInferrerServices(trace); // TODO : flow final Map supertypes = Maps.newLinkedHashMap(); JetVisitorVoid visitor = new JetVisitorVoid() { @@ -268,7 +238,7 @@ public class BodyResolver { ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor(); assert primaryConstructor != null; final JetScope scopeForInitializers = classDescriptor.getScopeForInitializers(); - ExpressionTypingServices typeInferrer = context.getSemanticServices().getTypeInferrerServices(traceForConstructors); + ExpressionTypingServices typeInferrer = context.getSemanticServices().getTypeInferrerServices(trace); for (JetClassInitializer anonymousInitializer : anonymousInitializers) { typeInferrer.getType(scopeForInitializers, anonymousInitializer.getBody(), NO_EXPECTED_TYPE); } @@ -294,9 +264,9 @@ public class BodyResolver { private void resolveSecondaryConstructorBody(JetSecondaryConstructor declaration, final ConstructorDescriptor descriptor) { if (!context.completeAnalysisNeeded(declaration)) return; MutableClassDescriptor classDescriptor = (MutableClassDescriptor) descriptor.getContainingDeclaration(); - final JetScope scopeForSupertypeInitializers = FunctionDescriptorUtil.getFunctionInnerScope(classDescriptor.getScopeForSupertypeResolution(), descriptor, traceForConstructors); + final JetScope scopeForSupertypeInitializers = FunctionDescriptorUtil.getFunctionInnerScope(classDescriptor.getScopeForSupertypeResolution(), descriptor, trace); //contains only constructor parameters - final JetScope scopeForConstructorBody = FunctionDescriptorUtil.getFunctionInnerScope(classDescriptor.getScopeForInitializers(), descriptor, traceForConstructors); + final JetScope scopeForConstructorBody = FunctionDescriptorUtil.getFunctionInnerScope(classDescriptor.getScopeForInitializers(), descriptor, trace); //contains members & backing fields final CallResolver callResolver = new CallResolver(context.getSemanticServices(), DataFlowInfo.EMPTY); // TODO: dataFlowInfo @@ -360,7 +330,7 @@ public class BodyResolver { } JetExpression bodyExpression = declaration.getBodyExpression(); if (bodyExpression != null) { - ExpressionTypingServices typeInferrer = context.getSemanticServices().getTypeInferrerServices(traceForConstructors); + ExpressionTypingServices typeInferrer = context.getSemanticServices().getTypeInferrerServices(trace); typeInferrer.checkFunctionReturnType(scopeForConstructorBody, declaration, JetStandardClasses.getUnitType()); } @@ -417,7 +387,6 @@ public class BodyResolver { JetScope propertyDeclarationInnerScope = context.getDescriptorResolver().getPropertyDeclarationInnerScope( declaringScope, propertyDescriptor, propertyDescriptor.getTypeParameters(), propertyDescriptor.getReceiverParameter()); WritableScope accessorScope = new WritableScopeImpl(propertyDeclarationInnerScope, declaringScope.getContainingDeclaration(), new TraceBasedRedeclarationHandler(context.getTrace())).setDebugName("Accessor scope"); - accessorScope.addPropertyDescriptorByFieldName("$" + propertyDescriptor.getName(), propertyDescriptor); accessorScope.changeLockLevel(WritableScope.LockLevel.READING); return accessorScope; @@ -442,7 +411,7 @@ public class BodyResolver { } private ObservableBindingTrace createFieldTrackingTrace(final PropertyDescriptor propertyDescriptor) { - return new ObservableBindingTrace(traceForMembers).addHandler(BindingContext.REFERENCE_TARGET, new ObservableBindingTrace.RecordHandler() { + return new ObservableBindingTrace(trace).addHandler(BindingContext.REFERENCE_TARGET, new ObservableBindingTrace.RecordHandler() { @Override public void handleRecord(WritableSlice slice, JetReferenceExpression expression, DeclarationDescriptor descriptor) { if (expression instanceof JetSimpleNameExpression) { @@ -450,7 +419,7 @@ public class BodyResolver { if (simpleNameExpression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER) { // This check may be considered redundant as long as $x is only accessible from accessors to $x if (descriptor == propertyDescriptor) { // TODO : original? - traceForMembers.record(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor); // TODO: this context.getTrace()? + trace.record(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor); // TODO: this context.getTrace()? } } } @@ -460,7 +429,7 @@ public class BodyResolver { private void resolvePropertyInitializer(JetProperty property, PropertyDescriptor propertyDescriptor, JetExpression initializer, JetScope scope) { //JetFlowInformationProvider flowInformationProvider = context.getDescriptorResolver().computeFlowData(property, initializer); // TODO : flow JET-15 - ExpressionTypingServices typeInferrer = context.getSemanticServices().getTypeInferrerServices(traceForConstructors); + ExpressionTypingServices typeInferrer = context.getSemanticServices().getTypeInferrerServices(trace); JetType expectedTypeForInitializer = property.getPropertyTypeRef() != null ? propertyDescriptor.getOutType() : NO_EXPECTED_TYPE; JetType type = typeInferrer.getType(context.getDescriptorResolver().getPropertyDeclarationInnerScope(scope, propertyDescriptor, propertyDescriptor.getTypeParameters(), propertyDescriptor.getReceiverParameter()), initializer, expectedTypeForInitializer); // @@ -494,7 +463,7 @@ public class BodyResolver { JetScope declaringScope = this.context.getDeclaringScopes().get(declaration); assert declaringScope != null; - resolveFunctionBody(traceForMembers, declaration, descriptor, declaringScope); + resolveFunctionBody(trace, declaration, descriptor, declaringScope); assert descriptor.getReturnType() != null; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationsChecker.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationsChecker.java index 34e55786dbc..9254fcdc0de 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationsChecker.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationsChecker.java @@ -181,7 +181,8 @@ public class DeclarationsChecker { if (!(classDescriptor.getModality() == Modality.ABSTRACT) && classDescriptor.getKind() != ClassKind.ENUM_CLASS) { PsiElement classElement = context.getTrace().get(BindingContext.DESCRIPTOR_TO_DECLARATION, classDescriptor); assert classElement instanceof JetClass; - context.getTrace().report(ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS.on(property, abstractNode, property.getName(), classDescriptor, (JetClass) classElement)); + String name = property.getName(); + context.getTrace().report(ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS.on(property, abstractNode, name != null ? name : "", classDescriptor, (JetClass) classElement)); return; } if (classDescriptor.getKind() == ClassKind.TRAIT) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java index a896a2bf4e5..09fef717803 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java @@ -64,7 +64,15 @@ public class CallResolver { if (referencedName == null) { return null; } - List> prioritizedTasks = TaskPrioritizers.PROPERTY_TASK_PRIORITIZER.computePrioritizedTasks(scope, call, referencedName, trace.getBindingContext(), dataFlowInfo); + TaskPrioritizer task_prioritizer; + if (nameExpression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER) { + referencedName = referencedName.substring(1); + task_prioritizer = TaskPrioritizers.PROPERTY_TASK_PRIORITIZER; + } + else { + task_prioritizer = TaskPrioritizers.VARIABLE_TASK_PRIORITIZER; + } + List> prioritizedTasks = task_prioritizer.computePrioritizedTasks(scope, call, referencedName, trace.getBindingContext(), dataFlowInfo); return resolveCallToDescriptor(trace, scope, call, expectedType, prioritizedTasks, nameExpression); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizers.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizers.java index 292cfd760d1..c5a4f75f8b1 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizers.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizers.java @@ -1,5 +1,6 @@ package org.jetbrains.jet.lang.resolve.calls; +import com.google.common.collect.Lists; import com.google.common.collect.Sets; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.*; @@ -8,10 +9,7 @@ import org.jetbrains.jet.lang.types.ErrorUtils; import org.jetbrains.jet.lang.types.JetStandardClasses; import org.jetbrains.jet.lang.types.JetType; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.Set; +import java.util.*; /** * @author abreslav @@ -83,7 +81,7 @@ public class TaskPrioritizers { } }; - /*package*/ static TaskPrioritizer PROPERTY_TASK_PRIORITIZER = new TaskPrioritizer() { + /*package*/ static TaskPrioritizer VARIABLE_TASK_PRIORITIZER = new TaskPrioritizer() { @NotNull @Override @@ -115,4 +113,34 @@ public class TaskPrioritizers { return Collections.emptyList(); } }; + + /*package*/ static TaskPrioritizer PROPERTY_TASK_PRIORITIZER = new TaskPrioritizer() { + private Collection filterProperties(Collection variableDescriptors) { + ArrayList properties = Lists.newArrayList(); + for (VariableDescriptor descriptor : variableDescriptors) { + if (descriptor instanceof PropertyDescriptor) { + properties.add(descriptor); + } + } + return properties; + } + + @NotNull + @Override + protected Collection getNonExtensionsByName(JetScope scope, String name) { + return filterProperties(VARIABLE_TASK_PRIORITIZER.getNonExtensionsByName(scope, name)); + } + + @NotNull + @Override + protected Collection getMembersByName(@NotNull JetType receiver, String name) { + return filterProperties(VARIABLE_TASK_PRIORITIZER.getMembersByName(receiver, name)); + } + + @NotNull + @Override + protected Collection getExtensionsByName(JetScope scope, String name) { + return filterProperties(VARIABLE_TASK_PRIORITIZER.getExtensionsByName(scope, name)); + } + }; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WritableScope.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WritableScope.java index e9002d3cc64..e0d2df9cc51 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WritableScope.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WritableScope.java @@ -36,8 +36,6 @@ public interface WritableScope extends JetScope { @Nullable NamespaceDescriptor getDeclaredNamespace(@NotNull String name); - void addPropertyDescriptorByFieldName(@NotNull String fieldName, @NotNull PropertyDescriptor propertyDescriptor); - void importScope(@NotNull JetScope imported); void setImplicitReceiver(@NotNull ReceiverDescriptor implicitReceiver); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WritableScopeImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WritableScopeImpl.java index bacaa26ea9e..77bb17c3982 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WritableScopeImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WritableScopeImpl.java @@ -338,17 +338,6 @@ public class WritableScopeImpl extends WritableScopeWithImports { return propertyDescriptorsByFieldNames; } - @Override - public void addPropertyDescriptorByFieldName(@NotNull String fieldName, @NotNull PropertyDescriptor propertyDescriptor) { - checkMayWrite(); - - if (!fieldName.startsWith("$")) { - throw new IllegalStateException(); - } - - getPropertyDescriptorsByFieldNames().put(fieldName, propertyDescriptor); - } - @Override public PropertyDescriptor getPropertyByFieldReference(@NotNull String fieldName) { checkMayRead(); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WriteThroughScope.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WriteThroughScope.java index c00a3e04547..5f123dc5a44 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WriteThroughScope.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WriteThroughScope.java @@ -176,13 +176,6 @@ public class WriteThroughScope extends WritableScopeWithImports { return writableWorker.getDeclaredNamespace(name); } - @Override - public void addPropertyDescriptorByFieldName(@NotNull String fieldName, @NotNull PropertyDescriptor propertyDescriptor) { - checkMayWrite(); - - writableWorker.addPropertyDescriptorByFieldName(fieldName, propertyDescriptor); - } - @Override public void importScope(@NotNull JetScope imported) { checkMayWrite(); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java index 09ef1b6e574..c59643b06d6 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java @@ -47,22 +47,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { public JetType visitSimpleNameExpression(JetSimpleNameExpression expression, ExpressionTypingContext context) { // TODO : other members // TODO : type substitutions??? - String referencedName = expression.getReferencedName(); - if (expression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER - && referencedName != null) { - PropertyDescriptor property = context.scope.getPropertyByFieldReference(referencedName); - if (property == null) { - context.trace.report(UNRESOLVED_REFERENCE.on(expression)); - } - else { - context.trace.record(REFERENCE_TARGET, expression, property); - return DataFlowUtils.checkType(property.getOutType(), expression, context); - } - } - else { - return DataFlowUtils.checkType(getSelectorReturnType(NO_RECEIVER, null, expression, context), expression, context); // TODO : Extensions to this - } - return null; + return DataFlowUtils.checkType(getSelectorReturnType(NO_RECEIVER, null, expression, context), expression, context); // TODO : Extensions to this } private JetType lookupNamespaceOrClassObject(JetSimpleNameExpression expression, String referencedName, ExpressionTypingContext context) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingVisitorForStatements.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingVisitorForStatements.java index 59642c4c73e..c483bfff97c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingVisitorForStatements.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingVisitorForStatements.java @@ -213,16 +213,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito basic.checkLValue(context.trace, expression.getLeft()); } if (left instanceof JetSimpleNameExpression) { - JetSimpleNameExpression simpleName = (JetSimpleNameExpression) left; - String referencedName = simpleName.getReferencedName(); - if (simpleName.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER - && referencedName != null) { - PropertyDescriptor property = context.scope.getPropertyByFieldReference(referencedName); - if (property != null) { - context.trace.record(BindingContext.VARIABLE_ASSIGNMENT, simpleName, property); - } - } - ExpressionTypingUtils.checkWrappingInRef(simpleName, context); + ExpressionTypingUtils.checkWrappingInRef(left, context); } return checkExpectedType(expression, contextWithExpectedType); } diff --git a/compiler/testData/diagnostics/tests/AnonymousInitializers.jet b/compiler/testData/diagnostics/tests/AnonymousInitializers.jet index 74efce233c3..515ed807058 100644 --- a/compiler/testData/diagnostics/tests/AnonymousInitializers.jet +++ b/compiler/testData/diagnostics/tests/AnonymousInitializers.jet @@ -24,7 +24,7 @@ class WithC() { { val z = b val zz = x - val zzz = $a + val zzz = $a } this(a : Int) : this() { diff --git a/compiler/testData/diagnostics/tests/Properties.jet b/compiler/testData/diagnostics/tests/Properties.jet index 1b3ca0b8dee..ecb73643452 100644 --- a/compiler/testData/diagnostics/tests/Properties.jet +++ b/compiler/testData/diagnostics/tests/Properties.jet @@ -1,4 +1,4 @@ - var x : Int = 1 + x +var x : Int = 1 + x get() : Int = 1 set(ref value : Long) { $x = value.int @@ -14,16 +14,16 @@ class Test() { var a : Int = 111 - var b : Int get() = $a; set(x) {a = x; $a = x} + var b : Int get() = $a; set(x) {a = x; $a = x} this(i : Int) : this() { - $b = $a - $a = $b - a = $b + $b = $a + $a = $b + a = $b } fun f() { - $b = $a - a = $b + $b = $a + a = $b } public val i = 1 } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/UninitializedOrReassignedVariables.jet b/compiler/testData/diagnostics/tests/UninitializedOrReassignedVariables.jet index a3dcf7c81cf..c9c53ef1fe7 100644 --- a/compiler/testData/diagnostics/tests/UninitializedOrReassignedVariables.jet +++ b/compiler/testData/diagnostics/tests/UninitializedOrReassignedVariables.jet @@ -137,14 +137,14 @@ class AnonymousInitializers(var a: String, val b: String) { { $i = 13 - $j = 30 - j = 34 + $j = 30 + j = 34 } val k: String { if (1 < 3) { - k = "a" + k = "a" } else { $k = "b" @@ -288,7 +288,7 @@ class TestObjectExpression() { val y : Int { if (true) - x = 12 + x = 12 else $x = 1 } @@ -349,4 +349,4 @@ fun test(m : M) { fun test1(m : M) { m.x++ m.y-- -} +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/backingField/ReadInFunction.jet b/compiler/testData/diagnostics/tests/backingField/ReadInFunction.jet index dac44656db9..9ed84b87bcc 100644 --- a/compiler/testData/diagnostics/tests/backingField/ReadInFunction.jet +++ b/compiler/testData/diagnostics/tests/backingField/ReadInFunction.jet @@ -1,4 +1,4 @@ class ReadByAnotherPropertyInitializer() { val a = 1 - fun ff() = $a + fun ff() = $a } diff --git a/compiler/testData/diagnostics/tests/backingField/ReadNonexistentAbstractPropertyInAnonymous.jet b/compiler/testData/diagnostics/tests/backingField/ReadNonexistentAbstractPropertyInAnonymous.jet index 31ecbc026b3..5c7863b359f 100644 --- a/compiler/testData/diagnostics/tests/backingField/ReadNonexistentAbstractPropertyInAnonymous.jet +++ b/compiler/testData/diagnostics/tests/backingField/ReadNonexistentAbstractPropertyInAnonymous.jet @@ -2,6 +2,6 @@ abstract class ReadNonexistent() { abstract val aa: Int { - val x = $aa + val x = $aa } -} +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/backingField/ReadNonexistentAbstractPropertyInFunction.jet b/compiler/testData/diagnostics/tests/backingField/ReadNonexistentAbstractPropertyInFunction.jet index bb29feddfae..dc3ddc9cc28 100644 --- a/compiler/testData/diagnostics/tests/backingField/ReadNonexistentAbstractPropertyInFunction.jet +++ b/compiler/testData/diagnostics/tests/backingField/ReadNonexistentAbstractPropertyInFunction.jet @@ -1,5 +1,5 @@ abstract class ReadNonexistent { abstract val aa: Int - fun ff() = $aa -} + fun ff() = $aa +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/backingField/ReadNonexistentCustomGetInAnonymous.jet b/compiler/testData/diagnostics/tests/backingField/ReadNonexistentCustomGetInAnonymous.jet index be275ba22fc..d90f9631d6f 100644 --- a/compiler/testData/diagnostics/tests/backingField/ReadNonexistentCustomGetInAnonymous.jet +++ b/compiler/testData/diagnostics/tests/backingField/ReadNonexistentCustomGetInAnonymous.jet @@ -3,6 +3,6 @@ class ReadNonexistent() { get() = 1 { - val x = $a + val x = $a } -} +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/backingField/ReadNonexistentCustomGetInAnotherInitializer.jet b/compiler/testData/diagnostics/tests/backingField/ReadNonexistentCustomGetInAnotherInitializer.jet index 80b852f68b0..5754f538a8e 100644 --- a/compiler/testData/diagnostics/tests/backingField/ReadNonexistentCustomGetInAnotherInitializer.jet +++ b/compiler/testData/diagnostics/tests/backingField/ReadNonexistentCustomGetInAnotherInitializer.jet @@ -2,5 +2,5 @@ class CustomValNoBackingField() { val a: Int get() = 1 - val b = $a -} + val b = $a +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/backingField/ReadNonexistentDeclaredInHigher.jet b/compiler/testData/diagnostics/tests/backingField/ReadNonexistentDeclaredInHigher.jet index 1ec73f2984e..5754f538a8e 100644 --- a/compiler/testData/diagnostics/tests/backingField/ReadNonexistentDeclaredInHigher.jet +++ b/compiler/testData/diagnostics/tests/backingField/ReadNonexistentDeclaredInHigher.jet @@ -1,7 +1,6 @@ -val y = 1 - -class A() { - { - val x = $y - } -} +class CustomValNoBackingField() { + val a: Int + get() = 1 + + val b = $a +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/backingField/WriteNonexistentDeclaredInHigher.jet b/compiler/testData/diagnostics/tests/backingField/WriteNonexistentDeclaredInHigher.jet index 039a381fd55..26cb04ea093 100644 --- a/compiler/testData/diagnostics/tests/backingField/WriteNonexistentDeclaredInHigher.jet +++ b/compiler/testData/diagnostics/tests/backingField/WriteNonexistentDeclaredInHigher.jet @@ -2,6 +2,6 @@ val y = 1 class A() { { - $y = 1 + $y = 1 } -} +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/backingField/kt462BackingFieldsResolve.jet b/compiler/testData/diagnostics/tests/backingField/kt462BackingFieldsResolve.jet new file mode 100644 index 00000000000..af0ec07ea8d --- /dev/null +++ b/compiler/testData/diagnostics/tests/backingField/kt462BackingFieldsResolve.jet @@ -0,0 +1,172 @@ +//KT-462 Consider allowing initializing properties via property names when it is safe +//KT-598 Allow to use backing fields after this expression + +namespace kt462 + +abstract class TestInitializationWithoutBackingField() { + val valWithBackingField : Int + { + valWithBackingField = 2 + } + + val valWithoutBackingField : Int + get() = 42 + { + valWithoutBackingField = 45 + } + + var finalDefaultVar : Int + { + finalDefaultVar = 3 + } + + open var openVar : Int + { + openVar = 4 + } + + var varWithCustomSetter : Int + set(v: Int) { + $varWithCustomSetter = v + } + { + varWithCustomSetter = 3 + } + + var varWithoutBackingField : Int + get() = 3 + set(v: Int) {} + { + varWithoutBackingField = 4 + } + + abstract var abstractVar : Int + { + abstractVar = 34 + } +} + +abstract class TestInitializationThroughBackingField() { + val valWithBackingField : Int + { + $valWithBackingField = 2 + } + + val valWithoutBackingField : Int + get() = 42 + { + $valWithoutBackingField = 45 + } + + var finalDefaultVar : Int + { + $finalDefaultVar = 3 + } + + open var openVar : Int + { + $openVar = 4 + } + + var varWithCustomSetter : Int + set(v: Int) { + $varWithCustomSetter = v + } + { + $varWithCustomSetter = 3 + } + + var varWithoutBackingField : Int + get() = 3 + set(v: Int) {} + { + $varWithoutBackingField = 4 + } + + abstract var abstractVar : Int + { + $abstractVar = 34 + } +} + +class TestBackingFieldsVisibility() { + var a : Int = 712 + { + $a = 37 + this.$a = 357 + } + + fun foo() { + $a = 334 + this.$a = 347 + } + + fun foo(a: TestBackingFieldsVisibility) { + val b : Int = 3 + $b = 342 + a.$a = 3 + } + + val x = $namespaceLevelVar + + class Inner() { + val z = this@TestBackingFieldsVisibility.$x + } + + abstract val w = 11 + get() = $w //test there is no second error here +} + +val namespaceLevelVar = 11 + +class T() { + val z : Int get() = 42 + + { + this.$z = 34 + } + + fun foo() { + this.$z = 343 + } + + val a = object { + val x = $z + { + $z = 23 + } + } + + var x: Int = 2 + get() { + val o = object { + { + $x = 34 + } + fun foo() { + $x = 23 + } + } + return 1 + } + + var r: Int = $x + set(v: Int) { + if (true) { + $r = 33 + } + else { + $r = 35 + } + } + + fun bar() { + $x = 34 + val o = object { + val y = $x + { + $x = 422 + } + } + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/control-flow-analysis/kt510.jet b/compiler/testData/diagnostics/tests/control-flow-analysis/kt510.jet index 050c84f2cf4..41feb040f2a 100644 --- a/compiler/testData/diagnostics/tests/control-flow-analysis/kt510.jet +++ b/compiler/testData/diagnostics/tests/control-flow-analysis/kt510.jet @@ -5,7 +5,7 @@ namespace kt510 public open class Identifier1() { var field : Boolean { - field = false; // error + field = false; // error } } @@ -13,6 +13,6 @@ public open class Identifier1() { public open class Identifier2() { var field : Boolean { - this.field = false; + this.field = false; } } \ No newline at end of file diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/AddModifierFix.java b/idea/src/org/jetbrains/jet/plugin/quickfix/AddModifierFix.java index 1872257488d..45918386a78 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/AddModifierFix.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/AddModifierFix.java @@ -31,7 +31,7 @@ public class AddModifierFix extends JetIntentionAction { } @NotNull - /*package*/ static String getElementName(JetModifierListOwner modifierListOwner) { + /*package*/ static String getElementName(@NotNull JetModifierListOwner modifierListOwner) { String name = null; if (modifierListOwner instanceof PsiNameIdentifierOwner) { PsiElement nameIdentifier = ((PsiNameIdentifierOwner) modifierListOwner).getNameIdentifier(); diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/ChangeToBackingFieldFix.java b/idea/src/org/jetbrains/jet/plugin/quickfix/ChangeToBackingFieldFix.java index b6d43fa5863..dae43ef8e60 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/ChangeToBackingFieldFix.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/ChangeToBackingFieldFix.java @@ -36,12 +36,7 @@ public class ChangeToBackingFieldFix extends JetIntentionAction createFactory() { diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/ChangeVariableMutabilityFix.java b/idea/src/org/jetbrains/jet/plugin/quickfix/ChangeVariableMutabilityFix.java index 23a01d37acf..9b7cdba6ee4 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/ChangeVariableMutabilityFix.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/ChangeVariableMutabilityFix.java @@ -78,8 +78,9 @@ public class ChangeVariableMutabilityFix implements IntentionAction { @Override public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { - JetProperty element = getCorrespondingProperty(editor, (JetFile)file); - JetProperty newElement = (JetProperty) element.copy(); + JetProperty property = getCorrespondingProperty(editor, (JetFile)file); + assert property != null && !property.isVar(); + JetProperty newElement = (JetProperty) property.copy(); if (newElement.isVar()) { PsiElement varElement = newElement.getNode().findChildByType(JetTokens.VAR_KEYWORD).getPsi(); @@ -94,7 +95,7 @@ public class ChangeVariableMutabilityFix implements IntentionAction { PsiElement varElement = varProperty.getNode().findChildByType(JetTokens.VAR_KEYWORD).getPsi(); CodeEditUtil.replaceChild(newElement.getNode(), valElement.getNode(), varElement.getNode()); } - element.replace(newElement); + property.replace(newElement); } @Override diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixes.java b/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixes.java index 3a98d0803ac..d34688b4736 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixes.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixes.java @@ -111,8 +111,10 @@ public class QuickFixes { add(Errors.ILLEGAL_MODIFIER, removeModifierFactory); add(Errors.PUBLIC_MEMBER_SHOULD_SPECIFY_TYPE, AddReturnTypeFix.createFactory()); - - add(Errors.INITIALIZATION_USING_BACKING_FIELD, ChangeToBackingFieldFix.createFactory()); + + JetIntentionActionFactory changeToBackingFieldFactory = ChangeToBackingFieldFix.createFactory(); + add(Errors.INITIALIZATION_USING_BACKING_FIELD_CUSTOM_SETTER, changeToBackingFieldFactory); + add(Errors.INITIALIZATION_USING_BACKING_FIELD_OPEN_SETTER, changeToBackingFieldFactory); ImplementMethodsHandler implementMethodsHandler = new ImplementMethodsHandler(); actionMap.put(Errors.ABSTRACT_MEMBER_NOT_IMPLEMENTED, implementMethodsHandler); diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/RemoveModifierFix.java b/idea/src/org/jetbrains/jet/plugin/quickfix/RemoveModifierFix.java index efe1337520b..fc0dfc0b647 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/RemoveModifierFix.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/RemoveModifierFix.java @@ -35,7 +35,7 @@ public class RemoveModifierFix { if (isRedundant) { return JetBundle.message("remove.redundant.modifier", modifier.getValue()); } - if (element != null && modifier == JetTokens.ABSTRACT_KEYWORD || modifier == JetTokens.OPEN_KEYWORD) { + if (element != null && (modifier == JetTokens.ABSTRACT_KEYWORD || modifier == JetTokens.OPEN_KEYWORD)) { return JetBundle.message("make.element.not.modifier", AddModifierFix.getElementName(element), modifier.getValue()); } return JetBundle.message("remove.modifier", modifier.getValue()); diff --git a/idea/testData/checker/Properties.jet b/idea/testData/checker/Properties.jet index 8f9ae255576..7ca6725365e 100644 --- a/idea/testData/checker/Properties.jet +++ b/idea/testData/checker/Properties.jet @@ -14,7 +14,7 @@ class Test() { var a : Int = 111 - var b : Int get() = $a; set(x) {a = x; $a = x} + var b : Int get() = $a; set(x) {a = x; $a = x} this(i : Int) : this() { $b = $a @@ -22,7 +22,7 @@ class Test() { a = $b } fun f() { - $b = $a + $b = $a a = $b } } \ No newline at end of file diff --git a/idea/testData/quickfix/variables/changeToBackingField/afterBFRequired.kt b/idea/testData/quickfix/variables/changeToBackingField/afterBFRequired.kt index b136e4ab85d..87c441a372c 100644 --- a/idea/testData/quickfix/variables/changeToBackingField/afterBFRequired.kt +++ b/idea/testData/quickfix/variables/changeToBackingField/afterBFRequired.kt @@ -1,6 +1,7 @@ // "Change reference to backing field" "true" class A() { - val a : Int + var a : Int + set(v) {} { $a = 1 } diff --git a/idea/testData/quickfix/variables/changeToBackingField/afterKt510.kt b/idea/testData/quickfix/variables/changeToBackingField/afterKt510.kt index c48a4e73754..5ce1e112210 100644 --- a/idea/testData/quickfix/variables/changeToBackingField/afterKt510.kt +++ b/idea/testData/quickfix/variables/changeToBackingField/afterKt510.kt @@ -1,7 +1,8 @@ // "Change reference to backing field" "true" public open class Identifier() { var field : Boolean + set(v) {} { - $field = false; + this.$field = false; } } \ No newline at end of file diff --git a/idea/testData/quickfix/variables/changeToBackingField/beforeBFRequired.kt b/idea/testData/quickfix/variables/changeToBackingField/beforeBFRequired.kt index 3c9b678fe9b..48fdd186232 100644 --- a/idea/testData/quickfix/variables/changeToBackingField/beforeBFRequired.kt +++ b/idea/testData/quickfix/variables/changeToBackingField/beforeBFRequired.kt @@ -1,6 +1,7 @@ // "Change reference to backing field" "true" class A() { - val a : Int + var a : Int + set(v) {} { a = 1 } diff --git a/idea/testData/quickfix/variables/changeToBackingField/beforeKt510.kt b/idea/testData/quickfix/variables/changeToBackingField/beforeKt510.kt index 46ccdd440a6..ad1ef0139cd 100644 --- a/idea/testData/quickfix/variables/changeToBackingField/beforeKt510.kt +++ b/idea/testData/quickfix/variables/changeToBackingField/beforeKt510.kt @@ -1,6 +1,7 @@ // "Change reference to backing field" "true" public open class Identifier() { var field : Boolean + set(v) {} { this.field = false; } From a9d1cea965359f70bbaa9e1fa79dddb63a302d4c Mon Sep 17 00:00:00 2001 From: svtk Date: Tue, 6 Dec 2011 22:45:19 +0400 Subject: [PATCH 11/15] fix after merge --- .../org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java index 8050efe8be6..21c0223bae1 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java @@ -530,7 +530,7 @@ public class JetFlowInformationProvider { } } else if (element instanceof JetPostfixExpression) { - IElementType operationToken = ((JetPostfixExpression) element).getOperationSign().getReferencedNameElementType(); + IElementType operationToken = ((JetPostfixExpression) element).getOperationReference().getReferencedNameElementType(); if (operationToken == JetTokens.PLUSPLUS || operationToken == JetTokens.MINUSMINUS) { trace.report(Errors.UNUSED_CHANGED_VALUE.on(element, element)); } From bf54dc54535569736683556980bba81aeb8f28b0 Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Tue, 6 Dec 2011 23:25:26 +0400 Subject: [PATCH 12/15] test nullable return types are read from .class files --- .../resolve/java/JavaDescriptorResolver.java | 26 ++++++++++++++++++- .../testData/readClass/ReturnTypeNotNull.kt | 3 +++ .../testData/readClass/ReturnTypeNullable.kt | 3 +++ .../org/jetbrains/jet/ReadClassDataTest.java | 5 ++-- 4 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 compiler/testData/readClass/ReturnTypeNotNull.kt create mode 100644 compiler/testData/readClass/ReturnTypeNullable.kt diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java index 7b581578eb0..4ce838b3069 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java @@ -479,7 +479,7 @@ public class JavaDescriptorResolver { DescriptorUtils.getExpectedThisObjectIfNeeded(classDescriptor), typeParameters, semanticServices.getDescriptorResolver().resolveParameterDescriptors(functionDescriptorImpl, parameters), - semanticServices.getTypeTransformer().transformToType(returnType), + semanticServices.getDescriptorResolver().makeReturnType(returnType, method), Modality.convertFromFlags(method.hasModifierProperty(PsiModifier.ABSTRACT), !method.hasModifierProperty(PsiModifier.FINAL)), resolveVisibilityFromPsiModifiers(method) ); @@ -491,6 +491,30 @@ public class JavaDescriptorResolver { return substitutedFunctionDescriptor; } + private JetType makeReturnType(PsiType returnType, PsiMethod method) { + boolean changeNullable = false; + boolean nullable = true; + + for (PsiAnnotation annotation : method.getModifierList().getAnnotations()) { + if (annotation.getQualifiedName().equals("jet.typeinfo.JetMethod")) { + PsiLiteralExpression nullableExpression = (PsiLiteralExpression) annotation.findAttributeValue("nullableReturnType"); + if (nullableExpression != null) { + nullable = (Boolean) nullableExpression.getValue(); + } else { + // default value of parameter + nullable = false; + changeNullable = true; + } + } + } + JetType transformedType = semanticServices.getTypeTransformer().transformToType(returnType); + if (changeNullable) { + return TypeUtils.makeNullableAsSpecified(transformedType, nullable); + } else { + return transformedType; + } + } + private static Visibility resolveVisibilityFromPsiModifiers(PsiModifierListOwner modifierListOwner) { //TODO report error return modifierListOwner.hasModifierProperty(PsiModifier.PUBLIC) ? Visibility.PUBLIC : diff --git a/compiler/testData/readClass/ReturnTypeNotNull.kt b/compiler/testData/readClass/ReturnTypeNotNull.kt new file mode 100644 index 00000000000..0e025241a22 --- /dev/null +++ b/compiler/testData/readClass/ReturnTypeNotNull.kt @@ -0,0 +1,3 @@ +namespace test + +fun ff(): String = "" diff --git a/compiler/testData/readClass/ReturnTypeNullable.kt b/compiler/testData/readClass/ReturnTypeNullable.kt new file mode 100644 index 00000000000..6b3e33f7136 --- /dev/null +++ b/compiler/testData/readClass/ReturnTypeNullable.kt @@ -0,0 +1,3 @@ +namespace test + +fun ff(): String? = "" diff --git a/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java b/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java index b476555280e..e97ad3202cd 100644 --- a/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java +++ b/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java @@ -105,8 +105,6 @@ public class ReadClassDataTest extends UsefulTestCase { @Override public void runTest() throws Exception { - if (true) return; - createMockCoreEnvironment(); LanguageASTFactory.INSTANCE.addExplicitExtension(JavaLanguage.INSTANCE, new JavaASTFactory()); @@ -184,7 +182,8 @@ public class ReadClassDataTest extends UsefulTestCase { for (int i = 0; i < a.getValueParameters().size(); ++i) { compareAnything(ValueParameterDescriptor.class, a.getValueParameters().get(i), b.getValueParameters().get(i)); } - System.out.println("function " + a.getName()); + Assert.assertEquals(a.getReturnType(), b.getReturnType()); + System.out.println("fun " + a.getName() + "(...): " + a.getReturnType()); } private void compareAnything(Class clazz, T a, T b) { From e5c39df519c967bff4d9b8cf3f562f6ff57555eb Mon Sep 17 00:00:00 2001 From: Nikolay Krasko Date: Wed, 7 Dec 2011 12:19:50 +0400 Subject: [PATCH 13/15] KT-658 Show types in IDEA auto assist for kotlin --- .../resolve/java/JavaDescriptorResolver.java | 2 +- .../lang/resolve/java/JavaPackageScope.java | 49 ++++++++++++-- .../resolve/scopes/WriteThroughScope.java | 4 ++ .../jetbrains/jet/plugin/JetIconProvider.java | 18 +++--- .../compiler/WholeProjectAnalyzerFacade.java | 18 ++++-- idea/testData/completion/basic/FromImports.kt | 9 +++ idea/testData/completion/basic/JavaPackage.kt | 6 ++ .../completion/basic/VariableClassName.kt | 4 +- .../completion/keywords/InTypeScope.kt | 2 +- idea/testData/completion/keywords/TopScope.kt | 10 +-- .../completion/JetBasicCompletionTest.java | 2 +- .../jet/completion/JetCompletionTestBase.java | 64 +++++++++---------- .../completion/KeywordsCompletionTest.java | 8 ++- 13 files changed, 129 insertions(+), 67 deletions(-) create mode 100644 idea/testData/completion/basic/FromImports.kt create mode 100644 idea/testData/completion/basic/JavaPackage.kt diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java index 4ce838b3069..56b9f16b534 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java @@ -267,7 +267,7 @@ public class JavaDescriptorResolver { return javaFacade.findClass(qualifiedName, javaSearchScope); } - private PsiPackage findPackage(String qualifiedName) { + /*package*/ PsiPackage findPackage(String qualifiedName) { return javaFacade.findPackage(qualifiedName); } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaPackageScope.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaPackageScope.java index 776e5219dfc..2763af7e1f4 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaPackageScope.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaPackageScope.java @@ -1,10 +1,17 @@ package org.jetbrains.jet.lang.resolve.java; +import com.google.common.collect.Sets; import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiModifier; +import com.intellij.psi.PsiPackage; import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor; +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; +import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; import org.jetbrains.jet.lang.resolve.scopes.JetScopeImpl; +import java.util.Collection; import java.util.Collections; import java.util.Set; @@ -14,11 +21,13 @@ import java.util.Set; public class JavaPackageScope extends JetScopeImpl { private final JavaSemanticServices semanticServices; private final DeclarationDescriptor containingDescriptor; - private final String packagePrefix; + private final String packageFQN; + + private Collection allDescriptors; public JavaPackageScope(@NotNull String packageFQN, DeclarationDescriptor containingDescriptor, JavaSemanticServices semanticServices) { this.semanticServices = semanticServices; - this.packagePrefix = packageFQN.isEmpty() ? "" : packageFQN + "."; + this.packageFQN = packageFQN; this.containingDescriptor = containingDescriptor; } @@ -36,7 +45,7 @@ public class JavaPackageScope extends JetScopeImpl { @Override public Set getFunctions(@NotNull String name) { // TODO: what is GlobalSearchScope - PsiClass psiClass = semanticServices.getDescriptorResolver().javaFacade.findClass(packagePrefix + "namespace"); + PsiClass psiClass = semanticServices.getDescriptorResolver().javaFacade.findClass(getQualifiedName("namespace")); if (psiClass == null) { return Collections.emptySet(); } @@ -54,7 +63,35 @@ public class JavaPackageScope extends JetScopeImpl { return containingDescriptor; } - private String getQualifiedName(String name) { - return packagePrefix + name; + @NotNull + @Override + public Collection getAllDescriptors() { + if (allDescriptors == null) { + allDescriptors = Sets.newHashSet(); + + final PsiPackage javaPackage = semanticServices.getDescriptorResolver().findPackage(packageFQN); + + if (javaPackage != null) { + final JavaDescriptorResolver descriptorResolver = semanticServices.getDescriptorResolver(); + + for (PsiPackage psiSubPackage : javaPackage.getSubPackages()) { + allDescriptors.add(descriptorResolver.resolveNamespace(psiSubPackage.getQualifiedName())); + } + + for (PsiClass psiClass : javaPackage.getClasses()) { + if (psiClass.hasModifierProperty(PsiModifier.PUBLIC)) { + allDescriptors.add(descriptorResolver.resolveClass(psiClass)); + } + } + } + } + + return allDescriptors; } + + private String getQualifiedName(String name) { + return (packageFQN.isEmpty() ? "" : packageFQN + ".") + name; + } + + } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WriteThroughScope.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WriteThroughScope.java index 5f123dc5a44..7113b9ceaaa 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WriteThroughScope.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WriteThroughScope.java @@ -199,6 +199,10 @@ public class WriteThroughScope extends WritableScopeWithImports { allDescriptors = Lists.newArrayList(); allDescriptors.addAll(writableWorker.getAllDescriptors()); allDescriptors.addAll(getWorkerScope().getAllDescriptors()); + + for (JetScope imported : getImports()) { + allDescriptors.addAll(imported.getAllDescriptors()); + } } return allDescriptors; } diff --git a/idea/src/org/jetbrains/jet/plugin/JetIconProvider.java b/idea/src/org/jetbrains/jet/plugin/JetIconProvider.java index 3d10d912353..c1a8df88bec 100644 --- a/idea/src/org/jetbrains/jet/plugin/JetIconProvider.java +++ b/idea/src/org/jetbrains/jet/plugin/JetIconProvider.java @@ -4,7 +4,7 @@ import com.intellij.ide.IconProvider; import com.intellij.openapi.util.Iconable; import com.intellij.psi.PsiElement; import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.util.Icons; +import com.intellij.util.PlatformIcons; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lexer.JetTokens; @@ -15,21 +15,21 @@ import javax.swing.*; * @author yole */ public class JetIconProvider extends IconProvider { - public static final Icon ICON_FOR_OBJECT = Icons.ANONYMOUS_CLASS_ICON; + public static final Icon ICON_FOR_OBJECT = PlatformIcons.ANONYMOUS_CLASS_ICON; @Override public Icon getIcon(@NotNull PsiElement psiElement, int flags) { if (psiElement instanceof JetNamespace) { - return (flags & Iconable.ICON_FLAG_OPEN) != 0 ? Icons.PACKAGE_OPEN_ICON : Icons.PACKAGE_ICON; + return (flags & Iconable.ICON_FLAG_OPEN) != 0 ? PlatformIcons.PACKAGE_OPEN_ICON : PlatformIcons.PACKAGE_ICON; } if (psiElement instanceof JetNamedFunction) { return PsiTreeUtil.getParentOfType(psiElement, JetNamedDeclaration.class) instanceof JetClass - ? Icons.METHOD_ICON - : Icons.FUNCTION_ICON; + ? PlatformIcons.METHOD_ICON + : PlatformIcons.FUNCTION_ICON; } if (psiElement instanceof JetClass) { JetClass jetClass = (JetClass) psiElement; - Icon icon = jetClass.hasModifier(JetTokens.ENUM_KEYWORD) ? Icons.ENUM_ICON : Icons.CLASS_ICON; + Icon icon = jetClass.hasModifier(JetTokens.ENUM_KEYWORD) ? PlatformIcons.ENUM_ICON : PlatformIcons.CLASS_ICON; if (jetClass instanceof JetEnumEntry) { JetEnumEntry enumEntry = (JetEnumEntry) jetClass; if (enumEntry.getPrimaryConstructorParameterList() == null) { @@ -42,13 +42,13 @@ public class JetIconProvider extends IconProvider { if (((JetParameter) psiElement).getValOrVarNode() != null) { JetParameterList parameterList = PsiTreeUtil.getParentOfType(psiElement, JetParameterList.class); if (parameterList != null && parameterList.getParent() instanceof JetClass) { - return Icons.PROPERTY_ICON; + return PlatformIcons.PROPERTY_ICON; } } - return Icons.PARAMETER_ICON; + return PlatformIcons.PARAMETER_ICON; } if (psiElement instanceof JetProperty) { - return Icons.PROPERTY_ICON; + return PlatformIcons.PROPERTY_ICON; } return null; } diff --git a/idea/src/org/jetbrains/jet/plugin/compiler/WholeProjectAnalyzerFacade.java b/idea/src/org/jetbrains/jet/plugin/compiler/WholeProjectAnalyzerFacade.java index 01d853c9d7d..ec99fa7d3df 100644 --- a/idea/src/org/jetbrains/jet/plugin/compiler/WholeProjectAnalyzerFacade.java +++ b/idea/src/org/jetbrains/jet/plugin/compiler/WholeProjectAnalyzerFacade.java @@ -24,13 +24,23 @@ import java.util.Set; /** * @author abreslav */ -public class WholeProjectAnalyzerFacade { - public static final Function> WHOLE_PROJECT_DECLARATION_PROVIDER = new Function>() { +public final class WholeProjectAnalyzerFacade { + + /** Forbid creating */ + private WholeProjectAnalyzerFacade() {} + + /** + * Will collect all root-namespaces in all kotlin files in the project. + */ + public static final Function> WHOLE_PROJECT_DECLARATION_PROVIDER = + new Function>() { + @Override public Collection fun(final JetFile rootFile) { final Project project = rootFile.getProject(); final Set namespaces = Sets.newLinkedHashSet(); - ProjectRootManager rootManager = ProjectRootManager.getInstance(project); + final ProjectRootManager rootManager = ProjectRootManager.getInstance(project); + if (rootManager != null && !ApplicationManager.getApplication().isUnitTestMode()) { VirtualFile[] contentRoots = rootManager.getContentRoots(); @@ -55,9 +65,9 @@ public class WholeProjectAnalyzerFacade { } }; + @NotNull public static BindingContext analyzeProjectWithCacheOnAFile(@NotNull JetFile file) { return AnalyzerFacade.analyzeFileWithCache(file, WHOLE_PROJECT_DECLARATION_PROVIDER); } - } diff --git a/idea/testData/completion/basic/FromImports.kt b/idea/testData/completion/basic/FromImports.kt new file mode 100644 index 00000000000..893b30bbadb --- /dev/null +++ b/idea/testData/completion/basic/FromImports.kt @@ -0,0 +1,9 @@ +namespace Tests + +import java.util.* + +fun hello() { + val a = So +} + +// EXIST: SortedSet, SortedMap diff --git a/idea/testData/completion/basic/JavaPackage.kt b/idea/testData/completion/basic/JavaPackage.kt new file mode 100644 index 00000000000..59e1767100b --- /dev/null +++ b/idea/testData/completion/basic/JavaPackage.kt @@ -0,0 +1,6 @@ +namespace Tests + +class A : java. + +// EXIST: lang, util, io +// ABSENT: fun, val, var, namespace diff --git a/idea/testData/completion/basic/VariableClassName.kt b/idea/testData/completion/basic/VariableClassName.kt index 0296a23af4c..38c1068b400 100644 --- a/idea/testData/completion/basic/VariableClassName.kt +++ b/idea/testData/completion/basic/VariableClassName.kt @@ -1,10 +1,10 @@ open class MyClass() { } -class A() : My { +class A() { public fun test() { val a : MyC } } -// EXIST: MyClass \ No newline at end of file +// EXIST: MyClass diff --git a/idea/testData/completion/keywords/InTypeScope.kt b/idea/testData/completion/keywords/InTypeScope.kt index 31f2249d499..c8a490df14c 100644 --- a/idea/testData/completion/keywords/InTypeScope.kt +++ b/idea/testData/completion/keywords/InTypeScope.kt @@ -3,4 +3,4 @@ fun foo() { } // TODO: Move all keywords to absent -// EXPECT: fun, val, var, namespace +// EXIST: fun, val, var, namespace diff --git a/idea/testData/completion/keywords/TopScope.kt b/idea/testData/completion/keywords/TopScope.kt index a151d11e196..308a7710384 100644 --- a/idea/testData/completion/keywords/TopScope.kt +++ b/idea/testData/completion/keywords/TopScope.kt @@ -1,8 +1,8 @@ -// EXPECT: namespace, as, type, class, this, super, val, var, fun, for, null, true -// EXPECT: false, is, in, throw, return, break, continue, object, if, try, else, while -// EXPECT: do, when, trait, This -// EXPECT: import, where, by, get, set, abstract, enum, open, annotation, override, private -// EXPECT: public, internal, protected, catch, out, vararg, inline, finally, final, ref +// EXIST: namespace, as, type, class, this, super, val, var, fun, for, null, true +// EXIST: false, is, in, throw, return, break, continue, object, if, try, else, while +// EXIST: do, when, trait, This +// EXIST: import, where, by, get, set, abstract, enum, open, annotation, override, private +// EXIST: public, internal, protected, catch, out, vararg, inline, finally, final, ref // ABSENT: ?in, new, extends, implements \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/completion/JetBasicCompletionTest.java b/idea/tests/org/jetbrains/jet/completion/JetBasicCompletionTest.java index 14bc6d16912..995363c1be8 100644 --- a/idea/tests/org/jetbrains/jet/completion/JetBasicCompletionTest.java +++ b/idea/tests/org/jetbrains/jet/completion/JetBasicCompletionTest.java @@ -23,7 +23,7 @@ public class JetBasicCompletionTest extends JetCompletionTestBase { setName("testCompletionExecute"); } - public void testCompletionExecute() { + public void testCompletionExecute() throws Exception { doTest(); } diff --git a/idea/tests/org/jetbrains/jet/completion/JetCompletionTestBase.java b/idea/tests/org/jetbrains/jet/completion/JetCompletionTestBase.java index c0ff4263210..39372cd71c2 100644 --- a/idea/tests/org/jetbrains/jet/completion/JetCompletionTestBase.java +++ b/idea/tests/org/jetbrains/jet/completion/JetCompletionTestBase.java @@ -2,70 +2,64 @@ package org.jetbrains.jet.completion; import com.intellij.codeInsight.completion.CodeCompletionHandlerBase; import com.intellij.codeInsight.completion.CompletionType; +import com.intellij.codeInsight.completion.LightCompletionTestCase; import com.intellij.codeInsight.lookup.LookupElement; -import com.intellij.codeInsight.lookup.LookupEx; import com.intellij.codeInsight.lookup.LookupManager; -import com.intellij.testFramework.LightCodeInsightTestCase; +import com.intellij.codeInsight.lookup.impl.LookupImpl; +import com.intellij.openapi.projectRoots.Sdk; import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.plugin.PluginTestCaseBase; import java.io.BufferedReader; import java.io.IOException; import java.io.StringReader; import java.util.ArrayList; -import java.util.HashSet; import java.util.List; /** * @author Nikolay.Krasko */ -public abstract class JetCompletionTestBase extends LightCodeInsightTestCase { +public abstract class JetCompletionTestBase extends LightCompletionTestCase { - protected void doTest() { + private CompletionType type; + + protected void doTest() throws Exception { final String testName = getTestName(false); + + type = (testName.startsWith("Smart")) ? CompletionType.SMART : CompletionType.BASIC; + configureByFile(testName + ".kt"); - CompletionType completionType = (testName.startsWith("Smart")) ? CompletionType.SMART : CompletionType.BASIC; - new CodeCompletionHandlerBase(completionType, false, false, true).invokeCompletion(getProject(), getEditor()); - - LookupEx lookup = LookupManager.getActiveLookup(getEditor()); - assert lookup != null; - - HashSet items = new HashSet(resolveLookups(lookup.getItems())); - - List shouldExist = itemsShouldExist(getFile().getText()); - for (String shouldExistItem : shouldExist) { - assertTrue(String.format("Should contain proposal '%s'.", shouldExistItem), - items.contains(shouldExistItem)); - } - - List shouldAbsent = itemsShouldAbsent(getFile().getText()); - for (String shouldAbsentItem : shouldAbsent) { - assertTrue(String.format("Shouldn't contain proposal '%s'.", shouldAbsentItem), - !items.contains(shouldAbsentItem)); - } + assertContainsItems(itemsShouldExist(getFile().getText())); + assertNotContainItems(itemsShouldAbsent(getFile().getText())); } - - private static List resolveLookups(List items) { - ArrayList result = new ArrayList(items.size()); - for (LookupElement item : items) { - result.add(item.getLookupString()); - } - return result; + @Override + protected Sdk getProjectJDK() { + return PluginTestCaseBase.jdkFromIdeaHome(); + } + + @Override + protected void complete(final int time) { + new CodeCompletionHandlerBase(type, false, false, true).invokeCompletion(getProject(), getEditor(), time, false); + + LookupImpl lookup = (LookupImpl) LookupManager.getActiveLookup(myEditor); + myItems = lookup == null ? null : lookup.getItems().toArray(LookupElement.EMPTY_ARRAY); + myPrefix = lookup == null ? null : lookup.itemPattern(lookup.getItems().get(0)); } @NotNull - private static List itemsShouldExist(String fileText) { + private static String[] itemsShouldExist(String fileText) { return findListWithPrefix("// EXIST:", fileText); } @NotNull - private static List itemsShouldAbsent(String fileText) { + private static String[] itemsShouldAbsent(String fileText) { return findListWithPrefix("// ABSENT:", fileText); } @NotNull - private static List findListWithPrefix(String prefix, String fileText) { + private static String[] findListWithPrefix(String prefix, String fileText) { ArrayList result = new ArrayList(); for (String line : findLinesWithPrefixRemoved(prefix, fileText)) { @@ -76,7 +70,7 @@ public abstract class JetCompletionTestBase extends LightCodeInsightTestCase { } } - return result; + return result.toArray(new String[result.size()]); } @NotNull diff --git a/idea/tests/org/jetbrains/jet/completion/KeywordsCompletionTest.java b/idea/tests/org/jetbrains/jet/completion/KeywordsCompletionTest.java index 1df0d5ef2cf..4a0e14d9ed4 100644 --- a/idea/tests/org/jetbrains/jet/completion/KeywordsCompletionTest.java +++ b/idea/tests/org/jetbrains/jet/completion/KeywordsCompletionTest.java @@ -1,5 +1,6 @@ package org.jetbrains.jet.completion; +import junit.framework.Test; import junit.framework.TestSuite; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.JetTestCaseBuilder; @@ -25,7 +26,7 @@ public class KeywordsCompletionTest extends JetCompletionTestBase { setName("testCompletionExecute"); } - public void testCompletionExecute() { + public void testCompletionExecute() throws Exception { doTest(); } @@ -49,13 +50,14 @@ public class KeywordsCompletionTest extends JetCompletionTestBase { PluginTestCaseBase.getTestDataPathBase(), "/completion/keywords/", false, JetTestCaseBuilder.emptyFilter, new JetTestCaseBuilder.NamedTestFactory() { + @NotNull @Override - public junit.framework.Test createTest(@NotNull String dataPath, @NotNull String name, @NotNull File file) { + public Test createTest(@NotNull String dataPath, @NotNull String name, @NotNull File file) { return new KeywordsCompletionTest(dataPath, name); } }, suite); return suite; } -} \ No newline at end of file +} From d272979b09e605ced6cba2d10c27177383411309 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Wed, 7 Dec 2011 11:51:50 +0200 Subject: [PATCH 14/15] thread ring benchmark and related bug fixes (non null array creation and wrong signature of enclosing class) --- .../jetbrains/jet/codegen/ClosureCodegen.java | 5 +- .../jetbrains/jet/codegen/CodegenContext.java | 34 ++--- .../jet/codegen/ExpressionCodegen.java | 19 +-- .../jet/codegen/GenerationState.java | 2 +- .../codegen/ImplementationBodyCodegen.java | 2 +- .../testData/codegen/classes/nonnullarray.jet | 8 + .../testData/codegen/regressions/kt694.jet | 9 ++ .../jetbrains/jet/codegen/ArrayGenTest.java | 5 + .../jetbrains/jet/codegen/ClassGenTest.java | 6 + examples/src/benchmarks/ThreadRing.java | 137 ++++++++++++++++++ examples/src/benchmarks/ThreadRing.kt | 95 ++++++++++++ 11 files changed, 284 insertions(+), 38 deletions(-) create mode 100644 compiler/testData/codegen/classes/nonnullarray.jet create mode 100644 compiler/testData/codegen/regressions/kt694.jet create mode 100644 examples/src/benchmarks/ThreadRing.java create mode 100644 examples/src/benchmarks/ThreadRing.kt diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java index 75241d6dc74..085dfb7f5c3 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java @@ -10,7 +10,6 @@ import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.psi.JetDeclarationWithBody; import org.jetbrains.jet.lang.psi.JetExpression; -import org.jetbrains.jet.lang.psi.JetFunctionLiteral; import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.scopes.JetScope; @@ -100,7 +99,7 @@ public class ClosureCodegen extends ObjectOrClosureCodegen { generateBridge(name, funDescriptor, fun, cv); captureThis = generateBody(funDescriptor, cv, fun.getFunctionLiteral()); ClassDescriptor thisDescriptor = context.getThisDescriptor(); - final Type enclosingType = thisDescriptor == null ? null : Type.getObjectType(thisDescriptor.getName()); + final Type enclosingType = thisDescriptor == null ? null : state.getTypeMapper().mapType(thisDescriptor.getDefaultType()); if (enclosingType == null) captureThis = false; @@ -164,7 +163,7 @@ public class ClosureCodegen extends ObjectOrClosureCodegen { Collections.emptyList(), Collections.singleton((funDescriptor.getReceiverParameter().exists() ? JetStandardClasses.getReceiverFunction(arity) : JetStandardClasses.getFunction(arity)).getDefaultType()), JetScope.EMPTY, Collections.emptySet(), null); - final CodegenContext.ClosureContext closureContext = context.intoClosure(funDescriptor, function, name, this); + final CodegenContext.ClosureContext closureContext = context.intoClosure(funDescriptor, function, name, this, state.getTypeMapper()); FunctionCodegen fc = new FunctionCodegen(closureContext, cv, state); fc.generateMethod(body, invokeSignature(funDescriptor), funDescriptor); return closureContext.outerWasUsed; diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java index a5d3447e98c..88ce2d7883b 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java @@ -104,24 +104,24 @@ public abstract class CodegenContext { return new ClassContext(descriptor, kind, this, typeMapper); } - public CodegenContext intoAnonymousClass(@NotNull ObjectOrClosureCodegen closure, ClassDescriptor descriptor, OwnerKind kind) { - return new AnonymousClassContext(descriptor, kind, this, closure); + public CodegenContext intoAnonymousClass(@NotNull ObjectOrClosureCodegen closure, ClassDescriptor descriptor, OwnerKind kind, JetTypeMapper typeMapper) { + return new AnonymousClassContext(descriptor, kind, this, closure, typeMapper); } public MethodContext intoFunction(FunctionDescriptor descriptor) { return new MethodContext(descriptor, getContextKind(), this); } - public ConstructorContext intoConstructor(ConstructorDescriptor descriptor) { + public ConstructorContext intoConstructor(ConstructorDescriptor descriptor, JetTypeMapper typeMapper) { if(descriptor == null) { descriptor = new ConstructorDescriptorImpl(getThisDescriptor(), Collections.emptyList(), true) .initialize(Collections.emptyList(), Collections.emptyList(), Modality.OPEN, Visibility.PUBLIC); } - return new ConstructorContext(descriptor, getContextKind(), this); + return new ConstructorContext(descriptor, getContextKind(), this, typeMapper); } - public ClosureContext intoClosure(FunctionDescriptor funDescriptor, ClassDescriptor classDescriptor, String internalClassName, ClosureCodegen closureCodegen) { - return new ClosureContext(funDescriptor, classDescriptor, this, closureCodegen, internalClassName); + public ClosureContext intoClosure(FunctionDescriptor funDescriptor, ClassDescriptor classDescriptor, String internalClassName, ClosureCodegen closureCodegen, JetTypeMapper typeMapper) { + return new ClosureContext(funDescriptor, classDescriptor, this, closureCodegen, internalClassName, typeMapper); } public FrameMap prepareFrame(JetTypeMapper mapper) { @@ -170,12 +170,12 @@ public abstract class CodegenContext { return parentContext != null ? parentContext.lookupInContext(d, v, result) : null; } - public Type enclosingClassType() { + public Type enclosingClassType(JetTypeMapper typeMapper) { CodegenContext cur = getParentContext(); while(cur != null && !(cur.getContextDescriptor() instanceof ClassDescriptor)) cur = cur.getParentContext(); - return cur == null ? null : Type.getObjectType(cur.getContextDescriptor().getName()); + return cur == null ? null : typeMapper.mapType(((ClassDescriptor)cur.getContextDescriptor()).getDefaultType()); } public int getTypeInfoConstantIndex(JetType type) { @@ -290,8 +290,8 @@ public abstract class CodegenContext { return getParentContext().lookupInContext(d, v, result); } - public Type enclosingClassType() { - return getParentContext().enclosingClassType(); + public Type enclosingClassType(JetTypeMapper typeMapper) { + return getParentContext().enclosingClassType(typeMapper); } @Override @@ -305,10 +305,10 @@ public abstract class CodegenContext { } public static class ConstructorContext extends MethodContext { - public ConstructorContext(ConstructorDescriptor contextType, OwnerKind kind, CodegenContext parent) { + public ConstructorContext(ConstructorDescriptor contextType, OwnerKind kind, CodegenContext parent, JetTypeMapper typeMapper) { super(contextType, kind, parent); - final Type type = enclosingClassType(); + final Type type = enclosingClassType(typeMapper); outerExpression = type != null ? local1 : null; @@ -323,7 +323,7 @@ public abstract class CodegenContext { public ClassContext(ClassDescriptor contextType, OwnerKind contextKind, CodegenContext parentContext, JetTypeMapper typeMapper) { super(contextType, contextKind, parentContext, null); - final Type type = enclosingClassType(); + final Type type = enclosingClassType(typeMapper); outerExpression = type != null ? StackValue.field(type, typeMapper.getFQName(contextType), "this$0", false) : null; @@ -341,10 +341,10 @@ public abstract class CodegenContext { } public static class AnonymousClassContext extends CodegenContext { - public AnonymousClassContext(ClassDescriptor contextType, OwnerKind contextKind, CodegenContext parentContext, @NotNull ObjectOrClosureCodegen closure) { + public AnonymousClassContext(ClassDescriptor contextType, OwnerKind contextKind, CodegenContext parentContext, @NotNull ObjectOrClosureCodegen closure, JetTypeMapper typeMapper) { super(contextType, contextKind, parentContext, closure); - final Type type = enclosingClassType(); + final Type type = enclosingClassType(typeMapper); outerExpression = type != null ? StackValue.field(type, closure.state.getTypeMapper().mapType(contextType.getDefaultType(), OwnerKind.IMPLEMENTATION).getInternalName(), "this$0", false) : null; @@ -364,11 +364,11 @@ public abstract class CodegenContext { public static class ClosureContext extends ReceiverContext { private ClassDescriptor classDescriptor; - public ClosureContext(FunctionDescriptor contextType, ClassDescriptor classDescriptor, CodegenContext parentContext, @NotNull ObjectOrClosureCodegen closureCodegen, String internalClassName) { + public ClosureContext(FunctionDescriptor contextType, ClassDescriptor classDescriptor, CodegenContext parentContext, @NotNull ObjectOrClosureCodegen closureCodegen, String internalClassName, JetTypeMapper typeMapper) { super(contextType, OwnerKind.IMPLEMENTATION, parentContext, closureCodegen); this.classDescriptor = classDescriptor; - final Type type = enclosingClassType(); + final Type type = enclosingClassType(typeMapper); outerExpression = type != null ? StackValue.field(type, internalClassName, "this$0", false) : null; diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index e77bf07342d..9f29c28ce15 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -1958,26 +1958,13 @@ public class ExpressionCodegen extends JetVisitor { } else { ClassDescriptor classDecl = (ClassDescriptor) constructorDescriptor.getContainingDeclaration(); - receiver.put(receiver.type, v); v.anew(type); + v.dup(); // TODO typechecker must verify that we're the outer class of the instance being created //noinspection ConstantConditions - if (classDecl.getContainingDeclaration() instanceof ClassDescriptor) { - if(!receiver.type.equals(Type.VOID_TYPE)) { - // class object is in receiver - v.dupX1(); - v.swap(); - } - else { - // this$0 need to be put on stack - v.dup(); - v.load(0, typeMapper.mapType(classDecl.getDefaultType(), OwnerKind.IMPLEMENTATION)); - } - } - else { - // regular case - v.dup(); + if(!receiver.type.equals(Type.VOID_TYPE)) { + receiver.put(receiver.type, v); } CallableMethod method = typeMapper.mapToCallableMethod((ConstructorDescriptor) constructorDescriptor, OwnerKind.IMPLEMENTATION); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java b/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java index e83fd50e11e..8ddc2d7f5a1 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java @@ -140,7 +140,7 @@ public class GenerationState { closure.cv = nameAndVisitor.getSecond(); closure.name = nameAndVisitor.getFirst(); - final CodegenContext objectContext = closure.context.intoAnonymousClass(closure, getBindingContext().get(BindingContext.CLASS, objectDeclaration), OwnerKind.IMPLEMENTATION); + final CodegenContext objectContext = closure.context.intoAnonymousClass(closure, getBindingContext().get(BindingContext.CLASS, objectDeclaration), OwnerKind.IMPLEMENTATION, typeMapper); new ImplementationBodyCodegen(objectDeclaration, objectContext, nameAndVisitor.getSecond(), this).generate(null); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index d9a6678e5f2..5a552c69372 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -267,7 +267,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { ConstructorDescriptor constructorDescriptor = bindingContext.get(BindingContext.CONSTRUCTOR, myClass); - CodegenContext.ConstructorContext constructorContext = context.intoConstructor(constructorDescriptor); + CodegenContext.ConstructorContext constructorContext = context.intoConstructor(constructorDescriptor, typeMapper); Method constructorMethod; CallableMethod callableMethod; diff --git a/compiler/testData/codegen/classes/nonnullarray.jet b/compiler/testData/codegen/classes/nonnullarray.jet new file mode 100644 index 00000000000..2e480979e6b --- /dev/null +++ b/compiler/testData/codegen/classes/nonnullarray.jet @@ -0,0 +1,8 @@ +class A() { + class B(val i: Int) { + } + + fun test() = Array (10, { B(it) }) +} + +fun box() = if(A().test()[5].i == 5) "OK" else "fail" diff --git a/compiler/testData/codegen/regressions/kt694.jet b/compiler/testData/codegen/regressions/kt694.jet new file mode 100644 index 00000000000..698558d3642 --- /dev/null +++ b/compiler/testData/codegen/regressions/kt694.jet @@ -0,0 +1,9 @@ +namespace org2 + +enum class Test { + A + B + C +} + +fun box() = Test.A.toString() diff --git a/compiler/tests/org/jetbrains/jet/codegen/ArrayGenTest.java b/compiler/tests/org/jetbrains/jet/codegen/ArrayGenTest.java index f5e8faf941a..5de65ac38f6 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/ArrayGenTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/ArrayGenTest.java @@ -286,4 +286,9 @@ public class ArrayGenTest extends CodegenTestCase { // System.out.println(generateToText()); blackBox(); } + + public void testNonNullArray() throws Exception { + blackBoxFile("classes/nonnullarray.jet"); + System.out.println(generateToText()); + } } diff --git a/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java b/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java index 1f300ca6406..d588a2b8207 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java @@ -1,5 +1,7 @@ package org.jetbrains.jet.codegen; +import org.jetbrains.jet.lang.psi.JetNamespace; + import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; @@ -216,6 +218,10 @@ public class ClassGenTest extends CodegenTestCase { blackBoxFile("regressions/kt500.jet"); } + public void testKt694 () throws Exception { + blackBoxFile("regressions/kt694.jet"); + } + public void testKt285 () throws Exception { // blackBoxFile("regressions/kt285.jet"); } diff --git a/examples/src/benchmarks/ThreadRing.java b/examples/src/benchmarks/ThreadRing.java new file mode 100644 index 00000000000..f4ffe660979 --- /dev/null +++ b/examples/src/benchmarks/ThreadRing.java @@ -0,0 +1,137 @@ +/** + * The Computer Language Benchmarks Game + * http://shootout.alioth.debian.org/ + * + * contributed by Fabien Le Floc'h + * + * Java implementation of thread-ring benchmark. Best performance is achieved with + * MAX_THREAD=1 as the thread-ring test is bested with only 1 os thread. + * This implementation shows using a simple thread pool solves the thread context + * switch issue. + */ + +import java.util.concurrent.*; + +public class ThreadRing { + private static final int MAX_NODES = 503; + private static final int MAX_THREADS = 503; + + private ExecutorService executor; + private final int N; + + static final CountDownLatch cdl = new CountDownLatch(1); + + public static void main(String[] args) throws InterruptedException { + long start = System.currentTimeMillis(); + int n = 5000000; + try { + n = Integer.parseInt(args[0]); + } catch (Exception e) {} + ThreadRing ring = new ThreadRing(n); + Node node = ring.start(MAX_NODES); + node.sendMessage(new TokenMessage(1,0)); + cdl.await(); + + long total = System.currentTimeMillis() - start; + System.out.println("[ThreadRing-" + System.getProperty("project.name")+ " Benchmark Result: " + total + "]"); + } + + public ThreadRing(int n) { + N = n; + } + + public Node start(int n) { + Node[] nodes = spawnNodes(n); + connectNodes(n, nodes); + return nodes[0]; + } + + private Node[] spawnNodes(int n) { + executor = Executors.newFixedThreadPool(MAX_THREADS); + Node[] nodes = new Node[n+1]; + for (int i = 0; i < n ; i++) { + nodes[i] = new Node(i+1, null); + } + return nodes; + } + + public void connectNodes(int n, Node[] nodes) { + nodes[n] = nodes[0]; + for (int i=0; i queue = new LinkedBlockingQueue(); + private boolean isActive = false; + private int counter; + + public Node(int id, Node nextNode) { + this.nodeId = id; + this.nextNode = nextNode; + this.counter = 0; + } + + public void connect(Node node) { + this.nextNode = node; + isActive = true; + } + + public void sendMessage(TokenMessage m) { + queue.add(m); + executor.execute(this); + } + + + public void run() { + if (isActive) { + try { + TokenMessage m = queue.take(); + if (m.isStop) { + int nextValue = m.value+1; + if (nextValue == MAX_NODES) { +// System.out.println("last one"); + executor.shutdown(); + cdl.countDown(); + } else { + m.value = nextValue; + nextNode.sendMessage(m); + } + isActive = false; +// System.out.println("ending node "+nodeId); + } else { + if (m.value == N) { + System.out.println(nodeId); + nextNode.sendMessage(new TokenMessage(nodeId, 0, true)); + } else { + m.value = m.value + 1; + nextNode.sendMessage(m); + } + } + } catch (InterruptedException ie) { + ie.printStackTrace(); + } + } + } + } +} \ No newline at end of file diff --git a/examples/src/benchmarks/ThreadRing.kt b/examples/src/benchmarks/ThreadRing.kt new file mode 100644 index 00000000000..17547adefdd --- /dev/null +++ b/examples/src/benchmarks/ThreadRing.kt @@ -0,0 +1,95 @@ +namespace threadring + +import java.util.concurrent.*; +import java.util.concurrent.atomic.*; + +val MAX_NODES = 503 +val MAX_THREADS = 503 + +val cdl = CountDownLatch(1) + +fun main(args: Array) { + val start = System.currentTimeMillis() + var n = 5000000; + try { + n = Integer.parseInt(args[0]); + } catch (e: Throwable) { + } + + val ring = ThreadRing(n) + ring.sendMessage(TokenMessage(1,0,false)) + cdl.await(); + + val total = System.currentTimeMillis() - start + System.out?.println("[ThreadRing-" + System.getProperty("project.name")+ " Benchmark Result: " + total + "]") +} + +class TokenMessage(val nodeId : Int, value: Int, val isStop: Boolean) : AtomicInteger(value){ +} + +class ThreadRing(val N: Int) { + val executor = Executors.newFixedThreadPool(MAX_THREADS).sure() + + val nodes : Array = Array(MAX_NODES+1, { Node(it+1) }) + + { + connectNodes() + } + + fun connectNodes() { + nodes[nodes.size-1] = nodes[0] + for (i in 0..nodes.size-2) { + nodes[i].connect(nodes[i+1]); + } + } + + fun sendMessage(m : TokenMessage) { + nodes[0].sendMessage(m) + } + class Node(val nodeId : Int) : Runnable { + val queue = LinkedBlockingQueue() + var isActive = false + var nextNode : Node? = null + + fun sendMessage(m: TokenMessage) { + queue.add(m) + executor.execute(this) + } + + fun connect(next: Node) { + nextNode = next + isActive = true + } + + override fun run() { + if(isActive) { + try { + val m = queue.take() + if(m.isStop) { + val nextValue = m.get()+1 + if (nextValue == MAX_NODES) { + executor.shutdown() + cdl.countDown() + } else { + m.set(nextValue) + nextNode.sure().sendMessage(m) + } + isActive = false + } + else { + if (m.get() == N) { + System.out?.println(nodeId); + nextNode.sure().sendMessage(TokenMessage(nodeId, 0, true)); + } else { + m.incrementAndGet() + nextNode.sure().sendMessage(m); + } + } + } + catch(e: InterruptedException) { + e.printStackTrace() + } + } + } + } +} From 2d9424873159ab1dd71bfd9bd25682e9c7e44056 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Wed, 7 Dec 2011 11:54:23 +0200 Subject: [PATCH 15/15] accidentally commited not finished test commented --- compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java b/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java index d588a2b8207..0de47ea91ab 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java @@ -219,7 +219,7 @@ public class ClassGenTest extends CodegenTestCase { } public void testKt694 () throws Exception { - blackBoxFile("regressions/kt694.jet"); +// blackBoxFile("regressions/kt694.jet"); } public void testKt285 () throws Exception {