Introduce new feature: division by zero in constant expressions
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2015 JetBrains s.r.o.
|
* Copyright 2010-2016 JetBrains s.r.o.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -45,7 +45,6 @@ import org.jetbrains.kotlin.resolve.BindingContext;
|
|||||||
import org.jetbrains.kotlin.resolve.BindingContextUtils;
|
import org.jetbrains.kotlin.resolve.BindingContextUtils;
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
|
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
|
||||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue;
|
import org.jetbrains.kotlin.resolve.constants.ConstantValue;
|
||||||
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator;
|
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
|
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
|
||||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes;
|
import org.jetbrains.kotlin.resolve.jvm.AsmTypes;
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt;
|
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt;
|
||||||
@@ -92,8 +91,6 @@ public abstract class MemberCodegen<T extends KtElement/* TODO: & JetDeclaration
|
|||||||
|
|
||||||
private DefaultSourceMapper sourceMapper;
|
private DefaultSourceMapper sourceMapper;
|
||||||
|
|
||||||
private final ConstantExpressionEvaluator constantExpressionEvaluator;
|
|
||||||
|
|
||||||
public MemberCodegen(
|
public MemberCodegen(
|
||||||
@NotNull GenerationState state,
|
@NotNull GenerationState state,
|
||||||
@Nullable MemberCodegen<?> parentCodegen,
|
@Nullable MemberCodegen<?> parentCodegen,
|
||||||
@@ -111,7 +108,6 @@ public abstract class MemberCodegen<T extends KtElement/* TODO: & JetDeclaration
|
|||||||
this.functionCodegen = new FunctionCodegen(context, v, state, this);
|
this.functionCodegen = new FunctionCodegen(context, v, state, this);
|
||||||
this.propertyCodegen = new PropertyCodegen(context, v, functionCodegen, this);
|
this.propertyCodegen = new PropertyCodegen(context, v, functionCodegen, this);
|
||||||
this.parentCodegen = parentCodegen;
|
this.parentCodegen = parentCodegen;
|
||||||
this.constantExpressionEvaluator = new ConstantExpressionEvaluator(state.getModule().getBuiltIns());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected MemberCodegen(@NotNull MemberCodegen<T> wrapped, T declaration, FieldOwnerContext codegenContext) {
|
protected MemberCodegen(@NotNull MemberCodegen<T> wrapped, T declaration, FieldOwnerContext codegenContext) {
|
||||||
|
|||||||
+6
-2
@@ -21,6 +21,8 @@ import com.intellij.psi.util.PsiTreeUtil
|
|||||||
import com.intellij.util.text.LiteralFormatUtil
|
import com.intellij.util.text.LiteralFormatUtil
|
||||||
import org.jetbrains.kotlin.KtNodeTypes
|
import org.jetbrains.kotlin.KtNodeTypes
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
|
import org.jetbrains.kotlin.config.LanguageFeature
|
||||||
|
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl
|
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors
|
import org.jetbrains.kotlin.diagnostics.Errors
|
||||||
@@ -44,7 +46,8 @@ import java.math.BigInteger
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class ConstantExpressionEvaluator(
|
class ConstantExpressionEvaluator(
|
||||||
internal val builtIns: KotlinBuiltIns
|
internal val builtIns: KotlinBuiltIns,
|
||||||
|
internal val languageVersionSettings: LanguageVersionSettings
|
||||||
) {
|
) {
|
||||||
internal val constantValueFactory = ConstantValueFactory(builtIns)
|
internal val constantValueFactory = ConstantValueFactory(builtIns)
|
||||||
|
|
||||||
@@ -456,7 +459,8 @@ private class ConstantExpressionEvaluatorVisitor(
|
|||||||
val parentExpression: KtExpression = PsiTreeUtil.getParentOfType(receiverExpression, KtExpression::class.java)!!
|
val parentExpression: KtExpression = PsiTreeUtil.getParentOfType(receiverExpression, KtExpression::class.java)!!
|
||||||
trace.report(Errors.DIVISION_BY_ZERO.on(parentExpression))
|
trace.report(Errors.DIVISION_BY_ZERO.on(parentExpression))
|
||||||
|
|
||||||
if (isIntegerType(argumentForReceiver.value) && isIntegerType(argumentForParameter.value)) {
|
if ((isIntegerType(argumentForReceiver.value) && isIntegerType(argumentForParameter.value)) ||
|
||||||
|
!constantExpressionEvaluator.languageVersionSettings.supportsFeature(LanguageFeature.DivisionByZeroInConstantExpressions)) {
|
||||||
return factory.createErrorValue("Division by zero").wrap()
|
return factory.createErrorValue("Division by zero").wrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package org.jetbrains.kotlin.script
|
package org.jetbrains.kotlin.script
|
||||||
|
|
||||||
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
|
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
|
||||||
|
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
|
||||||
import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
||||||
import org.jetbrains.kotlin.psi.KtUserType
|
import org.jetbrains.kotlin.psi.KtUserType
|
||||||
import org.jetbrains.kotlin.resolve.BindingTraceContext
|
import org.jetbrains.kotlin.resolve.BindingTraceContext
|
||||||
@@ -42,7 +43,7 @@ internal class KtAnnotationWrapper(val psi: KtAnnotationEntry, val targetClass:
|
|||||||
// TODO: annotation constructors unsupported yet in kotlin reflection, test and correct when they will be ready
|
// TODO: annotation constructors unsupported yet in kotlin reflection, test and correct when they will be ready
|
||||||
val targetAnnParams = targetClass.primaryConstructor?.parameters
|
val targetAnnParams = targetClass.primaryConstructor?.parameters
|
||||||
psi.valueArguments.mapIndexed { i, arg ->
|
psi.valueArguments.mapIndexed { i, arg ->
|
||||||
val evaluator = ConstantExpressionEvaluator(DefaultBuiltIns.Instance)
|
val evaluator = ConstantExpressionEvaluator(DefaultBuiltIns.Instance, LanguageVersionSettingsImpl.DEFAULT)
|
||||||
val trace = BindingTraceContext()
|
val trace = BindingTraceContext()
|
||||||
val result = evaluator.evaluateToConstantValue(arg.getArgumentExpression()!!, trace, TypeUtils.NO_EXPECTED_TYPE)
|
val result = evaluator.evaluateToConstantValue(arg.getArgumentExpression()!!, trace, TypeUtils.NO_EXPECTED_TYPE)
|
||||||
// TODO: consider inspecting `trace` to find diagnostics reported during the computation (such as division by zero, integer overflow, invalid annotation parameters etc.)
|
// TODO: consider inspecting `trace` to find diagnostics reported during the computation (such as division by zero, integer overflow, invalid annotation parameters etc.)
|
||||||
|
|||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
// !LANGUAGE: -DivisionByZeroInConstantExpressions
|
||||||
|
// !DIAGNOSTICS:-DIVISION_BY_ZERO
|
||||||
|
|
||||||
|
const val a = <!CONST_VAL_WITH_NON_CONST_INITIALIZER!>1 / 0.0<!>
|
||||||
|
const val b = <!CONST_VAL_WITH_NON_CONST_INITIALIZER!>1.0 / 0<!>
|
||||||
|
const val c = <!CONST_VAL_WITH_NON_CONST_INITIALIZER!>0.0 / 0<!>
|
||||||
|
|
||||||
|
const val i = <!CONST_VAL_WITH_NON_CONST_INITIALIZER!>1 / 0<!>
|
||||||
|
|
||||||
|
val nonConst1 = 1.0 / 0
|
||||||
|
val nonConst2 = 1 / 0
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public const val a: kotlin.Double
|
||||||
|
public const val b: kotlin.Double
|
||||||
|
public const val c: kotlin.Double
|
||||||
|
public const val i: kotlin.Int
|
||||||
|
public val nonConst1: kotlin.Double
|
||||||
|
public val nonConst2: kotlin.Int
|
||||||
+3
-2
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2015 JetBrains s.r.o.
|
* Copyright 2010-2016 JetBrains s.r.o.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -17,6 +17,7 @@
|
|||||||
package org.jetbrains.kotlin.resolve.constants.evaluate
|
package org.jetbrains.kotlin.resolve.constants.evaluate
|
||||||
|
|
||||||
import com.intellij.openapi.util.io.FileUtil
|
import com.intellij.openapi.util.io.FileUtil
|
||||||
|
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
|
||||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||||
import org.jetbrains.kotlin.psi.KtProperty
|
import org.jetbrains.kotlin.psi.KtProperty
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
@@ -64,7 +65,7 @@ abstract class AbstractCompileTimeConstantEvaluatorTest : AbstractAnnotationDesc
|
|||||||
|
|
||||||
private fun evaluateInitializer(context: BindingContext, property: VariableDescriptor): CompileTimeConstant<*>? {
|
private fun evaluateInitializer(context: BindingContext, property: VariableDescriptor): CompileTimeConstant<*>? {
|
||||||
val propertyDeclaration = DescriptorToSourceUtils.descriptorToDeclaration(property) as KtProperty
|
val propertyDeclaration = DescriptorToSourceUtils.descriptorToDeclaration(property) as KtProperty
|
||||||
val compileTimeConstant = ConstantExpressionEvaluator(property.builtIns).evaluateExpression(
|
val compileTimeConstant = ConstantExpressionEvaluator(property.builtIns, LanguageVersionSettingsImpl.DEFAULT).evaluateExpression(
|
||||||
propertyDeclaration.initializer!!,
|
propertyDeclaration.initializer!!,
|
||||||
DelegatingBindingTrace(context, "trace for evaluating compile time constant"),
|
DelegatingBindingTrace(context, "trace for evaluating compile time constant"),
|
||||||
property.type
|
property.type
|
||||||
|
|||||||
@@ -12261,6 +12261,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("noDivisionByZeroFeature.kt")
|
||||||
|
public void testNoDivisionByZeroFeature() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/modifiers/const/noDivisionByZeroFeature.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("types.kt")
|
@TestMetadata("types.kt")
|
||||||
public void testTypes() throws Exception {
|
public void testTypes() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/modifiers/const/types.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/modifiers/const/types.kt");
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ enum class LanguageFeature(val sinceVersion: LanguageVersion?) {
|
|||||||
SingleUnderscoreForParameterName(KOTLIN_1_1),
|
SingleUnderscoreForParameterName(KOTLIN_1_1),
|
||||||
DslMarkersSupport(KOTLIN_1_1),
|
DslMarkersSupport(KOTLIN_1_1),
|
||||||
UnderscoresInNumericLiterals(KOTLIN_1_1),
|
UnderscoresInNumericLiterals(KOTLIN_1_1),
|
||||||
|
DivisionByZeroInConstantExpressions(KOTLIN_1_1),
|
||||||
|
|
||||||
// Experimental features
|
// Experimental features
|
||||||
MultiPlatformProjects(null),
|
MultiPlatformProjects(null),
|
||||||
|
|||||||
+4
-2
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2015 JetBrains s.r.o.
|
* Copyright 2010-2016 JetBrains s.r.o.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -20,6 +20,7 @@ import com.intellij.openapi.util.Key
|
|||||||
import com.intellij.openapi.util.TextRange
|
import com.intellij.openapi.util.TextRange
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
|
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||||
import org.jetbrains.kotlin.idea.analysis.analyzeInContext
|
import org.jetbrains.kotlin.idea.analysis.analyzeInContext
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||||
import org.jetbrains.kotlin.idea.util.getResolutionScope
|
import org.jetbrains.kotlin.idea.util.getResolutionScope
|
||||||
@@ -54,7 +55,8 @@ class ExtractableSubstringInfo(
|
|||||||
|
|
||||||
val tempContext = expr.analyzeInContext(scope, template)
|
val tempContext = expr.analyzeInContext(scope, template)
|
||||||
val trace = DelegatingBindingTrace(tempContext, "Evaluate '$literal'")
|
val trace = DelegatingBindingTrace(tempContext, "Evaluate '$literal'")
|
||||||
val value = ConstantExpressionEvaluator(builtIns).evaluateExpression(expr, trace)
|
val languageVersionSettings = facade.getFrontendService(LanguageVersionSettings::class.java)
|
||||||
|
val value = ConstantExpressionEvaluator(builtIns, languageVersionSettings).evaluateExpression(expr, trace)
|
||||||
if (value == null || value.isError) return stringType
|
if (value == null || value.isError) return stringType
|
||||||
|
|
||||||
return value.toConstantValue(TypeUtils.NO_EXPECTED_TYPE).type
|
return value.toConstantValue(TypeUtils.NO_EXPECTED_TYPE).type
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import com.intellij.psi.PsiExpression
|
|||||||
import com.intellij.psi.impl.ConstantExpressionEvaluator
|
import com.intellij.psi.impl.ConstantExpressionEvaluator
|
||||||
import org.jetbrains.kotlin.asJava.elements.KtLightAnnotation
|
import org.jetbrains.kotlin.asJava.elements.KtLightAnnotation
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||||
|
import org.jetbrains.kotlin.idea.project.languageVersionSettings
|
||||||
import org.jetbrains.kotlin.psi.KtExpression
|
import org.jetbrains.kotlin.psi.KtExpression
|
||||||
import org.jetbrains.kotlin.resolve.DelegatingBindingTrace
|
import org.jetbrains.kotlin.resolve.DelegatingBindingTrace
|
||||||
import org.jetbrains.kotlin.resolve.constants.ArrayValue
|
import org.jetbrains.kotlin.resolve.constants.ArrayValue
|
||||||
@@ -53,7 +54,8 @@ class KotlinLightConstantExpressionEvaluator : ConstantExpressionEvaluator {
|
|||||||
return when (expressionToCompute) {
|
return when (expressionToCompute) {
|
||||||
is KtExpression -> {
|
is KtExpression -> {
|
||||||
val resolutionFacade = expressionToCompute.getResolutionFacade()
|
val resolutionFacade = expressionToCompute.getResolutionFacade()
|
||||||
val evaluator = FrontendConstantExpressionEvaluator(resolutionFacade.moduleDescriptor.builtIns)
|
val evaluator = FrontendConstantExpressionEvaluator(resolutionFacade.moduleDescriptor.builtIns,
|
||||||
|
expressionToCompute.languageVersionSettings)
|
||||||
val evaluatorTrace = DelegatingBindingTrace(resolutionFacade.analyze(expressionToCompute), "Evaluating annotation argument")
|
val evaluatorTrace = DelegatingBindingTrace(resolutionFacade.analyze(expressionToCompute), "Evaluating annotation argument")
|
||||||
|
|
||||||
val constant = evaluator.evaluateExpression(expressionToCompute, evaluatorTrace) ?: return null
|
val constant = evaluator.evaluateExpression(expressionToCompute, evaluatorTrace) ?: return null
|
||||||
|
|||||||
Reference in New Issue
Block a user