Support exhaustive when
This commit is contained in:
committed by
Dmitry Petrov
parent
a0d9d24c1f
commit
0b45655b7b
@@ -41,7 +41,7 @@ import org.jetbrains.kotlin.fileClasses.FileClasses;
|
|||||||
import org.jetbrains.kotlin.fileClasses.JvmFileClassInfo;
|
import org.jetbrains.kotlin.fileClasses.JvmFileClassInfo;
|
||||||
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil;
|
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil;
|
||||||
import org.jetbrains.kotlin.fileClasses.JvmFileClassesProvider;
|
import org.jetbrains.kotlin.fileClasses.JvmFileClassesProvider;
|
||||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltinOperatorDescriptorBase;
|
import org.jetbrains.kotlin.ir.descriptors.IrBuiltinsPackageFragmentDescriptor;
|
||||||
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature;
|
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature;
|
||||||
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature.SpecialSignatureInfo;
|
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature.SpecialSignatureInfo;
|
||||||
import org.jetbrains.kotlin.load.java.JvmAbi;
|
import org.jetbrains.kotlin.load.java.JvmAbi;
|
||||||
@@ -197,8 +197,8 @@ public class KotlinTypeMapper {
|
|||||||
if (facadeFqName != null) return facadeFqName;
|
if (facadeFqName != null) return facadeFqName;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (descriptor instanceof IrBuiltinOperatorDescriptorBase) {
|
if (descriptor.getContainingDeclaration() instanceof IrBuiltinsPackageFragmentDescriptor) {
|
||||||
return "intrinsic";
|
return descriptor.getContainingDeclaration().getName().asString();
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new RuntimeException("Could not find package member for " + descriptor +
|
throw new RuntimeException("Could not find package member for " + descriptor +
|
||||||
|
|||||||
+1
@@ -37,6 +37,7 @@ class IrIntrinsicMethods(irBuiltIns: IrBuiltIns) {
|
|||||||
irMapping.put(irBuiltIns.gt0, compare)
|
irMapping.put(irBuiltIns.gt0, compare)
|
||||||
irMapping.put(irBuiltIns.gteq0, compare)
|
irMapping.put(irBuiltIns.gteq0, compare)
|
||||||
irMapping.put(irBuiltIns.enumValueOf, IrEnumValueOf())
|
irMapping.put(irBuiltIns.enumValueOf, IrEnumValueOf())
|
||||||
|
irMapping.put(irBuiltIns.noWhenBranchMatchedException, IrNoWhenBranchMatchedException())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getIntrinsic(descriptor: CallableMemberDescriptor): IntrinsicMethod? {
|
fun getIntrinsic(descriptor: CallableMemberDescriptor): IntrinsicMethod? {
|
||||||
|
|||||||
+30
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 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.backend.jvm.intrinsics
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||||
|
import org.jetbrains.kotlin.codegen.AsmUtil.genThrow
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
|
||||||
|
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
||||||
|
|
||||||
|
class IrNoWhenBranchMatchedException : IntrinsicMethod() {
|
||||||
|
override fun toCallable(expression: IrMemberAccessExpression, signature: JvmMethodSignature, context: JvmBackendContext): IrIntrinsicFunction {
|
||||||
|
return IrIntrinsicFunction.create(expression, signature, context) {
|
||||||
|
genThrow(it, "kotlin/NoWhenBranchMatchedException", null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+16
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.psi2ir.generators
|
package org.jetbrains.kotlin.psi2ir.generators
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||||
@@ -108,10 +109,25 @@ class BranchingExpressionGenerator(statementGenerator: StatementGenerator) : Sta
|
|||||||
val irBranchResult = statementGenerator.generateExpression(ktEntry.expression!!)
|
val irBranchResult = statementGenerator.generateExpression(ktEntry.expression!!)
|
||||||
irWhen.branches.add(IrBranchImpl(irBranchCondition!!, irBranchResult))
|
irWhen.branches.add(IrBranchImpl(irBranchCondition!!, irBranchResult))
|
||||||
}
|
}
|
||||||
|
addElseBranchForExhaustiveWhenIfNeeded(irWhen, expression)
|
||||||
|
|
||||||
return generateWhenBody(expression, irSubject, irWhen)
|
return generateWhenBody(expression, irSubject, irWhen)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun addElseBranchForExhaustiveWhenIfNeeded(irWhen: IrWhen, whenExpression: KtWhenExpression) {
|
||||||
|
if (irWhen.branches.filterIsInstance<IrElseBranch>().isEmpty()) {
|
||||||
|
val bindingContext = context.bindingContext
|
||||||
|
//TODO: check condition: seems it's safe to always generate exception
|
||||||
|
val isExhaustive = java.lang.Boolean.TRUE == bindingContext.get(BindingContext.IMPLICIT_EXHAUSTIVE_WHEN, whenExpression) ||
|
||||||
|
java.lang.Boolean.TRUE == bindingContext.get(BindingContext.EXHAUSTIVE_WHEN, whenExpression)
|
||||||
|
|
||||||
|
if (isExhaustive) {
|
||||||
|
val call = IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, context.irBuiltIns.noWhenBranchMatchedException)
|
||||||
|
irWhen.branches.add(IrBranchImpl.elseBranch(call))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun generateWhenBody(expression: KtWhenExpression, irSubject: IrVariable?, irWhen: IrWhen): IrExpression {
|
private fun generateWhenBody(expression: KtWhenExpression, irSubject: IrVariable?, irWhen: IrWhen): IrExpression {
|
||||||
if (irSubject == null) {
|
if (irSubject == null) {
|
||||||
if (irWhen.branches.isEmpty())
|
if (irWhen.branches.isEmpty())
|
||||||
|
|||||||
@@ -82,6 +82,19 @@ class IrBuiltIns(val builtIns: KotlinBuiltIns) {
|
|||||||
initialize(null, null, listOf(typeParameterT), listOf(valueParameterName), returnType, Modality.FINAL, Visibilities.PUBLIC)
|
initialize(null, null, listOf(typeParameterT), listOf(valueParameterName), returnType, Modality.FINAL, Visibilities.PUBLIC)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val noWhenBranchMatchedException: FunctionDescriptor =
|
||||||
|
SimpleFunctionDescriptorImpl.create(
|
||||||
|
packageFragment,
|
||||||
|
Annotations.EMPTY,
|
||||||
|
Name.identifier("noWhenBranchMatchedException"),
|
||||||
|
CallableMemberDescriptor.Kind.SYNTHESIZED,
|
||||||
|
org.jetbrains.kotlin.descriptors.SourceElement.NO_SOURCE
|
||||||
|
).apply {
|
||||||
|
val returnType = KotlinTypeFactory.simpleType(Annotations.EMPTY, builtIns.unit.typeConstructor, listOf(), false)
|
||||||
|
|
||||||
|
initialize(null, null, listOf(), listOf(), returnType, Modality.FINAL, Visibilities.PUBLIC)
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val KOTLIN_INTERNAL_IR_FQN = FqName("kotlin.internal.ir")
|
val KOTLIN_INTERNAL_IR_FQN = FqName("kotlin.internal.ir")
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user