NI: introduce warning about implicitly inferred Nothing with existing non-Nothing expected type
^KT-35406 Fixed
This commit is contained in:
Generated
+8
-3
@@ -23347,9 +23347,14 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte
|
||||
runTest("compiler/testData/diagnostics/tests/typeParameters/functionTypeAsUpperBound.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("implicitNothingAsTypeParameter.kt")
|
||||
public void testImplicitNothingAsTypeParameter() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/typeParameters/implicitNothingAsTypeParameter.kt");
|
||||
@TestMetadata("implicitNothingAgainstNotNothingExpectedType.kt")
|
||||
public void testImplicitNothingAgainstNotNothingExpectedType() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/typeParameters/implicitNothingAgainstNotNothingExpectedType.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("implicitNothingInReturnPosition.kt")
|
||||
public void testImplicitNothingInReturnPosition() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/typeParameters/implicitNothingInReturnPosition.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("implicitNothingOnDelegates.kt")
|
||||
|
||||
@@ -780,7 +780,8 @@ public interface Errors {
|
||||
|
||||
DiagnosticFactory0<KtExpression> TYPE_INFERENCE_FAILED_ON_SPECIAL_CONSTRUCT = DiagnosticFactory0.create(ERROR, SPECIAL_CONSTRUCT_TOKEN);
|
||||
|
||||
DiagnosticFactory0<PsiElement> IMPLICIT_NOTHING_AS_TYPE_PARAMETER = DiagnosticFactory0.create(WARNING);
|
||||
DiagnosticFactory0<PsiElement> IMPLICIT_NOTHING_TYPE_ARGUMENT_IN_RETURN_POSITION = DiagnosticFactory0.create(WARNING);
|
||||
DiagnosticFactory0<PsiElement> IMPLICIT_NOTHING_TYPE_ARGUMENT_AGAINST_NOT_NOTHING_EXPECTED_TYPE = DiagnosticFactory0.create(WARNING);
|
||||
|
||||
// Reflection
|
||||
|
||||
|
||||
@@ -117,6 +117,18 @@ fun BindingTrace.reportDiagnosticOnce(diagnostic: Diagnostic) {
|
||||
report(diagnostic)
|
||||
}
|
||||
|
||||
fun BindingTrace.reportDiagnosticOnceWrtDiagnosticFactoryList(
|
||||
diagnosticToReport: Diagnostic,
|
||||
vararg diagnosticFactories: DiagnosticFactory<*>,
|
||||
) {
|
||||
val hasAlreadyReportedDiagnosticFromListOrSameType = bindingContext.diagnostics.forElement(diagnosticToReport.psiElement)
|
||||
.any { diagnostic -> diagnostic.factory == diagnosticToReport.factory || diagnosticFactories.any { it == diagnostic.factory } }
|
||||
|
||||
if (hasAlreadyReportedDiagnosticFromListOrSameType) return
|
||||
|
||||
report(diagnosticToReport)
|
||||
}
|
||||
|
||||
class TypeMismatchDueToTypeProjectionsData(
|
||||
val expectedType: KotlinType,
|
||||
val expressionType: KotlinType,
|
||||
|
||||
+2
-1
@@ -1001,7 +1001,8 @@ public class DefaultErrorMessages {
|
||||
MAP.put(ILLEGAL_SUSPEND_PROPERTY_ACCESS, "Suspend property ''{0}'' should be accessed only from a coroutine or suspend function", NAME);
|
||||
MAP.put(ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL, "Restricted suspending functions can only invoke member or extension suspending functions on their restricted coroutine scope");
|
||||
MAP.put(NON_MODIFIER_FORM_FOR_BUILT_IN_SUSPEND, "''suspend'' function can only be called in a form of modifier of a lambda: suspend { ... }");
|
||||
MAP.put(IMPLICIT_NOTHING_AS_TYPE_PARAMETER, "One of the type variables was implicitly inferred to Nothing. Please, specify type arguments explicitly to hide this warning.");
|
||||
MAP.put(IMPLICIT_NOTHING_TYPE_ARGUMENT_IN_RETURN_POSITION, "Returning type parameter has been inferred to Nothing implicitly. Please, specify type arguments explicitly to hide this warning. Nothing can produce an exception at runtime.");
|
||||
MAP.put(IMPLICIT_NOTHING_TYPE_ARGUMENT_AGAINST_NOT_NOTHING_EXPECTED_TYPE, "Returning type parameter has been inferred to Nothing implicitly because Nothing is more specific than specified expected type. Please specify type arguments explicitly in accordance with expected type to hide this warning. Nothing can produce an exception at runtime.");
|
||||
MAP.put(RETURN_FOR_BUILT_IN_SUSPEND, "Using implicit label for this lambda is prohibited");
|
||||
MAP.put(MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND, "Calls having a form of ''suspend {}'' are deprecated because ''suspend'' in the context will have a meaning of a modifier. Add empty argument list to the call: ''suspend() { ... }''");
|
||||
|
||||
|
||||
+128
-16
@@ -9,12 +9,20 @@ import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.builtins.isBuiltinFunctionalType
|
||||
import org.jetbrains.kotlin.builtins.isFunctionOrSuspendFunctionType
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.diagnostics.reportDiagnosticOnceWrtDiagnosticFactoryList
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.SPECIAL_FUNCTION_NAMES
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getParameterForArgument
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.NewResolvedCallImpl
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.psiExpression
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.psiKotlinCall
|
||||
import org.jetbrains.kotlin.types.DeferredType
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.expressions.ControlStructureTypingUtils
|
||||
import org.jetbrains.kotlin.types.typeUtil.isNothing
|
||||
import org.jetbrains.kotlin.types.typeUtil.isNothingOrNullableNothing
|
||||
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
|
||||
|
||||
object ImplicitNothingAsTypeParameterCallChecker : CallChecker {
|
||||
@@ -34,27 +42,131 @@ object ImplicitNothingAsTypeParameterCallChecker : CallChecker {
|
||||
* return inv()
|
||||
* }
|
||||
*/
|
||||
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
|
||||
private fun checkByReturnPositionWithoutExpected(
|
||||
resolvedCall: ResolvedCall<*>,
|
||||
reportOn: PsiElement,
|
||||
context: CallCheckerContext,
|
||||
): Boolean {
|
||||
val resultingDescriptor = resolvedCall.resultingDescriptor
|
||||
val expectedType = context.resolutionContext.expectedType
|
||||
val inferredReturnType = resultingDescriptor.returnType
|
||||
val isBuiltinFunctionalType =
|
||||
resolvedCall.resultingDescriptor.dispatchReceiverParameter?.value?.type?.isBuiltinFunctionalType == true
|
||||
|
||||
if (inferredReturnType is DeferredType || isBuiltinFunctionalType)
|
||||
return
|
||||
if (resultingDescriptor.name !in SPECIAL_FUNCTION_NAMES && resolvedCall.call.typeArguments.isEmpty()) {
|
||||
val lambdasFromArgumentsReturnTypes =
|
||||
resolvedCall.candidateDescriptor.valueParameters.filter { it.type.isFunctionOrSuspendFunctionType }
|
||||
.map { it.returnType?.arguments?.last()?.type }.toSet()
|
||||
val unsubstitutedReturnType = resultingDescriptor.original.returnType
|
||||
val expectedType = context.resolutionContext.expectedType
|
||||
val hasImplicitNothing = inferredReturnType?.isNothing() == true &&
|
||||
unsubstitutedReturnType?.isTypeParameter() == true &&
|
||||
(TypeUtils.noExpectedType(expectedType) || !expectedType.isNothing())
|
||||
if (inferredReturnType is DeferredType || isBuiltinFunctionalType) return false
|
||||
if (resultingDescriptor.name in SPECIAL_FUNCTION_NAMES || resolvedCall.call.typeArguments.isNotEmpty()) return false
|
||||
|
||||
if (hasImplicitNothing && unsubstitutedReturnType !in lambdasFromArgumentsReturnTypes) {
|
||||
context.trace.report(Errors.IMPLICIT_NOTHING_AS_TYPE_PARAMETER.on(reportOn))
|
||||
val lambdasFromArgumentsReturnTypes =
|
||||
resolvedCall.candidateDescriptor.valueParameters.filter { it.type.isFunctionOrSuspendFunctionType }
|
||||
.map { it.returnType?.arguments?.last()?.type }.toSet()
|
||||
val unsubstitutedReturnType = resultingDescriptor.original.returnType
|
||||
val hasImplicitNothing = inferredReturnType?.isNothing() == true &&
|
||||
unsubstitutedReturnType?.isTypeParameter() == true &&
|
||||
(TypeUtils.noExpectedType(expectedType) || !expectedType.isNothing())
|
||||
|
||||
if (hasImplicitNothing && unsubstitutedReturnType !in lambdasFromArgumentsReturnTypes) {
|
||||
context.trace.reportDiagnosticOnceWrtDiagnosticFactoryList(
|
||||
Errors.IMPLICIT_NOTHING_TYPE_ARGUMENT_IN_RETURN_POSITION.on(reportOn),
|
||||
Errors.IMPLICIT_NOTHING_TYPE_ARGUMENT_AGAINST_NOT_NOTHING_EXPECTED_TYPE,
|
||||
)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private fun ResolvedAtom.getResolvedCallAtom(bindingContext: BindingContext): ResolvedCallAtom? {
|
||||
if (this is SingleCallResolutionResult) return resultCallAtom
|
||||
|
||||
val resolutionAtom = atom as? KotlinCallArgument ?: return null
|
||||
val resolvedCall = resolutionAtom.psiExpression.getResolvedCall(bindingContext)
|
||||
|
||||
return if (resolvedCall is NewResolvedCallImpl) resolvedCall.resolvedCallAtom else null
|
||||
}
|
||||
|
||||
private fun findFunctionsWithImplicitNothingAndReport(resolvedAtoms: List<ResolvedAtom>, context: CallCheckerContext): Boolean {
|
||||
var hasAlreadyReportedAtDepth = false
|
||||
|
||||
for (resolvedAtom in resolvedAtoms) {
|
||||
val subResolveAtoms = resolvedAtom.subResolvedAtoms
|
||||
|
||||
if (!subResolveAtoms.isNullOrEmpty() && findFunctionsWithImplicitNothingAndReport(subResolveAtoms, context)) {
|
||||
hasAlreadyReportedAtDepth = true
|
||||
continue
|
||||
}
|
||||
|
||||
val resolvedCallAtom = resolvedAtom.getResolvedCallAtom(context.trace.bindingContext) ?: continue
|
||||
val candidateDescriptor = resolvedCallAtom.candidateDescriptor
|
||||
val isReturnTypeOwnTypeParameter = candidateDescriptor.typeParameters.any { it.defaultType == candidateDescriptor.returnType }
|
||||
val isSpecialCall = candidateDescriptor.name in SPECIAL_FUNCTION_NAMES
|
||||
val hasExplicitTypeArguments = resolvedCallAtom.atom.psiKotlinCall.typeArguments.isNotEmpty() // not required
|
||||
|
||||
if (!isSpecialCall && isReturnTypeOwnTypeParameter && !hasExplicitTypeArguments) {
|
||||
context.trace.reportDiagnosticOnceWrtDiagnosticFactoryList(
|
||||
Errors.IMPLICIT_NOTHING_TYPE_ARGUMENT_AGAINST_NOT_NOTHING_EXPECTED_TYPE.on(
|
||||
resolvedCallAtom.atom.psiKotlinCall.psiCall.run { calleeExpression ?: callElement },
|
||||
),
|
||||
Errors.IMPLICIT_NOTHING_TYPE_ARGUMENT_IN_RETURN_POSITION,
|
||||
)
|
||||
hasAlreadyReportedAtDepth = true
|
||||
}
|
||||
}
|
||||
|
||||
return hasAlreadyReportedAtDepth
|
||||
}
|
||||
|
||||
private fun getSubResolvedAtomsToAnalyze(
|
||||
resolvedCall: ResolvedCall<*>,
|
||||
expectedType: KotlinType,
|
||||
bindingContext: BindingContext,
|
||||
): List<ResolvedAtom>? {
|
||||
if (resolvedCall !is NewResolvedCallImpl) return null
|
||||
|
||||
val hasNotNothingExpectedType = !TypeUtils.noExpectedType(expectedType) && !expectedType.isNothingOrNullableNothing()
|
||||
val hasNothingReturnType = resolvedCall.resultingDescriptor.returnType?.isNothingOrNullableNothing() == true
|
||||
val isSubResolvedAtomsNotEmpty = !resolvedCall.resolvedCallAtom.subResolvedAtoms.isNullOrEmpty()
|
||||
|
||||
if (hasNotNothingExpectedType && hasNothingReturnType && isSubResolvedAtomsNotEmpty) {
|
||||
return resolvedCall.resolvedCallAtom.subResolvedAtoms
|
||||
}
|
||||
|
||||
val resolvedAtomsFromArguments = resolvedCall.valueArguments.values.mapNotNull { argument ->
|
||||
if (argument !is ExpressionValueArgument) return@mapNotNull null
|
||||
|
||||
val resolvedCallForArgument =
|
||||
argument.valueArgument?.getArgumentExpression()?.getResolvedCall(bindingContext) as? NewResolvedCallImpl
|
||||
?: return@mapNotNull null
|
||||
val expectedTypeForArgument = resolvedCall.getParameterForArgument(argument.valueArgument)?.type ?: return@mapNotNull null
|
||||
|
||||
getSubResolvedAtomsToAnalyze(resolvedCallForArgument, expectedTypeForArgument, bindingContext)
|
||||
}.flatten()
|
||||
|
||||
val extensionReceiver = resolvedCall.resolvedCallAtom.extensionReceiverArgument?.psiExpression
|
||||
val resolvedAtomsFromExtensionReceiver = extensionReceiver?.run {
|
||||
val extensionReceiverResolvedCall = getResolvedCall(bindingContext)
|
||||
// It's needed to exclude invoke with extension (when resolved call for extension equals to common resolved call)
|
||||
if (extensionReceiverResolvedCall == resolvedCall) return@run null
|
||||
|
||||
getSubResolvedAtomsToAnalyze(
|
||||
getResolvedCall(bindingContext) ?: return@run null,
|
||||
resolvedCall.resultingDescriptor.extensionReceiverParameter?.type ?: return@run null,
|
||||
bindingContext,
|
||||
)
|
||||
}
|
||||
|
||||
return if (resolvedAtomsFromExtensionReceiver != null) {
|
||||
resolvedAtomsFromArguments + resolvedAtomsFromExtensionReceiver
|
||||
} else resolvedAtomsFromArguments
|
||||
}
|
||||
|
||||
private fun checkAgainstNotNothingExpectedType(resolvedCall: ResolvedCall<*>, context: CallCheckerContext): Boolean {
|
||||
val subResolvedAtoms =
|
||||
getSubResolvedAtomsToAnalyze(resolvedCall, context.resolutionContext.expectedType, context.trace.bindingContext) ?: return false
|
||||
|
||||
return findFunctionsWithImplicitNothingAndReport(subResolvedAtoms, context)
|
||||
}
|
||||
|
||||
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
|
||||
checkByReturnPositionWithoutExpected(resolvedCall, reportOn, context) || checkAgainstNotNothingExpectedType(resolvedCall, context)
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -30,7 +30,7 @@ fun <T> test(x: T) {
|
||||
<!REIFIED_TYPE_FORBIDDEN_SUBSTITUTION, REIFIED_TYPE_FORBIDDEN_SUBSTITUTION!>baz<!>(null, null, ::foo)
|
||||
|
||||
val s3: Pair<Int, String?> = <!NI;TYPE_MISMATCH, OI;TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH!>bar(null, null, ::<!OI;TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>foo<!>)<!>
|
||||
val s4: Pair<Int?, String> = <!NI;TYPE_MISMATCH, NI;TYPE_MISMATCH, NI;TYPE_MISMATCH, OI;TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH!>bar(null, null, ::<!NI;IMPLICIT_NOTHING_AS_TYPE_PARAMETER, OI;TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>foo<!>)<!>
|
||||
val s4: Pair<Int?, String> = <!NI;TYPE_MISMATCH, NI;TYPE_MISMATCH, NI;TYPE_MISMATCH, OI;TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH!>bar(null, null, ::<!NI;IMPLICIT_NOTHING_TYPE_ARGUMENT_IN_RETURN_POSITION, OI;TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>foo<!>)<!>
|
||||
|
||||
val s5: Pair<Int, String> = <!NI;TYPE_MISMATCH, NI;TYPE_MISMATCH, OI;TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH!>bar(1, "", ::foo)<!>
|
||||
val (a1: Int, b1: String) = <!COMPONENT_FUNCTION_RETURN_TYPE_MISMATCH!>bar(1, "", ::foo)<!>
|
||||
|
||||
+2
-2
@@ -13,7 +13,7 @@ fun <E4, F : E4> noSmartCast4(arg: E4?, fn: F): E4 = TODO()
|
||||
fun testSmartCast(s: String?) {
|
||||
id(
|
||||
if (s != null) ""
|
||||
else <!IMPLICIT_NOTHING_AS_TYPE_PARAMETER!>smartCast<!>(null) { "" }
|
||||
else <!IMPLICIT_NOTHING_TYPE_ARGUMENT_IN_RETURN_POSITION!>smartCast<!>(null) { "" }
|
||||
)
|
||||
<!DEBUG_INFO_SMARTCAST!>s<!>.length
|
||||
}
|
||||
@@ -46,7 +46,7 @@ fun testNoSmartCast3(s: String?) {
|
||||
fun testNoSmartCast4(s: String?) {
|
||||
id(
|
||||
if (s != null) ( {""} )
|
||||
else <!IMPLICIT_NOTHING_AS_TYPE_PARAMETER, IMPLICIT_NOTHING_AS_TYPE_PARAMETER!>noSmartCast4<!>(null) <!TYPE_MISMATCH!>{ <!TYPE_MISMATCH!>""<!> }<!>
|
||||
else <!IMPLICIT_NOTHING_TYPE_ARGUMENT_IN_RETURN_POSITION!>noSmartCast4<!>(null) <!TYPE_MISMATCH!>{ <!TYPE_MISMATCH!>""<!> }<!>
|
||||
)
|
||||
s<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
|
||||
+1
-1
@@ -9,5 +9,5 @@ fun <K> invOut(y: K?): Inv<Out<K>> = TODO()
|
||||
fun <R> test(x: Inv<Out<R>>): R = TODO()
|
||||
|
||||
fun testNothing() {
|
||||
<!IMPLICIT_NOTHING_AS_TYPE_PARAMETER!>test<!>(invOut(null)) checkType { _<Nothing>() }
|
||||
<!IMPLICIT_NOTHING_TYPE_ARGUMENT_IN_RETURN_POSITION!>test<!>(invOut(null)) checkType { _<Nothing>() }
|
||||
}
|
||||
|
||||
Vendored
+4
-4
@@ -14,7 +14,7 @@ inline fun <reified M> materializeReifiedUnbound(): M = TODO()
|
||||
fun <T> select(a: T, b: T): T = TODO()
|
||||
|
||||
fun test1() {
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Nothing")!><!IMPLICIT_NOTHING_AS_TYPE_PARAMETER!>take<!>(null)<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Nothing")!><!IMPLICIT_NOTHING_TYPE_ARGUMENT_IN_RETURN_POSITION!>take<!>(null)<!>
|
||||
}
|
||||
|
||||
fun test2() {
|
||||
@@ -22,20 +22,20 @@ fun test2() {
|
||||
}
|
||||
|
||||
fun test3() {
|
||||
<!IMPLICIT_NOTHING_AS_TYPE_PARAMETER, REIFIED_TYPE_FORBIDDEN_SUBSTITUTION!>takeReifiedUnbound<!>(null)
|
||||
<!IMPLICIT_NOTHING_TYPE_ARGUMENT_IN_RETURN_POSITION, REIFIED_TYPE_FORBIDDEN_SUBSTITUTION!>takeReifiedUnbound<!>(null)
|
||||
}
|
||||
|
||||
fun test4(): Bound = <!DEBUG_INFO_EXPRESSION_TYPE("Bound")!>takeReifiedUnbound(null)<!>
|
||||
|
||||
fun test5(): Bound? = select(
|
||||
null,
|
||||
<!IMPLICIT_NOTHING_AS_TYPE_PARAMETER, IMPLICIT_NOTHING_AS_TYPE_PARAMETER!>materialize<!>()
|
||||
<!IMPLICIT_NOTHING_TYPE_ARGUMENT_IN_RETURN_POSITION!>materialize<!>()
|
||||
)
|
||||
|
||||
fun test6() {
|
||||
select(
|
||||
null,
|
||||
<!IMPLICIT_NOTHING_AS_TYPE_PARAMETER, IMPLICIT_NOTHING_AS_TYPE_PARAMETER, REIFIED_TYPE_FORBIDDEN_SUBSTITUTION, REIFIED_TYPE_FORBIDDEN_SUBSTITUTION!>materializeReified<!>()
|
||||
<!IMPLICIT_NOTHING_TYPE_ARGUMENT_IN_RETURN_POSITION, REIFIED_TYPE_FORBIDDEN_SUBSTITUTION, REIFIED_TYPE_FORBIDDEN_SUBSTITUTION!>materializeReified<!>()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE -UNCHECKED_CAST -UNUSED_EXPRESSION -UNREACHABLE_CODE
|
||||
// !LANGUAGE: +NewInference
|
||||
|
||||
fun <K> materialize(): K = null as K
|
||||
fun <K, T> materializeWithGenericArg(x: T): K = null as K
|
||||
|
||||
fun <K> id(x: K): K = null as K
|
||||
fun <K> K.idFromReceiver(): K = null as K
|
||||
fun <K> K.idFromReceiverWithArg(x: String): K = null as K
|
||||
|
||||
fun <S> select(x: S, y: S): S = x
|
||||
|
||||
class Foo<T> {
|
||||
fun idFromClassTypeArg(): T = null as T
|
||||
fun <K> idFromClassTypeArgWithAnotherTypeArg(): T = null as T
|
||||
fun <K> materialize(): K = null as K
|
||||
}
|
||||
|
||||
fun test() {
|
||||
if (true) materialize() else null
|
||||
|
||||
val x1: String? = if (true) materialize() else null
|
||||
|
||||
val x2: String? = if (true) materializeWithGenericArg("") else null
|
||||
|
||||
val x3: String? = if (true) {
|
||||
if (true) materialize() else null
|
||||
} else null
|
||||
|
||||
val x4: String? = if (true) {
|
||||
select(materialize(), null)
|
||||
} else null
|
||||
|
||||
val x5: String? = select(if (true) materialize() else null, null)
|
||||
|
||||
val x6: String? = select(materialize(), null)
|
||||
|
||||
val x7: String? = select(null.idFromReceiver(), null)
|
||||
|
||||
val x8: String? = select(null.idFromReceiverWithArg(""), null)
|
||||
|
||||
val foo = Foo<Nothing?>()
|
||||
|
||||
val x9: String? = select(foo.materialize(), null)
|
||||
val x10: String? = select(foo.idFromClassTypeArgWithAnotherTypeArg(), null)
|
||||
val x11: String? = select(foo.idFromClassTypeArg(), null)
|
||||
|
||||
foo.run {
|
||||
val x12: String? = select(materialize(), null)
|
||||
val x13: String? = select(idFromClassTypeArgWithAnotherTypeArg(), null)
|
||||
val x14: String? = select(idFromClassTypeArg(), null)
|
||||
}
|
||||
|
||||
val boolean: Boolean? = true
|
||||
|
||||
val x15: String? = when (boolean) {
|
||||
true -> select(materialize(), null)
|
||||
false -> select(materialize(), null)
|
||||
null -> null
|
||||
}
|
||||
|
||||
val x16: String? = when (boolean) {
|
||||
true -> null
|
||||
false -> materialize()
|
||||
null -> null
|
||||
}
|
||||
|
||||
val x17: String? = when (boolean) {
|
||||
true -> if (true) null else materialize()
|
||||
false -> if (true) materialize() else null
|
||||
null -> if (true) null else null
|
||||
}
|
||||
|
||||
val x18: String? = try {
|
||||
materialize()
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
|
||||
val x19: String? = if (true) materialize<Nothing?>() else null
|
||||
|
||||
val x20: String? = if (true) materialize<String?>() else null
|
||||
|
||||
val x21: String? = if (true) materialize() else TODO()
|
||||
|
||||
val x22: String? = if (true) return else materialize()
|
||||
|
||||
val x23: String? = if (true) id(null) else null
|
||||
|
||||
foo1(if (true) materialize() else null)
|
||||
|
||||
val x24 = id(foo1(if (true) materialize() else null))
|
||||
|
||||
val x25 = select(materialize(), null).foo2()
|
||||
|
||||
// TODO
|
||||
val x26 = select(materialize(), null).run { foo2() }
|
||||
|
||||
val x27: () -> String? = {
|
||||
id(id(if (true) materialize() else null))
|
||||
}
|
||||
}
|
||||
|
||||
fun foo1(x: String?) {}
|
||||
fun String?.foo2() {}
|
||||
Vendored
+105
@@ -0,0 +1,105 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE -UNCHECKED_CAST -UNUSED_EXPRESSION -UNREACHABLE_CODE
|
||||
// !LANGUAGE: +NewInference
|
||||
|
||||
fun <K> materialize(): K = null as K
|
||||
fun <K, T> materializeWithGenericArg(x: T): K = null as K
|
||||
|
||||
fun <K> id(x: K): K = null as K
|
||||
fun <K> K.idFromReceiver(): K = null as K
|
||||
fun <K> K.idFromReceiverWithArg(x: String): K = null as K
|
||||
|
||||
fun <S> select(x: S, y: S): S = x
|
||||
|
||||
class Foo<T> {
|
||||
fun idFromClassTypeArg(): T = null as T
|
||||
fun <K> idFromClassTypeArgWithAnotherTypeArg(): T = null as T
|
||||
fun <K> materialize(): K = null as K
|
||||
}
|
||||
|
||||
fun test() {
|
||||
if (true) materialize() else null
|
||||
|
||||
val x1: String? = if (true) <!IMPLICIT_NOTHING_TYPE_ARGUMENT_AGAINST_NOT_NOTHING_EXPECTED_TYPE!>materialize<!>() else null
|
||||
|
||||
val x2: String? = if (true) <!IMPLICIT_NOTHING_TYPE_ARGUMENT_AGAINST_NOT_NOTHING_EXPECTED_TYPE!>materializeWithGenericArg<!>("") else null
|
||||
|
||||
val x3: String? = if (true) {
|
||||
if (true) <!IMPLICIT_NOTHING_TYPE_ARGUMENT_AGAINST_NOT_NOTHING_EXPECTED_TYPE!>materialize<!>() else null
|
||||
} else null
|
||||
|
||||
val x4: String? = if (true) {
|
||||
select(<!IMPLICIT_NOTHING_TYPE_ARGUMENT_AGAINST_NOT_NOTHING_EXPECTED_TYPE!>materialize<!>(), null)
|
||||
} else null
|
||||
|
||||
val x5: String? = select(if (true) <!IMPLICIT_NOTHING_TYPE_ARGUMENT_AGAINST_NOT_NOTHING_EXPECTED_TYPE!>materialize<!>() else null, null)
|
||||
|
||||
val x6: String? = select(<!IMPLICIT_NOTHING_TYPE_ARGUMENT_AGAINST_NOT_NOTHING_EXPECTED_TYPE!>materialize<!>(), null)
|
||||
|
||||
val x7: String? = select(null.<!IMPLICIT_NOTHING_TYPE_ARGUMENT_AGAINST_NOT_NOTHING_EXPECTED_TYPE!>idFromReceiver<!>(), null)
|
||||
|
||||
val x8: String? = select(null.<!IMPLICIT_NOTHING_TYPE_ARGUMENT_AGAINST_NOT_NOTHING_EXPECTED_TYPE!>idFromReceiverWithArg<!>(""), null)
|
||||
|
||||
val foo = Foo<Nothing?>()
|
||||
|
||||
val x9: String? = select(foo.<!IMPLICIT_NOTHING_TYPE_ARGUMENT_AGAINST_NOT_NOTHING_EXPECTED_TYPE!>materialize<!>(), null)
|
||||
val x10: String? = select(foo.<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>idFromClassTypeArgWithAnotherTypeArg<!>(), null)
|
||||
val x11: String? = select(foo.idFromClassTypeArg(), null)
|
||||
|
||||
foo.run {
|
||||
val x12: String? = select(<!IMPLICIT_NOTHING_TYPE_ARGUMENT_AGAINST_NOT_NOTHING_EXPECTED_TYPE!>materialize<!>(), null)
|
||||
val x13: String? = select(<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>idFromClassTypeArgWithAnotherTypeArg<!>(), null)
|
||||
val x14: String? = select(idFromClassTypeArg(), null)
|
||||
}
|
||||
|
||||
val boolean: Boolean? = true
|
||||
|
||||
val x15: String? = when (boolean) {
|
||||
true -> select(<!IMPLICIT_NOTHING_TYPE_ARGUMENT_AGAINST_NOT_NOTHING_EXPECTED_TYPE!>materialize<!>(), null)
|
||||
false -> select(<!IMPLICIT_NOTHING_TYPE_ARGUMENT_AGAINST_NOT_NOTHING_EXPECTED_TYPE!>materialize<!>(), null)
|
||||
null -> null
|
||||
}
|
||||
|
||||
val x16: String? = when (boolean) {
|
||||
true -> null
|
||||
false -> <!IMPLICIT_NOTHING_TYPE_ARGUMENT_AGAINST_NOT_NOTHING_EXPECTED_TYPE!>materialize<!>()
|
||||
null -> null
|
||||
}
|
||||
|
||||
val x17: String? = when (boolean) {
|
||||
true -> if (true) null else <!IMPLICIT_NOTHING_TYPE_ARGUMENT_AGAINST_NOT_NOTHING_EXPECTED_TYPE!>materialize<!>()
|
||||
false -> if (true) <!IMPLICIT_NOTHING_TYPE_ARGUMENT_AGAINST_NOT_NOTHING_EXPECTED_TYPE!>materialize<!>() else null
|
||||
null -> if (true) null else null
|
||||
}
|
||||
|
||||
val x18: String? = try {
|
||||
<!IMPLICIT_NOTHING_TYPE_ARGUMENT_AGAINST_NOT_NOTHING_EXPECTED_TYPE!>materialize<!>()
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
|
||||
val x19: String? = if (true) materialize<Nothing?>() else null
|
||||
|
||||
val x20: String? = if (true) materialize<String?>() else null
|
||||
|
||||
val x21: String? = if (true) <!IMPLICIT_NOTHING_TYPE_ARGUMENT_IN_RETURN_POSITION!>materialize<!>() else TODO()
|
||||
|
||||
val x22: String? = if (true) return else <!IMPLICIT_NOTHING_TYPE_ARGUMENT_IN_RETURN_POSITION!>materialize<!>()
|
||||
|
||||
val x23: String? = if (true) <!IMPLICIT_NOTHING_TYPE_ARGUMENT_AGAINST_NOT_NOTHING_EXPECTED_TYPE!>id<!>(null) else null
|
||||
|
||||
foo1(if (true) <!IMPLICIT_NOTHING_TYPE_ARGUMENT_AGAINST_NOT_NOTHING_EXPECTED_TYPE!>materialize<!>() else null)
|
||||
|
||||
val x24 = id(foo1(if (true) <!IMPLICIT_NOTHING_TYPE_ARGUMENT_AGAINST_NOT_NOTHING_EXPECTED_TYPE!>materialize<!>() else null))
|
||||
|
||||
val x25 = select(<!IMPLICIT_NOTHING_TYPE_ARGUMENT_AGAINST_NOT_NOTHING_EXPECTED_TYPE!>materialize<!>(), null).foo2()
|
||||
|
||||
// TODO
|
||||
val x26 = select(materialize(), null).run { foo2() }
|
||||
|
||||
val x27: () -> String? = {
|
||||
id(id(if (true) <!IMPLICIT_NOTHING_TYPE_ARGUMENT_AGAINST_NOT_NOTHING_EXPECTED_TYPE!>materialize<!>() else null))
|
||||
}
|
||||
}
|
||||
|
||||
fun foo1(x: String?) {}
|
||||
fun String?.foo2() {}
|
||||
Vendored
+21
@@ -0,0 +1,21 @@
|
||||
package
|
||||
|
||||
public fun foo1(/*0*/ x: kotlin.String?): kotlin.Unit
|
||||
public fun </*0*/ K> id(/*0*/ x: K): K
|
||||
public fun </*0*/ K> materialize(): K
|
||||
public fun </*0*/ K, /*1*/ T> materializeWithGenericArg(/*0*/ x: T): K
|
||||
public fun </*0*/ S> select(/*0*/ x: S, /*1*/ y: S): S
|
||||
public fun test(): kotlin.Unit
|
||||
public fun kotlin.String?.foo2(): kotlin.Unit
|
||||
public fun </*0*/ K> K.idFromReceiver(): K
|
||||
public fun </*0*/ K> K.idFromReceiverWithArg(/*0*/ x: kotlin.String): K
|
||||
|
||||
public final class Foo</*0*/ T> {
|
||||
public constructor Foo</*0*/ 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 final fun idFromClassTypeArg(): T
|
||||
public final fun </*0*/ K> idFromClassTypeArgWithAnotherTypeArg(): T
|
||||
public final fun </*0*/ K> materialize(): K
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+4
-4
@@ -40,7 +40,7 @@ class Context<T>
|
||||
fun <T> Any.decodeIn(typeFrom: Context<in T>): T = something()
|
||||
|
||||
fun <T> Any?.decodeOut1(typeFrom: Context<out T>): T {
|
||||
return <!NI;TYPE_MISMATCH!>this?.<!IMPLICIT_NOTHING_AS_TYPE_PARAMETER, NI;IMPLICIT_NOTHING_AS_TYPE_PARAMETER!>decodeIn<!>(typeFrom) ?: <!OI;TYPE_MISMATCH!>kotlin.Unit<!><!>
|
||||
return <!NI;TYPE_MISMATCH!>this?.<!IMPLICIT_NOTHING_TYPE_ARGUMENT_IN_RETURN_POSITION!>decodeIn<!>(typeFrom) ?: <!OI;TYPE_MISMATCH!>kotlin.Unit<!><!>
|
||||
}
|
||||
|
||||
fun <T> Any.decodeOut2(typeFrom: Context<out T>): T {
|
||||
@@ -48,11 +48,11 @@ fun <T> Any.decodeOut2(typeFrom: Context<out T>): T {
|
||||
}
|
||||
|
||||
fun <T> Any.decodeOut3(typeFrom: Context<out T>): T {
|
||||
<!UNREACHABLE_CODE!>val x =<!> this.<!IMPLICIT_NOTHING_AS_TYPE_PARAMETER!>decodeIn<!>(typeFrom)
|
||||
<!UNREACHABLE_CODE!>val x =<!> this.<!IMPLICIT_NOTHING_TYPE_ARGUMENT_IN_RETURN_POSITION!>decodeIn<!>(typeFrom)
|
||||
}
|
||||
|
||||
fun <T> Any.decodeOut4(typeFrom: Context<out T>): T {
|
||||
<!UNREACHABLE_CODE!>val x: Any =<!> this.<!IMPLICIT_NOTHING_AS_TYPE_PARAMETER!>decodeIn<!>(typeFrom)
|
||||
<!UNREACHABLE_CODE!>val x: Any =<!> this.<!IMPLICIT_NOTHING_TYPE_ARGUMENT_IN_RETURN_POSITION!>decodeIn<!>(typeFrom)
|
||||
}
|
||||
|
||||
class TrieNode<out E> {
|
||||
@@ -91,7 +91,7 @@ interface Worker<out T>
|
||||
interface RenderContext<StateT, in OutputT : Any>
|
||||
|
||||
val emptyOrNull: List<Nothing>? = null
|
||||
val x = emptyOrNull?.<!IMPLICIT_NOTHING_AS_TYPE_PARAMETER!>get<!>(0)
|
||||
val x = emptyOrNull?.<!IMPLICIT_NOTHING_TYPE_ARGUMENT_IN_RETURN_POSITION!>get<!>(0)
|
||||
|
||||
val errorCompletion = { <!UNUSED_ANONYMOUS_PARAMETER!>e<!>: Throwable -> throw Exception() }
|
||||
|
||||
+1
-1
@@ -18,6 +18,6 @@ private object Scope {
|
||||
fun <T> materialize(): T = Any() as T
|
||||
|
||||
fun test(i: Inv<out Number>) {
|
||||
val <!UNUSED_VARIABLE!>p<!>: Int by <!IMPLICIT_NOTHING_AS_TYPE_PARAMETER!>Scope.Delegate(i)<!>
|
||||
val <!UNUSED_VARIABLE!>p<!>: Int by <!IMPLICIT_NOTHING_TYPE_ARGUMENT_IN_RETURN_POSITION!>Scope.Delegate(i)<!>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3831,12 +3831,12 @@ fun Nothing.case_63() {
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Nothing"), DEBUG_INFO_EXPRESSION_TYPE("kotlin.Nothing")!>this<!>.hashCode()
|
||||
|
||||
hashCode()
|
||||
<!IMPLICIT_NOTHING_AS_TYPE_PARAMETER!>apply<!> {
|
||||
<!IMPLICIT_NOTHING_TYPE_ARGUMENT_IN_RETURN_POSITION!>apply<!> {
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Nothing"), DEBUG_INFO_EXPRESSION_TYPE("kotlin.Nothing")!>this<!>
|
||||
<!UNREACHABLE_CODE!>hashCode()<!>
|
||||
<!UNREACHABLE_CODE!><!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Nothing"), DEBUG_INFO_EXPRESSION_TYPE("kotlin.Nothing")!>this<!>.hashCode()<!>
|
||||
}
|
||||
<!IMPLICIT_NOTHING_AS_TYPE_PARAMETER!>also<!> {
|
||||
<!IMPLICIT_NOTHING_TYPE_ARGUMENT_IN_RETURN_POSITION!>also<!> {
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Nothing")!>it<!>
|
||||
<!UNREACHABLE_CODE!><!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Nothing")!>it<!>.hashCode()<!>
|
||||
}
|
||||
|
||||
+8
-3
@@ -23429,9 +23429,14 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
runTest("compiler/testData/diagnostics/tests/typeParameters/functionTypeAsUpperBound.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("implicitNothingAsTypeParameter.kt")
|
||||
public void testImplicitNothingAsTypeParameter() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/typeParameters/implicitNothingAsTypeParameter.kt");
|
||||
@TestMetadata("implicitNothingAgainstNotNothingExpectedType.kt")
|
||||
public void testImplicitNothingAgainstNotNothingExpectedType() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/typeParameters/implicitNothingAgainstNotNothingExpectedType.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("implicitNothingInReturnPosition.kt")
|
||||
public void testImplicitNothingInReturnPosition() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/typeParameters/implicitNothingInReturnPosition.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("implicitNothingOnDelegates.kt")
|
||||
|
||||
Generated
+8
-3
@@ -23349,9 +23349,14 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
|
||||
runTest("compiler/testData/diagnostics/tests/typeParameters/functionTypeAsUpperBound.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("implicitNothingAsTypeParameter.kt")
|
||||
public void testImplicitNothingAsTypeParameter() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/typeParameters/implicitNothingAsTypeParameter.kt");
|
||||
@TestMetadata("implicitNothingAgainstNotNothingExpectedType.kt")
|
||||
public void testImplicitNothingAgainstNotNothingExpectedType() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/typeParameters/implicitNothingAgainstNotNothingExpectedType.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("implicitNothingInReturnPosition.kt")
|
||||
public void testImplicitNothingInReturnPosition() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/typeParameters/implicitNothingInReturnPosition.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("implicitNothingOnDelegates.kt")
|
||||
|
||||
Reference in New Issue
Block a user