Skip to content

Commit

Permalink
Merge branch 'master' of git://github.com/jgl87/kotlin
Browse files Browse the repository at this point in the history
  • Loading branch information
abreslav committed Apr 1, 2014
2 parents e2f3a58 + a31d950 commit 322d884
Show file tree
Hide file tree
Showing 18 changed files with 369 additions and 3 deletions.
Expand Up @@ -1902,6 +1902,20 @@ public StackValue visitCallExpression(@NotNull JetCallExpression expression, Sta
JetExpression callee = expression.getCalleeExpression();
assert callee != null;

DottedCallInfo dottedCallInfo = bindingContext.get(BindingContext.DOTTED_CALL_INFO, expression);
if (dottedCallInfo != null) {
ResolvedCall<? extends FunctionDescriptor> resolvedDotCall = dottedCallInfo.getResolvedCall();
FunctionDescriptor dotFunDescriptor = accessibleFunctionDescriptor(resolvedDotCall.getResultingDescriptor());

JetType dotType = dotFunDescriptor.getReturnType();
assert dotType != null : "can't resolve type of dot operation: " + dotFunDescriptor;

StackValue newReceiver = invokeFunction(dottedCallInfo.getCall(), receiver, resolvedDotCall);
if (!KotlinBuiltIns.getInstance().isUnit(dotType)) {
receiver = newReceiver;
}
}

ResolvedCall<?> resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, callee);
if (resolvedCall == null) {
throw new CompilationException("Cannot resolve: " + callee.getText(), null, expression);
Expand Down
Expand Up @@ -31,6 +31,7 @@
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.resolve.CompileTimeConstantUtils;
import org.jetbrains.jet.lang.resolve.calls.model.DottedCallInfo;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument;
import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall;
Expand Down Expand Up @@ -784,6 +785,11 @@ public void visitQualifiedExpressionVoid(@NotNull JetQualifiedExpression express

generateInstructions(selectorExpression, NOT_IN_CONDITION);

DottedCallInfo dottedCallInfo = trace.get(BindingContext.DOTTED_CALL_INFO, selectorExpression);
if (dottedCallInfo != null) {
generateInstructions((JetCallExpression) dottedCallInfo.getCall().getCallElement(), NOT_IN_CONDITION);
}

// receiver was generated for resolvedCall
JetExpression calleeExpression = JetPsiUtil.getCalleeExpressionIfAny(selectorExpression);
if (calleeExpression == null || getResolvedCall(calleeExpression) == null) {
Expand Down
Expand Up @@ -28,6 +28,7 @@
import org.jetbrains.jet.lang.resolve.calls.TailRecursionKind;
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.DottedCallInfo;
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;
Expand Down Expand Up @@ -79,6 +80,7 @@ public <K, V> ImmutableMap<K, V> getSliceContents(@NotNull ReadOnlySlice<K, V> s

WritableSlice<JetTypeReference, JetType> TYPE = Slices.createSimpleSlice();
WritableSlice<JetExpression, JetType> EXPRESSION_TYPE = new BasicWritableSlice<JetExpression, JetType>(DO_NOTHING);
WritableSlice<JetExpression, JetType> DOTTED_EXPRESSION_TYPE = new BasicWritableSlice<JetExpression, JetType>(DO_NOTHING);
WritableSlice<JetExpression, JetType> EXPECTED_EXPRESSION_TYPE = new BasicWritableSlice<JetExpression, JetType>(DO_NOTHING);
WritableSlice<JetExpression, DataFlowInfo> EXPRESSION_DATA_FLOW_INFO = new BasicWritableSlice<JetExpression, DataFlowInfo>(DO_NOTHING);
WritableSlice<JetExpression, DataFlowInfo> DATAFLOW_INFO_AFTER_CONDITION = Slices.createSimpleSlice();
Expand All @@ -92,6 +94,8 @@ public <K, V> ImmutableMap<K, V> getSliceContents(@NotNull ReadOnlySlice<K, V> s
WritableSlice<JetElement, ConstraintSystemCompleter> CONSTRAINT_SYSTEM_COMPLETER = new BasicWritableSlice<JetElement, ConstraintSystemCompleter>(DO_NOTHING);
WritableSlice<JetElement, Call> CALL = new BasicWritableSlice<JetElement, Call>(DO_NOTHING);

WritableSlice<JetElement, DottedCallInfo> DOTTED_CALL_INFO = new BasicWritableSlice<JetElement, DottedCallInfo>(DO_NOTHING);

@KotlinSignature("val AMBIGUOUS_REFERENCE_TARGET: WritableSlice<JetExpression, Collection<DeclarationDescriptor>>")
WritableSlice<JetExpression, Collection<? extends DeclarationDescriptor>> AMBIGUOUS_REFERENCE_TARGET =
new BasicWritableSlice<JetExpression, Collection<? extends DeclarationDescriptor>>(DO_NOTHING);
Expand Down
Expand Up @@ -32,10 +32,10 @@
import org.jetbrains.jet.lang.resolve.calls.context.CheckValueArgumentsMode;
import org.jetbrains.jet.lang.resolve.calls.context.ResolutionContext;
import org.jetbrains.jet.lang.resolve.calls.context.TemporaryTraceAndCache;
import org.jetbrains.jet.lang.resolve.calls.model.DottedCallInfo;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallWithTrace;
import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults;
import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResultsImpl;
import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResultsUtil;
import org.jetbrains.jet.lang.resolve.calls.util.CallMaker;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
Expand Down Expand Up @@ -451,6 +451,52 @@ public JetTypeInfo getQualifiedExpressionTypeInfo(

context = context.replaceDataFlowInfo(receiverTypeInfo.getDataFlowInfo());

if (PsiTreeUtil.getParentOfType(expression, JetAnnotationEntry.class) == null) {
TemporaryTraceAndCache temporaryForDotOperation = TemporaryTraceAndCache.create(
context, "trace to check dot operation", expression
);

JetCallExpression fakeOperation = (JetCallExpression) JetPsiFactory.createExpression(expression.getProject(), "dot()");
Call dotCall = CallMaker.makeCall(
fakeOperation,
new ExpressionReceiver(receiverExpression, receiverType),
null,
fakeOperation.getCalleeExpression(),
Collections.<ValueArgument>emptyList()
);
OverloadResolutionResults<FunctionDescriptor> dotOperationDescriptors =
expressionTypingServices.getCallResolver().resolveCallWithGivenName(
context.replaceTraceAndCache(temporaryForDotOperation),
dotCall,
fakeOperation, Name.identifier("dot")
);
JetType dotOperationType =
OverloadResolutionResultsUtil.getResultingType(dotOperationDescriptors, context.contextDependency);

if (dotOperationDescriptors.isSingleResult() && dotOperationType != null) {
ResolvedCall<FunctionDescriptor> resolvedDotCall = dotOperationDescriptors.getResultingCall();
((ResolvedCallWithTrace) resolvedDotCall).markCallAsCompleted();

DottedCallInfo dottedCallInfo = new DottedCallInfo(dotCall, resolvedDotCall);

context.trace.record(DOTTED_EXPRESSION_TYPE, receiverExpression, dotOperationType);
context.trace.record(DOTTED_CALL_INFO, selectorExpression, dottedCallInfo);
context.trace.record(RESOLVED_CALL, dotCall.getCalleeExpression(), resolvedDotCall);

if (!KotlinBuiltIns.getInstance().isUnit(dotOperationType)) {
receiverType = dotOperationType;
context = context.replaceDataFlowInfo(resolvedDotCall.getDataFlowInfoForArguments().getResultInfo());
}
}
else if (dotOperationDescriptors.isAmbiguity()) {
context.trace.report(
OVERLOAD_RESOLUTION_AMBIGUITY.on(
expression.getOperationTokenNode().getPsi(), dotOperationDescriptors.getResultingCalls()
)
);
}
}

JetTypeInfo selectorReturnTypeInfo = getSelectorReturnTypeInfo(
new ExpressionReceiver(receiverExpression, receiverType),
expression.getOperationTokenNode(), selectorExpression, context);
Expand Down
@@ -0,0 +1,24 @@
/*
* Copyright 2010-2014 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.model

import org.jetbrains.jet.lang.psi.Call
import org.jetbrains.jet.lang.descriptors.CallableDescriptor
import org.jetbrains.jet.lang.types.JetType
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor

class DottedCallInfo(val call: Call, val resolvedCall: ResolvedCall<out FunctionDescriptor>)
124 changes: 124 additions & 0 deletions compiler/testData/cfg/basic/humbleSimplicityOfDots.instructions
@@ -0,0 +1,124 @@
== dot ==
fun Int.dot(): Int {
return this + 1
}
---------------------
L0:
1 <START>
2 mark({ return this + 1 })
mark(this + 1)
r(this)
r(1)
call(+, plus)
ret(*) L1
L1:
1 <END> NEXT:[<SINK>]
error:
<ERROR> PREV:[]
sink:
<SINK> PREV:[<ERROR>, <END>]
=====================
== dot ==
fun String?.dot(): String = this ?: ""
---------------------
L0:
1 <START>
r(this)
jt(L2) NEXT:[mark(""), <END>]
mark("")
r("")
L1:
L2:
<END> NEXT:[<SINK>] PREV:[jt(L2), r("")]
error:
<ERROR> PREV:[]
sink:
<SINK> PREV:[<ERROR>, <END>]
=====================
== i ==
fun i(): Int? = null
---------------------
L0:
1 <START>
r(null)
L1:
<END> NEXT:[<SINK>]
error:
<ERROR> PREV:[]
sink:
<SINK> PREV:[<ERROR>, <END>]
=====================
== s ==
fun s(): String? = null
---------------------
L0:
1 <START>
r(null)
L1:
<END> NEXT:[<SINK>]
error:
<ERROR> PREV:[]
sink:
<SINK> PREV:[<ERROR>, <END>]
=====================
== f ==
fun f() : Unit {
2.toLong()
3.equals(4)
i()?.toLong()

"test".length
s().length()
}
---------------------
L0:
1 <START>
2 mark({ 2.toLong() 3.equals(4) i()?.toLong() "test".length s().length() })
mark(2.toLong())
mark(toLong())
r(2)
call(toLong, toLong)
mark(dot())
r(2)
call(dot, dot)
mark(3.equals(4))
mark(equals(4))
r(3)
r(4)
call(equals, equals)
mark(dot())
r(3)
call(dot, dot)
mark(i()?.toLong())
mark(toLong())
mark(i())
call(i, i)
call(toLong, toLong)
mark(dot())
mark(i())
call(i, i)
call(dot, dot)
mark("test".length)
mark("test")
r("test")
r(length)
mark(dot())
mark("test")
r("test")
call(dot, dot)
mark(s().length())
mark(length())
mark(s())
call(s, s)
r(length)
mark(dot())
mark(s())
call(s, s)
call(dot, dot)
L1:
1 <END> NEXT:[<SINK>]
error:
<ERROR> PREV:[]
sink:
<SINK> PREV:[<ERROR>, <END>]
=====================
18 changes: 18 additions & 0 deletions compiler/testData/cfg/basic/humbleSimplicityOfDots.kt
@@ -0,0 +1,18 @@
fun Int.dot(): Int {
return this + 1
}

fun String?.dot(): String = this ?: ""

fun i(): Int? = null

fun s(): String? = null

fun f() : Unit {
2.toLong()
3.equals(4)
i()?.toLong()

"test".length
s().length()
}
22 changes: 22 additions & 0 deletions compiler/testData/codegen/box/dot/inTheVoidOfDots.kt
@@ -0,0 +1,22 @@
class Foo {
fun foo(): String {
return "O"
}
}

class Bar {
fun bar(): String {
return ""
}
}

var t: String = ""

fun Foo.dot() {
t = "K"
}

fun box(): String {
val f: Foo = Foo()
return f.foo() + t
}
23 changes: 23 additions & 0 deletions compiler/testData/codegen/box/dot/onlyDotCanKeepYouFromFailure.kt
@@ -0,0 +1,23 @@
class Foo {
fun foo(): String {
return "FAIL"
}
}

class Bar {
fun bar(): String {
return "O"
}
}

var t: String = ""

fun Foo.dot(): Bar {
t = "K"
return Bar()
}

fun box(): String {
val f: Foo = Foo()
return f.bar() + t
}
@@ -0,0 +1,8 @@
fun Any?.dot(): Nothing {
throw RuntimeException()
}

fun test(): String {
val s: String? = ""
<!UNREACHABLE_CODE!>return s.dot()<!>
}
Expand Up @@ -86,6 +86,11 @@ public void testEmptyFunction() throws Exception {
doTest("compiler/testData/cfg/basic/EmptyFunction.kt");
}

@TestMetadata("humbleSimplicityOfDots.kt")
public void testHumbleSimplicityOfDots() throws Exception {
doTest("compiler/testData/cfg/basic/humbleSimplicityOfDots.kt");
}

@TestMetadata("ShortFunction.kt")
public void testShortFunction() throws Exception {
doTest("compiler/testData/cfg/basic/ShortFunction.kt");
Expand Down
Expand Up @@ -1957,6 +1957,11 @@ public void testIsExpression() throws Exception {
doTest("compiler/testData/diagnostics/tests/dataFlow/IsExpression.kt");
}

@TestMetadata("nothingLikeDot.kt")
public void testNothingLikeDot() throws Exception {
doTest("compiler/testData/diagnostics/tests/dataFlow/nothingLikeDot.kt");
}

@TestMetadata("WhenSubject.kt")
public void testWhenSubject() throws Exception {
doTest("compiler/testData/diagnostics/tests/dataFlow/WhenSubject.kt");
Expand Down

0 comments on commit 322d884

Please sign in to comment.