[FIR] Create fake hidden versions of List.getFirst/getLast in JDK < 21

... so that overrides are marked as deprecated regardless of the JDK.

#KT-65440 Fixed
This commit is contained in:
Kirill Rakhman
2024-02-06 13:26:18 +01:00
committed by Space Team
parent c6b2675089
commit 2f49272c42
22 changed files with 399 additions and 3 deletions
@@ -62,6 +62,7 @@ internal tailrec fun FirDeclaration.ktSymbolOrigin(): KtSymbolOrigin = when (ori
FirDeclarationOrigin.Enhancement -> KtSymbolOrigin.JAVA
FirDeclarationOrigin.IntersectionOverride -> KtSymbolOrigin.INTERSECTION_OVERRIDE
FirDeclarationOrigin.Delegated -> KtSymbolOrigin.DELEGATED
FirDeclarationOrigin.Synthetic.FakeHiddenInPreparationForNewJdk -> KtSymbolOrigin.LIBRARY
is FirDeclarationOrigin.Synthetic -> {
when {
source?.kind == KtFakeSourceElementKind.DataClassGeneratedMembers -> KtSymbolOrigin.SOURCE_MEMBER_GENERATED
@@ -45,3 +45,7 @@ open operator fun equals(other: kotlin.Any?): kotlin.Boolean
open fun hashCode(): kotlin.Int
open fun toString(): kotlin.String
fun getFirst(): E
fun getLast(): E
@@ -1546,4 +1546,86 @@ KtFunctionSymbol:
getContainingFileSymbol: null
getContainingJvmClassName: kotlin.Any
getContainingModule: KtBinaryModule "Builtins for JVM (1.8)"
deprecationStatus: null
KtFunctionSymbol:
annotationsList: []
callableIdIfNonLocal: kotlin/collections/MutableList.getFirst
contextReceivers: []
contractEffects: []
hasStableParameterNames: true
isActual: false
isBuiltinFunctionInvoke: false
isExpect: false
isExtension: false
isExternal: false
isInfix: false
isInline: false
isOperator: false
isOverride: false
isStatic: false
isSuspend: false
modality: OPEN
name: getFirst
origin: SUBSTITUTION_OVERRIDE
receiverParameter: null
returnType: KtTypeParameterType:
annotationsList: []
type: E
symbolKind: CLASS_MEMBER
typeParameters: []
valueParameters: []
visibility: Public
getDispatchReceiver(): KtUsualClassType:
annotationsList: []
ownTypeArguments: [
KtTypeParameterType:
annotationsList: []
type: E
]
type: kotlin/collections/MutableList<E>
getContainingFileSymbol: null
getContainingJvmClassName: kotlin.collections.MutableList
getContainingModule: KtBinaryModule "Builtins for JVM (1.8)"
deprecationStatus: null
KtFunctionSymbol:
annotationsList: []
callableIdIfNonLocal: kotlin/collections/MutableList.getLast
contextReceivers: []
contractEffects: []
hasStableParameterNames: true
isActual: false
isBuiltinFunctionInvoke: false
isExpect: false
isExtension: false
isExternal: false
isInfix: false
isInline: false
isOperator: false
isOverride: false
isStatic: false
isSuspend: false
modality: OPEN
name: getLast
origin: SUBSTITUTION_OVERRIDE
receiverParameter: null
returnType: KtTypeParameterType:
annotationsList: []
type: E
symbolKind: CLASS_MEMBER
typeParameters: []
valueParameters: []
visibility: Public
getDispatchReceiver(): KtUsualClassType:
annotationsList: []
ownTypeArguments: [
KtTypeParameterType:
annotationsList: []
type: E
]
type: kotlin/collections/MutableList<E>
getContainingFileSymbol: null
getContainingJvmClassName: kotlin.collections.MutableList
getContainingModule: KtBinaryModule "Builtins for JVM (1.8)"
deprecationStatus: null
@@ -13,6 +13,8 @@ val size: kotlin.Int
fun equals(other: kotlin.Any?): kotlin.Boolean
fun hashCode(): kotlin.Int
fun toString(): kotlin.String
fun getFirst(): kotlin.Int
fun getLast(): kotlin.Int
Declaration Scope:
@@ -30,3 +32,6 @@ val size: kotlin.Int
fun equals(other: kotlin.Any?): kotlin.Boolean
fun hashCode(): kotlin.Int
fun toString(): kotlin.String
fun getFirst(): E
fun getLast(): E
@@ -148,6 +148,18 @@ KtFunctionLikeSignature:
symbol = kotlin/Any.toString(<dispatch receiver>: kotlin.Any): kotlin.String
valueParameters = []
callableIdIfNonLocal = kotlin/Any.toString
KtFunctionLikeSignature:
receiverType = null
returnType = kotlin.Int
symbol = kotlin/collections/List.getFirst(<dispatch receiver>: kotlin.collections.List<E>): E
valueParameters = []
callableIdIfNonLocal = kotlin/collections/List.getFirst
KtFunctionLikeSignature:
receiverType = null
returnType = kotlin.Int
symbol = kotlin/collections/List.getLast(<dispatch receiver>: kotlin.collections.List<E>): E
valueParameters = []
callableIdIfNonLocal = kotlin/collections/List.getLast
Declaration Scope:
@@ -798,4 +810,60 @@ KtFunctionSymbol:
typeParameters: []
valueParameters: []
visibility: Public
KtFunctionSymbol:
annotationsList: []
callableIdIfNonLocal: kotlin/collections/List.getFirst
contextReceivers: []
contractEffects: []
hasStableParameterNames: true
isActual: false
isBuiltinFunctionInvoke: false
isExpect: false
isExtension: false
isExternal: false
isInfix: false
isInline: false
isOperator: false
isOverride: false
isStatic: false
isSuspend: false
modality: OPEN
name: getFirst
origin: LIBRARY
receiverParameter: null
returnType: KtTypeParameterType:
annotationsList: []
type: E
symbolKind: CLASS_MEMBER
typeParameters: []
valueParameters: []
visibility: Public
KtFunctionSymbol:
annotationsList: []
callableIdIfNonLocal: kotlin/collections/List.getLast
contextReceivers: []
contractEffects: []
hasStableParameterNames: true
isActual: false
isBuiltinFunctionInvoke: false
isExpect: false
isExtension: false
isExternal: false
isInfix: false
isInline: false
isOperator: false
isOverride: false
isStatic: false
isSuspend: false
modality: OPEN
name: getLast
origin: LIBRARY
receiverParameter: null
returnType: KtTypeParameterType:
annotationsList: []
type: E
symbolKind: CLASS_MEMBER
typeParameters: []
valueParameters: []
visibility: Public
@@ -13,6 +13,8 @@ val size: kotlin.Int
fun equals(other: kotlin.Any?): kotlin.Boolean
fun hashCode(): kotlin.Int
fun toString(): kotlin.String
fun getFirst(): AAA
fun getLast(): AAA
Declaration Scope:
@@ -30,3 +32,6 @@ val size: kotlin.Int
fun equals(other: kotlin.Any?): kotlin.Boolean
fun hashCode(): kotlin.Int
fun toString(): kotlin.String
fun getFirst(): E
fun getLast(): E
@@ -148,6 +148,18 @@ KtFunctionLikeSignature:
symbol = kotlin/Any.toString(<dispatch receiver>: kotlin.Any): kotlin.String
valueParameters = []
callableIdIfNonLocal = kotlin/Any.toString
KtFunctionLikeSignature:
receiverType = null
returnType = AAA
symbol = kotlin/collections/List.getFirst(<dispatch receiver>: kotlin.collections.List<E>): E
valueParameters = []
callableIdIfNonLocal = kotlin/collections/List.getFirst
KtFunctionLikeSignature:
receiverType = null
returnType = AAA
symbol = kotlin/collections/List.getLast(<dispatch receiver>: kotlin.collections.List<E>): E
valueParameters = []
callableIdIfNonLocal = kotlin/collections/List.getLast
Declaration Scope:
@@ -798,4 +810,60 @@ KtFunctionSymbol:
typeParameters: []
valueParameters: []
visibility: Public
KtFunctionSymbol:
annotationsList: []
callableIdIfNonLocal: kotlin/collections/List.getFirst
contextReceivers: []
contractEffects: []
hasStableParameterNames: true
isActual: false
isBuiltinFunctionInvoke: false
isExpect: false
isExtension: false
isExternal: false
isInfix: false
isInline: false
isOperator: false
isOverride: false
isStatic: false
isSuspend: false
modality: OPEN
name: getFirst
origin: LIBRARY
receiverParameter: null
returnType: KtTypeParameterType:
annotationsList: []
type: E
symbolKind: CLASS_MEMBER
typeParameters: []
valueParameters: []
visibility: Public
KtFunctionSymbol:
annotationsList: []
callableIdIfNonLocal: kotlin/collections/List.getLast
contextReceivers: []
contractEffects: []
hasStableParameterNames: true
isActual: false
isBuiltinFunctionInvoke: false
isExpect: false
isExtension: false
isExternal: false
isInfix: false
isInline: false
isOperator: false
isOverride: false
isStatic: false
isSuspend: false
modality: OPEN
name: getLast
origin: LIBRARY
receiverParameter: null
returnType: KtTypeParameterType:
annotationsList: []
type: E
symbolKind: CLASS_MEMBER
typeParameters: []
valueParameters: []
visibility: Public
@@ -38708,6 +38708,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/testsWithJava17"), Pattern.compile("^(.+)\\.(kt|kts)$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true);
}
@Test
@TestMetadata("newListMethods.kt")
public void testNewListMethods() throws Exception {
runTest("compiler/testData/diagnostics/tests/testsWithJava17/newListMethods.kt");
}
@Nested
@TestMetadata("compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord")
@TestDataPath("$PROJECT_ROOT")
@@ -38708,6 +38708,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/testsWithJava17"), Pattern.compile("^(.+)\\.(kt|kts)$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true);
}
@Test
@TestMetadata("newListMethods.kt")
public void testNewListMethods() throws Exception {
runTest("compiler/testData/diagnostics/tests/testsWithJava17/newListMethods.kt");
}
@Nested
@TestMetadata("compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord")
@TestDataPath("$PROJECT_ROOT")
@@ -36334,6 +36334,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/testsWithJava17"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true, "multiplatform");
}
@Test
@TestMetadata("newListMethods.kt")
public void testNewListMethods() throws Exception {
runTest("compiler/testData/diagnostics/tests/testsWithJava17/newListMethods.kt");
}
@Nested
@TestMetadata("compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord")
@TestDataPath("$PROJECT_ROOT")
@@ -36460,6 +36460,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/testsWithJava17"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true, "multiplatform");
}
@Test
@TestMetadata("newListMethods.kt")
public void testNewListMethods() throws Exception {
runTest("compiler/testData/diagnostics/tests/testsWithJava17/newListMethods.kt");
}
@Nested
@TestMetadata("compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord")
@TestDataPath("$PROJECT_ROOT")
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.analysis.jvm
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
import org.jetbrains.kotlin.fir.analysis.FirOverridesBackwardCompatibilityHelper
import org.jetbrains.kotlin.fir.containingClassLookupTag
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
import org.jetbrains.kotlin.fir.declarations.isJavaOrEnhancement
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
@@ -19,6 +20,8 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
*/
object FirJvmOverridesBackwardCompatibilityHelper : FirOverridesBackwardCompatibilityHelper() {
override fun additionalCheck(member: FirCallableSymbol<*>): Boolean? {
if (member.origin == FirDeclarationOrigin.Synthetic.FakeHiddenInPreparationForNewJdk) return true
if (!member.isJavaOrEnhancement) return false
val containingClassName = member.containingClassLookupTag()?.classId?.asSingleFqName()?.toUnsafe() ?: return false
// If the super class is mapped to a Kotlin built-in class, then we don't require `override` keyword.
@@ -314,6 +314,7 @@ class FakeOverrideGenerator(
val baseSymbol = originalSymbol.unwrapSubstitutionAndIntersectionOverrides() as S
if (!session.visibilityChecker.isVisibleForOverriding(klass.moduleData, klass.symbol, baseSymbol.fir)) return
if (originalDeclaration.originalOrSelf().origin == FirDeclarationOrigin.Synthetic.FakeHiddenInPreparationForNewJdk) return
val (fakeOverrideFirDeclaration, baseFirSymbolsForFakeOverride) = when {
originalSymbol.shouldHaveComputedBaseSymbolsForClass(classLookupTag) -> {
@@ -229,6 +229,7 @@ class Fir2IrLazyClass(
}
private fun shouldBuildStub(fir: FirDeclaration): Boolean {
if (fir is FirCallableDeclaration && fir.originalOrSelf().origin == FirDeclarationOrigin.Synthetic.FakeHiddenInPreparationForNewJdk) return false
if (fir !is FirMemberDeclaration) return true
return when {
fir is FirConstructor -> isObject || isEnumClass || !Visibilities.isPrivate(fir.visibility) // This special case seams to be not needed anymore - KT-65172
@@ -28,7 +28,7 @@ class FirJvmDelegatedMembersFilter(private val session: FirSession) : FirDelegat
override fun shouldNotGenerateDelegatedMember(memberSymbolFromSuperInterface: FirCallableSymbol<*>): Boolean {
val original = memberSymbolFromSuperInterface.unwrapFakeOverrides()
return original.isNonAbstractJavaMethod() || original.hasJvmDefaultAnnotation() || original.isBuiltInMemberMappedToJavaDefault()
return original.isNonAbstractJavaMethod() || original.hasJvmDefaultAnnotation() || original.isBuiltInMemberMappedToJavaDefault() || original.origin == FirDeclarationOrigin.Synthetic.FakeHiddenInPreparationForNewJdk
}
// If java interface method is not abstract, then it's a default method.
@@ -7,11 +7,17 @@ package org.jetbrains.kotlin.fir.scopes.jvm
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
import org.jetbrains.kotlin.builtins.jvm.JvmBuiltInsSignatures
import org.jetbrains.kotlin.descriptors.EffectiveVisibility
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.caches.*
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.builder.buildSimpleFunction
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl
import org.jetbrains.kotlin.fir.declarations.utils.classId
import org.jetbrains.kotlin.fir.declarations.utils.isFinal
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
import org.jetbrains.kotlin.fir.resolve.defaultType
import org.jetbrains.kotlin.fir.resolve.isRealOwnerOf
import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes
@@ -26,6 +32,8 @@ import org.jetbrains.kotlin.fir.scopes.impl.declaredMemberScope
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.ConeErrorType
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
import org.jetbrains.kotlin.fir.types.lowerBoundIfFlexible
@@ -36,6 +44,7 @@ import org.jetbrains.kotlin.load.kotlin.SignatureBuildingComponents
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.StandardClassIds
/**
* @param firKotlinClass Kotlin version of built-in class mapped to some JDK class (e.g. kotlin.collections.List)
@@ -75,8 +84,10 @@ class JvmMappedScope(
}
}
private val isList: Boolean = firKotlinClass.classId == StandardClassIds.List
// It's ok to have a super set of actually available member names
private val myCallableNames by lazy {
private val myCallableNames: Set<Name> by lazy {
if (firKotlinClass.isFinal) {
// For final classes we don't need to load HIDDEN members at all because they might not be overridden
val signaturePrefix = firJavaClass.symbol.classId.toString()
@@ -91,6 +102,13 @@ class JvmMappedScope(
declaredMemberScope.getCallableNames() + names
} else {
declaredMemberScope.getCallableNames() + javaMappedClassUseSiteScope.getCallableNames()
}.let {
// If getFirst/getLast don't exist, we need to add them so that we can mark overrides as deprecated (KT-65440)
if (isList && (GET_FIRST_NAME !in it || GET_LAST_NAME !in it)) {
it + listOf(GET_FIRST_NAME, GET_LAST_NAME)
} else {
it
}
}
}
@@ -112,6 +130,8 @@ class JvmMappedScope(
}
}
var needsHiddenFake = isList && (name == GET_FIRST_NAME || name == GET_LAST_NAME)
javaMappedClassUseSiteScope.processFunctionsByName(name) processor@{ symbol ->
if (!symbol.isDeclaredInMappedJavaClass() || !(symbol.fir.status as FirResolvedDeclarationStatus).visibility.isPublicAPI) {
return@processor
@@ -137,8 +157,46 @@ class JvmMappedScope(
if ((jdkMemberStatus == JDKMemberStatus.HIDDEN || jdkMemberStatus == JDKMemberStatus.HIDDEN_IN_DECLARING_CLASS_ONLY) && firKotlinClass.isFinal) return@processor
val newSymbol = mappedSymbolCache.mappedFunctions.getValue(symbol, this to jdkMemberStatus)
if (needsHiddenFake &&
allJavaMappedSuperClassIds.any {
SignatureBuildingComponents.signature(it, jvmDescriptor) in JvmBuiltInsSignatures.DEPRECATED_LIST_METHODS
}
) {
needsHiddenFake = false
}
processor(newSymbol)
}
if (needsHiddenFake) {
// We're in JDK < 21, i.e., getFirst/getLast don't exist in the List interface yet.
// We create a fake version of them for the sole purpose of reporting deprecations on to-become-overrides like in LinkedList.
// This is because we want to rename these two methods in the future,
// and we want to warn users of older JDKs of a potential breaking change caused by upgrading to JDK >= 21.
// See KT-65440.
val fakeSymbol = mappedSymbolCache.hiddenFakeFunctions.getValue(name, this)
processor(fakeSymbol)
}
}
private fun createHiddenFakeFunction(name: Name): FirNamedFunctionSymbol {
return buildSimpleFunction {
moduleData = firKotlinClass.moduleData
origin = FirDeclarationOrigin.Synthetic.FakeHiddenInPreparationForNewJdk
status = FirResolvedDeclarationStatusImpl(Visibilities.Public, Modality.OPEN, EffectiveVisibility.Public)
returnTypeRef = buildResolvedTypeRef {
type = firKotlinClass.typeParameters.firstOrNull()
?.let { ConeTypeParameterTypeImpl(it.symbol.toLookupTag(), isNullable = false) }
?: ConeErrorType(ConeSimpleDiagnostic("No type parameter found on '${firKotlinClass.classKind}'"))
}
this.name = name
dispatchReceiverType = firKotlinClass.defaultType()
symbol = FirNamedFunctionSymbol(CallableId(firKotlinClass.classId, name))
resolvePhase = FirResolvePhase.BODY_RESOLVE
}.apply {
isHiddenEverywhereBesideSuperCalls = HiddenEverywhereBesideSuperCallsStatus.HIDDEN_FAKE
}.symbol
}
private fun isOverrideOfKotlinDeclaredFunction(symbol: FirNamedFunctionSymbol) =
@@ -335,6 +393,11 @@ class JvmMappedScope(
scope.createMappedFunction(symbol, jdkMemberStatus)
}
val hiddenFakeFunctions: FirCache<Name, FirNamedFunctionSymbol, JvmMappedScope> =
cachesFactory.createCache { name, scope ->
scope.createHiddenFakeFunction(name)
}
val mappedConstructors: FirCache<FirConstructorSymbol, FirConstructorSymbol, JvmMappedScope> =
cachesFactory.createCache { symbol, scope ->
scope.createMappedConstructor(symbol)
@@ -357,6 +420,9 @@ class JvmMappedScope(
},
session
)
private val GET_FIRST_NAME = Name.identifier("getFirst")
private val GET_LAST_NAME = Name.identifier("getLast")
}
override fun toString(): String {
@@ -331,7 +331,7 @@ var FirCallableDeclaration.isHiddenEverywhereBesideSuperCalls: HiddenEverywhereB
)
enum class HiddenEverywhereBesideSuperCallsStatus {
HIDDEN, HIDDEN_IN_DECLARING_CLASS_ONLY
HIDDEN, HIDDEN_IN_DECLARING_CLASS_ONLY, HIDDEN_FAKE,
}
private object IsHiddenToOvercomeSignatureClash : FirDeclarationDataKey()
@@ -360,5 +360,7 @@ fun FirCallableSymbol<*>.isHidden(isSuperCall: Boolean, isOverridden: Boolean):
// we report a deprecation warning on super calls because we might want to rename the method in the future
// (getFirst -> first).
HiddenEverywhereBesideSuperCallsStatus.HIDDEN_IN_DECLARING_CLASS_ONLY -> if (isSuperCall || isOverridden) CallToPotentiallyHiddenSymbolResult.VisibleWithDeprecation else CallToPotentiallyHiddenSymbolResult.Hidden
// HIDDEN_FAKE is always hidden (even for super calls), unless overridden.
HiddenEverywhereBesideSuperCallsStatus.HIDDEN_FAKE -> if (isOverridden) CallToPotentiallyHiddenSymbolResult.VisibleWithDeprecation else CallToPotentiallyHiddenSymbolResult.Hidden
}
}
@@ -35,6 +35,7 @@ sealed class FirDeclarationOrigin(
object FakeFunction : Synthetic()
object ForwardDeclaration : Synthetic()
object ScriptTopLevelDestructuringDeclarationContainer : Synthetic()
object FakeHiddenInPreparationForNewJdk : Synthetic()
}
object DynamicScope : FirDeclarationOrigin()
object SamConstructor : FirDeclarationOrigin()
@@ -0,0 +1,29 @@
import java.util.LinkedList
class A<T> : ArrayList<T>() {
fun getFirst(): T = super.<!UNRESOLVED_REFERENCE!>getFirst<!>()
fun getLast(): T = super.<!UNRESOLVED_REFERENCE!>getLast<!>()
}
fun foo(x: List<String>, y: LinkedList<String>, z: A<String>) {
x.<!UNRESOLVED_REFERENCE!>getFirst<!>()
x.<!FUNCTION_CALL_EXPECTED!>first<!>
x.first() // stdlib extension on List
x.<!UNRESOLVED_REFERENCE!>getLast<!>()
x.<!FUNCTION_CALL_EXPECTED!>last<!>
x.last()
y.<!DEPRECATION!>getFirst<!>()
y.<!DEPRECATION!>first<!>
y.first()
y.<!DEPRECATION!>getLast<!>()
y.<!DEPRECATION!>last<!>
y.last()
z.<!DEPRECATION!>getFirst<!>()
z.<!FUNCTION_CALL_EXPECTED!>first<!>
z.first()
z.<!DEPRECATION!>getLast<!>()
z.<!FUNCTION_CALL_EXPECTED!>last<!>
z.last()
}
@@ -0,0 +1,29 @@
import java.util.LinkedList
class A<T> : ArrayList<T>() {
fun getFirst(): T = super.<!UNRESOLVED_REFERENCE!>getFirst<!>()
fun getLast(): T = super.<!UNRESOLVED_REFERENCE!>getLast<!>()
}
fun foo(x: List<String>, y: LinkedList<String>, z: A<String>) {
x.<!UNRESOLVED_REFERENCE!>getFirst<!>()
x.<!FUNCTION_CALL_EXPECTED!>first<!>
x.first() // stdlib extension on List
x.<!UNRESOLVED_REFERENCE!>getLast<!>()
x.<!FUNCTION_CALL_EXPECTED!>last<!>
x.last()
y.getFirst()
y.first
y.first()
y.getLast()
y.last
y.last()
z.getFirst()
z.<!FUNCTION_CALL_EXPECTED!>first<!>
z.first()
z.getLast()
z.<!FUNCTION_CALL_EXPECTED!>last<!>
z.last()
}
@@ -38708,6 +38708,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/testsWithJava17"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true);
}
@Test
@TestMetadata("newListMethods.kt")
public void testNewListMethods() throws Exception {
runTest("compiler/testData/diagnostics/tests/testsWithJava17/newListMethods.kt");
}
@Nested
@TestMetadata("compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord")
@TestDataPath("$PROJECT_ROOT")
@@ -83,6 +83,7 @@ class InlinerCycleReporter(
} finally {
if (!inlineCallInfos.isEmpty()) {
@Suppress("DEPRECATION") // KT-65247
if (inlineCallInfos.last.call == call) {
inlineCallInfos.removeLast()
}