FIR: Support inherited default parameters

This commit is contained in:
Denis Zharkov
2019-11-21 12:24:36 +03:00
parent c9cb4dff52
commit 256f5ca0a1
6 changed files with 165 additions and 6 deletions
@@ -7,8 +7,14 @@ package org.jetbrains.kotlin.fir.java.scopes
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.impl.FirSimpleFunctionImpl
import org.jetbrains.kotlin.fir.declarations.impl.FirValueParameterImpl
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.java.JavaTypeParameterStack
import org.jetbrains.kotlin.fir.java.declarations.FirJavaClass
import org.jetbrains.kotlin.fir.java.declarations.FirJavaMethod
import org.jetbrains.kotlin.fir.java.declarations.FirJavaValueParameter
import org.jetbrains.kotlin.fir.java.types.FirJavaTypeRef
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
import org.jetbrains.kotlin.fir.scopes.ProcessorAction.NEXT
@@ -103,6 +109,31 @@ class JavaClassUseSiteMemberScope(
}
}
override fun createFunctionCopy(firSimpleFunction: FirSimpleFunction, newSymbol: FirNamedFunctionSymbol): FirSimpleFunctionImpl {
if (firSimpleFunction !is FirJavaMethod) return super.createFunctionCopy(firSimpleFunction, newSymbol)
return FirJavaMethod(
firSimpleFunction.session,
firSimpleFunction.source,
newSymbol,
firSimpleFunction.name,
firSimpleFunction.visibility,
firSimpleFunction.modality,
firSimpleFunction.returnTypeRef as FirJavaTypeRef,
firSimpleFunction.status.isStatic
)
}
override fun createValueParameterCopy(parameter: FirValueParameter, newDefaultValue: FirExpression?): FirValueParameterImpl {
if (parameter !is FirJavaValueParameter) return super.createValueParameterCopy(parameter, newDefaultValue)
return FirJavaValueParameter(
parameter.session,
parameter.source,
parameter.name,
parameter.returnTypeRef as FirJavaTypeRef,
parameter.isVararg
)
}
override fun processPropertiesByName(name: Name, processor: (FirCallableSymbol<*>) -> ProcessorAction): ProcessorAction {
val getterName = Name.identifier(getterPrefix + name.asString().capitalize())
return processAccessorFunctionsAndPropertiesByName(name, getterName, isGetter = true, processor = processor)
@@ -13,7 +13,7 @@ import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
abstract class AbstractFirOverrideScope(val session: FirSession, private val overrideChecker: FirOverrideChecker) : FirScope() {
abstract class AbstractFirOverrideScope(val session: FirSession, protected val overrideChecker: FirOverrideChecker) : FirScope() {
//base symbol as key, overridden as value
val overrideByBase = mutableMapOf<FirCallableSymbol<*>, FirCallableSymbol<*>?>()
@@ -55,4 +55,4 @@ abstract class AbstractFirOverrideScope(val session: FirSession, private val ove
return override
}
}
}
@@ -6,11 +6,19 @@
package org.jetbrains.kotlin.fir.scopes.impl
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirFunction
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
import org.jetbrains.kotlin.fir.declarations.impl.FirSimpleFunctionImpl
import org.jetbrains.kotlin.fir.declarations.impl.FirValueParameterImpl
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.scopes.FirOverrideChecker
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
import org.jetbrains.kotlin.name.Name
abstract class AbstractFirUseSiteMemberScope(
@@ -22,13 +30,13 @@ abstract class AbstractFirUseSiteMemberScope(
override fun processFunctionsByName(name: Name, processor: (FirFunctionSymbol<*>) -> ProcessorAction): ProcessorAction {
val overrideCandidates = mutableSetOf<FirFunctionSymbol<*>>()
if (!declaredMemberScope.processFunctionsByName(name) {
overrideCandidates += it
processor(it)
val symbol = processInheritedDefaultParameters(it)
overrideCandidates += symbol
processor(symbol)
}
) return ProcessorAction.STOP
return superTypesScope.processFunctionsByName(name) {
val overriddenBy = it.getOverridden(overrideCandidates)
if (overriddenBy == null) {
processor(it)
@@ -38,6 +46,70 @@ abstract class AbstractFirUseSiteMemberScope(
}
}
private fun processInheritedDefaultParameters(symbol: FirFunctionSymbol<*>): FirFunctionSymbol<*> {
val firSimpleFunction = symbol.fir as? FirSimpleFunction ?: return symbol
if (firSimpleFunction.valueParameters.isEmpty() || firSimpleFunction.valueParameters.any { it.defaultValue != null }) return symbol
var foundFir: FirFunction<*>? = null
superTypesScope.processFunctionsByName(symbol.callableId.callableName) { superSymbol ->
val superFunctionFir = superSymbol.fir
if (superFunctionFir is FirSimpleFunction && overrideChecker.isOverriddenFunction(firSimpleFunction, superFunctionFir) &&
superFunctionFir.valueParameters.any { parameter -> parameter.defaultValue != null }
) {
foundFir = superFunctionFir
ProcessorAction.STOP
} else {
ProcessorAction.NEXT
}
}
if (foundFir == null) return symbol
val newSymbol = FirNamedFunctionSymbol(symbol.callableId, false, null)
createFunctionCopy(firSimpleFunction, newSymbol).apply {
resolvePhase = firSimpleFunction.resolvePhase
typeParameters += firSimpleFunction.typeParameters
valueParameters += firSimpleFunction.valueParameters.zip(foundFir.valueParameters)
.map { (overrideParameter, overriddenParameter) ->
if (overriddenParameter.defaultValue != null)
createValueParameterCopy(overrideParameter, overriddenParameter.defaultValue).apply {
annotations += overrideParameter.annotations
}
else
overrideParameter
}
}
return newSymbol
}
protected open fun createFunctionCopy(firSimpleFunction: FirSimpleFunction, newSymbol: FirNamedFunctionSymbol): FirSimpleFunctionImpl =
FirSimpleFunctionImpl(
firSimpleFunction.source,
firSimpleFunction.session,
firSimpleFunction.returnTypeRef,
firSimpleFunction.receiverTypeRef,
firSimpleFunction.name,
firSimpleFunction.status,
newSymbol
)
protected open fun createValueParameterCopy(parameter: FirValueParameter, newDefaultValue: FirExpression?): FirValueParameterImpl =
with(parameter) {
FirValueParameterImpl(
source,
session,
returnTypeRef,
name,
FirVariableSymbol(parameter.symbol.callableId),
newDefaultValue,
isCrossinline,
isNoinline,
isVararg
)
}
override fun processClassifiersByName(
name: Name,
processor: (FirClassifierSymbol<*>) -> ProcessorAction
@@ -47,4 +119,4 @@ abstract class AbstractFirUseSiteMemberScope(
}
return superTypesScope.processClassifiersByName(name, processor)
}
}
}
@@ -0,0 +1,22 @@
interface I1 {
fun foo(x: Int = 1)
}
interface I2 {
fun bar(x: String = "", y: Int)
}
class A : I1, I2 {
override fun foo(x: Int) {}
override fun bar(x: String, y: Int) {}
}
fun foo(a: A) {
a.foo()
a.foo(1)
a.<!INAPPLICABLE_CANDIDATE!>bar<!>()
a.<!INAPPLICABLE_CANDIDATE!>bar<!>("")
a.bar(y = 1)
a.bar("", 2)
}
@@ -0,0 +1,29 @@
FILE: defaultFromOverrides.kt
public abstract interface I1 : R|kotlin/Any| {
public abstract fun foo(x: R|kotlin/Int| = Int(1)): R|kotlin/Unit|
}
public abstract interface I2 : R|kotlin/Any| {
public abstract fun bar(x: R|kotlin/String| = String(), y: R|kotlin/Int|): R|kotlin/Unit|
}
public final class A : R|I1|, R|I2| {
public constructor(): R|A| {
super<R|kotlin/Any|>()
}
public final override fun foo(x: R|kotlin/Int|): R|kotlin/Unit| {
}
public final override fun bar(x: R|kotlin/String|, y: R|kotlin/Int|): R|kotlin/Unit| {
}
}
public final fun foo(a: R|A|): R|kotlin/Unit| {
R|<local>/a|.R|/A.foo|()
R|<local>/a|.R|/A.foo|(Int(1))
R|<local>/a|.<Inapplicable(PARAMETER_MAPPING_ERROR): [/A.bar]>#()
R|<local>/a|.<Inapplicable(PARAMETER_MAPPING_ERROR): [/A.bar]>#(String())
R|<local>/a|.R|/A.bar|(y = Int(1))
R|<local>/a|.R|/A.bar|(String(), Int(2))
}
@@ -245,6 +245,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
runTest("compiler/fir/resolve/testData/resolve/arguments/default.kt");
}
@TestMetadata("defaultFromOverrides.kt")
public void testDefaultFromOverrides() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/arguments/defaultFromOverrides.kt");
}
@TestMetadata("fieldPlusAssign.kt")
public void testFieldPlusAssign() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/arguments/fieldPlusAssign.kt");