diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorWithImplicitReceiver.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorBoundToReceiver.java similarity index 87% rename from compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorWithImplicitReceiver.java rename to compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorBoundToReceiver.java index 136be2a5019..ca19d1d236e 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorWithImplicitReceiver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorBoundToReceiver.java @@ -12,22 +12,22 @@ import java.util.Set; /** * @author svtk */ -public class FunctionDescriptorWithImplicitReceiver implements FunctionDescriptor { +public class FunctionDescriptorBoundToReceiver implements FunctionDescriptor { private FunctionDescriptor functionDescriptor; - private DeclarationDescriptor implicitReceiver; + private DeclarationDescriptor receiver; - public FunctionDescriptorWithImplicitReceiver(@NotNull FunctionDescriptor functionDescriptor, @NotNull DeclarationDescriptor implicitReceiver) { + public FunctionDescriptorBoundToReceiver(@NotNull FunctionDescriptor functionDescriptor, @NotNull DeclarationDescriptor receiver) { this.functionDescriptor = functionDescriptor; - this.implicitReceiver = implicitReceiver; + this.receiver = receiver; } public FunctionDescriptor getFunctionDescriptor() { return functionDescriptor; } - public DeclarationDescriptor getImplicitReceiver() { - return implicitReceiver; + public DeclarationDescriptor getReceiver() { + return receiver; } @NotNull diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/VariableDescriptorWithImplicitReceiver.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/VariableDescriptorBoundToReceiver.java similarity index 87% rename from compiler/frontend/src/org/jetbrains/jet/lang/descriptors/VariableDescriptorWithImplicitReceiver.java rename to compiler/frontend/src/org/jetbrains/jet/lang/descriptors/VariableDescriptorBoundToReceiver.java index a8cbc4b3af5..cf423deec90 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/VariableDescriptorWithImplicitReceiver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/VariableDescriptorBoundToReceiver.java @@ -12,21 +12,21 @@ import java.util.Set; /** * @author svtk */ -public class VariableDescriptorWithImplicitReceiver implements VariableDescriptor { +public class VariableDescriptorBoundToReceiver implements VariableDescriptor { private VariableDescriptor variableDescriptor; - private DeclarationDescriptor implicitReceiver; + private DeclarationDescriptor receiver; - public VariableDescriptorWithImplicitReceiver(VariableDescriptor variableDescriptor, DeclarationDescriptor implicitReceiver) { + public VariableDescriptorBoundToReceiver(VariableDescriptor variableDescriptor, DeclarationDescriptor receiver) { this.variableDescriptor = variableDescriptor; - this.implicitReceiver = implicitReceiver; + this.receiver = receiver; } public VariableDescriptor getVariableDescriptor() { return variableDescriptor; } - public DeclarationDescriptor getImplicitReceiver() { - return implicitReceiver; + public DeclarationDescriptor getReceiver() { + return receiver; } @Override 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 26e1a3c01c5..b9b81c3c7c3 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ImportsResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ImportsResolver.java @@ -8,6 +8,7 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.scopes.JetScope; +import org.jetbrains.jet.lang.resolve.scopes.ScopeBoundToReceiver; import org.jetbrains.jet.lang.resolve.scopes.WritableScope; import org.jetbrains.jet.lang.types.JetType; @@ -77,12 +78,21 @@ public class ImportsResolver { descriptors = lookupDescriptorsForSimpleNameReference((JetSimpleNameExpression) importedReference, scope); } if (importDirective.isAllUnder()) { - if (firstPhase) { - for (DeclarationDescriptor descriptor : descriptors) { + for (DeclarationDescriptor descriptor : descriptors) { + if (firstPhase) { if (descriptor instanceof NamespaceDescriptor) { namespaceScope.importScope(((NamespaceDescriptor) descriptor).getMemberScope()); } } + else if (descriptor instanceof VariableDescriptor) { + JetType type = ((VariableDescriptor) descriptor).getOutType(); + if (type != null) { + namespaceScope.importScope(ScopeBoundToReceiver.create(descriptor, type.getMemberScope())); + } + } + else if (descriptor instanceof ClassDescriptor) { + namespaceScope.importScope(ScopeBoundToReceiver.create(descriptor, ((ClassDescriptor) descriptor).getDefaultType().getMemberScope())); + } } return; } @@ -167,7 +177,7 @@ public class ImportsResolver { trace.report(NO_CLASS_OBJECT.on(classReference, classDescriptor)); return Collections.emptyList(); } - return addImplicitReceiver(lookupDescriptorsForSimpleNameReference(memberReference, classObjectType.getMemberScope()), classDescriptor); + return addBoundToReceiver(lookupDescriptorsForSimpleNameReference(memberReference, classObjectType.getMemberScope()), classDescriptor); } @NotNull @@ -176,19 +186,19 @@ public class ImportsResolver { JetType variableType = variableDescriptor.getReturnType(); if (variableType == null) return Collections.emptyList(); - return addImplicitReceiver(lookupDescriptorsForSimpleNameReference(memberReference, variableType.getMemberScope()), variableDescriptor); + return addBoundToReceiver(lookupDescriptorsForSimpleNameReference(memberReference, variableType.getMemberScope()), variableDescriptor); } @NotNull - private static Collection addImplicitReceiver(@NotNull Collection descriptors, @NotNull final DeclarationDescriptor implicitReceiver) { + private static Collection addBoundToReceiver(@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); + return new FunctionDescriptorBoundToReceiver((FunctionDescriptor) descriptor, implicitReceiver); } if (descriptor instanceof VariableDescriptor) { - return new VariableDescriptorWithImplicitReceiver((VariableDescriptor) descriptor, implicitReceiver); + return new VariableDescriptorBoundToReceiver((VariableDescriptor) descriptor, implicitReceiver); } return descriptor; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/ScopeBoundToReceiver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/ScopeBoundToReceiver.java new file mode 100644 index 00000000000..3a1adb599aa --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/ScopeBoundToReceiver.java @@ -0,0 +1,167 @@ +package org.jetbrains.jet.lang.resolve.scopes; + +import com.google.common.base.Function; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.SetMultimap; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; +import org.jetbrains.jet.util.CommonSuppliers; + +import java.util.*; + +/** + * @author svtk + */ +public class ScopeBoundToReceiver implements JetScope { + private final DeclarationDescriptor receiver; + private final JetScope scope; + + private SetMultimap propertiesMap; + private SetMultimap functionsMap; + private Map descriptorsBoundToReceiver; + + public static ScopeBoundToReceiver create(DeclarationDescriptor implicitReceiver, JetScope memberScope) { + return new ScopeBoundToReceiver(implicitReceiver, memberScope); + } + + private ScopeBoundToReceiver(DeclarationDescriptor receiver, JetScope scope) { + this.receiver = receiver; + this.scope = scope; + } + + public DeclarationDescriptor getReceiver() { + return receiver; + } + + private SetMultimap getPropertiesMap() { + if (propertiesMap == null) { + propertiesMap = CommonSuppliers.newLinkedHashSetHashSetMultimap(); + } + return propertiesMap; + } + + private SetMultimap getFunctionsMap() { + if (functionsMap == null) { + functionsMap = CommonSuppliers.newLinkedHashSetHashSetMultimap(); + } + return functionsMap; + } + + private Map getDescriptorsBoundToReceiver() { + if (descriptorsBoundToReceiver == null) { + descriptorsBoundToReceiver = Maps.newHashMap(); + } + return descriptorsBoundToReceiver; + } + + @Nullable + @Override + public ClassifierDescriptor getClassifier(@NotNull String name) { + return scope.getClassifier(name); + } + + @Nullable + @Override + public NamespaceDescriptor getNamespace(@NotNull String name) { + return scope.getNamespace(name); + } + + @NotNull + @Override + public Set getProperties(@NotNull String name) { + if (getPropertiesMap().containsKey(name)) { + return getPropertiesMap().get(name); + } + return getMembersBoundToReceiver(name, getPropertiesMap(), scope.getProperties(name), new Function() { + @Override + public VariableDescriptor apply(VariableDescriptor property) { + return new VariableDescriptorBoundToReceiver(property, receiver); + } + }); + } + + @Nullable + @Override + public VariableDescriptor getLocalVariable(@NotNull String name) { + return scope.getLocalVariable(name); + } + + private Set getMembersBoundToReceiver(String name, SetMultimap cache, Set oldMembers, Function transformation) { + for (D oldMember : oldMembers) { + cache.put(name, transformation.apply(oldMember)); + } + return cache.get(name); + } + + @NotNull + @Override + public Set getFunctions(@NotNull String name) { + if (getFunctionsMap().containsKey(name)) { + return getFunctionsMap().get(name); + } + return getMembersBoundToReceiver(name, getFunctionsMap(), scope.getFunctions(name), new Function() { + @Override + public FunctionDescriptor apply(FunctionDescriptor function) { + return new FunctionDescriptorBoundToReceiver(function, receiver); + } + }); + } + + @NotNull + @Override + public DeclarationDescriptor getContainingDeclaration() { + return scope.getContainingDeclaration(); + } + + @NotNull + @Override + public Collection getDeclarationsByLabel(String labelName) { + return scope.getDeclarationsByLabel(labelName); + } + + @Nullable + @Override + public PropertyDescriptor getPropertyByFieldReference(@NotNull String fieldName) { + return scope.getPropertyByFieldReference(fieldName); + } + + @NotNull + @Override + public Collection getAllDescriptors() { + Collection result = Lists.newArrayList(); + Collection allDescriptors = scope.getAllDescriptors(); + for (DeclarationDescriptor descriptor : allDescriptors) { + if (getDescriptorsBoundToReceiver().containsKey(descriptor)) { + result.add(getDescriptorsBoundToReceiver().get(descriptor)); + continue; + } + if (descriptor instanceof FunctionDescriptor) { + getFunctions(descriptor.getName()); + } + else if (descriptor instanceof VariableDescriptor) { + getProperties(descriptor.getName()); + } + else { + result.add(descriptor); + continue; + } + if (getDescriptorsBoundToReceiver().containsKey(descriptor)) { + result.add(getDescriptorsBoundToReceiver().get(descriptor)); + } + } + return result; + } + + @NotNull + @Override + public ReceiverDescriptor getImplicitReceiver() { + return ReceiverDescriptor.NO_RECEIVER; + } + + @Override + public void getImplicitReceiversHierarchy(@NotNull List result) { + } +} diff --git a/compiler/testData/diagnostics/tests/scopes/Imports.jet b/compiler/testData/diagnostics/tests/scopes/Imports.jet index e36a07aa110..2298476ae4b 100644 --- a/compiler/testData/diagnostics/tests/scopes/Imports.jet +++ b/compiler/testData/diagnostics/tests/scopes/Imports.jet @@ -56,4 +56,19 @@ class E() { class F() { fun f() {} +} + +//FILE:c.kt +package c + +import C.* + +object C { + fun a() { + } + val b = 3 +} + +fun foo() { + if (b == 3) a() } \ No newline at end of file