KT-3563 Compiler requiring java.io.File, and it's unclear why
#KT-3563 fixed
This commit is contained in:
@@ -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")
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user