diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 4a41b223c56..101767a0cc7 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -528,6 +528,8 @@ public interface Errors { DiagnosticFactory1 TYPE_INFERENCE_UPPER_BOUND_VIOLATED = DiagnosticFactory1.create(ERROR); DiagnosticFactory2 TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH = DiagnosticFactory2.create(ERROR); + DiagnosticFactory0 TYPE_INFERENCE_FAILED_ON_SPECIAL_CONSTRUCT = DiagnosticFactory0.create(ERROR, SPECIAL_CONSTRUCT_TOKEN); + // Reflection DiagnosticFactory1 EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED = DiagnosticFactory1.create(ERROR); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt index 6752d5416d9..148c23a2b45 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt @@ -339,6 +339,16 @@ object PositioningStrategies { } } + @JvmField val SPECIAL_CONSTRUCT_TOKEN: PositioningStrategy = object : PositioningStrategy() { + override fun mark(element: KtExpression): List = + when (element) { + is KtWhenExpression -> markElement(element.whenKeyword) + is KtIfExpression -> markElement(element.ifKeyword) + is KtOperationExpression -> markElement(element.operationReference) + else -> error("Expression is not an if, when or operation expression: ${element.getElementTextWithContext()}") + } + } + @JvmField val NULLABLE_TYPE: PositioningStrategy = object : PositioningStrategy() { override fun mark(element: KtNullableType): List { return markNode(element.getQuestionMarkNode()) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index 59a98edbff5..d009db238e4 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -658,6 +658,8 @@ public class DefaultErrorMessages { MAP.put(TYPE_INFERENCE_UPPER_BOUND_VIOLATED, "{0}", TYPE_INFERENCE_UPPER_BOUND_VIOLATED_RENDERER); MAP.put(TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH, "Type inference failed. Expected type mismatch: inferred type is {1} but {0} was expected", RENDER_TYPE, RENDER_TYPE); + MAP.put(TYPE_INFERENCE_FAILED_ON_SPECIAL_CONSTRUCT, "Type inference for control flow expression failed. Please specify its type explicitly."); + MAP.put(WRONG_NUMBER_OF_TYPE_ARGUMENTS, "{0,choice,0#No type arguments|1#Type argument|1<{0,number,integer} type arguments} expected", (Renderer) null); MAP.put(NO_TYPE_ARGUMENTS_ON_RHS, "{0,choice,0#No type arguments|1#Type argument|1<{0,number,integer} type arguments} expected. " + "Use ''{1}'' if you don''t want to pass type arguments", null, STRING); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/ResolutionCandidate.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/ResolutionCandidate.java index 1fa14694491..9f23825662e 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/ResolutionCandidate.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/ResolutionCandidate.java @@ -51,6 +51,14 @@ public class ResolutionCandidate { return new ResolutionCandidate(call, descriptor, null, null, ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, null); } + public static ResolutionCandidate create( + @NotNull Call call, @NotNull D descriptor, @Nullable TypeSubstitutor knownTypeParametersResultingSubstitutor + ) { + return new ResolutionCandidate(call, descriptor, + null, null, ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, + knownTypeParametersResultingSubstitutor); + } + public static ResolutionCandidate create( @NotNull Call call, @NotNull D descriptor, @Nullable ReceiverValue dispatchReceiver, @Nullable Receiver receiverArgument, @NotNull ExplicitReceiverKind explicitReceiverKind, diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingUtils.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingUtils.java index 689d56327c2..c9a793a5e29 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingUtils.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingUtils.java @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.types.expressions; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.intellij.lang.ASTNode; @@ -24,6 +25,7 @@ import com.intellij.openapi.util.Ref; import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.annotations.Annotations; import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl; @@ -50,13 +52,12 @@ import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy; import org.jetbrains.kotlin.resolve.calls.util.CallMaker; import org.jetbrains.kotlin.resolve.descriptorUtil.AnnotationsForResolveKt; import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue; -import org.jetbrains.kotlin.types.KotlinType; -import org.jetbrains.kotlin.types.TypeUtils; -import org.jetbrains.kotlin.types.Variance; +import org.jetbrains.kotlin.types.*; import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt; import java.util.*; +import static org.jetbrains.kotlin.diagnostics.Errors.TYPE_INFERENCE_FAILED_ON_SPECIAL_CONSTRUCT; import static org.jetbrains.kotlin.resolve.BindingContext.CALL; import static org.jetbrains.kotlin.resolve.BindingContext.RESOLVED_CALL; import static org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.EXPECTED_TYPE_POSITION; @@ -103,13 +104,34 @@ public class ControlStructureTypingUtils { SimpleFunctionDescriptorImpl function = createFunctionDescriptorForSpecialConstruction( construct, argumentNames, isArgumentNullable); TracingStrategy tracing = createTracingForSpecialConstruction(call, construct.getName(), context); - ResolutionCandidate resolutionCandidate = ResolutionCandidate.create(call, function); + TypeSubstitutor knownTypeParameterSubstitutor = createKnownTypeParameterSubstitutorForSpecialCall(construct, function, context.expectedType); + ResolutionCandidate resolutionCandidate = + ResolutionCandidate.create(call, function, knownTypeParameterSubstitutor); OverloadResolutionResults results = callResolver.resolveCallWithKnownCandidate( call, tracing, context, resolutionCandidate, dataFlowInfoForArguments); assert results.isSingleResult() : "Not single result after resolving one known candidate"; return results.getResultingCall(); } + private static @Nullable TypeSubstitutor createKnownTypeParameterSubstitutorForSpecialCall( + @NotNull ResolveConstruct construct, + @NotNull SimpleFunctionDescriptorImpl function, + @NotNull KotlinType expectedType + ) { + if (construct == ResolveConstruct.ELVIS + || TypeUtils.noExpectedType(expectedType) + || TypeUtils.isDontCarePlaceholder(expectedType) + || KotlinBuiltIns.isUnitOrNullableUnit(expectedType) + || KotlinBuiltIns.isAnyOrNullableAny(expectedType) + ) { + return null; + } + + TypeConstructor typeParameterConstructor = function.getTypeParameters().get(0).getTypeConstructor(); + TypeProjection typeProjection = new TypeProjectionImpl(expectedType); + return TypeSubstitutor.create(ImmutableMap.of(typeParameterConstructor, typeProjection)); + } + private SimpleFunctionDescriptorImpl createFunctionDescriptorForSpecialConstruction( @NotNull ResolveConstruct construct, @NotNull List argumentNames, @@ -426,7 +448,15 @@ public class ControlStructureTypingUtils { KtExpression expression = (KtExpression) call.getCallElement(); if (status.hasOnlyErrorsDerivedFrom(EXPECTED_TYPE_POSITION) || status.hasConflictingConstraints() || status.hasTypeInferenceIncorporationError()) { // todo after KT-... remove this line - expression.accept(checkTypeVisitor, new CheckTypeContext(context.trace, data.expectedType)); + if (Boolean.TRUE != expression.accept(checkTypeVisitor, new CheckTypeContext(context.trace, data.expectedType))) { + KtExpression calleeExpression = call.getCalleeExpression(); + if (calleeExpression instanceof KtWhenExpression || calleeExpression instanceof KtIfExpression) { + if (status.hasConflictingConstraints() || status.hasTypeInferenceIncorporationError()) { + // TODO provide comprehensible error report for hasConflictingConstraints() case (if possible) + context.trace.report(TYPE_INFERENCE_FAILED_ON_SPECIAL_CONSTRUCT.on(expression)); + } + } + } return; } KtDeclaration parentDeclaration = PsiTreeUtil.getParentOfType(expression, KtNamedDeclaration.class); diff --git a/compiler/testData/diagnostics/tests/controlStructures/specialConstructsAndPlatformTypes.kt b/compiler/testData/diagnostics/tests/controlStructures/specialConstructsAndPlatformTypes.kt new file mode 100644 index 00000000000..d75b6abfe43 --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlStructures/specialConstructsAndPlatformTypes.kt @@ -0,0 +1,39 @@ +// FILE: J.java +import java.util.*; + +public class J { + public static String s = null; + public static Map m = null; +} + +// FILE: k.kt + +val testImplicitExclExcl1: String = J.s +val testImplicitExclExcl2: String? = J.s + +val testImplicitExclExcl3: String = J.m[""] +val testImplicitExclExcl4: String? = J.m[""] + +val testExclExcl1: String = J.s!! +val testExclExcl2: String? = J.s!! + +val testExclExcl3: String = J.m[""]!! +val testExclExcl4: String? = J.m[""]!! + +val testSafeCall1: String = J.s?.let { it } +val testSafeCall2: String? = J.s?.let { it } + +val testSafeCall3: String = J.m[""]?.let { it } +val testSafeCall4: String? = J.m[""]?.let { it.toString() } + +val testIf1: String = if (true) J.s else J.s +val testIf2: String? = if (true) J.s else J.s + +val testIf3: String = if (true) J.m[""] else J.m[""] +val testIf4: String? = if (true) J.m[""] else J.m[""] + +val testWhen1: String = when { else -> J.s } +val testWhen2: String? = when { else -> J.s } + +val testWhen3: String = when { else -> J.m[""] } +val testWhen4: String? = when { else -> J.m[""] } diff --git a/compiler/testData/diagnostics/tests/controlStructures/specialConstructsAndPlatformTypes.txt b/compiler/testData/diagnostics/tests/controlStructures/specialConstructsAndPlatformTypes.txt new file mode 100644 index 00000000000..7dbb88fe86d --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlStructures/specialConstructsAndPlatformTypes.txt @@ -0,0 +1,33 @@ +package + +public val testExclExcl1: kotlin.String +public val testExclExcl2: kotlin.String? +public val testExclExcl3: kotlin.String +public val testExclExcl4: kotlin.String? +public val testIf1: kotlin.String +public val testIf2: kotlin.String? +public val testIf3: kotlin.String +public val testIf4: kotlin.String? +public val testImplicitExclExcl1: kotlin.String +public val testImplicitExclExcl2: kotlin.String? +public val testImplicitExclExcl3: kotlin.String +public val testImplicitExclExcl4: kotlin.String? +public val testSafeCall1: kotlin.String +public val testSafeCall2: kotlin.String? +public val testSafeCall3: kotlin.String +public val testSafeCall4: kotlin.String? +public val testWhen1: kotlin.String +public val testWhen2: kotlin.String? +public val testWhen3: kotlin.String +public val testWhen4: kotlin.String? + +public open class J { + public constructor J() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public final var m: kotlin.collections.(Mutable)Map! + public final var s: kotlin.String! +} diff --git a/compiler/testData/diagnostics/tests/controlStructures/specialConstructsWithNullableExpectedType.kt b/compiler/testData/diagnostics/tests/controlStructures/specialConstructsWithNullableExpectedType.kt new file mode 100644 index 00000000000..0e8ec5e19de --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlStructures/specialConstructsWithNullableExpectedType.kt @@ -0,0 +1,20 @@ +val ns: String? = null + +val testElvis1: String? = ns ?: "" +val testElvis2: String = run { ns ?: "" } +val testElvis3: String? = run { ns ?: "" } + +val testIf1: String? = if (true) "" else "" +val testIf2: String? = run { if (true) "" else "" } +val testIf3: String? = if (true) run { "" } else "" +val testIf4: String? = run { run { if (true) "" else "" } } +val testIf5: String? = run { if (true) run { "" } else "" } + +val testWhen1: String? = when { else -> "" } +val testWhen2: String? = run { when { else -> "" } } +val testWhen3: String? = when { else -> run { "" } } +val testWhen4: String? = run { run { when { else -> "" } } } +val testWhen5: String? = run { when { else -> run { "" } } } + +val testExcl1: String? = run { ns!! } +val testExcl2: String? = run { run { ns!! } } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/controlStructures/specialConstructsWithNullableExpectedType.txt b/compiler/testData/diagnostics/tests/controlStructures/specialConstructsWithNullableExpectedType.txt new file mode 100644 index 00000000000..6c9aadb9727 --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlStructures/specialConstructsWithNullableExpectedType.txt @@ -0,0 +1,18 @@ +package + +public val ns: kotlin.String? = null +public val testElvis1: kotlin.String? +public val testElvis2: kotlin.String +public val testElvis3: kotlin.String? +public val testExcl1: kotlin.String? +public val testExcl2: kotlin.String? +public val testIf1: kotlin.String? +public val testIf2: kotlin.String? +public val testIf3: kotlin.String? +public val testIf4: kotlin.String? +public val testIf5: kotlin.String? +public val testWhen1: kotlin.String? +public val testWhen2: kotlin.String? +public val testWhen3: kotlin.String? +public val testWhen4: kotlin.String? +public val testWhen5: kotlin.String? diff --git a/compiler/testData/diagnostics/tests/infos/SmartCasts.kt b/compiler/testData/diagnostics/tests/infos/SmartCasts.kt index c38d54c7aef..3c036401686 100644 --- a/compiler/testData/diagnostics/tests/infos/SmartCasts.kt +++ b/compiler/testData/diagnostics/tests/infos/SmartCasts.kt @@ -181,8 +181,8 @@ fun returnFunctionLiteral(a: Any?): Function0 { else return { -> 1 } } -fun returnFunctionLiteralDoesntWork(a: Any?): Function0 = - if (a is Int) { -> a } +fun returnFunctionLiteralExpressionBody(a: Any?): Function0 = + if (a is Int) { -> a } else { -> 1 } diff --git a/compiler/testData/diagnostics/tests/infos/SmartCasts.txt b/compiler/testData/diagnostics/tests/infos/SmartCasts.txt index 6abe1150e98..96fb52a7a75 100644 --- a/compiler/testData/diagnostics/tests/infos/SmartCasts.txt +++ b/compiler/testData/diagnostics/tests/infos/SmartCasts.txt @@ -17,7 +17,7 @@ public fun illegalWhenBody(/*0*/ a: kotlin.Any): kotlin.Int public fun mergeSmartCasts(/*0*/ a: kotlin.Any?): kotlin.Unit public fun returnFunctionLiteral(/*0*/ a: kotlin.Any?): () -> kotlin.Int public fun returnFunctionLiteralBlock(/*0*/ a: kotlin.Any?): () -> kotlin.Int -public fun returnFunctionLiteralDoesntWork(/*0*/ a: kotlin.Any?): () -> kotlin.Int +public fun returnFunctionLiteralExpressionBody(/*0*/ a: kotlin.Any?): () -> kotlin.Int public fun toInt(/*0*/ i: kotlin.Int?): kotlin.Int public fun vars(/*0*/ a: kotlin.Any?): kotlin.Unit diff --git a/compiler/testData/diagnostics/tests/resolve/specialConstructions/multipleSuperClasses.kt b/compiler/testData/diagnostics/tests/resolve/specialConstructions/multipleSuperClasses.kt index 1764d1da8d0..7433a8cdb7c 100644 --- a/compiler/testData/diagnostics/tests/resolve/specialConstructions/multipleSuperClasses.kt +++ b/compiler/testData/diagnostics/tests/resolve/specialConstructions/multipleSuperClasses.kt @@ -8,9 +8,21 @@ interface D: A, B interface E: A, B fun foo(c: C?, d: D?, e: E?) { - val a: A? = c ?: d ?: e + val test1: A? = c ?: d ?: e - val b: B? = if (false) if (true) c else d else e + val test2: B? = if (false) if (true) c else d else e - //outer elvis operator and if-expression have error types + val test3: A? = when { + true -> c + else -> when { + true -> d + else -> e + } + } + + val test4: B? = when (1) { + 1 -> c + 2 -> d + else -> e + } } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/when/kt10809.kt b/compiler/testData/diagnostics/tests/when/kt10809.kt new file mode 100644 index 00000000000..e04ff8feb23 --- /dev/null +++ b/compiler/testData/diagnostics/tests/when/kt10809.kt @@ -0,0 +1,50 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER -DEBUG_INFO_SMARTCAST + +interface Data +interface Item +class FlagData(val value: Boolean) : Data +class ListData(val list: List) : Data + +fun listOf(vararg items: T): List = null!! + +fun test1(o: Any) = when (o) { + is List<*> -> + ListData(listOf()) + is Int -> when { + o < 0 -> + FlagData(true) + else -> + null + } + else -> + null +} + +fun test1x(o: Any): Data? = when (o) { + is List<*> -> + ListData(listOf()) + is Int -> when { + o < 0 -> + FlagData(true) + else -> + null + } + else -> + null +} + +fun test2() = + if (true) + ListData(listOf()) + else + FlagData(true) + +fun test2x(): Data = + if (true) ListData(listOf()) else FlagData(true) + +fun test2y(): Any = + if (true) ListData(listOf()) else FlagData(true) + +fun test2z(): Any = + run { if (true) ListData(listOf()) else FlagData(true) } + diff --git a/compiler/testData/diagnostics/tests/when/kt10809.txt b/compiler/testData/diagnostics/tests/when/kt10809.txt new file mode 100644 index 00000000000..f1a2f161ff5 --- /dev/null +++ b/compiler/testData/diagnostics/tests/when/kt10809.txt @@ -0,0 +1,37 @@ +package + +public fun listOf(/*0*/ vararg items: T /*kotlin.Array*/): kotlin.collections.List +public fun test1(/*0*/ o: kotlin.Any): ??? +public fun test1x(/*0*/ o: kotlin.Any): Data? +public fun test2(): ??? +public fun test2x(): Data +public fun test2y(): kotlin.Any +public fun test2z(): kotlin.Any + +public interface Data { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class FlagData : Data { + public constructor FlagData(/*0*/ value: kotlin.Boolean) + public final val value: kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Item { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class ListData : Data { + public constructor ListData(/*0*/ list: kotlin.collections.List) + public final val list: kotlin.collections.List + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/when/kt10811.kt b/compiler/testData/diagnostics/tests/when/kt10811.kt new file mode 100644 index 00000000000..e99415e09a4 --- /dev/null +++ b/compiler/testData/diagnostics/tests/when/kt10811.kt @@ -0,0 +1,24 @@ +interface Maybe +class Some(val value: T) : Maybe +class None : Maybe + +fun none() : None = TODO() + +fun test1() : Maybe = if (true) none() else Some("") + +fun test2() : Maybe = when { + true -> none() + else -> Some("") +} + +fun test3() : Maybe = when { + true -> none() + else -> Some("") +} + +fun test4() : Maybe { + when ("") { + "a" -> return none() + else -> return Some("") + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/when/kt10811.txt b/compiler/testData/diagnostics/tests/when/kt10811.txt new file mode 100644 index 00000000000..1e85562d5c1 --- /dev/null +++ b/compiler/testData/diagnostics/tests/when/kt10811.txt @@ -0,0 +1,28 @@ +package + +public fun none(): None +public fun test1(): Maybe +public fun test2(): Maybe +public fun test3(): Maybe +public fun test4(): Maybe + +public interface Maybe { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class None : Maybe { + public constructor None() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Some : Maybe { + public constructor Some(/*0*/ value: T) + public final val value: T + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/when/whenAndLambdaWithExpectedType.kt b/compiler/testData/diagnostics/tests/when/whenAndLambdaWithExpectedType.kt new file mode 100644 index 00000000000..b899b3edb98 --- /dev/null +++ b/compiler/testData/diagnostics/tests/when/whenAndLambdaWithExpectedType.kt @@ -0,0 +1,24 @@ +val test1: (String) -> Boolean = + when { + true -> {{ true }} + else -> {{ false }} + } + +val test2: (String) -> Boolean = + when { + true -> {{ true }} + else -> null!! + } + +val test3: (String) -> Boolean = + when { + true -> { s -> true } + else -> null!! + } + +val test4: (String) -> Boolean = + when { + true -> { s1, s2 -> true } + else -> null!! + } + diff --git a/compiler/testData/diagnostics/tests/when/whenAndLambdaWithExpectedType.txt b/compiler/testData/diagnostics/tests/when/whenAndLambdaWithExpectedType.txt new file mode 100644 index 00000000000..9cba7226978 --- /dev/null +++ b/compiler/testData/diagnostics/tests/when/whenAndLambdaWithExpectedType.txt @@ -0,0 +1,6 @@ +package + +public val test1: (kotlin.String) -> kotlin.Boolean +public val test2: (kotlin.String) -> kotlin.Boolean +public val test3: (kotlin.String) -> kotlin.Boolean +public val test4: (kotlin.String) -> kotlin.Boolean diff --git a/compiler/testData/diagnostics/testsWithStdLib/kt10192.kt b/compiler/testData/diagnostics/testsWithStdLib/when/kt10192.kt similarity index 100% rename from compiler/testData/diagnostics/testsWithStdLib/kt10192.kt rename to compiler/testData/diagnostics/testsWithStdLib/when/kt10192.kt diff --git a/compiler/testData/diagnostics/testsWithStdLib/kt10192.txt b/compiler/testData/diagnostics/testsWithStdLib/when/kt10192.txt similarity index 100% rename from compiler/testData/diagnostics/testsWithStdLib/kt10192.txt rename to compiler/testData/diagnostics/testsWithStdLib/when/kt10192.txt diff --git a/compiler/testData/diagnostics/testsWithStdLib/when/kt10807.kt b/compiler/testData/diagnostics/testsWithStdLib/when/kt10807.kt new file mode 100644 index 00000000000..6d8c7badb00 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/when/kt10807.kt @@ -0,0 +1,17 @@ +import java.util.* +import kotlin.comparisons.compareBy +import kotlin.comparisons.nullsLast + +class Foo(val a: String, val b: Int) + +fun getComp(): Comparator = + when { + else -> nullsLast(compareBy({ it.a }, { it.b })) + } + +fun getCompInverted(): Comparator = + nullsLast( + when { + else -> compareBy({ it.a }, { it.b }) + } + ) \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithStdLib/when/kt10807.txt b/compiler/testData/diagnostics/testsWithStdLib/when/kt10807.txt new file mode 100644 index 00000000000..b3a68964599 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/when/kt10807.txt @@ -0,0 +1,13 @@ +package + +public fun getComp(): java.util.Comparator +public fun getCompInverted(): java.util.Comparator + +public final class Foo { + public constructor Foo(/*0*/ a: kotlin.String, /*1*/ b: kotlin.Int) + public final val a: kotlin.String + public final val b: kotlin.Int + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/when/noTypeArgumentsInConstructor.kt b/compiler/testData/diagnostics/testsWithStdLib/when/noTypeArgumentsInConstructor.kt new file mode 100644 index 00000000000..b61e8987e4a --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/when/noTypeArgumentsInConstructor.kt @@ -0,0 +1,41 @@ +import java.util.* + +fun nullable(x: T): T? = x + +@Suppress("UNUSED_PARAMETER") +fun select(x1: T, x2: T): T = x1 + +val test1 = + listOf(1, 2, 3).mapNotNullTo(ArrayList()) { + if (true) nullable(it) else null + } + +val test2: MutableList = + listOf(1, 2, 3).mapNotNullTo(ArrayList()) { + if (true) nullable(it) else null + } + +val test3: MutableList = + listOf(1, 2, 3).mapNotNullTo(ArrayList()) { + if (true) nullable(it) else null + } + +val test4: Collection = + listOf(1, 2, 3).flatMapTo(LinkedHashSet()) { + listOf(it) + } + +val test5: Collection = + listOf(1, 2, 3).flatMapTo(LinkedHashSet()) { // TODO + if (true) listOf(it) else listOf(it) + } + +val test6: Collection = + listOf(1, 2, 3).flatMapTo(LinkedHashSet()) { + if (true) listOf(it) else listOf(it) + } + +val test7: Collection = + listOf(1, 2, 3).flatMapTo(LinkedHashSet()) { + select(listOf(it), listOf(it)) + } \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithStdLib/when/noTypeArgumentsInConstructor.txt b/compiler/testData/diagnostics/testsWithStdLib/when/noTypeArgumentsInConstructor.txt new file mode 100644 index 00000000000..d3bb98a173d --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/when/noTypeArgumentsInConstructor.txt @@ -0,0 +1,11 @@ +package + +public val test1: java.util.ArrayList +public val test2: kotlin.collections.MutableList +public val test3: kotlin.collections.MutableList +public val test4: kotlin.collections.Collection +public val test5: kotlin.collections.Collection +public val test6: kotlin.collections.Collection +public val test7: kotlin.collections.Collection +public fun nullable(/*0*/ x: T): T? +@kotlin.Suppress(names = {"UNUSED_PARAMETER"}) public fun select(/*0*/ x1: T, /*1*/ x2: T): T diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 2b543abc095..d3253f39674 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -3438,6 +3438,18 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("specialConstructsAndPlatformTypes.kt") + public void testSpecialConstructsAndPlatformTypes() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/controlStructures/specialConstructsAndPlatformTypes.kt"); + doTest(fileName); + } + + @TestMetadata("specialConstructsWithNullableExpectedType.kt") + public void testSpecialConstructsWithNullableExpectedType() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/controlStructures/specialConstructsWithNullableExpectedType.kt"); + doTest(fileName); + } + @TestMetadata("tryReturnType.kt") public void testTryReturnType() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/controlStructures/tryReturnType.kt"); @@ -18714,6 +18726,18 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("kt10809.kt") + public void testKt10809() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/when/kt10809.kt"); + doTest(fileName); + } + + @TestMetadata("kt10811.kt") + public void testKt10811() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/when/kt10811.kt"); + doTest(fileName); + } + @TestMetadata("kt4434.kt") public void testKt4434() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/when/kt4434.kt"); @@ -18834,6 +18858,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("whenAndLambdaWithExpectedType.kt") + public void testWhenAndLambdaWithExpectedType() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/when/whenAndLambdaWithExpectedType.kt"); + doTest(fileName); + } + @TestMetadata("WhenTypeDisjunctions.kt") public void testWhenTypeDisjunctions() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/when/WhenTypeDisjunctions.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java index 53e901efb72..10868f7c5c1 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java @@ -95,12 +95,6 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW doTest(fileName); } - @TestMetadata("kt10192.kt") - public void testKt10192() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/kt10192.kt"); - doTest(fileName); - } - @TestMetadata("kt9078.kt") public void testKt9078() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/kt9078.kt"); @@ -1207,4 +1201,31 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW doTest(fileName); } } + + @TestMetadata("compiler/testData/diagnostics/testsWithStdLib/when") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class When extends AbstractDiagnosticsTestWithStdLib { + public void testAllFilesPresentInWhen() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/testsWithStdLib/when"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("kt10192.kt") + public void testKt10192() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/when/kt10192.kt"); + doTest(fileName); + } + + @TestMetadata("kt10807.kt") + public void testKt10807() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/when/kt10807.kt"); + doTest(fileName); + } + + @TestMetadata("noTypeArgumentsInConstructor.kt") + public void testNoTypeArgumentsInConstructor() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/when/noTypeArgumentsInConstructor.kt"); + doTest(fileName); + } + } } diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java b/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java index 1b701cfc6eb..0e8afaa0642 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java @@ -1097,6 +1097,10 @@ public abstract class KotlinBuiltIns { return isNotNullConstructedFromGivenClass(type, FQ_NAMES.unit); } + public static boolean isUnitOrNullableUnit(@NotNull KotlinType type) { + return isConstructedFromGivenClass(type, FQ_NAMES.unit); + } + public boolean isBooleanOrSubtype(@NotNull KotlinType type) { return KotlinTypeChecker.DEFAULT.isSubtypeOf(type, getBooleanType()); } diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt index dec74dd8e1d..5209f34de0b 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt @@ -197,7 +197,7 @@ class ReferenceVariantsHelper( } if (callType == CallType.SUPER_MEMBERS) { // we need to unwrap fake overrides in case of "super." because ShadowedDeclarationsFilter does not work correctly - return descriptors.flatMapTo(LinkedHashSet()) { + return descriptors.flatMapTo(LinkedHashSet()) { if (it is CallableMemberDescriptor && it.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) it.overriddenDescriptors else listOf(it) } }