[NI] Refactor adding expected type constraint

Add comments, make computation needed for expected type more clear
This commit is contained in:
Mikhail Zarechenskiy
2019-02-21 01:32:52 +03:00
parent 43cf6623f9
commit 92b40ea9d5
@@ -28,18 +28,22 @@ class KotlinCallCompleter(
resolutionCallbacks: KotlinResolutionCallbacks resolutionCallbacks: KotlinResolutionCallbacks
): CallResolutionResult { ): CallResolutionResult {
val diagnosticHolder = KotlinDiagnosticsHolder.SimpleHolder() val diagnosticHolder = KotlinDiagnosticsHolder.SimpleHolder()
if (candidates.isEmpty()) { when {
diagnosticHolder.addDiagnostic(NoneCandidatesCallDiagnostic(factory.kotlinCall)) candidates.isEmpty() -> diagnosticHolder.addDiagnostic(NoneCandidatesCallDiagnostic(factory.kotlinCall))
} candidates.size > 1 -> diagnosticHolder.addDiagnostic(ManyCandidatesCallDiagnostic(factory.kotlinCall, candidates))
if (candidates.size > 1) {
diagnosticHolder.addDiagnostic(ManyCandidatesCallDiagnostic(factory.kotlinCall, candidates))
} }
val candidate = prepareCandidateForCompletion(factory, candidates, resolutionCallbacks) val candidate = prepareCandidateForCompletion(factory, candidates, resolutionCallbacks)
val completionType = candidate.prepareForCompletion(expectedType, resolutionCallbacks) val returnType = candidate.returnTypeWithSmartCastInfo(resolutionCallbacks)
candidate.addExpectedTypeConstraint(returnType, expectedType, resolutionCallbacks)
return if (resolutionCallbacks.inferenceSession.shouldRunCompletion(candidate)) return if (resolutionCallbacks.inferenceSession.shouldRunCompletion(candidate))
candidate.runCompletion(completionType, diagnosticHolder, resolutionCallbacks) candidate.runCompletion(
candidate.computeCompletionMode(expectedType, returnType),
diagnosticHolder,
resolutionCallbacks
)
else else
candidate.asCallResolutionResult(ConstraintSystemCompletionMode.PARTIAL, diagnosticHolder) candidate.asCallResolutionResult(ConstraintSystemCompletionMode.PARTIAL, diagnosticHolder)
} }
@@ -51,7 +55,10 @@ class KotlinCallCompleter(
): CallResolutionResult { ): CallResolutionResult {
val diagnosticsHolder = KotlinDiagnosticsHolder.SimpleHolder() val diagnosticsHolder = KotlinDiagnosticsHolder.SimpleHolder()
for (candidate in candidates) { for (candidate in candidates) {
candidate.prepareForCompletion(expectedType, resolutionCallbacks) candidate.addExpectedTypeConstraint(
candidate.returnTypeWithSmartCastInfo(resolutionCallbacks), expectedType, resolutionCallbacks
)
runCompletion( runCompletion(
candidate.resolvedCall, candidate.resolvedCall,
ConstraintSystemCompletionMode.FULL, ConstraintSystemCompletionMode.FULL,
@@ -122,27 +129,40 @@ class KotlinCallCompleter(
return candidate ?: factory.createErrorCandidate().forceResolution() return candidate ?: factory.createErrorCandidate().forceResolution()
} }
// true if we should complete this call private fun KotlinResolutionCandidate.returnTypeWithSmartCastInfo(resolutionCallbacks: KotlinResolutionCallbacks): UnwrappedType? {
private fun KotlinResolutionCandidate.prepareForCompletion( val returnType = resolvedCall.candidateDescriptor.returnType?.unwrap() ?: return null
val returnTypeWithSmartCastInfo = computeReturnTypeWithSmartCastInfo(returnType, resolutionCallbacks)
return resolvedCall.substitutor.substituteKeepAnnotations(returnTypeWithSmartCastInfo)
}
private fun KotlinResolutionCandidate.addExpectedTypeConstraint(
returnType: UnwrappedType?,
expectedType: UnwrappedType?, expectedType: UnwrappedType?,
resolutionCallbacks: KotlinResolutionCallbacks resolutionCallbacks: KotlinResolutionCallbacks
): ConstraintSystemCompletionMode { ) {
if (expectedType != null && TypeUtils.noExpectedType(expectedType)) return ConstraintSystemCompletionMode.FULL if (returnType == null) return
if (expectedType == null || TypeUtils.noExpectedType(expectedType)) return
val returnType = resolvedCall.candidateDescriptor.returnType?.unwrap() ?: return ConstraintSystemCompletionMode.PARTIAL // We don't add expected type constraint for constant expression like "1 + 1" because of type coercion for numbers:
val substitutedType: UnwrappedType // val a: Long = 1 + 1, note that result type of "1 + 1" will be Int and adding constraint with Long will produce type mismatch
if (expectedType != null) { if (!resolutionCallbacks.isCompileTimeConstant(resolvedCall, expectedType)) {
val returnTypeWithSmartCastInfo = computeReturnTypeWithSmartCastInfo(returnType, resolutionCallbacks) csBuilder.addSubtypeConstraint(returnType, expectedType, ExpectedTypeConstraintPosition(resolvedCall.atom))
substitutedType = resolvedCall.substitutor.substituteKeepAnnotations(returnTypeWithSmartCastInfo)
if (!resolutionCallbacks.isCompileTimeConstant(resolvedCall, expectedType)) {
csBuilder.addSubtypeConstraint(substitutedType, expectedType, ExpectedTypeConstraintPosition(resolvedCall.atom))
}
} else {
substitutedType = resolvedCall.substitutor.substituteKeepAnnotations(returnType)
} }
}
return if (expectedType != null || csBuilder.isProperType(substitutedType)) private fun KotlinResolutionCandidate.computeCompletionMode(
expectedType: UnwrappedType?,
currentReturnType: UnwrappedType?
): ConstraintSystemCompletionMode {
// Presence of expected type means that we trying to complete outermost call => completion mode should be full
if (expectedType != null) return ConstraintSystemCompletionMode.FULL
// This is questionable as null return type can be only for error call
if (currentReturnType == null) return ConstraintSystemCompletionMode.PARTIAL
// Consider call foo(bar(x)), if return type of bar is a proper one, then we can complete resolve for bar => full completion mode
// Otherwise, we shouldn't complete bar until we process call foo
return if (csBuilder.isProperType(currentReturnType))
ConstraintSystemCompletionMode.FULL ConstraintSystemCompletionMode.FULL
else else
ConstraintSystemCompletionMode.PARTIAL ConstraintSystemCompletionMode.PARTIAL