diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt index a6408595e3c..f5a3cb87b99 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt @@ -38,6 +38,9 @@ object DIAGNOSTICS_LIST : DiagnosticList() { val UNSUPPORTED_FEATURE by error { parameter>("unsupportedFeature") } + val NEW_INFERENCE_ERROR by error { + parameter("error") + } } val Miscellaneous by object : DiagnosticGroup("Miscellaneous") { diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index e69d13092e6..d75ff3eef86 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -74,6 +74,7 @@ object FirErrors { // Meta-errors val UNSUPPORTED by error1() val UNSUPPORTED_FEATURE by error1>() + val NEW_INFERENCE_ERROR by error1() // Miscellaneous val SYNTAX by error0() diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt index 49deb83fba1..2dbd5452ec2 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt @@ -15,10 +15,17 @@ import org.jetbrains.kotlin.fir.declarations.isOperator import org.jetbrains.kotlin.fir.diagnostics.* import org.jetbrains.kotlin.fir.resolve.calls.* import org.jetbrains.kotlin.fir.resolve.diagnostics.* +import org.jetbrains.kotlin.fir.resolve.inference.model.ConeArgumentConstraintPosition +import org.jetbrains.kotlin.fir.resolve.inference.model.ConeExplicitTypeParameterConstraintPosition +import org.jetbrains.kotlin.fir.resolve.inference.model.ConeLambdaArgumentConstraintPosition import org.jetbrains.kotlin.fir.symbols.impl.FirBackingFieldSymbol +import org.jetbrains.kotlin.fir.typeContext +import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.resolve.calls.inference.model.* import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability import org.jetbrains.kotlin.resolve.calls.tower.isSuccess +import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance import org.jetbrains.kotlin.utils.addToStdlib.safeAs @@ -70,10 +77,11 @@ fun ConeDiagnostic.toFirDiagnostics( source: FirSourceElement, qualifiedAccessSource: FirSourceElement? ): List> { - if (this is ConeInapplicableCandidateError) { - return mapInapplicableCandidateError(this, source, qualifiedAccessSource) + return when (this) { + is ConeInapplicableCandidateError -> mapInapplicableCandidateError(this, source, qualifiedAccessSource) + is ConeConstraintSystemHasContradiction -> mapSystemHasContradictionError(this, source, qualifiedAccessSource) + else -> listOfNotNull(toFirDiagnostic(source, qualifiedAccessSource)) } - return listOfNotNull(toFirDiagnostic(source, qualifiedAccessSource)) } private fun mapUnsafeCallError( @@ -150,6 +158,76 @@ private fun mapInapplicableCandidateError( }.ifEmpty { listOf(FirErrors.INAPPLICABLE_CANDIDATE.on(source, diagnostic.candidate.symbol)) } } +@OptIn(ExperimentalStdlibApi::class) +private fun mapSystemHasContradictionError( + diagnostic: ConeConstraintSystemHasContradiction, + source: FirSourceElement, + qualifiedAccessSource: FirSourceElement?, +): List> = buildList> { + for (error in diagnostic.candidate.system.errors) { + addIfNotNull(error.toDiagnostic(source, qualifiedAccessSource, diagnostic.candidate.callInfo.session.typeContext)) + } +}.ifEmpty { + listOfNotNull( + diagnostic.candidate.system.errors.firstNotNullOfOrNull { + val message = when (it) { + is NewConstraintError -> "NewConstraintError at ${it.position}: ${it.lowerType} return@firstNotNullOfOrNull null + else -> "Inference error: ${it::class.simpleName}" + } + FirErrors.NEW_INFERENCE_ERROR.on(qualifiedAccessSource ?: source, message) + } + ) +} + +private fun ConstraintSystemError.toDiagnostic( + source: FirSourceElement, + qualifiedAccessSource: FirSourceElement?, + typeContext: ConeTypeContext, +): FirDiagnostic? = when (this) { + is NewConstraintError -> { + val position = position.from + val argument = + when (position) { + // TODO: Support other ReceiverConstraintPositionImpl, LHSArgumentConstraintPositionImpl + is ConeArgumentConstraintPosition -> position.argument + is ConeLambdaArgumentConstraintPosition -> position.lambda + else -> null + } + + argument?.let { + return FirErrors.TYPE_MISMATCH.on(it.source ?: source, lowerConeType, upperConeType) + } + + when (position) { + is ExpectedTypeConstraintPosition<*> -> { + val inferredType = + if (!lowerConeType.isNullableNothing) + lowerConeType + else + upperConeType.withNullability(ConeNullability.NULLABLE, typeContext) + + FirErrors.TYPE_MISMATCH.on(qualifiedAccessSource ?: source, upperConeType, inferredType) + } + is ExplicitTypeParameterConstraintPosition<*> -> { + val conePosition = position as ConeExplicitTypeParameterConstraintPosition + val typeArgument = conePosition.typeArgument + + FirErrors.UPPER_BOUND_VIOLATED.on( + typeArgument.source ?: qualifiedAccessSource ?: source, + upperConeType, + ) + } + else -> null + } + } + else -> null +} + +private val NewConstraintError.lowerConeType: ConeKotlinType get() = lowerType as ConeKotlinType +private val NewConstraintError.upperConeType: ConeKotlinType get() = upperType as ConeKotlinType + private fun ConeSimpleDiagnostic.getFactory(source: FirSourceElement): FirDiagnosticFactory0<*> { @Suppress("UNCHECKED_CAST") return when (kind) { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CreateFreshTypeVariableSubstitutorStage.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CreateFreshTypeVariableSubstitutorStage.kt index e9996777ab7..0573339bfd3 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CreateFreshTypeVariableSubstitutorStage.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CreateFreshTypeVariableSubstitutorStage.kt @@ -13,13 +13,14 @@ import org.jetbrains.kotlin.fir.resolve.fullyExpandedType import org.jetbrains.kotlin.fir.resolve.inference.ConeTypeParameterBasedTypeVariable import org.jetbrains.kotlin.fir.resolve.inference.inferenceComponents import org.jetbrains.kotlin.fir.resolve.inference.model.ConeDeclaredUpperBoundConstraintPosition +import org.jetbrains.kotlin.fir.resolve.inference.model.ConeExplicitTypeParameterConstraintPosition import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag import org.jetbrains.kotlin.fir.typeContext -import org.jetbrains.kotlin.name.StandardClassIds import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.impl.FirTypePlaceholderProjection +import org.jetbrains.kotlin.name.StandardClassIds import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemOperation import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition @@ -71,7 +72,7 @@ internal object CreateFreshTypeVariableSubstitutorStage : ResolutionStage() { typeParameter, context.session ).fullyExpandedType(context.session), - SimpleConstraintSystemConstraintPosition // TODO + ConeExplicitTypeParameterConstraintPosition(typeArgument) ) is FirStarProjection -> csBuilder.addEqualityConstraint( freshVariable.defaultType, diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/diagnostics/FirDiagnostics.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/diagnostics/FirDiagnostics.kt index e8a6e316b46..ddfc54164c4 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/diagnostics/FirDiagnostics.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/diagnostics/FirDiagnostics.kt @@ -50,6 +50,12 @@ class ConeInapplicableCandidateError( override val reason: String get() = "Inapplicable($applicability): ${describeSymbol(candidate.symbol)}" } +class ConeConstraintSystemHasContradiction( + val candidate: Candidate, +) : ConeDiagnostic() { + override val reason: String get() = "CS errors: ${describeSymbol(candidate.symbol)}" +} + class ConeArgumentTypeMismatchCandidateError( val expectedType: ConeKotlinType, val actualType: ConeKotlinType ) : ConeDiagnostic() { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedAtoms.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedAtoms.kt index bd42884e594..88661f56495 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedAtoms.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedAtoms.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.fir.resolve.inference +import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess @@ -12,10 +13,10 @@ import org.jetbrains.kotlin.fir.expressions.FirStatement import org.jetbrains.kotlin.fir.references.FirNamedReference import org.jetbrains.kotlin.fir.resolve.DoubleColonLHS import org.jetbrains.kotlin.fir.resolve.calls.Candidate -import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl -import org.jetbrains.kotlin.fir.types.* -import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl -import org.jetbrains.kotlin.name.StandardClassIds +import org.jetbrains.kotlin.fir.types.ConeKotlinType +import org.jetbrains.kotlin.fir.types.ConeTypeVariable +import org.jetbrains.kotlin.fir.types.ConeTypeVariableType +import org.jetbrains.kotlin.fir.types.FirTypeRef import org.jetbrains.kotlin.resolve.calls.model.LambdaWithTypeVariableAsExpectedTypeMarker import org.jetbrains.kotlin.resolve.calls.model.PostponedCallableReferenceMarker import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtomMarker @@ -29,6 +30,7 @@ class ConeTypeVariableForPostponedAtom(name: String) : ConeTypeVariable(name) // -------------------------- Atoms -------------------------- sealed class PostponedResolvedAtom : PostponedResolvedAtomMarker { + abstract val atom: FirElement abstract override val inputTypes: Collection abstract override val outputType: ConeKotlinType? override var analyzed: Boolean = false @@ -38,7 +40,7 @@ sealed class PostponedResolvedAtom : PostponedResolvedAtomMarker { // ------------- Lambdas ------------- class ResolvedLambdaAtom( - val atom: FirAnonymousFunction, + override val atom: FirAnonymousFunction, expectedType: ConeKotlinType?, val isSuspend: Boolean, val receiver: ConeKotlinType?, @@ -75,7 +77,7 @@ class ResolvedLambdaAtom( } class LambdaWithTypeVariableAsExpectedTypeAtom( - val atom: FirAnonymousFunction, + override val atom: FirAnonymousFunction, private val initialExpectedTypeType: ConeKotlinType, val expectedTypeRef: FirTypeRef, val candidateOfOuterCall: Candidate, @@ -116,6 +118,9 @@ class ResolvedCallableReferenceAtom( private val session: FirSession ) : PostponedResolvedAtom(), PostponedCallableReferenceMarker { + override val atom: FirCallableReferenceAccess + get() = reference + var hasBeenResolvedOnce: Boolean = false var hasBeenPostponed: Boolean = false diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/model/FirConstraintPositionAndErrors.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/model/FirConstraintPositionAndErrors.kt index b47668ca492..022caad3002 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/model/FirConstraintPositionAndErrors.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/model/FirConstraintPositionAndErrors.kt @@ -5,13 +5,24 @@ package org.jetbrains.kotlin.fir.resolve.inference.model -import org.jetbrains.kotlin.resolve.calls.inference.model.ArgumentConstraintPosition -import org.jetbrains.kotlin.resolve.calls.inference.model.DeclaredUpperBoundConstraintPosition -import org.jetbrains.kotlin.resolve.calls.inference.model.FixVariableConstraintPosition +import org.jetbrains.kotlin.fir.FirElement +import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction +import org.jetbrains.kotlin.fir.types.FirTypeProjection +import org.jetbrains.kotlin.resolve.calls.inference.model.* import org.jetbrains.kotlin.types.model.TypeVariableMarker class ConeDeclaredUpperBoundConstraintPosition : DeclaredUpperBoundConstraintPosition(null) class ConeFixVariableConstraintPosition(variable: TypeVariableMarker) : FixVariableConstraintPosition(variable, null) -class ConeArgumentConstraintPosition : ArgumentConstraintPosition(null) \ No newline at end of file +class ConeArgumentConstraintPosition(argument: FirElement) : ArgumentConstraintPosition(argument) + +class ConeExpectedTypeConstraintPosition : ExpectedTypeConstraintPosition(null) + +class ConeExplicitTypeParameterConstraintPosition( + typeArgument: FirTypeProjection, +) : ExplicitTypeParameterConstraintPosition(typeArgument) + +class ConeLambdaArgumentConstraintPosition( + anonymousFunction: FirAnonymousFunction +) : LambdaArgumentConstraintPosition(anonymousFunction) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt index 6d2c6f5e171..6fbe8a68c85 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt @@ -18,6 +18,7 @@ import org.jetbrains.kotlin.fir.references.builder.buildResolvedNamedReference import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.resolve.calls.* import org.jetbrains.kotlin.fir.resolve.dfa.FirDataFlowAnalyzer +import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeConstraintSystemHasContradiction import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeInapplicableCandidateError import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeTypeParameterInQualifiedAccess import org.jetbrains.kotlin.fir.resolve.inference.* @@ -37,6 +38,7 @@ import org.jetbrains.kotlin.fir.types.builder.buildStarProjection import org.jetbrains.kotlin.fir.types.builder.buildTypeProjectionWithVariance import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl import org.jetbrains.kotlin.fir.visitors.* +import org.jetbrains.kotlin.resolve.calls.tower.isSuccess import org.jetbrains.kotlin.types.TypeApproximatorConfiguration import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.utils.addToStdlib.runIf @@ -739,7 +741,14 @@ class FirCallCompletionResultsWriterTransformer( private fun FirNamedReferenceWithCandidate.toResolvedReference(): FirNamedReference { val errorDiagnostic = when { this is FirErrorReferenceWithCandidate -> this.diagnostic - !candidate.isSuccessful -> ConeInapplicableCandidateError(candidate.currentApplicability, candidate) + !candidate.currentApplicability.isSuccess -> ConeInapplicableCandidateError(candidate.currentApplicability, candidate) + !candidate.isSuccessful -> { + require(candidate.system.hasContradiction) { + "Candidate is not successful, but system has no contradiction" + } + + ConeConstraintSystemHasContradiction(candidate) + } else -> null } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt index aeea10bd856..d1ee8ec655b 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -71,6 +71,13 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.NEW_INFERENCE_ERROR) { firDiagnostic -> + NewInferenceErrorImpl( + firDiagnostic.a, + firDiagnostic as FirPsiDiagnostic<*>, + token, + ) + } add(FirErrors.SYNTAX) { firDiagnostic -> SyntaxImpl( firDiagnostic as FirPsiDiagnostic<*>, diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt index 56423332606..d42f2d0c38c 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt @@ -74,6 +74,11 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { abstract val unsupportedFeature: Pair } + abstract class NewInferenceError : KtFirDiagnostic() { + override val diagnosticClass get() = NewInferenceError::class + abstract val error: String + } + abstract class Syntax : KtFirDiagnostic() { override val diagnosticClass get() = Syntax::class } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index a8234f3474a..22335abc2d9 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -81,6 +81,14 @@ internal class UnsupportedFeatureImpl( override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) } +internal class NewInferenceErrorImpl( + override val error: String, + firDiagnostic: FirPsiDiagnostic<*>, + override val token: ValidityToken, +) : KtFirDiagnostic.NewInferenceError(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) +} + internal class SyntaxImpl( firDiagnostic: FirPsiDiagnostic<*>, override val token: ValidityToken,