KT-3563 Compiler requiring java.io.File, and it's unclear why

#KT-3563 fixed
This commit is contained in:
Svetlana Isakova
2013-06-13 20:27:31 +04:00
parent 3cf133bff7
commit 342e9ebe7a
11 changed files with 156 additions and 42 deletions
@@ -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 {
@@ -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<TypeProjection> 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());
}
}
@@ -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 <D extends CallableDescriptor> ResolutionStatus checkReceiver(
CallCandidateResolutionContext<D> context, ResolvedCall<D> candidateCall, BindingTrace trace,
ReceiverParameterDescriptor receiverParameter, ReceiverValue receiverArgument,
boolean isExplicitReceiver, boolean implicitInvokeCheck) {
@NotNull CallCandidateResolutionContext<D> context,
@NotNull ResolvedCall<D> 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 {
@@ -19,7 +19,7 @@ class A
fun A.plus(<!UNUSED_PARAMETER!>a<!> : Any) {
1.foo()
true.<!NONE_APPLICABLE!>foo<!>()
true.<!TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>foo<!>(<!NO_VALUE_FOR_PARAMETER, NO_VALUE_FOR_PARAMETER!>)<!>
<!UNUSED_EXPRESSION!>1<!>
}
@@ -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.<!UNRESOLVED_REFERENCE!>name<!> // name should be unresolved here
}
//from standard library
val File.name: String
get() = getName()
@@ -0,0 +1,49 @@
package bar
// should be thrown away
fun <R> List<R>.a() {}
fun test1(i: Int?) {
1.<!UNRESOLVED_REFERENCE!>a<!>()
i.<!UNRESOLVED_REFERENCE!>a<!>()
}
fun <R> test2(c: Collection<R>) {
c.<!UNRESOLVED_REFERENCE!>a<!>()
}
fun Int.foo() {}
fun test3(s: String?) {
"".<!UNRESOLVED_REFERENCE!>foo<!>()
s.<!UNRESOLVED_REFERENCE!>foo<!>()
}
trait A
fun <T: A> T.c() {}
fun test4() {
1.<!UNRESOLVED_REFERENCE!>c<!>()
}
// should be an error on receiver, shouldn't be thrown away
fun test5() {
<!TYPE_MISMATCH!>1<!>.{ String.(): String -> this}()
}
fun <R: Any> R?.sure() : R = this!!
fun <T> test6(l: List<T>?) {
<!TYPE_MISMATCH!>l<!>.sure<T>()
}
fun List<String>.b() {}
fun test7(l: List<String?>) {
<!TYPE_MISMATCH!>l<!>.b()
}
@@ -7,4 +7,6 @@ class List<T>(val head: T, val tail: List<T>? = null)
fun <T, Q> List<T>.map1(f: (T)-> Q): List<T>? = tail!!.map1(f)
fun <T, Q> List<T>.map2(f: (T)-> Q): List<T>? = <!TYPE_MISMATCH!>tail<!>.sure<T>().<!TYPE_INFERENCE_TYPE_CONSTRUCTOR_MISMATCH!>map2<!>(f)
fun <T, Q> List<T>.map2(f: (T)-> Q): List<T>? = tail.sure().map2(f)
fun <T, Q> List<T>.map3(f: (T)-> Q): List<T>? = <!TYPE_MISMATCH!>tail<!>.sure<T>().<!UNRESOLVED_REFERENCE!>map3<!>(f)
@@ -7,5 +7,5 @@ fun Array<String>.length() : Int {
}
fun test(array : Array<String?>?) {
array?.sure<Array<String?>>()<!UNSAFE_CALL!>.<!>length()
<!TYPE_MISMATCH!>array?.sure<Array<String?>>()<!>.length()
}
@@ -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
}
@@ -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")
+1 -1
View File
@@ -16,7 +16,7 @@ class A
fun A.plus(<warning>a</warning> : Any) {
1.foo()
true.<error>foo</error>()
true.<error>foo</error>(<error><error>)</error></error>
<warning>1</warning>
}