Support exhaustive when

This commit is contained in:
Michael Bogdanov
2016-09-30 14:41:52 +03:00
committed by Dmitry Petrov
parent a0d9d24c1f
commit 0b45655b7b
5 changed files with 63 additions and 3 deletions
@@ -41,7 +41,7 @@ import org.jetbrains.kotlin.fileClasses.FileClasses;
import org.jetbrains.kotlin.fileClasses.JvmFileClassInfo;
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil;
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.SpecialSignatureInfo;
import org.jetbrains.kotlin.load.java.JvmAbi;
@@ -197,8 +197,8 @@ public class KotlinTypeMapper {
if (facadeFqName != null) return facadeFqName;
}
if (descriptor instanceof IrBuiltinOperatorDescriptorBase) {
return "intrinsic";
if (descriptor.getContainingDeclaration() instanceof IrBuiltinsPackageFragmentDescriptor) {
return descriptor.getContainingDeclaration().getName().asString();
}
throw new RuntimeException("Could not find package member for " + descriptor +
@@ -37,6 +37,7 @@ class IrIntrinsicMethods(irBuiltIns: IrBuiltIns) {
irMapping.put(irBuiltIns.gt0, compare)
irMapping.put(irBuiltIns.gteq0, compare)
irMapping.put(irBuiltIns.enumValueOf, IrEnumValueOf())
irMapping.put(irBuiltIns.noWhenBranchMatchedException, IrNoWhenBranchMatchedException())
}
fun getIntrinsic(descriptor: CallableMemberDescriptor): IntrinsicMethod? {
@@ -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,6 +16,7 @@
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.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
@@ -108,10 +109,25 @@ class BranchingExpressionGenerator(statementGenerator: StatementGenerator) : Sta
val irBranchResult = statementGenerator.generateExpression(ktEntry.expression!!)
irWhen.branches.add(IrBranchImpl(irBranchCondition!!, irBranchResult))
}
addElseBranchForExhaustiveWhenIfNeeded(irWhen, expression)
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 {
if (irSubject == null) {
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)
}
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 {
val KOTLIN_INTERNAL_IR_FQN = FqName("kotlin.internal.ir")
}