Fix false negative UPPER_BOUND_VIOLATED with typealiases in supertypes
^KT-50797 Fixed ^KT-50798 Open
This commit is contained in:
@@ -220,6 +220,8 @@ public interface Errors {
|
||||
DiagnosticFactory1<KtElement, ClassifierDescriptor> RECURSIVE_TYPEALIAS_EXPANSION = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory3<KtElement, KotlinType, KotlinType, ClassifierDescriptor> UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION =
|
||||
DiagnosticFactory3.create(ERROR);
|
||||
DiagnosticFactory3<KtElement, KotlinType, KotlinType, ClassifierDescriptor> UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION_WARNING =
|
||||
DiagnosticFactory3.create(WARNING);
|
||||
DiagnosticFactory1<KtElement, KotlinType> CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory1<KtTypeReference, KotlinType> TYPEALIAS_SHOULD_EXPAND_TO_CLASS = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory2<KtTypeReference, KotlinType, String> TYPEALIAS_EXPANDED_TO_MALFORMED_TYPE = DiagnosticFactory2.create(ERROR);
|
||||
|
||||
+4
-1
@@ -10,7 +10,6 @@ import kotlin.Pair;
|
||||
import kotlin.collections.CollectionsKt;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.config.LanguageVersion;
|
||||
import org.jetbrains.kotlin.descriptors.MemberDescriptor;
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory;
|
||||
import org.jetbrains.kotlin.diagnostics.Errors;
|
||||
@@ -607,6 +606,10 @@ public class DefaultErrorMessages {
|
||||
"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(UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION_WARNING,
|
||||
"Type argument resulting from type alias expansion is not within required bounds for ''{2}'': " +
|
||||
"should be subtype of ''{0}'', substituted type is ''{1}''. This warning will become an error since 1.8",
|
||||
RENDER_TYPE, RENDER_TYPE, NAME);
|
||||
MAP.put(CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION, "Conflicting projection in type alias expansion in intermediate type ''{0}''", RENDER_TYPE);
|
||||
MAP.put(TYPEALIAS_SHOULD_EXPAND_TO_CLASS, "Type alias expands to {0}, which is not a class, an interface, or an object", RENDER_TYPE);
|
||||
MAP.put(TYPEALIAS_EXPANDED_TO_MALFORMED_TYPE, "Type alias expanded to malformed type {0}: {1}", RENDER_TYPE, STRING);
|
||||
|
||||
@@ -25,7 +25,6 @@ import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory0
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.diagnostics.Errors.*
|
||||
@@ -45,9 +44,11 @@ import org.jetbrains.kotlin.resolve.inline.isInlineOnly
|
||||
import org.jetbrains.kotlin.resolve.source.KotlinSourceElement
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||
import org.jetbrains.kotlin.types.typeUtil.*
|
||||
import org.jetbrains.kotlin.types.typeUtil.constituentTypes
|
||||
import org.jetbrains.kotlin.types.typeUtil.contains
|
||||
import org.jetbrains.kotlin.types.typeUtil.isArrayOfNothing
|
||||
import org.jetbrains.kotlin.types.typeUtil.isNothing
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
import java.util.*
|
||||
|
||||
internal class DeclarationsCheckerBuilder(
|
||||
private val descriptorResolver: DescriptorResolver,
|
||||
@@ -357,7 +358,7 @@ class DeclarationsChecker(
|
||||
|
||||
for (delegationSpecifier in classOrObject.superTypeListEntries) {
|
||||
val typeReference = delegationSpecifier.typeReference ?: continue
|
||||
typeReference.type()?.let { upperBoundChecker.checkBounds(typeReference, it, trace) }
|
||||
typeReference.type()?.let { upperBoundChecker.checkBoundsInSupertype(typeReference, it, trace, languageVersionSettings) }
|
||||
}
|
||||
|
||||
if (classOrObject !is KtClass) return
|
||||
@@ -380,7 +381,7 @@ class DeclarationsChecker(
|
||||
DescriptorResolver.checkUpperBoundTypes(trace, upperBoundCheckRequests, false)
|
||||
|
||||
for (request in upperBoundCheckRequests) {
|
||||
upperBoundChecker.checkBounds(request.upperBound, request.upperBoundType, trace)
|
||||
upperBoundChecker.checkBoundsInSupertype(request.upperBound, request.upperBoundType, trace, languageVersionSettings)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,13 +5,14 @@
|
||||
|
||||
package org.jetbrains.kotlin.resolve
|
||||
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.container.DefaultImplementation
|
||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory2
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory3
|
||||
import org.jetbrains.kotlin.diagnostics.Errors.UPPER_BOUND_VIOLATED
|
||||
import org.jetbrains.kotlin.diagnostics.Errors.UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION
|
||||
import org.jetbrains.kotlin.diagnostics.Errors.*
|
||||
import org.jetbrains.kotlin.diagnostics.reportDiagnosticOnce
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
@@ -34,17 +35,24 @@ open class UpperBoundChecker {
|
||||
substitutor: TypeSubstitutor,
|
||||
trace: BindingTrace,
|
||||
typeAliasUsageElement: KtElement? = null,
|
||||
diagnosticForTypeAliases: DiagnosticFactory3<KtElement, KotlinType, KotlinType, ClassifierDescriptor> = UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION
|
||||
) {
|
||||
if (typeParameterDescriptor.upperBounds.isEmpty()) return
|
||||
|
||||
val diagnosticsReporter = UpperBoundViolatedReporter(trace, argumentType, typeParameterDescriptor)
|
||||
val diagnosticsReporter =
|
||||
UpperBoundViolatedReporter(trace, argumentType, typeParameterDescriptor, diagnosticForTypeAliases = diagnosticForTypeAliases)
|
||||
|
||||
for (bound in typeParameterDescriptor.upperBounds) {
|
||||
checkBound(bound, argumentType, argumentReference, substitutor, typeAliasUsageElement, diagnosticsReporter)
|
||||
}
|
||||
}
|
||||
|
||||
fun checkBounds(typeReference: KtTypeReference, type: KotlinType, trace: BindingTrace) {
|
||||
fun checkBoundsInSupertype(
|
||||
typeReference: KtTypeReference,
|
||||
type: KotlinType,
|
||||
trace: BindingTrace,
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
) {
|
||||
if (type.isError) return
|
||||
|
||||
val typeElement = typeReference.typeElement ?: return
|
||||
@@ -63,8 +71,21 @@ open class UpperBoundChecker {
|
||||
}
|
||||
// it's really ft<Foo, Bar>
|
||||
val flexibleType = type.asFlexibleType()
|
||||
checkBounds(ktTypeArguments[0], flexibleType.lowerBound, trace)
|
||||
checkBounds(ktTypeArguments[1], flexibleType.upperBound, trace)
|
||||
checkBoundsInSupertype(ktTypeArguments[0], flexibleType.lowerBound, trace, languageVersionSettings)
|
||||
checkBoundsInSupertype(ktTypeArguments[1], flexibleType.upperBound, trace, languageVersionSettings)
|
||||
return
|
||||
}
|
||||
|
||||
if (type is AbbreviatedType) {
|
||||
checkBoundsForAbbreviatedSupertype(
|
||||
type, trace, typeReference,
|
||||
// The errors have been reported previously if ktTypeArguments.size accidentally was equal to the amount of arguments
|
||||
// in the expanded type
|
||||
reportWarning = ktTypeArguments.size != arguments.size &&
|
||||
!languageVersionSettings.supportsFeature(
|
||||
LanguageFeature.ReportMissingUpperBoundsViolatedErrorOnAbbreviationAtSupertypes
|
||||
)
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -75,11 +96,41 @@ open class UpperBoundChecker {
|
||||
|
||||
for (i in ktTypeArguments.indices) {
|
||||
val ktTypeArgument = ktTypeArguments[i] ?: continue
|
||||
checkBounds(ktTypeArgument, arguments[i].type, trace)
|
||||
checkBoundsInSupertype(ktTypeArgument, arguments[i].type, trace, languageVersionSettings)
|
||||
checkBounds(ktTypeArgument, arguments[i].type, parameters[i], substitutor, trace)
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkBoundsForAbbreviatedSupertype(
|
||||
type: KotlinType,
|
||||
trace: BindingTrace,
|
||||
typeReference: KtTypeReference,
|
||||
reportWarning: Boolean
|
||||
) {
|
||||
val parameters = type.constructor.parameters
|
||||
val arguments = type.arguments
|
||||
val substitutor = TypeSubstitutor.create(type)
|
||||
|
||||
val diagnostic =
|
||||
if (reportWarning)
|
||||
UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION_WARNING
|
||||
else
|
||||
UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION
|
||||
|
||||
for (i in arguments.indices) {
|
||||
if (arguments[i].isStarProjection) continue
|
||||
val argumentType = arguments[i].type
|
||||
|
||||
checkBoundsForAbbreviatedSupertype(argumentType, trace, typeReference, reportWarning)
|
||||
|
||||
checkBounds(
|
||||
argumentReference = null,
|
||||
argumentType, parameters[i], substitutor, trace,
|
||||
typeAliasUsageElement = typeReference, diagnosticForTypeAliases = diagnostic,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
protected fun checkBound(
|
||||
bound: KotlinType,
|
||||
argumentType: KotlinType,
|
||||
|
||||
Reference in New Issue
Block a user