Skip to content

Commit

Permalink
Disable some features when LV=1.1 API=1.0.
Browse files Browse the repository at this point in the history
Feature list:
 - bound callable references
 - local delegated properties
 - coroutines.

#KT-16017 Fixed
  • Loading branch information
erokhins committed Feb 13, 2017
1 parent be0211c commit b6fa10c
Show file tree
Hide file tree
Showing 43 changed files with 232 additions and 75 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.jetbrains.kotlin.cfg.WhenMissingCase;
import org.jetbrains.kotlin.config.LanguageFeature;
import org.jetbrains.kotlin.config.LanguageVersion;
import org.jetbrains.kotlin.config.LanguageVersionSettings;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.lexer.KtKeywordToken;
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken;
Expand Down Expand Up @@ -63,11 +64,11 @@ public interface Errors {
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

DiagnosticFactory1<PsiElement, String> UNSUPPORTED = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<PsiElement, LanguageFeature> UNSUPPORTED_FEATURE = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<PsiElement, Pair<LanguageFeature, LanguageVersionSettings>> UNSUPPORTED_FEATURE = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<PsiElement, Throwable> EXCEPTION_FROM_ANALYZER = DiagnosticFactory1.create(ERROR);

DiagnosticFactory1<PsiElement, LanguageFeature> EXPERIMENTAL_FEATURE_WARNING = DiagnosticFactory1.create(WARNING);
DiagnosticFactory1<PsiElement, LanguageFeature> EXPERIMENTAL_FEATURE_ERROR = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<PsiElement, Pair<LanguageFeature, LanguageVersionSettings>> EXPERIMENTAL_FEATURE_WARNING = DiagnosticFactory1.create(WARNING);
DiagnosticFactory1<PsiElement, Pair<LanguageFeature, LanguageVersionSettings>> EXPERIMENTAL_FEATURE_ERROR = DiagnosticFactory1.create(ERROR);

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Expand Down Expand Up @@ -453,7 +454,6 @@ public interface Errors {
DiagnosticFactory0<KtPropertyDelegate> ABSTRACT_DELEGATED_PROPERTY = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtPropertyAccessor> ACCESSOR_FOR_DELEGATED_PROPERTY = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtPropertyDelegate> DELEGATED_PROPERTY_IN_INTERFACE = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtPropertyDelegate> LOCAL_VARIABLE_WITH_DELEGATE = DiagnosticFactory0.create(ERROR);

DiagnosticFactory0<KtProperty> PROPERTY_WITH_NO_TYPE_NO_INITIALIZER = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,6 @@ public String render(@NotNull BadNamedArgumentsTarget target, @NotNull Rendering
MAP.put(ABSTRACT_DELEGATED_PROPERTY, "Delegated property cannot be abstract");
MAP.put(ACCESSOR_FOR_DELEGATED_PROPERTY, "Delegated property cannot have accessors with non-default implementations");
MAP.put(DELEGATED_PROPERTY_IN_INTERFACE, "Delegated properties are not allowed in interfaces");
MAP.put(LOCAL_VARIABLE_WITH_DELEGATE, "Local variables are not allowed to have delegates");

MAP.put(INAPPLICABLE_LATEINIT_MODIFIER, "''lateinit'' modifier {0}", STRING);

Expand Down Expand Up @@ -600,30 +599,11 @@ public String render(@NotNull KtExpression expression, @NotNull RenderingContext
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, "The feature is {0}", new DiagnosticParameterRenderer<LanguageFeature>() {
@NotNull
@Override
public String render(LanguageFeature feature, @NotNull RenderingContext renderingContext) {
LanguageVersion version = feature.getSinceVersion();
return version != null
? "only available since Kotlin " + version.getVersionString() + ": " + feature.getPresentableText()
: "experimental and should be turned on explicitly via a command line option or in IDE settings: " + feature.getPresentableText();
}
});
MAP.put(EXPERIMENTAL_FEATURE_WARNING, "The feature is experimental: {0}", new DiagnosticParameterRenderer<LanguageFeature>() {
@NotNull
@Override
public String render(LanguageFeature feature, @NotNull RenderingContext renderingContext) {
return feature.getPresentableText();
}
});
MAP.put(EXPERIMENTAL_FEATURE_ERROR, "The experimental feature is disabled: {0}", new DiagnosticParameterRenderer<LanguageFeature>() {
@NotNull
@Override
public String render(LanguageFeature feature, @NotNull RenderingContext renderingContext) {
return feature.getPresentableText();
}
});

MAP.put(UNSUPPORTED_FEATURE, "{0}", new LanguageFeatureMessageRenderer(LanguageFeatureMessageRenderer.Type.UNSUPPORTED));
MAP.put(EXPERIMENTAL_FEATURE_WARNING, "{0}", new LanguageFeatureMessageRenderer(LanguageFeatureMessageRenderer.Type.WARNING));
MAP.put(EXPERIMENTAL_FEATURE_ERROR, "{0}", new LanguageFeatureMessageRenderer(LanguageFeatureMessageRenderer.Type.ERROR));

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");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.jetbrains.kotlin.diagnostics.rendering

import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings

class LanguageFeatureMessageRenderer @JvmOverloads constructor(
private val type: Type,
private val useHtml: Boolean = false
): DiagnosticParameterRenderer<Pair<LanguageFeature, LanguageVersionSettings>> {

enum class Type {
UNSUPPORTED,
WARNING,
ERROR
}

override fun render(obj: Pair<LanguageFeature, LanguageVersionSettings>, renderingContext: RenderingContext): String {
val (feature, settings) = obj
val since = feature.sinceVersion

val sb = StringBuilder()
sb.append("The feature \"").append(feature.presentableName).append("\" is ")

when (type) {
Type.UNSUPPORTED ->
when {
since == null ->
sb.append("experimental and should be enabled explicitly")
since > settings.languageVersion ->
sb.append("only available since language version ").append(since.versionString)
feature.sinceApiVersion > settings.apiVersion ->
sb.append("only available since API version ").append(feature.sinceApiVersion.versionString)
else ->
sb.append("disabled")
}

Type.WARNING -> sb.append("experimental")
Type.ERROR -> sb.append("experimental and disabled")
}

val hintUrl = feature.hintUrl
if (hintUrl != null) {
if (useHtml) {
sb.append(" (").append("see more <a href=\"").append(hintUrl).append("\">here</a>)")
}
else {
sb.append(" (see: ").append(hintUrl).append(")")
}
}

return sb.toString()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -711,7 +711,7 @@ class DeclarationsChecker(
}
}
else if (property.typeReference == null && !languageVersionSettings.supportsFeature(LanguageFeature.ShortSyntaxForPropertyGetters)) {
trace.report(Errors.UNSUPPORTED_FEATURE.on(property, LanguageFeature.ShortSyntaxForPropertyGetters))
trace.report(Errors.UNSUPPORTED_FEATURE.on(property, LanguageFeature.ShortSyntaxForPropertyGetters to languageVersionSettings))
}
else if (noExplicitTypeOrGetterType(property)) {
trace.report(PROPERTY_WITH_NO_TYPE_NO_INITIALIZER.on(property))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import kotlin.Pair;
import kotlin.TuplesKt;
import kotlin.collections.CollectionsKt;
import kotlin.collections.SetsKt;
import kotlin.jvm.functions.Function0;
Expand Down Expand Up @@ -324,7 +325,8 @@ public ValueParameterDescriptorImpl resolveValueParameterDescriptor(
Function0<List<VariableDescriptor>> destructuringVariables;
if (destructuringDeclaration != null) {
if (!languageVersionSettings.supportsFeature(LanguageFeature.DestructuringLambdaParameters)) {
trace.report(Errors.UNSUPPORTED_FEATURE.on(valueParameter, LanguageFeature.DestructuringLambdaParameters));
trace.report(Errors.UNSUPPORTED_FEATURE.on(valueParameter,
TuplesKt.to(LanguageFeature.DestructuringLambdaParameters, languageVersionSettings)));
}

destructuringVariables = new Function0<List<VariableDescriptor>>() {
Expand Down Expand Up @@ -742,7 +744,8 @@ scope, containingDeclaration, false, new TraceBasedLocalRedeclarationChecker(tra
else if (!languageVersionSettings.supportsFeature(LanguageFeature.TypeAliases)) {
typeResolver.resolveAbbreviatedType(scopeWithTypeParameters, typeReference, trace);
PsiElement typeAliasKeyword = typeAlias.getTypeAliasKeyword();
trace.report(UNSUPPORTED_FEATURE.on(typeAliasKeyword != null ? typeAliasKeyword : typeAlias, LanguageFeature.TypeAliases));
trace.report(UNSUPPORTED_FEATURE.on(typeAliasKeyword != null ? typeAliasKeyword : typeAlias,
TuplesKt.to(LanguageFeature.TypeAliases, languageVersionSettings)));
typeAliasDescriptor.initialize(
typeParameterDescriptors,
ErrorUtils.createErrorType(name.asString()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ class LocalVariableResolver(
val delegateExpression = property.delegateExpression
if (delegateExpression != null) {
if (!languageVersionSettings.supportsFeature(LanguageFeature.LocalDelegatedProperties)) {
context.trace.report(LOCAL_VARIABLE_WITH_DELEGATE.on(property.delegate!!))
context.trace.report(UNSUPPORTED_FEATURE.on(property.delegate!!, LanguageFeature.LocalDelegatedProperties to languageVersionSettings))
}

if (propertyDescriptor is VariableDescriptorWithAccessors) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -277,24 +277,25 @@ object ModifierCheckerCore {
val errorOnDependencyFeature = errorOnFeature[dependency]?.let { languageVersionSettings.supportsFeature(it) } ?: false
val supportsFeature = languageVersionSettings.supportsFeature(dependency)

val diagnosticData = dependency to languageVersionSettings
if (!supportsFeature || errorOnDependencyFeature) {
val restrictedTargets = featureDependenciesTargets[dependency]
if (restrictedTargets != null && actualTargets.intersect(restrictedTargets).isEmpty()) {
return true
}

if (!supportsFeature) {
trace.report(Errors.UNSUPPORTED_FEATURE.on(node.psi, dependency))
trace.report(Errors.UNSUPPORTED_FEATURE.on(node.psi, diagnosticData))
}
else if (errorOnDependencyFeature) {
trace.report(Errors.EXPERIMENTAL_FEATURE_ERROR.on(node.psi, dependency))
trace.report(Errors.EXPERIMENTAL_FEATURE_ERROR.on(node.psi, diagnosticData))
}
return false
}

val pairedWarningFeature = warningOnFeature[dependency]
if (pairedWarningFeature != null && languageVersionSettings.supportsFeature(pairedWarningFeature)) {
trace.report(Errors.EXPERIMENTAL_FEATURE_WARNING.on(node.psi, dependency))
trace.report(Errors.EXPERIMENTAL_FEATURE_WARNING.on(node.psi, diagnosticData))
}

return true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ object OperatorModifierChecker {

private fun checkSupportsFeature(feature: LanguageFeature, languageVersionSettings: LanguageVersionSettings, diagnosticHolder: DiagnosticSink, modifier: PsiElement) {
if (!languageVersionSettings.supportsFeature(feature)) {
diagnosticHolder.report(Errors.UNSUPPORTED_FEATURE.on(modifier, feature))
diagnosticHolder.report(Errors.UNSUPPORTED_FEATURE.on(modifier, feature to languageVersionSettings))
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,7 @@ class TypeResolver(
return createErrorTypeForTypeConstructor(c, projectionFromAllQualifierParts, typeConstructor)
}
if (!languageVersionSettings.supportsFeature(LanguageFeature.TypeAliases)) {
c.trace.report(UNSUPPORTED_FEATURE.on(type, LanguageFeature.TypeAliases))
c.trace.report(UNSUPPORTED_FEATURE.on(type, LanguageFeature.TypeAliases to languageVersionSettings))
return createErrorTypeForTypeConstructor(c, projectionFromAllQualifierParts, typeConstructor)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ class CallableReferenceCompatibilityChecker : CallChecker {
val callableReferenceResolvedCall = argumentExpression.callableReference.getResolvedCall(context.trace.bindingContext) ?: continue@inner
if (callableReferenceResolvedCall.call.isCallableReference() &&
callableReferenceResolvedCall.candidateDescriptor.typeParameters.isNotEmpty()) {
context.trace.report(Errors.UNSUPPORTED_FEATURE.on(argumentExpression, typeInferenceForCallableReferencesFeature))
context.trace.report(Errors.UNSUPPORTED_FEATURE.on(argumentExpression,
typeInferenceForCallableReferencesFeature to context.languageVersionSettings))
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,14 +89,15 @@ object BuilderFunctionsCallChecker : CallChecker {
}

fun checkCoroutinesFeature(languageVersionSettings: LanguageVersionSettings, diagnosticHolder: DiagnosticSink, reportOn: PsiElement) {
val diagnosticData = LanguageFeature.Coroutines to languageVersionSettings
if (!languageVersionSettings.supportsFeature(LanguageFeature.Coroutines)) {
diagnosticHolder.report(Errors.UNSUPPORTED_FEATURE.on(reportOn, LanguageFeature.Coroutines))
diagnosticHolder.report(Errors.UNSUPPORTED_FEATURE.on(reportOn, diagnosticData))
}
else if (languageVersionSettings.supportsFeature(LanguageFeature.ErrorOnCoroutines)) {
diagnosticHolder.report(Errors.EXPERIMENTAL_FEATURE_ERROR.on(reportOn, LanguageFeature.Coroutines))
diagnosticHolder.report(Errors.EXPERIMENTAL_FEATURE_ERROR.on(reportOn, diagnosticData))
}
else if (languageVersionSettings.supportsFeature(LanguageFeature.WarnOnCoroutines)) {
diagnosticHolder.report(Errors.EXPERIMENTAL_FEATURE_WARNING.on(reportOn, LanguageFeature.Coroutines))
diagnosticHolder.report(Errors.EXPERIMENTAL_FEATURE_WARNING.on(reportOn, diagnosticData))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ object UnderscoreChecker : DeclarationChecker {
diagnosticHolder.report(Errors.UNDERSCORE_IS_RESERVED.on(identifier))
}
else if (isValidSingleUnderscore && !languageVersionSettings.supportsFeature(LanguageFeature.SingleUnderscoreForParameterName)) {
diagnosticHolder.report(Errors.UNSUPPORTED_FEATURE.on(identifier, LanguageFeature.SingleUnderscoreForParameterName))
diagnosticHolder.report(Errors.UNSUPPORTED_FEATURE.on(identifier, LanguageFeature.SingleUnderscoreForParameterName to languageVersionSettings))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import com.intellij.psi.util.PsiTreeUtil;
import kotlin.TuplesKt;
import kotlin.jvm.functions.Function0;
import kotlin.jvm.functions.Function1;
import org.jetbrains.annotations.NotNull;
Expand Down Expand Up @@ -238,7 +239,8 @@ private void checkUnderscores(
if (!text.contains("_")) return;

if (!components.languageVersionSettings.supportsFeature(LanguageFeature.UnderscoresInNumericLiterals)) {
context.trace.report(Errors.UNSUPPORTED_FEATURE.on(expression, LanguageFeature.UnderscoresInNumericLiterals));
context.trace.report(Errors.UNSUPPORTED_FEATURE.on(expression,
TuplesKt.to(LanguageFeature.UnderscoresInNumericLiterals, components.languageVersionSettings)));
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ class DoubleColonExpressionResolver(

private fun reportUnsupportedIfNeeded(expression: KtDoubleColonExpression, c: ExpressionTypingContext) {
if (!languageVersionSettings.supportsFeature(LanguageFeature.BoundCallableReferences)) {
c.trace.report(UNSUPPORTED_FEATURE.on(expression.receiverExpression!!, LanguageFeature.BoundCallableReferences))
c.trace.report(UNSUPPORTED_FEATURE.on(expression.receiverExpression!!, LanguageFeature.BoundCallableReferences to languageVersionSettings))
}
}

Expand Down
5 changes: 4 additions & 1 deletion compiler/testData/cli/jvm/apiVersion.out
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
compiler/testData/cli/jvm/apiVersion.kt:2:5: error: the feature "bound callable references" is only available since API version 1.1
""::class.isInstance(42)
^
compiler/testData/cli/jvm/apiVersion.kt:2:15: error: unresolved reference: isInstance
""::class.isInstance(42)
^
COMPILATION_ERROR
COMPILATION_ERROR
7 changes: 7 additions & 0 deletions compiler/testData/cli/jvm/apiVersion1.0.args
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
$TESTDATA_DIR$/apiVersion1.0.kt
-d
$TEMP_DIR$
-language-version
1.1
-api-version
1.0
16 changes: 16 additions & 0 deletions compiler/testData/cli/jvm/apiVersion1.0.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
typealias Foo = Int

sealed class A
data class B(val foo: Int): A()

inline val f get() = ""

suspend fun test() {
""::class
""::toString

Foo::class
Foo::toString

val b by lazy { "" }
}
13 changes: 13 additions & 0 deletions compiler/testData/cli/jvm/apiVersion1.0.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
compiler/testData/cli/jvm/apiVersion1.0.kt:8:1: error: the feature "coroutines" is only available since API version 1.1 (see: https://kotlinlang.org/docs/diagnostics/experimental-coroutines)
suspend fun test() {
^
compiler/testData/cli/jvm/apiVersion1.0.kt:9:5: error: the feature "bound callable references" is only available since API version 1.1
""::class
^
compiler/testData/cli/jvm/apiVersion1.0.kt:10:5: error: the feature "bound callable references" is only available since API version 1.1
""::toString
^
compiler/testData/cli/jvm/apiVersion1.0.kt:15:11: error: the feature "local delegated properties" is only available since API version 1.1
val b by lazy { "" }
^
COMPILATION_ERROR
5 changes: 4 additions & 1 deletion compiler/testData/cli/jvm/apiVersionLessThanLanguage.out
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
compiler/testData/cli/jvm/apiVersion.kt:2:5: error: the feature "bound callable references" is only available since API version 1.1
""::class.isInstance(42)
^
compiler/testData/cli/jvm/apiVersion.kt:2:15: error: unresolved reference: isInstance
""::class.isInstance(42)
^
COMPILATION_ERROR
COMPILATION_ERROR
1 change: 1 addition & 0 deletions compiler/testData/cli/jvm/coroutines.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
suspend fun simple() = 5
4 changes: 4 additions & 0 deletions compiler/testData/cli/jvm/coroutinesEnable.args
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
$TESTDATA_DIR$/coroutines.kt
-d
$TEMP_DIR$
-Xcoroutines=enable
1 change: 1 addition & 0 deletions compiler/testData/cli/jvm/coroutinesEnable.out
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
OK
4 changes: 4 additions & 0 deletions compiler/testData/cli/jvm/coroutinesError.args
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
$TESTDATA_DIR$/coroutines.kt
-d
$TEMP_DIR$
-Xcoroutines=error
4 changes: 4 additions & 0 deletions compiler/testData/cli/jvm/coroutinesError.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
compiler/testData/cli/jvm/coroutines.kt:1:1: error: the feature "coroutines" is experimental and disabled (see: https://kotlinlang.org/docs/diagnostics/experimental-coroutines)
suspend fun simple() = 5
^
COMPILATION_ERROR
Loading

0 comments on commit b6fa10c

Please sign in to comment.