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,
|
||||
existingNames = (regularClass as? FirJavaClass)?.existingNestedClassifierNames
|
||||
)
|
||||
val wrappedDeclaredScope = wrapScopeWithJvmMapped(regularClass.classId, declaredScope, useSiteSession, scopeSession)
|
||||
val wrappedDeclaredScope = wrapScopeWithJvmMapped(regularClass, declaredScope, useSiteSession, scopeSession)
|
||||
val superTypeEnhancementScopes =
|
||||
lookupSuperTypes(regularClass, lookupInterfaces = true, deep = false, useSiteSession = useSiteSession)
|
||||
.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.impl.*
|
||||
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.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
@@ -57,11 +59,12 @@ abstract class FirSymbolProvider : FirSessionComponent {
|
||||
): FirScope?
|
||||
|
||||
protected fun wrapScopeWithJvmMapped(
|
||||
classId: ClassId,
|
||||
klass: FirClass<*>,
|
||||
declaredMemberScope: FirScope,
|
||||
useSiteSession: FirSession,
|
||||
scopeSession: ScopeSession
|
||||
): FirScope {
|
||||
val classId = klass.classId
|
||||
val javaClassId = JavaToKotlinClassMap.mapKotlinToJava(classId.asSingleFqName().toUnsafe())
|
||||
?: return declaredMemberScope
|
||||
val symbolProvider = useSiteSession.firSymbolProvider
|
||||
@@ -69,8 +72,17 @@ abstract class FirSymbolProvider : FirSessionComponent {
|
||||
?: return declaredMemberScope
|
||||
val preparedSignatures = JvmMappedScope.prepareSignatures(javaClass)
|
||||
return if (preparedSignatures.isNotEmpty()) {
|
||||
symbolProvider.getClassUseSiteMemberScope(javaClassId, useSiteSession, scopeSession)?.let {
|
||||
JvmMappedScope(declaredMemberScope, it, preparedSignatures)
|
||||
symbolProvider.getClassUseSiteMemberScope(javaClassId, useSiteSession, scopeSession)?.let { javaClassUseSiteScope ->
|
||||
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
|
||||
} else {
|
||||
declaredMemberScope
|
||||
@@ -82,7 +94,7 @@ abstract class FirSymbolProvider : FirSessionComponent {
|
||||
|
||||
val declaredScope = declaredMemberScope(klass)
|
||||
val wrappedDeclaredScope = wrapScopeWithJvmMapped(
|
||||
klass.classId, declaredScope, useSiteSession, scopeSession
|
||||
klass, declaredScope, useSiteSession, scopeSession
|
||||
)
|
||||
val scopes = lookupSuperTypes(klass, lookupInterfaces = true, deep = false, useSiteSession = useSiteSession)
|
||||
.mapNotNull { useSiteSuperType ->
|
||||
|
||||
@@ -15,14 +15,14 @@ import org.jetbrains.kotlin.name.Name
|
||||
|
||||
class JvmMappedScope(
|
||||
private val declaredMemberScope: FirScope,
|
||||
private val javaMappedScope: FirScope,
|
||||
private val javaMappedClassUseSiteScope: FirScope,
|
||||
private val whiteListSignaturesByName: Map<Name, List<String>>
|
||||
) : FirScope() {
|
||||
|
||||
override fun processFunctionsByName(name: Name, processor: (FirFunctionSymbol<*>) -> ProcessorAction): ProcessorAction {
|
||||
val whiteListSignatures = whiteListSignaturesByName[name]
|
||||
?: return declaredMemberScope.processFunctionsByName(name, processor)
|
||||
if (!javaMappedScope.processFunctionsByName(name) { symbol ->
|
||||
if (!javaMappedClassUseSiteScope.processFunctionsByName(name) { symbol ->
|
||||
val jvmSignature = symbol.fir.computeJvmDescriptor()
|
||||
if (jvmSignature !in whiteListSignatures) {
|
||||
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");
|
||||
}
|
||||
|
||||
@TestMetadata("noneWithForEach.kt")
|
||||
public void testNoneWithForEach() throws Exception {
|
||||
runTest("compiler/fir/resolve/testData/resolve/stdlib/noneWithForEach.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("nullableTypeParameter.kt")
|
||||
public void testNullableTypeParameter() throws Exception {
|
||||
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");
|
||||
}
|
||||
|
||||
@TestMetadata("SyntheticWithForEach.kt")
|
||||
public void testSyntheticWithForEach() throws Exception {
|
||||
runTest("compiler/fir/resolve/testData/resolve/stdlib/j+k/SyntheticWithForEach.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeParameterUse.kt")
|
||||
public void testTypeParameterUse() throws Exception {
|
||||
runTest("compiler/fir/resolve/testData/resolve/stdlib/j+k/typeParameterUse.kt");
|
||||
|
||||
Reference in New Issue
Block a user