Humanize type mismatch diagnostic caused by type projections

#KT-10581 Fixed
This commit is contained in:
Denis Zharkov
2016-01-15 12:22:44 +03:00
parent 0c52960d7a
commit e9693e987f
60 changed files with 796 additions and 111 deletions
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.InferenceErrorData;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.varianceChecker.VarianceChecker.VarianceConflictDiagnosticData; import org.jetbrains.kotlin.resolve.varianceChecker.VarianceChecker.VarianceConflictDiagnosticData;
import org.jetbrains.kotlin.types.KotlinType; import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.types.TypeProjection;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
@@ -714,6 +715,8 @@ public interface Errors {
// Type mismatch // Type mismatch
DiagnosticFactory2<KtExpression, KotlinType, KotlinType> TYPE_MISMATCH = DiagnosticFactory2.create(ERROR); DiagnosticFactory2<KtExpression, KotlinType, KotlinType> TYPE_MISMATCH = DiagnosticFactory2.create(ERROR);
DiagnosticFactory1<KtElement, TypeMismatchDueToTypeProjectionsData> TYPE_MISMATCH_DUE_TO_TYPE_PROJECTIONS = DiagnosticFactory1.create(ERROR);
DiagnosticFactory2<KtElement, CallableDescriptor, KotlinType> MEMBER_PROJECTED_OUT = DiagnosticFactory2.create(ERROR);
DiagnosticFactory1<KtExpression, KotlinType> RETURN_TYPE_MISMATCH = DiagnosticFactory1.create(ERROR); DiagnosticFactory1<KtExpression, KotlinType> RETURN_TYPE_MISMATCH = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<KtExpression, KotlinType> EXPECTED_TYPE_MISMATCH = DiagnosticFactory1.create(ERROR); DiagnosticFactory1<KtExpression, KotlinType> EXPECTED_TYPE_MISMATCH = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<KtBinaryExpression, KotlinType> ASSIGNMENT_TYPE_MISMATCH = DiagnosticFactory1.create(ERROR); DiagnosticFactory1<KtBinaryExpression, KotlinType> ASSIGNMENT_TYPE_MISMATCH = DiagnosticFactory1.create(ERROR);
@@ -785,6 +788,9 @@ public interface Errors {
ImmutableSet<? extends DiagnosticFactory<?>> MUST_BE_INITIALIZED_DIAGNOSTICS = ImmutableSet.of( ImmutableSet<? extends DiagnosticFactory<?>> MUST_BE_INITIALIZED_DIAGNOSTICS = ImmutableSet.of(
MUST_BE_INITIALIZED, MUST_BE_INITIALIZED_OR_BE_ABSTRACT MUST_BE_INITIALIZED, MUST_BE_INITIALIZED_OR_BE_ABSTRACT
); );
ImmutableSet<? extends DiagnosticFactory<?>> TYPE_MISMATCH_ERRORS = ImmutableSet.of(
TYPE_MISMATCH, CONSTANT_EXPECTED_TYPE_MISMATCH, NULL_FOR_NONNULL_TYPE, TYPE_MISMATCH_DUE_TO_TYPE_PROJECTIONS,
MEMBER_PROJECTED_OUT);
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -0,0 +1,115 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.diagnostics
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.getEffectiveExpectedType
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.context.CallPosition
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
import org.jetbrains.kotlin.resolve.calls.inference.isCaptured
import org.jetbrains.kotlin.resolve.calls.inference.wrapWithCapturingSubstitution
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeConstructorSubstitution
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.typeUtil.isAnyOrNullableAny
import org.jetbrains.kotlin.types.typeUtil.isNothing
import org.jetbrains.kotlin.types.typeUtil.isNullableNothing
fun ResolutionContext<*>.reportTypeMismatchDueToTypeProjection(
expression: KtElement,
expectedType: KotlinType,
expressionType: KotlinType?
): Boolean {
if (!TypeUtils.containsSpecialType(expectedType) { it.isAnyOrNullableAny() || it.isNothing() || it.isNullableNothing() }) return false
val callPosition = this.callPosition
val (resolvedCall, correspondingNotApproximatedTypeByDescriptor: (CallableDescriptor) -> KotlinType?) = when (callPosition) {
is CallPosition.ValueArgumentPosition -> Pair(
callPosition.resolvedCall, {
f: CallableDescriptor ->
getEffectiveExpectedType(f.valueParameters[callPosition.valueParameter.index], callPosition.valueArgument)
})
is CallPosition.ExtensionReceiverPosition -> Pair(
callPosition.resolvedCall, {
f: CallableDescriptor ->
f.extensionReceiverParameter?.type
})
is CallPosition.PropertyAssignment -> Pair(
callPosition.leftPart.getResolvedCall(trace.bindingContext) ?: return false, {
f: CallableDescriptor ->
(f as? PropertyDescriptor)?.setter?.valueParameters?.get(0)?.type
})
is CallPosition.Unknown -> return false
}
val receiverType = resolvedCall.dispatchReceiver?.type ?: return false
val callableDescriptor = resolvedCall.resultingDescriptor.original
val substitutedDescriptor =
TypeConstructorSubstitution
.create(receiverType)
.wrapWithCapturingSubstitution(needApproximation = false)
.buildSubstitutor().let { callableDescriptor.substitute(it) } ?: return false
val nonApproximatedExpectedType = correspondingNotApproximatedTypeByDescriptor(substitutedDescriptor) ?: return false
if (!TypeUtils.containsSpecialType(nonApproximatedExpectedType) { it.isCaptured() }) return false
if (expectedType.isNothing()) {
if (callPosition is CallPosition.PropertyAssignment) {
trace.report(Errors.SETTER_PROJECTED_OUT.on(callPosition.leftPart ?: return false, resolvedCall.resultingDescriptor))
}
else {
val call = resolvedCall.call
val reportOn =
if (resolvedCall is VariableAsFunctionResolvedCall)
resolvedCall.variableCall.call.calleeExpression
else
call.calleeExpression
trace.reportDiagnosticOnce(Errors.MEMBER_PROJECTED_OUT.on(reportOn ?: call.callElement, callableDescriptor, receiverType))
}
}
else {
// expressionType can be null when reporting CONSTANT_EXPECTED_TYPE_MISMATCH (see addAll.kt test)
expressionType ?: return false
trace.report(
Errors.TYPE_MISMATCH_DUE_TO_TYPE_PROJECTIONS.on(
expression, TypeMismatchDueToTypeProjectionsData(
expectedType, expressionType, receiverType, callableDescriptor)))
}
return true
}
private fun BindingTrace.reportDiagnosticOnce(diagnostic: Diagnostic) {
if (bindingContext.diagnostics.forElement(diagnostic.psiElement).any { it.factory == diagnostic.factory }) return
report(diagnostic)
}
class TypeMismatchDueToTypeProjectionsData(
val expectedType: KotlinType,
val expressionType: KotlinType,
val receiverType: KotlinType,
val callableDescriptor: CallableDescriptor
)
@@ -25,6 +25,7 @@ import org.jetbrains.annotations.TestOnly;
import org.jetbrains.kotlin.diagnostics.Diagnostic; import org.jetbrains.kotlin.diagnostics.Diagnostic;
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory; import org.jetbrains.kotlin.diagnostics.DiagnosticFactory;
import org.jetbrains.kotlin.diagnostics.Errors; import org.jetbrains.kotlin.diagnostics.Errors;
import org.jetbrains.kotlin.diagnostics.TypeMismatchDueToTypeProjectionsData;
import org.jetbrains.kotlin.psi.KtExpression; import org.jetbrains.kotlin.psi.KtExpression;
import org.jetbrains.kotlin.psi.KtSimpleNameExpression; import org.jetbrains.kotlin.psi.KtSimpleNameExpression;
import org.jetbrains.kotlin.psi.KtTypeConstraint; import org.jetbrains.kotlin.psi.KtTypeConstraint;
@@ -126,6 +127,22 @@ public class DefaultErrorMessages {
MAP.put(ACCESSOR_PARAMETER_NAME_SHADOWING, "Accessor parameter name 'field' is shadowed by backing field variable"); MAP.put(ACCESSOR_PARAMETER_NAME_SHADOWING, "Accessor parameter name 'field' is shadowed by backing field variable");
MAP.put(TYPE_MISMATCH, "Type mismatch: inferred type is {1} but {0} was expected", RENDER_TYPE, RENDER_TYPE); MAP.put(TYPE_MISMATCH, "Type mismatch: inferred type is {1} but {0} was expected", RENDER_TYPE, RENDER_TYPE);
MAP.put(TYPE_MISMATCH_DUE_TO_TYPE_PROJECTIONS,
"Type mismatch: inferred type is {1} but {0} was expected. Projected type {2} restricts use of {3}",
new MultiRenderer<TypeMismatchDueToTypeProjectionsData>() {
@NotNull
@Override
public String[] render(@NotNull TypeMismatchDueToTypeProjectionsData object) {
return new String[] {
RENDER_TYPE.render(object.getExpectedType()),
RENDER_TYPE.render(object.getExpressionType()),
RENDER_TYPE.render(object.getReceiverType()),
DescriptorRenderer.FQ_NAMES_IN_TYPES.render(object.getCallableDescriptor())
};
}
});
MAP.put(MEMBER_PROJECTED_OUT, "Out-projected type ''{1}'' prohibits the use of ''{0}''", DescriptorRenderer.FQ_NAMES_IN_TYPES, RENDER_TYPE);
MAP.put(INCOMPATIBLE_MODIFIERS, "Modifier ''{0}'' is incompatible with ''{1}''", TO_STRING, TO_STRING); MAP.put(INCOMPATIBLE_MODIFIERS, "Modifier ''{0}'' is incompatible with ''{1}''", TO_STRING, TO_STRING);
MAP.put(DEPRECATED_MODIFIER_PAIR, "Modifier ''{0}'' is deprecated in presence of ''{1}''", TO_STRING, TO_STRING); MAP.put(DEPRECATED_MODIFIER_PAIR, "Modifier ''{0}'' is deprecated in presence of ''{1}''", TO_STRING, TO_STRING);
MAP.put(REPEATED_MODIFIER, "Repeated ''{0}''", TO_STRING); MAP.put(REPEATED_MODIFIER, "Repeated ''{0}''", TO_STRING);
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isInvokeCallOnVariabl
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
import org.jetbrains.kotlin.resolve.calls.context.CallCandidateResolutionContext import org.jetbrains.kotlin.resolve.calls.context.CallCandidateResolutionContext
import org.jetbrains.kotlin.resolve.calls.context.CallPosition
import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem
import org.jetbrains.kotlin.resolve.calls.inference.InferenceErrorData import org.jetbrains.kotlin.resolve.calls.inference.InferenceErrorData
@@ -68,7 +69,6 @@ class CallCompleter(
// for the case 'foo(a)' where 'foo' is a variable, the call 'foo.invoke(a)' shouldn't be completed separately, // for the case 'foo(a)' where 'foo' is a variable, the call 'foo.invoke(a)' shouldn't be completed separately,
// it's completed when the outer (variable as function call) is completed // it's completed when the outer (variable as function call) is completed
if (!isInvokeCallOnVariable(context.call)) { if (!isInvokeCallOnVariable(context.call)) {
val temporaryTrace = TemporaryBindingTrace.create(context.trace, "Trace to complete a resulting call") val temporaryTrace = TemporaryBindingTrace.create(context.trace, "Trace to complete a resulting call")
completeResolvedCallAndArguments(resolvedCall, results, context.replaceBindingTrace(temporaryTrace), tracing) completeResolvedCallAndArguments(resolvedCall, results, context.replaceBindingTrace(temporaryTrace), tracing)
@@ -222,7 +222,7 @@ class CallCompleter(
candidateDescriptor, constraintSystem!!, valueArgumentsCheckingResult.argumentTypes, candidateDescriptor, constraintSystem!!, valueArgumentsCheckingResult.argumentTypes,
receiverType, context.expectedType, context.call receiverType, context.expectedType, context.call
) )
tracing.typeInferenceFailed(context.trace, errorData) tracing.typeInferenceFailed(context, errorData)
addStatus(ResolutionStatus.OTHER_ERROR) addStatus(ResolutionStatus.OTHER_ERROR)
} }
@@ -247,11 +247,16 @@ class CallCompleter(
for (valueArgument in context.call.valueArguments) { for (valueArgument in context.call.valueArguments) {
val argumentMapping = getArgumentMapping(valueArgument!!) val argumentMapping = getArgumentMapping(valueArgument!!)
val expectedType = when (argumentMapping) { val (expectedType, callPosition) = when (argumentMapping) {
is ArgumentMatch -> getEffectiveExpectedType(argumentMapping.valueParameter, valueArgument) is ArgumentMatch -> Pair(
else -> TypeUtils.NO_EXPECTED_TYPE getEffectiveExpectedType(argumentMapping.valueParameter, valueArgument),
CallPosition.ValueArgumentPosition(results.resultingCall, argumentMapping.valueParameter, valueArgument))
else -> Pair(TypeUtils.NO_EXPECTED_TYPE, CallPosition.Unknown)
} }
val newContext = context.replaceDataFlowInfo(getDataFlowInfoForArgument(valueArgument)).replaceExpectedType(expectedType) val newContext =
context.replaceDataFlowInfo(getDataFlowInfoForArgument(valueArgument))
.replaceExpectedType(expectedType)
.replaceCallPosition(callPosition)
completeOneArgument(valueArgument, newContext) completeOneArgument(valueArgument, newContext)
} }
} }
@@ -306,7 +311,7 @@ class CallCompleter(
val (cachedResolutionResults, cachedContext, tracing) = cachedData val (cachedResolutionResults, cachedContext, tracing) = cachedData
val contextForArgument = cachedContext.replaceBindingTrace(context.trace) val contextForArgument = cachedContext.replaceBindingTrace(context.trace)
.replaceExpectedType(context.expectedType).replaceCollectAllCandidates(false) .replaceExpectedType(context.expectedType).replaceCollectAllCandidates(false).replaceCallPosition(context.callPosition)
return completeCall(contextForArgument, cachedResolutionResults, tracing) return completeCall(contextForArgument, cachedResolutionResults, tracing)
} }
@@ -449,7 +449,9 @@ class CandidateResolver(
receiverArgument, receiverParameter.type, this) receiverArgument, receiverParameter.type, this)
if (!isSubtypeBySmartCastIgnoringNullability) { if (!isSubtypeBySmartCastIgnoringNullability) {
tracing.wrongReceiverType(trace, receiverParameter, receiverArgument) tracing.wrongReceiverType(
trace, receiverParameter, receiverArgument,
this.replaceCallPosition(CallPosition.ExtensionReceiverPosition(candidateCall)))
return OTHER_ERROR return OTHER_ERROR
} }
@@ -42,10 +42,11 @@ public class BasicCallResolutionContext extends CallResolutionContext<BasicCallR
@NotNull CallChecker callChecker, @NotNull CallChecker callChecker,
@NotNull StatementFilter statementFilter, @NotNull StatementFilter statementFilter,
boolean isAnnotationContext, boolean isAnnotationContext,
boolean collectAllCandidates boolean collectAllCandidates,
@NotNull CallPosition callPosition
) { ) {
super(trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments, resolutionResultsCache, super(trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments, resolutionResultsCache,
dataFlowInfoForArguments, callChecker, statementFilter, isAnnotationContext, collectAllCandidates); dataFlowInfoForArguments, callChecker, statementFilter, isAnnotationContext, collectAllCandidates, callPosition);
} }
@NotNull @NotNull
@@ -62,7 +63,8 @@ public class BasicCallResolutionContext extends CallResolutionContext<BasicCallR
) { ) {
return new BasicCallResolutionContext(trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments, return new BasicCallResolutionContext(trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments,
new ResolutionResultsCacheImpl(), null, new ResolutionResultsCacheImpl(), null,
callChecker, StatementFilter.NONE, isAnnotationContext, false); callChecker, StatementFilter.NONE, isAnnotationContext, false,
CallPosition.Unknown.INSTANCE);
} }
@NotNull @NotNull
@@ -74,7 +76,7 @@ public class BasicCallResolutionContext extends CallResolutionContext<BasicCallR
context.trace, context.scope, call, context.expectedType, context.dataFlowInfo, context.contextDependency, checkArguments, context.trace, context.scope, call, context.expectedType, context.dataFlowInfo, context.contextDependency, checkArguments,
context.resolutionResultsCache, dataFlowInfoForArguments, context.resolutionResultsCache, dataFlowInfoForArguments,
context.callChecker, context.callChecker,
context.statementFilter, context.isAnnotationContext, context.collectAllCandidates); context.statementFilter, context.isAnnotationContext, context.collectAllCandidates, context.callPosition);
} }
@NotNull @NotNull
@@ -93,18 +95,19 @@ public class BasicCallResolutionContext extends CallResolutionContext<BasicCallR
@NotNull ContextDependency contextDependency, @NotNull ContextDependency contextDependency,
@NotNull ResolutionResultsCache resolutionResultsCache, @NotNull ResolutionResultsCache resolutionResultsCache,
@NotNull StatementFilter statementFilter, @NotNull StatementFilter statementFilter,
boolean collectAllCandidates boolean collectAllCandidates,
@NotNull CallPosition callPosition
) { ) {
return new BasicCallResolutionContext( return new BasicCallResolutionContext(
trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments, resolutionResultsCache, trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments, resolutionResultsCache,
dataFlowInfoForArguments, callChecker, statementFilter, isAnnotationContext, collectAllCandidates); dataFlowInfoForArguments, callChecker, statementFilter, isAnnotationContext, collectAllCandidates, callPosition);
} }
@NotNull @NotNull
public BasicCallResolutionContext replaceCall(@NotNull Call newCall) { public BasicCallResolutionContext replaceCall(@NotNull Call newCall) {
return new BasicCallResolutionContext( return new BasicCallResolutionContext(
trace, scope, newCall, expectedType, dataFlowInfo, contextDependency, checkArguments, resolutionResultsCache, trace, scope, newCall, expectedType, dataFlowInfo, contextDependency, checkArguments, resolutionResultsCache,
dataFlowInfoForArguments, callChecker, statementFilter, isAnnotationContext, collectAllCandidates); dataFlowInfoForArguments, callChecker, statementFilter, isAnnotationContext, collectAllCandidates, callPosition);
} }
public void performContextDependentCallChecks(@NotNull ResolvedCall<?> resolvedCall) { public void performContextDependentCallChecks(@NotNull ResolvedCall<?> resolvedCall) {
@@ -58,11 +58,12 @@ public final class CallCandidateResolutionContext<D extends CallableDescriptor>
@Nullable Receiver explicitExtensionReceiverForInvoke, @Nullable Receiver explicitExtensionReceiverForInvoke,
@NotNull CandidateResolveMode candidateResolveMode, @NotNull CandidateResolveMode candidateResolveMode,
boolean isAnnotationContext, boolean isAnnotationContext,
boolean collectAllCandidates boolean collectAllCandidates,
@NotNull CallPosition callPosition
) { ) {
super(trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments, resolutionResultsCache, super(trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments, resolutionResultsCache,
dataFlowInfoForArguments, callChecker, statementFilter, isAnnotationContext, dataFlowInfoForArguments, callChecker, statementFilter, isAnnotationContext,
collectAllCandidates); collectAllCandidates, callPosition);
this.candidateCall = candidateCall; this.candidateCall = candidateCall;
this.tracing = tracing; this.tracing = tracing;
this.explicitExtensionReceiverForInvoke = explicitExtensionReceiverForInvoke; this.explicitExtensionReceiverForInvoke = explicitExtensionReceiverForInvoke;
@@ -79,7 +80,7 @@ public final class CallCandidateResolutionContext<D extends CallableDescriptor>
context.dataFlowInfo, context.contextDependency, context.checkArguments, context.dataFlowInfo, context.contextDependency, context.checkArguments,
context.resolutionResultsCache, context.dataFlowInfoForArguments, context.resolutionResultsCache, context.dataFlowInfoForArguments,
context.callChecker, context.statementFilter, explicitExtensionReceiverForInvoke, context.callChecker, context.statementFilter, explicitExtensionReceiverForInvoke,
candidateResolveMode, context.isAnnotationContext, context.collectAllCandidates); candidateResolveMode, context.isAnnotationContext, context.collectAllCandidates, context.callPosition);
} }
@NotNull @NotNull
@@ -90,7 +91,8 @@ public final class CallCandidateResolutionContext<D extends CallableDescriptor>
candidateCall, tracing, context.trace, context.scope, context.call, context.expectedType, candidateCall, tracing, context.trace, context.scope, context.call, context.expectedType,
context.dataFlowInfo, context.contextDependency, context.checkArguments, context.resolutionResultsCache, context.dataFlowInfo, context.contextDependency, context.checkArguments, context.resolutionResultsCache,
context.dataFlowInfoForArguments, context.callChecker, context.statementFilter, context.dataFlowInfoForArguments, context.callChecker, context.statementFilter,
null, CandidateResolveMode.FULLY, context.isAnnotationContext, context.collectAllCandidates); null, CandidateResolveMode.FULLY, context.isAnnotationContext, context.collectAllCandidates,
context.callPosition);
} }
@Override @Override
@@ -102,11 +104,12 @@ public final class CallCandidateResolutionContext<D extends CallableDescriptor>
@NotNull ContextDependency contextDependency, @NotNull ContextDependency contextDependency,
@NotNull ResolutionResultsCache resolutionResultsCache, @NotNull ResolutionResultsCache resolutionResultsCache,
@NotNull StatementFilter statementFilter, @NotNull StatementFilter statementFilter,
boolean collectAllCandidates boolean collectAllCandidates,
@NotNull CallPosition callPosition
) { ) {
return new CallCandidateResolutionContext<D>( return new CallCandidateResolutionContext<D>(
candidateCall, tracing, trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments, candidateCall, tracing, trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments,
resolutionResultsCache, dataFlowInfoForArguments, callChecker, statementFilter, resolutionResultsCache, dataFlowInfoForArguments, callChecker, statementFilter,
explicitExtensionReceiverForInvoke, candidateResolveMode, isAnnotationContext, collectAllCandidates); explicitExtensionReceiverForInvoke, candidateResolveMode, isAnnotationContext, collectAllCandidates, callPosition);
} }
} }
@@ -0,0 +1,37 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.resolve.calls.context
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.ValueArgument
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
sealed class CallPosition {
object Unknown : CallPosition()
class ExtensionReceiverPosition(val resolvedCall: ResolvedCall<*>) : CallPosition()
class ValueArgumentPosition(
val resolvedCall: ResolvedCall<*>,
val valueParameter: ValueParameterDescriptor,
val valueArgument: ValueArgument
) : CallPosition()
class PropertyAssignment(val leftPart: KtExpression?) : CallPosition()
}
@@ -50,10 +50,11 @@ public abstract class CallResolutionContext<Context extends CallResolutionContex
@NotNull CallChecker callChecker, @NotNull CallChecker callChecker,
@NotNull StatementFilter statementFilter, @NotNull StatementFilter statementFilter,
boolean isAnnotationContext, boolean isAnnotationContext,
boolean collectAllCandidates boolean collectAllCandidates,
@NotNull CallPosition callPosition
) { ) {
super(trace, scope, expectedType, dataFlowInfo, contextDependency, resolutionResultsCache, callChecker, super(trace, scope, expectedType, dataFlowInfo, contextDependency, resolutionResultsCache, callChecker,
statementFilter, isAnnotationContext, collectAllCandidates); statementFilter, isAnnotationContext, collectAllCandidates, callPosition);
this.call = call; this.call = call;
this.checkArguments = checkArguments; this.checkArguments = checkArguments;
if (dataFlowInfoForArguments != null) { if (dataFlowInfoForArguments != null) {
@@ -54,6 +54,9 @@ public abstract class ResolutionContext<Context extends ResolutionContext<Contex
public final boolean collectAllCandidates; public final boolean collectAllCandidates;
@NotNull
public final CallPosition callPosition;
protected ResolutionContext( protected ResolutionContext(
@NotNull BindingTrace trace, @NotNull BindingTrace trace,
@NotNull LexicalScope scope, @NotNull LexicalScope scope,
@@ -64,7 +67,8 @@ public abstract class ResolutionContext<Context extends ResolutionContext<Contex
@NotNull CallChecker callChecker, @NotNull CallChecker callChecker,
@NotNull StatementFilter statementFilter, @NotNull StatementFilter statementFilter,
boolean isAnnotationContext, boolean isAnnotationContext,
boolean collectAllCandidates boolean collectAllCandidates,
@NotNull CallPosition callPosition
) { ) {
this.trace = trace; this.trace = trace;
this.scope = scope; this.scope = scope;
@@ -76,6 +80,7 @@ public abstract class ResolutionContext<Context extends ResolutionContext<Contex
this.statementFilter = statementFilter; this.statementFilter = statementFilter;
this.isAnnotationContext = isAnnotationContext; this.isAnnotationContext = isAnnotationContext;
this.collectAllCandidates = collectAllCandidates; this.collectAllCandidates = collectAllCandidates;
this.callPosition = callPosition;
} }
protected abstract Context create( protected abstract Context create(
@@ -86,7 +91,8 @@ public abstract class ResolutionContext<Context extends ResolutionContext<Contex
@NotNull ContextDependency contextDependency, @NotNull ContextDependency contextDependency,
@NotNull ResolutionResultsCache resolutionResultsCache, @NotNull ResolutionResultsCache resolutionResultsCache,
@NotNull StatementFilter statementFilter, @NotNull StatementFilter statementFilter,
boolean collectAllCandidates boolean collectAllCandidates,
@NotNull CallPosition callPosition
); );
@NotNull @NotNull
@@ -99,14 +105,14 @@ public abstract class ResolutionContext<Context extends ResolutionContext<Contex
public Context replaceBindingTrace(@NotNull BindingTrace trace) { public Context replaceBindingTrace(@NotNull BindingTrace trace) {
if (this.trace == trace) return self(); if (this.trace == trace) return self();
return create(trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter, return create(trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter,
collectAllCandidates); collectAllCandidates, callPosition);
} }
@NotNull @NotNull
public Context replaceDataFlowInfo(@NotNull DataFlowInfo newDataFlowInfo) { public Context replaceDataFlowInfo(@NotNull DataFlowInfo newDataFlowInfo) {
if (newDataFlowInfo == dataFlowInfo) return self(); if (newDataFlowInfo == dataFlowInfo) return self();
return create(trace, scope, newDataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter, return create(trace, scope, newDataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter,
collectAllCandidates); collectAllCandidates, callPosition);
} }
@NotNull @NotNull
@@ -114,28 +120,28 @@ public abstract class ResolutionContext<Context extends ResolutionContext<Contex
if (newExpectedType == null) return replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE); if (newExpectedType == null) return replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE);
if (expectedType == newExpectedType) return self(); if (expectedType == newExpectedType) return self();
return create(trace, scope, dataFlowInfo, newExpectedType, contextDependency, resolutionResultsCache, statementFilter, return create(trace, scope, dataFlowInfo, newExpectedType, contextDependency, resolutionResultsCache, statementFilter,
collectAllCandidates); collectAllCandidates, callPosition);
} }
@NotNull @NotNull
public Context replaceScope(@NotNull LexicalScope newScope) { public Context replaceScope(@NotNull LexicalScope newScope) {
if (newScope == scope) return self(); if (newScope == scope) return self();
return create(trace, newScope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter, return create(trace, newScope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter,
collectAllCandidates); collectAllCandidates, callPosition);
} }
@NotNull @NotNull
public Context replaceContextDependency(@NotNull ContextDependency newContextDependency) { public Context replaceContextDependency(@NotNull ContextDependency newContextDependency) {
if (newContextDependency == contextDependency) return self(); if (newContextDependency == contextDependency) return self();
return create(trace, scope, dataFlowInfo, expectedType, newContextDependency, resolutionResultsCache, statementFilter, return create(trace, scope, dataFlowInfo, expectedType, newContextDependency, resolutionResultsCache, statementFilter,
collectAllCandidates); collectAllCandidates, callPosition);
} }
@NotNull @NotNull
public Context replaceResolutionResultsCache(@NotNull ResolutionResultsCache newResolutionResultsCache) { public Context replaceResolutionResultsCache(@NotNull ResolutionResultsCache newResolutionResultsCache) {
if (newResolutionResultsCache == resolutionResultsCache) return self(); if (newResolutionResultsCache == resolutionResultsCache) return self();
return create(trace, scope, dataFlowInfo, expectedType, contextDependency, newResolutionResultsCache, statementFilter, return create(trace, scope, dataFlowInfo, expectedType, contextDependency, newResolutionResultsCache, statementFilter,
collectAllCandidates); collectAllCandidates, callPosition);
} }
@NotNull @NotNull
@@ -146,12 +152,18 @@ public abstract class ResolutionContext<Context extends ResolutionContext<Contex
@NotNull @NotNull
public Context replaceCollectAllCandidates(boolean newCollectAllCandidates) { public Context replaceCollectAllCandidates(boolean newCollectAllCandidates) {
return create(trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter, return create(trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter,
newCollectAllCandidates); newCollectAllCandidates, callPosition);
} }
@NotNull @NotNull
public Context replaceStatementFilter(@NotNull StatementFilter statementFilter) { public Context replaceStatementFilter(@NotNull StatementFilter statementFilter) {
return create(trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter, return create(trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter,
collectAllCandidates); collectAllCandidates, callPosition);
}
@NotNull
public Context replaceCallPosition(@NotNull CallPosition callPosition) {
return create(trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter,
collectAllCandidates, callPosition);
} }
} }
@@ -21,6 +21,7 @@ import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.diagnostics.DiagnosticUtilsKt;
import org.jetbrains.kotlin.lexer.KtToken; import org.jetbrains.kotlin.lexer.KtToken;
import org.jetbrains.kotlin.lexer.KtTokens; import org.jetbrains.kotlin.lexer.KtTokens;
import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.name.FqName;
@@ -29,13 +30,13 @@ import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.BindingTrace; import org.jetbrains.kotlin.resolve.BindingTrace;
import org.jetbrains.kotlin.resolve.DescriptorUtils; import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt; import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext;
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem; import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem;
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemStatus; import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemStatus;
import org.jetbrains.kotlin.resolve.calls.inference.InferenceErrorData; import org.jetbrains.kotlin.resolve.calls.inference.InferenceErrorData;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt; import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver; import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
import org.jetbrains.kotlin.resolve.scopes.receivers.Receiver;
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue; import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
import org.jetbrains.kotlin.types.KotlinType; import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.types.Variance; import org.jetbrains.kotlin.types.Variance;
@@ -80,13 +81,19 @@ public abstract class AbstractTracingStrategy implements TracingStrategy {
} }
@Override @Override
public void wrongReceiverType(@NotNull BindingTrace trace, @NotNull ReceiverParameterDescriptor receiverParameter, @NotNull ReceiverValue receiverArgument) { public void wrongReceiverType(
if (receiverArgument instanceof ExpressionReceiver) { @NotNull BindingTrace trace,
ExpressionReceiver expressionReceiver = (ExpressionReceiver)receiverArgument; @NotNull ReceiverParameterDescriptor receiverParameter,
trace.report(TYPE_MISMATCH.on(expressionReceiver.getExpression(), receiverParameter.getType(), receiverArgument.getType())); @NotNull ReceiverValue receiverArgument,
} @NotNull ResolutionContext<?> c
else { ) {
trace.report(TYPE_MISMATCH.on(reference, receiverParameter.getType(), receiverArgument.getType())); KtExpression reportOn = receiverArgument instanceof ExpressionReceiver
? ((ExpressionReceiver) receiverArgument).getExpression()
: reference;
if (!DiagnosticUtilsKt.reportTypeMismatchDueToTypeProjection(
c, reportOn, receiverParameter.getType(), receiverArgument.getType())) {
trace.report(TYPE_MISMATCH.on(reportOn, receiverParameter.getType(), receiverArgument.getType()));
} }
} }
@@ -195,7 +202,7 @@ public abstract class AbstractTracingStrategy implements TracingStrategy {
} }
@Override @Override
public void typeInferenceFailed(@NotNull BindingTrace trace, @NotNull InferenceErrorData data) { public void typeInferenceFailed(@NotNull ResolutionContext<?> context, @NotNull InferenceErrorData data) {
ConstraintSystem constraintSystem = data.constraintSystem; ConstraintSystem constraintSystem = data.constraintSystem;
ConstraintSystemStatus status = constraintSystem.getStatus(); ConstraintSystemStatus status = constraintSystem.getStatus();
assert !status.isSuccessful() : "Report error only for not successful constraint system"; assert !status.isSuccessful() : "Report error only for not successful constraint system";
@@ -205,6 +212,7 @@ public abstract class AbstractTracingStrategy implements TracingStrategy {
// (it's useful, when the arguments, e.g. lambdas or calls are incomplete) // (it's useful, when the arguments, e.g. lambdas or calls are incomplete)
return; return;
} }
BindingTrace trace = context.trace;
if (status.hasOnlyErrorsDerivedFrom(EXPECTED_TYPE_POSITION)) { if (status.hasOnlyErrorsDerivedFrom(EXPECTED_TYPE_POSITION)) {
KotlinType declaredReturnType = data.descriptor.getReturnType(); KotlinType declaredReturnType = data.descriptor.getReturnType();
if (declaredReturnType == null) return; if (declaredReturnType == null) return;
@@ -215,7 +223,10 @@ public abstract class AbstractTracingStrategy implements TracingStrategy {
assert substitutedReturnType != null; //todo assert substitutedReturnType != null; //todo
assert !noExpectedType(data.expectedType) : "Expected type doesn't exist, but there is an expected type mismatch error"; assert !noExpectedType(data.expectedType) : "Expected type doesn't exist, but there is an expected type mismatch error";
trace.report(TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH.on(call.getCallElement(), data.expectedType, substitutedReturnType)); if (!DiagnosticUtilsKt.reportTypeMismatchDueToTypeProjection(
context, call.getCallElement(), data.expectedType, substitutedReturnType)) {
trace.report(TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH.on(call.getCallElement(), data.expectedType, substitutedReturnType));
}
} }
else if (status.hasCannotCaptureTypesError()) { else if (status.hasCannotCaptureTypesError()) {
trace.report(TYPE_INFERENCE_CANNOT_CAPTURE_TYPES.on(reference, data)); trace.report(TYPE_INFERENCE_CANNOT_CAPTURE_TYPES.on(reference, data));
@@ -58,10 +58,11 @@ public class ResolutionTask<D extends CallableDescriptor, F extends D> extends C
@NotNull StatementFilter statementFilter, @NotNull StatementFilter statementFilter,
@NotNull Collection<MutableResolvedCall<F>> resolvedCalls, @NotNull Collection<MutableResolvedCall<F>> resolvedCalls,
boolean isAnnotationContext, boolean isAnnotationContext,
boolean collectAllCandidates boolean collectAllCandidates,
@NotNull CallPosition callPosition
) { ) {
super(trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments, resolutionResultsCache, super(trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments, resolutionResultsCache,
dataFlowInfoForArguments, callChecker, statementFilter, isAnnotationContext, collectAllCandidates); dataFlowInfoForArguments, callChecker, statementFilter, isAnnotationContext, collectAllCandidates, callPosition);
this.lazyCandidates = lazyCandidates; this.lazyCandidates = lazyCandidates;
this.resolvedCalls = resolvedCalls; this.resolvedCalls = resolvedCalls;
this.tracing = tracing; this.tracing = tracing;
@@ -78,7 +79,7 @@ public class ResolutionTask<D extends CallableDescriptor, F extends D> extends C
context.resolutionResultsCache, context.dataFlowInfoForArguments, context.resolutionResultsCache, context.dataFlowInfoForArguments,
context.callChecker, context.callChecker,
context.statementFilter, new SmartList<MutableResolvedCall<F>>(), context.statementFilter, new SmartList<MutableResolvedCall<F>>(),
context.isAnnotationContext, context.collectAllCandidates); context.isAnnotationContext, context.collectAllCandidates, context.callPosition);
} }
@NotNull @NotNull
@@ -104,14 +105,15 @@ public class ResolutionTask<D extends CallableDescriptor, F extends D> extends C
@NotNull ContextDependency contextDependency, @NotNull ContextDependency contextDependency,
@NotNull ResolutionResultsCache resolutionResultsCache, @NotNull ResolutionResultsCache resolutionResultsCache,
@NotNull StatementFilter statementFilter, @NotNull StatementFilter statementFilter,
boolean collectAllCandidates boolean collectAllCandidates,
@NotNull CallPosition callPosition
) { ) {
return new ResolutionTask<D, F>( return new ResolutionTask<D, F>(
lazyCandidates, tracing, trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments, lazyCandidates, tracing, trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments,
resolutionResultsCache, dataFlowInfoForArguments, resolutionResultsCache, dataFlowInfoForArguments,
callChecker, callChecker,
statementFilter, resolvedCalls, statementFilter, resolvedCalls,
isAnnotationContext, collectAllCandidates); isAnnotationContext, collectAllCandidates, callPosition);
} }
@Override @Override
@@ -20,6 +20,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.psi.Call; import org.jetbrains.kotlin.psi.Call;
import org.jetbrains.kotlin.resolve.BindingTrace; import org.jetbrains.kotlin.resolve.BindingTrace;
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext;
import org.jetbrains.kotlin.resolve.calls.inference.InferenceErrorData; import org.jetbrains.kotlin.resolve.calls.inference.InferenceErrorData;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue; import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
@@ -52,7 +53,12 @@ public interface TracingStrategy {
public void missingReceiver(@NotNull BindingTrace trace, @NotNull ReceiverParameterDescriptor expectedReceiver) {} public void missingReceiver(@NotNull BindingTrace trace, @NotNull ReceiverParameterDescriptor expectedReceiver) {}
@Override @Override
public void wrongReceiverType(@NotNull BindingTrace trace, @NotNull ReceiverParameterDescriptor receiverParameter, @NotNull ReceiverValue receiverArgument) {} public void wrongReceiverType(
@NotNull BindingTrace trace,
@NotNull ReceiverParameterDescriptor receiverParameter,
@NotNull ReceiverValue receiverArgument,
@NotNull ResolutionContext<?> c
) {}
@Override @Override
public void noReceiverAllowed(@NotNull BindingTrace trace) {} public void noReceiverAllowed(@NotNull BindingTrace trace) {}
@@ -95,7 +101,7 @@ public interface TracingStrategy {
public void invisibleMember(@NotNull BindingTrace trace, @NotNull DeclarationDescriptorWithVisibility descriptor) {} public void invisibleMember(@NotNull BindingTrace trace, @NotNull DeclarationDescriptorWithVisibility descriptor) {}
@Override @Override
public void typeInferenceFailed(@NotNull BindingTrace trace, @NotNull InferenceErrorData inferenceErrorData) {} public void typeInferenceFailed(@NotNull ResolutionContext<?> context, @NotNull InferenceErrorData inferenceErrorData) {}
@Override @Override
public void nonExtensionFunctionCalledAsExtension(@NotNull BindingTrace trace) { } public void nonExtensionFunctionCalledAsExtension(@NotNull BindingTrace trace) { }
@@ -115,7 +121,12 @@ public interface TracingStrategy {
void missingReceiver(@NotNull BindingTrace trace, @NotNull ReceiverParameterDescriptor expectedReceiver); void missingReceiver(@NotNull BindingTrace trace, @NotNull ReceiverParameterDescriptor expectedReceiver);
void wrongReceiverType(@NotNull BindingTrace trace, @NotNull ReceiverParameterDescriptor receiverParameter, @NotNull ReceiverValue receiverArgument); void wrongReceiverType(
@NotNull BindingTrace trace,
@NotNull ReceiverParameterDescriptor receiverParameter,
@NotNull ReceiverValue receiverArgument,
@NotNull ResolutionContext<?> c
);
void noReceiverAllowed(@NotNull BindingTrace trace); void noReceiverAllowed(@NotNull BindingTrace trace);
@@ -146,7 +157,7 @@ public interface TracingStrategy {
void invisibleMember(@NotNull BindingTrace trace, @NotNull DeclarationDescriptorWithVisibility descriptor); void invisibleMember(@NotNull BindingTrace trace, @NotNull DeclarationDescriptorWithVisibility descriptor);
void typeInferenceFailed(@NotNull BindingTrace trace, @NotNull InferenceErrorData inferenceErrorData); void typeInferenceFailed(@NotNull ResolutionContext<?> context, @NotNull InferenceErrorData inferenceErrorData);
void nonExtensionFunctionCalledAsExtension(@NotNull BindingTrace trace); void nonExtensionFunctionCalledAsExtension(@NotNull BindingTrace trace);
} }
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.resolve.BindingContext.CALL
import org.jetbrains.kotlin.resolve.BindingContext.REFERENCE_TARGET import org.jetbrains.kotlin.resolve.BindingContext.REFERENCE_TARGET
import org.jetbrains.kotlin.resolve.BindingContext.RESOLVED_CALL import org.jetbrains.kotlin.resolve.BindingContext.RESOLVED_CALL
import org.jetbrains.kotlin.resolve.BindingTrace import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
import org.jetbrains.kotlin.resolve.calls.inference.InferenceErrorData import org.jetbrains.kotlin.resolve.calls.inference.InferenceErrorData
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
@@ -117,7 +118,7 @@ class TracingStrategyForImplicitConstructorDelegationCall(
unexpectedError("missingReceiver") unexpectedError("missingReceiver")
} }
override fun wrongReceiverType(trace: BindingTrace, receiverParameter: ReceiverParameterDescriptor, receiverArgument: ReceiverValue) { override fun wrongReceiverType(trace: BindingTrace, receiverParameter: ReceiverParameterDescriptor, receiverArgument: ReceiverValue, c: ResolutionContext<*>) {
unexpectedError("wrongReceiverType") unexpectedError("wrongReceiverType")
} }
@@ -129,7 +130,7 @@ class TracingStrategyForImplicitConstructorDelegationCall(
unexpectedError("wrongNumberOfTypeArguments") unexpectedError("wrongNumberOfTypeArguments")
} }
override fun typeInferenceFailed(trace: BindingTrace, data: InferenceErrorData) { override fun typeInferenceFailed(context: ResolutionContext<*>, data: InferenceErrorData) {
unexpectedError("typeInferenceFailed") unexpectedError("typeInferenceFailed")
} }
@@ -24,12 +24,15 @@ import org.jetbrains.kotlin.KtNodeTypes;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.diagnostics.Diagnostic; import org.jetbrains.kotlin.diagnostics.Diagnostic;
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory; import org.jetbrains.kotlin.diagnostics.DiagnosticFactory;
import org.jetbrains.kotlin.diagnostics.DiagnosticUtilsKt;
import org.jetbrains.kotlin.psi.KtConstantExpression; import org.jetbrains.kotlin.psi.KtConstantExpression;
import org.jetbrains.kotlin.psi.KtElement; import org.jetbrains.kotlin.psi.KtElement;
import org.jetbrains.kotlin.resolve.BindingTrace; import org.jetbrains.kotlin.resolve.BindingTrace;
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext;
import org.jetbrains.kotlin.types.KotlinType; import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.types.TypeUtils; import org.jetbrains.kotlin.types.TypeUtils;
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker; import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext;
import java.util.Set; import java.util.Set;
@@ -42,15 +45,17 @@ public class CompileTimeConstantChecker {
private final KotlinBuiltIns builtIns; private final KotlinBuiltIns builtIns;
private final BindingTrace trace; private final BindingTrace trace;
private final boolean checkOnlyErrorsThatDependOnExpectedType; private final boolean checkOnlyErrorsThatDependOnExpectedType;
private final ResolutionContext<?> context;
public CompileTimeConstantChecker( public CompileTimeConstantChecker(
@NotNull BindingTrace trace, @NotNull ResolutionContext<?> context,
@NotNull KotlinBuiltIns builtIns, @NotNull KotlinBuiltIns builtIns,
boolean checkOnlyErrorsThatDependOnExpectedType boolean checkOnlyErrorsThatDependOnExpectedType
) { ) {
this.checkOnlyErrorsThatDependOnExpectedType = checkOnlyErrorsThatDependOnExpectedType; this.checkOnlyErrorsThatDependOnExpectedType = checkOnlyErrorsThatDependOnExpectedType;
this.builtIns = builtIns; this.builtIns = builtIns;
this.trace = trace; this.trace = context.trace;
this.context = context;
} }
// return true if there is an error // return true if there is an error
@@ -95,7 +100,7 @@ public class CompileTimeConstantChecker {
if (!noExpectedTypeOrError(expectedType)) { if (!noExpectedTypeOrError(expectedType)) {
KotlinType valueType = value.getType(); KotlinType valueType = value.getType();
if (!KotlinTypeChecker.DEFAULT.isSubtypeOf(valueType, expectedType)) { if (!KotlinTypeChecker.DEFAULT.isSubtypeOf(valueType, expectedType)) {
return reportError(CONSTANT_EXPECTED_TYPE_MISMATCH.on(expression, "integer", expectedType)); return reportConstantExpectedTypeMismatch(expression, "integer", expectedType, null);
} }
} }
return false; return false;
@@ -112,7 +117,7 @@ public class CompileTimeConstantChecker {
if (!noExpectedTypeOrError(expectedType)) { if (!noExpectedTypeOrError(expectedType)) {
KotlinType valueType = value.getType(); KotlinType valueType = value.getType();
if (!KotlinTypeChecker.DEFAULT.isSubtypeOf(valueType, expectedType)) { if (!KotlinTypeChecker.DEFAULT.isSubtypeOf(valueType, expectedType)) {
return reportError(CONSTANT_EXPECTED_TYPE_MISMATCH.on(expression, "floating-point", expectedType)); return reportConstantExpectedTypeMismatch(expression, "floating-point", expectedType, null);
} }
} }
return false; return false;
@@ -124,7 +129,7 @@ public class CompileTimeConstantChecker {
) { ) {
if (!noExpectedTypeOrError(expectedType) if (!noExpectedTypeOrError(expectedType)
&& !KotlinTypeChecker.DEFAULT.isSubtypeOf(builtIns.getBooleanType(), expectedType)) { && !KotlinTypeChecker.DEFAULT.isSubtypeOf(builtIns.getBooleanType(), expectedType)) {
return reportError(CONSTANT_EXPECTED_TYPE_MISMATCH.on(expression, "boolean", expectedType)); return reportConstantExpectedTypeMismatch(expression, "boolean", expectedType, builtIns.getBooleanType());
} }
return false; return false;
} }
@@ -132,7 +137,7 @@ public class CompileTimeConstantChecker {
private boolean checkCharValue(ConstantValue<?> constant, KotlinType expectedType, KtConstantExpression expression) { private boolean checkCharValue(ConstantValue<?> constant, KotlinType expectedType, KtConstantExpression expression) {
if (!noExpectedTypeOrError(expectedType) if (!noExpectedTypeOrError(expectedType)
&& !KotlinTypeChecker.DEFAULT.isSubtypeOf(builtIns.getCharType(), expectedType)) { && !KotlinTypeChecker.DEFAULT.isSubtypeOf(builtIns.getCharType(), expectedType)) {
return reportError(CONSTANT_EXPECTED_TYPE_MISMATCH.on(expression, "character", expectedType)); return reportConstantExpectedTypeMismatch(expression, "character", expectedType, builtIns.getCharType());
} }
if (constant != null) { if (constant != null) {
@@ -148,6 +153,9 @@ public class CompileTimeConstantChecker {
private boolean checkNullValue(@NotNull KotlinType expectedType, @NotNull KtConstantExpression expression) { private boolean checkNullValue(@NotNull KotlinType expectedType, @NotNull KtConstantExpression expression) {
if (!noExpectedTypeOrError(expectedType) && !TypeUtils.acceptsNullable(expectedType)) { if (!noExpectedTypeOrError(expectedType) && !TypeUtils.acceptsNullable(expectedType)) {
if (DiagnosticUtilsKt.reportTypeMismatchDueToTypeProjection(context, expression, expectedType, builtIns.getNullableNothingType())) {
return true;
}
return reportError(NULL_FOR_NONNULL_TYPE.on(expression, expectedType)); return reportError(NULL_FOR_NONNULL_TYPE.on(expression, expectedType));
} }
return false; return false;
@@ -269,10 +277,22 @@ public class CompileTimeConstantChecker {
return null; return null;
} }
public static boolean noExpectedTypeOrError(KotlinType expectedType) { private static boolean noExpectedTypeOrError(KotlinType expectedType) {
return TypeUtils.noExpectedType(expectedType) || expectedType.isError(); return TypeUtils.noExpectedType(expectedType) || expectedType.isError();
} }
private boolean reportConstantExpectedTypeMismatch(
@NotNull KtConstantExpression expression,
@NotNull String typeName,
@NotNull KotlinType expectedType,
@Nullable KotlinType expressionType
) {
if (DiagnosticUtilsKt.reportTypeMismatchDueToTypeProjection(context, expression, expectedType, expressionType)) return true;
trace.report(CONSTANT_EXPECTED_TYPE_MISMATCH.on(expression, typeName, expectedType));
return true;
}
private boolean reportError(@NotNull Diagnostic diagnostic) { private boolean reportError(@NotNull Diagnostic diagnostic) {
if (!checkOnlyErrorsThatDependOnExpectedType || errorsThatDependOnExpectedType.contains(diagnostic.getFactory())) { if (!checkOnlyErrorsThatDependOnExpectedType || errorsThatDependOnExpectedType.contains(diagnostic.getFactory())) {
trace.report(diagnostic); trace.report(diagnostic);
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.types.expressions; package org.jetbrains.kotlin.types.expressions;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.intellij.openapi.util.Ref;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet; import com.intellij.psi.tree.TokenSet;
@@ -31,6 +32,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.annotations.Annotations; import org.jetbrains.kotlin.descriptors.annotations.Annotations;
import org.jetbrains.kotlin.diagnostics.Diagnostic; import org.jetbrains.kotlin.diagnostics.Diagnostic;
import org.jetbrains.kotlin.diagnostics.DiagnosticUtilsKt;
import org.jetbrains.kotlin.diagnostics.Errors; import org.jetbrains.kotlin.diagnostics.Errors;
import org.jetbrains.kotlin.lexer.KtKeywordToken; import org.jetbrains.kotlin.lexer.KtKeywordToken;
import org.jetbrains.kotlin.lexer.KtTokens; import org.jetbrains.kotlin.lexer.KtTokens;
@@ -196,7 +198,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
); );
if (!(compileTimeConstant instanceof IntegerValueTypeConstant)) { if (!(compileTimeConstant instanceof IntegerValueTypeConstant)) {
CompileTimeConstantChecker constantChecker = new CompileTimeConstantChecker(context.trace, components.builtIns, false); CompileTimeConstantChecker constantChecker = new CompileTimeConstantChecker(context, components.builtIns, false);
ConstantValue constantValue = ConstantValue constantValue =
compileTimeConstant != null ? ((TypedCompileTimeConstant) compileTimeConstant).getConstantValue() : null; compileTimeConstant != null ? ((TypedCompileTimeConstant) compileTimeConstant).getConstantValue() : null;
boolean hasError = constantChecker.checkConstantExpressionType(constantValue, expression, context.expectedType); boolean hasError = constantChecker.checkConstantExpressionType(constantValue, expression, context.expectedType);
@@ -35,6 +35,7 @@ import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.BindingContextUtils; import org.jetbrains.kotlin.resolve.BindingContextUtils;
import org.jetbrains.kotlin.resolve.BindingTrace; import org.jetbrains.kotlin.resolve.BindingTrace;
import org.jetbrains.kotlin.resolve.calls.CallResolver; import org.jetbrains.kotlin.resolve.calls.CallResolver;
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext;
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem; import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem;
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemStatus; import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemStatus;
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintsUtil; import org.jetbrains.kotlin.resolve.calls.inference.ConstraintsUtil;
@@ -386,7 +387,7 @@ public class ControlStructureTypingUtils {
@Override @Override
public void typeInferenceFailed( public void typeInferenceFailed(
@NotNull BindingTrace trace, @NotNull InferenceErrorData data @NotNull ResolutionContext<?> context, @NotNull InferenceErrorData data
) { ) {
ConstraintSystem constraintSystem = data.constraintSystem; ConstraintSystem constraintSystem = data.constraintSystem;
ConstraintSystemStatus status = constraintSystem.getStatus(); ConstraintSystemStatus status = constraintSystem.getStatus();
@@ -398,7 +399,7 @@ public class ControlStructureTypingUtils {
KtExpression expression = (KtExpression) call.getCallElement(); KtExpression expression = (KtExpression) call.getCallElement();
if (status.hasOnlyErrorsDerivedFrom(EXPECTED_TYPE_POSITION) || status.hasConflictingConstraints() if (status.hasOnlyErrorsDerivedFrom(EXPECTED_TYPE_POSITION) || status.hasConflictingConstraints()
|| status.hasTypeInferenceIncorporationError()) { // todo after KT-... remove this line || status.hasTypeInferenceIncorporationError()) { // todo after KT-... remove this line
expression.accept(checkTypeVisitor, new CheckTypeContext(trace, data.expectedType)); expression.accept(checkTypeVisitor, new CheckTypeContext(context.trace, data.expectedType));
return; return;
} }
KtDeclaration parentDeclaration = PsiTreeUtil.getParentOfType(expression, KtNamedDeclaration.class); KtDeclaration parentDeclaration = PsiTreeUtil.getParentOfType(expression, KtNamedDeclaration.class);
@@ -455,7 +456,10 @@ public class ControlStructureTypingUtils {
@Override @Override
public void wrongReceiverType( public void wrongReceiverType(
@NotNull BindingTrace trace, @NotNull ReceiverParameterDescriptor receiverParameter, @NotNull ReceiverValue receiverArgument @NotNull BindingTrace trace,
@NotNull ReceiverParameterDescriptor receiverParameter,
@NotNull ReceiverValue receiverArgument,
@NotNull ResolutionContext<?> c
) { ) {
logError(); logError();
} }
@@ -532,7 +536,7 @@ public class ControlStructureTypingUtils {
@Override @Override
public void typeInferenceFailed( public void typeInferenceFailed(
@NotNull BindingTrace trace, @NotNull InferenceErrorData inferenceErrorData @NotNull ResolutionContext<?> context, @NotNull InferenceErrorData inferenceErrorData
) { ) {
logError(); logError();
} }
@@ -22,6 +22,7 @@ import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.diagnostics.DiagnosticUtilsKt;
import org.jetbrains.kotlin.lexer.KtTokens; import org.jetbrains.kotlin.lexer.KtTokens;
import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.BindingContext;
@@ -196,7 +197,7 @@ public class DataFlowAnalyzer {
if (expression instanceof KtConstantExpression) { if (expression instanceof KtConstantExpression) {
ConstantValue<?> constantValue = constantExpressionEvaluator.evaluateToConstantValue(expression, c.trace, c.expectedType); ConstantValue<?> constantValue = constantExpressionEvaluator.evaluateToConstantValue(expression, c.trace, c.expectedType);
boolean error = new CompileTimeConstantChecker(c.trace, builtIns, true) boolean error = new CompileTimeConstantChecker(c, builtIns, true)
.checkConstantExpressionType(constantValue, (KtConstantExpression) expression, c.expectedType); .checkConstantExpressionType(constantValue, (KtConstantExpression) expression, c.expectedType);
hasError.set(error); hasError.set(error);
return expressionType; return expressionType;
@@ -210,7 +211,9 @@ public class DataFlowAnalyzer {
SmartCastResult castResult = checkPossibleCast(expressionType, expression, c); SmartCastResult castResult = checkPossibleCast(expressionType, expression, c);
if (castResult != null) return castResult.getResultType(); if (castResult != null) return castResult.getResultType();
c.trace.report(TYPE_MISMATCH.on(expression, c.expectedType, expressionType)); if (!DiagnosticUtilsKt.reportTypeMismatchDueToTypeProjection(c, expression, c.expectedType, expressionType)) {
c.trace.report(TYPE_MISMATCH.on(expression, c.expectedType, expressionType));
}
hasError.set(true); hasError.set(true);
return expressionType; return expressionType;
} }
@@ -20,10 +20,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.resolve.BindingTrace; import org.jetbrains.kotlin.resolve.BindingTrace;
import org.jetbrains.kotlin.resolve.StatementFilter; import org.jetbrains.kotlin.resolve.StatementFilter;
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker; import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker;
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency; import org.jetbrains.kotlin.resolve.calls.context.*;
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext;
import org.jetbrains.kotlin.resolve.calls.context.ResolutionResultsCache;
import org.jetbrains.kotlin.resolve.calls.context.ResolutionResultsCacheImpl;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo; import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
import org.jetbrains.kotlin.resolve.scopes.LexicalScope; import org.jetbrains.kotlin.resolve.scopes.LexicalScope;
import org.jetbrains.kotlin.types.KotlinType; import org.jetbrains.kotlin.types.KotlinType;
@@ -61,8 +58,8 @@ public class ExpressionTypingContext extends ResolutionContext<ExpressionTypingC
context.contextDependency, context.resolutionResultsCache, context.contextDependency, context.resolutionResultsCache,
context.callChecker, context.callChecker,
context.statementFilter, context.statementFilter,
context.isAnnotationContext, context.collectAllCandidates context.isAnnotationContext, context.collectAllCandidates,
); context.callPosition);
} }
@NotNull @NotNull
@@ -79,7 +76,7 @@ public class ExpressionTypingContext extends ResolutionContext<ExpressionTypingC
) { ) {
return new ExpressionTypingContext( return new ExpressionTypingContext(
trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, callChecker, trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, callChecker,
statementFilter, isAnnotationContext, false); statementFilter, isAnnotationContext, false, CallPosition.Unknown.INSTANCE);
} }
private ExpressionTypingContext( private ExpressionTypingContext(
@@ -92,11 +89,12 @@ public class ExpressionTypingContext extends ResolutionContext<ExpressionTypingC
@NotNull CallChecker callChecker, @NotNull CallChecker callChecker,
@NotNull StatementFilter statementFilter, @NotNull StatementFilter statementFilter,
boolean isAnnotationContext, boolean isAnnotationContext,
boolean collectAllCandidates boolean collectAllCandidates,
@NotNull CallPosition callPosition
) { ) {
super(trace, scope, expectedType, dataFlowInfo, contextDependency, resolutionResultsCache, super(trace, scope, expectedType, dataFlowInfo, contextDependency, resolutionResultsCache,
callChecker, callChecker,
statementFilter, isAnnotationContext, collectAllCandidates); statementFilter, isAnnotationContext, collectAllCandidates, callPosition);
} }
@Override @Override
@@ -108,11 +106,12 @@ public class ExpressionTypingContext extends ResolutionContext<ExpressionTypingC
@NotNull ContextDependency contextDependency, @NotNull ContextDependency contextDependency,
@NotNull ResolutionResultsCache resolutionResultsCache, @NotNull ResolutionResultsCache resolutionResultsCache,
@NotNull StatementFilter statementFilter, @NotNull StatementFilter statementFilter,
boolean collectAllCandidates boolean collectAllCandidates,
@NotNull CallPosition callPosition
) { ) {
return new ExpressionTypingContext(trace, scope, dataFlowInfo, return new ExpressionTypingContext(trace, scope, dataFlowInfo,
expectedType, contextDependency, resolutionResultsCache, expectedType, contextDependency, resolutionResultsCache,
callChecker, callChecker,
statementFilter, isAnnotationContext, collectAllCandidates); statementFilter, isAnnotationContext, collectAllCandidates, callPosition);
} }
} }
@@ -124,8 +124,7 @@ public class ExpressionTypingUtils {
@Override @Override
public void report(@NotNull Diagnostic diagnostic) { public void report(@NotNull Diagnostic diagnostic) {
DiagnosticFactory<?> factory = diagnostic.getFactory(); DiagnosticFactory<?> factory = diagnostic.getFactory();
if ((factory == TYPE_MISMATCH || factory == CONSTANT_EXPECTED_TYPE_MISMATCH || factory == NULL_FOR_NONNULL_TYPE) if (Errors.TYPE_MISMATCH_ERRORS.contains(factory) && diagnostic.getPsiElement() == expressionToWatch) {
&& diagnostic.getPsiElement() == expressionToWatch) {
mismatchFound[0] = true; mismatchFound[0] = true;
} }
if (TYPE_INFERENCE_ERRORS.contains(factory) && if (TYPE_INFERENCE_ERRORS.contains(factory) &&
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.diagnostics.Errors;
import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.*; import org.jetbrains.kotlin.resolve.*;
import org.jetbrains.kotlin.resolve.bindingContextUtil.BindingContextUtilsKt; import org.jetbrains.kotlin.resolve.bindingContextUtil.BindingContextUtilsKt;
import org.jetbrains.kotlin.resolve.calls.context.CallPosition;
import org.jetbrains.kotlin.resolve.scopes.LexicalScopeKind; import org.jetbrains.kotlin.resolve.scopes.LexicalScopeKind;
import org.jetbrains.kotlin.resolve.scopes.LexicalWritableScope; import org.jetbrains.kotlin.resolve.scopes.LexicalWritableScope;
import org.jetbrains.kotlin.types.DeferredType; import org.jetbrains.kotlin.types.DeferredType;
@@ -230,7 +231,8 @@ public abstract class ExpressionTypingVisitorDispatcher extends KtVisitor<Kotlin
@Override @Override
public KotlinTypeInfo visitLambdaExpression(@NotNull KtLambdaExpression expression, ExpressionTypingContext data) { public KotlinTypeInfo visitLambdaExpression(@NotNull KtLambdaExpression expression, ExpressionTypingContext data) {
return functions.visitLambdaExpression(expression, data); // Erasing call position to unknown is necessary to prevent wrong call positions when type checking lambda's body
return functions.visitLambdaExpression(expression, data.replaceCallPosition(CallPosition.Unknown.INSTANCE));
} }
@Override @Override
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.BindingContextUtils; import org.jetbrains.kotlin.resolve.BindingContextUtils;
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace; import org.jetbrains.kotlin.resolve.TemporaryBindingTrace;
import org.jetbrains.kotlin.resolve.calls.context.CallPosition;
import org.jetbrains.kotlin.resolve.calls.context.TemporaryTraceAndCache; import org.jetbrains.kotlin.resolve.calls.context.TemporaryTraceAndCache;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults; import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults;
@@ -269,7 +270,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
KotlinType expectedType = refineTypeFromPropertySetterIfPossible(context.trace.getBindingContext(), leftOperand, leftType); KotlinType expectedType = refineTypeFromPropertySetterIfPossible(context.trace.getBindingContext(), leftOperand, leftType);
components.dataFlowAnalyzer.checkType(binaryOperationType, expression, context.replaceExpectedType(expectedType) components.dataFlowAnalyzer.checkType(binaryOperationType, expression, context.replaceExpectedType(expectedType)
.replaceDataFlowInfo(rightInfo.getDataFlowInfo())); .replaceDataFlowInfo(rightInfo.getDataFlowInfo()).replaceCallPosition(new CallPosition.PropertyAssignment(left)));
basic.checkLValue(context.trace, context, leftOperand, right); basic.checkLValue(context.trace, context, leftOperand, right);
} }
temporary.commit(); temporary.commit();
@@ -317,7 +318,9 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
DataFlowInfo dataFlowInfo = leftInfo.getDataFlowInfo(); DataFlowInfo dataFlowInfo = leftInfo.getDataFlowInfo();
KotlinTypeInfo resultInfo; KotlinTypeInfo resultInfo;
if (right != null) { if (right != null) {
resultInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo).replaceExpectedType(expectedType)); resultInfo = facade.getTypeInfo(
right, context.replaceDataFlowInfo(dataFlowInfo).replaceExpectedType(expectedType).replaceCallPosition(
new CallPosition.PropertyAssignment(leftOperand)));
dataFlowInfo = resultInfo.getDataFlowInfo(); dataFlowInfo = resultInfo.getDataFlowInfo();
KotlinType rightType = resultInfo.getType(); KotlinType rightType = resultInfo.getType();
@@ -2,5 +2,5 @@
fun foo() { fun foo() {
val f : Function1<*, *> = { x -> x.toString() } val f : Function1<*, *> = { x -> x.toString() }
f(<!CONSTANT_EXPECTED_TYPE_MISMATCH!>1<!>) <!MEMBER_PROJECTED_OUT!>f<!>(1)
} }
@@ -36,13 +36,13 @@ fun testInOut() {
Inv<Int>().f(1) Inv<Int>().f(1)
(null <!CAST_NEVER_SUCCEEDS!>as<!> Inv<in Int>).f(1) (null <!CAST_NEVER_SUCCEEDS!>as<!> Inv<in Int>).f(1)
(null <!CAST_NEVER_SUCCEEDS!>as<!> Inv<out Int>).f(<!CONSTANT_EXPECTED_TYPE_MISMATCH!>1<!>) // !! (null <!CAST_NEVER_SUCCEEDS!>as<!> Inv<out Int>).<!MEMBER_PROJECTED_OUT!>f<!>(1) // !!
(null <!CAST_NEVER_SUCCEEDS!>as<!> Inv<*>).f(<!CONSTANT_EXPECTED_TYPE_MISMATCH!>1<!>) // !! (null <!CAST_NEVER_SUCCEEDS!>as<!> Inv<*>).<!MEMBER_PROJECTED_OUT!>f<!>(1) // !!
Inv<Int>().inf(1) Inv<Int>().inf(1)
(null <!CAST_NEVER_SUCCEEDS!>as<!> Inv<in Int>).inf(1) (null <!CAST_NEVER_SUCCEEDS!>as<!> Inv<in Int>).inf(1)
(null <!CAST_NEVER_SUCCEEDS!>as<!> Inv<out Int>).inf(<!CONSTANT_EXPECTED_TYPE_MISMATCH!>1<!>) // !! (null <!CAST_NEVER_SUCCEEDS!>as<!> Inv<out Int>).<!MEMBER_PROJECTED_OUT!>inf<!>(1) // !!
(null <!CAST_NEVER_SUCCEEDS!>as<!> Inv<*>).inf(<!CONSTANT_EXPECTED_TYPE_MISMATCH!>1<!>) // !! (null <!CAST_NEVER_SUCCEEDS!>as<!> Inv<*>).<!MEMBER_PROJECTED_OUT!>inf<!>(1) // !!
Inv<Int>().outf() Inv<Int>().outf()
checkSubtype<Int>(<!TYPE_MISMATCH!>(null <!CAST_NEVER_SUCCEEDS!>as<!> Inv<in Int>).outf()<!>) // Type mismatch checkSubtype<Int>(<!TYPE_MISMATCH!>(null <!CAST_NEVER_SUCCEEDS!>as<!> Inv<in Int>).outf()<!>) // Type mismatch
@@ -28,9 +28,9 @@ fun main() {
checkSubtype<Outer<out CharSequence>.Inner>(outer.bar()) checkSubtype<Outer<out CharSequence>.Inner>(outer.bar())
checkSubtype<Outer<out CharSequence>.Inner>(outer.Inner()) checkSubtype<Outer<out CharSequence>.Inner>(outer.Inner())
outer.set(<!TYPE_MISMATCH(kotlin.Nothing; Outer<out kotlin.String>.Inner)!>outer.bar()<!>) outer.<!MEMBER_PROJECTED_OUT!>set<!>(outer.bar())
outer.set(<!TYPE_MISMATCH(kotlin.Nothing; Outer<out kotlin.String>.Inner)!>outer.Inner()<!>) outer.<!MEMBER_PROJECTED_OUT!>set<!>(outer.Inner())
val x: Outer<String>.Inner = factoryString() val x: Outer<String>.Inner = factoryString()
outer.set(<!TYPE_MISMATCH(kotlin.Nothing; Outer<kotlin.String>.Inner)!>x<!>) outer.<!MEMBER_PROJECTED_OUT!>set<!>(x)
} }
@@ -4,6 +4,7 @@ interface C<out T>
interface MC<T> : C<T> { interface MC<T> : C<T> {
fun addAll(x: C<T>): Boolean fun addAll(x: C<T>): Boolean
fun addAllMC(x: MC<out T>): Boolean fun addAllMC(x: MC<out T>): Boolean
fun addAllInv(x: MC<T>): Boolean
} }
interface Open interface Open
@@ -13,15 +14,18 @@ fun <T> mc(): MC<T> = null!!
fun <T> c(): C<T> = null!! fun <T> c(): C<T> = null!!
fun foo(x: MC<out Open>) { fun foo(x: MC<out Open>) {
x.addAll(<!TYPE_MISMATCH(C<kotlin.Nothing>; MC<out Open>)!>x<!>) x.addAll(<!TYPE_MISMATCH_DUE_TO_TYPE_PROJECTIONS(C<kotlin.Nothing>; MC<out Open>; MC<out Open>; public abstract fun addAll\(x: C<T>\): kotlin.Boolean defined in MC)!>x<!>)
x.addAllMC(<!TYPE_MISMATCH(MC<kotlin.Nothing>; MC<out Open>)!>x<!>) x.addAllMC(<!TYPE_MISMATCH_DUE_TO_TYPE_PROJECTIONS(MC<kotlin.Nothing>; MC<out Open>; MC<out Open>; public abstract fun addAllMC\(x: MC<out T>\): kotlin.Boolean defined in MC)!>x<!>)
x.addAll(<!TYPE_MISMATCH(C<kotlin.Nothing>; MC<Open>)!>mc<Open>()<!>) x.addAll(<!TYPE_MISMATCH_DUE_TO_TYPE_PROJECTIONS(C<kotlin.Nothing>; MC<Open>; MC<out Open>; public abstract fun addAll\(x: C<T>\): kotlin.Boolean defined in MC)!>mc<Open>()<!>)
x.addAllMC(<!TYPE_MISMATCH(MC<kotlin.Nothing>; MC<Open>)!>mc<Open>()<!>) x.addAllMC(<!TYPE_MISMATCH_DUE_TO_TYPE_PROJECTIONS(MC<kotlin.Nothing>; MC<Open>; MC<out Open>; public abstract fun addAllMC\(x: MC<out T>\): kotlin.Boolean defined in MC)!>mc<Open>()<!>)
x.addAll(<!TYPE_MISMATCH(C<kotlin.Nothing>; MC<Derived>)!>mc<Derived>()<!>) x.addAll(<!TYPE_MISMATCH_DUE_TO_TYPE_PROJECTIONS(C<kotlin.Nothing>; MC<Derived>; MC<out Open>; public abstract fun addAll\(x: C<T>\): kotlin.Boolean defined in MC)!>mc<Derived>()<!>)
x.addAllMC(<!TYPE_MISMATCH(MC<kotlin.Nothing>; MC<Derived>)!>mc<Derived>()<!>) x.addAllMC(<!TYPE_MISMATCH_DUE_TO_TYPE_PROJECTIONS(MC<kotlin.Nothing>; MC<Derived>; MC<out Open>; public abstract fun addAllMC\(x: MC<out T>\): kotlin.Boolean defined in MC)!>mc<Derived>()<!>)
x.addAll(c()) x.addAll(c())
x.addAll(c<Nothing>()) x.addAll(c<Nothing>())
x.<!MEMBER_PROJECTED_OUT!>addAllInv<!>(mc<Open>())
x.addAll(<!CONSTANT_EXPECTED_TYPE_MISMATCH!>1<!>)
} }
@@ -19,6 +19,7 @@ public final class Derived : Open {
public interface MC</*0*/ T> : C<T> { public interface MC</*0*/ T> : C<T> {
public abstract fun addAll(/*0*/ x: C<T>): kotlin.Boolean public abstract fun addAll(/*0*/ x: C<T>): kotlin.Boolean
public abstract fun addAllInv(/*0*/ x: MC<T>): kotlin.Boolean
public abstract fun addAllMC(/*0*/ x: MC<out T>): kotlin.Boolean public abstract fun addAllMC(/*0*/ x: MC<out T>): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
@@ -0,0 +1,19 @@
class A<T> {
fun T.foo() {}
fun Out<T>.bar() {}
}
class Out<out E>
public inline fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f()
fun test(x: A<out CharSequence>, y: Out<CharSequence>) {
with(x) {
// TODO: this diagnostic could be replaced with TYPE_MISMATCH_DUE_TO_TYPE_PROJECTION
"".<!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>foo<!>()
<!TYPE_MISMATCH_DUE_TO_TYPE_PROJECTIONS!>y<!>.bar()
with(y) {
<!TYPE_MISMATCH_DUE_TO_TYPE_PROJECTIONS!>bar<!>()
}
}
}
@@ -0,0 +1,20 @@
package
public fun test(/*0*/ x: A<out kotlin.CharSequence>, /*1*/ y: Out<kotlin.CharSequence>): kotlin.Unit
public inline fun </*0*/ T, /*1*/ R> with(/*0*/ receiver: T, /*1*/ f: T.() -> R): R
public final class A</*0*/ T> {
public constructor A</*0*/ T>()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
public final fun Out<T>.bar(): kotlin.Unit
public final fun T.foo(): kotlin.Unit
}
public final class Out</*0*/ out E> {
public constructor Out</*0*/ out E>()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,8 @@
interface A<T>
interface B<E> {
fun foo(x: A<in E>)
}
fun foo(x: B<in CharSequence>, y: A<CharSequence>) {
x.foo(<!TYPE_MISMATCH_DUE_TO_TYPE_PROJECTIONS!>y<!>)
}
@@ -0,0 +1,16 @@
package
public fun foo(/*0*/ x: B<in kotlin.CharSequence>, /*1*/ y: A<kotlin.CharSequence>): kotlin.Unit
public interface A</*0*/ T> {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public interface B</*0*/ E> {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public abstract fun foo(/*0*/ x: A<in E>): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,19 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
class Out<out T>
class In<in T> {
fun invoke1(x: T) {}
fun invoke2(x: Out<T>) {}
}
interface A<E> {
fun foo(): In<E>
}
fun test(a: A<out CharSequence>, y: Out<CharSequence>) {
val i = a.foo()
// TODO: These diagnostic are wrong, type of 'i' --- 'In<Nothing>' is not projected itself,
// but it's approximation result caused by 'a' projection
i.invoke1(<!TYPE_MISMATCH!>""<!>)
i.invoke2(<!TYPE_MISMATCH!>y<!>)
}
@@ -0,0 +1,26 @@
package
public fun test(/*0*/ a: A<out kotlin.CharSequence>, /*1*/ y: Out<kotlin.CharSequence>): kotlin.Unit
public interface A</*0*/ E> {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public abstract fun foo(): In<E>
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class In</*0*/ in T> {
public constructor In</*0*/ in T>()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final fun invoke1(/*0*/ x: T): kotlin.Unit
public final fun invoke2(/*0*/ x: Out<T>): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class Out</*0*/ out T> {
public constructor Out</*0*/ out T>()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,9 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
class A<T> {
fun foo(x: T, y: T) {}
}
fun test(a: A<out CharSequence>) {
a.<!MEMBER_PROJECTED_OUT!>foo<!>("", "")
}
@@ -0,0 +1,11 @@
package
public fun test(/*0*/ a: A<out kotlin.CharSequence>): kotlin.Unit
public final class A</*0*/ T> {
public constructor A</*0*/ T>()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final fun foo(/*0*/ x: T, /*1*/ y: T): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,13 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
class A<T> {
operator fun plus(x: T): A<T> = this
operator fun set(x: Int, y: T) {}
operator fun get(x: T) = 1
}
fun test(a: A<out CharSequence>) {
a <!MEMBER_PROJECTED_OUT(public final operator fun plus\(x: T\): A<T> defined in A; A<out kotlin.CharSequence>)!>+<!> ""
<!MEMBER_PROJECTED_OUT(public final operator fun set\(x: kotlin.Int, y: T\): kotlin.Unit defined in A; A<out kotlin.CharSequence>)!>a[1]<!> = ""
<!MEMBER_PROJECTED_OUT(public final operator fun get\(x: T\): kotlin.Int defined in A; A<out kotlin.CharSequence>)!>a[""]<!>
}
@@ -0,0 +1,13 @@
package
public fun test(/*0*/ a: A<out kotlin.CharSequence>): kotlin.Unit
public final class A</*0*/ T> {
public constructor A</*0*/ T>()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final operator fun get(/*0*/ x: T): kotlin.Int
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final operator fun plus(/*0*/ x: T): A<T>
public final operator fun set(/*0*/ x: kotlin.Int, /*1*/ y: T): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,19 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
class A<T> {
operator fun plus(x: Out<T>): A<T> = this
operator fun set(x: Int, y: Out<T>) {}
operator fun get(x: Out<T>) = 1
}
class Out<out F>
fun test(a: A<out CharSequence>, y: Out<CharSequence>) {
a + <!TYPE_MISMATCH_DUE_TO_TYPE_PROJECTIONS!>y<!>
a[1] = <!TYPE_MISMATCH_DUE_TO_TYPE_PROJECTIONS!>y<!>
a[<!TYPE_MISMATCH_DUE_TO_TYPE_PROJECTIONS!>y<!>]
a + Out<Nothing>()
a[1] = Out<Nothing>()
a[Out<Nothing>()]
}
@@ -0,0 +1,20 @@
package
public fun test(/*0*/ a: A<out kotlin.CharSequence>, /*1*/ y: Out<kotlin.CharSequence>): kotlin.Unit
public final class A</*0*/ T> {
public constructor A</*0*/ T>()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final operator fun get(/*0*/ x: Out<T>): kotlin.Int
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final operator fun plus(/*0*/ x: Out<T>): A<T>
public final operator fun set(/*0*/ x: kotlin.Int, /*1*/ y: Out<T>): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class Out</*0*/ out F> {
public constructor Out</*0*/ out F>()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,26 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE
class Out<out T> {
fun id() = this
fun foobar(x: Any) {}
}
class A<E> {
inline fun foo(block: () -> E) {}
inline fun bar(block: () -> Out<E>) {}
}
fun test(a: A<out CharSequence>, z: Out<CharSequence>) {
a.foo {
val x: String = <!CONSTANT_EXPECTED_TYPE_MISMATCH!>1<!> // Should be no TYPE_MISMATCH_DUE_TO_TYPE_PROJECTIONS
<!TYPE_MISMATCH!>""<!>
}
a.bar { <!TYPE_MISMATCH!>Out<CharSequence>()<!> }
a.bar { Out() }
a.bar { <!TYPE_MISMATCH!>z.id()<!> }
a.foo {
z.foobar(if (1 > 2) return@foo <!TYPE_MISMATCH!>""<!> else "")
<!TYPE_MISMATCH!>""<!>
}
}
@@ -0,0 +1,21 @@
package
public fun test(/*0*/ a: A<out kotlin.CharSequence>, /*1*/ z: Out<kotlin.CharSequence>): kotlin.Unit
public final class A</*0*/ E> {
public constructor A</*0*/ E>()
public final inline fun bar(/*0*/ block: () -> Out<E>): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final inline fun foo(/*0*/ block: () -> E): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class Out</*0*/ out T> {
public constructor Out</*0*/ out T>()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final fun foobar(/*0*/ x: kotlin.Any): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final fun id(): Out<T>
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,12 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
class A<T> {
fun foo(vararg x: T) {}
}
fun test(a: A<out CharSequence>, y: Array<out CharSequence>) {
a.<!MEMBER_PROJECTED_OUT!>foo<!>("", "", "")
a.foo(*<!TYPE_MISMATCH_DUE_TO_TYPE_PROJECTIONS!>y<!>)
// TODO: TYPE_MISMATCH_DUE_TO_TYPE_PROJECTIONS probably redundant
a.<!MEMBER_PROJECTED_OUT!>foo<!>(*<!TYPE_MISMATCH_DUE_TO_TYPE_PROJECTIONS!>y<!>, "")
}
@@ -0,0 +1,11 @@
package
public fun test(/*0*/ a: A<out kotlin.CharSequence>, /*1*/ y: kotlin.Array<out kotlin.CharSequence>): kotlin.Unit
public final class A</*0*/ T> {
public constructor A</*0*/ T>()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final fun foo(/*0*/ vararg x: T /*kotlin.Array<out T>*/): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -4,6 +4,6 @@ interface Tr<T> {
} }
fun test(t: Tr<*>) { fun test(t: Tr<*>) {
t.v = <!TYPE_MISMATCH!>t<!> <!SETTER_PROJECTED_OUT!>t.v<!> = t
t.v checkType { _<Tr<*>>() } t.v checkType { _<Tr<*>>() }
} }
@@ -7,7 +7,7 @@ interface Tr<T> {
fun test(t: Tr<*>) { fun test(t: Tr<*>) {
t.v = null!! t.v = null!!
t.v = <!TYPE_MISMATCH!>""<!> <!SETTER_PROJECTED_OUT!>t.v<!> = ""
t.v = <!NULL_FOR_NONNULL_TYPE!>null<!> <!SETTER_PROJECTED_OUT!>t.v<!> = null
t.v checkType { _<Any?>() } t.v checkType { _<Any?>() }
} }
@@ -6,5 +6,5 @@ interface Tr<T> {
fun test(t: Tr<out String>) { fun test(t: Tr<out String>) {
// resolved as t.v = t.v + null!!, where type of right operand is String, // resolved as t.v = t.v + null!!, where type of right operand is String,
// so TYPE_MISMATCH: String is not <: of Captured(out String) // so TYPE_MISMATCH: String is not <: of Captured(out String)
<!TYPE_MISMATCH!>t.v += null!!<!> <!SETTER_PROJECTED_OUT!>t.v<!> += null!!
} }
@@ -1,12 +1,12 @@
fun test(mc: MutableCollection<out CharSequence>) { fun test(mc: MutableCollection<out CharSequence>) {
mc.addAll(<!TYPE_MISMATCH!>mc<!>) mc.addAll(<!TYPE_MISMATCH_DUE_TO_TYPE_PROJECTIONS!>mc<!>)
mc.addAll(<!TYPE_MISMATCH!>arrayListOf<CharSequence>()<!>) mc.addAll(<!TYPE_MISMATCH_DUE_TO_TYPE_PROJECTIONS!>arrayListOf<CharSequence>()<!>)
mc.addAll(arrayListOf()) mc.addAll(arrayListOf())
mc.addAll(<!TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH!>listOf("")<!>) mc.addAll(<!TYPE_MISMATCH_DUE_TO_TYPE_PROJECTIONS!>listOf("")<!>)
mc.addAll(<!TYPE_MISMATCH!>listOf<String>("")<!>) mc.addAll(<!TYPE_MISMATCH_DUE_TO_TYPE_PROJECTIONS!>listOf<String>("")<!>)
mc.addAll(<!TYPE_MISMATCH!>listOf<CharSequence>("")<!>) mc.addAll(<!TYPE_MISMATCH_DUE_TO_TYPE_PROJECTIONS!>listOf<CharSequence>("")<!>)
mc.addAll(emptyList()) mc.addAll(emptyList())
mc.addAll(emptyList<Nothing>()) mc.addAll(emptyList<Nothing>())
@@ -7190,6 +7190,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("extensionReceiverTypeMismatch.kt")
public void testExtensionReceiverTypeMismatch() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/extensionReceiverTypeMismatch.kt");
doTest(fileName);
}
@TestMetadata("extensionResultSubstitution.kt") @TestMetadata("extensionResultSubstitution.kt")
public void testExtensionResultSubstitution() throws Exception { public void testExtensionResultSubstitution() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/extensionResultSubstitution.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/extensionResultSubstitution.kt");
@@ -7202,6 +7208,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("inValueParameter.kt")
public void testInValueParameter() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/inValueParameter.kt");
doTest(fileName);
}
@TestMetadata("kt7296.kt") @TestMetadata("kt7296.kt")
public void testKt7296() throws Exception { public void testKt7296() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/kt7296.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/kt7296.kt");
@@ -7220,18 +7232,36 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("leakedApproximatedType.kt")
public void testLeakedApproximatedType() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/leakedApproximatedType.kt");
doTest(fileName);
}
@TestMetadata("MLOut.kt") @TestMetadata("MLOut.kt")
public void testMLOut() throws Exception { public void testMLOut() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/MLOut.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/MLOut.kt");
doTest(fileName); doTest(fileName);
} }
@TestMetadata("multipleArgumentProjectedOut.kt")
public void testMultipleArgumentProjectedOut() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/multipleArgumentProjectedOut.kt");
doTest(fileName);
}
@TestMetadata("platformSuperClass.kt") @TestMetadata("platformSuperClass.kt")
public void testPlatformSuperClass() throws Exception { public void testPlatformSuperClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/platformSuperClass.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/platformSuperClass.kt");
doTest(fileName); doTest(fileName);
} }
@TestMetadata("projectedOutConventions.kt")
public void testProjectedOutConventions() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/projectedOutConventions.kt");
doTest(fileName);
}
@TestMetadata("recursiveUpperBoundStar.kt") @TestMetadata("recursiveUpperBoundStar.kt")
public void testRecursiveUpperBoundStar() throws Exception { public void testRecursiveUpperBoundStar() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/recursiveUpperBoundStar.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/recursiveUpperBoundStar.kt");
@@ -7262,6 +7292,18 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("typeMismatchConventions.kt")
public void testTypeMismatchConventions() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/typeMismatchConventions.kt");
doTest(fileName);
}
@TestMetadata("typeMismatchInLambda.kt")
public void testTypeMismatchInLambda() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/typeMismatchInLambda.kt");
doTest(fileName);
}
@TestMetadata("typeParameterBounds.kt") @TestMetadata("typeParameterBounds.kt")
public void testTypeParameterBounds() throws Exception { public void testTypeParameterBounds() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/typeParameterBounds.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/typeParameterBounds.kt");
@@ -7273,6 +7315,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceStar.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/unsafeVarianceStar.kt");
doTest(fileName); doTest(fileName);
} }
@TestMetadata("varargs.kt")
public void testVarargs() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/varargs.kt");
doTest(fileName);
}
} }
@TestMetadata("compiler/testData/diagnostics/tests/generics/starProjections") @TestMetadata("compiler/testData/diagnostics/tests/generics/starProjections")
@@ -98,17 +98,17 @@ fun createCapturedType(typeProjection: TypeProjection): KotlinType
fun KotlinType.isCaptured(): Boolean = constructor is CapturedTypeConstructor fun KotlinType.isCaptured(): Boolean = constructor is CapturedTypeConstructor
fun TypeSubstitution.wrapWithCapturingSubstitution(): TypeSubstitution = fun TypeSubstitution.wrapWithCapturingSubstitution(needApproximation: Boolean = true): TypeSubstitution =
if (this is IndexedParametersSubstitution) if (this is IndexedParametersSubstitution)
IndexedParametersSubstitution( IndexedParametersSubstitution(
this.parameters, this.parameters,
this.arguments.zip(this.parameters).map { this.arguments.zip(this.parameters).map {
it.first.createCapturedIfNeeded(it.second) it.first.createCapturedIfNeeded(it.second)
}.toTypedArray(), }.toTypedArray(),
approximateCapturedTypes = true) approximateCapturedTypes = needApproximation)
else else
object : DelegatedTypeSubstitution(this@wrapWithCapturingSubstitution) { object : DelegatedTypeSubstitution(this@wrapWithCapturingSubstitution) {
override fun approximateContravariantCapturedTypes() = true override fun approximateContravariantCapturedTypes() = needApproximation
override fun get(key: KotlinType) = super.get(key)?.createCapturedIfNeeded(key.constructor.declarationDescriptor as? TypeParameterDescriptor) override fun get(key: KotlinType) = super.get(key)?.createCapturedIfNeeded(key.constructor.declarationDescriptor as? TypeParameterDescriptor)
} }
@@ -23,7 +23,8 @@ import org.jetbrains.kotlin.resolve.calls.inference.isCaptured
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import org.jetbrains.kotlin.types.typeUtil.builtIns import org.jetbrains.kotlin.types.typeUtil.*
import org.jetbrains.kotlin.utils.addToStdlib.check
import java.util.* import java.util.*
data class ApproximationBounds<T>( data class ApproximationBounds<T>(
@@ -20,12 +20,14 @@ import com.intellij.icons.AllIcons;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.TestOnly; import org.jetbrains.annotations.TestOnly;
import org.jetbrains.kotlin.diagnostics.Diagnostic; import org.jetbrains.kotlin.diagnostics.Diagnostic;
import org.jetbrains.kotlin.diagnostics.TypeMismatchDueToTypeProjectionsData;
import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages; import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages;
import org.jetbrains.kotlin.diagnostics.rendering.DiagnosticFactoryToRendererMap; import org.jetbrains.kotlin.diagnostics.rendering.DiagnosticFactoryToRendererMap;
import org.jetbrains.kotlin.diagnostics.rendering.DiagnosticRenderer; import org.jetbrains.kotlin.diagnostics.rendering.DiagnosticRenderer;
import org.jetbrains.kotlin.js.resolve.diagnostics.ErrorsJs; import org.jetbrains.kotlin.js.resolve.diagnostics.ErrorsJs;
import org.jetbrains.kotlin.js.resolve.diagnostics.JsCallDataHtmlRenderer; import org.jetbrains.kotlin.js.resolve.diagnostics.JsCallDataHtmlRenderer;
import org.jetbrains.kotlin.renderer.DescriptorRenderer; import org.jetbrains.kotlin.renderer.DescriptorRenderer;
import org.jetbrains.kotlin.renderer.MultiRenderer;
import java.net.URL; import java.net.URL;
@@ -66,6 +68,22 @@ public class IdeErrorMessages {
MAP.put(TYPE_MISMATCH, "<html>Type mismatch.<table><tr><td>Required:</td><td>{0}</td></tr><tr><td>Found:</td><td>{1}</td></tr></table></html>", MAP.put(TYPE_MISMATCH, "<html>Type mismatch.<table><tr><td>Required:</td><td>{0}</td></tr><tr><td>Found:</td><td>{1}</td></tr></table></html>",
HTML_RENDER_TYPE, HTML_RENDER_TYPE); HTML_RENDER_TYPE, HTML_RENDER_TYPE);
MAP.put(TYPE_MISMATCH_DUE_TO_TYPE_PROJECTIONS,
"<html>Type mismatch.<table><tr><td>Required:</td><td>{0}</td></tr><tr><td>Found:</td><td>{1}</td></tr></table><br />\n" +
"Projected type {2} restricts use of <br />\n{3}\n</html>",
new MultiRenderer<TypeMismatchDueToTypeProjectionsData>() {
@NotNull
@Override
public String[] render(@NotNull TypeMismatchDueToTypeProjectionsData object) {
return new String[] {
HTML_RENDER_TYPE.render(object.getExpectedType()),
HTML_RENDER_TYPE.render(object.getExpressionType()),
HTML_RENDER_TYPE.render(object.getReceiverType()),
DescriptorRenderer.HTML.render(object.getCallableDescriptor())
};
}
});
MAP.put(ASSIGN_OPERATOR_AMBIGUITY, "<html>Assignment operators ambiguity. All these functions match.<ul>{0}</ul></table></html>", MAP.put(ASSIGN_OPERATOR_AMBIGUITY, "<html>Assignment operators ambiguity. All these functions match.<ul>{0}</ul></table></html>",
HTML_AMBIGUOUS_CALLS); HTML_AMBIGUOUS_CALLS);
@@ -0,0 +1,6 @@
// !DIAGNOSTICS_NUMBER: 1
// !DIAGNOSTICS: MEMBER_PROJECTED_OUT
fun foo(x: MutableCollection<out CharSequence>) {
x.add("")
}
@@ -0,0 +1,2 @@
<!-- expectedNothingDueToProjections1 -->
Out-projected type 'kotlin.MutableCollection<out kotlin.CharSequence>' prohibits the use of 'public abstract fun add(element: E): kotlin.Boolean defined in kotlin.MutableCollection'
@@ -0,0 +1,6 @@
// !DIAGNOSTICS_NUMBER: 1
// !DIAGNOSTICS: TYPE_MISMATCH_DUE_TO_TYPE_PROJECTIONS
fun foo(x: MutableCollection<out CharSequence>, y: MutableCollection<CharSequence>) {
x.addAll(y)
}
@@ -0,0 +1,17 @@
<!-- typeMismatchDueToProjections1 -->
<html>
Type mismatch.
<table>
<tr>
<td>Required:</td>
<td>kotlin.Collection<`kotlin.Nothing></td>
</tr>
<tr>
<td>Found:</td>
<td>kotlin.MutableCollection<`kotlin.CharSequence></td>
</tr>
</table>
<br />
Projected type kotlin.MutableCollection<`out kotlin.CharSequence> restricts use of <br />
<b>public</b> <b>abstract</b> <b>fun</b> addAll(elements: kotlin.Collection<`E>): kotlin.Boolean <i>defined in</i> kotlin.MutableCollection
</html>
@@ -0,0 +1,11 @@
// !DIAGNOSTICS_NUMBER: 1
// !DIAGNOSTICS: TYPE_MISMATCH_DUE_TO_TYPE_PROJECTIONS
interface A<T>
interface B<E> {
fun foo(x: A<in E>)
}
fun foo(x: B<in CharSequence>, y: A<CharSequence>) {
x.foo(y)
}
@@ -0,0 +1,17 @@
<!-- typeMismatchDueToProjectionsIn1 -->
<html>
Type mismatch.
<table>
<tr>
<td>Required:</td>
<td>A<`kotlin.Any?></td>
</tr>
<tr>
<td>Found:</td>
<td>A<`kotlin.CharSequence></td>
</tr>
</table>
<br />
Projected type B<`in kotlin.CharSequence> restricts use of <br />
<b>public</b> <b>abstract</b> <b>fun</b> foo(x: A<`in E>): kotlin.Unit <i>defined in</i> B
</html>
@@ -0,0 +1,7 @@
// !DIAGNOSTICS_NUMBER: 1
// !DIAGNOSTICS: TYPE_MISMATCH_DUE_TO_TYPE_PROJECTIONS
// !MESSAGE_TYPE: TEXT
fun foo(x: MutableCollection<out CharSequence>, y: MutableCollection<CharSequence>) {
x.addAll(y)
}
@@ -0,0 +1,2 @@
<!-- typeMismatchDueToProjectionsTxt1 -->
Type mismatch: inferred type is kotlin.MutableCollection<kotlin.CharSequence> but kotlin.Collection<kotlin.Nothing> was expected. Projected type kotlin.MutableCollection<out kotlin.CharSequence> restricts use of public abstract fun addAll(elements: kotlin.Collection<E>): kotlin.Boolean defined in kotlin.MutableCollection
@@ -101,6 +101,12 @@ public class DiagnosticMessageTestGenerated extends AbstractDiagnosticMessageTes
doTest(fileName); doTest(fileName);
} }
@TestMetadata("expectedNothingDueToProjections.kt")
public void testExpectedNothingDueToProjections() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/diagnosticMessage/expectedNothingDueToProjections.kt");
doTest(fileName);
}
@TestMetadata("extensionInClassReference.kt") @TestMetadata("extensionInClassReference.kt")
public void testExtensionInClassReference() throws Exception { public void testExtensionInClassReference() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/diagnosticMessage/extensionInClassReference.kt"); String fileName = KotlinTestUtils.navigationMetadata("idea/testData/diagnosticMessage/extensionInClassReference.kt");
@@ -179,6 +185,24 @@ public class DiagnosticMessageTestGenerated extends AbstractDiagnosticMessageTes
doTest(fileName); doTest(fileName);
} }
@TestMetadata("typeMismatchDueToProjections.kt")
public void testTypeMismatchDueToProjections() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/diagnosticMessage/typeMismatchDueToProjections.kt");
doTest(fileName);
}
@TestMetadata("typeMismatchDueToProjectionsIn.kt")
public void testTypeMismatchDueToProjectionsIn() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/diagnosticMessage/typeMismatchDueToProjectionsIn.kt");
doTest(fileName);
}
@TestMetadata("typeMismatchDueToProjectionsTxt.kt")
public void testTypeMismatchDueToProjectionsTxt() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/diagnosticMessage/typeMismatchDueToProjectionsTxt.kt");
doTest(fileName);
}
@TestMetadata("typeMismatchWithNothing.kt") @TestMetadata("typeMismatchWithNothing.kt")
public void testTypeMismatchWithNothing() throws Exception { public void testTypeMismatchWithNothing() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/diagnosticMessage/typeMismatchWithNothing.kt"); String fileName = KotlinTestUtils.navigationMetadata("idea/testData/diagnosticMessage/typeMismatchWithNothing.kt");