Resolve anonymous functions in block as expression

#KT-7265 Fixed
This commit is contained in:
Denis Zharkov
2016-03-18 18:34:37 +03:00
parent 77e37ff75d
commit 16736e3a0e
13 changed files with 171 additions and 15 deletions
@@ -70,7 +70,7 @@ class FunctionDescriptorResolver(
trace: BindingTrace,
dataFlowInfo: DataFlowInfo
): SimpleFunctionDescriptor {
if (function.getName() == null) trace.report(FUNCTION_DECLARATION_WITH_NO_NAME.on(function))
if (function.name == null) trace.report(FUNCTION_DECLARATION_WITH_NO_NAME.on(function))
return resolveFunctionDescriptor(
SimpleFunctionDescriptorImpl::create, containingDescriptor, scope, function, trace, dataFlowInfo, TypeUtils.NO_EXPECTED_TYPE)
@@ -293,7 +293,9 @@ public class ExpressionTypingServices {
if (coercionStrategyForLastExpression == COERCION_TO_UNIT) {
boolean mightBeUnit = false;
if (statementExpression instanceof KtDeclaration) {
mightBeUnit = true;
if (!(statementExpression instanceof KtNamedFunction) || statementExpression.getName() != null) {
mightBeUnit = true;
}
}
if (statementExpression instanceof KtBinaryExpression) {
KtBinaryExpression binaryExpression = (KtBinaryExpression) statementExpression;
@@ -138,7 +138,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
@Override
public KotlinTypeInfo visitNamedFunction(@NotNull KtNamedFunction function, ExpressionTypingContext context) {
return functions.visitNamedFunction(function, context, true, scope);
return functions.visitNamedFunction(function, context, /* isDeclaration = */ function.getName() != null, scope);
}
@Override
@@ -48,17 +48,17 @@ import org.jetbrains.kotlin.utils.addIfNotNull
internal class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : ExpressionTypingVisitor(facade) {
override fun visitNamedFunction(function: KtNamedFunction, data: ExpressionTypingContext): KotlinTypeInfo {
return visitNamedFunction(function, data, false, null)
return visitNamedFunction(function, data, isDeclaration = false, statementScope = null)
}
fun visitNamedFunction(
function: KtNamedFunction,
context: ExpressionTypingContext,
isStatement: Boolean,
statementScope: LexicalWritableScope? // must be not null if isStatement
isDeclaration: Boolean,
statementScope: LexicalWritableScope? // must be not null if isDeclaration
): KotlinTypeInfo {
checkReservedAsync(context, function)
if (!isStatement) {
if (!isDeclaration) {
// function expression
if (!function.getTypeParameters().isEmpty()) {
context.trace.report(TYPE_PARAMETERS_NOT_ALLOWED.on(function))
@@ -79,7 +79,7 @@ internal class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Expre
}
val functionDescriptor: SimpleFunctionDescriptor
if (isStatement) {
if (isDeclaration) {
functionDescriptor = components.functionDescriptorResolver.resolveFunctionDescriptor(
context.scope.ownerDescriptor, context.scope, function, context.trace, context.dataFlowInfo)
assert(statementScope != null) {
@@ -115,7 +115,7 @@ internal class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Expre
components.identifierChecker.checkDeclaration(function, context.trace)
components.declarationsCheckerBuilder.withTrace(context.trace).checkFunction(function, functionDescriptor)
if (isStatement) {
if (isDeclaration) {
return createTypeInfo(components.dataFlowAnalyzer.checkStatementType(function, context), context)
}
else {
@@ -18,9 +18,9 @@ class Outer {
}
fun outerFun() {
<!FUNCTION_DECLARATION_WITH_NO_NAME, CONFLICTING_OVERLOADS!>fun ()<!> {}
<!FUNCTION_DECLARATION_WITH_NO_NAME!>fun B.()<!> {}
fun () {}
fun B.() {}
<!FUNCTION_DECLARATION_WITH_NO_NAME, CONFLICTING_OVERLOADS!>@a fun ()<!> {}
<!FUNCTION_DECLARATION_WITH_NO_NAME!>fun @a A.()<!> {}
@a fun () {}
fun @a A.() {}
}
@@ -0,0 +1,43 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE
// !CHECK_TYPE
fun foo(block: () -> (() -> Int)) {}
fun test() {
foo { fun(): Int {return 1} }
foo({ fun() = 1 })
val x1 =
if (1 == 1)
fun(): Int {return 1}
else
fun() = 1
val x2 =
if (1 == 1) {
fun(): Int {
return 1
}
}
else
fun() = 1
val x3 = when (1) {
0 -> fun(): Int {return 1}
else -> fun() = 1
}
val x31 = when (1) {
0 -> {
fun(): Int {return 1}
}
else -> fun() = 1
}
val x4 = {
y: Int -> fun(): Int {return 1}
}
x4 checkType { _<Function1<Int, Function0<Int>>>() }
<!UNUSED_LAMBDA_EXPRESSION!>{ y: Int -> fun(): Int {return 1} }<!>
}
@@ -0,0 +1,4 @@
package
public fun foo(/*0*/ block: () -> () -> kotlin.Int): kotlin.Unit
public fun test(): kotlin.Unit
@@ -0,0 +1,21 @@
fun unusedExpressions() {
if (1 == 1)
fun(): Int {return 1}
else
fun() = 1
if (1 == 1) {
fun(): Int {
return 1
}
}
else
fun() = 1
when (1) {
0 -> fun(): Int {return 1}
else -> fun() = 1
}
fun() = 1
}
@@ -0,0 +1,3 @@
package
public fun unusedExpressions(): kotlin.Unit
@@ -0,0 +1,58 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE
// !CHECK_TYPE
fun foo(block: () -> (() -> Int)) {}
fun test() {
val x = fun <!ANONYMOUS_FUNCTION_WITH_NAME!>named1<!>(x: Int): Int { return 1 }
x checkType { _<Function1<Int, Int>>() }
foo { <!EXPECTED_TYPE_MISMATCH(\(\) -> Int)!>fun named2(): Int {return 1}<!> }
foo({ <!EXPECTED_TYPE_MISMATCH!>fun named3() = 1<!> })
val x1 =
if (1 == 1)
// TODO: Diagnostic content could be better
<!EXPECTED_TYPE_MISMATCH(\(\) -> Int)!>fun named4(): Int {return 1}<!>
else
<!EXPECTED_TYPE_MISMATCH!>fun named5() = 1<!>
val x2 =
if (1 == 1) {
<!EXPECTED_TYPE_MISMATCH!>fun named6(): Int {
return 1
}<!>
}
else
<!EXPECTED_TYPE_MISMATCH!>fun named7() = 1<!>
val x3 = when (1) {
0 -> <!EXPECTED_TYPE_MISMATCH!>fun named8(): Int {return 1}<!>
else -> <!EXPECTED_TYPE_MISMATCH!>fun named9() = 1<!>
}
val x31 = when (1) {
0 -> {
<!EXPECTED_TYPE_MISMATCH!>fun named10(): Int {return 1}<!>
}
else -> <!EXPECTED_TYPE_MISMATCH!>fun named11() = 1<!>
}
val x4 = {
y: Int -> fun named12(): Int {return 1}
}
x4 checkType { _<Function1<Int, Unit>>() }
<!UNUSED_LAMBDA_EXPRESSION!>{ y: Int -> fun named14(): Int {return 1} }<!>
}
fun <T> run(block: () -> T): T = null!!
fun run2(block: () -> Unit): Unit = null!!
fun success() {
run { fun named1() = 1 }
run2 { fun named2() = 1 }
val x = run { fun named3() = 1 }
x checkType { _<Unit>() }
}
@@ -0,0 +1,7 @@
package
public fun foo(/*0*/ block: () -> () -> kotlin.Int): kotlin.Unit
public fun </*0*/ T> run(/*0*/ block: () -> T): T
public fun run2(/*0*/ block: () -> kotlin.Unit): kotlin.Unit
public fun success(): kotlin.Unit
public fun test(): kotlin.Unit
@@ -58,10 +58,10 @@ class Outer {
}
fun outerFun() {
<!FUNCTION_DECLARATION_WITH_NO_NAME, CONFLICTING_OVERLOADS!>fun ()<!> {
fun () {
}
<!FUNCTION_DECLARATION_WITH_NO_NAME, CONFLICTING_OVERLOADS!>fun ()<!> {
fun () {
}
}
@@ -4320,6 +4320,18 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
doTest(fileName);
}
@TestMetadata("anonymousFunAsLastExpressionInBlock.kt")
public void testAnonymousFunAsLastExpressionInBlock() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/declarationChecks/anonymousFunAsLastExpressionInBlock.kt");
doTest(fileName);
}
@TestMetadata("anonymousFunUnusedLastExpressionInBlock.kt")
public void testAnonymousFunUnusedLastExpressionInBlock() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/declarationChecks/anonymousFunUnusedLastExpressionInBlock.kt");
doTest(fileName);
}
@TestMetadata("ComponentFunctionReturnTypeMismatch.kt")
public void testComponentFunctionReturnTypeMismatch() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/declarationChecks/ComponentFunctionReturnTypeMismatch.kt");
@@ -4434,6 +4446,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
doTest(fileName);
}
@TestMetadata("namedFunAsLastExpressionInBlock.kt")
public void testNamedFunAsLastExpressionInBlock() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/declarationChecks/namedFunAsLastExpressionInBlock.kt");
doTest(fileName);
}
@TestMetadata("packageDeclarationModifiers.kt")
public void testPackageDeclarationModifiers() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/declarationChecks/packageDeclarationModifiers.kt");