Introduce warning about implicitly inferred Nothing as a type parameter
^KT-20849 Fixed
This commit is contained in:
@@ -743,6 +743,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);
|
||||
|
||||
// Reflection
|
||||
|
||||
DiagnosticFactory1<KtExpression, CallableMemberDescriptor> EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED = DiagnosticFactory1.create(ERROR);
|
||||
|
||||
+1
@@ -959,6 +959,7 @@ 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(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() { ... }''");
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ private val DEFAULT_CALL_CHECKERS = listOf(
|
||||
ConstructorHeaderCallChecker, ProtectedConstructorCallChecker, ApiVersionCallChecker,
|
||||
CoroutineSuspendCallChecker, BuilderFunctionsCallChecker, DslScopeViolationCallChecker, MissingDependencyClassChecker,
|
||||
CallableReferenceCompatibilityChecker(), LateinitIntrinsicApplicabilityChecker,
|
||||
UnderscoreUsageChecker, AssigningNamedArgumentToVarargChecker(),
|
||||
UnderscoreUsageChecker, AssigningNamedArgumentToVarargChecker(), ImplicitNothingAsTypeParameterCallChecker,
|
||||
PrimitiveNumericComparisonCallChecker, LambdaWithSuspendModifierCallChecker,
|
||||
UselessElvisCallChecker(), ResultTypeWithNullableOperatorsChecker(), NullableVarargArgumentCallChecker,
|
||||
NamedFunAsExpressionChecker, ContractNotAllowedCallChecker, ReifiedTypeParameterSubstitutionChecker(), TypeOfChecker
|
||||
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.resolve.calls.checkers
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.builtins.isFunctionType
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.types.expressions.ControlStructureTypingUtils
|
||||
import org.jetbrains.kotlin.types.typeUtil.isNothing
|
||||
|
||||
object ImplicitNothingAsTypeParameterCallChecker : CallChecker {
|
||||
private val SPECIAL_FUNCTION_NAMES = ControlStructureTypingUtils.ResolveConstruct.values().map { it.specialFunctionName }.toSet()
|
||||
|
||||
/*
|
||||
* The warning isn't reported in cases where there are lambda among the function arguments,
|
||||
* the return type of which is a type variable, that was inferred to Nothing.
|
||||
* This corresponds to useful cases in which this report will not be helpful.
|
||||
*
|
||||
* E.g.:
|
||||
*
|
||||
* 1) Return if null:
|
||||
* x?.let { return }
|
||||
*
|
||||
* 2) Implicit receiver to shorter code writing:
|
||||
* x.run {
|
||||
* println(inv())
|
||||
* return inv()
|
||||
* }
|
||||
*/
|
||||
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
|
||||
if (resolvedCall.candidateDescriptor.name !in SPECIAL_FUNCTION_NAMES && resolvedCall.call.typeArguments.isEmpty()) {
|
||||
val lambdasFromArgumentsReturnTypes =
|
||||
resolvedCall.candidateDescriptor.valueParameters.filter { it.type.isFunctionType }
|
||||
.map { it.returnType?.arguments?.last()?.type }.toSet()
|
||||
|
||||
val hasImplicitNothingExceptLambdaReturnTypes = resolvedCall.typeArguments.any { (unsubstitutedType, resultingType) ->
|
||||
resultingType.isNothing() && unsubstitutedType.defaultType !in lambdasFromArgumentsReturnTypes
|
||||
}
|
||||
|
||||
if (hasImplicitNothingExceptLambdaReturnTypes) {
|
||||
context.trace.report(Errors.IMPLICIT_NOTHING_AS_TYPE_PARAMETER.on(reportOn))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user