Effects: add (de)serialization of contracts in metadata
- Introduce new definitions in descriptors.proto - Add new corresponding values in Flags.java - Introduce ContractSerializer and ContractDeserializer, responsible for for conversion ContractDescription <-> ProtoBuf.Contract - Add dependency of 'serialization' module on 'resolution' so that it could see contracts model. Note that here we do a lot of seemingly unnecessary hoops, which in fact necessary to respect existing module system (in particular, to be able to extract ContractDescription declarations from 'descriptors' module to make them invisible from reflection) ========== Effect System introduction: 8/18
This commit is contained in:
@@ -354,6 +354,11 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR
|
||||
if (old.versionRequirement != new.versionRequirement) return false
|
||||
}
|
||||
|
||||
if (old.hasContract() != new.hasContract()) return false
|
||||
if (old.hasContract()) {
|
||||
if (!checkEquals(old.contract, new.contract)) return false
|
||||
}
|
||||
|
||||
if (old.hasExtension(JvmProtoBuf.methodSignature) != new.hasExtension(JvmProtoBuf.methodSignature)) return false
|
||||
if (old.hasExtension(JvmProtoBuf.methodSignature)) {
|
||||
if (!checkEquals(old.getExtension(JvmProtoBuf.methodSignature), new.getExtension(JvmProtoBuf.methodSignature))) return false
|
||||
@@ -745,6 +750,12 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR
|
||||
return true
|
||||
}
|
||||
|
||||
open fun checkEquals(old: ProtoBuf.Contract, new: ProtoBuf.Contract): Boolean {
|
||||
if (!checkEqualsContractEffect(old, new)) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
open fun checkEquals(old: JvmProtoBuf.JvmMethodSignature, new: JvmProtoBuf.JvmMethodSignature): Boolean {
|
||||
if (old.hasName() != new.hasName()) return false
|
||||
if (old.hasName()) {
|
||||
@@ -890,6 +901,27 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR
|
||||
return true
|
||||
}
|
||||
|
||||
open fun checkEquals(old: ProtoBuf.Effect, new: ProtoBuf.Effect): Boolean {
|
||||
if (old.hasEffectType() != new.hasEffectType()) return false
|
||||
if (old.hasEffectType()) {
|
||||
if (old.effectType != new.effectType) return false
|
||||
}
|
||||
|
||||
if (!checkEqualsEffectEffectConstructorArgument(old, new)) return false
|
||||
|
||||
if (old.hasConclusionOfConditionalEffect() != new.hasConclusionOfConditionalEffect()) return false
|
||||
if (old.hasConclusionOfConditionalEffect()) {
|
||||
if (!checkEquals(old.conclusionOfConditionalEffect, new.conclusionOfConditionalEffect)) return false
|
||||
}
|
||||
|
||||
if (old.hasKind() != new.hasKind()) return false
|
||||
if (old.hasKind()) {
|
||||
if (old.kind != new.kind) return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
open fun checkEquals(old: JvmProtoBuf.JvmFieldSignature, new: JvmProtoBuf.JvmFieldSignature): Boolean {
|
||||
if (old.hasName() != new.hasName()) return false
|
||||
if (old.hasName()) {
|
||||
@@ -904,6 +936,39 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR
|
||||
return true
|
||||
}
|
||||
|
||||
open fun checkEquals(old: ProtoBuf.Expression, new: ProtoBuf.Expression): Boolean {
|
||||
if (old.hasFlags() != new.hasFlags()) return false
|
||||
if (old.hasFlags()) {
|
||||
if (old.flags != new.flags) return false
|
||||
}
|
||||
|
||||
if (old.hasValueParameterReference() != new.hasValueParameterReference()) return false
|
||||
if (old.hasValueParameterReference()) {
|
||||
if (old.valueParameterReference != new.valueParameterReference) return false
|
||||
}
|
||||
|
||||
if (old.hasConstantValue() != new.hasConstantValue()) return false
|
||||
if (old.hasConstantValue()) {
|
||||
if (old.constantValue != new.constantValue) return false
|
||||
}
|
||||
|
||||
if (old.hasIsInstanceType() != new.hasIsInstanceType()) return false
|
||||
if (old.hasIsInstanceType()) {
|
||||
if (!checkEquals(old.isInstanceType, new.isInstanceType)) return false
|
||||
}
|
||||
|
||||
if (old.hasIsInstanceTypeId() != new.hasIsInstanceTypeId()) return false
|
||||
if (old.hasIsInstanceTypeId()) {
|
||||
if (old.isInstanceTypeId != new.isInstanceTypeId) return false
|
||||
}
|
||||
|
||||
if (!checkEqualsExpressionAndArgument(old, new)) return false
|
||||
|
||||
if (!checkEqualsExpressionOrArgument(old, new)) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
open fun checkEqualsPackageFunction(old: ProtoBuf.Package, new: ProtoBuf.Package): Boolean {
|
||||
if (old.functionCount != new.functionCount) return false
|
||||
|
||||
@@ -1154,6 +1219,16 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR
|
||||
return true
|
||||
}
|
||||
|
||||
open fun checkEqualsContractEffect(old: ProtoBuf.Contract, new: ProtoBuf.Contract): Boolean {
|
||||
if (old.effectCount != new.effectCount) return false
|
||||
|
||||
for(i in 0..old.effectCount - 1) {
|
||||
if (!checkEquals(old.getEffect(i), new.getEffect(i))) return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
open fun checkEqualsAnnotationArgumentValueArrayElement(old: ProtoBuf.Annotation.Argument.Value, new: ProtoBuf.Annotation.Argument.Value): Boolean {
|
||||
if (old.arrayElementCount != new.arrayElementCount) return false
|
||||
|
||||
@@ -1164,6 +1239,36 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR
|
||||
return true
|
||||
}
|
||||
|
||||
open fun checkEqualsEffectEffectConstructorArgument(old: ProtoBuf.Effect, new: ProtoBuf.Effect): Boolean {
|
||||
if (old.effectConstructorArgumentCount != new.effectConstructorArgumentCount) return false
|
||||
|
||||
for(i in 0..old.effectConstructorArgumentCount - 1) {
|
||||
if (!checkEquals(old.getEffectConstructorArgument(i), new.getEffectConstructorArgument(i))) return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
open fun checkEqualsExpressionAndArgument(old: ProtoBuf.Expression, new: ProtoBuf.Expression): Boolean {
|
||||
if (old.andArgumentCount != new.andArgumentCount) return false
|
||||
|
||||
for(i in 0..old.andArgumentCount - 1) {
|
||||
if (!checkEquals(old.getAndArgument(i), new.getAndArgument(i))) return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
open fun checkEqualsExpressionOrArgument(old: ProtoBuf.Expression, new: ProtoBuf.Expression): Boolean {
|
||||
if (old.orArgumentCount != new.orArgumentCount) return false
|
||||
|
||||
for(i in 0..old.orArgumentCount - 1) {
|
||||
if (!checkEquals(old.getOrArgument(i), new.getOrArgument(i))) return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
fun oldGetIndexOfString(index: Int): Int = getIndexOfString(index, oldStringIndexesMap, oldNameResolver)
|
||||
fun newGetIndexOfString(index: Int): Int = getIndexOfString(index, newStringIndexesMap, newNameResolver)
|
||||
|
||||
@@ -1362,6 +1467,10 @@ fun ProtoBuf.Function.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: (Int)
|
||||
hashCode = 31 * hashCode + versionRequirement
|
||||
}
|
||||
|
||||
if (hasContract()) {
|
||||
hashCode = 31 * hashCode + contract.hashCode(stringIndexes, fqNameIndexes)
|
||||
}
|
||||
|
||||
if (hasExtension(JvmProtoBuf.methodSignature)) {
|
||||
hashCode = 31 * hashCode + getExtension(JvmProtoBuf.methodSignature).hashCode(stringIndexes, fqNameIndexes)
|
||||
}
|
||||
@@ -1701,6 +1810,16 @@ fun ProtoBuf.ValueParameter.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes:
|
||||
return hashCode
|
||||
}
|
||||
|
||||
fun ProtoBuf.Contract.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: (Int) -> Int): Int {
|
||||
var hashCode = 1
|
||||
|
||||
for(i in 0..effectCount - 1) {
|
||||
hashCode = 31 * hashCode + getEffect(i).hashCode(stringIndexes, fqNameIndexes)
|
||||
}
|
||||
|
||||
return hashCode
|
||||
}
|
||||
|
||||
fun JvmProtoBuf.JvmMethodSignature.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: (Int) -> Int): Int {
|
||||
var hashCode = 1
|
||||
|
||||
@@ -1837,6 +1956,28 @@ fun ProtoBuf.Annotation.Argument.hashCode(stringIndexes: (Int) -> Int, fqNameInd
|
||||
return hashCode
|
||||
}
|
||||
|
||||
fun ProtoBuf.Effect.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: (Int) -> Int): Int {
|
||||
var hashCode = 1
|
||||
|
||||
if (hasEffectType()) {
|
||||
hashCode = 31 * hashCode + effectType.hashCode()
|
||||
}
|
||||
|
||||
for(i in 0..effectConstructorArgumentCount - 1) {
|
||||
hashCode = 31 * hashCode + getEffectConstructorArgument(i).hashCode(stringIndexes, fqNameIndexes)
|
||||
}
|
||||
|
||||
if (hasConclusionOfConditionalEffect()) {
|
||||
hashCode = 31 * hashCode + conclusionOfConditionalEffect.hashCode(stringIndexes, fqNameIndexes)
|
||||
}
|
||||
|
||||
if (hasKind()) {
|
||||
hashCode = 31 * hashCode + kind.hashCode()
|
||||
}
|
||||
|
||||
return hashCode
|
||||
}
|
||||
|
||||
fun JvmProtoBuf.JvmFieldSignature.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: (Int) -> Int): Int {
|
||||
var hashCode = 1
|
||||
|
||||
@@ -1850,3 +1991,37 @@ fun JvmProtoBuf.JvmFieldSignature.hashCode(stringIndexes: (Int) -> Int, fqNameIn
|
||||
|
||||
return hashCode
|
||||
}
|
||||
|
||||
fun ProtoBuf.Expression.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: (Int) -> Int): Int {
|
||||
var hashCode = 1
|
||||
|
||||
if (hasFlags()) {
|
||||
hashCode = 31 * hashCode + flags
|
||||
}
|
||||
|
||||
if (hasValueParameterReference()) {
|
||||
hashCode = 31 * hashCode + valueParameterReference
|
||||
}
|
||||
|
||||
if (hasConstantValue()) {
|
||||
hashCode = 31 * hashCode + constantValue.hashCode()
|
||||
}
|
||||
|
||||
if (hasIsInstanceType()) {
|
||||
hashCode = 31 * hashCode + isInstanceType.hashCode(stringIndexes, fqNameIndexes)
|
||||
}
|
||||
|
||||
if (hasIsInstanceTypeId()) {
|
||||
hashCode = 31 * hashCode + isInstanceTypeId
|
||||
}
|
||||
|
||||
for(i in 0..andArgumentCount - 1) {
|
||||
hashCode = 31 * hashCode + getAndArgument(i).hashCode(stringIndexes, fqNameIndexes)
|
||||
}
|
||||
|
||||
for(i in 0..orArgumentCount - 1) {
|
||||
hashCode = 31 * hashCode + getOrArgument(i).hashCode(stringIndexes, fqNameIndexes)
|
||||
}
|
||||
|
||||
return hashCode
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.container.*
|
||||
import org.jetbrains.kotlin.context.ModuleContext
|
||||
import org.jetbrains.kotlin.contracts.ContractDeserializerImpl
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PackagePartProvider
|
||||
import org.jetbrains.kotlin.frontend.di.configureModule
|
||||
@@ -109,6 +110,8 @@ fun createContainerForLazyResolveWithJava(
|
||||
}
|
||||
|
||||
targetEnvironment.configure(this)
|
||||
|
||||
useImpl<ContractDeserializerImpl>()
|
||||
}.apply {
|
||||
get<AbstractJavaClassFinder>().initialize(bindingTrace, get<KotlinCodeAnalyzer>())
|
||||
}
|
||||
|
||||
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
* 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.contracts
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.contracts.description.*
|
||||
import org.jetbrains.kotlin.contracts.description.expressions.*
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.serialization.Flags
|
||||
import org.jetbrains.kotlin.serialization.ProtoBuf
|
||||
import org.jetbrains.kotlin.serialization.deserialization.ContractDeserializer
|
||||
import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfiguration
|
||||
import org.jetbrains.kotlin.serialization.deserialization.TypeDeserializer
|
||||
import org.jetbrains.kotlin.serialization.deserialization.TypeTable
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
|
||||
class ContractDeserializerImpl(private val configuration: DeserializationConfiguration) : ContractDeserializer {
|
||||
override fun deserializeContractFromFunction(
|
||||
proto: ProtoBuf.Function,
|
||||
ownerFunction: FunctionDescriptor,
|
||||
typeTable: TypeTable,
|
||||
typeDeserializer: TypeDeserializer
|
||||
): Pair<FunctionDescriptor.UserDataKey<*>, LazyContractProvider>? {
|
||||
if (!proto.hasContract()) return null
|
||||
|
||||
if (!configuration.returnsEffectAllowed && !configuration.callsInPlaceEffectAllowed) return null
|
||||
|
||||
val worker = ContractDeserializationWorker(typeTable, typeDeserializer, ownerFunction)
|
||||
val contract = worker.deserializeContract(proto.contract)
|
||||
return ContractProviderKey to LazyContractProvider.createInitialized(contract)
|
||||
}
|
||||
|
||||
private class ContractDeserializationWorker(
|
||||
private val typeTable: TypeTable,
|
||||
private val typeDeserializer: TypeDeserializer,
|
||||
private val ownerFunction: FunctionDescriptor
|
||||
) {
|
||||
|
||||
fun deserializeContract(proto: ProtoBuf.Contract): ContractDescription? {
|
||||
val effects = proto.effectList.map { deserializePossiblyConditionalEffect(it) ?: return null }
|
||||
return ContractDescription(effects, ownerFunction)
|
||||
}
|
||||
|
||||
private fun deserializePossiblyConditionalEffect(proto: ProtoBuf.Effect): EffectDeclaration? {
|
||||
if (proto.hasConclusionOfConditionalEffect()) {
|
||||
// conditional effect
|
||||
val conclusion = deserializeExpression(proto.conclusionOfConditionalEffect) ?: return null
|
||||
val effect = deserializeSimpleEffect(proto) ?: return null
|
||||
return ConditionalEffectDeclaration(effect, conclusion)
|
||||
}
|
||||
return deserializeSimpleEffect(proto)
|
||||
}
|
||||
|
||||
private fun deserializeSimpleEffect(proto: ProtoBuf.Effect): EffectDeclaration? {
|
||||
val type = if (proto.hasEffectType()) proto.effectType else return null
|
||||
return when (type!!) {
|
||||
ProtoBuf.Effect.EffectType.RETURNS_CONSTANT -> {
|
||||
val argument = proto.effectConstructorArgumentList.getOrNull(0)
|
||||
val returnValue = if (argument == null) ConstantReference.WILDCARD else deserializeExpression(argument) as? ConstantReference ?: return null
|
||||
ReturnsEffectDeclaration(returnValue)
|
||||
}
|
||||
|
||||
ProtoBuf.Effect.EffectType.RETURNS_NOT_NULL -> {
|
||||
ReturnsEffectDeclaration(ConstantReference.NOT_NULL)
|
||||
}
|
||||
|
||||
ProtoBuf.Effect.EffectType.CALLS -> {
|
||||
val argument = proto.effectConstructorArgumentList.getOrNull(0) ?: return null
|
||||
val callable = extractVariable(argument) ?: return null
|
||||
val invocationKind = if (proto.hasKind())
|
||||
proto.kind.toDescriptorInvocationKind() ?: return null
|
||||
else
|
||||
InvocationKind.UNKNOWN
|
||||
CallsEffectDeclaration(callable, invocationKind)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun deserializeExpression(proto: ProtoBuf.Expression): BooleanExpression? {
|
||||
val primitiveType = getPrimitiveType(proto)
|
||||
val primitiveExpression = extractPrimitiveExpression(proto, primitiveType)
|
||||
|
||||
val complexType = getComplexType(proto)
|
||||
val childs: MutableList<BooleanExpression> = mutableListOf()
|
||||
childs.addIfNotNull(primitiveExpression)
|
||||
|
||||
return when (complexType) {
|
||||
ComplexExpressionType.AND_SEQUENCE -> {
|
||||
proto.andArgumentList.mapTo(childs) { deserializeExpression(it) ?: return null }
|
||||
childs.reduce { acc, booleanExpression -> LogicalAnd(acc, booleanExpression) }
|
||||
}
|
||||
|
||||
ComplexExpressionType.OR_SEQUENCE -> {
|
||||
proto.orArgumentList.mapTo(childs) { deserializeExpression(it) ?: return null }
|
||||
childs.reduce { acc, booleanExpression -> LogicalOr(acc, booleanExpression) }
|
||||
}
|
||||
|
||||
null -> primitiveExpression
|
||||
}
|
||||
}
|
||||
|
||||
private fun extractPrimitiveExpression(proto: ProtoBuf.Expression, primitiveType: PrimitiveExpressionType?): BooleanExpression? {
|
||||
val isInverted = proto.hasFlags() && Flags.IS_NEGATED.get(proto.flags)
|
||||
|
||||
return when (primitiveType) {
|
||||
PrimitiveExpressionType.VALUE_PARAMETER_REFERENCE, PrimitiveExpressionType.RECEIVER_REFERENCE -> {
|
||||
(extractVariable(proto) as? BooleanVariableReference?)?.invertIfNecessary(isInverted)
|
||||
}
|
||||
|
||||
PrimitiveExpressionType.CONSTANT ->
|
||||
(deserializeConstant(proto.constantValue) as? BooleanConstantReference)?.invertIfNecessary(isInverted)
|
||||
|
||||
PrimitiveExpressionType.INSTANCE_CHECK -> {
|
||||
val variable = extractVariable(proto) ?: return null
|
||||
val type = extractType(proto) ?: return null
|
||||
IsInstancePredicate(variable, type, isInverted)
|
||||
}
|
||||
|
||||
PrimitiveExpressionType.NULLABILITY_CHECK -> {
|
||||
val variable = extractVariable(proto) ?: return null
|
||||
IsNullPredicate(variable, isInverted)
|
||||
}
|
||||
|
||||
null -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun BooleanExpression.invertIfNecessary(shouldInvert: Boolean) = if (shouldInvert) LogicalNot(this) else this
|
||||
|
||||
private fun extractVariable(proto: ProtoBuf.Expression): VariableReference? {
|
||||
if (!proto.hasValueParameterReference()) return null
|
||||
|
||||
val parameterDescriptor = if (proto.valueParameterReference == 0)
|
||||
ownerFunction.extensionReceiverParameter ?: return null
|
||||
else
|
||||
ownerFunction.valueParameters.getOrNull(proto.valueParameterReference - 1) ?: return null
|
||||
|
||||
return if (!KotlinBuiltIns.isBoolean(parameterDescriptor.type))
|
||||
VariableReference(parameterDescriptor)
|
||||
else
|
||||
BooleanVariableReference(parameterDescriptor)
|
||||
}
|
||||
|
||||
private fun ProtoBuf.Effect.InvocationKind.toDescriptorInvocationKind(): InvocationKind? = when (this) {
|
||||
ProtoBuf.Effect.InvocationKind.AT_MOST_ONCE -> InvocationKind.AT_MOST_ONCE
|
||||
ProtoBuf.Effect.InvocationKind.EXACTLY_ONCE -> InvocationKind.EXACTLY_ONCE
|
||||
ProtoBuf.Effect.InvocationKind.AT_LEAST_ONCE -> InvocationKind.AT_LEAST_ONCE
|
||||
}
|
||||
|
||||
private fun extractType(proto: ProtoBuf.Expression): KotlinType? {
|
||||
val protoType = when {
|
||||
proto.hasIsInstanceType() -> proto.isInstanceType
|
||||
proto.hasIsInstanceTypeId() -> typeTable.types.getOrNull(proto.isInstanceTypeId) ?: return null
|
||||
else -> return null
|
||||
}
|
||||
|
||||
return typeDeserializer.type(protoType)
|
||||
}
|
||||
|
||||
private fun deserializeConstant(value: ProtoBuf.Expression.ConstantValue): ConstantReference? = when (value) {
|
||||
ProtoBuf.Expression.ConstantValue.TRUE -> BooleanConstantReference.TRUE
|
||||
ProtoBuf.Expression.ConstantValue.FALSE -> BooleanConstantReference.FALSE
|
||||
ProtoBuf.Expression.ConstantValue.NULL -> ConstantReference.NULL
|
||||
}
|
||||
|
||||
private fun getComplexType(proto: ProtoBuf.Expression): ComplexExpressionType? {
|
||||
val isOrSequence = proto.orArgumentCount != 0
|
||||
val isAndSequence = proto.andArgumentCount != 0
|
||||
return when {
|
||||
isOrSequence && isAndSequence -> null
|
||||
isOrSequence -> ComplexExpressionType.OR_SEQUENCE
|
||||
isAndSequence -> ComplexExpressionType.AND_SEQUENCE
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun getPrimitiveType(proto: ProtoBuf.Expression): PrimitiveExpressionType? {
|
||||
// Expected to be one element, but can be empty (unknown expression) or contain several elements (invalid data)
|
||||
val expressionTypes: MutableList<PrimitiveExpressionType> = mutableListOf()
|
||||
|
||||
// Check for predicates
|
||||
when {
|
||||
proto.hasValueParameterReference() && proto.hasType() ->
|
||||
expressionTypes.add(PrimitiveExpressionType.INSTANCE_CHECK)
|
||||
|
||||
proto.hasValueParameterReference() && proto.hasFlag(Flags.IS_NULL_CHECK_PREDICATE) ->
|
||||
expressionTypes.add(PrimitiveExpressionType.NULLABILITY_CHECK)
|
||||
}
|
||||
|
||||
// If message contains correct predicate, then predicate's type overrides type of value,
|
||||
// even is message has one
|
||||
if (expressionTypes.isNotEmpty()) {
|
||||
return expressionTypes.singleOrNull()
|
||||
}
|
||||
|
||||
// Otherwise, check if it is a value
|
||||
when {
|
||||
proto.hasValueParameterReference() && proto.valueParameterReference > 0 ->
|
||||
expressionTypes.add(PrimitiveExpressionType.VALUE_PARAMETER_REFERENCE)
|
||||
|
||||
proto.hasValueParameterReference() && proto.valueParameterReference == 0 ->
|
||||
expressionTypes.add(PrimitiveExpressionType.RECEIVER_REFERENCE)
|
||||
|
||||
proto.hasConstantValue() -> expressionTypes.add(PrimitiveExpressionType.CONSTANT)
|
||||
}
|
||||
|
||||
return expressionTypes.singleOrNull()
|
||||
}
|
||||
|
||||
private fun ProtoBuf.Expression.hasType(): Boolean = this.hasIsInstanceType() || this.hasIsInstanceTypeId()
|
||||
|
||||
private fun ProtoBuf.Expression.hasFlag(flag: Flags.BooleanFlagField) =
|
||||
this.hasFlags() && flag.get(this.flags)
|
||||
|
||||
// Arguments of expressions with such types are never other expressions
|
||||
private enum class PrimitiveExpressionType {
|
||||
VALUE_PARAMETER_REFERENCE,
|
||||
RECEIVER_REFERENCE,
|
||||
CONSTANT,
|
||||
INSTANCE_CHECK,
|
||||
NULLABILITY_CHECK
|
||||
}
|
||||
|
||||
// Expressions with such type can take other expressions as arguments.
|
||||
// Additionally, for performance reasons, "complex expression" and "primitive expression"
|
||||
// can co-exist in the one and the same message. If "primitive expression" is present
|
||||
// in the current message, it is treated as the first argument of "complex expression".
|
||||
private enum class ComplexExpressionType {
|
||||
AND_SEQUENCE,
|
||||
OR_SEQUENCE
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
@@ -27,4 +27,8 @@ class CompilerDeserializationConfiguration(languageVersionSettings: LanguageVers
|
||||
override val skipMetadataVersionCheck = languageVersionSettings.getFlag(AnalysisFlag.skipMetadataVersionCheck)
|
||||
|
||||
override val isJvmPackageNameSupported = languageVersionSettings.supportsFeature(LanguageFeature.JvmPackageName)
|
||||
|
||||
override val returnsEffectAllowed: Boolean = languageVersionSettings.supportsFeature(LanguageFeature.ReturnsEffect)
|
||||
|
||||
override val callsInPlaceEffectAllowed: Boolean = languageVersionSettings.supportsFeature(LanguageFeature.CallsInPlaceEffect)
|
||||
}
|
||||
|
||||
+2
-1
@@ -17,12 +17,13 @@
|
||||
package org.jetbrains.kotlin.contracts.description
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.serialization.deserialization.ContractProvider
|
||||
|
||||
/**
|
||||
* Essentially, this is a composition of two fields: value of type 'ContractDescription' and
|
||||
* 'computation', which guarantees to initialize this field.
|
||||
*/
|
||||
class LazyContractProvider(private val computation: () -> Any?) {
|
||||
class LazyContractProvider(private val computation: () -> Any?) : ContractProvider {
|
||||
@Volatile
|
||||
private var isComputed: Boolean = false
|
||||
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* 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.serialization
|
||||
|
||||
import org.jetbrains.kotlin.contracts.description.*
|
||||
import org.jetbrains.kotlin.contracts.description.expressions.*
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
|
||||
class ContractSerializer {
|
||||
fun serializeContractOfFunctionIfAny(
|
||||
functionDescriptor: FunctionDescriptor,
|
||||
proto: ProtoBuf.Function.Builder,
|
||||
parentSerializer: DescriptorSerializer
|
||||
) {
|
||||
val contractDescription = functionDescriptor.getUserData(ContractProviderKey)?.getContractDescription()
|
||||
if (contractDescription != null) {
|
||||
val worker = ContractSerializerWorker(parentSerializer)
|
||||
proto.setContract(worker.contractProto(contractDescription))
|
||||
}
|
||||
}
|
||||
|
||||
private class ContractSerializerWorker(private val parentSerializer: DescriptorSerializer) {
|
||||
fun contractProto(contractDescription: ContractDescription): ProtoBuf.Contract.Builder {
|
||||
return ProtoBuf.Contract.newBuilder().apply {
|
||||
contractDescription.effects.forEach { addEffect(effectProto(it, contractDescription)) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun effectProto(effectDeclaration: EffectDeclaration, contractDescription: ContractDescription): ProtoBuf.Effect.Builder {
|
||||
return ProtoBuf.Effect.newBuilder().apply {
|
||||
fillEffectProto(this, effectDeclaration, contractDescription)
|
||||
}
|
||||
}
|
||||
|
||||
private fun fillEffectProto(builder: ProtoBuf.Effect.Builder, effectDeclaration: EffectDeclaration, contractDescription: ContractDescription) {
|
||||
when (effectDeclaration) {
|
||||
is ConditionalEffectDeclaration -> {
|
||||
builder.setConclusionOfConditionalEffect(contractExpressionProto(effectDeclaration.condition, contractDescription))
|
||||
fillEffectProto(builder, effectDeclaration.effect, contractDescription)
|
||||
}
|
||||
|
||||
is ReturnsEffectDeclaration -> {
|
||||
when {
|
||||
effectDeclaration.value == ConstantReference.NOT_NULL -> builder.effectType = ProtoBuf.Effect.EffectType.RETURNS_NOT_NULL
|
||||
effectDeclaration.value == ConstantReference.WILDCARD -> builder.effectType = ProtoBuf.Effect.EffectType.RETURNS_CONSTANT
|
||||
else -> {
|
||||
builder.effectType = ProtoBuf.Effect.EffectType.RETURNS_CONSTANT
|
||||
builder.addEffectConstructorArgument(contractExpressionProto(effectDeclaration.value, contractDescription))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is CallsEffectDeclaration -> {
|
||||
builder.effectType = ProtoBuf.Effect.EffectType.CALLS
|
||||
builder.addEffectConstructorArgument(contractExpressionProto(effectDeclaration.variableReference, contractDescription))
|
||||
val invocationKindProtobufEnum = invocationKindProtobufEnum(effectDeclaration.kind)
|
||||
if (invocationKindProtobufEnum != null) {
|
||||
builder.kind = invocationKindProtobufEnum
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Add else and do something like reporting issue?
|
||||
}
|
||||
}
|
||||
|
||||
private fun contractExpressionProto(contractDescriptionElement: ContractDescriptionElement, contractDescription: ContractDescription): ProtoBuf.Expression.Builder {
|
||||
return contractDescriptionElement.accept(object : ContractDescriptionVisitor<ProtoBuf.Expression.Builder, Unit> {
|
||||
override fun visitLogicalOr(logicalOr: LogicalOr, data: Unit): ProtoBuf.Expression.Builder {
|
||||
val leftBuilder = logicalOr.left.accept(this, data)
|
||||
|
||||
return if (leftBuilder.andArgumentCount != 0) {
|
||||
// can't flatten and re-use left builder
|
||||
ProtoBuf.Expression.newBuilder().apply {
|
||||
addOrArgument(leftBuilder)
|
||||
addOrArgument(contractExpressionProto(logicalOr.right, contractDescription))
|
||||
}
|
||||
}
|
||||
else {
|
||||
// we can save some space by re-using left builder instead of nesting new one
|
||||
leftBuilder.apply { addOrArgument(contractExpressionProto(logicalOr.right, contractDescription)) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitLogicalAnd(logicalAnd: LogicalAnd, data: Unit): ProtoBuf.Expression.Builder {
|
||||
val leftBuilder = logicalAnd.left.accept(this, data)
|
||||
|
||||
return if (leftBuilder.orArgumentCount != 0) {
|
||||
// leftBuilder is already a sequence of Or-operators, so we can't re-use it
|
||||
ProtoBuf.Expression.newBuilder().apply {
|
||||
addAndArgument(leftBuilder)
|
||||
addAndArgument(contractExpressionProto(logicalAnd.right, contractDescription))
|
||||
}
|
||||
}
|
||||
else {
|
||||
// we can save some space by re-using left builder instead of nesting new one
|
||||
leftBuilder.apply { addAndArgument(contractExpressionProto(logicalAnd.right, contractDescription)) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitLogicalNot(logicalNot: LogicalNot, data: Unit): ProtoBuf.Expression.Builder =
|
||||
logicalNot.arg.accept(this, data).apply {
|
||||
writeFlags(Flags.IS_NEGATED.invert(flags))
|
||||
}
|
||||
|
||||
override fun visitIsInstancePredicate(isInstancePredicate: IsInstancePredicate, data: Unit): ProtoBuf.Expression.Builder {
|
||||
// write variable
|
||||
val builder = visitVariableReference(isInstancePredicate.arg, data)
|
||||
|
||||
// write rhs type
|
||||
builder.isInstanceTypeId = parentSerializer.typeId(isInstancePredicate.type)
|
||||
|
||||
// set flags
|
||||
builder.writeFlags(Flags.getContractExpressionFlags(isInstancePredicate.isNegated, false))
|
||||
|
||||
return builder
|
||||
}
|
||||
|
||||
override fun visitIsNullPredicate(isNullPredicate: IsNullPredicate, data: Unit): ProtoBuf.Expression.Builder {
|
||||
// get builder with variable embeded into it
|
||||
val builder = visitVariableReference(isNullPredicate.arg, data)
|
||||
|
||||
// set flags
|
||||
builder.writeFlags(Flags.getContractExpressionFlags(isNullPredicate.isNegated, true))
|
||||
|
||||
return builder
|
||||
}
|
||||
|
||||
override fun visitConstantDescriptor(constantReference: ConstantReference, data: Unit): ProtoBuf.Expression.Builder {
|
||||
val builder = ProtoBuf.Expression.newBuilder()
|
||||
|
||||
// write constant value
|
||||
val constantValueProtobufEnum = constantValueProtobufEnum(constantReference)
|
||||
if (constantValueProtobufEnum != null) {
|
||||
builder.constantValue = constantValueProtobufEnum
|
||||
}
|
||||
|
||||
return builder
|
||||
}
|
||||
|
||||
override fun visitVariableReference(variableReference: VariableReference, data: Unit): ProtoBuf.Expression.Builder {
|
||||
val builder = ProtoBuf.Expression.newBuilder()
|
||||
|
||||
val descriptor = variableReference.descriptor
|
||||
val indexOfParameter = when (descriptor) {
|
||||
is ReceiverParameterDescriptor -> 0
|
||||
|
||||
is ValueParameterDescriptor ->
|
||||
contractDescription.ownerFunction.valueParameters.indexOf(descriptor).takeIf { it != -1 }?.inc()
|
||||
|
||||
else -> null
|
||||
}
|
||||
|
||||
builder.valueParameterReference = indexOfParameter ?: return builder
|
||||
|
||||
return builder
|
||||
}
|
||||
}, Unit)
|
||||
}
|
||||
|
||||
private fun ProtoBuf.Expression.Builder.writeFlags(newFlagsValue: Int) {
|
||||
if (flags != newFlagsValue) {
|
||||
flags = newFlagsValue
|
||||
}
|
||||
}
|
||||
|
||||
private fun invocationKindProtobufEnum(kind: InvocationKind): ProtoBuf.Effect.InvocationKind? = when (kind) {
|
||||
InvocationKind.AT_MOST_ONCE -> ProtoBuf.Effect.InvocationKind.AT_MOST_ONCE
|
||||
InvocationKind.EXACTLY_ONCE -> ProtoBuf.Effect.InvocationKind.EXACTLY_ONCE
|
||||
InvocationKind.AT_LEAST_ONCE -> ProtoBuf.Effect.InvocationKind.AT_LEAST_ONCE
|
||||
InvocationKind.UNKNOWN -> null
|
||||
}
|
||||
|
||||
private fun constantValueProtobufEnum(constantReference: ConstantReference): ProtoBuf.Expression.ConstantValue? = when (constantReference) {
|
||||
BooleanConstantReference.TRUE -> ProtoBuf.Expression.ConstantValue.TRUE
|
||||
BooleanConstantReference.FALSE -> ProtoBuf.Expression.ConstantValue.FALSE
|
||||
ConstantReference.NULL -> ProtoBuf.Expression.ConstantValue.NULL
|
||||
ConstantReference.NOT_NULL -> throw IllegalStateException(
|
||||
"Internal error during serialization of function contract: NOT_NULL constant isn't denotable in protobuf format. " +
|
||||
"Its serialization should be handled at higher level"
|
||||
)
|
||||
ConstantReference.WILDCARD -> null
|
||||
else -> throw IllegalArgumentException("Unknown constant: $constantReference")
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
-3
@@ -49,6 +49,8 @@ class DescriptorSerializer private constructor(
|
||||
private val versionRequirementTable: MutableVersionRequirementTable,
|
||||
private val serializeTypeTableToFunction: Boolean
|
||||
) {
|
||||
private val contractSerializer = ContractSerializer()
|
||||
|
||||
fun serialize(message: MessageLite): ByteArray {
|
||||
return ByteArrayOutputStream().apply {
|
||||
stringTable.serializeTo(this)
|
||||
@@ -150,7 +152,6 @@ class DescriptorSerializer private constructor(
|
||||
}
|
||||
|
||||
extension.serializeClass(classDescriptor, builder)
|
||||
|
||||
return builder
|
||||
}
|
||||
|
||||
@@ -295,6 +296,8 @@ class DescriptorSerializer private constructor(
|
||||
builder.versionRequirement = writeVersionRequirement(LanguageFeature.Coroutines)
|
||||
}
|
||||
|
||||
contractSerializer.serializeContractOfFunctionIfAny(descriptor, builder, this)
|
||||
|
||||
extension.serializeFunction(descriptor, builder)
|
||||
|
||||
return builder
|
||||
@@ -452,9 +455,9 @@ class DescriptorSerializer private constructor(
|
||||
return builder
|
||||
}
|
||||
|
||||
private fun typeId(type: KotlinType): Int = typeTable[type(type)]
|
||||
internal fun typeId(type: KotlinType): Int = typeTable[type(type)]
|
||||
|
||||
private fun type(type: KotlinType): ProtoBuf.Type.Builder {
|
||||
internal fun type(type: KotlinType): ProtoBuf.Type.Builder {
|
||||
val builder = ProtoBuf.Type.newBuilder()
|
||||
|
||||
if (type.isError) {
|
||||
@@ -661,6 +664,8 @@ class DescriptorSerializer private constructor(
|
||||
private fun getTypeParameterId(descriptor: TypeParameterDescriptor): Int =
|
||||
typeParameters.intern(descriptor)
|
||||
|
||||
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun createTopLevel(extension: SerializerExtension): DescriptorSerializer {
|
||||
|
||||
+3
-1
@@ -51,7 +51,9 @@ class JvmBuiltInsPackageFragmentProvider(
|
||||
BuiltInFictitiousFunctionClassFactory(storageManager, moduleDescriptor),
|
||||
JvmBuiltInClassDescriptorFactory(storageManager, moduleDescriptor)
|
||||
),
|
||||
notFoundClasses, additionalClassPartsProvider, platformDependentDeclarationFilter
|
||||
notFoundClasses,
|
||||
ContractDeserializer.DEFAULT,
|
||||
additionalClassPartsProvider, platformDependentDeclarationFilter
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+4
-6
@@ -23,10 +23,7 @@ import org.jetbrains.kotlin.descriptors.deserialization.PlatformDependentDeclara
|
||||
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||
import org.jetbrains.kotlin.load.java.lazy.LazyJavaPackageFragmentProvider
|
||||
import org.jetbrains.kotlin.platform.JvmBuiltIns
|
||||
import org.jetbrains.kotlin.serialization.deserialization.DeserializationComponents
|
||||
import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfiguration
|
||||
import org.jetbrains.kotlin.serialization.deserialization.ErrorReporter
|
||||
import org.jetbrains.kotlin.serialization.deserialization.LocalClassifierTypeSettings
|
||||
import org.jetbrains.kotlin.serialization.deserialization.*
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
|
||||
// This class is needed only for easier injection: exact types of needed components are specified in the constructor here.
|
||||
@@ -40,7 +37,8 @@ class DeserializationComponentsForJava(
|
||||
packageFragmentProvider: LazyJavaPackageFragmentProvider,
|
||||
notFoundClasses: NotFoundClasses,
|
||||
errorReporter: ErrorReporter,
|
||||
lookupTracker: LookupTracker
|
||||
lookupTracker: LookupTracker,
|
||||
contractDeserializer: ContractDeserializer
|
||||
) {
|
||||
val components: DeserializationComponents
|
||||
|
||||
@@ -50,7 +48,7 @@ class DeserializationComponentsForJava(
|
||||
components = DeserializationComponents(
|
||||
storageManager, moduleDescriptor, configuration, classDataFinder, annotationAndConstantLoader, packageFragmentProvider,
|
||||
LocalClassifierTypeSettings.Default, errorReporter, lookupTracker, JavaFlexibleTypeDeserializer,
|
||||
emptyList(), notFoundClasses,
|
||||
emptyList(), notFoundClasses, contractDeserializer,
|
||||
additionalClassPartsProvider = jvmBuiltIns?.settings ?: AdditionalClassPartsProvider.None,
|
||||
platformDependentDeclarationFilter = jvmBuiltIns?.settings ?: PlatformDependentDeclarationFilter.NoPlatformDependent
|
||||
)
|
||||
|
||||
+2
-1
@@ -36,6 +36,7 @@ import org.jetbrains.kotlin.load.kotlin.JavaClassDataFinder
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.platform.JvmBuiltIns
|
||||
import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolver
|
||||
import org.jetbrains.kotlin.serialization.deserialization.ContractDeserializer
|
||||
import org.jetbrains.kotlin.serialization.deserialization.DeserializationComponents
|
||||
import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfiguration
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
@@ -82,7 +83,7 @@ class RuntimeModuleData private constructor(
|
||||
val deserializationComponentsForJava = DeserializationComponentsForJava(
|
||||
storageManager, module, DeserializationConfiguration.Default, javaClassDataFinder,
|
||||
binaryClassAnnotationAndConstantLoader, lazyJavaPackageFragmentProvider, notFoundClasses,
|
||||
RuntimeErrorReporter, LookupTracker.DO_NOTHING
|
||||
RuntimeErrorReporter, LookupTracker.DO_NOTHING, ContractDeserializer.DEFAULT
|
||||
)
|
||||
|
||||
singleModuleClassResolver.resolver = javaDescriptorResolver
|
||||
|
||||
@@ -818,4 +818,9 @@ public abstract class FunctionDescriptorImpl extends DeclarationDescriptorNonRoo
|
||||
private void setInitialSignatureDescriptor(@Nullable FunctionDescriptor initialSignatureDescriptor) {
|
||||
this.initialSignatureDescriptor = initialSignatureDescriptor;
|
||||
}
|
||||
|
||||
// Don't use on published descriptors
|
||||
public <V> void putInUserDataMap(UserDataKey<V> key, Object value) {
|
||||
userDataMap.put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -289,6 +289,8 @@ message Function {
|
||||
// Index into the VersionRequirementTable
|
||||
optional int32 version_requirement = 31;
|
||||
|
||||
optional Contract contract = 32;
|
||||
|
||||
extensions 100 to 199;
|
||||
}
|
||||
|
||||
@@ -469,3 +471,78 @@ message PackageFragment {
|
||||
|
||||
extensions 100 to 199;
|
||||
}
|
||||
|
||||
|
||||
|
||||
message Contract {
|
||||
repeated Effect effect = 1;
|
||||
}
|
||||
|
||||
message Effect {
|
||||
// This enum controls which effect this message contains and how 'effectConstructorArguments'
|
||||
// should be parsed.
|
||||
// Each enum value documented in the following syntax: "EffectName(arg1: T1, arg2: T2, ...)"
|
||||
// Those arguments are expected to be found in 'effectConstructorArguments' in exactly the same
|
||||
// order and amount as defined by signature, otherwise message should be dropped.
|
||||
enum EffectType {
|
||||
// Returns(value: ConstantValue?)
|
||||
RETURNS_CONSTANT = 0;
|
||||
|
||||
// CallsInPlace(callable: ParameterReference)
|
||||
// Additionally, InvocationKind in the field 'kind' may be provided to define exact amount of invocations.
|
||||
CALLS = 1;
|
||||
|
||||
// ReturnsNotNull()
|
||||
RETURNS_NOT_NULL = 2;
|
||||
}
|
||||
optional EffectType effect_type = 1;
|
||||
|
||||
repeated Expression effect_constructor_argument = 2;
|
||||
|
||||
// If present, then whole message is clause of form 'Effect -> Expression', where 'Effect'
|
||||
// is given by other fields in this message, and 'Expression' is stored in this field.
|
||||
optional Expression conclusion_of_conditional_effect = 3;
|
||||
|
||||
enum InvocationKind {
|
||||
AT_MOST_ONCE = 0;
|
||||
EXACTLY_ONCE = 1;
|
||||
AT_LEAST_ONCE = 2;
|
||||
}
|
||||
optional InvocationKind kind = 4;
|
||||
}
|
||||
|
||||
// We use some trickery to optimize memory footprint of contract-expressions:
|
||||
// exact type of Expression is determined based on its contents.
|
||||
message Expression {
|
||||
/*
|
||||
isNegated => this expression should be negated
|
||||
isIsNullPredicate => this expression is IsNullPredicate with 'variableName' as argument
|
||||
*/
|
||||
optional int32 flags = 1;
|
||||
|
||||
// stored as index in valueParameters list of owner-function in 1-indexation
|
||||
// Index '0' is reserved for extension receiver
|
||||
optional int32 value_parameter_reference = 2;
|
||||
|
||||
enum ConstantValue {
|
||||
TRUE = 0;
|
||||
FALSE = 1;
|
||||
NULL = 2;
|
||||
}
|
||||
optional ConstantValue constant_value = 3;
|
||||
|
||||
// present => this expression is IsInstancePredicate, with 'variableName' as LHS
|
||||
// and with type encoded in either one of next two fields as RHS.
|
||||
optional Type is_instance_type = 4;
|
||||
optional int32 is_instance_type_id = 5;
|
||||
|
||||
// non-empty => this expression is boolean formula of form 'andArguments[0] && andArguments[1] && ...'
|
||||
// Additionally, if first argument of formula is primitive expression (i.e. predicate or value),
|
||||
// it is optimized and embedded straight into this message
|
||||
repeated Expression and_argument = 6;
|
||||
|
||||
// non-empty => this expression is boolean formula of form 'orArguments[0] || andArguments[1] || ...'
|
||||
// Additionally, if first argument of formula is primitive expression (i.e. predicate or value),
|
||||
// it is optimized and embedded straight into this message.
|
||||
repeated Expression or_argument = 7;
|
||||
}
|
||||
@@ -82,8 +82,9 @@ class BuiltInsLoaderImpl : BuiltInsLoader {
|
||||
FlexibleTypeDeserializer.ThrowException,
|
||||
classDescriptorFactories,
|
||||
notFoundClasses,
|
||||
additionalClassPartsProvider = additionalClassPartsProvider,
|
||||
platformDependentDeclarationFilter = platformDependentDeclarationFilter
|
||||
ContractDeserializer.DEFAULT,
|
||||
additionalClassPartsProvider,
|
||||
platformDependentDeclarationFilter
|
||||
)
|
||||
|
||||
for (packageFragment in packageFragments) {
|
||||
|
||||
@@ -83,6 +83,11 @@ public class Flags {
|
||||
public static final BooleanFlagField IS_EXTERNAL_ACCESSOR = FlagField.booleanAfter(IS_NOT_DEFAULT);
|
||||
public static final BooleanFlagField IS_INLINE_ACCESSOR = FlagField.booleanAfter(IS_EXTERNAL_ACCESSOR);
|
||||
|
||||
// Contracts expressions
|
||||
public static final BooleanFlagField IS_NEGATED = FlagField.booleanFirst();
|
||||
public static final BooleanFlagField IS_NULL_CHECK_PREDICATE = FlagField.booleanAfter(IS_NEGATED);
|
||||
|
||||
|
||||
// ---
|
||||
|
||||
public static int getTypeFlags(boolean isSuspend) {
|
||||
@@ -217,6 +222,14 @@ public class Flags {
|
||||
;
|
||||
}
|
||||
|
||||
public static int getContractExpressionFlags(
|
||||
@NotNull boolean isNegated,
|
||||
@NotNull boolean isNullCheckPredicate
|
||||
) {
|
||||
return IS_NEGATED.toFlags(isNegated)
|
||||
| IS_NULL_CHECK_PREDICATE.toFlags(isNullCheckPredicate);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static ProtoBuf.Visibility visibility(@NotNull Visibility visibility) {
|
||||
if (visibility == Visibilities.INTERNAL) {
|
||||
@@ -339,6 +352,8 @@ public class Flags {
|
||||
public int toFlags(Boolean value) {
|
||||
return value ? 1 << offset : 0;
|
||||
}
|
||||
|
||||
public int invert(int flags) { return (flags ^ (1 << offset)); }
|
||||
}
|
||||
|
||||
private static class EnumLiteFlagField<E extends Internal.EnumLite> extends FlagField<E> {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.serialization.deserialization
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.serialization.ProtoBuf
|
||||
|
||||
interface ContractDeserializer {
|
||||
fun deserializeContractFromFunction(
|
||||
proto: ProtoBuf.Function,
|
||||
ownerFunction: FunctionDescriptor,
|
||||
typeTable: TypeTable,
|
||||
typeDeserializer: TypeDeserializer
|
||||
): Pair<FunctionDescriptor.UserDataKey<*>, ContractProvider>?
|
||||
|
||||
companion object {
|
||||
val DEFAULT = object : ContractDeserializer {
|
||||
override fun deserializeContractFromFunction(
|
||||
proto: ProtoBuf.Function,
|
||||
ownerFunction: FunctionDescriptor,
|
||||
typeTable: TypeTable,
|
||||
typeDeserializer: TypeDeserializer
|
||||
): Pair<FunctionDescriptor.UserDataKey<*>, Nothing>? = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface ContractProvider
|
||||
+6
@@ -26,5 +26,11 @@ interface DeserializationConfiguration {
|
||||
val isJvmPackageNameSupported: Boolean
|
||||
get() = true
|
||||
|
||||
val returnsEffectAllowed: Boolean
|
||||
get() = false
|
||||
|
||||
val callsInPlaceEffectAllowed: Boolean
|
||||
get() = false
|
||||
|
||||
object Default : DeserializationConfiguration
|
||||
}
|
||||
|
||||
+9
-1
@@ -162,6 +162,7 @@ class MemberDeserializer(private val c: DeserializationContext) {
|
||||
c.containerSource
|
||||
)
|
||||
val local = c.childContext(function, proto.typeParameterList)
|
||||
|
||||
function.initialize(
|
||||
proto.receiverType(c.typeTable)?.let { local.typeDeserializer.type(it, receiverAnnotations) },
|
||||
getDispatchReceiverParameter(),
|
||||
@@ -169,7 +170,8 @@ class MemberDeserializer(private val c: DeserializationContext) {
|
||||
local.memberDeserializer.valueParameters(proto.valueParameterList, proto, AnnotatedCallableKind.FUNCTION),
|
||||
local.typeDeserializer.type(proto.returnType(c.typeTable)),
|
||||
Deserialization.modality(Flags.MODALITY.get(flags)),
|
||||
Deserialization.visibility(Flags.VISIBILITY.get(flags))
|
||||
Deserialization.visibility(Flags.VISIBILITY.get(flags)),
|
||||
emptyMap<FunctionDescriptor.UserDataKey<*>, Any?>()
|
||||
)
|
||||
function.isOperator = Flags.IS_OPERATOR.get(flags)
|
||||
function.isInfix = Flags.IS_INFIX.get(flags)
|
||||
@@ -178,6 +180,12 @@ class MemberDeserializer(private val c: DeserializationContext) {
|
||||
function.isTailrec = Flags.IS_TAILREC.get(flags)
|
||||
function.isSuspend = Flags.IS_SUSPEND.get(flags)
|
||||
function.isExpect = Flags.IS_EXPECT_FUNCTION.get(flags)
|
||||
|
||||
val mapValueForContract = c.components.contractDeserializer.deserializeContractFromFunction(proto, function, c.typeTable, c.typeDeserializer)
|
||||
if (mapValueForContract != null) {
|
||||
function.putInUserDataMap(mapValueForContract.first, mapValueForContract.second)
|
||||
}
|
||||
|
||||
return function
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -58,7 +58,9 @@ class MetadataPackageFragmentProvider(
|
||||
LookupTracker.DO_NOTHING,
|
||||
FlexibleTypeDeserializer.ThrowException,
|
||||
emptyList(),
|
||||
notFoundClasses, AdditionalClassPartsProvider.None, PlatformDependentDeclarationFilter.All
|
||||
notFoundClasses,
|
||||
ContractDeserializer.DEFAULT,
|
||||
AdditionalClassPartsProvider.None, PlatformDependentDeclarationFilter.All
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ class DeserializationComponents(
|
||||
val flexibleTypeDeserializer: FlexibleTypeDeserializer,
|
||||
val fictitiousClassDescriptorFactories: Iterable<ClassDescriptorFactory>,
|
||||
val notFoundClasses: NotFoundClasses,
|
||||
val contractDeserializer: ContractDeserializer,
|
||||
val additionalClassPartsProvider: AdditionalClassPartsProvider = AdditionalClassPartsProvider.None,
|
||||
val platformDependentDeclarationFilter: PlatformDependentDeclarationFilter = PlatformDependentDeclarationFilter.All
|
||||
) {
|
||||
|
||||
+3
-1
@@ -35,6 +35,7 @@ import org.jetbrains.kotlin.resolve.TargetPlatform
|
||||
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
|
||||
import org.jetbrains.kotlin.serialization.ClassDataWithSource
|
||||
import org.jetbrains.kotlin.serialization.deserialization.ClassDataFinder
|
||||
import org.jetbrains.kotlin.serialization.deserialization.ContractDeserializer
|
||||
import org.jetbrains.kotlin.serialization.deserialization.DeserializationComponents
|
||||
import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfiguration
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPackageMemberScope
|
||||
@@ -68,7 +69,8 @@ class DeserializerForClassfileDecompiler(
|
||||
deserializationComponents = DeserializationComponents(
|
||||
storageManager, moduleDescriptor, DeserializationConfiguration.Default, classDataFinder, annotationAndConstantLoader,
|
||||
packageFragmentProvider, ResolveEverythingToKotlinAnyLocalClassifierResolver(builtIns), LoggingErrorReporter(LOG),
|
||||
LookupTracker.DO_NOTHING, JavaFlexibleTypeDeserializer, emptyList(), notFoundClasses
|
||||
LookupTracker.DO_NOTHING, JavaFlexibleTypeDeserializer, emptyList(), notFoundClasses,
|
||||
ContractDeserializer.DEFAULT
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -51,7 +51,8 @@ class KotlinMetadataDeserializerForDecompiler(
|
||||
storageManager, moduleDescriptor, DeserializationConfiguration.Default, ProtoBasedClassDataFinder(proto, nameResolver),
|
||||
AnnotationAndConstantLoaderImpl(moduleDescriptor, notFoundClasses, serializerProtocol), packageFragmentProvider,
|
||||
ResolveEverythingToKotlinAnyLocalClassifierResolver(builtIns), LoggingErrorReporter(LOG),
|
||||
LookupTracker.DO_NOTHING, flexibleTypeDeserializer, emptyList(), notFoundClasses
|
||||
LookupTracker.DO_NOTHING, flexibleTypeDeserializer, emptyList(), notFoundClasses,
|
||||
ContractDeserializer.DEFAULT
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+2
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.serialization.js
|
||||
|
||||
import org.jetbrains.kotlin.contracts.ContractDeserializerImpl
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.NotFoundClasses
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
|
||||
@@ -58,6 +59,7 @@ fun createKotlinJavascriptPackageFragmentProvider(
|
||||
DynamicTypeDeserializer,
|
||||
emptyList(),
|
||||
notFoundClasses,
|
||||
ContractDeserializerImpl(configuration),
|
||||
platformDependentDeclarationFilter = PlatformDependentDeclarationFilter.NoPlatformDependent
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user