Support "::foo" as a short-hand for "this::foo"

#KT-15667 Fixed
This commit is contained in:
Alexander Udalov
2017-08-24 17:15:42 +03:00
parent d2ff821a3b
commit 2877314313
24 changed files with 195 additions and 116 deletions
@@ -659,7 +659,6 @@ public interface Errors {
DiagnosticFactory1<KtExpression, CallableMemberDescriptor> EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED = DiagnosticFactory1.create(ERROR);
DiagnosticFactory0<KtExpression> CALLABLE_REFERENCE_LHS_NOT_A_CLASS = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtExpression> CALLABLE_REFERENCE_TO_MEMBER_OR_EXTENSION_WITH_EMPTY_LHS = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtExpression> CALLABLE_REFERENCE_TO_ANNOTATION_CONSTRUCTOR = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtExpression> CLASS_LITERAL_LHS_NOT_A_CLASS = DiagnosticFactory0.create(ERROR);
@@ -839,9 +839,6 @@ public class DefaultErrorMessages {
MAP.put(EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED,
"''{0}'' is a member and an extension at the same time. References to such elements are not allowed", NAME);
MAP.put(CALLABLE_REFERENCE_LHS_NOT_A_CLASS, "Left-hand side of a callable reference cannot be a type parameter");
MAP.put(CALLABLE_REFERENCE_TO_MEMBER_OR_EXTENSION_WITH_EMPTY_LHS,
"Left-hand side of a callable reference with a receiver parameter cannot be empty. " +
"Please specify the type of the receiver before '::' explicitly");
MAP.put(CALLABLE_REFERENCE_TO_ANNOTATION_CONSTRUCTOR, "Annotation class cannot be instantiated");
MAP.put(CLASS_LITERAL_LHS_NOT_A_CLASS, "Only classes are allowed on the left hand side of a class literal");
@@ -550,9 +550,13 @@ class DoubleColonExpressionResolver(
descriptor: CallableDescriptor, trace: BindingTrace, expression: KtCallableReferenceExpression
) {
val simpleName = expression.callableReference
if (expression.isEmptyLHS &&
(descriptor.dispatchReceiverParameter != null || descriptor.extensionReceiverParameter != null)) {
trace.report(CALLABLE_REFERENCE_TO_MEMBER_OR_EXTENSION_WITH_EMPTY_LHS.on(simpleName))
if (!languageVersionSettings.supportsFeature(LanguageFeature.CallableReferencesToClassMembersWithEmptyLHS)) {
if (expression.isEmptyLHS &&
(descriptor.dispatchReceiverParameter != null || descriptor.extensionReceiverParameter != null)) {
trace.report(UNSUPPORTED_FEATURE.on(
simpleName, LanguageFeature.CallableReferencesToClassMembersWithEmptyLHS to languageVersionSettings
))
}
}
if (descriptor is ConstructorDescriptor && DescriptorUtils.isAnnotationClass(descriptor.containingDeclaration)) {
trace.report(CALLABLE_REFERENCE_TO_ANNOTATION_CONSTRUCTOR.on(simpleName))
@@ -0,0 +1,58 @@
// IGNORE_BACKEND: JS
// LANGUAGE_VERSION: 1.2
var result = ""
class A {
fun memberFunction() { result += "A.mf," }
fun aMemberFunction() { result += "A.amf," }
val memberProperty: Int get() = 42.also { result += "A.mp," }
val aMemberProperty: Int get() = 42.also { result += "A.amp," }
fun test(): String {
(::memberFunction)()
(::aExtensionFunction)()
(::memberProperty)()
(::aExtensionProperty)()
return result
}
inner class B {
fun memberFunction() { result += "B.mf," }
val memberProperty: Int get() = 42.also { result += "B.mp," }
fun test(): String {
(::aMemberFunction)()
(::aExtensionFunction)()
(::aMemberProperty)()
(::aExtensionProperty)()
(::memberFunction)()
(::memberProperty)()
(::bExtensionFunction)()
(::bExtensionProperty)()
return result
}
}
}
fun A.aExtensionFunction() { result += "A.ef," }
val A.aExtensionProperty: Int get() = 42.also { result += "A.ep," }
fun A.B.bExtensionFunction() { result += "B.ef," }
val A.B.bExtensionProperty: Int get() = 42.also { result += "B.ep," }
fun box(): String {
val a = A().test()
if (a != "A.mf,A.ef,A.mp,A.ep,") return "Fail $a"
result = ""
val b = A().B().test()
if (b != "A.amf,A.ef,A.amp,A.ep,B.mf,B.mp,B.ef,B.ep,") return "Fail $b"
return "OK"
}
@@ -1,4 +1,5 @@
// !DIAGNOSTICS: -UNUSED_EXPRESSION, -EXTENSION_SHADOWED_BY_MEMBER
// !LANGUAGE: +CallableReferencesToClassMembersWithEmptyLHS
val topLevelVal = 1
fun topLevelFun() = 2
@@ -14,13 +15,13 @@ class A {
val ok2 = ::topLevelFun
fun fail1() {
::<!CALLABLE_REFERENCE_TO_MEMBER_OR_EXTENSION_WITH_EMPTY_LHS!>extensionVal<!>
::<!CALLABLE_REFERENCE_TO_MEMBER_OR_EXTENSION_WITH_EMPTY_LHS!>extensionFun<!>
::extensionVal
::extensionFun
}
fun fail2() {
::<!CALLABLE_REFERENCE_TO_MEMBER_OR_EXTENSION_WITH_EMPTY_LHS!>memberVal<!>
::<!CALLABLE_REFERENCE_TO_MEMBER_OR_EXTENSION_WITH_EMPTY_LHS!>memberFun<!>
::memberVal
::memberFun
}
}
@@ -30,11 +31,11 @@ val ok1 = ::topLevelVal
val ok2 = ::topLevelFun
fun A.fail1() {
::<!CALLABLE_REFERENCE_TO_MEMBER_OR_EXTENSION_WITH_EMPTY_LHS!>extensionVal<!>
::<!CALLABLE_REFERENCE_TO_MEMBER_OR_EXTENSION_WITH_EMPTY_LHS!>extensionFun<!>
::extensionVal
::extensionFun
}
fun A.fail2() {
::<!CALLABLE_REFERENCE_TO_MEMBER_OR_EXTENSION_WITH_EMPTY_LHS!>memberVal<!>
::<!CALLABLE_REFERENCE_TO_MEMBER_OR_EXTENSION_WITH_EMPTY_LHS!>memberFun<!>
::memberVal
::memberFun
}
@@ -1,12 +1,14 @@
// !CHECK_TYPE
// !DIAGNOSTICS: -UNUSED_EXPRESSION
// !LANGUAGE: +CallableReferencesToClassMembersWithEmptyLHS
import kotlin.reflect.KFunction1
class A {
inner class Inner
fun main() {
::<!CALLABLE_REFERENCE_TO_MEMBER_OR_EXTENSION_WITH_EMPTY_LHS!>Inner<!>
::Inner
val y = A::Inner
checkSubtype<KFunction1<A, Inner>>(y)
@@ -1,5 +1,7 @@
// !CHECK_TYPE
// !DIAGNOSTICS: -UNUSED_EXPRESSION
// !LANGUAGE: +CallableReferencesToClassMembersWithEmptyLHS
import kotlin.reflect.KFunction1
class A {
@@ -7,7 +9,7 @@ class A {
}
fun A.main() {
::<!CALLABLE_REFERENCE_TO_MEMBER_OR_EXTENSION_WITH_EMPTY_LHS!>Inner<!>
::Inner
val y = A::Inner
checkSubtype<KFunction1<A, A.Inner>>(y)
@@ -1,24 +1,31 @@
// !CHECK_TYPE
// !LANGUAGE: +CallableReferencesToClassMembersWithEmptyLHS
import kotlin.reflect.KFunction0
fun explicitlyExpectFunction0(f: () -> Unit) = f
fun explicitlyExpectFunction1(f: (A) -> Unit) = f
fun expectFunction0Unit(f: () -> Unit) = f
fun expectFunction0String(f: () -> String) = f
fun expectFunction1Unit(f: (A) -> Unit) = f
fun expectFunction1String(f: (A) -> String) = f
fun foo() {}
fun foo(): String = ""
class A {
fun foo() {}
fun main() {
val x = ::<!CALLABLE_REFERENCE_TO_MEMBER_OR_EXTENSION_WITH_EMPTY_LHS!>foo<!>
val x = ::foo
checkSubtype<KFunction0<Unit>>(x)
explicitlyExpectFunction0(x)
explicitlyExpectFunction1(<!TYPE_MISMATCH!>x<!>)
expectFunction0Unit(x)
expectFunction0String(<!TYPE_MISMATCH!>x<!>)
expectFunction1Unit(<!TYPE_MISMATCH!>x<!>)
expectFunction1String(<!TYPE_MISMATCH!>x<!>)
explicitlyExpectFunction0(::<!CALLABLE_REFERENCE_TO_MEMBER_OR_EXTENSION_WITH_EMPTY_LHS!>foo<!>)
explicitlyExpectFunction1(<!TYPE_MISMATCH!>::<!CALLABLE_REFERENCE_TO_MEMBER_OR_EXTENSION_WITH_EMPTY_LHS!>foo<!><!>)
expectFunction0Unit(::foo)
expectFunction0String(::foo)
expectFunction1Unit(<!TYPE_MISMATCH!>::foo<!>)
expectFunction1String(<!TYPE_MISMATCH!>::foo<!>)
}
}
@@ -1,8 +1,10 @@
package
public fun explicitlyExpectFunction0(/*0*/ f: () -> kotlin.Unit): () -> kotlin.Unit
public fun explicitlyExpectFunction1(/*0*/ f: (A) -> kotlin.Unit): (A) -> kotlin.Unit
public fun foo(): kotlin.Unit
public fun expectFunction0String(/*0*/ f: () -> kotlin.String): () -> kotlin.String
public fun expectFunction0Unit(/*0*/ f: () -> kotlin.Unit): () -> kotlin.Unit
public fun expectFunction1String(/*0*/ f: (A) -> kotlin.String): (A) -> kotlin.String
public fun expectFunction1Unit(/*0*/ f: (A) -> kotlin.Unit): (A) -> kotlin.Unit
public fun foo(): kotlin.String
public final class A {
public constructor A()
@@ -0,0 +1,28 @@
// !LANGUAGE: -CallableReferencesToClassMembersWithEmptyLHS
class A {
fun memberFunction() {}
val memberProperty: Int get() = 42
fun test() {
(::<!UNSUPPORTED_FEATURE!>memberFunction<!>)()
(::<!UNSUPPORTED_FEATURE!>extensionFunction<!>)()
(::<!UNSUPPORTED_FEATURE!>memberProperty<!>)()
(::<!UNSUPPORTED_FEATURE!>extensionProperty<!>)()
}
inner class B {
fun memberFunction() { }
val memberProperty: Int get() = 43
fun test() {
(::<!UNSUPPORTED_FEATURE!>memberFunction<!>)()
(::<!UNSUPPORTED_FEATURE!>extensionFunction<!>)()
(::<!UNSUPPORTED_FEATURE!>memberProperty<!>)()
(::<!UNSUPPORTED_FEATURE!>extensionProperty<!>)()
}
}
}
fun A.extensionFunction() {}
val A.extensionProperty: Int get() = 44
@@ -0,0 +1,24 @@
package
public val A.extensionProperty: kotlin.Int
public fun A.extensionFunction(): kotlin.Unit
public final class A {
public constructor A()
public final val memberProperty: 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 memberFunction(): kotlin.Unit
public final fun test(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
public final inner class B {
public constructor B()
public final val memberProperty: 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 memberFunction(): kotlin.Unit
public final fun test(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
}
@@ -1669,6 +1669,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
doTest(fileName);
}
@TestMetadata("emptyLHS.kt")
public void testEmptyLHS() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/emptyLHS.kt");
doTest(fileName);
}
@TestMetadata("enumEntryMember.kt")
public void testEnumEntryMember() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/enumEntryMember.kt");
@@ -21877,6 +21877,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
doTest(fileName);
}
@TestMetadata("noCallableReferencesWithEmptyLHS.kt")
public void testNoCallableReferencesWithEmptyLHS() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/sourceCompatibility/noCallableReferencesWithEmptyLHS.kt");
doTest(fileName);
}
@TestMetadata("noDataClassInheritance.kt")
public void testNoDataClassInheritance() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/sourceCompatibility/noDataClassInheritance.kt");
@@ -21877,6 +21877,12 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
doTest(fileName);
}
@TestMetadata("noCallableReferencesWithEmptyLHS.kt")
public void testNoCallableReferencesWithEmptyLHS() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/sourceCompatibility/noCallableReferencesWithEmptyLHS.kt");
doTest(fileName);
}
@TestMetadata("noDataClassInheritance.kt")
public void testNoDataClassInheritance() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/sourceCompatibility/noDataClassInheritance.kt");
@@ -1669,6 +1669,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName);
}
@TestMetadata("emptyLHS.kt")
public void testEmptyLHS() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/emptyLHS.kt");
doTest(fileName);
}
@TestMetadata("enumEntryMember.kt")
public void testEnumEntryMember() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/enumEntryMember.kt");
@@ -1669,6 +1669,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
doTest(fileName);
}
@TestMetadata("emptyLHS.kt")
public void testEmptyLHS() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/emptyLHS.kt");
doTest(fileName);
}
@TestMetadata("enumEntryMember.kt")
public void testEnumEntryMember() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/enumEntryMember.kt");
@@ -59,6 +59,7 @@ enum class LanguageFeature(
CapturedInClosureSmartCasts(KOTLIN_1_2),
LateinitTopLevelProperties(KOTLIN_1_2),
LateinitLocalVariables(KOTLIN_1_2),
CallableReferencesToClassMembersWithEmptyLHS(KOTLIN_1_2),
RestrictionOfValReassignmentViaBackingField(KOTLIN_1_3),