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.varianceChecker.VarianceChecker.VarianceConflictDiagnosticData;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.types.TypeProjection;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
@@ -714,6 +715,8 @@ public interface Errors {
// Type mismatch
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> EXPECTED_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(
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.DiagnosticFactory;
import org.jetbrains.kotlin.diagnostics.Errors;
import org.jetbrains.kotlin.diagnostics.TypeMismatchDueToTypeProjectionsData;
import org.jetbrains.kotlin.psi.KtExpression;
import org.jetbrains.kotlin.psi.KtSimpleNameExpression;
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(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(DEPRECATED_MODIFIER_PAIR, "Modifier ''{0}'' is deprecated in presence of ''{1}''", TO_STRING, 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.context.BasicCallResolutionContext
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.inference.ConstraintSystem
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,
// it's completed when the outer (variable as function call) is completed
if (!isInvokeCallOnVariable(context.call)) {
val temporaryTrace = TemporaryBindingTrace.create(context.trace, "Trace to complete a resulting call")
completeResolvedCallAndArguments(resolvedCall, results, context.replaceBindingTrace(temporaryTrace), tracing)
@@ -222,7 +222,7 @@ class CallCompleter(
candidateDescriptor, constraintSystem!!, valueArgumentsCheckingResult.argumentTypes,
receiverType, context.expectedType, context.call
)
tracing.typeInferenceFailed(context.trace, errorData)
tracing.typeInferenceFailed(context, errorData)
addStatus(ResolutionStatus.OTHER_ERROR)
}
@@ -247,11 +247,16 @@ class CallCompleter(
for (valueArgument in context.call.valueArguments) {
val argumentMapping = getArgumentMapping(valueArgument!!)
val expectedType = when (argumentMapping) {
is ArgumentMatch -> getEffectiveExpectedType(argumentMapping.valueParameter, valueArgument)
else -> TypeUtils.NO_EXPECTED_TYPE
val (expectedType, callPosition) = when (argumentMapping) {
is ArgumentMatch -> Pair(
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)
}
}
@@ -306,7 +311,7 @@ class CallCompleter(
val (cachedResolutionResults, cachedContext, tracing) = cachedData
val contextForArgument = cachedContext.replaceBindingTrace(context.trace)
.replaceExpectedType(context.expectedType).replaceCollectAllCandidates(false)
.replaceExpectedType(context.expectedType).replaceCollectAllCandidates(false).replaceCallPosition(context.callPosition)
return completeCall(contextForArgument, cachedResolutionResults, tracing)
}
@@ -449,7 +449,9 @@ class CandidateResolver(
receiverArgument, receiverParameter.type, this)
if (!isSubtypeBySmartCastIgnoringNullability) {
tracing.wrongReceiverType(trace, receiverParameter, receiverArgument)
tracing.wrongReceiverType(
trace, receiverParameter, receiverArgument,
this.replaceCallPosition(CallPosition.ExtensionReceiverPosition(candidateCall)))
return OTHER_ERROR
}
@@ -42,10 +42,11 @@ public class BasicCallResolutionContext extends CallResolutionContext<BasicCallR
@NotNull CallChecker callChecker,
@NotNull StatementFilter statementFilter,
boolean isAnnotationContext,
boolean collectAllCandidates
boolean collectAllCandidates,
@NotNull CallPosition callPosition
) {
super(trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments, resolutionResultsCache,
dataFlowInfoForArguments, callChecker, statementFilter, isAnnotationContext, collectAllCandidates);
dataFlowInfoForArguments, callChecker, statementFilter, isAnnotationContext, collectAllCandidates, callPosition);
}
@NotNull
@@ -62,7 +63,8 @@ public class BasicCallResolutionContext extends CallResolutionContext<BasicCallR
) {
return new BasicCallResolutionContext(trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments,
new ResolutionResultsCacheImpl(), null,
callChecker, StatementFilter.NONE, isAnnotationContext, false);
callChecker, StatementFilter.NONE, isAnnotationContext, false,
CallPosition.Unknown.INSTANCE);
}
@NotNull
@@ -74,7 +76,7 @@ public class BasicCallResolutionContext extends CallResolutionContext<BasicCallR
context.trace, context.scope, call, context.expectedType, context.dataFlowInfo, context.contextDependency, checkArguments,
context.resolutionResultsCache, dataFlowInfoForArguments,
context.callChecker,
context.statementFilter, context.isAnnotationContext, context.collectAllCandidates);
context.statementFilter, context.isAnnotationContext, context.collectAllCandidates, context.callPosition);
}
@NotNull
@@ -93,18 +95,19 @@ public class BasicCallResolutionContext extends CallResolutionContext<BasicCallR
@NotNull ContextDependency contextDependency,
@NotNull ResolutionResultsCache resolutionResultsCache,
@NotNull StatementFilter statementFilter,
boolean collectAllCandidates
boolean collectAllCandidates,
@NotNull CallPosition callPosition
) {
return new BasicCallResolutionContext(
trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments, resolutionResultsCache,
dataFlowInfoForArguments, callChecker, statementFilter, isAnnotationContext, collectAllCandidates);
dataFlowInfoForArguments, callChecker, statementFilter, isAnnotationContext, collectAllCandidates, callPosition);
}
@NotNull
public BasicCallResolutionContext replaceCall(@NotNull Call newCall) {
return new BasicCallResolutionContext(
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) {
@@ -58,11 +58,12 @@ public final class CallCandidateResolutionContext<D extends CallableDescriptor>
@Nullable Receiver explicitExtensionReceiverForInvoke,
@NotNull CandidateResolveMode candidateResolveMode,
boolean isAnnotationContext,
boolean collectAllCandidates
boolean collectAllCandidates,
@NotNull CallPosition callPosition
) {
super(trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments, resolutionResultsCache,
dataFlowInfoForArguments, callChecker, statementFilter, isAnnotationContext,
collectAllCandidates);
collectAllCandidates, callPosition);
this.candidateCall = candidateCall;
this.tracing = tracing;
this.explicitExtensionReceiverForInvoke = explicitExtensionReceiverForInvoke;
@@ -79,7 +80,7 @@ public final class CallCandidateResolutionContext<D extends CallableDescriptor>
context.dataFlowInfo, context.contextDependency, context.checkArguments,
context.resolutionResultsCache, context.dataFlowInfoForArguments,
context.callChecker, context.statementFilter, explicitExtensionReceiverForInvoke,
candidateResolveMode, context.isAnnotationContext, context.collectAllCandidates);
candidateResolveMode, context.isAnnotationContext, context.collectAllCandidates, context.callPosition);
}
@NotNull
@@ -90,7 +91,8 @@ public final class CallCandidateResolutionContext<D extends CallableDescriptor>
candidateCall, tracing, context.trace, context.scope, context.call, context.expectedType,
context.dataFlowInfo, context.contextDependency, context.checkArguments, context.resolutionResultsCache,
context.dataFlowInfoForArguments, context.callChecker, context.statementFilter,
null, CandidateResolveMode.FULLY, context.isAnnotationContext, context.collectAllCandidates);
null, CandidateResolveMode.FULLY, context.isAnnotationContext, context.collectAllCandidates,
context.callPosition);
}
@Override
@@ -102,11 +104,12 @@ public final class CallCandidateResolutionContext<D extends CallableDescriptor>
@NotNull ContextDependency contextDependency,
@NotNull ResolutionResultsCache resolutionResultsCache,
@NotNull StatementFilter statementFilter,
boolean collectAllCandidates
boolean collectAllCandidates,
@NotNull CallPosition callPosition
) {
return new CallCandidateResolutionContext<D>(
candidateCall, tracing, trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments,
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 StatementFilter statementFilter,
boolean isAnnotationContext,
boolean collectAllCandidates
boolean collectAllCandidates,
@NotNull CallPosition callPosition
) {
super(trace, scope, expectedType, dataFlowInfo, contextDependency, resolutionResultsCache, callChecker,
statementFilter, isAnnotationContext, collectAllCandidates);
statementFilter, isAnnotationContext, collectAllCandidates, callPosition);
this.call = call;
this.checkArguments = checkArguments;
if (dataFlowInfoForArguments != null) {
@@ -54,6 +54,9 @@ public abstract class ResolutionContext<Context extends ResolutionContext<Contex
public final boolean collectAllCandidates;
@NotNull
public final CallPosition callPosition;
protected ResolutionContext(
@NotNull BindingTrace trace,
@NotNull LexicalScope scope,
@@ -64,7 +67,8 @@ public abstract class ResolutionContext<Context extends ResolutionContext<Contex
@NotNull CallChecker callChecker,
@NotNull StatementFilter statementFilter,
boolean isAnnotationContext,
boolean collectAllCandidates
boolean collectAllCandidates,
@NotNull CallPosition callPosition
) {
this.trace = trace;
this.scope = scope;
@@ -76,6 +80,7 @@ public abstract class ResolutionContext<Context extends ResolutionContext<Contex
this.statementFilter = statementFilter;
this.isAnnotationContext = isAnnotationContext;
this.collectAllCandidates = collectAllCandidates;
this.callPosition = callPosition;
}
protected abstract Context create(
@@ -86,7 +91,8 @@ public abstract class ResolutionContext<Context extends ResolutionContext<Contex
@NotNull ContextDependency contextDependency,
@NotNull ResolutionResultsCache resolutionResultsCache,
@NotNull StatementFilter statementFilter,
boolean collectAllCandidates
boolean collectAllCandidates,
@NotNull CallPosition callPosition
);
@NotNull
@@ -99,14 +105,14 @@ public abstract class ResolutionContext<Context extends ResolutionContext<Contex
public Context replaceBindingTrace(@NotNull BindingTrace trace) {
if (this.trace == trace) return self();
return create(trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter,
collectAllCandidates);
collectAllCandidates, callPosition);
}
@NotNull
public Context replaceDataFlowInfo(@NotNull DataFlowInfo newDataFlowInfo) {
if (newDataFlowInfo == dataFlowInfo) return self();
return create(trace, scope, newDataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter,
collectAllCandidates);
collectAllCandidates, callPosition);
}
@NotNull
@@ -114,28 +120,28 @@ public abstract class ResolutionContext<Context extends ResolutionContext<Contex
if (newExpectedType == null) return replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE);
if (expectedType == newExpectedType) return self();
return create(trace, scope, dataFlowInfo, newExpectedType, contextDependency, resolutionResultsCache, statementFilter,
collectAllCandidates);
collectAllCandidates, callPosition);
}
@NotNull
public Context replaceScope(@NotNull LexicalScope newScope) {
if (newScope == scope) return self();
return create(trace, newScope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter,
collectAllCandidates);
collectAllCandidates, callPosition);
}
@NotNull
public Context replaceContextDependency(@NotNull ContextDependency newContextDependency) {
if (newContextDependency == contextDependency) return self();
return create(trace, scope, dataFlowInfo, expectedType, newContextDependency, resolutionResultsCache, statementFilter,
collectAllCandidates);
collectAllCandidates, callPosition);
}
@NotNull
public Context replaceResolutionResultsCache(@NotNull ResolutionResultsCache newResolutionResultsCache) {
if (newResolutionResultsCache == resolutionResultsCache) return self();
return create(trace, scope, dataFlowInfo, expectedType, contextDependency, newResolutionResultsCache, statementFilter,
collectAllCandidates);
collectAllCandidates, callPosition);
}
@NotNull
@@ -146,12 +152,18 @@ public abstract class ResolutionContext<Context extends ResolutionContext<Contex
@NotNull
public Context replaceCollectAllCandidates(boolean newCollectAllCandidates) {
return create(trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter,
newCollectAllCandidates);
newCollectAllCandidates, callPosition);
}
@NotNull
public Context replaceStatementFilter(@NotNull StatementFilter 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 org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.diagnostics.DiagnosticUtilsKt;
import org.jetbrains.kotlin.lexer.KtToken;
import org.jetbrains.kotlin.lexer.KtTokens;
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.DescriptorUtils;
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.ConstraintSystemStatus;
import org.jetbrains.kotlin.resolve.calls.inference.InferenceErrorData;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
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.types.KotlinType;
import org.jetbrains.kotlin.types.Variance;
@@ -80,13 +81,19 @@ public abstract class AbstractTracingStrategy implements TracingStrategy {
}
@Override
public void wrongReceiverType(@NotNull BindingTrace trace, @NotNull ReceiverParameterDescriptor receiverParameter, @NotNull ReceiverValue receiverArgument) {
if (receiverArgument instanceof ExpressionReceiver) {
ExpressionReceiver expressionReceiver = (ExpressionReceiver)receiverArgument;
trace.report(TYPE_MISMATCH.on(expressionReceiver.getExpression(), receiverParameter.getType(), receiverArgument.getType()));
}
else {
trace.report(TYPE_MISMATCH.on(reference, receiverParameter.getType(), receiverArgument.getType()));
public void wrongReceiverType(
@NotNull BindingTrace trace,
@NotNull ReceiverParameterDescriptor receiverParameter,
@NotNull ReceiverValue receiverArgument,
@NotNull ResolutionContext<?> c
) {
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
public void typeInferenceFailed(@NotNull BindingTrace trace, @NotNull InferenceErrorData data) {
public void typeInferenceFailed(@NotNull ResolutionContext<?> context, @NotNull InferenceErrorData data) {
ConstraintSystem constraintSystem = data.constraintSystem;
ConstraintSystemStatus status = constraintSystem.getStatus();
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)
return;
}
BindingTrace trace = context.trace;
if (status.hasOnlyErrorsDerivedFrom(EXPECTED_TYPE_POSITION)) {
KotlinType declaredReturnType = data.descriptor.getReturnType();
if (declaredReturnType == null) return;
@@ -215,7 +223,10 @@ public abstract class AbstractTracingStrategy implements TracingStrategy {
assert substitutedReturnType != null; //todo
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()) {
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 Collection<MutableResolvedCall<F>> resolvedCalls,
boolean isAnnotationContext,
boolean collectAllCandidates
boolean collectAllCandidates,
@NotNull CallPosition callPosition
) {
super(trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments, resolutionResultsCache,
dataFlowInfoForArguments, callChecker, statementFilter, isAnnotationContext, collectAllCandidates);
dataFlowInfoForArguments, callChecker, statementFilter, isAnnotationContext, collectAllCandidates, callPosition);
this.lazyCandidates = lazyCandidates;
this.resolvedCalls = resolvedCalls;
this.tracing = tracing;
@@ -78,7 +79,7 @@ public class ResolutionTask<D extends CallableDescriptor, F extends D> extends C
context.resolutionResultsCache, context.dataFlowInfoForArguments,
context.callChecker,
context.statementFilter, new SmartList<MutableResolvedCall<F>>(),
context.isAnnotationContext, context.collectAllCandidates);
context.isAnnotationContext, context.collectAllCandidates, context.callPosition);
}
@NotNull
@@ -104,14 +105,15 @@ public class ResolutionTask<D extends CallableDescriptor, F extends D> extends C
@NotNull ContextDependency contextDependency,
@NotNull ResolutionResultsCache resolutionResultsCache,
@NotNull StatementFilter statementFilter,
boolean collectAllCandidates
boolean collectAllCandidates,
@NotNull CallPosition callPosition
) {
return new ResolutionTask<D, F>(
lazyCandidates, tracing, trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments,
resolutionResultsCache, dataFlowInfoForArguments,
callChecker,
statementFilter, resolvedCalls,
isAnnotationContext, collectAllCandidates);
isAnnotationContext, collectAllCandidates, callPosition);
}
@Override
@@ -20,6 +20,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.psi.Call;
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.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
@@ -52,7 +53,12 @@ public interface TracingStrategy {
public void missingReceiver(@NotNull BindingTrace trace, @NotNull ReceiverParameterDescriptor expectedReceiver) {}
@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
public void noReceiverAllowed(@NotNull BindingTrace trace) {}
@@ -95,7 +101,7 @@ public interface TracingStrategy {
public void invisibleMember(@NotNull BindingTrace trace, @NotNull DeclarationDescriptorWithVisibility descriptor) {}
@Override
public void typeInferenceFailed(@NotNull BindingTrace trace, @NotNull InferenceErrorData inferenceErrorData) {}
public void typeInferenceFailed(@NotNull ResolutionContext<?> context, @NotNull InferenceErrorData inferenceErrorData) {}
@Override
public void nonExtensionFunctionCalledAsExtension(@NotNull BindingTrace trace) { }
@@ -115,7 +121,12 @@ public interface TracingStrategy {
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);
@@ -146,7 +157,7 @@ public interface TracingStrategy {
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);
}
@@ -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.RESOLVED_CALL
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.model.ResolvedCall
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
@@ -117,7 +118,7 @@ class TracingStrategyForImplicitConstructorDelegationCall(
unexpectedError("missingReceiver")
}
override fun wrongReceiverType(trace: BindingTrace, receiverParameter: ReceiverParameterDescriptor, receiverArgument: ReceiverValue) {
override fun wrongReceiverType(trace: BindingTrace, receiverParameter: ReceiverParameterDescriptor, receiverArgument: ReceiverValue, c: ResolutionContext<*>) {
unexpectedError("wrongReceiverType")
}
@@ -129,7 +130,7 @@ class TracingStrategyForImplicitConstructorDelegationCall(
unexpectedError("wrongNumberOfTypeArguments")
}
override fun typeInferenceFailed(trace: BindingTrace, data: InferenceErrorData) {
override fun typeInferenceFailed(context: ResolutionContext<*>, data: InferenceErrorData) {
unexpectedError("typeInferenceFailed")
}
@@ -24,12 +24,15 @@ import org.jetbrains.kotlin.KtNodeTypes;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.diagnostics.Diagnostic;
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory;
import org.jetbrains.kotlin.diagnostics.DiagnosticUtilsKt;
import org.jetbrains.kotlin.psi.KtConstantExpression;
import org.jetbrains.kotlin.psi.KtElement;
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.TypeUtils;
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext;
import java.util.Set;
@@ -42,15 +45,17 @@ public class CompileTimeConstantChecker {
private final KotlinBuiltIns builtIns;
private final BindingTrace trace;
private final boolean checkOnlyErrorsThatDependOnExpectedType;
private final ResolutionContext<?> context;
public CompileTimeConstantChecker(
@NotNull BindingTrace trace,
@NotNull ResolutionContext<?> context,
@NotNull KotlinBuiltIns builtIns,
boolean checkOnlyErrorsThatDependOnExpectedType
) {
this.checkOnlyErrorsThatDependOnExpectedType = checkOnlyErrorsThatDependOnExpectedType;
this.builtIns = builtIns;
this.trace = trace;
this.trace = context.trace;
this.context = context;
}
// return true if there is an error
@@ -95,7 +100,7 @@ public class CompileTimeConstantChecker {
if (!noExpectedTypeOrError(expectedType)) {
KotlinType valueType = value.getType();
if (!KotlinTypeChecker.DEFAULT.isSubtypeOf(valueType, expectedType)) {
return reportError(CONSTANT_EXPECTED_TYPE_MISMATCH.on(expression, "integer", expectedType));
return reportConstantExpectedTypeMismatch(expression, "integer", expectedType, null);
}
}
return false;
@@ -112,7 +117,7 @@ public class CompileTimeConstantChecker {
if (!noExpectedTypeOrError(expectedType)) {
KotlinType valueType = value.getType();
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;
@@ -124,7 +129,7 @@ public class CompileTimeConstantChecker {
) {
if (!noExpectedTypeOrError(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;
}
@@ -132,7 +137,7 @@ public class CompileTimeConstantChecker {
private boolean checkCharValue(ConstantValue<?> constant, KotlinType expectedType, KtConstantExpression expression) {
if (!noExpectedTypeOrError(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) {
@@ -148,6 +153,9 @@ public class CompileTimeConstantChecker {
private boolean checkNullValue(@NotNull KotlinType expectedType, @NotNull KtConstantExpression expression) {
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 false;
@@ -269,10 +277,22 @@ public class CompileTimeConstantChecker {
return null;
}
public static boolean noExpectedTypeOrError(KotlinType expectedType) {
private static boolean noExpectedTypeOrError(KotlinType expectedType) {
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) {
if (!checkOnlyErrorsThatDependOnExpectedType || errorsThatDependOnExpectedType.contains(diagnostic.getFactory())) {
trace.report(diagnostic);
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.types.expressions;
import com.google.common.collect.Lists;
import com.intellij.openapi.util.Ref;
import com.intellij.psi.PsiElement;
import com.intellij.psi.tree.IElementType;
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.annotations.Annotations;
import org.jetbrains.kotlin.diagnostics.Diagnostic;
import org.jetbrains.kotlin.diagnostics.DiagnosticUtilsKt;
import org.jetbrains.kotlin.diagnostics.Errors;
import org.jetbrains.kotlin.lexer.KtKeywordToken;
import org.jetbrains.kotlin.lexer.KtTokens;
@@ -196,7 +198,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
);
if (!(compileTimeConstant instanceof IntegerValueTypeConstant)) {
CompileTimeConstantChecker constantChecker = new CompileTimeConstantChecker(context.trace, components.builtIns, false);
CompileTimeConstantChecker constantChecker = new CompileTimeConstantChecker(context, components.builtIns, false);
ConstantValue constantValue =
compileTimeConstant != null ? ((TypedCompileTimeConstant) compileTimeConstant).getConstantValue() : null;
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.BindingTrace;
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.ConstraintSystemStatus;
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintsUtil;
@@ -386,7 +387,7 @@ public class ControlStructureTypingUtils {
@Override
public void typeInferenceFailed(
@NotNull BindingTrace trace, @NotNull InferenceErrorData data
@NotNull ResolutionContext<?> context, @NotNull InferenceErrorData data
) {
ConstraintSystem constraintSystem = data.constraintSystem;
ConstraintSystemStatus status = constraintSystem.getStatus();
@@ -398,7 +399,7 @@ public class ControlStructureTypingUtils {
KtExpression expression = (KtExpression) call.getCallElement();
if (status.hasOnlyErrorsDerivedFrom(EXPECTED_TYPE_POSITION) || status.hasConflictingConstraints()
|| 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;
}
KtDeclaration parentDeclaration = PsiTreeUtil.getParentOfType(expression, KtNamedDeclaration.class);
@@ -455,7 +456,10 @@ public class ControlStructureTypingUtils {
@Override
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();
}
@@ -532,7 +536,7 @@ public class ControlStructureTypingUtils {
@Override
public void typeInferenceFailed(
@NotNull BindingTrace trace, @NotNull InferenceErrorData inferenceErrorData
@NotNull ResolutionContext<?> context, @NotNull InferenceErrorData inferenceErrorData
) {
logError();
}
@@ -22,6 +22,7 @@ import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.diagnostics.DiagnosticUtilsKt;
import org.jetbrains.kotlin.lexer.KtTokens;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.BindingContext;
@@ -196,7 +197,7 @@ public class DataFlowAnalyzer {
if (expression instanceof KtConstantExpression) {
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);
hasError.set(error);
return expressionType;
@@ -210,7 +211,9 @@ public class DataFlowAnalyzer {
SmartCastResult castResult = checkPossibleCast(expressionType, expression, c);
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);
return expressionType;
}
@@ -20,10 +20,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.resolve.BindingTrace;
import org.jetbrains.kotlin.resolve.StatementFilter;
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker;
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency;
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.context.*;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
import org.jetbrains.kotlin.resolve.scopes.LexicalScope;
import org.jetbrains.kotlin.types.KotlinType;
@@ -61,8 +58,8 @@ public class ExpressionTypingContext extends ResolutionContext<ExpressionTypingC
context.contextDependency, context.resolutionResultsCache,
context.callChecker,
context.statementFilter,
context.isAnnotationContext, context.collectAllCandidates
);
context.isAnnotationContext, context.collectAllCandidates,
context.callPosition);
}
@NotNull
@@ -79,7 +76,7 @@ public class ExpressionTypingContext extends ResolutionContext<ExpressionTypingC
) {
return new ExpressionTypingContext(
trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, callChecker,
statementFilter, isAnnotationContext, false);
statementFilter, isAnnotationContext, false, CallPosition.Unknown.INSTANCE);
}
private ExpressionTypingContext(
@@ -92,11 +89,12 @@ public class ExpressionTypingContext extends ResolutionContext<ExpressionTypingC
@NotNull CallChecker callChecker,
@NotNull StatementFilter statementFilter,
boolean isAnnotationContext,
boolean collectAllCandidates
boolean collectAllCandidates,
@NotNull CallPosition callPosition
) {
super(trace, scope, expectedType, dataFlowInfo, contextDependency, resolutionResultsCache,
callChecker,
statementFilter, isAnnotationContext, collectAllCandidates);
statementFilter, isAnnotationContext, collectAllCandidates, callPosition);
}
@Override
@@ -108,11 +106,12 @@ public class ExpressionTypingContext extends ResolutionContext<ExpressionTypingC
@NotNull ContextDependency contextDependency,
@NotNull ResolutionResultsCache resolutionResultsCache,
@NotNull StatementFilter statementFilter,
boolean collectAllCandidates
boolean collectAllCandidates,
@NotNull CallPosition callPosition
) {
return new ExpressionTypingContext(trace, scope, dataFlowInfo,
expectedType, contextDependency, resolutionResultsCache,
callChecker,
statementFilter, isAnnotationContext, collectAllCandidates);
statementFilter, isAnnotationContext, collectAllCandidates, callPosition);
}
}
@@ -124,8 +124,7 @@ public class ExpressionTypingUtils {
@Override
public void report(@NotNull Diagnostic diagnostic) {
DiagnosticFactory<?> factory = diagnostic.getFactory();
if ((factory == TYPE_MISMATCH || factory == CONSTANT_EXPECTED_TYPE_MISMATCH || factory == NULL_FOR_NONNULL_TYPE)
&& diagnostic.getPsiElement() == expressionToWatch) {
if (Errors.TYPE_MISMATCH_ERRORS.contains(factory) && diagnostic.getPsiElement() == expressionToWatch) {
mismatchFound[0] = true;
}
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.resolve.*;
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.LexicalWritableScope;
import org.jetbrains.kotlin.types.DeferredType;
@@ -230,7 +231,8 @@ public abstract class ExpressionTypingVisitorDispatcher extends KtVisitor<Kotlin
@Override
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
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.BindingContextUtils;
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.model.ResolvedCall;
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);
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);
}
temporary.commit();
@@ -317,7 +318,9 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
DataFlowInfo dataFlowInfo = leftInfo.getDataFlowInfo();
KotlinTypeInfo resultInfo;
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();
KotlinType rightType = resultInfo.getType();
@@ -2,5 +2,5 @@
fun foo() {
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)
(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<*>).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<*>).<!MEMBER_PROJECTED_OUT!>f<!>(1) // !!
Inv<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<*>).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<*>).<!MEMBER_PROJECTED_OUT!>inf<!>(1) // !!
Inv<Int>().outf()
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.Inner())
outer.set(<!TYPE_MISMATCH(kotlin.Nothing; Outer<out kotlin.String>.Inner)!>outer.bar()<!>)
outer.set(<!TYPE_MISMATCH(kotlin.Nothing; Outer<out kotlin.String>.Inner)!>outer.Inner()<!>)
outer.<!MEMBER_PROJECTED_OUT!>set<!>(outer.bar())
outer.<!MEMBER_PROJECTED_OUT!>set<!>(outer.Inner())
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> {
fun addAll(x: C<T>): Boolean
fun addAllMC(x: MC<out T>): Boolean
fun addAllInv(x: MC<T>): Boolean
}
interface Open
@@ -13,15 +14,18 @@ fun <T> mc(): MC<T> = null!!
fun <T> c(): C<T> = null!!
fun foo(x: MC<out Open>) {
x.addAll(<!TYPE_MISMATCH(C<kotlin.Nothing>; MC<out Open>)!>x<!>)
x.addAllMC(<!TYPE_MISMATCH(MC<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_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.addAllMC(<!TYPE_MISMATCH(MC<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_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.addAllMC(<!TYPE_MISMATCH(MC<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_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<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 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 open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
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<*>) {
t.v = <!TYPE_MISMATCH!>t<!>
<!SETTER_PROJECTED_OUT!>t.v<!> = t
t.v checkType { _<Tr<*>>() }
}
@@ -7,7 +7,7 @@ interface Tr<T> {
fun test(t: Tr<*>) {
t.v = null!!
t.v = <!TYPE_MISMATCH!>""<!>
t.v = <!NULL_FOR_NONNULL_TYPE!>null<!>
<!SETTER_PROJECTED_OUT!>t.v<!> = ""
<!SETTER_PROJECTED_OUT!>t.v<!> = null
t.v checkType { _<Any?>() }
}
@@ -6,5 +6,5 @@ interface Tr<T> {
fun test(t: Tr<out 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)
<!TYPE_MISMATCH!>t.v += null!!<!>
<!SETTER_PROJECTED_OUT!>t.v<!> += null!!
}
@@ -1,12 +1,12 @@
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(<!TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH!>listOf("")<!>)
mc.addAll(<!TYPE_MISMATCH!>listOf<String>("")<!>)
mc.addAll(<!TYPE_MISMATCH!>listOf<CharSequence>("")<!>)
mc.addAll(<!TYPE_MISMATCH_DUE_TO_TYPE_PROJECTIONS!>listOf("")<!>)
mc.addAll(<!TYPE_MISMATCH_DUE_TO_TYPE_PROJECTIONS!>listOf<String>("")<!>)
mc.addAll(<!TYPE_MISMATCH_DUE_TO_TYPE_PROJECTIONS!>listOf<CharSequence>("")<!>)
mc.addAll(emptyList())
mc.addAll(emptyList<Nothing>())
@@ -7190,6 +7190,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
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")
public void testExtensionResultSubstitution() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/extensionResultSubstitution.kt");
@@ -7202,6 +7208,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
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")
public void testKt7296() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/kt7296.kt");
@@ -7220,18 +7232,36 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
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")
public void testMLOut() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/MLOut.kt");
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")
public void testPlatformSuperClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/platformSuperClass.kt");
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")
public void testRecursiveUpperBoundStar() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/projectionsScope/recursiveUpperBoundStar.kt");
@@ -7262,6 +7292,18 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
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")
public void testTypeParameterBounds() throws Exception {
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");
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")
@@ -98,17 +98,17 @@ fun createCapturedType(typeProjection: TypeProjection): KotlinType
fun KotlinType.isCaptured(): Boolean = constructor is CapturedTypeConstructor
fun TypeSubstitution.wrapWithCapturingSubstitution(): TypeSubstitution =
fun TypeSubstitution.wrapWithCapturingSubstitution(needApproximation: Boolean = true): TypeSubstitution =
if (this is IndexedParametersSubstitution)
IndexedParametersSubstitution(
this.parameters,
this.arguments.zip(this.parameters).map {
it.first.createCapturedIfNeeded(it.second)
}.toTypedArray(),
approximateCapturedTypes = true)
approximateCapturedTypes = needApproximation)
else
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)
}
@@ -23,7 +23,8 @@ import org.jetbrains.kotlin.resolve.calls.inference.isCaptured
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.types.*
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.*
data class ApproximationBounds<T>(
@@ -20,12 +20,14 @@ import com.intellij.icons.AllIcons;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.TestOnly;
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.DiagnosticFactoryToRendererMap;
import org.jetbrains.kotlin.diagnostics.rendering.DiagnosticRenderer;
import org.jetbrains.kotlin.js.resolve.diagnostics.ErrorsJs;
import org.jetbrains.kotlin.js.resolve.diagnostics.JsCallDataHtmlRenderer;
import org.jetbrains.kotlin.renderer.DescriptorRenderer;
import org.jetbrains.kotlin.renderer.MultiRenderer;
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>",
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>",
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);
}
@TestMetadata("expectedNothingDueToProjections.kt")
public void testExpectedNothingDueToProjections() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/diagnosticMessage/expectedNothingDueToProjections.kt");
doTest(fileName);
}
@TestMetadata("extensionInClassReference.kt")
public void testExtensionInClassReference() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/diagnosticMessage/extensionInClassReference.kt");
@@ -179,6 +185,24 @@ public class DiagnosticMessageTestGenerated extends AbstractDiagnosticMessageTes
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")
public void testTypeMismatchWithNothing() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/diagnosticMessage/typeMismatchWithNothing.kt");