[FIR] Report UPPER_BOUND_VIOLATED only on checkers stage, fix detection of missing cases and testData
This commit is contained in:
committed by
teamcityserver
parent
ada14413e0
commit
5741374883
@@ -45,7 +45,7 @@ class Foo() {}
|
||||
|
||||
class Bar<T : <!FINAL_UPPER_BOUND!>Foo<!>>
|
||||
|
||||
class Buzz<T> where T : <!FINAL_UPPER_BOUND!>Bar<Int><!>, T : <!UNRESOLVED_REFERENCE!>nioho<!>
|
||||
class Buzz<T> where T : <!FINAL_UPPER_BOUND!>Bar<<!UPPER_BOUND_VIOLATED!>Int<!>><!>, T : <!UNRESOLVED_REFERENCE!>nioho<!>
|
||||
|
||||
class X<T : <!FINAL_UPPER_BOUND!>Foo<!>>
|
||||
class Y<<!CONFLICTING_UPPER_BOUNDS!>T<!>> where T : <!FINAL_UPPER_BOUND!>Foo<!>, T : <!FINAL_UPPER_BOUND, ONLY_ONE_CLASS_BOUND_ALLOWED!>Bar<Foo><!>
|
||||
@@ -62,8 +62,8 @@ fun <T> test2(t : T)
|
||||
t.bar()
|
||||
}
|
||||
|
||||
val t1 = test2<A>(<!ARGUMENT_TYPE_MISMATCH!>A()<!>)
|
||||
val t2 = test2<B>(<!ARGUMENT_TYPE_MISMATCH!>C()<!>)
|
||||
val t1 = test2<<!UPPER_BOUND_VIOLATED!>A<!>>(<!ARGUMENT_TYPE_MISMATCH!>A()<!>)
|
||||
val t2 = test2<<!UPPER_BOUND_VIOLATED!>B<!>>(<!ARGUMENT_TYPE_MISMATCH!>C()<!>)
|
||||
val t3 = test2<C>(C())
|
||||
|
||||
val <<!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>T<!>, <!TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER!>B : T<!>> x : Int = 0
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@ class G<E : <!FINAL_UPPER_BOUND!>Double<!>>(val balue: E) : F<E>(balue) {
|
||||
override var rest: E = balue
|
||||
}
|
||||
|
||||
class H<E : <!FINAL_UPPER_BOUND!>String<!>>(val balue: E) : F<E>(<!ARGUMENT_TYPE_MISMATCH!>balue<!>) {
|
||||
class H<E : <!FINAL_UPPER_BOUND!>String<!>>(val balue: E) : F<<!UPPER_BOUND_VIOLATED!>E<!>>(<!ARGUMENT_TYPE_MISMATCH!>balue<!>) {
|
||||
override var rest: E = balue // no report because of INAPPLICABLE_CANDIDATE
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@ class G<E : <!FINAL_UPPER_BOUND!>Double<!>>(val balue: E) : F<E>(balue) {
|
||||
override fun rest(): E = balue
|
||||
}
|
||||
|
||||
class H<E : <!FINAL_UPPER_BOUND!>String<!>>(val balue: E) : F<E>(<!ARGUMENT_TYPE_MISMATCH!>balue<!>) {
|
||||
class H<E : <!FINAL_UPPER_BOUND!>String<!>>(val balue: E) : F<<!UPPER_BOUND_VIOLATED!>E<!>>(<!ARGUMENT_TYPE_MISMATCH!>balue<!>) {
|
||||
override fun rest(): E = balue // no report because of INAPPLICABLE_CANDIDATE
|
||||
}
|
||||
|
||||
|
||||
+5
-5
@@ -41,14 +41,14 @@ FILE: upperBoundViolated.kt
|
||||
}
|
||||
|
||||
}
|
||||
public final class P<T> : R|kotlin/Any| {
|
||||
public constructor<T>(): R|P<T>| {
|
||||
public final class P<T0 : R|kotlin/Number|, T1> : R|kotlin/Any| {
|
||||
public constructor<T0 : R|kotlin/Number|, T1>(): R|P<T0, T1>| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
public final class P1<T1 : R|kotlin/Number|, T2 : R|kotlin/Number|> : R|kotlin/Any| {
|
||||
public constructor<T1 : R|kotlin/Number|, T2 : R|kotlin/Number|>(): R|P1<T1, T2>| {
|
||||
public final class P1<T2 : R|kotlin/Number|, T3 : R|kotlin/Number|> : R|kotlin/Any| {
|
||||
public constructor<T2 : R|kotlin/Number|, T3 : R|kotlin/Number|>(): R|P1<T2, T3>| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ FILE: upperBoundViolated.kt
|
||||
lval o5: R|S<S<L, L>, T<K, L>>| = <CS errors: /S.S>#<R|S<L, L>|, R|T<K, L>|>()
|
||||
lval o6: R|S<kotlin/Any, T<S<K, L>, kotlin/String>>| = R|/S.S|<R|kotlin/Any|, R|T<S<K, L>, kotlin/String>|>()
|
||||
lval o7: R|S<kotlin/Any, T<S<K, L>, kotlin/Nothing>>| = R|/S.S|<R|kotlin/Any|, R|T<S<K, L>, kotlin/Nothing>|>()
|
||||
lval o8: R|P<P1<kotlin/String, kotlin/String>>| = R|/P.P|<R|P1<kotlin/String, kotlin/String>|>()
|
||||
lval o8: R|P<kotlin/String, P1<kotlin/String, kotlin/String>>| = <CS errors: /P.P>#<R|kotlin/String|, R|P1<kotlin/String, kotlin/String>|>()
|
||||
}
|
||||
public final class NumColl<T : R|kotlin/collections/Collection<kotlin/Number>|> : R|kotlin/Any| {
|
||||
public constructor<T : R|kotlin/collections/Collection<kotlin/Number>|>(): R|NumColl<T>| {
|
||||
|
||||
+3
-3
@@ -24,8 +24,8 @@ fun test() {
|
||||
|
||||
open class S<F, G : F>
|
||||
class T<U, Y : U> : S<U, Y>()
|
||||
class P<T>
|
||||
class P1<T1: Number, T2: Number>
|
||||
class P<T0: Number, T1>
|
||||
class P1<T2 : Number, T3 : Number>
|
||||
|
||||
|
||||
fun <K, L : K> rest() {
|
||||
@@ -39,7 +39,7 @@ fun <K, L : K> rest() {
|
||||
|
||||
val o6 = S<Any, T<S<K, L>, <!UPPER_BOUND_VIOLATED!>String<!>>>()
|
||||
val o7 = S<Any, T<S<K, L>, Nothing>>()
|
||||
val o8 = P<P1<<!UPPER_BOUND_VIOLATED!>String<!>, <!UPPER_BOUND_VIOLATED!>String<!>>>()
|
||||
val o8 = P<<!UPPER_BOUND_VIOLATED!>String<!>, P1<<!UPPER_BOUND_VIOLATED!>String<!>, <!UPPER_BOUND_VIOLATED!>String<!>>>()
|
||||
}
|
||||
|
||||
class NumColl<T : Collection<Number>>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
interface FirDeclaration
|
||||
|
||||
interface FirSymbolOwner<E : FirSymbolOwner<E>> {
|
||||
val symbol: AbstractFirBasedSymbol<E>
|
||||
val symbol: AbstractFirBasedSymbol<<!UPPER_BOUND_VIOLATED!>E<!>>
|
||||
}
|
||||
interface FirFunction<F : FirFunction<F>> : FirSymbolOwner<F>, FirDeclaration
|
||||
|
||||
|
||||
+3
-1
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.fir.analysis.checkers.syntax.FirDelegationInInterfac
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.syntax.FirFunctionTypeParametersSyntaxChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.syntax.FirTypeParameterSyntaxChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirReservedUnderscoreDeclarationChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirUpperBoundViolatedClassChecker
|
||||
|
||||
object CommonDeclarationCheckers : DeclarationCheckers() {
|
||||
override val basicDeclarationCheckers: Set<FirBasicDeclarationChecker>
|
||||
@@ -23,7 +24,8 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
|
||||
FirConflictsChecker,
|
||||
FirProjectionRelationChecker,
|
||||
FirTypeConstraintsChecker,
|
||||
FirReservedUnderscoreDeclarationChecker
|
||||
FirReservedUnderscoreDeclarationChecker,
|
||||
FirUpperBoundViolatedClassChecker
|
||||
)
|
||||
|
||||
override val memberDeclarationCheckers: Set<FirMemberDeclarationChecker>
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ object CommonExpressionCheckers : ExpressionCheckers() {
|
||||
FirAbstractSuperCallChecker,
|
||||
FirQualifiedSupertypeExtendedByOtherSupertypeChecker,
|
||||
FirProjectionsOnNonClassTypeArgumentChecker,
|
||||
FirUpperBoundViolatedChecker,
|
||||
FirUpperBoundViolatedExpressionChecker,
|
||||
FirTypeArgumentsNotAllowedExpressionChecker,
|
||||
FirTypeParameterInQualifiedAccessChecker,
|
||||
FirSealedClassConstructorCallChecker,
|
||||
|
||||
+127
-98
@@ -7,142 +7,171 @@ package org.jetbrains.kotlin.fir.analysis.checkers.expression
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSourceElement
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirBasicDeclarationChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.extractTypeRefAndSourceFromTypeArgument
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
import org.jetbrains.kotlin.fir.declarations.FirTypeParameterRefsOwner
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
|
||||
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
|
||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeInapplicableCandidateError
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.fir.typeContext
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability
|
||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
object FirUpperBoundViolatedChecker : FirQualifiedAccessExpressionChecker() {
|
||||
object FirUpperBoundViolatedClassChecker : FirBasicDeclarationChecker() {
|
||||
override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (declaration is FirClass<*>) {
|
||||
for (typeParameter in declaration.typeParameters) {
|
||||
if (typeParameter is FirTypeParameter) {
|
||||
for (bound in typeParameter.bounds) {
|
||||
analyzeTypeParameters(bound, context, reporter)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (superTypeRef in declaration.superTypeRefs) {
|
||||
analyzeTypeParameters(superTypeRef, context, reporter)
|
||||
}
|
||||
} else if (declaration is FirCallableDeclaration<*>) {
|
||||
analyzeTypeParameters(declaration.returnTypeRef, context, reporter)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object FirUpperBoundViolatedExpressionChecker : FirQualifiedAccessExpressionChecker() {
|
||||
override fun check(expression: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
// something that contains the type parameters
|
||||
// declarations with their declared bounds.
|
||||
// it may be the called function declaration
|
||||
// or the class declaration
|
||||
val calleeFir = expression.calleeReference.safeAs<FirResolvedNamedReference>()
|
||||
?.resolvedSymbol
|
||||
?.fir.safeAs<FirTypeParameterRefsOwner>()
|
||||
?: return
|
||||
|
||||
val coneType = expression.typeRef.coneType
|
||||
if (coneType is ConeClassLikeType) {
|
||||
analyzeTypeParameters(
|
||||
coneType,
|
||||
expression.typeRef,
|
||||
calleeFir.typeParameters.map { it.symbol },
|
||||
expression.typeArguments,
|
||||
context,
|
||||
reporter
|
||||
)
|
||||
val calleReference = expression.calleeReference
|
||||
var calleeFir: FirTypeParameterRefsOwner? = null
|
||||
if (calleReference is FirResolvedNamedReference) {
|
||||
calleeFir = calleReference.safeAs<FirResolvedNamedReference>()?.resolvedSymbol?.fir.safeAs()
|
||||
} else if (calleReference is FirErrorNamedReference) {
|
||||
val diagnostic = calleReference.diagnostic
|
||||
if (diagnostic is ConeInapplicableCandidateError &&
|
||||
diagnostic.applicability == CandidateApplicability.INAPPLICABLE_WRONG_RECEIVER
|
||||
) {
|
||||
return
|
||||
}
|
||||
calleeFir = calleReference.candidateSymbol?.fir.safeAs()
|
||||
}
|
||||
|
||||
analyzeTypeParameters(
|
||||
expression.typeRef,
|
||||
context,
|
||||
reporter,
|
||||
calleeFir?.typeParameters?.map { it.symbol },
|
||||
expression.typeArguments
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively analyzes type parameters and reports the diagnostic on the given source calculated using typeRef
|
||||
* Returns true if an error occurred
|
||||
*/
|
||||
private fun analyzeTypeParameters(
|
||||
typeRef: FirTypeRef?,
|
||||
context: CheckerContext,
|
||||
reporter: DiagnosticReporter,
|
||||
typeParameters: List<FirTypeParameterSymbol>? = null,
|
||||
typeArguments: List<FirTypeProjection>? = null
|
||||
) {
|
||||
val type = when (typeRef) {
|
||||
is ConeKotlinType -> typeRef
|
||||
is FirResolvedTypeRef -> typeRef.type
|
||||
else -> return
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively analyzes type parameters and reports the diagnostic on the given source calculated using typeRef
|
||||
* Returns true if an error occurred
|
||||
*/
|
||||
private fun analyzeTypeParameters(
|
||||
type: ConeClassLikeType,
|
||||
typeRef: FirTypeRef?,
|
||||
typeParameters: List<FirTypeParameterSymbol>?,
|
||||
typeArguments: List<FirTypeProjection>?,
|
||||
context: CheckerContext,
|
||||
reporter: DiagnosticReporter
|
||||
) {
|
||||
fun getTypeArgument(index: Int): Any {
|
||||
return typeArguments?.elementAt(index) ?: type.typeArguments[index]
|
||||
}
|
||||
val typeArgumentsCount = typeArguments?.size ?: type.typeArguments.size
|
||||
if (typeArgumentsCount == 0) {
|
||||
return
|
||||
}
|
||||
|
||||
val typeArgumentsCount = typeArguments?.size ?: type.typeArguments.size
|
||||
if (typeArgumentsCount == 0) {
|
||||
return
|
||||
}
|
||||
|
||||
val typeParameterSymbols = if (typeParameters != null) {
|
||||
typeParameters
|
||||
} else {
|
||||
val typeParameterSymbols = typeParameters
|
||||
?: if (type is ConeClassLikeType) {
|
||||
val prototypeClass = type.lookupTag.toSymbol(context.session)
|
||||
?.fir.safeAs<FirRegularClass>()
|
||||
?: return
|
||||
|
||||
prototypeClass.typeParameters.map { it.symbol }
|
||||
} else {
|
||||
listOf()
|
||||
}
|
||||
|
||||
if (typeParameterSymbols.isEmpty()) {
|
||||
return
|
||||
}
|
||||
if (typeParameterSymbols.isEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
val count = minOf(typeParameterSymbols.size, typeArgumentsCount)
|
||||
val substitution = mutableMapOf<FirTypeParameterSymbol, ConeKotlinType>()
|
||||
val count = minOf(typeParameterSymbols.size, typeArgumentsCount)
|
||||
val substitution = mutableMapOf<FirTypeParameterSymbol, ConeKotlinType>()
|
||||
|
||||
for (index in 0 until count) {
|
||||
val typeArgument = getTypeArgument(index)
|
||||
val typeParameterSymbol = typeParameterSymbols[index]
|
||||
for (index in 0 until count) {
|
||||
val typeArgument = typeArguments?.elementAt(index) ?: type.typeArguments[index]
|
||||
val typeParameterSymbol = typeParameterSymbols[index]
|
||||
|
||||
if (typeArgument is FirTypeProjectionWithVariance) {
|
||||
substitution[typeParameterSymbol] = typeArgument.typeRef.coneType
|
||||
} else if (typeArgument is ConeClassLikeType) {
|
||||
substitution[typeParameterSymbol] = typeArgument.type
|
||||
}
|
||||
}
|
||||
|
||||
val substitutor = substitutorByMap(substitution, context.session)
|
||||
val typeSystemContext = context.session.typeContext
|
||||
|
||||
for (index in 0 until count) {
|
||||
var typeArgument: ConeClassLikeType? = null
|
||||
var typeArgumentTypeRef: FirTypeRef? = null
|
||||
var typeArgumentSource: FirSourceElement? = null
|
||||
|
||||
if (typeArguments != null) {
|
||||
val localTypeArgument = typeArguments[index]
|
||||
if (localTypeArgument is FirTypeProjectionWithVariance) {
|
||||
typeArgumentTypeRef = localTypeArgument.typeRef
|
||||
typeArgument = typeArgumentTypeRef.coneType as? ConeClassLikeType
|
||||
typeArgumentSource = localTypeArgument.source
|
||||
}
|
||||
} else {
|
||||
typeArgument = type.typeArguments[index] as? ConeClassLikeType
|
||||
val argTypeRefSource = extractTypeRefAndSourceFromTypeArgument(typeRef, index)
|
||||
typeArgumentTypeRef = argTypeRefSource?.first
|
||||
typeArgumentSource = argTypeRefSource?.second
|
||||
}
|
||||
|
||||
if (typeArgument != null && typeArgumentSource != null) {
|
||||
val upperBound = getSubstitutedUpperBound(typeParameterSymbols[index], substitutor, typeSystemContext)
|
||||
if (upperBound != null && !satisfiesBounds(upperBound, typeArgument.type, typeSystemContext)) {
|
||||
reporter.reportOn(typeArgumentSource, FirErrors.UPPER_BOUND_VIOLATED, upperBound, context)
|
||||
} else {
|
||||
analyzeTypeParameters(typeArgument, typeArgumentTypeRef, null, null, context, reporter)
|
||||
}
|
||||
}
|
||||
if (typeArgument is FirTypeProjectionWithVariance) {
|
||||
substitution[typeParameterSymbol] = typeArgument.typeRef.coneType
|
||||
} else if (typeArgument is ConeKotlinType) {
|
||||
substitution[typeParameterSymbol] = typeArgument.type
|
||||
}
|
||||
}
|
||||
|
||||
private fun getSubstitutedUpperBound(
|
||||
prototypeSymbol: FirTypeParameterSymbol,
|
||||
substitutor: ConeSubstitutor,
|
||||
typeSystemContext: ConeTypeContext
|
||||
): ConeKotlinType? {
|
||||
val intersection = typeSystemContext.intersectTypes(
|
||||
prototypeSymbol.fir.bounds.map { it.coneType }
|
||||
).safeAs<ConeKotlinType>() ?: return null
|
||||
val substitutor = substitutorByMap(substitution, context.session)
|
||||
val typeSystemContext = context.session.typeContext
|
||||
|
||||
return substitutor.substituteOrSelf(intersection)
|
||||
}
|
||||
for (index in 0 until count) {
|
||||
var typeArgument: ConeKotlinType? = null
|
||||
var typeArgumentTypeRef: FirTypeRef? = null
|
||||
var typeArgumentSource: FirSourceElement? = null
|
||||
|
||||
private fun satisfiesBounds(upperBound: ConeKotlinType, target: ConeKotlinType, typeSystemContext: ConeTypeContext): Boolean {
|
||||
return AbstractTypeChecker.isSubtypeOf(typeSystemContext, target, upperBound, stubTypesEqualToAnything = false)
|
||||
if (typeArguments != null) {
|
||||
val localTypeArgument = typeArguments[index]
|
||||
if (localTypeArgument is FirTypeProjectionWithVariance) {
|
||||
typeArgumentTypeRef = localTypeArgument.typeRef
|
||||
typeArgument = typeArgumentTypeRef.coneType
|
||||
typeArgumentSource = localTypeArgument.source
|
||||
}
|
||||
} else {
|
||||
typeArgument = type.typeArguments[index] as? ConeKotlinType
|
||||
val argTypeRefSource = extractTypeRefAndSourceFromTypeArgument(typeRef, index)
|
||||
if (argTypeRefSource != null) {
|
||||
typeArgumentTypeRef = argTypeRefSource.first
|
||||
typeArgumentSource = argTypeRefSource.second
|
||||
}
|
||||
}
|
||||
|
||||
if (typeArgument != null && typeArgumentSource != null) {
|
||||
val upperBound = getSubstitutedUpperBound(typeParameterSymbols[index], substitutor, typeSystemContext)
|
||||
if (upperBound != null && !satisfiesBounds(upperBound, typeArgument.type, typeSystemContext)) {
|
||||
reporter.reportOn(typeArgumentSource, FirErrors.UPPER_BOUND_VIOLATED, upperBound, context)
|
||||
}
|
||||
|
||||
analyzeTypeParameters(typeArgumentTypeRef, context, reporter)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getSubstitutedUpperBound(
|
||||
prototypeSymbol: FirTypeParameterSymbol,
|
||||
substitutor: ConeSubstitutor,
|
||||
typeSystemContext: ConeTypeContext
|
||||
): ConeKotlinType? {
|
||||
val intersection = typeSystemContext.intersectTypes(prototypeSymbol.fir.bounds.map { it.coneType }) as? ConeKotlinType ?: return null
|
||||
return substitutor.substituteOrSelf(intersection)
|
||||
}
|
||||
|
||||
private fun satisfiesBounds(upperBound: ConeKotlinType, target: ConeKotlinType, typeSystemContext: ConeTypeContext): Boolean {
|
||||
return AbstractTypeChecker.isSubtypeOf(typeSystemContext, target, upperBound, stubTypesEqualToAnything = false)
|
||||
}
|
||||
|
||||
+1
-9
@@ -286,15 +286,7 @@ private fun ConstraintSystemError.toDiagnostic(
|
||||
|
||||
FirErrors.TYPE_MISMATCH.createOn(qualifiedAccessSource ?: source, upperConeType, inferredType)
|
||||
}
|
||||
is ExplicitTypeParameterConstraintPosition<*> -> {
|
||||
val conePosition = position as ConeExplicitTypeParameterConstraintPosition
|
||||
val typeArgument = conePosition.typeArgument
|
||||
|
||||
FirErrors.UPPER_BOUND_VIOLATED.createOn(
|
||||
typeArgument.source ?: qualifiedAccessSource ?: source,
|
||||
upperConeType,
|
||||
)
|
||||
}
|
||||
is ExplicitTypeParameterConstraintPosition<*>,
|
||||
is DelegatedPropertyConstraintPosition<*> -> {
|
||||
errorsToIgnore.add(this)
|
||||
return null
|
||||
|
||||
Reference in New Issue
Block a user