Add checks that coroutines are available at the given language level
This commit is contained in:
@@ -24,6 +24,7 @@ enum class LanguageFeature(val sinceVersion: LanguageVersion) {
|
||||
BoundCallableReferences(KOTLIN_1_1),
|
||||
LocalDelegatedProperties(KOTLIN_1_1),
|
||||
TopLevelSealedInheritance(KOTLIN_1_1),
|
||||
Coroutines(KOTLIN_1_1)
|
||||
;
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.impl.source.tree.LeafPsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.cfg.WhenMissingCase;
|
||||
import org.jetbrains.kotlin.config.LanguageFeature;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.lexer.KtKeywordToken;
|
||||
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken;
|
||||
@@ -54,6 +55,7 @@ public interface Errors {
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DiagnosticFactory1<PsiElement, String> UNSUPPORTED = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, LanguageFeature> UNSUPPORTED_FEATURE = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, Throwable> EXCEPTION_FROM_ANALYZER = DiagnosticFactory1.create(ERROR);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
+1
@@ -497,6 +497,7 @@ public class DefaultErrorMessages {
|
||||
MAP.put(UNSAFE_IMPLICIT_INVOKE_CALL, "Reference has a nullable type ''{0}'', use explicit ''?.invoke()'' to make a function-like call instead", RENDER_TYPE);
|
||||
MAP.put(AMBIGUOUS_LABEL, "Ambiguous label");
|
||||
MAP.put(UNSUPPORTED, "Unsupported [{0}]", STRING);
|
||||
MAP.put(UNSUPPORTED_FEATURE, "{0} are unsupported at this language level", TO_STRING);
|
||||
MAP.put(EXCEPTION_FROM_ANALYZER, "Internal Error occurred while analyzing this expression:\n{0}", THROWABLE);
|
||||
MAP.put(UNNECESSARY_SAFE_CALL, "Unnecessary safe call on a non-null receiver of type {0}", RENDER_TYPE);
|
||||
MAP.put(UNEXPECTED_SAFE_CALL, "Safe-call is not allowed here");
|
||||
|
||||
@@ -558,7 +558,7 @@ public class BodyResolver {
|
||||
|
||||
private void processModifiersOnInitializer(@NotNull KtModifierListOwner owner, @NotNull LexicalScope scope) {
|
||||
annotationChecker.check(owner, trace, null);
|
||||
ModifierCheckerCore.INSTANCE.check(owner, trace, null);
|
||||
ModifierCheckerCore.INSTANCE.check(owner, trace, null, languageFeatureSettings);
|
||||
KtModifierList modifierList = owner.getModifierList();
|
||||
if (modifierList == null) return;
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.google.common.collect.ImmutableSet
|
||||
import com.google.common.collect.Sets
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.config.LanguageFeatureSettings
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory0
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
@@ -70,10 +71,11 @@ internal class DeclarationsCheckerBuilder(
|
||||
private val descriptorResolver: DescriptorResolver,
|
||||
private val originalModifiersChecker: ModifiersChecker,
|
||||
private val annotationChecker: AnnotationChecker,
|
||||
private val identifierChecker: IdentifierChecker
|
||||
private val identifierChecker: IdentifierChecker,
|
||||
private val languageFeatureSettings: LanguageFeatureSettings
|
||||
) {
|
||||
fun withTrace(trace: BindingTrace) =
|
||||
DeclarationsChecker(descriptorResolver, originalModifiersChecker, annotationChecker, identifierChecker, trace)
|
||||
DeclarationsChecker(descriptorResolver, originalModifiersChecker, annotationChecker, identifierChecker, trace, languageFeatureSettings)
|
||||
}
|
||||
|
||||
class DeclarationsChecker(
|
||||
@@ -81,7 +83,8 @@ class DeclarationsChecker(
|
||||
modifiersChecker: ModifiersChecker,
|
||||
private val annotationChecker: AnnotationChecker,
|
||||
private val identifierChecker: IdentifierChecker,
|
||||
private val trace: BindingTrace
|
||||
private val trace: BindingTrace,
|
||||
private val languageFeatureSettings: LanguageFeatureSettings
|
||||
) {
|
||||
|
||||
private val modifiersChecker = modifiersChecker.withTrace(trace)
|
||||
@@ -190,7 +193,7 @@ class DeclarationsChecker(
|
||||
}
|
||||
}
|
||||
annotationChecker.check(packageDirective, trace, null)
|
||||
ModifierCheckerCore.check(packageDirective, trace, null)
|
||||
ModifierCheckerCore.check(packageDirective, trace, descriptor = null, languageFeatureSettings = languageFeatureSettings)
|
||||
}
|
||||
|
||||
private fun checkTypesInClassHeader(classOrObject: KtClassOrObject) {
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.google.common.collect.Sets;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.config.LanguageFeatureSettings;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory1;
|
||||
import org.jetbrains.kotlin.lexer.KtKeywordToken;
|
||||
@@ -157,9 +158,12 @@ public class ModifiersChecker {
|
||||
|
||||
@NotNull
|
||||
private final BindingTrace trace;
|
||||
@NotNull
|
||||
private final LanguageFeatureSettings languageFeatureSettings;
|
||||
|
||||
private ModifiersCheckingProcedure(@NotNull BindingTrace trace) {
|
||||
private ModifiersCheckingProcedure(@NotNull BindingTrace trace, LanguageFeatureSettings languageFeatureSettings) {
|
||||
this.trace = trace;
|
||||
this.languageFeatureSettings = languageFeatureSettings;
|
||||
}
|
||||
|
||||
public void checkParameterHasNoValOrVar(
|
||||
@@ -182,7 +186,7 @@ public class ModifiersChecker {
|
||||
AnnotationUseSiteTargetChecker.INSTANCE.check(modifierListOwner, descriptor, trace);
|
||||
runDeclarationCheckers(modifierListOwner, descriptor);
|
||||
annotationChecker.check(modifierListOwner, trace, descriptor);
|
||||
ModifierCheckerCore.INSTANCE.check(modifierListOwner, trace, descriptor);
|
||||
ModifierCheckerCore.INSTANCE.check(modifierListOwner, trace, descriptor, languageFeatureSettings);
|
||||
}
|
||||
|
||||
public void checkModifiersForLocalDeclaration(
|
||||
@@ -194,10 +198,10 @@ public class ModifiersChecker {
|
||||
|
||||
public void checkModifiersForDestructuringDeclaration(@NotNull KtDestructuringDeclaration multiDeclaration) {
|
||||
annotationChecker.check(multiDeclaration, trace, null);
|
||||
ModifierCheckerCore.INSTANCE.check(multiDeclaration, trace, null);
|
||||
ModifierCheckerCore.INSTANCE.check(multiDeclaration, trace, null, languageFeatureSettings);
|
||||
for (KtDestructuringDeclarationEntry multiEntry: multiDeclaration.getEntries()) {
|
||||
annotationChecker.check(multiEntry, trace, null);
|
||||
ModifierCheckerCore.INSTANCE.check(multiEntry, trace, null);
|
||||
ModifierCheckerCore.INSTANCE.check(multiEntry, trace, null, languageFeatureSettings);
|
||||
UnderscoreChecker.INSTANCE.checkNamed(multiEntry, trace);
|
||||
}
|
||||
}
|
||||
@@ -235,13 +239,14 @@ public class ModifiersChecker {
|
||||
for (DeclarationChecker checker : declarationCheckers) {
|
||||
checker.check(declaration, descriptor, trace, trace.getBindingContext());
|
||||
}
|
||||
OperatorModifierChecker.INSTANCE.check(declaration, descriptor, trace, languageFeatureSettings);
|
||||
}
|
||||
|
||||
public void checkTypeParametersModifiers(@NotNull KtModifierListOwner modifierListOwner) {
|
||||
if (!(modifierListOwner instanceof KtTypeParameterListOwner)) return;
|
||||
List<KtTypeParameter> typeParameters = ((KtTypeParameterListOwner) modifierListOwner).getTypeParameters();
|
||||
for (KtTypeParameter typeParameter : typeParameters) {
|
||||
ModifierCheckerCore.INSTANCE.check(typeParameter, trace, null);
|
||||
ModifierCheckerCore.INSTANCE.check(typeParameter, trace, null, languageFeatureSettings);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -252,13 +257,21 @@ public class ModifiersChecker {
|
||||
@NotNull
|
||||
private final Iterable<DeclarationChecker> declarationCheckers;
|
||||
|
||||
public ModifiersChecker(@NotNull AnnotationChecker annotationChecker, @NotNull Iterable<DeclarationChecker> declarationCheckers) {
|
||||
@NotNull
|
||||
private final LanguageFeatureSettings languageFeatureSettings;
|
||||
|
||||
public ModifiersChecker(
|
||||
@NotNull AnnotationChecker annotationChecker,
|
||||
@NotNull Iterable<DeclarationChecker> declarationCheckers,
|
||||
@NotNull LanguageFeatureSettings languageFeatureSettings
|
||||
) {
|
||||
this.annotationChecker = annotationChecker;
|
||||
this.declarationCheckers = declarationCheckers;
|
||||
this.languageFeatureSettings = languageFeatureSettings;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ModifiersCheckingProcedure withTrace(@NotNull BindingTrace trace) {
|
||||
return new ModifiersCheckingProcedure(trace);
|
||||
return new ModifiersCheckingProcedure(trace, languageFeatureSettings);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ package org.jetbrains.kotlin.resolve
|
||||
import com.intellij.lang.ASTNode
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.tree.TokenSet
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageFeatureSettings
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
@@ -90,6 +92,11 @@ object ModifierCheckerCore {
|
||||
INFIX_KEYWORD to EnumSet.of(FUNCTION)
|
||||
)
|
||||
|
||||
val featureDependencies = mapOf(
|
||||
COROUTINE_KEYWORD to LanguageFeature.Coroutines,
|
||||
SUSPEND_KEYWORD to LanguageFeature.Coroutines
|
||||
)
|
||||
|
||||
// NOTE: deprecated targets must be possible!
|
||||
private val deprecatedTargetMap = mapOf<KtModifierKeywordToken, Set<KotlinTarget>>()
|
||||
|
||||
@@ -242,6 +249,23 @@ object ModifierCheckerCore {
|
||||
return true
|
||||
}
|
||||
|
||||
private fun checkLanguageLevelSupport(
|
||||
trace: BindingTrace,
|
||||
node: ASTNode,
|
||||
languageFeatureSettings: LanguageFeatureSettings
|
||||
): Boolean {
|
||||
val modifier = node.elementType as KtModifierKeywordToken
|
||||
val dependency = featureDependencies[modifier] ?: return true
|
||||
|
||||
if (!languageFeatureSettings.supportsFeature(dependency)) {
|
||||
trace.report(Errors.UNSUPPORTED_FEATURE.on(node.psi, dependency))
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
// Should return false if error is reported, true otherwise
|
||||
private fun checkParent(trace: BindingTrace, node: ASTNode, parentDescriptor: DeclarationDescriptor?): Boolean {
|
||||
val modifier = node.elementType as KtModifierKeywordToken
|
||||
@@ -264,7 +288,13 @@ object ModifierCheckerCore {
|
||||
|
||||
private val MODIFIER_KEYWORD_SET = TokenSet.orSet(KtTokens.SOFT_KEYWORDS, TokenSet.create(KtTokens.IN_KEYWORD))
|
||||
|
||||
private fun checkModifierList(list: KtModifierList, trace: BindingTrace, parentDescriptor: DeclarationDescriptor?, actualTargets: List<KotlinTarget>) {
|
||||
private fun checkModifierList(
|
||||
list: KtModifierList,
|
||||
trace: BindingTrace,
|
||||
parentDescriptor: DeclarationDescriptor?,
|
||||
actualTargets: List<KotlinTarget>,
|
||||
languageFeatureSettings: LanguageFeatureSettings
|
||||
) {
|
||||
// It's a list of all nodes with error already reported
|
||||
// General strategy: report no more than one error but any number of warnings
|
||||
val incorrectNodes = hashSetOf<ASTNode>()
|
||||
@@ -283,21 +313,29 @@ object ModifierCheckerCore {
|
||||
else if (!checkParent(trace, second, parentDescriptor)) {
|
||||
incorrectNodes += second
|
||||
}
|
||||
else if (!checkLanguageLevelSupport(trace, second, languageFeatureSettings)) {
|
||||
incorrectNodes += second
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun check(listOwner: KtModifierListOwner, trace: BindingTrace, descriptor: DeclarationDescriptor?) {
|
||||
fun check(
|
||||
listOwner: KtModifierListOwner,
|
||||
trace: BindingTrace,
|
||||
descriptor: DeclarationDescriptor?,
|
||||
languageFeatureSettings: LanguageFeatureSettings
|
||||
) {
|
||||
if (listOwner is KtDeclarationWithBody) {
|
||||
// JetFunction or JetPropertyAccessor
|
||||
for (parameter in listOwner.valueParameters) {
|
||||
if (!parameter.hasValOrVar()) {
|
||||
check(parameter, trace, null)
|
||||
check(parameter, trace, null, languageFeatureSettings)
|
||||
}
|
||||
}
|
||||
}
|
||||
val actualTargets = AnnotationChecker.getDeclarationSiteActualTargetList(listOwner, descriptor as? ClassDescriptor, trace)
|
||||
val list = listOwner.modifierList ?: return
|
||||
checkModifierList(list, trace, descriptor?.containingDeclaration, actualTargets)
|
||||
checkModifierList(list, trace, descriptor?.containingDeclaration, actualTargets, languageFeatureSettings)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,8 @@
|
||||
|
||||
package org.jetbrains.kotlin.resolve
|
||||
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageFeatureSettings
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
|
||||
@@ -40,20 +42,28 @@ import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.util.CheckResult
|
||||
import org.jetbrains.kotlin.util.OperatorChecks
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
|
||||
class OperatorModifierChecker : DeclarationChecker {
|
||||
override fun check(
|
||||
object OperatorModifierChecker {
|
||||
fun check(
|
||||
declaration: KtDeclaration,
|
||||
descriptor: DeclarationDescriptor,
|
||||
diagnosticHolder: DiagnosticSink,
|
||||
bindingContext: BindingContext
|
||||
languageFeatureSettings: LanguageFeatureSettings
|
||||
) {
|
||||
val functionDescriptor = descriptor as? FunctionDescriptor ?: return
|
||||
if (!functionDescriptor.isOperator) return
|
||||
val modifier = declaration.modifierList?.getModifier(KtTokens.OPERATOR_KEYWORD) ?: return
|
||||
|
||||
val checkResult = OperatorChecks.checkOperator(functionDescriptor)
|
||||
if (checkResult.isSuccess) return
|
||||
if (checkResult.isSuccess) {
|
||||
if (functionDescriptor.name == OperatorNameConventions.COROUTINE_HANDLE_RESULT
|
||||
&& !languageFeatureSettings.supportsFeature(LanguageFeature.Coroutines)
|
||||
) {
|
||||
diagnosticHolder.report(Errors.UNSUPPORTED_FEATURE.on(modifier, LanguageFeature.Coroutines))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
val errorDescription = if (checkResult is CheckResult.IllegalSignature)
|
||||
checkResult.error
|
||||
@@ -62,4 +72,4 @@ class OperatorModifierChecker : DeclarationChecker {
|
||||
|
||||
diagnosticHolder.report(Errors.INAPPLICABLE_OPERATOR_MODIFIER.on(modifier, errorDescription))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +62,6 @@ private val DEFAULT_DECLARATION_CHECKERS = listOf(
|
||||
ConstModifierChecker,
|
||||
UnderscoreChecker,
|
||||
InlineParameterChecker,
|
||||
OperatorModifierChecker(),
|
||||
InfixModifierChecker(),
|
||||
SuspendModifierChecker,
|
||||
CoroutineModifierChecker)
|
||||
|
||||
@@ -673,7 +673,7 @@ class TypeResolver(
|
||||
): List<TypeProjection> {
|
||||
return argumentElements.mapIndexed { i, argumentElement ->
|
||||
val projectionKind = argumentElement.projectionKind
|
||||
ModifierCheckerCore.check(argumentElement, c.trace, null)
|
||||
ModifierCheckerCore.check(argumentElement, c.trace, null, languageFeatureSettings)
|
||||
if (projectionKind == KtProjectionKind.STAR) {
|
||||
val parameters = constructor.parameters
|
||||
if (parameters.size > i) {
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.jetbrains.kotlin.resolve.calls
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.config.LanguageFeatureSettings
|
||||
import org.jetbrains.kotlin.coroutines.controllerTypeIfCoroutine
|
||||
import org.jetbrains.kotlin.coroutines.resolveCoroutineHandleResultCallIfNeeded
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
@@ -27,6 +28,7 @@ import org.jetbrains.kotlin.resolve.calls.callResolverUtil.ResolveArgumentsMode.
|
||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.getEffectiveExpectedType
|
||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isInvokeCallOnVariable
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.checkCoroutineBuilderCall
|
||||
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
|
||||
import org.jetbrains.kotlin.resolve.calls.context.CallCandidateResolutionContext
|
||||
import org.jetbrains.kotlin.resolve.calls.context.CallPosition
|
||||
@@ -58,7 +60,8 @@ class CallCompleter(
|
||||
private val dataFlowAnalyzer: DataFlowAnalyzer,
|
||||
private val callCheckers: Iterable<CallChecker>,
|
||||
private val builtIns: KotlinBuiltIns,
|
||||
private val fakeCallResolver: FakeCallResolver
|
||||
private val fakeCallResolver: FakeCallResolver,
|
||||
private val languageFeatureSettings: LanguageFeatureSettings
|
||||
) {
|
||||
fun <D : CallableDescriptor> completeCall(
|
||||
context: BasicCallResolutionContext,
|
||||
@@ -92,6 +95,7 @@ class CallCompleter(
|
||||
symbolUsageValidator.validateCall(resolvedCall, resolvedCall.resultingDescriptor, context.trace, element!!)
|
||||
|
||||
resolveHandleResultCallForCoroutineLambdaExpressions(context, resolvedCall)
|
||||
checkCoroutineBuilderCall(resolvedCall, context, languageFeatureSettings)
|
||||
}
|
||||
|
||||
if (results.isSingleResult && results.resultingCall.status.isSuccess) {
|
||||
|
||||
@@ -22,6 +22,7 @@ import kotlin.jvm.functions.Function0;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||
import org.jetbrains.kotlin.config.LanguageFeatureSettings;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
@@ -70,13 +71,16 @@ public class CallResolver {
|
||||
private CallCompleter callCompleter;
|
||||
private NewResolutionOldInference newCallResolver;
|
||||
private final KotlinBuiltIns builtIns;
|
||||
private final LanguageFeatureSettings languageFeatureSettings;
|
||||
|
||||
private static final PerformanceCounter callResolvePerfCounter = PerformanceCounter.Companion.create("Call resolve", ExpressionTypingVisitorDispatcher.typeInfoPerfCounter);
|
||||
|
||||
public CallResolver(
|
||||
@NotNull KotlinBuiltIns builtIns
|
||||
@NotNull KotlinBuiltIns builtIns,
|
||||
@NotNull LanguageFeatureSettings languageFeatureSettings
|
||||
) {
|
||||
this.builtIns = builtIns;
|
||||
this.languageFeatureSettings = languageFeatureSettings;
|
||||
}
|
||||
|
||||
// component dependency cycle
|
||||
@@ -583,7 +587,7 @@ public class CallResolver {
|
||||
for (KtTypeProjection projection : typeArguments) {
|
||||
if (projection.getProjectionKind() != KtProjectionKind.NONE) {
|
||||
context.trace.report(PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT.on(projection));
|
||||
ModifierCheckerCore.INSTANCE.check(projection, context.trace, null);
|
||||
ModifierCheckerCore.INSTANCE.check(projection, context.trace, null, languageFeatureSettings);
|
||||
}
|
||||
KotlinType type = argumentTypeResolver.resolveTypeRefWithDefault(
|
||||
projection.getTypeReference(), context.scope, context.trace,
|
||||
|
||||
+18
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.jetbrains.kotlin.resolve.calls.checkers
|
||||
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageFeatureSettings
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
@@ -37,3 +39,19 @@ object CoroutineSuspendCallChecker : CallChecker {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// It can't be another CallChecker implementation because of 3rd parameter
|
||||
fun checkCoroutineBuilderCall(
|
||||
resolvedCall: ResolvedCall<*>,
|
||||
context: BasicCallResolutionContext,
|
||||
languageFeatureSettings: LanguageFeatureSettings
|
||||
) {
|
||||
val descriptor = resolvedCall.candidateDescriptor as? FunctionDescriptor ?: return
|
||||
if (descriptor.valueParameters.any { it.isCoroutine }
|
||||
&& !languageFeatureSettings.supportsFeature(LanguageFeature.Coroutines)) {
|
||||
context.trace.report(
|
||||
Errors.UNSUPPORTED_FEATURE.on(
|
||||
resolvedCall.call.calleeExpression ?: resolvedCall.call.callElement, LanguageFeature.Coroutines))
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -489,7 +489,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
|
||||
components.identifierChecker.checkDeclaration(catchParameter, context.trace);
|
||||
ModifiersChecker.ModifiersCheckingProcedure modifiersChecking = components.modifiersChecker.withTrace(context.trace);
|
||||
modifiersChecking.checkParameterHasNoValOrVar(catchParameter, VAL_OR_VAR_ON_CATCH_PARAMETER);
|
||||
ModifierCheckerCore.INSTANCE.check(catchParameter, context.trace, null);
|
||||
ModifierCheckerCore.INSTANCE.check(catchParameter, context.trace, null, components.languageFeatureSettings);
|
||||
|
||||
VariableDescriptor variableDescriptor = components.descriptorResolver.resolveLocalVariableDescriptor(
|
||||
context.scope, catchParameter, context.trace);
|
||||
|
||||
+7
-6
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.types.expressions;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||
import org.jetbrains.kotlin.builtins.ReflectionTypes;
|
||||
import org.jetbrains.kotlin.config.LanguageFeatureSettings;
|
||||
import org.jetbrains.kotlin.context.GlobalContext;
|
||||
import org.jetbrains.kotlin.incremental.components.LookupTracker;
|
||||
import org.jetbrains.kotlin.platform.PlatformToKotlinClassMap;
|
||||
@@ -61,8 +62,8 @@ public class ExpressionTypingComponents {
|
||||
/*package*/ DeclarationsCheckerBuilder declarationsCheckerBuilder;
|
||||
/*package*/ LocalVariableResolver localVariableResolver;
|
||||
/*package*/ LookupTracker lookupTracker;
|
||||
/*package*/ DelegatedPropertyResolver delegatedPropertyResolver;
|
||||
/*package*/ OverloadChecker overloadChecker;
|
||||
/*package*/ LanguageFeatureSettings languageFeatureSettings;
|
||||
|
||||
@Inject
|
||||
public void setGlobalContext(@NotNull GlobalContext globalContext) {
|
||||
@@ -209,13 +210,13 @@ public class ExpressionTypingComponents {
|
||||
this.lookupTracker = lookupTracker;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setDelegatedPropertyResolver(DelegatedPropertyResolver delegatedPropertyResolver) {
|
||||
this.delegatedPropertyResolver = delegatedPropertyResolver;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setOverloadChecker(OverloadChecker overloadChecker) {
|
||||
this.overloadChecker = overloadChecker;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setLanguageFeatureSettings(@NotNull LanguageFeatureSettings languageFeatureSettings) {
|
||||
this.languageFeatureSettings = languageFeatureSettings;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
// !LANGUAGE: -Coroutines
|
||||
|
||||
class Controller {
|
||||
<!UNSUPPORTED_FEATURE!>suspend<!> fun suspendHere(x: Continuation<String>) {
|
||||
x.resume("OK")
|
||||
}
|
||||
|
||||
<!UNSUPPORTED_FEATURE!>operator<!> fun handleResult(x: String, y: Continuation<Nothing>) {}
|
||||
}
|
||||
|
||||
fun builder(<!UNSUPPORTED_FEATURE!>coroutine<!> c: Controller.() -> Continuation<Unit>) {
|
||||
c(Controller()).resume(Unit)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
var result = ""
|
||||
|
||||
<!UNSUPPORTED_FEATURE!>builder<!> {
|
||||
suspendHere()
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package
|
||||
|
||||
public fun box(): kotlin.String
|
||||
public fun builder(/*0*/ coroutine c: Controller.() -> kotlin.coroutines.Continuation<kotlin.Unit>): kotlin.Unit
|
||||
|
||||
public final class Controller {
|
||||
public constructor Controller()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public final operator fun handleResult(/*0*/ x: kotlin.String, /*1*/ y: kotlin.coroutines.Continuation<kotlin.Nothing>): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public final suspend fun suspendHere(/*0*/ x: kotlin.coroutines.Continuation<kotlin.String>): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
@@ -3915,6 +3915,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("unsupported.kt")
|
||||
public void testUnsupported() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/coroutines/unsupported.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("wrongHandleResult.kt")
|
||||
public void testWrongHandleResult() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/coroutines/wrongHandleResult.kt");
|
||||
|
||||
Reference in New Issue
Block a user