[FIR] Implement ADAPTED_CALLABLE_REFERENCE_AGAINST_REFLECTION_TYPE diagnostic
#KT-59401 Fixed
This commit is contained in:
committed by
Space Team
parent
d91000e39c
commit
789f886d3c
+6
@@ -2597,6 +2597,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.ADAPTED_CALLABLE_REFERENCE_AGAINST_REFLECTION_TYPE) { firDiagnostic ->
|
||||
AdaptedCallableReferenceAgainstReflectionTypeImpl(
|
||||
firDiagnostic as KtPsiDiagnostic,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.CLASS_LITERAL_LHS_NOT_A_CLASS) { firDiagnostic ->
|
||||
ClassLiteralLhsNotAClassImpl(
|
||||
firDiagnostic as KtPsiDiagnostic,
|
||||
|
||||
+4
@@ -1841,6 +1841,10 @@ sealed interface KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
override val diagnosticClass get() = CallableReferenceToAnnotationConstructor::class
|
||||
}
|
||||
|
||||
interface AdaptedCallableReferenceAgainstReflectionType : KtFirDiagnostic<KtExpression> {
|
||||
override val diagnosticClass get() = AdaptedCallableReferenceAgainstReflectionType::class
|
||||
}
|
||||
|
||||
interface ClassLiteralLhsNotAClass : KtFirDiagnostic<KtExpression> {
|
||||
override val diagnosticClass get() = ClassLiteralLhsNotAClass::class
|
||||
}
|
||||
|
||||
+5
@@ -2212,6 +2212,11 @@ internal class CallableReferenceToAnnotationConstructorImpl(
|
||||
token: KtLifetimeToken,
|
||||
) : KtAbstractFirDiagnostic<KtExpression>(firDiagnostic, token), KtFirDiagnostic.CallableReferenceToAnnotationConstructor
|
||||
|
||||
internal class AdaptedCallableReferenceAgainstReflectionTypeImpl(
|
||||
firDiagnostic: KtPsiDiagnostic,
|
||||
token: KtLifetimeToken,
|
||||
) : KtAbstractFirDiagnostic<KtExpression>(firDiagnostic, token), KtFirDiagnostic.AdaptedCallableReferenceAgainstReflectionType
|
||||
|
||||
internal class ClassLiteralLhsNotAClassImpl(
|
||||
firDiagnostic: KtPsiDiagnostic,
|
||||
token: KtLifetimeToken,
|
||||
|
||||
+1
@@ -872,6 +872,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
}
|
||||
val CALLABLE_REFERENCE_LHS_NOT_A_CLASS by error<KtExpression>()
|
||||
val CALLABLE_REFERENCE_TO_ANNOTATION_CONSTRUCTOR by error<KtExpression>(PositioningStrategy.REFERENCE_BY_QUALIFIED)
|
||||
val ADAPTED_CALLABLE_REFERENCE_AGAINST_REFLECTION_TYPE by error<KtExpression>()
|
||||
|
||||
val CLASS_LITERAL_LHS_NOT_A_CLASS by error<KtExpression>()
|
||||
val NULLABLE_TYPE_IN_CLASS_LITERAL_LHS by error<KtExpression>()
|
||||
|
||||
@@ -488,6 +488,7 @@ object FirErrors {
|
||||
val EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED by error1<KtExpression, FirCallableSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
val CALLABLE_REFERENCE_LHS_NOT_A_CLASS by error0<KtExpression>()
|
||||
val CALLABLE_REFERENCE_TO_ANNOTATION_CONSTRUCTOR by error0<KtExpression>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
val ADAPTED_CALLABLE_REFERENCE_AGAINST_REFLECTION_TYPE by error0<KtExpression>()
|
||||
val CLASS_LITERAL_LHS_NOT_A_CLASS by error0<KtExpression>()
|
||||
val NULLABLE_TYPE_IN_CLASS_LITERAL_LHS by error0<KtExpression>()
|
||||
val EXPRESSION_OF_NULLABLE_TYPE_IN_CLASS_LITERAL_LHS by error1<PsiElement, ConeKotlinType>()
|
||||
|
||||
+1
@@ -319,6 +319,7 @@ val FIR_NON_SUPPRESSIBLE_ERROR_NAMES: Set<String> = setOf(
|
||||
"EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED",
|
||||
"CALLABLE_REFERENCE_LHS_NOT_A_CLASS",
|
||||
"CALLABLE_REFERENCE_TO_ANNOTATION_CONSTRUCTOR",
|
||||
"ADAPTED_CALLABLE_REFERENCE_AGAINST_REFLECTION_TYPE",
|
||||
"CLASS_LITERAL_LHS_NOT_A_CLASS",
|
||||
"NULLABLE_TYPE_IN_CLASS_LITERAL_LHS",
|
||||
"EXPRESSION_OF_NULLABLE_TYPE_IN_CLASS_LITERAL_LHS",
|
||||
|
||||
+5
@@ -72,6 +72,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_TYPE_ALIAS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_TYPE_ALIAS_WITH_COMPLEX_SUBSTITUTION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_TYPE_ALIAS_WITH_USE_SITE_VARIANCE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_WITHOUT_EXPECT
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ADAPTED_CALLABLE_REFERENCE_AGAINST_REFLECTION_TYPE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.AMBIGUOUS_ACTUALS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.AMBIGUOUS_ALTERED_ASSIGN
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.AMBIGUOUS_ANNOTATION_ARGUMENT
|
||||
@@ -1474,6 +1475,10 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
|
||||
)
|
||||
map.put(CALLABLE_REFERENCE_LHS_NOT_A_CLASS, "Left-hand side of callable reference cannot be a type parameter.")
|
||||
map.put(CALLABLE_REFERENCE_TO_ANNOTATION_CONSTRUCTOR, "Annotation class cannot be instantiated.")
|
||||
map.put(
|
||||
ADAPTED_CALLABLE_REFERENCE_AGAINST_REFLECTION_TYPE,
|
||||
"Adapted callable reference cannot be resolved against reflective types."
|
||||
)
|
||||
|
||||
map.put(CLASS_LITERAL_LHS_NOT_A_CLASS, "Only classes are allowed on the left-hand side of a class literal.")
|
||||
map.put(NULLABLE_TYPE_IN_CLASS_LITERAL_LHS, "Type in a class literal must not be nullable.")
|
||||
|
||||
+2
@@ -358,6 +358,8 @@ private fun mapInapplicableCandidateError(
|
||||
isError = rootCause.isError
|
||||
)
|
||||
|
||||
is AdaptedCallableReferenceIsUsedWithReflection -> FirErrors.ADAPTED_CALLABLE_REFERENCE_AGAINST_REFLECTION_TYPE.createOn(source)
|
||||
|
||||
else -> genericDiagnostic
|
||||
}
|
||||
}.distinct()
|
||||
|
||||
@@ -400,8 +400,9 @@ class FirCallResolver(
|
||||
manager = TowerResolveManager(localCollector),
|
||||
)
|
||||
}
|
||||
val isSuccess = result.currentApplicability.isSuccess
|
||||
|
||||
val (reducedCandidates, newApplicability) = reduceCandidates(result, callableReferenceAccess.explicitReceiver)
|
||||
val isSuccess = reducedCandidates.isNotEmpty() && reducedCandidates.all { it.isSuccessful }
|
||||
val applicability = newApplicability ?: result.currentApplicability
|
||||
|
||||
(callableReferenceAccess.explicitReceiver as? FirResolvedQualifier)?.replaceResolvedToCompanionObject(
|
||||
|
||||
+44
-15
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.name.StandardClassIds
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemOperation
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.runTransaction
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.isSuccess
|
||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||
import org.jetbrains.kotlin.types.expressions.CoercionStrategy
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.shouldNotBeCalled
|
||||
import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment
|
||||
@@ -47,13 +48,31 @@ internal object CheckCallableReferenceExpectedType : CheckerStage() {
|
||||
|
||||
val fir: FirCallableDeclaration = candidate.symbol.fir as FirCallableDeclaration
|
||||
|
||||
val (rawResultingType, callableReferenceAdaptation) = buildReflectionType(fir, resultingReceiverType, candidate, context)
|
||||
val isExpectedTypeReflectionType = callInfo.expectedType?.isReflectFunctionType(callInfo.session) == true
|
||||
val (rawResultingType, callableReferenceAdaptation) = buildResultingTypeAndAdaptation(
|
||||
fir,
|
||||
resultingReceiverType,
|
||||
candidate,
|
||||
context,
|
||||
// If the input and output types match the expected type but the expected type is a reflection type, and we need an adaptation,
|
||||
// we want to report AdaptedCallableReferenceIsUsedWithReflection but *not* InapplicableCandidate because
|
||||
// AdaptedCallableReferenceIsUsedWithReflection has the higher applicability.
|
||||
// Therefore, we force a reflection type whenever the expected type is a reflection type.
|
||||
//
|
||||
// If the input and output types end up not matching, we'll report InapplicableCandidate, regardless of whether the
|
||||
// expected/actual type is a reflection type.
|
||||
forceReflectionType = isExpectedTypeReflectionType
|
||||
)
|
||||
val resultingType = candidate.substitutor.substituteOrSelf(rawResultingType)
|
||||
|
||||
if (callableReferenceAdaptation.needCompatibilityResolveForCallableReference()) {
|
||||
if (callableReferenceAdaptation != null) {
|
||||
if (!context.session.languageVersionSettings.supportsFeature(LanguageFeature.DisableCompatibilityModeForNewInference)) {
|
||||
sink.reportDiagnostic(LowerPriorityToPreserveCompatibilityDiagnostic)
|
||||
}
|
||||
|
||||
if (isExpectedTypeReflectionType) {
|
||||
sink.reportDiagnostic(AdaptedCallableReferenceIsUsedWithReflection)
|
||||
}
|
||||
}
|
||||
|
||||
candidate.resultingTypeForCallableReference = resultingType
|
||||
@@ -88,11 +107,17 @@ internal object CheckCallableReferenceExpectedType : CheckerStage() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildReflectionType(
|
||||
/**
|
||||
* The resulting type is a reflection type ([FunctionTypeKind.reflectKind])
|
||||
* iff the adaptation is `null` or [forceReflectionType]` == true`.
|
||||
* Otherwise, it's a non-reflection type ([FunctionTypeKind.nonReflectKind]).
|
||||
*/
|
||||
private fun buildResultingTypeAndAdaptation(
|
||||
fir: FirCallableDeclaration,
|
||||
receiverType: ConeKotlinType?,
|
||||
candidate: Candidate,
|
||||
context: ResolutionContext
|
||||
context: ResolutionContext,
|
||||
forceReflectionType: Boolean,
|
||||
): Pair<ConeKotlinType, CallableReferenceAdaptation?> {
|
||||
val returnTypeRef = context.bodyResolveComponents.returnTypeCalculator.tryCalculateReturnType(fir)
|
||||
return when (fir) {
|
||||
@@ -128,7 +153,7 @@ private fun buildReflectionType(
|
||||
?: FunctionTypeKind.Function
|
||||
|
||||
return createFunctionType(
|
||||
if (callableReferenceAdaptation == null) baseFunctionTypeKind.reflectKind() else baseFunctionTypeKind.nonReflectKind(),
|
||||
if (callableReferenceAdaptation == null || forceReflectionType) baseFunctionTypeKind.reflectKind() else baseFunctionTypeKind.nonReflectKind(),
|
||||
parameters,
|
||||
receiverType = receiverType.takeIf { fir.receiverParameter != null },
|
||||
rawReturnType = returnType,
|
||||
@@ -145,16 +170,20 @@ internal class CallableReferenceAdaptation(
|
||||
val coercionStrategy: CoercionStrategy,
|
||||
val defaults: Int,
|
||||
val mappedArguments: CallableReferenceMappedArguments,
|
||||
val suspendConversionStrategy: CallableReferenceConversionStrategy
|
||||
)
|
||||
|
||||
private fun CallableReferenceAdaptation?.needCompatibilityResolveForCallableReference(): Boolean {
|
||||
// KT-13934: check containing declaration for companion object
|
||||
if (this == null) return false
|
||||
return defaults != 0 ||
|
||||
suspendConversionStrategy != CallableReferenceConversionStrategy.NoConversion ||
|
||||
coercionStrategy != CoercionStrategy.NO_COERCION ||
|
||||
mappedArguments.values.any { it is ResolvedCallArgument.VarargArgument }
|
||||
val suspendConversionStrategy: CallableReferenceConversionStrategy,
|
||||
) {
|
||||
init {
|
||||
if (AbstractTypeChecker.RUN_SLOW_ASSERTIONS) {
|
||||
require(
|
||||
defaults != 0 ||
|
||||
suspendConversionStrategy != CallableReferenceConversionStrategy.NoConversion ||
|
||||
coercionStrategy != CoercionStrategy.NO_COERCION ||
|
||||
mappedArguments.values.any { it is ResolvedCallArgument.VarargArgument }
|
||||
) {
|
||||
"Adaptation must be non-trivial."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun BodyResolveComponents.getCallableReferenceAdaptation(
|
||||
|
||||
+2
@@ -146,3 +146,5 @@ class AmbiguousValuesForContextReceiverParameter(
|
||||
) : ResolutionDiagnostic(INAPPLICABLE)
|
||||
|
||||
object ResolutionResultOverridesOtherToPreserveCompatibility : ResolutionDiagnostic(RESOLVED)
|
||||
|
||||
object AdaptedCallableReferenceIsUsedWithReflection : ResolutionDiagnostic(RESOLVED_WITH_ERROR)
|
||||
Vendored
+2
-2
@@ -3,12 +3,12 @@ fun foo(x: String = "O"): String = x
|
||||
fun bar(x: String = "K"): String = x
|
||||
|
||||
fun dump(dumpStrategy: String) {
|
||||
val k0: kotlin.reflect.KFunction0<String> = returnAdapter(::<!INAPPLICABLE_CANDIDATE!>foo<!>) // Error: ADAPTED_CALLABLE_REFERENCE_AGAINST_REFLECTION_TYPE
|
||||
val k0: kotlin.reflect.KFunction0<String> = returnAdapter(<!ADAPTED_CALLABLE_REFERENCE_AGAINST_REFLECTION_TYPE!>::foo<!>) // Error: ADAPTED_CALLABLE_REFERENCE_AGAINST_REFLECTION_TYPE
|
||||
val k1: kotlin.reflect.KFunction0<String> = <!INITIALIZER_TYPE_MISMATCH!>::foo<!>
|
||||
// Should be error here, too
|
||||
val k2: kotlin.reflect.KFunction0<String> = <!INITIALIZER_TYPE_MISMATCH, TYPE_MISMATCH!>if (dumpStrategy == "KotlinLike") ::foo else ::bar<!>
|
||||
|
||||
val f0: Function0<String> = returnAdapter(::<!INAPPLICABLE_CANDIDATE!>foo<!>)
|
||||
val f0: Function0<String> = returnAdapter(<!ADAPTED_CALLABLE_REFERENCE_AGAINST_REFLECTION_TYPE!>::foo<!>)
|
||||
val f1: Function0<String> = ::foo
|
||||
val f2: Function0<String> = if (dumpStrategy == "KotlinLike") ::foo else ::bar
|
||||
}
|
||||
|
||||
-27
@@ -1,27 +0,0 @@
|
||||
// !LANGUAGE: -AdaptedCallableReferenceAgainstReflectiveType +DisableCompatibilityModeForNewInference
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
import kotlin.reflect.KFunction1
|
||||
|
||||
fun foo(x: Int): Unit {} // (1)
|
||||
fun bar(f: KFunction1<Int, Unit>) {}
|
||||
|
||||
fun test() {
|
||||
bar(::foo) // OK, foo resolved to (1)
|
||||
}
|
||||
|
||||
object Scope {
|
||||
fun foo(x: Int, y: Int = 0): Int = 0 // (2)
|
||||
|
||||
fun test() {
|
||||
bar(::foo) // Error and foo should be resolved to (2)
|
||||
}
|
||||
}
|
||||
|
||||
object Local {
|
||||
fun baz(x: Int, y: Int = 0): Int = 0
|
||||
|
||||
fun test() {
|
||||
bar(::<!INAPPLICABLE_CANDIDATE!>baz<!>)
|
||||
}
|
||||
}
|
||||
+10
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !LANGUAGE: -AdaptedCallableReferenceAgainstReflectiveType +DisableCompatibilityModeForNewInference
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
@@ -15,6 +16,7 @@ object Scope {
|
||||
|
||||
fun test() {
|
||||
bar(<!ADAPTED_CALLABLE_REFERENCE_AGAINST_REFLECTION_TYPE!>::foo<!>) // Error and foo should be resolved to (2)
|
||||
bar(<!ADAPTED_CALLABLE_REFERENCE_AGAINST_REFLECTION_TYPE!>Scope::foo<!>) // Error and foo should be resolved to (2)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,3 +27,11 @@ object Local {
|
||||
bar(<!ADAPTED_CALLABLE_REFERENCE_AGAINST_REFLECTION_TYPE!>::baz<!>)
|
||||
}
|
||||
}
|
||||
|
||||
object WrongType {
|
||||
fun foo(x: String, y: Int = 0) {} // (3)
|
||||
|
||||
fun test() {
|
||||
bar(::foo) // Should resolve to (1) because (3) has wrong type on top of being adapted
|
||||
}
|
||||
}
|
||||
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
package
|
||||
|
||||
public fun bar(/*0*/ f: kotlin.reflect.KFunction1<kotlin.Int, kotlin.Unit>): kotlin.Unit
|
||||
public fun foo(/*0*/ x: kotlin.Int): kotlin.Unit
|
||||
public fun test(): kotlin.Unit
|
||||
|
||||
public object Local {
|
||||
private constructor Local()
|
||||
public final fun baz(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.Int = ...): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public final fun test(): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public object Scope {
|
||||
private constructor Scope()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public final fun foo(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.Int = ...): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public final fun test(): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+10
-1
@@ -15,6 +15,7 @@ object Scope {
|
||||
|
||||
fun test() {
|
||||
bar(::foo)
|
||||
bar(<!ADAPTED_CALLABLE_REFERENCE_AGAINST_REFLECTION_TYPE!>Scope::foo<!>)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +23,14 @@ object Local {
|
||||
fun baz(x: Int, y: Int = 0): Int = 0
|
||||
|
||||
fun test() {
|
||||
bar(::<!INAPPLICABLE_CANDIDATE!>baz<!>)
|
||||
bar(<!ADAPTED_CALLABLE_REFERENCE_AGAINST_REFLECTION_TYPE!>::baz<!>)
|
||||
}
|
||||
}
|
||||
|
||||
object WrongType {
|
||||
fun foo(x: String, y: Int = 0) {} // (3)
|
||||
|
||||
fun test() {
|
||||
bar(::foo) // Should resolve to (1) because (3) has wrong type on top of being adapted
|
||||
}
|
||||
}
|
||||
+9
@@ -15,6 +15,7 @@ object Scope {
|
||||
|
||||
fun test() {
|
||||
bar(<!COMPATIBILITY_WARNING!>::foo<!>)
|
||||
bar(<!ADAPTED_CALLABLE_REFERENCE_AGAINST_REFLECTION_TYPE!>Scope::foo<!>)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,3 +26,11 @@ object Local {
|
||||
bar(<!ADAPTED_CALLABLE_REFERENCE_AGAINST_REFLECTION_TYPE!>::baz<!>)
|
||||
}
|
||||
}
|
||||
|
||||
object WrongType {
|
||||
fun foo(x: String, y: Int = 0) {} // (3)
|
||||
|
||||
fun test() {
|
||||
bar(::foo) // Should resolve to (1) because (3) has wrong type on top of being adapted
|
||||
}
|
||||
}
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
package
|
||||
|
||||
public fun bar(/*0*/ f: kotlin.reflect.KFunction1<kotlin.Int, kotlin.Unit>): kotlin.Unit
|
||||
public fun foo(/*0*/ x: kotlin.Int): kotlin.Unit
|
||||
public fun test(): kotlin.Unit
|
||||
|
||||
public object Local {
|
||||
private constructor Local()
|
||||
public final fun baz(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.Int = ...): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public final fun test(): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public object Scope {
|
||||
private constructor Scope()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public final fun foo(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.Int = ...): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public final fun test(): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
Reference in New Issue
Block a user