diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/MemberCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/MemberCodegen.java index 7b359dc0a40..f763f555c3f 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/MemberCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/MemberCodegen.java @@ -32,6 +32,7 @@ import org.jetbrains.jet.lang.descriptors.impl.SimpleFunctionDescriptorImpl; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContextUtils; +import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.resolve.java.JvmAbi; import org.jetbrains.jet.lang.resolve.name.Name; @@ -247,8 +248,16 @@ public abstract class MemberCodegen pdResolvedCall = + bindingContext.get(BindingContext.DELEGATED_PROPERTY_PD_RESOLVED_CALL, propertyDescriptor); + if (pdResolvedCall != null) { + int index = PropertyCodegen.indexOfDelegatedProperty(property); + StackValue lastValue = PropertyCodegen.invokeDelegatedPropertyConventionMethod(propertyDescriptor, codegen, + state.getTypeMapper(), pdResolvedCall, index, 0); + lastValue.put(Type.VOID_TYPE, codegen.v); + } } private boolean shouldInitializeProperty(@NotNull JetProperty property) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java index eb33a338b66..d1d0bb676ab 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java @@ -344,7 +344,7 @@ public class PropertyCodegen { functionCodegen.generateMethod(OtherOrigin(accessor != null ? accessor : p, accessorDescriptor), signature, accessorDescriptor, strategy); } - private static int indexOfDelegatedProperty(@NotNull JetProperty property) { + public static int indexOfDelegatedProperty(@NotNull JetProperty property) { PsiElement parent = property.getParent(); JetDeclarationContainer container; if (parent instanceof JetClassBody) { @@ -409,6 +409,46 @@ public class PropertyCodegen { } } + public static StackValue invokeDelegatedPropertyConventionMethod( + @NotNull PropertyDescriptor propertyDescriptor, + @NotNull ExpressionCodegen codegen, + @NotNull JetTypeMapper typeMapper, + @NotNull ResolvedCall resolvedCall, + final int indexInPropertyMetadataArray, + int propertyMetadataArgumentIndex + ) { + if (codegen.getContext().getContextKind() != OwnerKind.PACKAGE) { + codegen.v.load(0, OBJECT_TYPE); + } + + CodegenContext ownerContext = codegen.getContext().getClassOrPackageParentContext(); + final Type owner; + if (ownerContext instanceof ClassContext) { + owner = typeMapper.mapClass(((ClassContext) ownerContext).getContextDescriptor()); + } + else if (ownerContext instanceof PackageContext) { + owner = ((PackageContext) ownerContext).getPackagePartType(); + } + else { + throw new UnsupportedOperationException("Unknown context: " + ownerContext); + } + + codegen.tempVariables.put( + resolvedCall.getCall().getValueArguments().get(propertyMetadataArgumentIndex).asElement(), + new StackValue(PROPERTY_METADATA_TYPE) { + @Override + public void put(Type type, InstructionAdapter v) { + v.getstatic(owner.getInternalName(), JvmAbi.PROPERTY_METADATA_ARRAY_NAME, "[" + PROPERTY_METADATA_TYPE); + v.iconst(indexInPropertyMetadataArray); + StackValue.arrayElement(PROPERTY_METADATA_TYPE).put(type, v); + } + } + ); + + StackValue delegatedProperty = codegen.intermediateValueForProperty(propertyDescriptor, true, null); + return codegen.invokeFunction(resolvedCall, delegatedProperty); + } + private static class DelegatedPropertyAccessorStrategy extends FunctionGenerationStrategy.CodegenBased { private final int index; @@ -426,37 +466,8 @@ public class PropertyCodegen { bindingContext.get(BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, callableDescriptor); assert resolvedCall != null : "Resolve call should be recorded for delegate call " + signature.toString(); - if (codegen.getContext().getContextKind() != OwnerKind.PACKAGE) { - v.load(0, OBJECT_TYPE); - } - - CodegenContext ownerContext = codegen.getContext().getClassOrPackageParentContext(); - final Type owner; - if (ownerContext instanceof ClassContext) { - owner = state.getTypeMapper().mapClass(((ClassContext) ownerContext).getContextDescriptor()); - } - else if (ownerContext instanceof PackageContext) { - owner = ((PackageContext) ownerContext).getPackagePartType(); - } - else { - throw new UnsupportedOperationException("Unknown context: " + ownerContext); - } - - codegen.tempVariables.put( - resolvedCall.getCall().getValueArguments().get(1).asElement(), - new StackValue(PROPERTY_METADATA_TYPE) { - @Override - public void put(Type type, InstructionAdapter v) { - v.getstatic(owner.getInternalName(), JvmAbi.PROPERTY_METADATA_ARRAY_NAME, "[" + PROPERTY_METADATA_TYPE); - v.iconst(index); - StackValue.arrayElement(PROPERTY_METADATA_TYPE).put(type, v); - } - } - ); - - StackValue delegatedProperty = codegen.intermediateValueForProperty(callableDescriptor.getCorrespondingProperty(), true, null); - StackValue lastValue = codegen.invokeFunction(resolvedCall, delegatedProperty); - + StackValue lastValue = invokeDelegatedPropertyConventionMethod(callableDescriptor.getCorrespondingProperty(), + codegen, state.getTypeMapper(), resolvedCall, index, 1); Type asmType = signature.getReturnType(); lastValue.put(asmType, v); v.areturn(asmType); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java index df20ffd2213..22f9175efd1 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java @@ -446,6 +446,7 @@ public interface Errors { DiagnosticFactory2>> DELEGATE_SPECIAL_FUNCTION_AMBIGUITY = DiagnosticFactory2.create(ERROR); DiagnosticFactory2>> DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE = DiagnosticFactory2.create(ERROR); DiagnosticFactory3 DELEGATE_SPECIAL_FUNCTION_RETURN_TYPE_MISMATCH = DiagnosticFactory3.create(ERROR); + DiagnosticFactory2>> DELEGATE_PD_METHOD_NONE_APPLICABLE = DiagnosticFactory2.create(WARNING); DiagnosticFactory1 COMPARE_TO_TYPE_MISMATCH = DiagnosticFactory1.create(ERROR); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java index 57ce94d2bed..2c9e9318b99 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java @@ -285,6 +285,7 @@ public class DefaultErrorMessages { STRING, AMBIGUOUS_CALLS); MAP.put(DELEGATE_SPECIAL_FUNCTION_RETURN_TYPE_MISMATCH, "The ''{0}'' function of property delegate is expected to return ''{1}'', but returns ''{2}''", STRING, RENDER_TYPE, RENDER_TYPE); + MAP.put(DELEGATE_PD_METHOD_NONE_APPLICABLE, "''{0}'' method may be missing. None of the following functions will be called: {1}", STRING, AMBIGUOUS_CALLS); MAP.put(COMPARE_TO_TYPE_MISMATCH, "''compareTo()'' must return kotlin.Int, but returns {0}", RENDER_TYPE); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java index 82323680578..749404f6e9b 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java @@ -113,6 +113,8 @@ public interface BindingContext { WritableSlice> DELEGATED_PROPERTY_RESOLVED_CALL = Slices.createSimpleSlice(); WritableSlice DELEGATED_PROPERTY_CALL = Slices.createSimpleSlice(); + WritableSlice> DELEGATED_PROPERTY_PD_RESOLVED_CALL = Slices.createSimpleSlice(); + WritableSlice> COMPONENT_RESOLVED_CALL = Slices.createSimpleSlice(); WritableSlice> INDEXED_LVALUE_GET = Slices.createSimpleSlice(); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java index 59ca5f6be6c..c0dba0c378a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java @@ -18,7 +18,6 @@ package org.jetbrains.jet.lang.resolve; import com.google.common.collect.Maps; import com.google.common.collect.Sets; -import com.intellij.lang.ASTNode; import com.intellij.psi.PsiElement; import com.intellij.util.containers.Queue; import org.jetbrains.annotations.NotNull; @@ -26,17 +25,13 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.calls.CallResolver; -import org.jetbrains.jet.lang.resolve.calls.context.ContextDependency; -import org.jetbrains.jet.lang.resolve.calls.context.SimpleResolutionContext; import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults; import org.jetbrains.jet.lang.resolve.calls.util.CallMaker; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.resolve.scopes.*; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue; import org.jetbrains.jet.lang.types.*; -import org.jetbrains.jet.lang.types.expressions.DataFlowUtils; import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices; -import org.jetbrains.jet.lexer.JetModifierKeywordToken; import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.util.Box; import org.jetbrains.jet.util.ReenteringLazyValueComputationException; @@ -553,6 +548,9 @@ public class BodyResolver { delegatedPropertyResolver.resolveDelegatedPropertySetMethod(propertyDescriptor, delegateExpression, delegateType, trace, accessorScope); } + + delegatedPropertyResolver.resolveDelegatedPropertyPDMethod(propertyDescriptor, delegateExpression, delegateType, + trace, accessorScope); } public void resolvePropertyInitializer( diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DelegatedPropertyResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DelegatedPropertyResolver.java index cd35edfe785..2ca7eae7add 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DelegatedPropertyResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DelegatedPropertyResolver.java @@ -61,6 +61,8 @@ public class DelegatedPropertyResolver { @NotNull private CallResolver callResolver; + private static final String PD_METHOD_NAME = "propertyDelegated"; + @Inject public void setExpressionTypingServices(@NotNull ExpressionTypingServices expressionTypingServices) { this.expressionTypingServices = expressionTypingServices; @@ -115,6 +117,55 @@ public class DelegatedPropertyResolver { resolveDelegatedPropertyConventionMethod(propertyDescriptor, delegateExpression, delegateType, trace, scope, false); } + @NotNull + private static JetExpression createExpressionForPropertyMetadata( + @NotNull JetPsiFactory psiFactory, + @NotNull PropertyDescriptor propertyDescriptor + ) { + return psiFactory.createExpression(KotlinBuiltIns.getInstance().getPropertyMetadataImpl().getName().asString() + + "(\"" + + propertyDescriptor.getName().asString() + + "\")"); + } + + public void resolveDelegatedPropertyPDMethod( + @NotNull PropertyDescriptor propertyDescriptor, + @NotNull JetExpression delegateExpression, + @NotNull JetType delegateType, + @NotNull BindingTrace trace, + @NotNull JetScope scope + ) { + TemporaryBindingTrace traceToResolvePDMethod = TemporaryBindingTrace.create(trace, "Trace to resolve propertyDelegated method in delegated property"); + ExpressionTypingContext context = ExpressionTypingContext.newContext( + expressionTypingServices, traceToResolvePDMethod, scope, + DataFlowInfo.EMPTY, TypeUtils.NO_EXPECTED_TYPE); + + List arguments = Lists.newArrayList(); + JetPsiFactory psiFactory = JetPsiFactory(delegateExpression); + arguments.add(createExpressionForPropertyMetadata(psiFactory, propertyDescriptor)); + Name functionName = Name.identifier(PD_METHOD_NAME); + JetReferenceExpression fakeCalleeExpression = psiFactory.createSimpleName(functionName.asString()); + ExpressionReceiver receiver = new ExpressionReceiver(delegateExpression, delegateType); + Call call = CallMaker.makeCallWithExpressions(fakeCalleeExpression, receiver, null, fakeCalleeExpression, arguments, Call.CallType.DEFAULT); + + OverloadResolutionResults functionResults = + callResolver.resolveCallWithGivenName(context, call, fakeCalleeExpression, functionName); + + if (!functionResults.isSuccess()) { + String expectedFunction = renderCall(call, traceToResolvePDMethod.getBindingContext()); + if (functionResults.isIncomplete() || functionResults.isSingleResult() || + functionResults.getResultCode() == OverloadResolutionResults.Code.MANY_FAILED_CANDIDATES) { + trace.report(DELEGATE_PD_METHOD_NONE_APPLICABLE.on(delegateExpression, expectedFunction, functionResults.getResultingCalls())); + } else if (functionResults.isAmbiguity()) { + trace.report(DELEGATE_SPECIAL_FUNCTION_AMBIGUITY + .on(delegateExpression, expectedFunction, functionResults.getResultingCalls())); + } + return; + } + + trace.record(DELEGATED_PROPERTY_PD_RESOLVED_CALL, propertyDescriptor, functionResults.getResultingCall()); + } + /* Resolve get() or set() methods from delegate */ private void resolveDelegatedPropertyConventionMethod( @NotNull PropertyDescriptor propertyDescriptor, @@ -179,10 +230,7 @@ public class DelegatedPropertyResolver { JetPsiFactory psiFactory = JetPsiFactory(delegateExpression); arguments.add(psiFactory.createExpression(hasThis ? "this" : "null")); - arguments.add(psiFactory.createExpression(KotlinBuiltIns.getInstance().getPropertyMetadataImpl().getName().asString() + - "(\"" + - propertyDescriptor.getName().asString() + - "\")")); + arguments.add(createExpressionForPropertyMetadata(psiFactory, propertyDescriptor)); if (!isGet) { JetReferenceExpression fakeArgument = (JetReferenceExpression) createFakeExpressionOfType(expressionTypingServices.getProject(), trace, diff --git a/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/defaultArgs.kt b/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/defaultArgs.kt new file mode 100644 index 00000000000..8e9c3fa8ee7 --- /dev/null +++ b/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/defaultArgs.kt @@ -0,0 +1,11 @@ +class Delegate { + var name = "" + fun get(t: Any?, p: PropertyMetadata): String = name + fun propertyDelegated(p: PropertyMetadata, s: String = "is OK") { name = "${p.name} $s" } +} + +val prop by Delegate() + +fun box(): String { + return if (prop == "prop is OK") "OK" else "fail"; +} diff --git a/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/delegateAsInnerClass.kt b/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/delegateAsInnerClass.kt new file mode 100644 index 00000000000..bfdcab95031 --- /dev/null +++ b/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/delegateAsInnerClass.kt @@ -0,0 +1,13 @@ +class A { + val prop: String by Delegate() + + inner class Delegate { + var name = "" + fun get(t: Any?, p: PropertyMetadata): String = name + fun propertyDelegated(p: PropertyMetadata) { name = p.name } + } +} + +fun box(): String { + return if (A().prop == "prop") "OK" else "fail" +} diff --git a/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/delegateByOtherProperty.kt b/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/delegateByOtherProperty.kt new file mode 100644 index 00000000000..662e8c3558d --- /dev/null +++ b/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/delegateByOtherProperty.kt @@ -0,0 +1,14 @@ +class Delegate { + var name = "" + fun get(t: Any?, p: PropertyMetadata): String = name + fun propertyDelegated(p: PropertyMetadata) { name = p.name } +} + +class A { + val p = Delegate() + val prop by p +} + +fun box(): String { + return if (A().prop == "prop") "OK" else "fail" +} diff --git a/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/delegateByTopLevelFun.kt b/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/delegateByTopLevelFun.kt new file mode 100644 index 00000000000..3d04b072ad6 --- /dev/null +++ b/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/delegateByTopLevelFun.kt @@ -0,0 +1,15 @@ +class Delegate { + var name = "" + fun get(t: Any?, p: PropertyMetadata): String = name + fun propertyDelegated(p: PropertyMetadata) { name = p.name } +} + +fun foo() = Delegate() + +class A { + val prop by foo() +} + +fun box(): String { + return if (A().prop == "prop") "OK" else "fail" +} diff --git a/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/delegateByTopLevelProperty.kt b/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/delegateByTopLevelProperty.kt new file mode 100644 index 00000000000..ecd202ed1b2 --- /dev/null +++ b/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/delegateByTopLevelProperty.kt @@ -0,0 +1,15 @@ +class Delegate { + var name = "" + fun get(t: Any?, p: PropertyMetadata): String = name + fun propertyDelegated(p: PropertyMetadata) { name = p.name } +} + +val p = Delegate() + +class A { + val prop by p +} + +fun box(): String { + return if (A().prop == "prop") "OK" else "fail" +} diff --git a/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/delegateForExtProperty.kt b/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/delegateForExtProperty.kt new file mode 100644 index 00000000000..78b6b72c799 --- /dev/null +++ b/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/delegateForExtProperty.kt @@ -0,0 +1,14 @@ +class Delegate { + var name = "" + fun get(t: A, p: PropertyMetadata): String = name + fun propertyDelegated(p: PropertyMetadata) { name = p.name } +} + +val A.prop by Delegate() + +class A { +} + +fun box(): String { + return if (A().prop == "prop") "OK" else "fail" +} diff --git a/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/delegateForExtPropertyInClass.kt b/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/delegateForExtPropertyInClass.kt new file mode 100644 index 00000000000..9847d59141e --- /dev/null +++ b/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/delegateForExtPropertyInClass.kt @@ -0,0 +1,20 @@ +class Delegate { + var name = "" + fun get(t: F.A, p: PropertyMetadata): String = name + fun propertyDelegated(p: PropertyMetadata) { name = p.name } +} + +class F { + val A.prop by Delegate() + + class A { + } + + fun foo(): String { + return A().prop + } +} + +fun box(): String { + return if (F().foo() == "prop") "OK" else "fail" +} diff --git a/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/inTrait.kt b/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/inTrait.kt new file mode 100644 index 00000000000..c721d6b81b9 --- /dev/null +++ b/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/inTrait.kt @@ -0,0 +1,17 @@ +class Delegate { + var name = "" + fun get(t: Any?, p: PropertyMetadata): String = name + fun propertyDelegated(p: PropertyMetadata) { name = p.name } +} + +trait A { + val prop: String +} + +class AImpl: A { + override val prop by Delegate() +} + +fun box(): String { + return if(AImpl().prop == "prop") "OK" else "fail" +} diff --git a/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/noneApplicable.kt b/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/noneApplicable.kt new file mode 100644 index 00000000000..be58e350a95 --- /dev/null +++ b/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/noneApplicable.kt @@ -0,0 +1,17 @@ +class Delegate { + var inner = "OK" + fun get(t: Any?, p: PropertyMetadata): String = inner + + private fun propertyDelegated(p: PropertyMetadata) { inner = "fail" } + fun propertyDelegated() { inner = "fail" } + fun propertyDelegated(a: Int) { inner = "fail" } + fun propertyDelegated(a: String) { inner = "fail" } + fun propertyDelegated(p: PropertyMetadata, a: Int) { inner = "fail" } + fun propertyDelegated(p: PropertyMetadata, s: String = "") { inner = "fail" } +} + +val prop by Delegate() + +fun box(): String { + return prop +} diff --git a/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/pdAsExtensionFun.kt b/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/pdAsExtensionFun.kt new file mode 100644 index 00000000000..288da33c340 --- /dev/null +++ b/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/pdAsExtensionFun.kt @@ -0,0 +1,14 @@ +class Delegate { + var name = "" + fun get(t: Any?, p: PropertyMetadata): String = name +} + +fun Delegate.propertyDelegated(p: PropertyMetadata) { name = p.name } + +class A { + val prop by Delegate() +} + +fun box(): String { + return if (A().prop == "prop") "OK" else "fail" +} diff --git a/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/privateProperty.kt b/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/privateProperty.kt new file mode 100644 index 00000000000..90b752b9d35 --- /dev/null +++ b/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/privateProperty.kt @@ -0,0 +1,17 @@ +class Delegate { + var name = "" + fun get(t: Any?, p: PropertyMetadata): String = name + fun propertyDelegated(p: PropertyMetadata) { name = p.name } +} + +class A { + private val prop by Delegate() + + fun test(): String { + return if (prop == "prop") "OK" else "fail" + } +} + +fun box(): String { + return A().test() +} diff --git a/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/topLevel.kt b/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/topLevel.kt new file mode 100644 index 00000000000..3aee0c69b88 --- /dev/null +++ b/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/topLevel.kt @@ -0,0 +1,11 @@ +class Delegate { + var name = "" + fun get(t: Any?, p: PropertyMetadata): String = name + fun propertyDelegated(p: PropertyMetadata) { name = p.name } +} + +val prop by Delegate() + +fun box(): String { + return if (prop == "prop") "OK" else "fail" +} diff --git a/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/twoPropsByOneDelegate.kt b/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/twoPropsByOneDelegate.kt new file mode 100644 index 00000000000..2d7c5413cbe --- /dev/null +++ b/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/twoPropsByOneDelegate.kt @@ -0,0 +1,14 @@ +class Delegate { + var count = 0 + fun get(t: Any?, p: PropertyMetadata) {} + fun propertyDelegated(vararg p: PropertyMetadata) { count++ } +} + +val delegate = Delegate() + +val prop1 by delegate +val prop2 by delegate + +fun box(): String { + return if(delegate.count == 2) "OK" else "fail" +} diff --git a/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/valInInnerClass.kt b/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/valInInnerClass.kt new file mode 100644 index 00000000000..fb933a3716f --- /dev/null +++ b/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/valInInnerClass.kt @@ -0,0 +1,16 @@ +class Delegate { + var name = "" + fun get(t: Any?, p: PropertyMetadata): String = name + fun propertyDelegated(p: PropertyMetadata) { name = p.name } +} + +class A { + inner class B { + val prop by Delegate() + } +} + +fun box(): String { + val p = A().B().prop + return if(p == "prop") "OK" else "fail" +} diff --git a/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/vararg.kt b/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/vararg.kt new file mode 100644 index 00000000000..91935aaa9c9 --- /dev/null +++ b/compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/vararg.kt @@ -0,0 +1,11 @@ +class Delegate { + var name = "" + fun get(t: Any?, p: PropertyMetadata): String = name + fun propertyDelegated(vararg p: PropertyMetadata) { name = p[0].name } +} + +val prop by Delegate() + +fun box(): String { + return if (prop == "prop") "OK" else "fail" +} diff --git a/compiler/testData/diagnostics/tests/delegatedProperty/propertyDelegatedAmbiguity.kt b/compiler/testData/diagnostics/tests/delegatedProperty/propertyDelegatedAmbiguity.kt new file mode 100644 index 00000000000..0c0e737eb71 --- /dev/null +++ b/compiler/testData/diagnostics/tests/delegatedProperty/propertyDelegatedAmbiguity.kt @@ -0,0 +1,16 @@ +val a: Int by Delegate() + +class Delegate { + fun get(t: Any?, p: PropertyMetadata): Int { + t.equals(p) // to avoid UNUSED_PARAMETER warning + return 1 + } + + fun propertyDelegated(p: PropertyMetadata) { + p.equals(p) + } + + fun propertyDelegated(p: PropertyMetadata, s: String = "") { + p.equals(s) + } +} diff --git a/compiler/testData/diagnostics/tests/delegatedProperty/propertyDelegatedAmbiguity.txt b/compiler/testData/diagnostics/tests/delegatedProperty/propertyDelegatedAmbiguity.txt new file mode 100644 index 00000000000..5dea54e228e --- /dev/null +++ b/compiler/testData/diagnostics/tests/delegatedProperty/propertyDelegatedAmbiguity.txt @@ -0,0 +1,13 @@ +package + +internal val a: kotlin.Int + +internal final class Delegate { + public constructor Delegate() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + internal final fun get(/*0*/ t: kotlin.Any?, /*1*/ p: kotlin.PropertyMetadata): kotlin.Int + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + internal final fun propertyDelegated(/*0*/ p: kotlin.PropertyMetadata): kotlin.Unit + internal final fun propertyDelegated(/*0*/ p: kotlin.PropertyMetadata, /*1*/ s: kotlin.String = ...): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/delegatedProperty/propertyDelegatedIncomplete.kt b/compiler/testData/diagnostics/tests/delegatedProperty/propertyDelegatedIncomplete.kt new file mode 100644 index 00000000000..85ad8005d42 --- /dev/null +++ b/compiler/testData/diagnostics/tests/delegatedProperty/propertyDelegatedIncomplete.kt @@ -0,0 +1,12 @@ +val a: Int by Delegate() + +class Delegate { + fun get(t: Any?, p: PropertyMetadata): Int { + t.equals(p) // to avoid UNUSED_PARAMETER warning + return 1 + } + + fun propertyDelegated(p: PropertyMetadata) { + p.equals(p) + } +} diff --git a/compiler/testData/diagnostics/tests/delegatedProperty/propertyDelegatedIncomplete.txt b/compiler/testData/diagnostics/tests/delegatedProperty/propertyDelegatedIncomplete.txt new file mode 100644 index 00000000000..a0a4d7f7be7 --- /dev/null +++ b/compiler/testData/diagnostics/tests/delegatedProperty/propertyDelegatedIncomplete.txt @@ -0,0 +1,12 @@ +package + +internal val a: kotlin.Int + +internal final class Delegate { + public constructor Delegate() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + internal final fun get(/*0*/ t: kotlin.Any?, /*1*/ p: kotlin.PropertyMetadata): kotlin.Int + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + internal final fun propertyDelegated(/*0*/ p: kotlin.PropertyMetadata): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/delegatedProperty/propertyDelegatedMissing.kt b/compiler/testData/diagnostics/tests/delegatedProperty/propertyDelegatedMissing.kt new file mode 100644 index 00000000000..b57b29014ec --- /dev/null +++ b/compiler/testData/diagnostics/tests/delegatedProperty/propertyDelegatedMissing.kt @@ -0,0 +1,8 @@ +val a: Int by Delegate() + +class Delegate { + fun get(t: Any?, p: PropertyMetadata): Int { + t.equals(p) // to avoid UNUSED_PARAMETER warning + return 1 + } +} diff --git a/compiler/testData/diagnostics/tests/delegatedProperty/propertyDelegatedMissing.txt b/compiler/testData/diagnostics/tests/delegatedProperty/propertyDelegatedMissing.txt new file mode 100644 index 00000000000..82a024cfa5a --- /dev/null +++ b/compiler/testData/diagnostics/tests/delegatedProperty/propertyDelegatedMissing.txt @@ -0,0 +1,11 @@ +package + +internal val a: kotlin.Int + +internal final class Delegate { + public constructor Delegate() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + internal final fun get(/*0*/ t: kotlin.Any?, /*1*/ p: kotlin.PropertyMetadata): kotlin.Int + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/delegatedProperty/propertyDelegatedPrivate.kt b/compiler/testData/diagnostics/tests/delegatedProperty/propertyDelegatedPrivate.kt new file mode 100644 index 00000000000..fc4e108a60e --- /dev/null +++ b/compiler/testData/diagnostics/tests/delegatedProperty/propertyDelegatedPrivate.kt @@ -0,0 +1,12 @@ +val a: Int by Delegate() + +class Delegate { + fun get(t: Any?, p: PropertyMetadata): Int { + t.equals(p) // to avoid UNUSED_PARAMETER warning + return 1 + } + + private fun propertyDelegated(p: PropertyMetadata) { + p.equals(p) + } +} diff --git a/compiler/testData/diagnostics/tests/delegatedProperty/propertyDelegatedPrivate.txt b/compiler/testData/diagnostics/tests/delegatedProperty/propertyDelegatedPrivate.txt new file mode 100644 index 00000000000..5b447221764 --- /dev/null +++ b/compiler/testData/diagnostics/tests/delegatedProperty/propertyDelegatedPrivate.txt @@ -0,0 +1,12 @@ +package + +internal val a: kotlin.Int + +internal final class Delegate { + public constructor Delegate() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + internal final fun get(/*0*/ t: kotlin.Any?, /*1*/ p: kotlin.PropertyMetadata): kotlin.Int + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + private final fun propertyDelegated(/*0*/ p: kotlin.PropertyMetadata): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/delegatedProperty/propertyDelegatedWrongArguments.kt b/compiler/testData/diagnostics/tests/delegatedProperty/propertyDelegatedWrongArguments.kt new file mode 100644 index 00000000000..1a9516e4e8c --- /dev/null +++ b/compiler/testData/diagnostics/tests/delegatedProperty/propertyDelegatedWrongArguments.kt @@ -0,0 +1,22 @@ +val a: Int by Delegate() + +class Delegate { + fun get(t: Any?, p: PropertyMetadata): Int { + t.equals(p) // to avoid UNUSED_PARAMETER warning + return 1 + } + + fun propertyDelegated() {} + + fun propertyDelegated(a: Int) { + a.equals(a) + } + + fun propertyDelegated(a: String) { + a.equals(a) + } + + fun propertyDelegated(p: PropertyMetadata, a: Int) { + p.equals(a) + } +} diff --git a/compiler/testData/diagnostics/tests/delegatedProperty/propertyDelegatedWrongArguments.txt b/compiler/testData/diagnostics/tests/delegatedProperty/propertyDelegatedWrongArguments.txt new file mode 100644 index 00000000000..368b9eafbb3 --- /dev/null +++ b/compiler/testData/diagnostics/tests/delegatedProperty/propertyDelegatedWrongArguments.txt @@ -0,0 +1,15 @@ +package + +internal val a: kotlin.Int + +internal final class Delegate { + public constructor Delegate() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + internal final fun get(/*0*/ t: kotlin.Any?, /*1*/ p: kotlin.PropertyMetadata): kotlin.Int + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + internal final fun propertyDelegated(): kotlin.Unit + internal final fun propertyDelegated(/*0*/ a: kotlin.Int): kotlin.Unit + internal final fun propertyDelegated(/*0*/ p: kotlin.PropertyMetadata, /*1*/ a: kotlin.Int): kotlin.Unit + internal final fun propertyDelegated(/*0*/ a: kotlin.String): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index 1852e4fff26..2431c8dbc24 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -2934,6 +2934,36 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest(fileName); } + @TestMetadata("propertyDelegatedAmbiguity.kt") + public void testPropertyDelegatedAmbiguity() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/delegatedProperty/propertyDelegatedAmbiguity.kt"); + doTest(fileName); + } + + @TestMetadata("propertyDelegatedIncomplete.kt") + public void testPropertyDelegatedIncomplete() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/delegatedProperty/propertyDelegatedIncomplete.kt"); + doTest(fileName); + } + + @TestMetadata("propertyDelegatedMissing.kt") + public void testPropertyDelegatedMissing() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/delegatedProperty/propertyDelegatedMissing.kt"); + doTest(fileName); + } + + @TestMetadata("propertyDelegatedPrivate.kt") + public void testPropertyDelegatedPrivate() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/delegatedProperty/propertyDelegatedPrivate.kt"); + doTest(fileName); + } + + @TestMetadata("propertyDelegatedWrongArguments.kt") + public void testPropertyDelegatedWrongArguments() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/delegatedProperty/propertyDelegatedWrongArguments.kt"); + doTest(fileName); + } + @TestMetadata("publicDelegatedProperty.kt") public void testPublicDelegatedProperty() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/delegatedProperty/publicDelegatedProperty.kt"); diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java index 115e504779b..49b3445ad60 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java @@ -2276,6 +2276,7 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { @TestMetadata("compiler/testData/codegen/box/delegatedProperty") @TestDataPath("$PROJECT_ROOT") + @InnerTestClasses({DelegatedProperty.PropertyDelegatedMethod.class}) @RunWith(org.jetbrains.jet.JUnit3RunnerWithInners.class) public static class DelegatedProperty extends AbstractBlackBoxCodegenTest { @TestMetadata("accessTopLevelDelegatedPropertyInClinit.kt") @@ -2456,6 +2457,106 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod") + @TestDataPath("$PROJECT_ROOT") + @RunWith(org.jetbrains.jet.JUnit3RunnerWithInners.class) + public static class PropertyDelegatedMethod extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInPropertyDelegatedMethod() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("defaultArgs.kt") + public void testDefaultArgs() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/defaultArgs.kt"); + doTest(fileName); + } + + @TestMetadata("delegateAsInnerClass.kt") + public void testDelegateAsInnerClass() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/delegateAsInnerClass.kt"); + doTest(fileName); + } + + @TestMetadata("delegateByOtherProperty.kt") + public void testDelegateByOtherProperty() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/delegateByOtherProperty.kt"); + doTest(fileName); + } + + @TestMetadata("delegateByTopLevelFun.kt") + public void testDelegateByTopLevelFun() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/delegateByTopLevelFun.kt"); + doTest(fileName); + } + + @TestMetadata("delegateByTopLevelProperty.kt") + public void testDelegateByTopLevelProperty() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/delegateByTopLevelProperty.kt"); + doTest(fileName); + } + + @TestMetadata("delegateForExtProperty.kt") + public void testDelegateForExtProperty() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/delegateForExtProperty.kt"); + doTest(fileName); + } + + @TestMetadata("delegateForExtPropertyInClass.kt") + public void testDelegateForExtPropertyInClass() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/delegateForExtPropertyInClass.kt"); + doTest(fileName); + } + + @TestMetadata("inTrait.kt") + public void testInTrait() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/inTrait.kt"); + doTest(fileName); + } + + @TestMetadata("noneApplicable.kt") + public void testNoneApplicable() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/noneApplicable.kt"); + doTest(fileName); + } + + @TestMetadata("pdAsExtensionFun.kt") + public void testPdAsExtensionFun() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/pdAsExtensionFun.kt"); + doTest(fileName); + } + + @TestMetadata("privateProperty.kt") + public void testPrivateProperty() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/privateProperty.kt"); + doTest(fileName); + } + + @TestMetadata("topLevel.kt") + public void testTopLevel() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/topLevel.kt"); + doTest(fileName); + } + + @TestMetadata("twoPropsByOneDelegate.kt") + public void testTwoPropsByOneDelegate() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/twoPropsByOneDelegate.kt"); + doTest(fileName); + } + + @TestMetadata("valInInnerClass.kt") + public void testValInInnerClass() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/valInInnerClass.kt"); + doTest(fileName); + } + + @TestMetadata("vararg.kt") + public void testVararg() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/propertyDelegatedMethod/vararg.kt"); + doTest(fileName); + } + + } + } @TestMetadata("compiler/testData/codegen/box/elvis") diff --git a/idea/idea-analysis/src/org/jetbrains/jet/plugin/highlighter/IdeErrorMessages.java b/idea/idea-analysis/src/org/jetbrains/jet/plugin/highlighter/IdeErrorMessages.java index cd33cdddede..7202f40e17c 100644 --- a/idea/idea-analysis/src/org/jetbrains/jet/plugin/highlighter/IdeErrorMessages.java +++ b/idea/idea-analysis/src/org/jetbrains/jet/plugin/highlighter/IdeErrorMessages.java @@ -104,6 +104,8 @@ public class IdeErrorMessages { MAP.put(DELEGATE_SPECIAL_FUNCTION_AMBIGUITY, "Overload resolution ambiguity on method ''{0}''. All these functions match.
    {1}
", STRING, HTML_AMBIGUOUS_CALLS); MAP.put(DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE, "Property delegate must have a ''{0}'' method. None of the following functions is suitable.
    {1}
", STRING, HTML_NONE_APPLICABLE_CALLS); + MAP.put(DELEGATE_PD_METHOD_NONE_APPLICABLE, "''{0}'' method may be missing. None of the following functions will be called:
    {1}
", + STRING, HTML_NONE_APPLICABLE_CALLS); MAP.put(CONFLICTING_JVM_DECLARATIONS, "Platform declaration clash: {0}", HTML_CONFLICTING_JVM_DECLARATIONS_DATA); MAP.put(ACCIDENTAL_OVERRIDE, "Accidental override: {0}", HTML_CONFLICTING_JVM_DECLARATIONS_DATA);