[FIR] KT-54978 Prohibit explicit type arguments in property accesses
- Add a checker which ensures that property accesses have no explicit type arguments. If an error on the property access's callee reference already exists, the new error is not reported in favor of the existing error, as the property access may have been intended to be a function call. - `complicatedLTGT.fir.kt`: The underlying parser issue is not yet solved, which is why `x` is parsed as a property access with explicit type arguments. - `reservedExpressionSyntax` tests: This new check makes a lot of the access expressions in these tests illegal, so valid lines have been added and invalid lines appropriately marked with `EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS` errors. ^KT-54978 fixed
This commit is contained in:
committed by
teamcity
parent
4d20b43619
commit
d4e6a4ad54
+88
@@ -0,0 +1,88 @@
|
||||
FILE: propertyAccessWithExplicitTypeArguments.kt
|
||||
public final fun f1(x: R|kotlin/Int|): R|kotlin/Unit| {
|
||||
lval y: R|kotlin/Int| = Int(5)
|
||||
lval s: R|kotlin/String| = String(hello)
|
||||
R|<local>/x|<R|kotlin/Int|>
|
||||
R|<local>/x|<R|kotlin/String|, R|kotlin/String|>
|
||||
R|<local>/y|<R|kotlin/Int|>
|
||||
R|<local>/y|<R|kotlin/String|, R|kotlin/Int|>
|
||||
R|<local>/s|<R|kotlin/String|>
|
||||
R|<local>/s|<R|kotlin/Int|, R|kotlin/String|>
|
||||
}
|
||||
public final val property: R|kotlin/Int| = Int(10)
|
||||
public get(): R|kotlin/Int|
|
||||
public final fun f2(): R|kotlin/Unit| {
|
||||
R|/property|<R|kotlin/String|>
|
||||
}
|
||||
public final val property2: R|kotlin/Int|
|
||||
public get(): R|kotlin/Int| {
|
||||
^ Int(10)
|
||||
}
|
||||
public final fun f3(): R|kotlin/Unit| {
|
||||
R|/property2|<R|kotlin/String|>
|
||||
}
|
||||
public abstract interface Context<A> : R|kotlin/Any| {
|
||||
}
|
||||
public final class ContextImpl<A> : R|Context<A>| {
|
||||
public constructor<A>(): R|ContextImpl<A>| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
public final class Receiver<A> : R|kotlin/Any| {
|
||||
public constructor<A>(): R|Receiver<A>| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
public final val <A> R|Receiver<A>|.hello1: R|kotlin/String|
|
||||
public get(): R|kotlin/String| {
|
||||
^ String(hello 1)
|
||||
}
|
||||
context(R|Context<A>|)
|
||||
public final val <A> hello2: R|kotlin/String|
|
||||
public get(): R|kotlin/String| {
|
||||
^ String(hello 2)
|
||||
}
|
||||
context(R|Context<B>|)
|
||||
public final val <A, B> R|Receiver<A>|.hello3: R|kotlin/String|
|
||||
public get(): R|kotlin/String| {
|
||||
^ String(hello 3)
|
||||
}
|
||||
public final operator fun <A, B> R|kotlin/String|.invoke(): R|kotlin/String| {
|
||||
^invoke String(world)
|
||||
}
|
||||
public final fun f4(): R|kotlin/Unit| {
|
||||
lval receiver: R|Receiver<kotlin/Int>| = R|/Receiver.Receiver|<R|kotlin/Int|>()
|
||||
R|<local>/receiver|.R|/hello1|<R|kotlin/Int|>
|
||||
R|<local>/receiver|.R|/hello1|<R|kotlin/Int|>
|
||||
R|<local>/receiver|.R|/hello1|<R|kotlin/Int|>.R|/invoke|<R|kotlin/Int|, R|kotlin/String|>()
|
||||
R|<local>/receiver|.R|/hello1|<R|kotlin/Int|>
|
||||
R|<local>/receiver|.R|/hello1|<R|kotlin/Int|>
|
||||
R|<local>/receiver|.R|/hello1|<R|kotlin/Int|>
|
||||
R|kotlin/with|<R|ContextImpl<kotlin/String>|, R|kotlin/String|>(R|/ContextImpl.ContextImpl|<R|kotlin/String|>(), <L> = with@fun R|ContextImpl<kotlin/String>|.<anonymous>(): R|kotlin/String| <inline=Inline, kind=EXACTLY_ONCE> {
|
||||
R|/hello2|<R|kotlin/String|>
|
||||
R|/hello2|<R|kotlin/String|>
|
||||
R|/hello2|<R|kotlin/String|>.R|/invoke|<R|kotlin/String|, R|kotlin/Int|>()
|
||||
R|/hello2|<R|kotlin/String|>
|
||||
R|/hello2|<R|kotlin/String|>
|
||||
R|/hello2|<R|kotlin/String|>
|
||||
R|<local>/receiver|.R|/hello3|<R|kotlin/Int|, R|kotlin/String|>
|
||||
R|<local>/receiver|.R|/hello3|<R|kotlin/Int|, R|kotlin/String|>
|
||||
R|<local>/receiver|.R|/hello3|<R|kotlin/Int|, R|kotlin/String|>.R|/invoke|<R|kotlin/Int|, R|kotlin/String|>()
|
||||
R|<local>/receiver|.R|/hello3|<R|kotlin/Int|, R|kotlin/String|>
|
||||
R|<local>/receiver|.R|/hello3|<R|kotlin/Int|, R|kotlin/String|>
|
||||
^ R|<local>/receiver|.R|/hello3|<R|kotlin/Int|, R|kotlin/String|>
|
||||
}
|
||||
)
|
||||
}
|
||||
public final val <reified A> R|Receiver<A>|.helloReified: R|kotlin/String|
|
||||
public inline get(): R|kotlin/String| {
|
||||
^ String(hello)
|
||||
}
|
||||
public final fun f5(): R|kotlin/Unit| {
|
||||
lval receiver: R|Receiver<kotlin/Int>| = R|/Receiver.Receiver|<R|kotlin/Int|>()
|
||||
R|<local>/receiver|.R|/helloReified|<R|kotlin/Int|>
|
||||
R|<local>/receiver|.R|/helloReified|<R|kotlin/Int|>
|
||||
R|<local>/receiver|.R|/helloReified|<R|kotlin/Int|>
|
||||
}
|
||||
compiler/fir/analysis-tests/testData/resolve/expresssions/propertyAccessWithExplicitTypeArguments.kt
Vendored
+85
@@ -0,0 +1,85 @@
|
||||
// ISSUE: KT-54978
|
||||
|
||||
// Case 1: Parameters and local variables
|
||||
fun f1(x: Int) {
|
||||
val y = 5
|
||||
val s = "hello"
|
||||
|
||||
<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>x<!><Int>
|
||||
<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>x<!><String, String>
|
||||
<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>y<!><Int>
|
||||
<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>y<!><String, Int>
|
||||
<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>s<!><String>
|
||||
<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>s<!><Int, String>
|
||||
}
|
||||
|
||||
// Case 2: Simple property
|
||||
val property: Int = 10
|
||||
|
||||
fun f2() {
|
||||
<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>property<!><String>
|
||||
}
|
||||
|
||||
// Case 3: Simple property with getter
|
||||
val property2: Int
|
||||
get() = 10
|
||||
|
||||
fun f3() {
|
||||
<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>property2<!><String>
|
||||
}
|
||||
|
||||
// Case 4: Property with extension and/or context receiver
|
||||
interface Context<A>
|
||||
class ContextImpl<A> : Context<A>
|
||||
class Receiver<A>
|
||||
|
||||
val <A> Receiver<A>.hello1: String
|
||||
get() = "hello 1"
|
||||
|
||||
context(Context<A>)
|
||||
val <A> hello2: String
|
||||
get() = "hello 2"
|
||||
|
||||
context(Context<B>)
|
||||
val <A, B> Receiver<A>.hello3: String
|
||||
get() = "hello 3"
|
||||
|
||||
operator fun <A, B> String.invoke(): String = "world"
|
||||
|
||||
fun f4() {
|
||||
val receiver = Receiver<Int>()
|
||||
|
||||
receiver.hello1
|
||||
receiver.<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>hello1<!><Int>
|
||||
receiver.hello1<Int, String>() // legal `String.invoke` call
|
||||
receiver.<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>hello1<!><String>
|
||||
receiver.<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>hello1<!><Int, String>
|
||||
receiver.<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>hello1<!><Int, String, String>
|
||||
|
||||
with (ContextImpl<String>()) {
|
||||
hello2
|
||||
<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>hello2<!><String>
|
||||
hello2<String, Int>() // legal `String.invoke` call
|
||||
<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>hello2<!><Int>
|
||||
<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>hello2<!><String, Int>
|
||||
<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>hello2<!><String, Int, Int>
|
||||
|
||||
receiver.hello3
|
||||
receiver.<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>hello3<!><Int, String>
|
||||
receiver.hello3<Int, String>() // legal `String.invoke` call
|
||||
receiver.<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>hello3<!><String, Int>
|
||||
receiver.<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>hello3<!><Int>
|
||||
receiver.<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>hello3<!><Int, String, String>
|
||||
}
|
||||
}
|
||||
|
||||
// Case 5: Property with receiver and reified type parameter
|
||||
inline val <reified A> Receiver<A>.helloReified: String
|
||||
get() = "hello"
|
||||
|
||||
fun f5() {
|
||||
val receiver = Receiver<Int>()
|
||||
receiver.helloReified
|
||||
receiver.<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>helloReified<!><Int>
|
||||
receiver.<!EXPLICIT_TYPE_ARGUMENTS_IN_PROPERTY_ACCESS!>helloReified<!><String>
|
||||
}
|
||||
Reference in New Issue
Block a user