[FIR] Report INVISIBLE_REFERENCE on the first unresolved qualifier
#KT-61719 Fixed
This commit is contained in:
committed by
Space Team
parent
2127b2ce68
commit
2566dabfce
+1
-1
@@ -3,7 +3,7 @@ class A {
|
||||
}
|
||||
|
||||
class B {
|
||||
fun foo(<!EXPOSED_PARAMETER_TYPE!>value: <!INVISIBLE_REFERENCE!>A.AInner<!><!>) {
|
||||
fun foo(<!EXPOSED_PARAMETER_TYPE!>value: A.<!INVISIBLE_REFERENCE!>AInner<!><!>) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ class A {
|
||||
}
|
||||
|
||||
abstract class B {
|
||||
<!NON_ABSTRACT_FUNCTION_WITH_NO_BODY!>fun <!EXPOSED_FUNCTION_RETURN_TYPE!>foo<!>(str: String): <!INVISIBLE_REFERENCE!>A.InnerA<!><!>
|
||||
<!NON_ABSTRACT_FUNCTION_WITH_NO_BODY!>fun <!EXPOSED_FUNCTION_RETURN_TYPE!>foo<!>(str: String): A.<!INVISIBLE_REFERENCE!>InnerA<!><!>
|
||||
}
|
||||
|
||||
private enum class Some {
|
||||
|
||||
+2
-2
@@ -17,7 +17,7 @@ class Property {
|
||||
<!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>var var1: String<!>
|
||||
<!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>var var2: String<!>
|
||||
<!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>var var3: Int<!>
|
||||
<!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>var <!EXPOSED_PROPERTY_TYPE!>var4<!>: <!INVISIBLE_REFERENCE!>A.AInnerPrivate<!><!>
|
||||
<!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>var <!EXPOSED_PROPERTY_TYPE!>var4<!>: A.<!INVISIBLE_REFERENCE!>AInnerPrivate<!><!>
|
||||
<!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>var var5: A.AInnerPublic<!>
|
||||
<!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>var <!EXPOSED_PROPERTY_TYPE!>var6<!>: <!INVISIBLE_REFERENCE!>A.AInnerProtectedEnum<!><!>
|
||||
<!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>var <!EXPOSED_PROPERTY_TYPE!>var6<!>: A.<!INVISIBLE_REFERENCE!>AInnerProtectedEnum<!><!>
|
||||
}
|
||||
|
||||
+1
-1
@@ -46,7 +46,7 @@ class Test3 : C.CPublicI, <!EXPOSED_SUPER_CLASS, FINAL_SUPERTYPE, SUPERTYPE_NOT_
|
||||
|
||||
}
|
||||
|
||||
class Test4 : E, <!INVISIBLE_REFERENCE!>A.AProtectedI<!> {
|
||||
class Test4 : E, A.<!INVISIBLE_REFERENCE!>AProtectedI<!> {
|
||||
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@ class A {
|
||||
private inner class Inner
|
||||
}
|
||||
class B {
|
||||
<!TOPLEVEL_TYPEALIASES_ONLY!>typealias <!EXPOSED_TYPEALIAS_EXPANDED_TYPE!>AInner<!> = <!INVISIBLE_REFERENCE!>A.Inner<!><!>
|
||||
<!TOPLEVEL_TYPEALIASES_ONLY!>typealias <!EXPOSED_TYPEALIAS_EXPANDED_TYPE!>AInner<!> = A.<!INVISIBLE_REFERENCE!>Inner<!><!>
|
||||
inner class Inner
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ class C {
|
||||
<!TOPLEVEL_TYPEALIASES_ONLY!>typealias BInner = B.Inner<!>
|
||||
}
|
||||
|
||||
typealias <!EXPOSED_TYPEALIAS_EXPANDED_TYPE!>AInner0<!> = <!INVISIBLE_REFERENCE!>A.Inner<!>
|
||||
typealias <!EXPOSED_TYPEALIAS_EXPANDED_TYPE!>AInner0<!> = A.<!INVISIBLE_REFERENCE!>Inner<!>
|
||||
typealias BInner0 = B.Inner
|
||||
|
||||
private typealias MyString = String
|
||||
|
||||
+2
-2
@@ -15,7 +15,7 @@ public class Test1<T: <!EXPOSED_TYPE_PARAMETER_BOUND!>A<!>>
|
||||
public class Test2<T: C, P: E>
|
||||
|
||||
// invalid, D is protected
|
||||
public class Test3<T: E, P: <!EXPOSED_TYPE_PARAMETER_BOUND, INVISIBLE_REFERENCE!>C.D<!>>
|
||||
public class Test3<T: E, P: <!EXPOSED_TYPE_PARAMETER_BOUND!>C.<!INVISIBLE_REFERENCE!>D<!><!>>
|
||||
|
||||
// valid, B is internal
|
||||
internal class Test4<T: B>
|
||||
@@ -32,4 +32,4 @@ public class Container : <!SUPERTYPE_NOT_INITIALIZED!>C<!> {
|
||||
}
|
||||
|
||||
// invalid, A is private, B is internal, D is protected
|
||||
public interface Test8<T: <!EXPOSED_TYPE_PARAMETER_BOUND!>A<!>, P: <!EXPOSED_TYPE_PARAMETER_BOUND!>B<!>, F: C, N: <!EXPOSED_TYPE_PARAMETER_BOUND, INVISIBLE_REFERENCE!>C.D<!>, M: E>
|
||||
public interface Test8<T: <!EXPOSED_TYPE_PARAMETER_BOUND!>A<!>, P: <!EXPOSED_TYPE_PARAMETER_BOUND!>B<!>, F: C, N: <!EXPOSED_TYPE_PARAMETER_BOUND!>C.<!INVISIBLE_REFERENCE!>D<!><!>, M: E>
|
||||
|
||||
+2
-1
@@ -91,6 +91,7 @@ private fun ConeDiagnostic.toKtDiagnostic(
|
||||
)
|
||||
}
|
||||
|
||||
is ConeTypeVisibilityError -> symbol.toInvisibleReferenceDiagnostic(smallestUnresolvablePrefix.last().source)
|
||||
is ConeVisibilityError -> symbol.toInvisibleReferenceDiagnostic(source)
|
||||
is ConeInapplicableWrongReceiver -> FirErrors.UNRESOLVED_REFERENCE_WRONG_RECEIVER.createOn(source, this.candidateSymbols)
|
||||
is ConeNoCompanionObject -> FirErrors.NO_COMPANION_OBJECT.createOn(source, this.candidateSymbol as FirClassLikeSymbol<*>)
|
||||
@@ -175,7 +176,7 @@ private val KtFakeSourceElementKind.canBeIgnored: Boolean
|
||||
get() = this == KtFakeSourceElementKind.DelegatingConstructorCall
|
||||
|| this == KtFakeSourceElementKind.ErrorTypeRef
|
||||
|
||||
fun FirBasedSymbol<*>.toInvisibleReferenceDiagnostic(source: KtSourceElement?): KtDiagnostic? = when (val symbol = this) {
|
||||
fun FirBasedSymbol<*>.toInvisibleReferenceDiagnostic(source: KtSourceElement?): KtDiagnostic = when (val symbol = this) {
|
||||
is FirCallableSymbol<*> -> FirErrors.INVISIBLE_REFERENCE.createOn(source, symbol, symbol.visibility, symbol.callableId.classId)
|
||||
is FirClassLikeSymbol<*> -> FirErrors.INVISIBLE_REFERENCE.createOn(source, symbol, symbol.visibility, symbol.classId.outerClassId)
|
||||
else -> shouldNotBeCalled("Unexpected receiver $javaClass")
|
||||
|
||||
+39
-20
@@ -20,8 +20,10 @@ import org.jetbrains.kotlin.fir.recordTypeLookup
|
||||
import org.jetbrains.kotlin.fir.render
|
||||
import org.jetbrains.kotlin.fir.resolve.FirTypeResolutionResult
|
||||
import org.jetbrains.kotlin.fir.resolve.SupertypeSupplier
|
||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeTypeVisibilityError
|
||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedTypeQualifierError
|
||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnsupportedDefaultValueInFunctionType
|
||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeVisibilityError
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType
|
||||
import org.jetbrains.kotlin.fir.resolve.typeResolver
|
||||
@@ -148,16 +150,10 @@ class FirSpecificTypeResolverTransformer(
|
||||
): FirResolvedTypeRef {
|
||||
return when {
|
||||
resolvedType is ConeErrorType -> {
|
||||
buildErrorType(typeRef, resolvedType, scopeClassDeclaration)
|
||||
buildErrorType(typeRef, resolvedType, resolvedType.diagnostic, scopeClassDeclaration)
|
||||
}
|
||||
diagnostic != null -> {
|
||||
buildErrorTypeRef {
|
||||
source = typeRef.source
|
||||
this.diagnostic = diagnostic
|
||||
type = resolvedType
|
||||
delegatedTypeRef = typeRef
|
||||
partiallyResolvedTypeRef = tryCalculatingPartiallyResolvedTypeRef(typeRef, scopeClassDeclaration)
|
||||
}
|
||||
buildErrorType(typeRef, resolvedType, diagnostic, scopeClassDeclaration)
|
||||
}
|
||||
else -> {
|
||||
buildResolvedTypeRef {
|
||||
@@ -172,11 +168,11 @@ class FirSpecificTypeResolverTransformer(
|
||||
|
||||
private fun buildErrorType(
|
||||
typeRef: FirTypeRef,
|
||||
resolvedType: ConeErrorType,
|
||||
resolvedType: ConeKotlinType,
|
||||
diagnostic: ConeDiagnostic,
|
||||
scopeClassDeclaration: ScopeClassDeclaration,
|
||||
): FirErrorTypeRef {
|
||||
return buildErrorTypeRef {
|
||||
var diagnostic = resolvedType.diagnostic
|
||||
val typeRefSourceKind = typeRef.source?.kind
|
||||
val diagnosticSource = (diagnostic as? ConeUnexpectedTypeArgumentsError)?.source
|
||||
|
||||
@@ -192,22 +188,45 @@ class FirSpecificTypeResolverTransformer(
|
||||
|
||||
delegatedTypeRef = typeRef
|
||||
type = resolvedType
|
||||
|
||||
val partiallyResolvedTypeRef = tryCalculatingPartiallyResolvedTypeRef(typeRef, scopeClassDeclaration)
|
||||
this.partiallyResolvedTypeRef = partiallyResolvedTypeRef
|
||||
|
||||
if (diagnostic is ConeUnresolvedTypeQualifierError) {
|
||||
val totalQualifierCount = diagnostic.qualifiers.size
|
||||
val resolvedQualifierCount = (partiallyResolvedTypeRef?.delegatedTypeRef as? FirUserTypeRef)?.qualifier?.size
|
||||
?: calculatePartiallyResolvablePackageSegments(diagnostic.qualifiers)
|
||||
|
||||
val unresolvedQualifierCount = totalQualifierCount - resolvedQualifierCount
|
||||
|
||||
if (unresolvedQualifierCount > 1) {
|
||||
diagnostic = ConeUnresolvedTypeQualifierError(diagnostic.qualifiers.dropLast(unresolvedQualifierCount - 1), false)
|
||||
this.diagnostic = when {
|
||||
diagnostic is ConeUnresolvedTypeQualifierError -> {
|
||||
ConeUnresolvedTypeQualifierError(smallestUnresolvablePrefix(diagnostic.qualifiers, partiallyResolvedTypeRef), diagnostic.isNullable)
|
||||
}
|
||||
diagnostic is ConeVisibilityError && typeRef is FirUserTypeRef -> {
|
||||
ConeTypeVisibilityError(diagnostic.symbol, smallestUnresolvablePrefix(typeRef.qualifier, partiallyResolvedTypeRef))
|
||||
}
|
||||
else -> diagnostic
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.diagnostic = diagnostic
|
||||
/**
|
||||
* Returns the smallest non-resolvable prefix of the given [qualifiers].
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* - Given `A.B.C` and `A.B` can be resolved, then `A.B.C` will be returned
|
||||
* - Given `A.B.C` and `A` cannot be resolved, then `A` will be returned
|
||||
* - Given `a.b.C` and package `a` exists but package `a.b` doesn't exist, `a.b.` will be returned.
|
||||
*/
|
||||
private fun smallestUnresolvablePrefix(
|
||||
qualifiers: List<FirQualifierPart>,
|
||||
partiallyResolvedTypeRef: FirResolvedTypeRef?,
|
||||
): List<FirQualifierPart> {
|
||||
val totalQualifierCount = qualifiers.size
|
||||
val resolvedQualifierCount = (partiallyResolvedTypeRef?.delegatedTypeRef as? FirUserTypeRef)?.qualifier?.size
|
||||
?: calculatePartiallyResolvablePackageSegments(qualifiers)
|
||||
|
||||
val unresolvedQualifierCount = totalQualifierCount - resolvedQualifierCount
|
||||
|
||||
return if (unresolvedQualifierCount > 1) {
|
||||
qualifiers.dropLast(unresolvedQualifierCount - 1)
|
||||
} else {
|
||||
qualifiers
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+6
-1
@@ -104,12 +104,17 @@ class ConeHiddenCandidateError(
|
||||
override val reason: String get() = "HIDDEN: ${describeSymbol(candidateSymbol)} is deprecated with DeprecationLevel.HIDDEN"
|
||||
}
|
||||
|
||||
class ConeVisibilityError(
|
||||
open class ConeVisibilityError(
|
||||
override val symbol: FirBasedSymbol<*>
|
||||
) : ConeDiagnosticWithSymbol<FirBasedSymbol<*>> {
|
||||
override val reason: String get() = "HIDDEN: ${describeSymbol(symbol)} is invisible"
|
||||
}
|
||||
|
||||
class ConeTypeVisibilityError(
|
||||
symbol: FirBasedSymbol<*>,
|
||||
val smallestUnresolvablePrefix: List<FirQualifierPart>,
|
||||
) : ConeVisibilityError(symbol)
|
||||
|
||||
class ConeInapplicableWrongReceiver(override val candidates: Collection<AbstractCandidate>) : ConeDiagnosticWithCandidates {
|
||||
override val reason: String
|
||||
get() = "None of the following candidates is applicable because of receiver type mismatch: ${
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
package p
|
||||
|
||||
import p.Foo.Nested
|
||||
|
||||
open class Foo {
|
||||
protected class Nested
|
||||
}
|
||||
|
||||
class Bar: Foo() {
|
||||
protected fun foo(): Nested? = null
|
||||
}
|
||||
|
||||
private fun foo(): <!INVISIBLE_REFERENCE!>Nested<!>? = null
|
||||
private fun bar(): <!INVISIBLE_REFERENCE!>p.Foo.Nested<!>? = null
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
package p
|
||||
|
||||
import p.Foo.Nested
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
// !CHECK_TYPE
|
||||
|
||||
|
||||
@<!INVISIBLE_REFERENCE!>kotlin.internal.<!INVISIBLE_REFERENCE!>InlineOnly<!><!>
|
||||
@kotlin.internal.<!INVISIBLE_REFERENCE, INVISIBLE_REFERENCE!>InlineOnly<!>
|
||||
public inline fun <C, R> C.ifEmpty(f: () -> R): R where C : Collection<*>, C : R = if (isEmpty()) f() else this
|
||||
|
||||
public fun <T> listOf(t: T): List<T> = TODO()
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
// FILE: a/M.java
|
||||
package a;
|
||||
|
||||
public class M {
|
||||
public class Inner {
|
||||
|
||||
}
|
||||
|
||||
public static class Nested {
|
||||
|
||||
}
|
||||
|
||||
private class PrInner {
|
||||
|
||||
}
|
||||
|
||||
private static class PrNested {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: b.kt
|
||||
package b
|
||||
|
||||
fun f() {
|
||||
val c1: a.M.Inner
|
||||
val c2: a.M.Nested
|
||||
val c3: <!INVISIBLE_REFERENCE!>a.M.PrInner<!>
|
||||
val c4: <!INVISIBLE_REFERENCE!>a.M.PrNested<!>
|
||||
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// FILE: a/M.java
|
||||
package a;
|
||||
|
||||
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
// FILE: p/Foo.java
|
||||
package p;
|
||||
|
||||
public class Foo {
|
||||
protected static class Nested {}
|
||||
}
|
||||
|
||||
// FILE: foo.kt
|
||||
package a
|
||||
|
||||
import p.Foo
|
||||
import p.Foo.Nested
|
||||
|
||||
class Bar : Foo() {
|
||||
protected fun foo(): Nested? = null
|
||||
}
|
||||
|
||||
private fun foo(): <!INVISIBLE_REFERENCE!>Nested<!>? = null
|
||||
private fun bar(): <!INVISIBLE_REFERENCE!>p.Foo.Nested<!>? = null
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// FILE: p/Foo.java
|
||||
package p;
|
||||
|
||||
|
||||
+1
-1
@@ -16,4 +16,4 @@ class Bar : <!EXPOSED_SUPER_CLASS, INVISIBLE_REFERENCE, INVISIBLE_REFERENCE!>Foo
|
||||
}
|
||||
|
||||
private fun foo(): <!INVISIBLE_REFERENCE!>Nested<!>? = null
|
||||
private fun bar(): <!INVISIBLE_REFERENCE!>p.Foo.Nested<!>? = null
|
||||
private fun bar(): p.<!INVISIBLE_REFERENCE!>Foo<!>.Nested? = null
|
||||
|
||||
@@ -30,7 +30,7 @@ fun test() {
|
||||
<!INVISIBLE_REFERENCE!>foo<!>()
|
||||
|
||||
val u : <!INVISIBLE_REFERENCE!>A<!> = <!INVISIBLE_REFERENCE!>A<!>()
|
||||
val a : <!INVISIBLE_REFERENCE!>java.util.Arrays.ArrayList<Int><!>;
|
||||
val a : java.util.Arrays.<!INVISIBLE_REFERENCE!>ArrayList<!><Int>;
|
||||
|
||||
val po = <!INVISIBLE_REFERENCE!>PO<!>
|
||||
}
|
||||
|
||||
+1
-1
@@ -30,5 +30,5 @@ fun baz() {
|
||||
|
||||
a.A3("") checkType { _<String>() }
|
||||
|
||||
val x: <!INVISIBLE_REFERENCE!>a.A2<!> = B("") // A2 is unresolved because it's private in file, OK
|
||||
val x: a.<!INVISIBLE_REFERENCE!>A2<!> = B("") // A2 is unresolved because it's private in file, OK
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ private class C {
|
||||
private typealias TA = C
|
||||
|
||||
private val test1: <!INVISIBLE_REFERENCE!>C<!> = <!INVISIBLE_REFERENCE!>C<!>()
|
||||
private val test1co: <!INVISIBLE_REFERENCE!>C.Companion<!> = <!INITIALIZER_TYPE_MISMATCH, INVISIBLE_REFERENCE, NO_COMPANION_OBJECT!>C<!>
|
||||
private val test1co: <!INVISIBLE_REFERENCE!>C<!>.Companion = <!INITIALIZER_TYPE_MISMATCH, INVISIBLE_REFERENCE, NO_COMPANION_OBJECT!>C<!>
|
||||
|
||||
private val test2: <!INVISIBLE_REFERENCE!>TA<!> = <!INVISIBLE_REFERENCE!>TA<!>()
|
||||
private val test2co = <!INVISIBLE_REFERENCE!>TA<!>
|
||||
|
||||
@@ -18,7 +18,7 @@ private val test2co = TA
|
||||
|
||||
// FILE: file2.kt
|
||||
private val test1: <!INVISIBLE_REFERENCE!>C<!> = <!INVISIBLE_REFERENCE!>C<!>()
|
||||
private val test1co: <!INVISIBLE_REFERENCE!>C.Companion<!> = <!INVISIBLE_REFERENCE!>C<!>
|
||||
private val test1co: <!INVISIBLE_REFERENCE!>C<!>.Companion = <!INVISIBLE_REFERENCE!>C<!>
|
||||
|
||||
private val test2: <!INVISIBLE_REFERENCE!>TA<!> = <!INVISIBLE_REFERENCE!>TA<!>()
|
||||
private val test2co = <!INVISIBLE_REFERENCE!>TA<!>
|
||||
|
||||
+1
-1
@@ -8,6 +8,6 @@ private class Private {
|
||||
|
||||
import <!INVISIBLE_REFERENCE!>Private<!>.Public
|
||||
|
||||
private fun test_1(x: <!INVISIBLE_REFERENCE!>Private.Public<!>, y: <!INVISIBLE_REFERENCE!>Public<!>) {
|
||||
private fun test_1(x: <!INVISIBLE_REFERENCE!>Private<!>.Public, y: <!INVISIBLE_REFERENCE!>Public<!>) {
|
||||
|
||||
}
|
||||
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
// SKIP_TXT
|
||||
// FILE: a.kt
|
||||
package p
|
||||
|
||||
class FilteringSequence
|
||||
|
||||
// FILE: b.kt
|
||||
package kotlin.sequences
|
||||
|
||||
import p.*
|
||||
|
||||
interface I {
|
||||
val v1: FilteringSequence
|
||||
val <!EXPOSED_PROPERTY_TYPE!>v2<!>: <!INVISIBLE_REFERENCE!>IndexingSequence<String><!>
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// SKIP_TXT
|
||||
// FILE: a.kt
|
||||
package p
|
||||
|
||||
Reference in New Issue
Block a user