Pseudocode: Do not generate implicit return instruction inside of
Unit-typed lambdas #KT-5549 Fixed
This commit is contained in:
@@ -32,6 +32,7 @@ import org.jetbrains.jet.lang.cfg.pseudocode.instructions.eval.AccessTarget;
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.eval.InstructionWithValue;
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.eval.MagicKind;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.descriptors.impl.AnonymousFunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.psi.psiUtil.PsiUtilPackage;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
@@ -100,6 +101,13 @@ public class JetControlFlowProcessor {
|
||||
}
|
||||
|
||||
private void generateImplicitReturnValue(@NotNull JetExpression bodyExpression, @NotNull JetElement subroutine) {
|
||||
CallableDescriptor subroutineDescriptor = (CallableDescriptor) trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, subroutine);
|
||||
if (subroutineDescriptor == null) return;
|
||||
|
||||
JetType returnType = subroutineDescriptor.getReturnType();
|
||||
KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance();
|
||||
if (returnType != null && builtIns.isUnit(returnType) && subroutineDescriptor instanceof AnonymousFunctionDescriptor) return;
|
||||
|
||||
PseudoValue returnValue = builder.getBoundValue(bodyExpression);
|
||||
if (returnValue == null) return;
|
||||
|
||||
|
||||
@@ -152,9 +152,8 @@ L6:
|
||||
read (Unit) PREV:[jf(L6|<v2>)]
|
||||
L7:
|
||||
merge(if (2 > 3) { return@l }|!<v3>) -> <v4>
|
||||
4 ret(*|<v4>) L5
|
||||
L5:
|
||||
<END> NEXT:[<SINK>] PREV:[ret L5, ret(*|<v4>) L5]
|
||||
4 <END> NEXT:[<SINK>] PREV:[ret L5, merge(if (2 > 3) { return@l }|!<v3>) -> <v4>]
|
||||
error:
|
||||
<ERROR> PREV:[]
|
||||
sink:
|
||||
@@ -235,9 +234,8 @@ L10 [skipFinallyToErrorBlock]:
|
||||
7 mark({ 2 }) PREV:[jmp(L10 [skipFinallyToErrorBlock])]
|
||||
r(2) -> <v4>
|
||||
4 merge(try { 1 if (2 > 3) { return@l } } finally { 2 }|<v6>) -> <v7>
|
||||
3 ret(*|<v7>) L4
|
||||
L4:
|
||||
<END> NEXT:[<SINK>] PREV:[ret L4, ret(*|<v7>) L4]
|
||||
3 <END> NEXT:[<SINK>] PREV:[ret L4, merge(try { 1 if (2 > 3) { return@l } } finally { 2 }|<v6>) -> <v7>]
|
||||
error:
|
||||
<ERROR> PREV:[jmp(error)]
|
||||
sink:
|
||||
|
||||
@@ -74,8 +74,8 @@ try { 1 @l{ () -> if (2 > 3) { return@l } } } finally { 2 } <v3>: * NEW:
|
||||
2 > 3 <v2>: Boolean NEW: call(2 > 3, compareTo|<v0>, <v1>) -> <v2>
|
||||
return@l !<v3>: *
|
||||
{ return@l } !<v3>: * COPY
|
||||
if (2 > 3) { return@l } <v4>: Unit NEW: merge(if (2 > 3) { return@l }|!<v3>) -> <v4>
|
||||
if (2 > 3) { return@l } <v4>: Unit COPY
|
||||
if (2 > 3) { return@l } <v4>: * NEW: merge(if (2 > 3) { return@l }|!<v3>) -> <v4>
|
||||
if (2 > 3) { return@l } <v4>: * COPY
|
||||
=====================
|
||||
== t4 ==
|
||||
fun t4() {
|
||||
@@ -113,12 +113,12 @@ fun t4() {
|
||||
2 > 3 <v3>: Boolean NEW: call(2 > 3, compareTo|<v1>, <v2>) -> <v3>
|
||||
return@l !<v5>: *
|
||||
{ return@l } !<v5>: * COPY
|
||||
if (2 > 3) { return@l } <v6>: Unit NEW: merge(if (2 > 3) { return@l }|!<v5>) -> <v6>
|
||||
{ 1 if (2 > 3) { return@l } } <v6>: Unit COPY
|
||||
if (2 > 3) { return@l } <v6>: * NEW: merge(if (2 > 3) { return@l }|!<v5>) -> <v6>
|
||||
{ 1 if (2 > 3) { return@l } } <v6>: * COPY
|
||||
2 <v4>: * NEW: r(2) -> <v4>
|
||||
{ 2 } <v4>: * COPY
|
||||
try { 1 if (2 > 3) { return@l } } finally { 2 } <v7>: Unit NEW: merge(try { 1 if (2 > 3) { return@l } } finally { 2 }|<v6>) -> <v7>
|
||||
try { 1 if (2 > 3) { return@l } } finally { 2 } <v7>: Unit COPY
|
||||
try { 1 if (2 > 3) { return@l } } finally { 2 } <v7>: * NEW: merge(try { 1 if (2 > 3) { return@l } } finally { 2 }|<v6>) -> <v7>
|
||||
try { 1 if (2 > 3) { return@l } } finally { 2 } <v7>: * COPY
|
||||
=====================
|
||||
== t5 ==
|
||||
fun t5() {
|
||||
|
||||
@@ -78,9 +78,8 @@ L3:
|
||||
r("") -> <v2>
|
||||
mark((foo)())
|
||||
call((foo)(), invoke|<v1>, <v2>) -> <v3>
|
||||
3 ret(*|<v3>) L4
|
||||
L4:
|
||||
<END> NEXT:[<SINK>]
|
||||
3 <END> NEXT:[<SINK>]
|
||||
error:
|
||||
<ERROR> PREV:[]
|
||||
sink:
|
||||
|
||||
@@ -36,7 +36,7 @@ with(1) { "".(foo)() } <v2>: * NEW: call(with(1) { "".
|
||||
"" <v2>: String NEW: r("") -> <v2>
|
||||
foo <v1>: {<: String.() -> Unit} NEW: r(foo|<v0>) -> <v1>
|
||||
(foo) <v1>: {<: String.() -> Unit} COPY
|
||||
(foo)() <v3>: Unit NEW: call((foo)(), invoke|<v1>, <v2>) -> <v3>
|
||||
"".(foo)() <v3>: Unit COPY
|
||||
"".(foo)() <v3>: Unit COPY
|
||||
(foo)() <v3>: * NEW: call((foo)(), invoke|<v1>, <v2>) -> <v3>
|
||||
"".(foo)() <v3>: * COPY
|
||||
"".(foo)() <v3>: * COPY
|
||||
=====================
|
||||
|
||||
@@ -60,7 +60,7 @@ fun main1() {
|
||||
1.({Int.() -> 1})()
|
||||
1.(f())()
|
||||
1.if(true){f()}else{f()}()
|
||||
1.if(true){Int.() -> 1}else{f()}()
|
||||
1.if(true){Int.() -> <!UNUSED_EXPRESSION!>1<!>}else{f()}()
|
||||
1.if(true){Int.() -> 1}else{Int.() -> 1}()
|
||||
|
||||
1.<!FUNCTION_EXPECTED!>"sdf"<!>()
|
||||
|
||||
@@ -205,4 +205,4 @@ fun testFunctionLiterals() {
|
||||
object A {}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ fun test() {
|
||||
v1({})
|
||||
v1({}, {})
|
||||
v1({}, <!CONSTANT_EXPECTED_TYPE_MISMATCH!>1<!>, {})
|
||||
v1({}, {}, {it})
|
||||
v1({}, {}, {<!UNUSED_EXPRESSION!>it<!>})
|
||||
v1({}) <!VARARG_OUTSIDE_PARENTHESES, DANGLING_FUNCTION_LITERAL_ARGUMENT_SUSPECTED!>{}<!>
|
||||
v1 <!VARARG_OUTSIDE_PARENTHESES, DANGLING_FUNCTION_LITERAL_ARGUMENT_SUSPECTED!>{}<!>
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
fun main(args: Array<String>) {
|
||||
"".run {
|
||||
<!UNUSED_EXPRESSION!>""<!>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun <T> T.run(f: (T) -> Unit): Unit = f(this)
|
||||
@@ -13,4 +13,4 @@ fun test() {
|
||||
foo({if (1==1);}())
|
||||
|
||||
return if (true);
|
||||
}
|
||||
}
|
||||
+5
-5
@@ -48,13 +48,13 @@ fun test2(): Unit { while(true) {} }
|
||||
|
||||
fun testCoercionToUnit() {
|
||||
val <!UNUSED_VARIABLE!>simple<!>: ()-> Unit = {
|
||||
41
|
||||
<!UNUSED_EXPRESSION!>41<!>
|
||||
}
|
||||
val <!UNUSED_VARIABLE!>withIf<!>: ()-> Unit = {
|
||||
if (true) {
|
||||
3
|
||||
<!UNUSED_EXPRESSION!>3<!>
|
||||
} else {
|
||||
45
|
||||
<!UNUSED_EXPRESSION!>45<!>
|
||||
}
|
||||
}
|
||||
val i = 34
|
||||
@@ -66,8 +66,8 @@ fun testCoercionToUnit() {
|
||||
doSmth(d)
|
||||
|
||||
}
|
||||
2 -> '4'
|
||||
else -> true
|
||||
2 -> <!UNUSED_EXPRESSION!>'4'<!>
|
||||
else -> <!UNUSED_EXPRESSION!>true<!>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
fun main(args: Array<String>) {
|
||||
"".run {
|
||||
<!UNUSED_FUNCTION_LITERAL!>{}<!>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun <T> T.run(f: (T) -> Unit): Unit = f(this)
|
||||
@@ -13,6 +13,5 @@ public class A {
|
||||
|
||||
fun main() {
|
||||
A.<!OVERLOAD_RESOLUTION_AMBIGUITY!>foo<!> { "Hello!" }
|
||||
A.foo(Runnable { "Hello!" })
|
||||
}
|
||||
|
||||
A.foo(Runnable { <!UNUSED_EXPRESSION!>"Hello!"<!> })
|
||||
}
|
||||
@@ -15,7 +15,7 @@ fun new2(body: Comment2.() -> Unit) = body
|
||||
fun main(args: Array<String>) {
|
||||
new {
|
||||
new2 {
|
||||
this@new //UNRESOLVED REFERENCE
|
||||
<!UNUSED_EXPRESSION!>this@new<!> //UNRESOLVED REFERENCE
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
fun foo(x: Int) {
|
||||
r {
|
||||
when (x) {
|
||||
2 -> 0
|
||||
2 -> <!UNUSED_EXPRESSION!>0<!>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1541,6 +1541,11 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
||||
doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeInWhileFromBreak.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("expressionInUnitLiteral.kt")
|
||||
public void testExpressionInUnitLiteral() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/expressionInUnitLiteral.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt2585_1.kt")
|
||||
public void testKt2585_1() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/kt2585_1.kt");
|
||||
@@ -3493,6 +3498,11 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
||||
doTest("compiler/testData/diagnostics/tests/functionLiterals/unusedLiteral.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("unusedLiteralInsideUnitLiteral.kt")
|
||||
public void testUnusedLiteralInsideUnitLiteral() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/functionLiterals/unusedLiteralInsideUnitLiteral.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/functionLiterals/return")
|
||||
public static class Return extends AbstractJetDiagnosticsTest {
|
||||
public void testAllFilesPresentInReturn() throws Exception {
|
||||
|
||||
@@ -22,10 +22,10 @@ fun inline() {
|
||||
fun notInline() {
|
||||
val <info descr="Value captured in a closure">y2</info> = 1
|
||||
run { <info descr="Value captured in a closure">y2</info> }
|
||||
run2 { <info descr="Value captured in a closure">y2</info> }
|
||||
run2 { <warning><info descr="Value captured in a closure">y2</info></warning> }
|
||||
|
||||
val <info descr="Value captured in a closure">y3</info> = 1
|
||||
run2 { <info descr="Value captured in a closure">y3</info> }
|
||||
run2 { <warning><info descr="Value captured in a closure">y3</info></warning> }
|
||||
run { <info descr="Value captured in a closure">y3</info> }
|
||||
|
||||
// wrapped, using in not inline
|
||||
@@ -33,7 +33,7 @@ fun notInline() {
|
||||
{ <info descr="Value captured in a closure">z</info> }()
|
||||
|
||||
val <info descr="Value captured in a closure">z1</info> = 3
|
||||
run2 { <info descr="Value captured in a closure">z1</info> }
|
||||
run2 { <warning><info descr="Value captured in a closure">z1</info></warning> }
|
||||
}
|
||||
|
||||
fun nestedDifferent() { // inline within non-inline and vice-versa
|
||||
|
||||
Reference in New Issue
Block a user