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:
@@ -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
|
||||
) {
|
||||
|
||||
Reference in New Issue
Block a user