From 342e9ebe7ad7260280ad35083bca6a2f9998aac5 Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Thu, 13 Jun 2013 20:27:31 +0400 Subject: [PATCH] KT-3563 Compiler requiring java.io.File, and it's unclear why #KT-3563 fixed --- .../jet/lang/resolve/DescriptorUtils.java | 6 +- .../lang/resolve/calls/CallResolverUtil.java | 40 ++++++++++-- .../lang/resolve/calls/CandidateResolver.java | 61 ++++++++++--------- .../tests/extensions/ExtensionFunctions.kt | 2 +- .../diagnostics/tests/extensions/kt3563.kt | 17 ++++++ .../throwOutCandidatesByReceiver.kt | 49 +++++++++++++++ .../tests/inference/regressions/kt742.kt | 4 +- .../diagnostics/tests/regressions/kt557.kt | 2 +- .../resolve/ExtensionFunctions.resolve | 5 +- .../checkers/JetDiagnosticsTestGenerated.java | 10 +++ idea/testData/checker/ExtensionFunctions.kt | 2 +- 11 files changed, 156 insertions(+), 42 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/extensions/kt3563.kt create mode 100644 compiler/testData/diagnostics/tests/extensions/throwOutCandidatesByReceiver.kt diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java index fba14d1131c..03955144b36 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java @@ -36,10 +36,7 @@ import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.resolve.scopes.FilteringScope; import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue; -import org.jetbrains.jet.lang.types.DescriptorSubstitutor; -import org.jetbrains.jet.lang.types.JetType; -import org.jetbrains.jet.lang.types.TypeUtils; -import org.jetbrains.jet.lang.types.Variance; +import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.checker.JetTypeChecker; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import org.jetbrains.jet.renderer.DescriptorRenderer; @@ -47,6 +44,7 @@ import org.jetbrains.jet.renderer.DescriptorRenderer; import java.util.*; import static org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor.NO_RECEIVER_PARAMETER; +import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.DONT_CARE; public class DescriptorUtils { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolverUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolverUtil.java index d1dd55523af..44bb0618819 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolverUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolverUtil.java @@ -20,10 +20,7 @@ import com.google.common.collect.Lists; import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.descriptors.CallableDescriptor; -import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; -import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; -import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; +import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.Call; import org.jetbrains.jet.lang.psi.CallKey; import org.jetbrains.jet.lang.psi.JetExpression; @@ -38,6 +35,7 @@ import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallWithTrace; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument; import org.jetbrains.jet.lang.resolve.calls.tasks.ResolutionCandidate; import org.jetbrains.jet.lang.types.*; +import org.jetbrains.jet.lang.types.checker.JetTypeChecker; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import java.util.Collections; @@ -153,4 +151,38 @@ public class CallResolverUtil { if (!(callElement instanceof JetExpression)) return null; return CallKey.create(context.call.getCallType(), (JetExpression) callElement); } + + public static boolean checkArgumentCannotBeReceiver( + @NotNull JetType receiverArgumentType, + @NotNull CallableDescriptor descriptor + ) { + JetType effectiveReceiverArgumentType = TypeUtils.makeNotNullable(receiverArgumentType); + + JetType erasedReceiverType = getErasedReceiverType(descriptor); + if (erasedReceiverType == null) return true; + + return !JetTypeChecker.INSTANCE.isSubtypeOf(effectiveReceiverArgumentType, erasedReceiverType); + } + + @Nullable + private static JetType getErasedReceiverType(@NotNull CallableDescriptor descriptor) { + ReceiverParameterDescriptor receiverDescriptor = descriptor.getReceiverParameter(); + ReceiverParameterDescriptor expectedThisObjectDescriptor = descriptor.getExpectedThisObject(); + JetType receiverType = receiverDescriptor != null ? receiverDescriptor.getType() : + expectedThisObjectDescriptor != null ? expectedThisObjectDescriptor.getType() : null; + if (receiverType == null) return null; + + for (TypeParameterDescriptor typeParameter : descriptor.getTypeParameters()) { + if (typeParameter.getTypeConstructor().equals(receiverType.getConstructor())) { + return typeParameter.getUpperBoundsAsType(); + } + } + List fakeTypeArguments = Lists.newArrayList(); + for (TypeProjection typeProjection : receiverType.getArguments()) { + fakeTypeArguments.add(new TypeProjection(typeProjection.getProjectionKind(), DONT_CARE)); + } + return new JetTypeImpl( + receiverType.getAnnotations(), receiverType.getConstructor(), receiverType.isNullable(), + fakeTypeArguments, receiverType.getMemberScope()); + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java index 8d15321b81d..9cb99b27291 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java @@ -41,6 +41,7 @@ import org.jetbrains.jet.lang.resolve.calls.results.ResolutionDebugInfo; import org.jetbrains.jet.lang.resolve.calls.results.ResolutionStatus; import org.jetbrains.jet.lang.resolve.calls.tasks.ResolutionTask; import org.jetbrains.jet.lang.resolve.calls.tasks.TaskPrioritizer; +import org.jetbrains.jet.lang.resolve.calls.util.ExpressionAsFunctionDescriptor; import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue; import org.jetbrains.jet.lang.types.*; @@ -660,39 +661,43 @@ public class CandidateResolver { } private ResolutionStatus checkReceiver( - CallCandidateResolutionContext context, ResolvedCall candidateCall, BindingTrace trace, - ReceiverParameterDescriptor receiverParameter, ReceiverValue receiverArgument, - boolean isExplicitReceiver, boolean implicitInvokeCheck) { + @NotNull CallCandidateResolutionContext context, + @NotNull ResolvedCall candidateCall, + @NotNull BindingTrace trace, + @Nullable ReceiverParameterDescriptor receiverParameter, + @NotNull ReceiverValue receiverArgument, + boolean isExplicitReceiver, + boolean implicitInvokeCheck + ) { + if (receiverParameter == null || !receiverArgument.exists()) return SUCCESS; - BindingContext bindingContext = trace.getBindingContext(); + JetType receiverArgumentType = receiverArgument.getType(); + JetType effectiveReceiverArgumentType = TypeUtils.makeNotNullable(receiverArgumentType); + D candidateDescriptor = candidateCall.getCandidateDescriptor(); + if (!argumentTypeResolver.isSubtypeOfForArgumentType(effectiveReceiverArgumentType, receiverParameter.getType())) { - ResolutionStatus result = SUCCESS; - if (receiverParameter != null && receiverArgument.exists()) { - boolean safeAccess = isExplicitReceiver && !implicitInvokeCheck && candidateCall.isSafeCall(); - JetType receiverArgumentType = receiverArgument.getType(); - AutoCastServiceImpl autoCastService = new AutoCastServiceImpl(context.dataFlowInfo, bindingContext); - if (!safeAccess && !receiverParameter.getType().isNullable() && !autoCastService.isNotNull(receiverArgument)) { - - context.tracing.unsafeCall(trace, receiverArgumentType, implicitInvokeCheck); - result = UNSAFE_CALL_ERROR; + if (CallResolverUtil.checkArgumentCannotBeReceiver(effectiveReceiverArgumentType, candidateDescriptor) + && !(candidateDescriptor instanceof ExpressionAsFunctionDescriptor)) { + return STRONG_ERROR; } - else { - JetType effectiveReceiverArgumentType = safeAccess - ? TypeUtils.makeNotNullable(receiverArgumentType) - : receiverArgumentType; - if (!TypeUtils.dependsOnTypeParameters(receiverParameter.getType(), - candidateCall.getCandidateDescriptor().getTypeParameters()) && - !argumentTypeResolver.isSubtypeOfForArgumentType(effectiveReceiverArgumentType, receiverParameter.getType())) { - context.tracing.wrongReceiverType(trace, receiverParameter, receiverArgument); - result = OTHER_ERROR; - } - } - DataFlowValue receiverValue = DataFlowValueFactory.INSTANCE.createDataFlowValue(receiverArgument, bindingContext); - if (safeAccess && !context.dataFlowInfo.getNullability(receiverValue).canBeNull()) { - context.tracing.unnecessarySafeCall(trace, receiverArgumentType); + if (!TypeUtils.dependsOnTypeParameters(receiverParameter.getType(), candidateDescriptor.getTypeParameters())) { + context.tracing.wrongReceiverType(trace, receiverParameter, receiverArgument); + return OTHER_ERROR; } } - return result; + BindingContext bindingContext = trace.getBindingContext(); + boolean safeAccess = isExplicitReceiver && !implicitInvokeCheck && candidateCall.isSafeCall(); + AutoCastServiceImpl autoCastService = new AutoCastServiceImpl(context.dataFlowInfo, bindingContext); + if (!safeAccess && !receiverParameter.getType().isNullable() && !autoCastService.isNotNull(receiverArgument)) { + + context.tracing.unsafeCall(trace, receiverArgumentType, implicitInvokeCheck); + return UNSAFE_CALL_ERROR; + } + DataFlowValue receiverValue = DataFlowValueFactory.INSTANCE.createDataFlowValue(receiverArgument, bindingContext); + if (safeAccess && !context.dataFlowInfo.getNullability(receiverValue).canBeNull()) { + context.tracing.unnecessarySafeCall(trace, receiverArgumentType); + } + return SUCCESS; } private static class ValueArgumentsCheckingResult { diff --git a/compiler/testData/diagnostics/tests/extensions/ExtensionFunctions.kt b/compiler/testData/diagnostics/tests/extensions/ExtensionFunctions.kt index 9d11eb8bbc9..a2c5585ac31 100644 --- a/compiler/testData/diagnostics/tests/extensions/ExtensionFunctions.kt +++ b/compiler/testData/diagnostics/tests/extensions/ExtensionFunctions.kt @@ -19,7 +19,7 @@ class A fun A.plus(a : Any) { 1.foo() - true.foo() + true.foo() 1 } diff --git a/compiler/testData/diagnostics/tests/extensions/kt3563.kt b/compiler/testData/diagnostics/tests/extensions/kt3563.kt new file mode 100644 index 00000000000..e4401193846 --- /dev/null +++ b/compiler/testData/diagnostics/tests/extensions/kt3563.kt @@ -0,0 +1,17 @@ +// KT-3563 Compiler requiring java.io.File, and it's unclear why + +package bar + +import java.io.File + +class Customer(name: String) + +fun foo(f: File, c: Customer) { + f.name + + c.name // name should be unresolved here +} + +//from standard library +val File.name: String + get() = getName() diff --git a/compiler/testData/diagnostics/tests/extensions/throwOutCandidatesByReceiver.kt b/compiler/testData/diagnostics/tests/extensions/throwOutCandidatesByReceiver.kt new file mode 100644 index 00000000000..92a76c68f8b --- /dev/null +++ b/compiler/testData/diagnostics/tests/extensions/throwOutCandidatesByReceiver.kt @@ -0,0 +1,49 @@ +package bar + + +// should be thrown away + +fun List.a() {} + +fun test1(i: Int?) { + 1.a() + i.a() +} + +fun test2(c: Collection) { + c.a() +} + +fun Int.foo() {} + +fun test3(s: String?) { + "".foo() + s.foo() +} + +trait A +fun T.c() {} + +fun test4() { + 1.c() +} + + +// should be an error on receiver, shouldn't be thrown away + +fun test5() { + 1.{ String.(): String -> this}() +} + +fun R?.sure() : R = this!! + +fun test6(l: List?) { + l.sure() +} + + +fun List.b() {} + +fun test7(l: List) { + l.b() +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inference/regressions/kt742.kt b/compiler/testData/diagnostics/tests/inference/regressions/kt742.kt index d8f1846148c..59c9090b75f 100644 --- a/compiler/testData/diagnostics/tests/inference/regressions/kt742.kt +++ b/compiler/testData/diagnostics/tests/inference/regressions/kt742.kt @@ -7,4 +7,6 @@ class List(val head: T, val tail: List? = null) fun List.map1(f: (T)-> Q): List? = tail!!.map1(f) -fun List.map2(f: (T)-> Q): List? = tail.sure().map2(f) \ No newline at end of file +fun List.map2(f: (T)-> Q): List? = tail.sure().map2(f) + +fun List.map3(f: (T)-> Q): List? = tail.sure().map3(f) \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/regressions/kt557.kt b/compiler/testData/diagnostics/tests/regressions/kt557.kt index 993d2703426..bd964a524ff 100644 --- a/compiler/testData/diagnostics/tests/regressions/kt557.kt +++ b/compiler/testData/diagnostics/tests/regressions/kt557.kt @@ -7,5 +7,5 @@ fun Array.length() : Int { } fun test(array : Array?) { - array?.sure>().length() + array?.sure>().length() } diff --git a/compiler/testData/resolve/ExtensionFunctions.resolve b/compiler/testData/resolve/ExtensionFunctions.resolve index 19f490db5c6..28de6f75ddc 100644 --- a/compiler/testData/resolve/ExtensionFunctions.resolve +++ b/compiler/testData/resolve/ExtensionFunctions.resolve @@ -1,4 +1,4 @@ -fun <~T~T, ~E~E> `T`T.foo(x : `E`E, y : `A`A) : `T`T { +~T.foo~fun <~T~T, ~E~E> `T`T.foo(x : `E`E, y : `A`A) : `T`T { y.`+`plus(1) y `+`plus 1 y `+1`+ 1.0 @@ -13,7 +13,8 @@ fun <~T~T, ~E~E> `T`T.foo(x : `E`E, y : `A`A) : `T`T { ~+1~fun `A`A.plus(a : Any) { 1.`foo`foo() - true.`!null`foo() + true.`T.foo`foo() + 3.`!null`foo(4) 1 } diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index 6da64048a60..247de11cbc4 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -2282,11 +2282,21 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage doTest("compiler/testData/diagnostics/tests/extensions/kt2317.kt"); } + @TestMetadata("kt3563.kt") + public void testKt3563() throws Exception { + doTest("compiler/testData/diagnostics/tests/extensions/kt3563.kt"); + } + @TestMetadata("kt819ExtensionProperties.kt") public void testKt819ExtensionProperties() throws Exception { doTest("compiler/testData/diagnostics/tests/extensions/kt819ExtensionProperties.kt"); } + @TestMetadata("throwOutCandidatesByReceiver.kt") + public void testThrowOutCandidatesByReceiver() throws Exception { + doTest("compiler/testData/diagnostics/tests/extensions/throwOutCandidatesByReceiver.kt"); + } + } @TestMetadata("compiler/testData/diagnostics/tests/functionLiterals") diff --git a/idea/testData/checker/ExtensionFunctions.kt b/idea/testData/checker/ExtensionFunctions.kt index d52c79e886e..55c078ae6d3 100644 --- a/idea/testData/checker/ExtensionFunctions.kt +++ b/idea/testData/checker/ExtensionFunctions.kt @@ -16,7 +16,7 @@ class A fun A.plus(a : Any) { 1.foo() - true.foo() + true.foo() 1 }