Skip to content

Commit c71098e

Browse files
committed
Self types: implementation of Self types using @Self as annotation.
Self type will be generated for classes/interfaces annotated with `@Self`. For FIR will be generated special type <Self> and transformed to $Self during FIR2IR. Self type is added as last type parameter. Example: ``` @self class Foo { // generated type: out Self: Foo<Self> fun foo(): Self = this as Self // without UNCHECKED_CAST warning } ```
1 parent 4af0f11 commit c71098e

File tree

71 files changed

+671
-26
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+671
-26
lines changed

analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerFirTestdataTestGenerated.java

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
FILE: selfTypes.kt
2+
@R|kotlin/Self|() public final class JustSelfAnnotation<out <Self> : R|JustSelfAnnotation<<Self>>|> : R|kotlin/Any| {
3+
public constructor(): R|JustSelfAnnotation| {
4+
super<R|kotlin/Any|>()
5+
}
6+
7+
public final fun anyFun(): R|kotlin/String| {
8+
^anyFun String(string)
9+
}
10+
11+
}
12+
@R|kotlin/Self|() public final class ReturnType<out <Self> : R|ReturnType<<Self>>|> : R|kotlin/Any| {
13+
public constructor(): R|ReturnType| {
14+
super<R|kotlin/Any|>()
15+
}
16+
17+
public final fun returnTypeWithVal(): R|<Self>| {
18+
lval res: R|<Self>| = (this@R|/ReturnType| as R|<Self>|)
19+
^returnTypeWithVal R|<local>/res|
20+
}
21+
22+
}
23+
@R|kotlin/Self|() public final class ReturnTypeWithTypeParameter<T, out <Self> : R|ReturnTypeWithTypeParameter<T, <Self>>|> : R|kotlin/Any| {
24+
public constructor<T>(): R|ReturnTypeWithTypeParameter<T>| {
25+
super<R|kotlin/Any|>()
26+
}
27+
28+
public final fun returnType(): R|<Self>| {
29+
^returnType (this@R|/ReturnTypeWithTypeParameter| as R|<Self>|)
30+
}
31+
32+
}
33+
@R|kotlin/Self|() public final class ReturnTypeWithTypeParameters<T, A, F, out <Self> : R|ReturnTypeWithTypeParameters<T, A, F, <Self>>|> : R|kotlin/Any| {
34+
public constructor<T, A, F>(): R|ReturnTypeWithTypeParameters<T, A, F>| {
35+
super<R|kotlin/Any|>()
36+
}
37+
38+
public final fun returnType(): R|<Self>| {
39+
^returnType (this@R|/ReturnTypeWithTypeParameters| as R|<Self>|)
40+
}
41+
42+
}
43+
public final class InnerClass : R|kotlin/Any| {
44+
public constructor(): R|InnerClass| {
45+
super<R|kotlin/Any|>()
46+
}
47+
48+
@R|kotlin/Self|() public final inner class Inner<out <Self> : R|InnerClass.Inner<<Self>>|> : R|kotlin/Any| {
49+
public InnerClass.constructor(): R|InnerClass.Inner| {
50+
super<R|kotlin/Any|>()
51+
}
52+
53+
public final fun returnType(): R|<Self>| {
54+
^returnType (this@R|/InnerClass.Inner| as R|<Self>|)
55+
}
56+
57+
}
58+
59+
}
60+
public final class NestedClass : R|kotlin/Any| {
61+
public constructor(): R|NestedClass| {
62+
super<R|kotlin/Any|>()
63+
}
64+
65+
@R|kotlin/Self|() public final class Nested<out <Self> : R|NestedClass.Nested<<Self>>|> : R|kotlin/Any| {
66+
public constructor(): R|NestedClass.Nested| {
67+
super<R|kotlin/Any|>()
68+
}
69+
70+
public final fun returnType(): R|<Self>| {
71+
^returnType (this@R|/NestedClass.Nested| as R|<Self>|)
72+
}
73+
74+
}
75+
76+
}
77+
@R|kotlin/Self|() public final class InnerSelfClass<out <Self> : R|InnerSelfClass<<Self>>|> : R|kotlin/Any| {
78+
public constructor(): R|InnerSelfClass| {
79+
super<R|kotlin/Any|>()
80+
}
81+
82+
public final inner class Self : R|kotlin/Any| {
83+
public InnerSelfClass.constructor(): R|InnerSelfClass.Self| {
84+
super<R|kotlin/Any|>()
85+
}
86+
87+
public final fun returnSelf(): R|InnerSelfClass.Self| {
88+
^returnSelf this@R|/InnerSelfClass.Self|
89+
}
90+
91+
}
92+
93+
public final fun returnType(): R|<Self>| {
94+
^returnType (this@R|/InnerSelfClass| as R|<Self>|)
95+
}
96+
97+
public final fun returnSelfClassType(): R|InnerSelfClass.Self| {
98+
^returnSelfClassType R|/InnerSelfClass.InnerSelfClass|().R|/InnerSelfClass.Self.Self|()
99+
}
100+
101+
}
102+
@R|kotlin/Self|() public final class TypeAliasSelf<out <Self> : R|TypeAliasSelf<<Self>>|> : R|kotlin/Any| {
103+
public constructor(): R|TypeAliasSelf| {
104+
super<R|kotlin/Any|>()
105+
}
106+
107+
@R|kotlin/Suppress|(names = vararg(String(TOPLEVEL_TYPEALIASES_ONLY))) public final typealias Self = R|kotlin/String|
108+
109+
public final fun returnType(): R|<Self>| {
110+
^returnType (this@R|/TypeAliasSelf| as R|<Self>|)
111+
}
112+
113+
public final fun returnTypealias(): R|TypeAliasSelf.Self| {
114+
^returnTypealias String(typealias)
115+
}
116+
117+
}
118+
@R|kotlin/Self|() public final class SelfWithSelfVariable<out <Self> : R|SelfWithSelfVariable<<Self>>|> : R|kotlin/Any| {
119+
public constructor(): R|SelfWithSelfVariable| {
120+
super<R|kotlin/Any|>()
121+
}
122+
123+
public final fun returnType(): R|<Self>| {
124+
lval Self: R|<Self>| = (this@R|/SelfWithSelfVariable| as R|<Self>|)
125+
^returnType R|<local>/Self|
126+
}
127+
128+
}
129+
public final class InnerClassWithSelfAnnotation<S : R|InnerClassWithSelfAnnotation<S>|> : R|kotlin/Any| {
130+
public constructor<S : R|InnerClassWithSelfAnnotation<S>|>(): R|InnerClassWithSelfAnnotation<S>| {
131+
super<R|kotlin/Any|>()
132+
}
133+
134+
@R|kotlin/Self|() public final inner class SelfAnnotated<S : R|InnerClassWithSelfAnnotation<S>|, out <Self> : R|InnerClassWithSelfAnnotation.SelfAnnotated<S, <Self>>|> : R|kotlin/Any| {
135+
public InnerClassWithSelfAnnotation<S>.constructor(): R|InnerClassWithSelfAnnotation.SelfAnnotated<S>| {
136+
super<R|kotlin/Any|>()
137+
}
138+
139+
public final fun returnType(): R|<Self>| {
140+
^returnType (this@R|/InnerClassWithSelfAnnotation.SelfAnnotated| as R|<Self>|)
141+
}
142+
143+
}
144+
145+
@R|kotlin/Suppress|(names = vararg(String(UNCHECKED_CAST))) public final fun returnType(): R|S| {
146+
^returnType (this@R|/InnerClassWithSelfAnnotation| as R|S|)
147+
}
148+
149+
}
150+
@R|kotlin/Self|() public abstract interface SelfTypeParameterInterface<out <Self> : R|SelfTypeParameterInterface<<Self>>|> : R|kotlin/Any| {
151+
}
152+
@R|kotlin/Self|() public final class SelfTypeAsTypeParameterInExtends<out <Self> : R|SelfTypeAsTypeParameterInExtends<<Self>>|> : R|SelfTypeParameterInterface<<Self>>| {
153+
public constructor(): R|SelfTypeAsTypeParameterInExtends| {
154+
super<R|kotlin/Any|>()
155+
}
156+
157+
public final fun returnType(): R|<Self>| {
158+
^returnType (this@R|/SelfTypeAsTypeParameterInExtends| as R|<Self>|)
159+
}
160+
161+
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import kotlin.Self
2+
3+
@Self
4+
class JustSelfAnnotation {
5+
fun anyFun(): String = "string"
6+
}
7+
8+
@Self
9+
class ReturnType {
10+
fun returnTypeWithVal(): Self {
11+
val res: Self = this as Self
12+
return res
13+
}
14+
}
15+
16+
@Self
17+
class ReturnTypeWithTypeParameter<T> {
18+
fun returnType(): Self {
19+
return this as Self
20+
}
21+
}
22+
23+
@Self
24+
class ReturnTypeWithTypeParameters<T, A, F> {
25+
fun returnType(): Self {
26+
return this as Self
27+
}
28+
}
29+
30+
class InnerClass {
31+
@Self
32+
inner class Inner {
33+
fun returnType(): Self {
34+
return this as Self
35+
}
36+
}
37+
}
38+
39+
class NestedClass {
40+
@Self
41+
class Nested {
42+
fun returnType(): Self {
43+
return this as Self
44+
}
45+
}
46+
}
47+
48+
@Self
49+
class InnerSelfClass {
50+
inner class Self {
51+
fun returnSelf(): InnerSelfClass.Self {
52+
return this
53+
}
54+
}
55+
56+
fun returnType(): Self {
57+
return this as Self
58+
}
59+
60+
fun returnSelfClassType(): InnerSelfClass.Self {
61+
return InnerSelfClass().Self()
62+
}
63+
}
64+
65+
@Self
66+
class TypeAliasSelf {
67+
@Suppress("TOPLEVEL_TYPEALIASES_ONLY")
68+
typealias Self = String
69+
70+
fun returnType(): Self {
71+
return this as Self
72+
}
73+
74+
fun returnTypealias(): TypeAliasSelf.Self {
75+
return "typealias"
76+
}
77+
}
78+
79+
@Self
80+
class SelfWithSelfVariable {
81+
fun returnType(): Self {
82+
val Self: Self = this as Self
83+
return Self
84+
}
85+
}
86+
87+
class InnerClassWithSelfAnnotation<S: InnerClassWithSelfAnnotation<S>> {
88+
89+
@Self
90+
inner class SelfAnnotated {
91+
fun returnType(): Self {
92+
return this as Self
93+
}
94+
}
95+
96+
@Suppress("UNCHECKED_CAST")
97+
fun returnType(): S {
98+
return this as S
99+
}
100+
101+
}
102+
103+
@Self
104+
interface SelfTypeParameterInterface
105+
106+
@Self
107+
class SelfTypeAsTypeParameterInExtends : SelfTypeParameterInterface<Self> {
108+
109+
fun returnType(): Self {
110+
return this as Self
111+
}
112+
}

compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirCastOperatorsChecker.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import org.jetbrains.kotlin.fir.expressions.FirTypeOperatorCall
1818
import org.jetbrains.kotlin.fir.resolve.dfa.unwrapSmartcastExpression
1919
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
2020
import org.jetbrains.kotlin.fir.types.coneType
21+
import org.jetbrains.kotlin.fir.types.toSymbol
22+
import org.jetbrains.kotlin.name.SpecialNames
2123

2224
object FirCastOperatorsChecker : FirTypeOperatorCallChecker() {
2325
override fun check(expression: FirTypeOperatorCall, context: CheckerContext, reporter: DiagnosticReporter) {
@@ -39,7 +41,12 @@ object FirCastOperatorsChecker : FirTypeOperatorCallChecker() {
3941
reporter.reportOn(expression.source, FirErrors.USELESS_CAST, context)
4042
}
4143
} else if (isCastErased(actualType, targetType, context)) {
42-
reporter.reportOn(expression.source, FirErrors.UNCHECKED_CAST, actualType, targetType, context)
44+
45+
val isTargetTypeSelf = targetType.toSymbol(session)?.toLookupTag()?.name.let { it == SpecialNames.SELF_TYPE }
46+
val isTargetTypeTypeArg = actualType.typeArguments.contains(targetType)
47+
48+
if (!(isTargetTypeTypeArg && isTargetTypeSelf))
49+
reporter.reportOn(expression.source, FirErrors.UNCHECKED_CAST, actualType, targetType, context)
4350
}
4451
} else if (expression.operation == FirOperation.IS) {
4552
if (!context.isContractBody && isCastErased(actualType, targetType, context)) {

compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrClassifierStorage.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
3434
import org.jetbrains.kotlin.ir.util.IdSignature
3535
import org.jetbrains.kotlin.name.FqName
3636
import org.jetbrains.kotlin.name.Name
37+
import org.jetbrains.kotlin.name.SpecialNames.SELF_TYPE
3738
import org.jetbrains.kotlin.name.StandardClassIds
3839
import org.jetbrains.kotlin.utils.addToStdlib.runIf
3940
import org.jetbrains.kotlin.utils.addToStdlib.runUnless
@@ -388,6 +389,7 @@ class Fir2IrClassifierStorage(
388389
require(index >= 0)
389390
val origin = typeParameter.computeIrOrigin()
390391
val irTypeParameter = with(typeParameter) {
392+
val replacedSelfName = if (name == SELF_TYPE) SELF_TYPE_IDENTIFIER else name
391393
convertWithOffsets { startOffset, endOffset ->
392394
signatureComposer.composeTypeParameterSignature(
393395
typeParameter, index, ownerSymbol.signature
@@ -420,7 +422,7 @@ class Fir2IrClassifierStorage(
420422
}
421423
} ?: irFactory.createTypeParameter(
422424
startOffset, endOffset, origin, IrTypeParameterSymbolImpl(),
423-
name, if (index < 0) 0 else index,
425+
replacedSelfName, if (index < 0) 0 else index,
424426
isReified,
425427
variance
426428
)
@@ -622,4 +624,8 @@ class Fir2IrClassifierStorage(
622624
parent = IrExternalPackageFragmentImpl(IrExternalPackageFragmentSymbolImpl(), FqName.ROOT)
623625
}
624626
}
627+
628+
companion object Fir2IrClassifierStorage {
629+
private val SELF_TYPE_IDENTIFIER = Name.identifier("\$Self")
630+
}
625631
}

compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)