FIR JvmMappedScope: substitute type parameters in Java scope with Kotlin ones
Without it, override mapping does not work properly. NB: at this moment Java forEach often supersedes Kotlin forEach, because call isn't reported as erroneous properly.
This commit is contained in:
@@ -100,7 +100,7 @@ class JavaSymbolProvider(
|
|||||||
useLazyNestedClassifierScope = regularClass is FirJavaClass,
|
useLazyNestedClassifierScope = regularClass is FirJavaClass,
|
||||||
existingNames = (regularClass as? FirJavaClass)?.existingNestedClassifierNames
|
existingNames = (regularClass as? FirJavaClass)?.existingNestedClassifierNames
|
||||||
)
|
)
|
||||||
val wrappedDeclaredScope = wrapScopeWithJvmMapped(regularClass.classId, declaredScope, useSiteSession, scopeSession)
|
val wrappedDeclaredScope = wrapScopeWithJvmMapped(regularClass, declaredScope, useSiteSession, scopeSession)
|
||||||
val superTypeEnhancementScopes =
|
val superTypeEnhancementScopes =
|
||||||
lookupSuperTypes(regularClass, lookupInterfaces = true, deep = false, useSiteSession = useSiteSession)
|
lookupSuperTypes(regularClass, lookupInterfaces = true, deep = false, useSiteSession = useSiteSession)
|
||||||
.mapNotNull { useSiteSuperType ->
|
.mapNotNull { useSiteSuperType ->
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ import org.jetbrains.kotlin.fir.scopes.jvm.JvmMappedScope
|
|||||||
import org.jetbrains.kotlin.fir.symbols.*
|
import org.jetbrains.kotlin.fir.symbols.*
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||||
import org.jetbrains.kotlin.fir.types.ConeClassErrorType
|
import org.jetbrains.kotlin.fir.types.ConeClassErrorType
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||||
|
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
|
||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
@@ -57,11 +59,12 @@ abstract class FirSymbolProvider : FirSessionComponent {
|
|||||||
): FirScope?
|
): FirScope?
|
||||||
|
|
||||||
protected fun wrapScopeWithJvmMapped(
|
protected fun wrapScopeWithJvmMapped(
|
||||||
classId: ClassId,
|
klass: FirClass<*>,
|
||||||
declaredMemberScope: FirScope,
|
declaredMemberScope: FirScope,
|
||||||
useSiteSession: FirSession,
|
useSiteSession: FirSession,
|
||||||
scopeSession: ScopeSession
|
scopeSession: ScopeSession
|
||||||
): FirScope {
|
): FirScope {
|
||||||
|
val classId = klass.classId
|
||||||
val javaClassId = JavaToKotlinClassMap.mapKotlinToJava(classId.asSingleFqName().toUnsafe())
|
val javaClassId = JavaToKotlinClassMap.mapKotlinToJava(classId.asSingleFqName().toUnsafe())
|
||||||
?: return declaredMemberScope
|
?: return declaredMemberScope
|
||||||
val symbolProvider = useSiteSession.firSymbolProvider
|
val symbolProvider = useSiteSession.firSymbolProvider
|
||||||
@@ -69,8 +72,17 @@ abstract class FirSymbolProvider : FirSessionComponent {
|
|||||||
?: return declaredMemberScope
|
?: return declaredMemberScope
|
||||||
val preparedSignatures = JvmMappedScope.prepareSignatures(javaClass)
|
val preparedSignatures = JvmMappedScope.prepareSignatures(javaClass)
|
||||||
return if (preparedSignatures.isNotEmpty()) {
|
return if (preparedSignatures.isNotEmpty()) {
|
||||||
symbolProvider.getClassUseSiteMemberScope(javaClassId, useSiteSession, scopeSession)?.let {
|
symbolProvider.getClassUseSiteMemberScope(javaClassId, useSiteSession, scopeSession)?.let { javaClassUseSiteScope ->
|
||||||
JvmMappedScope(declaredMemberScope, it, preparedSignatures)
|
val jvmMappedScope = JvmMappedScope(declaredMemberScope, javaClassUseSiteScope, preparedSignatures)
|
||||||
|
if (klass !is FirRegularClass) {
|
||||||
|
jvmMappedScope
|
||||||
|
} else {
|
||||||
|
// We should substitute Java type parameters with base Kotlin type parameters to match overrides perfectly
|
||||||
|
(klass.symbol.constructType(
|
||||||
|
klass.typeParameters.map { ConeTypeParameterTypeImpl(it.symbol.toLookupTag(), false) }.toTypedArray(),
|
||||||
|
false
|
||||||
|
) as ConeClassLikeType).wrapSubstitutionScopeIfNeed(useSiteSession, jvmMappedScope, klass, scopeSession)
|
||||||
|
}
|
||||||
} ?: declaredMemberScope
|
} ?: declaredMemberScope
|
||||||
} else {
|
} else {
|
||||||
declaredMemberScope
|
declaredMemberScope
|
||||||
@@ -82,7 +94,7 @@ abstract class FirSymbolProvider : FirSessionComponent {
|
|||||||
|
|
||||||
val declaredScope = declaredMemberScope(klass)
|
val declaredScope = declaredMemberScope(klass)
|
||||||
val wrappedDeclaredScope = wrapScopeWithJvmMapped(
|
val wrappedDeclaredScope = wrapScopeWithJvmMapped(
|
||||||
klass.classId, declaredScope, useSiteSession, scopeSession
|
klass, declaredScope, useSiteSession, scopeSession
|
||||||
)
|
)
|
||||||
val scopes = lookupSuperTypes(klass, lookupInterfaces = true, deep = false, useSiteSession = useSiteSession)
|
val scopes = lookupSuperTypes(klass, lookupInterfaces = true, deep = false, useSiteSession = useSiteSession)
|
||||||
.mapNotNull { useSiteSuperType ->
|
.mapNotNull { useSiteSuperType ->
|
||||||
|
|||||||
@@ -15,14 +15,14 @@ import org.jetbrains.kotlin.name.Name
|
|||||||
|
|
||||||
class JvmMappedScope(
|
class JvmMappedScope(
|
||||||
private val declaredMemberScope: FirScope,
|
private val declaredMemberScope: FirScope,
|
||||||
private val javaMappedScope: FirScope,
|
private val javaMappedClassUseSiteScope: FirScope,
|
||||||
private val whiteListSignaturesByName: Map<Name, List<String>>
|
private val whiteListSignaturesByName: Map<Name, List<String>>
|
||||||
) : FirScope() {
|
) : FirScope() {
|
||||||
|
|
||||||
override fun processFunctionsByName(name: Name, processor: (FirFunctionSymbol<*>) -> ProcessorAction): ProcessorAction {
|
override fun processFunctionsByName(name: Name, processor: (FirFunctionSymbol<*>) -> ProcessorAction): ProcessorAction {
|
||||||
val whiteListSignatures = whiteListSignaturesByName[name]
|
val whiteListSignatures = whiteListSignaturesByName[name]
|
||||||
?: return declaredMemberScope.processFunctionsByName(name, processor)
|
?: return declaredMemberScope.processFunctionsByName(name, processor)
|
||||||
if (!javaMappedScope.processFunctionsByName(name) { symbol ->
|
if (!javaMappedClassUseSiteScope.processFunctionsByName(name) { symbol ->
|
||||||
val jvmSignature = symbol.fir.computeJvmDescriptor()
|
val jvmSignature = symbol.fir.computeJvmDescriptor()
|
||||||
if (jvmSignature !in whiteListSignatures) {
|
if (jvmSignature !in whiteListSignatures) {
|
||||||
ProcessorAction.NEXT
|
ProcessorAction.NEXT
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
// FULL_JDK
|
||||||
|
// FILE: Call.java
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public interface Call<D> {
|
||||||
|
@NotNull
|
||||||
|
Map<String, String> getArguments();
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: test.kt
|
||||||
|
|
||||||
|
fun <D : Any> Call<D>.testForEach() {
|
||||||
|
arguments.forEach { key, value ->
|
||||||
|
key.length
|
||||||
|
value.length
|
||||||
|
}
|
||||||
|
arguments.forEach {
|
||||||
|
<!UNRESOLVED_REFERENCE!>it<!>.<!UNRESOLVED_REFERENCE!>key<!>.<!UNRESOLVED_REFERENCE!>length<!>
|
||||||
|
<!UNRESOLVED_REFERENCE!>it<!>.<!UNRESOLVED_REFERENCE!>value<!>.<!UNRESOLVED_REFERENCE!>length<!>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
FILE: test.kt
|
||||||
|
public final fun <D : R|kotlin/Any|> R|Call<D>|.testForEach(): R|kotlin/Unit| {
|
||||||
|
R|/Call.arguments|.R|FakeOverride<java/util/Map.forEach: R|kotlin/Unit|>|(<L> = forEach@fun <anonymous>(key: R|kotlin/String!|, value: R|kotlin/String!|): R|kotlin/Unit| {
|
||||||
|
R|<local>/key|.R|kotlin/String.length|
|
||||||
|
R|<local>/value|.R|kotlin/String.length|
|
||||||
|
}
|
||||||
|
)
|
||||||
|
R|/Call.arguments|.R|FakeOverride<java/util/Map.forEach: R|kotlin/Unit|>|(<L> = forEach@fun <anonymous>(): R|kotlin/Unit| {
|
||||||
|
<Unresolved name: it>#.<Unresolved name: key>#.<Unresolved name: length>#
|
||||||
|
<Unresolved name: it>#.<Unresolved name: value>#.<Unresolved name: length>#
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
interface Diagnostic {
|
||||||
|
val name: String
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo(conflicting: List<Diagnostic>) {
|
||||||
|
val filtered = arrayListOf<Diagnostic>()
|
||||||
|
conflicting.groupBy {
|
||||||
|
it.name
|
||||||
|
}.forEach {
|
||||||
|
val diagnostics = <!UNRESOLVED_REFERENCE!>it<!>.<!UNRESOLVED_REFERENCE!>value<!>
|
||||||
|
filtered.addAll(
|
||||||
|
diagnostics.<!AMBIGUITY!>filter<!> { me ->
|
||||||
|
diagnostics.<!AMBIGUITY!>none<!> { other ->
|
||||||
|
me != other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
FILE: noneWithForEach.kt
|
||||||
|
public abstract interface Diagnostic : R|kotlin/Any| {
|
||||||
|
public abstract val name: R|kotlin/String|
|
||||||
|
public get(): R|kotlin/String|
|
||||||
|
|
||||||
|
}
|
||||||
|
public final fun foo(conflicting: R|kotlin/collections/List<Diagnostic>|): R|kotlin/Unit| {
|
||||||
|
lval filtered: R|kotlin/collections/ArrayList<Diagnostic>| = R|kotlin/collections/arrayListOf|<R|Diagnostic|>()
|
||||||
|
R|<local>/conflicting|.R|kotlin/collections/groupBy|<R|Diagnostic|, R|kotlin/String|>(<L> = groupBy@fun <anonymous>(it: R|Diagnostic|): R|kotlin/String| <kind=UNKNOWN> {
|
||||||
|
R|<local>/it|.R|/Diagnostic.name|
|
||||||
|
}
|
||||||
|
).R|FakeOverride<java/util/Map.forEach: R|kotlin/Unit|>|(<L> = forEach@fun <anonymous>(): R|kotlin/Unit| {
|
||||||
|
lval diagnostics: <ERROR TYPE REF: Unresolved name: value> = <Unresolved name: it>#.<Unresolved name: value>#
|
||||||
|
R|<local>/filtered|.R|FakeOverride<java/util/ArrayList.addAll: R|kotlin/Boolean|>|(R|<local>/diagnostics|.<Ambiguity: filter, [kotlin/collections/filter, kotlin/collections/filter, kotlin/collections/filter, kotlin/collections/filter, kotlin/collections/filter, kotlin/collections/filter, kotlin/collections/filter, kotlin/collections/filter, kotlin/collections/filter, kotlin/collections/filter, kotlin/collections/filter, kotlin/collections/filter, kotlin/collections/filter, kotlin/collections/filter, kotlin/collections/filter, kotlin/sequences/filter, kotlin/text/filter, kotlin/text/filter]>#(<L> = filter@fun <anonymous>(me: R|class error: No type for parameter|): <ERROR TYPE REF: Ambiguity: none, [kotlin/collections/none, kotlin/collections/none, kotlin/collections/none, kotlin/collections/none, kotlin/collections/none, kotlin/collections/none, kotlin/collections/none, kotlin/collections/none, kotlin/collections/none, kotlin/collections/none, kotlin/collections/none, kotlin/collections/none, kotlin/collections/none, kotlin/collections/none, kotlin/collections/none, kotlin/sequences/none, kotlin/text/none]> {
|
||||||
|
R|<local>/diagnostics|.<Ambiguity: none, [kotlin/collections/none, kotlin/collections/none, kotlin/collections/none, kotlin/collections/none, kotlin/collections/none, kotlin/collections/none, kotlin/collections/none, kotlin/collections/none, kotlin/collections/none, kotlin/collections/none, kotlin/collections/none, kotlin/collections/none, kotlin/collections/none, kotlin/collections/none, kotlin/collections/none, kotlin/sequences/none, kotlin/text/none]>#(<L> = none@fun <anonymous>(other: R|class error: No type for parameter|): R|kotlin/Boolean| {
|
||||||
|
!=(R|<local>/me|, R|<local>/other|)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
Generated
+10
@@ -133,6 +133,11 @@ public class FirDiagnosticsWithStdlibTestGenerated extends AbstractFirDiagnostic
|
|||||||
runTest("compiler/fir/resolve/testData/resolve/stdlib/multipleImplicitReceivers.kt");
|
runTest("compiler/fir/resolve/testData/resolve/stdlib/multipleImplicitReceivers.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("noneWithForEach.kt")
|
||||||
|
public void testNoneWithForEach() throws Exception {
|
||||||
|
runTest("compiler/fir/resolve/testData/resolve/stdlib/noneWithForEach.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("nullableTypeParameter.kt")
|
@TestMetadata("nullableTypeParameter.kt")
|
||||||
public void testNullableTypeParameter() throws Exception {
|
public void testNullableTypeParameter() throws Exception {
|
||||||
runTest("compiler/fir/resolve/testData/resolve/stdlib/nullableTypeParameter.kt");
|
runTest("compiler/fir/resolve/testData/resolve/stdlib/nullableTypeParameter.kt");
|
||||||
@@ -524,6 +529,11 @@ public class FirDiagnosticsWithStdlibTestGenerated extends AbstractFirDiagnostic
|
|||||||
runTest("compiler/fir/resolve/testData/resolve/stdlib/j+k/StaticGenericMethod.kt");
|
runTest("compiler/fir/resolve/testData/resolve/stdlib/j+k/StaticGenericMethod.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("SyntheticWithForEach.kt")
|
||||||
|
public void testSyntheticWithForEach() throws Exception {
|
||||||
|
runTest("compiler/fir/resolve/testData/resolve/stdlib/j+k/SyntheticWithForEach.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("typeParameterUse.kt")
|
@TestMetadata("typeParameterUse.kt")
|
||||||
public void testTypeParameterUse() throws Exception {
|
public void testTypeParameterUse() throws Exception {
|
||||||
runTest("compiler/fir/resolve/testData/resolve/stdlib/j+k/typeParameterUse.kt");
|
runTest("compiler/fir/resolve/testData/resolve/stdlib/j+k/typeParameterUse.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user