diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index fbdec54b7f9..75f29f34539 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -1864,12 +1864,23 @@ public class ExpressionCodegen extends JetVisitor { } private void callAugAssignMethod(JetBinaryExpression expression, CallableMethod callable, Type lhsType, final boolean keepReturnValue) { + ResolvedCall resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, expression.getOperationReference()); + assert resolvedCall != null; + StackValue value = gen(expression.getLeft()); if (keepReturnValue) { value.dupReceiver(v); } value.put(lhsType, v); - genToJVMStack(expression.getRight()); + StackValue receiver = StackValue.onStack(lhsType); + + if(!(resolvedCall.getResultingDescriptor() instanceof ConstructorDescriptor)) { // otherwise already + receiver = StackValue.receiver(resolvedCall, receiver, this, callable); + receiver.put(receiver.type, v); + } + + pushTypeArguments(resolvedCall); + pushMethodArguments(resolvedCall, callable.getValueParameterTypes()); callable.invoke(v); if (keepReturnValue) { value.store(v); 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 eeb091c419e..61ca8881c90 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ImportsResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ImportsResolver.java @@ -69,22 +69,20 @@ public class ImportsResolver { if (importedReference == null) return; Collection descriptors; if (importedReference instanceof JetQualifiedExpression) { - descriptors = lookupDescriptorsForQualifiedExpression((JetQualifiedExpression) importedReference, namespaceScope); + descriptors = lookupDescriptorsForQualifiedExpression((JetQualifiedExpression) importedReference, + namespaceScope, !importDirective.isAllUnder()); } else { assert importedReference instanceof JetSimpleNameExpression; - if (importDirective.isAllUnder()) { - // Example: import java.* - descriptors = lookupDescriptorsForSimpleNameReference((JetSimpleNameExpression) importedReference, namespaceScope); - } - else { - // Example: import IDENTIFIER - // Should be unresolved error - descriptors = lookupDescriptorsForSimpleNameReference((JetSimpleNameExpression) importedReference, JetScope.EMPTY); - trace.record(BindingContext.RESOLUTION_SCOPE, importedReference, namespaceScope); - } + // for "import java.*" there's should be a correct resolving + // but for "import SomeClass" we want to get unresolved error, even if SomeClass descriptor exist in outer scope + JetScope resolveScope = importDirective.isAllUnder() ? namespaceScope : JetScope.EMPTY; + + descriptors = lookupDescriptorsForSimpleNameReference((JetSimpleNameExpression) importedReference, + resolveScope, namespaceScope, !importDirective.isAllUnder()); } + JetSimpleNameExpression referenceExpression = getLastReference(importedReference); if (importDirective.isAllUnder()) { if (referenceExpression == null || !canImportMembersFrom(descriptors, referenceExpression)) return; @@ -153,16 +151,19 @@ public class ImportsResolver { } @NotNull - private Collection lookupDescriptorsForQualifiedExpression(@NotNull JetQualifiedExpression importedReference, @NotNull JetScope outerScope) { + private Collection lookupDescriptorsForQualifiedExpression( + @NotNull JetQualifiedExpression importedReference, @NotNull JetScope outerScope, boolean isForLastPart) { + JetExpression receiverExpression = importedReference.getReceiverExpression(); Collection declarationDescriptors; if (receiverExpression instanceof JetQualifiedExpression) { - declarationDescriptors = lookupDescriptorsForQualifiedExpression((JetQualifiedExpression) receiverExpression, outerScope); + declarationDescriptors = lookupDescriptorsForQualifiedExpression((JetQualifiedExpression) receiverExpression, outerScope, false); } else { assert receiverExpression instanceof JetSimpleNameExpression; - declarationDescriptors = lookupDescriptorsForSimpleNameReference((JetSimpleNameExpression) receiverExpression, outerScope); + declarationDescriptors = lookupDescriptorsForSimpleNameReference((JetSimpleNameExpression) receiverExpression, outerScope, false); } + JetExpression selectorExpression = importedReference.getSelectorExpression(); assert selectorExpression instanceof JetSimpleNameExpression; JetSimpleNameExpression selector = (JetSimpleNameExpression) selectorExpression; @@ -173,7 +174,7 @@ public class ImportsResolver { Collection result; for (DeclarationDescriptor declarationDescriptor : declarationDescriptors) { if (declarationDescriptor instanceof NamespaceDescriptor) { - result = lookupDescriptorsForSimpleNameReference(selector, ((NamespaceDescriptor) declarationDescriptor).getMemberScope()); + result = lookupDescriptorsForSimpleNameReference(selector, ((NamespaceDescriptor) declarationDescriptor).getMemberScope(), isForLastPart); if (!result.isEmpty()) return result; } if (declarationDescriptor instanceof ClassDescriptor) { @@ -205,7 +206,9 @@ public class ImportsResolver { return canImport; } - private boolean canImportMembersFrom(@NotNull DeclarationDescriptor descriptor, @NotNull JetSimpleNameExpression reference, @NotNull BindingTrace trace) { + private boolean canImportMembersFrom(@NotNull DeclarationDescriptor descriptor, + @NotNull JetSimpleNameExpression reference, + @NotNull BindingTrace trace) { assert !firstPhase; if (descriptor instanceof NamespaceDescriptor) { return true; @@ -235,7 +238,7 @@ public class ImportsResolver { if (firstPhase) return Collections.emptyList(); JetType classObjectType = classDescriptor.getClassObjectType(); assert classObjectType != null; - Collection members = lookupDescriptorsForSimpleNameReference(memberReference, classObjectType.getMemberScope()); + Collection members = lookupDescriptorsForSimpleNameReference(memberReference, classObjectType.getMemberScope(), true); return addBoundToReceiver(members, classDescriptor); } @@ -247,7 +250,7 @@ public class ImportsResolver { ClassDescriptor innerClass = classDescriptor.getInnerClass(memberReference.getReferencedName()); if (innerClass == null) return Collections.emptyList(); descriptors = Collections.singletonList(innerClass); - recordReference(descriptors, memberReference, JetScope.EMPTY); + storeResolutionResult(descriptors, memberReference, JetScope.EMPTY, true); } else { descriptors = classDescriptor.getInnerClasses(); @@ -260,17 +263,42 @@ public class ImportsResolver { JetType variableType = variableDescriptor.getReturnType(); if (variableType == null) return Collections.emptyList(); - Collection members = lookupDescriptorsForSimpleNameReference(memberReference, variableType.getMemberScope()); + Collection members = lookupDescriptorsForSimpleNameReference(memberReference, variableType.getMemberScope(), true); return addBoundToReceiver(members, variableDescriptor); } @NotNull - public static Collection addBoundToReceiver(@NotNull Collection descriptors, @NotNull final DeclarationDescriptor receiver) { + public static Collection addBoundToReceiver(@NotNull Collection descriptors, + @NotNull final DeclarationDescriptor receiver) { return Collections2.transform(descriptors, DescriptorUtils.getAddBoundToReceiverFunction(receiver)); } @NotNull - private Collection lookupDescriptorsForSimpleNameReference(@NotNull JetSimpleNameExpression referenceExpression, @NotNull JetScope outerScope) { + private Collection lookupDescriptorsForSimpleNameReference( + @NotNull JetSimpleNameExpression referenceExpression, + @NotNull JetScope outerScope, + boolean isLastPart) { + + return lookupDescriptorsForSimpleNameReference(referenceExpression, outerScope, outerScope, isLastPart); + } + + /** + * + * @param referenceExpression + * @param outerScope + * @param bindingScope scope for searching completion descriptors. In most cases it's equal to outer scope + * but for case "import SomeIdentifier" we want an unresolved reference error, so give empty + * outer scope. + * @param isLastPart is the part given by referenceExpression last in import directive. Parameter should be false + * if there's .* after it or some other parts in full qualified name. + * @return + */ + @NotNull + private Collection lookupDescriptorsForSimpleNameReference( + @NotNull JetSimpleNameExpression referenceExpression, + @NotNull JetScope outerScope, + @NotNull JetScope bindingScope, + boolean isLastPart) { List descriptors = Lists.newArrayList(); String referencedName = referenceExpression.getReferencedName(); @@ -288,25 +316,33 @@ public class ImportsResolver { descriptors.addAll(outerScope.getProperties(referencedName)); } - recordReference(descriptors, referenceExpression, outerScope); + + storeResolutionResult(descriptors, referenceExpression, bindingScope, isLastPart); + return descriptors; } - private void recordReference(Collection descriptors, JetSimpleNameExpression referenceExpression, JetScope outerScope) { - if (firstPhase) return; - if (descriptors.size() == 1) { - trace.record(BindingContext.REFERENCE_TARGET, referenceExpression, descriptors.iterator().next()); - } - else if (descriptors.size() > 1) { - trace.record(BindingContext.AMBIGUOUS_REFERENCE_TARGET, referenceExpression, descriptors); - } - else { - trace.report(UNRESOLVED_REFERENCE.on(referenceExpression)); - } + private void storeResolutionResult( + @NotNull Collection descriptors, + @NotNull JetSimpleNameExpression referenceExpression, + @NotNull JetScope resolutionScope, + boolean isLastPart) { - // If it's not an ambiguous case - store resolution scope - if (descriptors.size() <= 1 && outerScope != JetScope.EMPTY) { - trace.record(BindingContext.RESOLUTION_SCOPE, referenceExpression, outerScope); + if (!firstPhase) { + if (descriptors.size() == 1 && !(isLastPart && descriptors.iterator().next() instanceof NamespaceDescriptor)) { + trace.record(BindingContext.REFERENCE_TARGET, referenceExpression, descriptors.iterator().next()); + } + else if (descriptors.size() > 1) { + trace.record(BindingContext.AMBIGUOUS_REFERENCE_TARGET, referenceExpression, descriptors); + } + else { + trace.report(UNRESOLVED_REFERENCE.on(referenceExpression)); + } + + // If it's not an ambiguous case - store resolution scope + if (descriptors.size() <= 1) { + trace.record(BindingContext.RESOLUTION_SCOPE, referenceExpression, resolutionScope); + } } } } diff --git a/compiler/testData/codegen/regressions/kt935.kt b/compiler/testData/codegen/regressions/kt935.kt new file mode 100644 index 00000000000..7b76c881cdf --- /dev/null +++ b/compiler/testData/codegen/regressions/kt935.kt @@ -0,0 +1,30 @@ +package bottles + +fun box() : String { + var bottles = 10 + while (bottles > 0) { + print(bottlesOfBeer(bottles) + " on the wall, ") + println(bottlesOfBeer(bottles) + ".") + print("Take one down, pass it around, ") + if (--bottles == 0) { + println("no more bottles of beer on the wall.") + } + else { + println(bottlesOfBeer(bottles) + " on the wall.") + } + } + return "OK" +} + +fun bottlesOfBeer(count : Int) : String { + val result = StringBuilder() + result += count + result += if (count > 1) " bottles of beer" else " bottle of beer" + return result.toString() ?: "" +} + +// An excerpt from the standard library +fun print(message : String) { System.out?.print(message) } +fun println(message : String) { System.out?.println(message) } +fun StringBuilder.plusAssign(o : Any) { append(o) } +val Array.isEmpty : Boolean get() = size == 0 \ 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 77eeccc0997..fc073e4bd1f 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java @@ -387,4 +387,8 @@ public class PrimitiveTypesTest extends CodegenTestCase { public void testKt945 () { blackBoxFile("regressions/kt945.jet"); } + + public void testKt935 () { + blackBoxFile("regressions/kt935.kt"); + } } diff --git a/idea/testData/checker/regression/kt960.jet b/idea/testData/checker/regression/kt960.jet new file mode 100644 index 00000000000..0371e95fabf --- /dev/null +++ b/idea/testData/checker/regression/kt960.jet @@ -0,0 +1,8 @@ +// KT-960 import namespace should give unresolved reference +package some + +import java.util + +class Test { + +} \ No newline at end of file