Use upper bound checker for typealias expansion
This commit is contained in:
+33
-24
@@ -7,40 +7,49 @@ package org.jetbrains.kotlin.resolve.jvm.checkers
|
||||
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtTypeReference
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.UpperBoundChecker
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
|
||||
import org.jetbrains.kotlin.resolve.UpperBoundViolatedReporter
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm.UPPER_BOUND_VIOLATED_BASED_ON_JAVA_ANNOTATIONS
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm.UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION_BASED_ON_JAVA_ANNOTATIONS
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||
|
||||
class EnhancedUpperBoundChecker(override val languageVersionSettings: LanguageVersionSettings) : UpperBoundChecker {
|
||||
override fun checkBound(
|
||||
bound: KotlinType,
|
||||
// TODO: remove this checker after removing support LV < 1.6
|
||||
class EnhancedUpperBoundChecker(languageVersionSettings: LanguageVersionSettings) : UpperBoundChecker(languageVersionSettings) {
|
||||
val isTypeEnhancementImprovementsEnabled = languageVersionSettings.supportsFeature(LanguageFeature.ImprovementsAroundTypeEnhancement)
|
||||
|
||||
override fun checkBounds(
|
||||
argumentReference: KtTypeReference?,
|
||||
argumentType: KotlinType,
|
||||
typeParameterDescriptor: TypeParameterDescriptor,
|
||||
substitutor: TypeSubstitutor,
|
||||
trace: BindingTrace,
|
||||
jetTypeArgument: KtTypeReference,
|
||||
typeArgument: KotlinType
|
||||
): Boolean {
|
||||
val isCheckPassed = super.checkBound(bound, substitutor, trace, jetTypeArgument, typeArgument)
|
||||
typeAliasUsageElement: KtElement?
|
||||
) {
|
||||
if (typeParameterDescriptor.upperBounds.isEmpty()) return
|
||||
|
||||
// The error is already reported, it's unnecessary to do more checks
|
||||
if (!isCheckPassed) return false
|
||||
val diagnosticsReporter = UpperBoundViolatedReporter(trace, argumentType, typeParameterDescriptor)
|
||||
val diagnosticsReporterForWarnings = UpperBoundViolatedReporter(
|
||||
trace, argumentType, typeParameterDescriptor,
|
||||
baseDiagnostic = UPPER_BOUND_VIOLATED_BASED_ON_JAVA_ANNOTATIONS,
|
||||
diagnosticForTypeAliases = UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION_BASED_ON_JAVA_ANNOTATIONS
|
||||
)
|
||||
|
||||
val enhancedBound = bound.getEnhancement() ?: return false
|
||||
for (bound in typeParameterDescriptor.upperBounds) {
|
||||
val isCheckPassed = checkBound(bound, argumentType, argumentReference, substitutor, typeAliasUsageElement, diagnosticsReporter)
|
||||
|
||||
val isTypeEnhancementImprovementsEnabled =
|
||||
languageVersionSettings.supportsFeature(LanguageFeature.ImprovementsAroundTypeEnhancement)
|
||||
val substitutedBound = substitutor.safeSubstitute(enhancedBound, Variance.INVARIANT)
|
||||
if (!KotlinTypeChecker.DEFAULT.isSubtypeOf(typeArgument, substitutedBound)) {
|
||||
if (isTypeEnhancementImprovementsEnabled) {
|
||||
trace.report(Errors.UPPER_BOUND_VIOLATED.on(jetTypeArgument, substitutedBound, typeArgument))
|
||||
} else {
|
||||
trace.report(ErrorsJvm.UPPER_BOUND_VIOLATED_BASED_ON_JAVA_ANNOTATIONS.on(jetTypeArgument, substitutedBound, typeArgument))
|
||||
}
|
||||
return false
|
||||
// The error is already reported, it's unnecessary to do more checks
|
||||
if (!isCheckPassed) continue
|
||||
|
||||
// If improvements are enabled, then type parameter's upper bounds will already enhanced, and the error will reported inside the first check
|
||||
if (isTypeEnhancementImprovementsEnabled) continue
|
||||
|
||||
val enhancedBound = bound.getEnhancementDeeply() ?: continue
|
||||
|
||||
checkBound(enhancedBound, argumentType, argumentReference, substitutor, typeAliasUsageElement, diagnosticsReporterForWarnings)
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
+2
-29
@@ -215,9 +215,9 @@ class JavaNullabilityChecker : AdditionalTypeChecker {
|
||||
|
||||
if (!doesExpectedTypeContainsEnhancement && !doesExpressionTypeContainsEnhancement) return
|
||||
|
||||
val enhancedExpectedType = if (doesExpectedTypeContainsEnhancement) buildTypeWithEnhancement(expectedType) else expectedType
|
||||
val enhancedExpectedType = if (doesExpectedTypeContainsEnhancement) expectedType.unwrapEnhancementDeeply() else expectedType
|
||||
val enhancedExpressionType = enhanceExpressionTypeByDataFlowNullability(
|
||||
if (doesExpressionTypeContainsEnhancement) buildTypeWithEnhancement(expressionType) else expressionType,
|
||||
if (doesExpressionTypeContainsEnhancement) expressionType.unwrapEnhancementDeeply() else expressionType,
|
||||
expressionTypeDataFlowValue,
|
||||
dataFlowInfo
|
||||
)
|
||||
@@ -253,33 +253,6 @@ class JavaNullabilityChecker : AdditionalTypeChecker {
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
private fun enhanceTypeArguments(arguments: List<TypeProjection>) =
|
||||
arguments.map { argument ->
|
||||
// TODO: think about star projections with enhancement (e.g. came from Java: Foo<@NotNull ?>)
|
||||
if (argument.isStarProjection) {
|
||||
return@map argument
|
||||
}
|
||||
val argumentType = argument.type
|
||||
val enhancedArgumentType = if (argumentType is TypeWithEnhancement) argumentType.enhancement else argumentType
|
||||
val enhancedDeeplyArgumentType = buildTypeWithEnhancement(enhancedArgumentType)
|
||||
|
||||
argument.replaceType(enhancedDeeplyArgumentType)
|
||||
}
|
||||
|
||||
fun buildTypeWithEnhancement(type: KotlinType): KotlinType {
|
||||
val newArguments = enhanceTypeArguments(type.arguments)
|
||||
val newArgumentsForUpperBound =
|
||||
if (type is FlexibleType) {
|
||||
enhanceTypeArguments(type.upperBound.arguments)
|
||||
} else newArguments
|
||||
val enhancedType = if (type is TypeWithEnhancement) type.enhancement else type
|
||||
|
||||
return enhancedType.replace(
|
||||
newArguments = newArguments,
|
||||
newArgumentsForUpperBound = newArgumentsForUpperBound
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class EnhancedNullabilityInfo(val enhancedType: KotlinType, val isFromJava: Boolean) {
|
||||
|
||||
+5
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.utils.StringsKt;
|
||||
import java.util.List;
|
||||
|
||||
import static kotlin.collections.CollectionsKt.*;
|
||||
import static org.jetbrains.kotlin.diagnostics.Errors.UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION;
|
||||
import static org.jetbrains.kotlin.diagnostics.rendering.Renderers.*;
|
||||
import static org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm.*;
|
||||
|
||||
@@ -86,6 +87,10 @@ public class DefaultErrorMessagesJvm implements DefaultErrorMessages.Extension {
|
||||
|
||||
MAP.put(NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS, "Type mismatch: inferred type is {1} but {0} was expected", RENDER_TYPE, RENDER_TYPE);
|
||||
MAP.put(UPPER_BOUND_VIOLATED_BASED_ON_JAVA_ANNOTATIONS, "Type argument is not within its bounds: should be subtype of ''{0}''", RENDER_TYPE, RENDER_TYPE);
|
||||
MAP.put(UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION_BASED_ON_JAVA_ANNOTATIONS,
|
||||
"Type argument resulting from type alias expansion is not within required bounds for ''{2}'': " +
|
||||
"should be subtype of ''{0}'', substituted type is ''{1}''",
|
||||
RENDER_TYPE, RENDER_TYPE, NAME);
|
||||
MAP.put(NULLABLE_TYPE_PARAMETER_AGAINST_NOT_NULL_TYPE_PARAMETER,
|
||||
"Type mismatch: value of a nullable type {0} is used where non-nullable type is expected. " +
|
||||
"This warning will become an error soon. " +
|
||||
|
||||
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.resolve.jvm.diagnostics;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.kotlin.diagnostics.*;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
@@ -140,6 +141,9 @@ public interface ErrorsJvm {
|
||||
DiagnosticFactory2<KtTypeReference, KotlinType, KotlinType> UPPER_BOUND_VIOLATED_BASED_ON_JAVA_ANNOTATIONS
|
||||
= DiagnosticFactory2.create(WARNING);
|
||||
|
||||
DiagnosticFactory3<KtElement, KotlinType, KotlinType, ClassifierDescriptor> UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION_BASED_ON_JAVA_ANNOTATIONS
|
||||
= DiagnosticFactory3.create(WARNING);
|
||||
|
||||
DiagnosticFactory1<KtElement, KotlinType> NULLABLE_TYPE_PARAMETER_AGAINST_NOT_NULL_TYPE_PARAMETER
|
||||
= DiagnosticFactory1.create(WARNING);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user