From ecec6acde89a8a1c6abf301d0e661c677ecfd343 Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Tue, 4 Jun 2013 16:25:31 +0400 Subject: [PATCH 1/4] use explicit type of delegated property as expected while resolving constraint system for delegated expression --- .../jetbrains/jet/lang/psi/JetPsiUtil.java | 21 ++++ .../jet/lang/resolve/BindingContext.java | 2 + .../jet/lang/resolve/BodyResolver.java | 95 ++++++++++++++++++- .../lang/resolve/calls/CandidateResolver.java | 15 +++ .../calls/inference/ConstraintPosition.java | 1 + .../inference/ConstraintSystemCompleter.java | 27 ++++++ .../expressions/DelegatedPropertyUtils.java | 72 ++++++++------ .../differentDelegatedExpressions.kt | 50 ++++++++++ .../noErrorsForImplicitConstraints.kt | 42 ++++++++ .../inference/useExpectedType.kt | 84 ++++++++++++++++ .../checkers/JetDiagnosticsTestGenerated.java | 37 +++++++- .../BlackBoxCodegenTestGenerated.java | 4 +- 12 files changed, 416 insertions(+), 34 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintSystemCompleter.java create mode 100644 compiler/testData/diagnostics/tests/delegatedProperty/inference/differentDelegatedExpressions.kt create mode 100644 compiler/testData/diagnostics/tests/delegatedProperty/inference/noErrorsForImplicitConstraints.kt create mode 100644 compiler/testData/diagnostics/tests/delegatedProperty/inference/useExpectedType.kt diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java index bb3a578a368..379a1e36630 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java @@ -755,4 +755,25 @@ public class JetPsiUtil { public static boolean isInComment(PsiElement element) { return CommentUtilCore.isComment(element) || element instanceof KDocElement; } + + @Nullable + public static JetExpression getCalleeExpressionIfAny(@NotNull JetExpression expression) { + if (expression instanceof JetCallElement) { + JetCallElement callExpression = (JetCallElement) expression; + return callExpression.getCalleeExpression(); + } + if (expression instanceof JetQualifiedExpression) { + JetExpression selectorExpression = ((JetQualifiedExpression) expression).getSelectorExpression(); + if (selectorExpression != null) { + return getCalleeExpressionIfAny(selectorExpression); + } + } + if (expression instanceof JetUnaryExpression) { + return ((JetUnaryExpression) expression).getOperationReference(); + } + if (expression instanceof JetBinaryExpression) { + return ((JetBinaryExpression) expression).getOperationReference(); + } + return null; + } } 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 fe4b97949a4..9e51ebd58c2 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java @@ -26,6 +26,7 @@ import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.diagnostics.Diagnostic; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo; +import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemCompleter; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.resolve.name.FqName; @@ -82,6 +83,7 @@ public interface BindingContext { new BasicWritableSlice(DO_NOTHING); WritableSlice> RESOLVED_CALL = new BasicWritableSlice>(DO_NOTHING); + WritableSlice CONSTRAINT_SYSTEM_COMPLETER = new BasicWritableSlice(DO_NOTHING); WritableSlice CALL = new BasicWritableSlice(DO_NOTHING); WritableSlice> AMBIGUOUS_REFERENCE_TARGET = 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 19c1188212f..f3f5946f9cb 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java @@ -26,6 +26,10 @@ import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.impl.FunctionDescriptorUtil; import org.jetbrains.jet.lang.descriptors.impl.MutableClassDescriptor; import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintPosition; +import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystem; +import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemCompleter; +import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; import org.jetbrains.jet.lang.resolve.calls.util.CallMaker; import org.jetbrains.jet.lang.resolve.calls.CallResolver; import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults; @@ -46,7 +50,8 @@ import java.util.*; import static org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor.NO_RECEIVER_PARAMETER; import static org.jetbrains.jet.lang.diagnostics.Errors.*; -import static org.jetbrains.jet.lang.resolve.BindingContext.DEFERRED_TYPE; +import static org.jetbrains.jet.lang.resolve.BindingContext.*; +import static org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults.Code; import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE; public class BodyResolver { @@ -487,10 +492,25 @@ public class BodyResolver { JetScope propertyDeclarationInnerScope = descriptorResolver.getPropertyDeclarationInnerScopeForInitializer( propertyScope, propertyDescriptor.getTypeParameters(), NO_RECEIVER_PARAMETER, trace); - JetType delegateType = expressionTypingServices.safeGetType(propertyDeclarationInnerScope, delegateExpression, NO_EXPECTED_TYPE, - DataFlowInfo.EMPTY, trace); + TemporaryBindingTrace traceToResolveDelegatedProperty = TemporaryBindingTrace.create(trace, "Trace to resolve delegated property"); + JetScope accessorScope = JetScopeUtils.makeScopeForPropertyAccessor( + propertyDescriptor, parentScopeForAccessor, descriptorResolver, trace); + + JetExpression calleeExpression = JetPsiUtil.getCalleeExpressionIfAny(delegateExpression); + ConstraintSystemCompleter completer = + createConstraintSystemCompleter(jetProperty, propertyDescriptor, delegateExpression, accessorScope); + if (calleeExpression != null) { + traceToResolveDelegatedProperty.record(CONSTRAINT_SYSTEM_COMPLETER, calleeExpression, completer); + } + JetType delegateType = expressionTypingServices.safeGetType(propertyDeclarationInnerScope, delegateExpression, NO_EXPECTED_TYPE, + DataFlowInfo.EMPTY, traceToResolveDelegatedProperty); + traceToResolveDelegatedProperty.commit(new TraceEntryFilter() { + @Override + public boolean accept(@NotNull WritableSlice slice, Object key) { + return slice != CONSTRAINT_SYSTEM_COMPLETER; + } + }, true); - JetScope accessorScope = JetScopeUtils.makeScopeForPropertyAccessor(propertyDescriptor, parentScopeForAccessor, descriptorResolver, trace); DelegatedPropertyUtils.resolveDelegatedPropertyGetMethod(propertyDescriptor, delegateExpression, delegateType, expressionTypingServices, trace, accessorScope); @@ -500,6 +520,73 @@ public class BodyResolver { } } + private ConstraintSystemCompleter createConstraintSystemCompleter( + JetProperty property, + final PropertyDescriptor propertyDescriptor, + final JetExpression delegateExpression, + final JetScope accessorScope + ) { + final JetType expectedType = property.getTypeRef() != null ? propertyDescriptor.getType() : NO_EXPECTED_TYPE; + return new ConstraintSystemCompleter() { + @Override + public void completeConstraintSystem( + @NotNull ConstraintSystem constraintSystem, @NotNull ResolvedCall resolvedCall + ) { + JetType returnType = resolvedCall.getCandidateDescriptor().getReturnType(); + if (returnType == null) return; + + TemporaryBindingTrace traceToResolveConventionMethods = + TemporaryBindingTrace.create(trace, "Trace to resolve delegated property convention methods"); + OverloadResolutionResults + getMethodResults = DelegatedPropertyUtils.getDelegatedPropertyConventionMethod( + propertyDescriptor, delegateExpression, returnType, expressionTypingServices, + traceToResolveConventionMethods, accessorScope, true); + + if (conventionMethodFound(getMethodResults)) { + FunctionDescriptor descriptor = getMethodResults.getResultingDescriptor(); + JetType returnTypeOfGetMethod = descriptor.getReturnType(); + if (returnTypeOfGetMethod != null) { + constraintSystem.addSupertypeConstraint(expectedType, returnTypeOfGetMethod, ConstraintPosition.FROM_COMPLETER); + } + addConstraintForThisValue(constraintSystem, descriptor); + } + if (propertyDescriptor.isVar()) { + OverloadResolutionResults setMethodResults = + DelegatedPropertyUtils.getDelegatedPropertyConventionMethod( + propertyDescriptor, delegateExpression, returnType, expressionTypingServices, + traceToResolveConventionMethods, accessorScope, false); + + if (conventionMethodFound(setMethodResults)) { + FunctionDescriptor descriptor = setMethodResults.getResultingDescriptor(); + List valueParameters = descriptor.getValueParameters(); + if (valueParameters.size() == 3) { + ValueParameterDescriptor valueParameterForThis = valueParameters.get(2); + constraintSystem.addSubtypeConstraint(expectedType, valueParameterForThis.getType(), ConstraintPosition.FROM_COMPLETER); + addConstraintForThisValue(constraintSystem, descriptor); + } + } + } + } + + private boolean conventionMethodFound(@NotNull OverloadResolutionResults results) { + return results.isSuccess() || + (results.isSingleResult() && results.getResultCode() == Code.SINGLE_CANDIDATE_ARGUMENT_MISMATCH); + } + + private void addConstraintForThisValue(ConstraintSystem constraintSystem, FunctionDescriptor resultingDescriptor) { + ReceiverParameterDescriptor receiverParameter = propertyDescriptor.getReceiverParameter(); + ReceiverParameterDescriptor thisObject = propertyDescriptor.getExpectedThisObject(); + if (receiverParameter == null && thisObject == null) return; + + List valueParameters = resultingDescriptor.getValueParameters(); + if (valueParameters.isEmpty()) return; + ValueParameterDescriptor valueParameterForThis = valueParameters.get(0); + JetType typeOfThis = receiverParameter != null ? receiverParameter.getType() : thisObject.getType(); + constraintSystem.addSubtypeConstraint(typeOfThis, valueParameterForThis.getType(), ConstraintPosition.FROM_COMPLETER); + } + }; + } + public void resolvePropertyInitializer( @NotNull JetProperty property, @NotNull PropertyDescriptor propertyDescriptor, diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java index d79ca3fbbf1..8d15321b81d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java @@ -235,6 +235,21 @@ public class CandidateResolver { constraintSystem.addSupertypeConstraint(context.expectedType, descriptor.getReturnType(), ConstraintPosition.EXPECTED_TYPE_POSITION); + ConstraintSystemCompleter constraintSystemCompleter = context.trace.get( + BindingContext.CONSTRAINT_SYSTEM_COMPLETER, context.call.getCalleeExpression()); + if (constraintSystemCompleter != null) { + ConstraintSystemImpl backup = (ConstraintSystemImpl) constraintSystem.copy(); + + //todo improve error reporting with errors in constraints from completer + constraintSystemCompleter.completeConstraintSystem(constraintSystem, resolvedCall); + if (constraintSystem.hasTypeConstructorMismatchAt(ConstraintPosition.FROM_COMPLETER) || + (constraintSystem.hasContradiction() && !backup.hasContradiction())) { + + constraintSystem = backup; + resolvedCall.setConstraintSystem(backup); + } + } + if (constraintSystem.hasContradiction()) { return reportInferenceError(context); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintPosition.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintPosition.java index c8c77099e8d..d2343cb0e7b 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintPosition.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintPosition.java @@ -24,6 +24,7 @@ public class ConstraintPosition { public static final ConstraintPosition RECEIVER_POSITION = new ConstraintPosition("RECEIVER_POSITION"); public static final ConstraintPosition EXPECTED_TYPE_POSITION = new ConstraintPosition("EXPECTED_TYPE_POSITION"); public static final ConstraintPosition BOUND_CONSTRAINT_POSITION = new ConstraintPosition("BOUND_CONSTRAINT_POSITION"); + public static final ConstraintPosition FROM_COMPLETER = new ConstraintPosition("FROM_COMPLETER"); private static final Map valueParameterPositions = Maps.newHashMap(); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintSystemCompleter.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintSystemCompleter.java new file mode 100644 index 00000000000..20df3897113 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintSystemCompleter.java @@ -0,0 +1,27 @@ +/* + * Copyright 2010-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.lang.resolve.calls.inference; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; + +public interface ConstraintSystemCompleter { + void completeConstraintSystem( + @NotNull ConstraintSystem constraintSystem, + @NotNull ResolvedCall resolvedCall + ); +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/DelegatedPropertyUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/DelegatedPropertyUtils.java index c852ed51ad2..2165091bd94 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/DelegatedPropertyUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/DelegatedPropertyUtils.java @@ -123,8 +123,48 @@ public class DelegatedPropertyUtils { PropertyAccessorDescriptor accessor = isGet ? propertyDescriptor.getGetter() : propertyDescriptor.getSetter(); assert accessor != null : "Delegated property should have getter/setter " + propertyDescriptor + " " + delegateExpression.getText(); + if (trace.getBindingContext().get(DELEGATED_PROPERTY_CALL, accessor) != null) return; + + OverloadResolutionResults functionResults = getDelegatedPropertyConventionMethod( + propertyDescriptor, delegateExpression, delegateType, expressionTypingServices, trace, scope, isGet); Call call = trace.getBindingContext().get(DELEGATED_PROPERTY_CALL, accessor); - if (call != null) return; + assert call != null : "'getDelegatedPropertyConventionMethod' didn't record a call"; + + if (!functionResults.isSuccess()) { + String expectedFunction = renderCall(call, trace.getBindingContext()); + if (functionResults.isIncomplete()) { + trace.report(DELEGATE_SPECIAL_FUNCTION_MISSING.on(delegateExpression, expectedFunction, delegateType)); + } + else if (functionResults.isSingleResult() || + functionResults.getResultCode() == OverloadResolutionResults.Code.MANY_FAILED_CANDIDATES) { + trace.report(DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE + .on(delegateExpression, expectedFunction, functionResults.getResultingCalls())); + } + else if (functionResults.isAmbiguity()) { + trace.report(DELEGATE_SPECIAL_FUNCTION_AMBIGUITY + .on(delegateExpression, expectedFunction, functionResults.getResultingCalls())); + } + else { + trace.report(DELEGATE_SPECIAL_FUNCTION_MISSING.on(delegateExpression, expectedFunction, delegateType)); + } + return; + } + + trace.record(DELEGATED_PROPERTY_RESOLVED_CALL, accessor, functionResults.getResultingCall()); + } + + /* Resolve get() or set() methods from delegate */ + public static OverloadResolutionResults getDelegatedPropertyConventionMethod( + @NotNull PropertyDescriptor propertyDescriptor, + @NotNull JetExpression delegateExpression, + @NotNull JetType delegateType, + @NotNull ExpressionTypingServices expressionTypingServices, + @NotNull BindingTrace trace, + @NotNull JetScope scope, + boolean isGet + ) { + PropertyAccessorDescriptor accessor = isGet ? propertyDescriptor.getGetter() : propertyDescriptor.getSetter(); + assert accessor != null : "Delegated property should have getter/setter " + propertyDescriptor + " " + delegateExpression.getText(); ExpressionTypingContext context = ExpressionTypingContext.newContext( expressionTypingServices, trace, scope, @@ -144,39 +184,17 @@ public class DelegatedPropertyUtils { propertyDescriptor.getType()); arguments.add(fakeArgument); List valueParameters = accessor.getValueParameters(); - context.trace.record(REFERENCE_TARGET, fakeArgument, valueParameters.get(0)); + trace.record(REFERENCE_TARGET, fakeArgument, valueParameters.get(0)); } Name functionName = Name.identifier(isGet ? "get" : "set"); JetReferenceExpression fakeCalleeExpression = createSimpleName(project, functionName.asString()); ExpressionReceiver receiver = new ExpressionReceiver(delegateExpression, delegateType); - call = CallMaker.makeCallWithExpressions(fakeCalleeExpression, receiver, null, fakeCalleeExpression, arguments, Call.CallType.DEFAULT); - context.trace.record(BindingContext.DELEGATED_PROPERTY_CALL, accessor, call); + Call call = CallMaker.makeCallWithExpressions(fakeCalleeExpression, receiver, null, fakeCalleeExpression, arguments, Call.CallType.DEFAULT); + trace.record(BindingContext.DELEGATED_PROPERTY_CALL, accessor, call); - OverloadResolutionResults functionResults = context.resolveCallWithGivenName(call, fakeCalleeExpression, functionName); - - if (!functionResults.isSuccess()) { - String expectedFunction = renderCall(call, trace.getBindingContext()); - if (functionResults.isIncomplete()) { - context.trace.report(DELEGATE_SPECIAL_FUNCTION_MISSING.on(delegateExpression, expectedFunction, delegateType)); - } - else if (functionResults.isSingleResult() || - functionResults.getResultCode() == OverloadResolutionResults.Code.MANY_FAILED_CANDIDATES) { - context.trace.report(DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE - .on(delegateExpression, expectedFunction, functionResults.getResultingCalls())); - } - else if (functionResults.isAmbiguity()) { - context.trace.report(DELEGATE_SPECIAL_FUNCTION_AMBIGUITY - .on(delegateExpression, expectedFunction, functionResults.getResultingCalls())); - } - else { - context.trace.report(DELEGATE_SPECIAL_FUNCTION_MISSING.on(delegateExpression, expectedFunction, delegateType)); - } - return; - } - - context.trace.record(DELEGATED_PROPERTY_RESOLVED_CALL, accessor, functionResults.getResultingCall()); + return context.resolveCallWithGivenName(call, fakeCalleeExpression, functionName); } private static String renderCall(@NotNull Call call, @NotNull BindingContext context) { diff --git a/compiler/testData/diagnostics/tests/delegatedProperty/inference/differentDelegatedExpressions.kt b/compiler/testData/diagnostics/tests/delegatedProperty/inference/differentDelegatedExpressions.kt new file mode 100644 index 00000000000..fe071d20932 --- /dev/null +++ b/compiler/testData/diagnostics/tests/delegatedProperty/inference/differentDelegatedExpressions.kt @@ -0,0 +1,50 @@ +package baz + +class A(outer: Outer) { + var i: String by + getMyConcreteProperty() + var d: String by getMyConcreteProperty() - 1 + var c: String by O.getMyProperty() + var g: String by outer.getContainer().getMyProperty() + + + var b: String by foo(getMyProperty()) + var r: String by foo(outer.getContainer().getMyProperty()) + var e: String by + foo(getMyProperty()) + var f: String by foo(getMyProperty()) - 1 +} + +fun foo(a: Any?) = MyProperty() + +fun getMyProperty() = MyProperty() + +fun getMyConcreteProperty() = MyProperty() + +class MyProperty { + + public fun get(thisRef: R, desc: PropertyMetadata): T { + println("get $thisRef ${desc.name}") + return null as T + } + + public fun set(thisRef: R, desc: PropertyMetadata, value: T) { + println("set $thisRef ${desc.name} $value") + } +} + +fun MyProperty.plus() = MyProperty() +fun MyProperty.minus(i: Int) = MyProperty() + +object O { + fun getMyProperty() = MyProperty() +} + +trait MyPropertyContainer { + fun getMyProperty(): MyProperty +} + +trait Outer { + fun getContainer(): MyPropertyContainer +} + +// ----------------- +fun println(a: Any?) = a \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/delegatedProperty/inference/noErrorsForImplicitConstraints.kt b/compiler/testData/diagnostics/tests/delegatedProperty/inference/noErrorsForImplicitConstraints.kt new file mode 100644 index 00000000000..8a4bdbe9836 --- /dev/null +++ b/compiler/testData/diagnostics/tests/delegatedProperty/inference/noErrorsForImplicitConstraints.kt @@ -0,0 +1,42 @@ +package foo + +class A { + var a5: String by MyProperty1() + var b5: String by getMyProperty1() +} + +fun getMyProperty1() = MyProperty1() + +class MyProperty1 { + + public fun get(thisRef: R, desc: PropertyMetadata): T { + throw Exception() + } + + public fun set(i: Int, j: Int, k: Int) { + println("set") + } +} + +// ----------------- + +class B { + var a5: String by MyProperty2() + var b5: String by getMyProperty2() +} + +fun getMyProperty2() = MyProperty2() + +class MyProperty2 { + + public fun get(thisRef: R, desc: PropertyMetadata): T { + throw Exception() + } + + public fun set(i: Int) { + println("set") + } +} + +// ----------------- +fun println(a: Any?) = a \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/delegatedProperty/inference/useExpectedType.kt b/compiler/testData/diagnostics/tests/delegatedProperty/inference/useExpectedType.kt new file mode 100644 index 00000000000..ac018117d76 --- /dev/null +++ b/compiler/testData/diagnostics/tests/delegatedProperty/inference/useExpectedType.kt @@ -0,0 +1,84 @@ +package foo + +class A1 { + var a1: String by MyProperty1() + var b1: String by getMyProperty1() +} + +var c1: String by getMyProperty1() + +fun getMyProperty1() = MyProperty1() + +class MyProperty1 { + + public fun get(thisRef: R, desc: PropertyMetadata): T { + println("get $thisRef ${desc.name}") + throw Exception() + } + + public fun set(thisRef: R, desc: PropertyMetadata, value: T) { + println("set $thisRef ${desc.name} $value") + } +} + +//-------------------------- + +class A2 { + var a2: String by MyProperty2() + var b2: String by getMyProperty2() +} + +fun getMyProperty2() = MyProperty2() + +class MyProperty2 { + + public fun get(thisRef: Any?, desc: PropertyMetadata): T { + println("get $thisRef ${desc.name}") + throw Exception() + } + + public fun set(thisRef: Any?, desc: PropertyMetadata, value: T) { + println("set $thisRef ${desc.name} $value") + } +} + +//-------------------------- + +class A3 { + var a3: String by MyProperty3() + var b3: String by getMyProperty3() +} + +fun getMyProperty3() = MyProperty3() + +class MyProperty3 { + + public fun get(thisRef: T, desc: PropertyMetadata): String { + println("get $thisRef ${desc.name}") + return "" + } + + public fun set(thisRef: Any?, desc: PropertyMetadata, value: T) { + println("set $thisRef ${desc.name} $value") + } +} + +//-------------------------- + +class A4 { + val a4: String by MyProperty4() + val b4: String by getMyProperty4() +} + +fun getMyProperty4() = MyProperty4() + +class MyProperty4 { + + public fun get(thisRef: R, desc: PropertyMetadata): T { + println("get $thisRef ${desc.name}") + throw Exception() + } +} + +//-------------------------- +fun println(a: Any?) = a \ 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 3ccf049c0d8..6c6e4d1a01c 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -1888,6 +1888,7 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage } @TestMetadata("compiler/testData/diagnostics/tests/delegatedProperty") + @InnerTestClasses({DelegatedProperty.Inference.class}) public static class DelegatedProperty extends AbstractDiagnosticsTestWithEagerResolve { @TestMetadata("absentErrorAboutInitializer.kt") public void testAbsentErrorAboutInitializer() throws Exception { @@ -2053,6 +2054,35 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage doTest("compiler/testData/diagnostics/tests/delegatedProperty/wrongSetterReturnType.kt"); } + @TestMetadata("compiler/testData/diagnostics/tests/delegatedProperty/inference") + public static class Inference extends AbstractDiagnosticsTestWithEagerResolve { + public void testAllFilesPresentInInference() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/diagnostics/tests/delegatedProperty/inference"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("differentDelegatedExpressions.kt") + public void testDifferentDelegatedExpressions() throws Exception { + doTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/differentDelegatedExpressions.kt"); + } + + @TestMetadata("noErrorsForImplicitConstraints.kt") + public void testNoErrorsForImplicitConstraints() throws Exception { + doTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/noErrorsForImplicitConstraints.kt"); + } + + @TestMetadata("useExpectedType.kt") + public void testUseExpectedType() throws Exception { + doTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/useExpectedType.kt"); + } + + } + + public static Test innerSuite() { + TestSuite suite = new TestSuite("DelegatedProperty"); + suite.addTestSuite(DelegatedProperty.class); + suite.addTestSuite(Inference.class); + return suite; + } } @TestMetadata("compiler/testData/diagnostics/tests/deparenthesize") @@ -4717,6 +4747,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/diagnostics/tests/smartCasts"), Pattern.compile("^(.+)\\.kt$"), true); } + @TestMetadata("combineWithNoSelectorInfo.kt") + public void testCombineWithNoSelectorInfo() throws Exception { + doTest("compiler/testData/diagnostics/tests/smartCasts/combineWithNoSelectorInfo.kt"); + } + @TestMetadata("kt1461.kt") public void testKt1461() throws Exception { doTest("compiler/testData/diagnostics/tests/smartCasts/kt1461.kt"); @@ -4945,7 +4980,7 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage suite.addTestSuite(DataFlow.class); suite.addTestSuite(DataFlowInfoTraversal.class); suite.addTest(DeclarationChecks.innerSuite()); - suite.addTestSuite(DelegatedProperty.class); + suite.addTest(DelegatedProperty.innerSuite()); suite.addTestSuite(Deparenthesize.class); suite.addTest(Enum.innerSuite()); suite.addTestSuite(Extensions.class); diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java index aa30ff43a69..bd7388a1c49 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java @@ -1546,8 +1546,8 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest("compiler/testData/codegen/box/defaultArguments/constructor/kt2852.kt"); } - } - + } + @TestMetadata("compiler/testData/codegen/box/defaultArguments/function") public static class Function extends AbstractBlackBoxCodegenTest { public void testAllFilesPresentInFunction() throws Exception { From 2337f4b9481e3df14fc38c7c9aa4a41058c69bc0 Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Tue, 4 Jun 2013 18:08:13 +0400 Subject: [PATCH 2/4] bug fix do not combine receiverInfo with error selectorInfo --- .../calls/autocasts/DataFlowValueFactory.java | 5 ++++- .../tests/smartCasts/combineWithNoSelectorInfo.kt | 13 +++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 compiler/testData/diagnostics/tests/smartCasts/combineWithNoSelectorInfo.kt diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/autocasts/DataFlowValueFactory.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/autocasts/DataFlowValueFactory.java index 5399c1a0af1..4b26bddd5bb 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/autocasts/DataFlowValueFactory.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/autocasts/DataFlowValueFactory.java @@ -133,6 +133,9 @@ public class DataFlowValueFactory { @NotNull private static IdentifierInfo combineInfo(@Nullable IdentifierInfo receiverInfo, @NotNull IdentifierInfo selectorInfo) { + if (selectorInfo.id == null) { + return ERROR_IDENTIFIER_INFO; + } if (receiverInfo == null || receiverInfo == ERROR_IDENTIFIER_INFO || receiverInfo.isNamespace) { return selectorInfo; } @@ -182,7 +185,7 @@ public class DataFlowValueFactory { DeclarationDescriptor declarationDescriptor = bindingContext.get(REFERENCE_TARGET, simpleNameExpression); if (declarationDescriptor instanceof VariableDescriptor) { ResolvedCall resolvedCall = bindingContext.get(RESOLVED_CALL, simpleNameExpression); - // todo return assert + // todo uncomment assert // for now it fails for resolving 'invoke' convention, return it after 'invoke' algorithm changes // assert resolvedCall != null : "Cannot create right identifier info if the resolved call is not known yet for " + declarationDescriptor; diff --git a/compiler/testData/diagnostics/tests/smartCasts/combineWithNoSelectorInfo.kt b/compiler/testData/diagnostics/tests/smartCasts/combineWithNoSelectorInfo.kt new file mode 100644 index 00000000000..705b772b9d2 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/combineWithNoSelectorInfo.kt @@ -0,0 +1,13 @@ +package foo + +fun dispatch(request: Request) { + val url = request.getRequestURI() as String + + if (request.getMethod()?.length != 0) { + } +} + +trait Request { + fun getRequestURI(): String? + fun getMethod(): String? +} From 2b0616b1c4633aaecc3a1d749f747574f484bd58 Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Tue, 4 Jun 2013 19:28:57 +0400 Subject: [PATCH 3/4] rename ERROR_IDENTIFIER_INFO -> NO_IDENTIFIER_INFO --- .../calls/autocasts/DataFlowValueFactory.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/autocasts/DataFlowValueFactory.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/autocasts/DataFlowValueFactory.java index 4b26bddd5bb..d0069211aef 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/autocasts/DataFlowValueFactory.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/autocasts/DataFlowValueFactory.java @@ -119,7 +119,7 @@ public class DataFlowValueFactory { } } - private static final IdentifierInfo ERROR_IDENTIFIER_INFO = new IdentifierInfo(null, false, false); + private static final IdentifierInfo NO_IDENTIFIER_INFO = new IdentifierInfo(null, false, false); @NotNull private static IdentifierInfo createInfo(Object id, boolean isStable) { @@ -134,9 +134,9 @@ public class DataFlowValueFactory { @NotNull private static IdentifierInfo combineInfo(@Nullable IdentifierInfo receiverInfo, @NotNull IdentifierInfo selectorInfo) { if (selectorInfo.id == null) { - return ERROR_IDENTIFIER_INFO; + return NO_IDENTIFIER_INFO; } - if (receiverInfo == null || receiverInfo == ERROR_IDENTIFIER_INFO || receiverInfo.isNamespace) { + if (receiverInfo == null || receiverInfo == NO_IDENTIFIER_INFO || receiverInfo.isNamespace) { return selectorInfo; } return createInfo(Pair.create(receiverInfo.id, selectorInfo.id), receiverInfo.isStable && selectorInfo.isStable); @@ -174,7 +174,7 @@ public class DataFlowValueFactory { else if (expression instanceof JetRootNamespaceExpression) { return createNamespaceInfo(JetModuleUtil.getRootNamespaceType(expression)); } - return ERROR_IDENTIFIER_INFO; + return NO_IDENTIFIER_INFO; } @NotNull @@ -201,7 +201,7 @@ public class DataFlowValueFactory { ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor; return createInfo(classDescriptor, classDescriptor.isClassObjectAValue()); } - return ERROR_IDENTIFIER_INFO; + return NO_IDENTIFIER_INFO; } @Nullable @@ -257,7 +257,7 @@ public class DataFlowValueFactory { if (descriptorOfThisReceiver instanceof ClassDescriptor) { return createInfo(((ClassDescriptor) descriptorOfThisReceiver).getThisAsReceiverParameter().getValue(), true); } - return ERROR_IDENTIFIER_INFO; + return NO_IDENTIFIER_INFO; } public static boolean isStableVariable(@NotNull VariableDescriptor variableDescriptor) { From 7e564de71a2b0e23954df6a1fcdff01b9fc525e5 Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Tue, 4 Jun 2013 19:58:56 +0400 Subject: [PATCH 4/4] added constraint for package level delegated property --- .../jet/lang/resolve/BodyResolver.java | 7 ++- .../inference/useExpectedType.kt | 26 +++----- .../inference/useExpectedTypeForVal.kt | 62 +++++++++++++++++++ .../checkers/JetDiagnosticsTestGenerated.java | 5 ++ 4 files changed, 80 insertions(+), 20 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/delegatedProperty/inference/useExpectedTypeForVal.kt 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 f3f5946f9cb..2a050a21880 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java @@ -40,6 +40,7 @@ import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.checker.JetTypeChecker; import org.jetbrains.jet.lang.types.expressions.DelegatedPropertyUtils; import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices; +import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.util.Box; import org.jetbrains.jet.util.lazy.ReenteringLazyValueComputationException; @@ -576,12 +577,14 @@ public class BodyResolver { private void addConstraintForThisValue(ConstraintSystem constraintSystem, FunctionDescriptor resultingDescriptor) { ReceiverParameterDescriptor receiverParameter = propertyDescriptor.getReceiverParameter(); ReceiverParameterDescriptor thisObject = propertyDescriptor.getExpectedThisObject(); - if (receiverParameter == null && thisObject == null) return; + JetType typeOfThis = + receiverParameter != null ? receiverParameter.getType() : + thisObject != null ? thisObject.getType() : + KotlinBuiltIns.getInstance().getNullableNothingType(); List valueParameters = resultingDescriptor.getValueParameters(); if (valueParameters.isEmpty()) return; ValueParameterDescriptor valueParameterForThis = valueParameters.get(0); - JetType typeOfThis = receiverParameter != null ? receiverParameter.getType() : thisObject.getType(); constraintSystem.addSubtypeConstraint(typeOfThis, valueParameterForThis.getType(), ConstraintPosition.FROM_COMPLETER); } }; diff --git a/compiler/testData/diagnostics/tests/delegatedProperty/inference/useExpectedType.kt b/compiler/testData/diagnostics/tests/delegatedProperty/inference/useExpectedType.kt index ac018117d76..1d937178eb1 100644 --- a/compiler/testData/diagnostics/tests/delegatedProperty/inference/useExpectedType.kt +++ b/compiler/testData/diagnostics/tests/delegatedProperty/inference/useExpectedType.kt @@ -5,7 +5,8 @@ class A1 { var b1: String by getMyProperty1() } -var c1: String by getMyProperty1() +var c1: String by getMyProperty1() +var d1: String by MyProperty1() fun getMyProperty1() = MyProperty1() @@ -28,6 +29,9 @@ class A2 { var b2: String by getMyProperty2() } +var c2: String by getMyProperty2() +var d2: String by MyProperty2() + fun getMyProperty2() = MyProperty2() class MyProperty2 { @@ -49,6 +53,9 @@ class A3 { var b3: String by getMyProperty3() } +var c3: String by getMyProperty3() +var d3: String by MyProperty3() + fun getMyProperty3() = MyProperty3() class MyProperty3 { @@ -63,22 +70,5 @@ class MyProperty3 { } } -//-------------------------- - -class A4 { - val a4: String by MyProperty4() - val b4: String by getMyProperty4() -} - -fun getMyProperty4() = MyProperty4() - -class MyProperty4 { - - public fun get(thisRef: R, desc: PropertyMetadata): T { - println("get $thisRef ${desc.name}") - throw Exception() - } -} - //-------------------------- fun println(a: Any?) = a \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/delegatedProperty/inference/useExpectedTypeForVal.kt b/compiler/testData/diagnostics/tests/delegatedProperty/inference/useExpectedTypeForVal.kt new file mode 100644 index 00000000000..5de3690d5d7 --- /dev/null +++ b/compiler/testData/diagnostics/tests/delegatedProperty/inference/useExpectedTypeForVal.kt @@ -0,0 +1,62 @@ +package foo + +class A1 { + val a1: String by MyProperty1() + val b1: String by getMyProperty1() +} + +val c1: String by getMyProperty1() +val d1: String by MyProperty1() + +fun getMyProperty1() = MyProperty1() + +class MyProperty1 { + + public fun get(thisRef: R, desc: PropertyMetadata): T { + println("get $thisRef ${desc.name}") + throw Exception() + } +} + +//-------------------------- + +class A2 { + val a2: String by MyProperty2() + val b2: String by getMyProperty2() +} + +val c2: String by getMyProperty2() +val d2: String by MyProperty2() + +fun getMyProperty2() = MyProperty2() + +class MyProperty2 { + + public fun get(thisRef: Any?, desc: PropertyMetadata): T { + println("get $thisRef ${desc.name}") + throw Exception() + } +} + +//-------------------------- + +class A3 { + val a3: String by MyProperty3() + val b3: String by getMyProperty3() +} + +val c3: String by getMyProperty3() +val d3: String by MyProperty3() + +fun getMyProperty3() = MyProperty3() + +class MyProperty3 { + + public fun get(thisRef: T, desc: PropertyMetadata): String { + println("get $thisRef ${desc.name}") + return "" + } +} + +//-------------------------- +fun println(a: Any?) = a \ 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 6c6e4d1a01c..c95d768f16c 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -2075,6 +2075,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage doTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/useExpectedType.kt"); } + @TestMetadata("useExpectedTypeForVal.kt") + public void testUseExpectedTypeForVal() throws Exception { + doTest("compiler/testData/diagnostics/tests/delegatedProperty/inference/useExpectedTypeForVal.kt"); + } + } public static Test innerSuite() {