diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorWithImplicitReceiver.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorWithImplicitReceiver.java new file mode 100644 index 00000000000..136be2a5019 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorWithImplicitReceiver.java @@ -0,0 +1,123 @@ +package org.jetbrains.jet.lang.descriptors; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; +import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; +import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.TypeSubstitutor; + +import java.util.List; +import java.util.Set; + +/** + * @author svtk + */ +public class FunctionDescriptorWithImplicitReceiver implements FunctionDescriptor { + + private FunctionDescriptor functionDescriptor; + private DeclarationDescriptor implicitReceiver; + + public FunctionDescriptorWithImplicitReceiver(@NotNull FunctionDescriptor functionDescriptor, @NotNull DeclarationDescriptor implicitReceiver) { + this.functionDescriptor = functionDescriptor; + this.implicitReceiver = implicitReceiver; + } + + public FunctionDescriptor getFunctionDescriptor() { + return functionDescriptor; + } + + public DeclarationDescriptor getImplicitReceiver() { + return implicitReceiver; + } + + @NotNull + @Override + public DeclarationDescriptor getContainingDeclaration() { + return functionDescriptor.getContainingDeclaration(); + } + + @NotNull + @Override + public FunctionDescriptor getOriginal() { + return functionDescriptor.getOriginal(); + } + + @Override + public FunctionDescriptor substitute(TypeSubstitutor substitutor) { + return functionDescriptor.substitute(substitutor); + } + + @NotNull + @Override + public Set getOverriddenDescriptors() { + return functionDescriptor.getOverriddenDescriptors(); + } + + @NotNull + @Override + public FunctionDescriptor copy(DeclarationDescriptor newOwner, boolean makeNonAbstract) { + return functionDescriptor.copy(newOwner, makeNonAbstract); + } + + @NotNull + @Override + public ReceiverDescriptor getReceiverParameter() { + return ReceiverDescriptor.NO_RECEIVER; + } + + @NotNull + @Override + public ReceiverDescriptor getExpectedThisObject() { + return ReceiverDescriptor.NO_RECEIVER; + } + + @NotNull + @Override + public List getTypeParameters() { + return functionDescriptor.getTypeParameters(); + } + + @Override + public JetType getReturnType() { + return functionDescriptor.getReturnType(); + } + + @NotNull + @Override + public List getValueParameters() { + return functionDescriptor.getValueParameters(); + } + + @NotNull + @Override + public Modality getModality() { + return functionDescriptor.getModality(); + } + + @NotNull + @Override + public Visibility getVisibility() { + return functionDescriptor.getVisibility(); + } + + @Override + public R accept(DeclarationDescriptorVisitor visitor, D data) { + return functionDescriptor.accept(visitor, data); + } + + @Override + public void acceptVoid(DeclarationDescriptorVisitor visitor) { + functionDescriptor.acceptVoid(visitor); + } + + @Override + public List getAnnotations() { + return functionDescriptor.getAnnotations(); + } + + @NotNull + @Override + public String getName() { + return functionDescriptor.getName(); + } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/VariableDescriptorWithImplicitReceiver.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/VariableDescriptorWithImplicitReceiver.java new file mode 100644 index 00000000000..a8cbc4b3af5 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/VariableDescriptorWithImplicitReceiver.java @@ -0,0 +1,119 @@ +package org.jetbrains.jet.lang.descriptors; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; +import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; +import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.TypeSubstitutor; + +import java.util.List; +import java.util.Set; + +/** + * @author svtk + */ +public class VariableDescriptorWithImplicitReceiver implements VariableDescriptor { + private VariableDescriptor variableDescriptor; + private DeclarationDescriptor implicitReceiver; + + public VariableDescriptorWithImplicitReceiver(VariableDescriptor variableDescriptor, DeclarationDescriptor implicitReceiver) { + this.variableDescriptor = variableDescriptor; + this.implicitReceiver = implicitReceiver; + } + + public VariableDescriptor getVariableDescriptor() { + return variableDescriptor; + } + + public DeclarationDescriptor getImplicitReceiver() { + return implicitReceiver; + } + + @Override + public JetType getOutType() { + return variableDescriptor.getOutType(); + } + + @Override + public JetType getInType() { + return variableDescriptor.getInType(); + } + + @NotNull + @Override + public DeclarationDescriptor getContainingDeclaration() { + return variableDescriptor.getContainingDeclaration(); + } + + @NotNull + @Override + public ReceiverDescriptor getReceiverParameter() { + return ReceiverDescriptor.NO_RECEIVER; + } + + @NotNull + @Override + public ReceiverDescriptor getExpectedThisObject() { + return ReceiverDescriptor.NO_RECEIVER; + } + + @NotNull + @Override + public List getTypeParameters() { + return variableDescriptor.getTypeParameters(); + } + + @Override + public JetType getReturnType() { + return variableDescriptor.getReturnType(); + } + + @NotNull + @Override + public CallableDescriptor getOriginal() { + return variableDescriptor.getOriginal(); + } + + @Override + public VariableDescriptor substitute(TypeSubstitutor substitutor) { + return variableDescriptor.substitute(substitutor); + } + + @Override + public R accept(DeclarationDescriptorVisitor visitor, D data) { + return variableDescriptor.accept(visitor, data); + } + + @Override + public void acceptVoid(DeclarationDescriptorVisitor visitor) { + variableDescriptor.acceptVoid(visitor); + } + + @NotNull + @Override + public List getValueParameters() { + return variableDescriptor.getValueParameters(); + } + + @NotNull + @Override + public Set getOverriddenDescriptors() { + return variableDescriptor.getOverriddenDescriptors(); + } + + @Override + public boolean isVar() { + return variableDescriptor.isVar(); + } + + @Override + public List getAnnotations() { + return variableDescriptor.getAnnotations(); + } + + @NotNull + @Override + public String getName() { + return variableDescriptor.getName(); + } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ImportsResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ImportsResolver.java index 2735a9eb566..26e1a3c01c5 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ImportsResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ImportsResolver.java @@ -1,5 +1,7 @@ package org.jetbrains.jet.lang.resolve; +import com.google.common.base.Function; +import com.google.common.collect.Collections2; import com.google.common.collect.Lists; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -101,19 +103,17 @@ public class ImportsResolver { if (firstPhase) { if (descriptor instanceof ClassifierDescriptor) { namespaceScope.importClassifierAlias(aliasName, (ClassifierDescriptor) descriptor); - return; } if (descriptor instanceof NamespaceDescriptor) { namespaceScope.importNamespaceAlias(aliasName, (NamespaceDescriptor) descriptor); - return; } + return; } if (descriptor instanceof FunctionDescriptor) { namespaceScope.importFunctionAlias(aliasName, (FunctionDescriptor) descriptor); - return; } - if (descriptor instanceof PropertyDescriptor) { - namespaceScope.importVariableAlias(aliasName, (PropertyDescriptor) descriptor); + if (descriptor instanceof VariableDescriptor) { + namespaceScope.importVariableAlias(aliasName, (VariableDescriptor) descriptor); } } @@ -167,7 +167,7 @@ public class ImportsResolver { trace.report(NO_CLASS_OBJECT.on(classReference, classDescriptor)); return Collections.emptyList(); } - return lookupDescriptorsForSimpleNameReference(memberReference, classObjectType.getMemberScope()); + return addImplicitReceiver(lookupDescriptorsForSimpleNameReference(memberReference, classObjectType.getMemberScope()), classDescriptor); } @NotNull @@ -176,9 +176,25 @@ public class ImportsResolver { JetType variableType = variableDescriptor.getReturnType(); if (variableType == null) return Collections.emptyList(); - return lookupDescriptorsForSimpleNameReference(memberReference, variableType.getMemberScope()); + return addImplicitReceiver(lookupDescriptorsForSimpleNameReference(memberReference, variableType.getMemberScope()), variableDescriptor); } + @NotNull + private static Collection addImplicitReceiver(@NotNull Collection descriptors, @NotNull final DeclarationDescriptor implicitReceiver) { + return Collections2.transform(descriptors, new Function() { + @Override + public DeclarationDescriptor apply(@Nullable DeclarationDescriptor descriptor) { + if (descriptor instanceof FunctionDescriptor) { + return new FunctionDescriptorWithImplicitReceiver((FunctionDescriptor) descriptor, implicitReceiver); + } + if (descriptor instanceof VariableDescriptor) { + return new VariableDescriptorWithImplicitReceiver((VariableDescriptor) descriptor, implicitReceiver); + } + return descriptor; + } + }); + } + @NotNull private Collection lookupDescriptorsForSimpleNameReference(@NotNull JetSimpleNameExpression referenceExpression, @NotNull JetScope outerScope) { List descriptors = Lists.newArrayList(); 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 be455d54bd6..993c9b8fb70 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 @@ -21,7 +21,7 @@ public interface WritableScope extends JetScope { void addVariableDescriptor(@NotNull VariableDescriptor variableDescriptor); - void addPropertyDescriptor(@NotNull PropertyDescriptor propertyDescriptor); + void addPropertyDescriptor(@NotNull VariableDescriptor propertyDescriptor); void addFunctionDescriptor(@NotNull FunctionDescriptor functionDescriptor); @@ -52,5 +52,5 @@ public interface WritableScope extends JetScope { void importFunctionAlias(@NotNull String aliasName, @NotNull FunctionDescriptor functionDescriptor); - void importVariableAlias(@NotNull String aliasName, @NotNull PropertyDescriptor variableDescriptor); + void importVariableAlias(@NotNull String aliasName, @NotNull VariableDescriptor variableDescriptor); } 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 8c73ddbe2c5..2180d9022b0 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 @@ -89,7 +89,7 @@ public class WritableScopeImpl extends WritableScopeWithImports { } @Override - public void importVariableAlias(@NotNull String aliasName, @NotNull PropertyDescriptor variableDescriptor) { + public void importVariableAlias(@NotNull String aliasName, @NotNull VariableDescriptor variableDescriptor) { checkMayWrite(); addPropertyDescriptor(variableDescriptor); @@ -173,7 +173,7 @@ public class WritableScopeImpl extends WritableScopeWithImports { } @Override - public void addPropertyDescriptor(@NotNull PropertyDescriptor propertyDescriptor) { + public void addPropertyDescriptor(@NotNull VariableDescriptor propertyDescriptor) { addVariableDescriptor(propertyDescriptor, true); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WritableScopeWithImports.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WritableScopeWithImports.java index 285b16ab0f1..3d26fdaa2e8 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WritableScopeWithImports.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/WritableScopeWithImports.java @@ -193,7 +193,7 @@ public abstract class WritableScopeWithImports extends JetScopeAdapter implement } @Override - public void importVariableAlias(@NotNull String aliasName, @NotNull PropertyDescriptor variableDescriptor) { + public void importVariableAlias(@NotNull String aliasName, @NotNull VariableDescriptor variableDescriptor) { checkMayWrite(); getCurrentIndividualImportScope().addVariableAlias(aliasName, variableDescriptor); 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 43c5c1d1ffc..1a57a7c84bf 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 @@ -139,7 +139,7 @@ public class WriteThroughScope extends WritableScopeWithImports { } @Override - public void addPropertyDescriptor(@NotNull PropertyDescriptor propertyDescriptor) { + public void addPropertyDescriptor(@NotNull VariableDescriptor propertyDescriptor) { checkMayWrite(); writableWorker.addPropertyDescriptor(propertyDescriptor); diff --git a/compiler/testData/diagnostics/tests/scopes/Imports.jet b/compiler/testData/diagnostics/tests/scopes/Imports.jet index 8ff30e6834d..e36a07aa110 100644 --- a/compiler/testData/diagnostics/tests/scopes/Imports.jet +++ b/compiler/testData/diagnostics/tests/scopes/Imports.jet @@ -7,10 +7,20 @@ import b.ext //extension function import b.value //property import b.C.bar //function from class object import b.C.cValue //property from class object +import b.constant.fff //function from val +import b.constant.dValue //property from val +import b.E.f //val from class object fun test(arg: B) { foo(value) arg.ext() + + bar() + foo(cValue) + + fff(dValue) + + f.f() } //FILE:b.kt @@ -18,7 +28,7 @@ package b class B() {} -fun foo(i: Int) {} +fun foo(i: Int) = i fun B.ext() {} @@ -29,4 +39,21 @@ class C() { fun bar() {} val cValue = 1 } +} + +class D() { + fun fff(s: String) = s + val dValue = "w" +} + +val constant = D() + +class E() { + class object { + val f = F() + } +} + +class F() { + fun f() {} } \ No newline at end of file diff --git a/stdlib/ktSrc/JavaIterablesSpecial.kt b/stdlib/ktSrc/JavaIterablesSpecial.kt new file mode 100644 index 00000000000..2e30749f216 --- /dev/null +++ b/stdlib/ktSrc/JavaIterablesSpecial.kt @@ -0,0 +1,85 @@ +package std.util +// Number of extension function for ava.lang.Iterable that shouldn't participate in auto generation + +import java.util.Collection +import java.util.List +import java.util.AbstractList + +/** + * Count the number of elements in collection. + * + * If base collection implements Collection interface method Collection#size() will be used. + * Otherwise, this method determines the count by iterating through the all items. + */ +fun java.lang.Iterable.count() : Int { + if (this is Collection) { + return this.size() + } + + var number : Int = 0 + for (elem in this) { + ++number + } + return number +} + +/** + * Get the first element in the collection. + * + * Will throw an exception if there are no elements + * TODO: Specify type of the exception + */ +inline fun java.lang.Iterable.first() : T { + if (this is AbstractList) { + return this.get(0) + } + + return this.iterator().sure().next() +} + +/** + * Get the last element in the collection. + * + * If base collection implements List interface, the combination of size() and get() + * methods will be used for getting last element. Otherwise, this method determines the + * last item by iterating through the all items. + * + * Will throw an exception if there are no elements. + * TODO: Specify type of the exception + */ +fun java.lang.Iterable.last() : T { + if (this is List) { + return this.get(this.size() - 1); + } + + val iterator = this.iterator().sure() + var last : T = iterator.next() + + while (iterator.hasNext()) { + last = iterator.next() + } + + return last; +} + +/** + * Checks if collection contains given item. + * + * Method checks equality of the objects with T.equals method. + * If collection implements java.util.AbstractCollection an overridden implementation of the contains + * method will be used. + */ +fun java.lang.Iterable.contains(item : T) : Boolean { + std.io.println("!!!!!") + if (this is java.util.AbstractCollection) { + return this.contains(item); + } + + for (var elem in this) { + if (elem.equals(item)) { + return true + } + } + + return false +} \ No newline at end of file diff --git a/testlib/src/Test.kt b/testlib/src/Test.kt index 7694865d2a1..d6e0a26e9c3 100644 --- a/testlib/src/Test.kt +++ b/testlib/src/Test.kt @@ -81,6 +81,14 @@ fun assert(actual: Boolean, message: String) { println("Answer: ${actual} for ${message}") } +fun assertTrue(actual: Boolean, message: String = "") { + return assertEquals(true, actual, message) +} + +fun assertFalse(actual: Boolean, message: String = "") { + return assertEquals(false, actual, message) +} + fun assertEquals(expected: Any, actual: Any?, message: String = "") { Assert.assertEquals(message, expected, actual) } diff --git a/testlib/test/CollectionTest.kt b/testlib/test/CollectionTest.kt index 5fc1a980b4a..3cfd2f7b6fe 100644 --- a/testlib/test/CollectionTest.kt +++ b/testlib/test/CollectionTest.kt @@ -9,6 +9,16 @@ import std.test.* import java.util.* class CollectionTest() : TestSupport() { + + class IterableWrapper(collection : java.lang.Iterable) : java.lang.Iterable { + private val collection = collection + + override fun iterator(): java.util.Iterator { + return collection.iterator().sure() + } + } + + val data = arrayList("foo", "bar") fun testAny() { @@ -177,4 +187,39 @@ class CollectionTest() : TestSupport() { } } } + + fun testSimpleCount() { + assertEquals(2, data.count()) + assertEquals(3, hashSet(12, 14, 15).count()) + assertEquals(0, ArrayList().count()) + } + + fun testLast() { + assertEquals("bar", data.last()) + assertEquals(25, arrayList(15, 19, 20, 25).last()) + // assertEquals(19, TreeSet(arrayList(90, 47, 19)).first()) + assertEquals('a', linkedList('a').last()) + } + + fun testLastException() { + fails { arrayList().last() } + fails { linkedList().last() } + fails { hashSet().last() } + } + + fun testContains() { + assertTrue(data.contains("foo")) + assertTrue(data.contains("bar")) + assertFalse(data.contains("some")) + + // TODO: Problems with generation +// assertTrue(IterableWrapper(data).contains("bar")) +// assertFalse(IterableWrapper(data).contains("some")) + + assertFalse(hashSet().contains(12)) + assertTrue(linkedList(15, 19, 20).contains(15)) + +// assertTrue(IterableWrapper(hashSet(45, 14, 13)).contains(14)) +// assertFalse(IterableWrapper(linkedList()).contains(15)) + } } \ No newline at end of file