Revert "FIR DFA: store stability in RealVariable"

This reverts commit 62f7e8f7
This commit is contained in:
Dmitriy Novozhilov
2021-06-03 09:53:57 +03:00
parent 796f8e6bce
commit 0497f60af3
9 changed files with 73 additions and 147 deletions
@@ -156,34 +156,30 @@ object FirReturnsImpliesAnalyzer : FirControlFlowChecker() {
variableStorage: VariableStorage,
flow: Flow,
context: CheckerContext
): MutableTypeStatements? {
fun buildTypeStatements(arg: ConeValueParameterReference, exactType: Boolean, type: ConeKotlinType): MutableTypeStatements? {
): MutableTypeStatements? = when (this) {
is ConeBinaryLogicExpression -> {
val left = left.buildTypeStatements(function, logicSystem, variableStorage, flow, context)
val right = right.buildTypeStatements(function, logicSystem, variableStorage, flow, context)
if (left != null && right != null) {
if (kind == LogicOperationKind.AND) {
left.apply { mergeTypeStatements(right) }
} else logicSystem.orForTypeStatements(left, right)
} else (left ?: right)
}
is ConeIsInstancePredicate -> {
val fir = function.getParameterSymbol(arg.parameterIndex, context).fir
val realVar = variableStorage.getOrCreateRealVariable(flow, fir.symbol, fir)
?.takeIf {
it.stability == PropertyStability.STABLE_VALUE ||
// TODO: consider removing the part below
it.stability == PropertyStability.LOCAL_VAR
}
return realVar?.to(simpleTypeStatement(realVar, exactType, type))?.let { mutableMapOf(it) }
realVar?.to(simpleTypeStatement(realVar, !isNegated, type))?.let { mutableMapOf(it) }
}
return when (this) {
is ConeBinaryLogicExpression -> {
val left = left.buildTypeStatements(function, logicSystem, variableStorage, flow, context)
val right = right.buildTypeStatements(function, logicSystem, variableStorage, flow, context)
if (left != null && right != null) {
if (kind == LogicOperationKind.AND) {
left.apply { mergeTypeStatements(right) }
} else logicSystem.orForTypeStatements(left, right)
} else (left ?: right)
}
is ConeIsInstancePredicate -> buildTypeStatements(arg, !isNegated, type)
is ConeIsNullPredicate -> buildTypeStatements(arg, isNegated, context.session.builtinTypes.anyType.type)
is ConeLogicalNot -> arg.buildTypeStatements(function, logicSystem, variableStorage, flow, context)
?.mapValuesTo(mutableMapOf()) { (_, value) -> value.invert() }
is ConeIsNullPredicate -> {
val fir = function.getParameterSymbol(arg.parameterIndex, context).fir
val realVar = variableStorage.getOrCreateRealVariable(flow, fir.symbol, fir)
realVar?.to(simpleTypeStatement(realVar, isNegated, context.session.builtinTypes.anyType.type))?.let { mutableMapOf(it) }
}
is ConeLogicalNot -> arg.buildTypeStatements(function, logicSystem, variableStorage, flow, context)
?.mapValuesTo(mutableMapOf()) { (_, value) -> value.invert() }
else -> null
}
else -> null
}
private fun ConeKotlinType.isInapplicableWith(operation: Operation, session: FirSession): Boolean {
@@ -10,10 +10,7 @@ import org.jetbrains.kotlin.builtins.functions.FunctionClassKind
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.ConeStubDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
import org.jetbrains.kotlin.fir.diagnostics.*
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.builder.*
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
@@ -26,12 +23,12 @@ import org.jetbrains.kotlin.fir.resolve.calls.ImplicitDispatchReceiverValue
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedNameError
import org.jetbrains.kotlin.fir.resolve.inference.inferenceComponents
import org.jetbrains.kotlin.fir.resolve.inference.isBuiltinFunctionalType
import org.jetbrains.kotlin.fir.resolve.providers.getSymbolByTypeRef
import org.jetbrains.kotlin.fir.resolve.providers.*
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType
import org.jetbrains.kotlin.fir.resolve.transformers.ensureResolved
import org.jetbrains.kotlin.fir.scopes.impl.delegatedWrapperData
import org.jetbrains.kotlin.fir.scopes.impl.importedFromObjectData
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.*
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.builder.buildErrorTypeRef
@@ -250,8 +247,7 @@ private fun BodyResolveComponents.typeFromSymbol(symbol: AbstractFirBasedSymbol<
fun BodyResolveComponents.transformQualifiedAccessUsingSmartcastInfo(
qualifiedAccessExpression: FirQualifiedAccessExpression
): FirQualifiedAccessExpression {
val (stability, typesFromSmartCast) = dataFlowAnalyzer.getTypeUsingSmartcastInfo(qualifiedAccessExpression)
?: return qualifiedAccessExpression
val typesFromSmartCast = dataFlowAnalyzer.getTypeUsingSmartcastInfo(qualifiedAccessExpression) ?: return qualifiedAccessExpression
val originalType = qualifiedAccessExpression.resultType.coneType
// For example, if (x == null) { ... },
// we don't want to smartcast to Nothing?, but we want to record the nullability to its own kind of node.
@@ -272,11 +268,9 @@ fun BodyResolveComponents.transformQualifiedAccessUsingSmartcastInfo(
return buildExpressionWithSmartcastToNull {
originalExpression = qualifiedAccessExpression
// TODO: Use Nothing? during resolution?
smartcastType = intersectedTypeRefWithoutNullableNothing
typeRef = intersectedTypeRefWithoutNullableNothing
// NB: Nothing? in types from smartcast in DFA is recorded here (and the expression kind itself).
this.typesFromSmartCast = typesFromSmartCast
// TODO: differentiate capture local variable
this.smartcastStability = stability.impliedSmartcastStability ?: SmartcastStability.STABLE_VALUE
}
}
val allTypes = typesFromSmartCast.also {
@@ -294,8 +288,7 @@ fun BodyResolveComponents.transformQualifiedAccessUsingSmartcastInfo(
originalExpression = qualifiedAccessExpression
smartcastType = intersectedTypeRef
this.typesFromSmartCast = typesFromSmartCast
// TODO: differentiate capture local variable
this.smartcastStability = stability.impliedSmartcastStability ?: SmartcastStability.STABLE_VALUE
smartcastStability = SmartcastStability.STABLE_VALUE
}
}
@@ -162,7 +162,7 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
// ----------------------------------- Requests -----------------------------------
fun getTypeUsingSmartcastInfo(qualifiedAccessExpression: FirQualifiedAccessExpression): Pair<PropertyStability, MutableList<ConeKotlinType>>? {
fun getTypeUsingSmartcastInfo(qualifiedAccessExpression: FirQualifiedAccessExpression): MutableList<ConeKotlinType>? {
/*
* DataFlowAnalyzer holds variables only for declarations that have some smartcast (or can have)
* If there is no useful information there is no data flow variable also
@@ -170,14 +170,13 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
val symbol: AbstractFirBasedSymbol<*> = qualifiedAccessExpression.symbol ?: return null
val flow = graphBuilder.lastNode.flow
var variable = variableStorage.getRealVariableWithoutUnwrappingAlias(symbol, qualifiedAccessExpression, flow) ?: return null
val stability = variable.stability
val result = mutableListOf<ConeKotlinType>()
flow.directAliasMap[variable]?.let {
result.addIfNotNull(it.originalType)
variable = it.variable
}
flow.getTypeStatement(variable)?.exactType?.let { result += it }
return result.takeIf { it.isNotEmpty() }?.let { stability to it }
return result.takeIf { it.isNotEmpty() }
}
fun returnExpressionsOfAnonymousFunction(function: FirAnonymousFunction): Collection<FirStatement> {
@@ -1010,12 +1009,7 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
assignment: FirVariableAssignment?
) {
val flow = node.flow
val propertyVariable = variableStorage.getOrCreateRealVariableWithoutUnwrappingAlias(
flow,
property.symbol,
assignment ?: property,
if (property.isVal) PropertyStability.STABLE_VALUE else PropertyStability.LOCAL_VAR
)
val propertyVariable = variableStorage.getOrCreateRealVariableWithoutUnwrappingAlias(flow, property.symbol, assignment ?: property)
val isAssignment = assignment != null
if (isAssignment) {
logicSystem.removeLocalVariableAlias(flow, propertyVariable)
@@ -1023,21 +1017,13 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
logicSystem.recordNewAssignment(flow, propertyVariable, context.newAssignmentIndex())
}
variableStorage.getOrCreateRealVariable(flow, initializer.symbol, initializer)
?.let { initializerVariable ->
// TODO: handle capture variable
if ((initializerVariable.stability == PropertyStability.STABLE_VALUE || initializerVariable.stability == PropertyStability.LOCAL_VAR) &&
(propertyVariable.stability == PropertyStability.STABLE_VALUE || propertyVariable.stability == PropertyStability.LOCAL_VAR)
) {
logicSystem.addLocalVariableAlias(
flow, propertyVariable,
RealVariableAndType(initializerVariable, initializer.coneType)
)
// node.flow.addImplication((propertyVariable notEq null) implies (initializerVariable notEq null))
} else {
logicSystem.replaceVariableFromConditionInStatements(flow, initializerVariable, propertyVariable)
}
}
variableStorage.getOrCreateRealVariable(flow, initializer.symbol, initializer)?.let { initializerVariable ->
logicSystem.addLocalVariableAlias(
flow, propertyVariable,
RealVariableAndType(initializerVariable, initializer.coneType)
)
// node.flow.addImplication((propertyVariable notEq null) implies (initializerVariable notEq null))
}
variableStorage.getSyntheticVariable(initializer)?.let { initializerVariable ->
/*
@@ -8,9 +8,7 @@ package org.jetbrains.kotlin.fir.resolve.dfa
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirAnonymousObject
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor
import org.jetbrains.kotlin.fir.declarations.modality
import org.jetbrains.kotlin.fir.expressions.*
@@ -36,24 +34,14 @@ class VariableStorage(private val session: FirSession) {
fun clear(): VariableStorage = VariableStorage(session)
fun getOrCreateRealVariableWithoutUnwrappingAlias(
flow: Flow,
symbol: AbstractFirBasedSymbol<*>,
fir: FirElement,
stability: PropertyStability
): RealVariable {
fun getOrCreateRealVariableWithoutUnwrappingAlias(flow: Flow, symbol: AbstractFirBasedSymbol<*>, fir: FirElement): RealVariable {
val realFir = fir.unwrapElement()
val identifier = getIdentifierBySymbol(flow, symbol, realFir)
return _realVariables.getOrPut(identifier) { createRealVariableInternal(flow, identifier, realFir, stability) }
return _realVariables.getOrPut(identifier) { createRealVariableInternal(flow, identifier, realFir) }
}
private fun getOrCreateRealVariable(
flow: Flow,
symbol: AbstractFirBasedSymbol<*>,
fir: FirElement,
stability: PropertyStability
): RealVariable {
val variable = getOrCreateRealVariableWithoutUnwrappingAlias(flow, symbol, fir, stability)
private fun getOrCreateRealVariable(flow: Flow, symbol: AbstractFirBasedSymbol<*>, fir: FirElement): RealVariable {
val variable = getOrCreateRealVariableWithoutUnwrappingAlias(flow, symbol, fir)
return flow.directAliasMap[variable]?.variable ?: variable
}
@@ -81,12 +69,7 @@ class VariableStorage(private val session: FirSession) {
/**
* [originalFir] used for extracting expression under <when_subject> and extracting receiver
*/
private fun createRealVariableInternal(
flow: Flow,
identifier: Identifier,
originalFir: FirElement,
stability: PropertyStability
): RealVariable {
private fun createRealVariableInternal(flow: Flow, identifier: Identifier, originalFir: FirElement): RealVariable {
val receiver: FirExpression?
val isThisReference: Boolean
val expression: FirQualifiedAccess? = when (originalFir) {
@@ -105,12 +88,12 @@ class VariableStorage(private val session: FirSession) {
}
val receiverVariable = receiver?.let { getOrCreateVariable(flow, it) }
return RealVariable(identifier, isThisReference, receiverVariable, counter++, stability)
return RealVariable(identifier, isThisReference, receiverVariable, counter++)
}
@JvmName("getOrCreateRealVariableOrNull")
fun getOrCreateRealVariable(flow: Flow, symbol: AbstractFirBasedSymbol<*>?, fir: FirElement): RealVariable? =
symbol.getStability(fir)?.let { getOrCreateRealVariable(flow, symbol!!, fir, it) }
symbol.takeIf { it.isStable(fir) }?.let { getOrCreateRealVariable(flow, it, fir) }
fun createSyntheticVariable(fir: FirElement): SyntheticVariable =
SyntheticVariable(fir, counter++).also { syntheticVariables[fir] = it }
@@ -118,9 +101,8 @@ class VariableStorage(private val session: FirSession) {
fun getOrCreateVariable(flow: Flow, fir: FirElement): DataFlowVariable {
val realFir = fir.unwrapElement()
val symbol = realFir.symbol
val stability = symbol.getStability(realFir)
return if (stability != null) {
getOrCreateRealVariable(flow, symbol!!, realFir, stability)
return if (symbol.isStable(realFir)) {
getOrCreateRealVariable(flow, symbol!!, realFir)
} else {
syntheticVariables[realFir] ?: createSyntheticVariable(realFir)
}
@@ -128,7 +110,7 @@ class VariableStorage(private val session: FirSession) {
fun getRealVariableWithoutUnwrappingAlias(symbol: AbstractFirBasedSymbol<*>?, fir: FirElement, flow: Flow): RealVariable? {
val realFir = fir.unwrapElement()
return symbol.takeIf { it.getStability(realFir) != null }?.let {
return symbol.takeIf { it.isStable(realFir) }?.let {
_realVariables[getIdentifierBySymbol(flow, it, realFir.unwrapElement())]
}
}
@@ -144,8 +126,7 @@ class VariableStorage(private val session: FirSession) {
fun getVariable(fir: FirElement, flow: Flow): DataFlowVariable? {
val realFir = fir.unwrapElement()
val symbol = realFir.symbol
val stability = symbol.getStability(fir)
return if (stability != null) {
return if (symbol.isStable(fir)) {
getRealVariable(symbol, realFir, flow)
} else {
getSyntheticVariable(fir)
@@ -162,40 +143,39 @@ class VariableStorage(private val session: FirSession) {
}
@OptIn(ExperimentalContracts::class)
fun AbstractFirBasedSymbol<*>?.getStability(originalFir: FirElement): PropertyStability? {
fun AbstractFirBasedSymbol<*>?.isStable(originalFir: FirElement): Boolean {
contract {
returnsNotNull() implies (this@getStability != null)
returns(true) implies(this@isStable != null)
}
when (this) {
is FirAnonymousObjectSymbol -> return null
is FirAnonymousObjectSymbol -> return false
is FirFunctionSymbol<*>,
is FirClassSymbol<*>,
is FirBackingFieldSymbol -> return PropertyStability.STABLE_VALUE
null -> return null
is FirBackingFieldSymbol -> return true
null -> return false
}
if (originalFir is FirThisReceiverExpression) return PropertyStability.STABLE_VALUE
if (this !is FirVariableSymbol<*>) return null
if (originalFir is FirThisReceiverExpression) return true
if (this !is FirVariableSymbol<*>) return false
val property = this.fir as? FirProperty ?: return PropertyStability.STABLE_VALUE
val property = this.fir as? FirProperty ?: return true
return when {
property.delegate != null -> PropertyStability.DELEGATED_PROPERTY
property.isLocal -> if (property.isVal) PropertyStability.STABLE_VALUE else PropertyStability.LOCAL_VAR
property.isVar -> PropertyStability.MUTABLE_PROPERTY
property.receiverTypeRef != null -> PropertyStability.PROPERTY_WITH_GETTER
property.getter.let { it != null && it !is FirDefaultPropertyAccessor } -> PropertyStability.PROPERTY_WITH_GETTER
property.moduleData.session != session -> PropertyStability.ALIEN_PUBLIC_PROPERTY
property.isLocal -> true
property.isVar -> false
property.receiverTypeRef != null -> false
property.getter.let { it != null && it !is FirDefaultPropertyAccessor } -> false
property.modality != Modality.FINAL -> {
val dispatchReceiver = (originalFir.unwrapElement() as? FirQualifiedAccess)?.dispatchReceiver ?: return null
val receiverType = dispatchReceiver.typeRef.coneTypeSafe<ConeClassLikeType>()?.fullyExpandedType(session) ?: return null
val receiverSymbol = receiverType.lookupTag.toSymbol(session) ?: return null
val dispatchReceiver = (originalFir.unwrapElement() as? FirQualifiedAccess)?.dispatchReceiver ?: return false
val receiverType = dispatchReceiver.typeRef.coneTypeSafe<ConeClassLikeType>()?.fullyExpandedType(session) ?: return false
val receiverSymbol = receiverType.lookupTag.toSymbol(session) ?: return false
when (val receiverFir = receiverSymbol.fir) {
is FirAnonymousObject -> PropertyStability.STABLE_VALUE
is FirRegularClass -> if (receiverFir.modality == Modality.FINAL) PropertyStability.STABLE_VALUE else PropertyStability.PROPERTY_WITH_GETTER
is org.jetbrains.kotlin.fir.declarations.FirAnonymousObject -> true
is org.jetbrains.kotlin.fir.declarations.FirRegularClass -> receiverFir.modality == Modality.FINAL
else -> throw IllegalStateException("Should not be here: $receiverFir")
}
}
else -> PropertyStability.STABLE_VALUE
else -> true
}
}
}
@@ -11,7 +11,6 @@ import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.types.ConeClassErrorType
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.types.SmartcastStability
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract
@@ -34,37 +33,11 @@ sealed class DataFlowVariable(private val variableIndexForDebug: Int) {
}
}
enum class PropertyStability(val impliedSmartcastStability: SmartcastStability?) {
// Immutable and no custom getter or local.
// Smartcast is definitely safe regardless of usage.
STABLE_VALUE(SmartcastStability.STABLE_VALUE),
// Open or custom getter.
// Smartcast is always unsafe regardless of usage.
PROPERTY_WITH_GETTER(SmartcastStability.PROPERTY_WITH_GETTER),
// Protected / public member value from another module.
// Smartcast is always unsafe regardless of usage.
ALIEN_PUBLIC_PROPERTY(SmartcastStability.ALIEN_PUBLIC_PROPERTY),
// Smartcast may or may not be safe, depending on whether there are concurrent writes to this local variable.
LOCAL_VAR(null),
// Mutable member property of a class or object.
// Smartcast is always unsafe regardless of usage.
MUTABLE_PROPERTY(SmartcastStability.MUTABLE_PROPERTY),
// Delegated property of a class or object.
// Smartcast is always unsafe regardless of usage.
DELEGATED_PROPERTY(SmartcastStability.DELEGATED_PROPERTY),
}
class RealVariable(
val identifier: Identifier,
val isThisReference: Boolean,
val explicitReceiverVariable: DataFlowVariable?,
variableIndexForDebug: Int,
val stability: PropertyStability,
variableIndexForDebug: Int
) : DataFlowVariable(variableIndexForDebug) {
override fun equals(other: Any?): Boolean {
return this === other
@@ -467,8 +467,6 @@ object NodeConfigurator : AbstractFieldConfigurator<FirTreeBuilder>(FirTreeBuild
+field("originalExpression", qualifiedAccessExpression)
+field("typesFromSmartCast", "Collection<ConeKotlinType>", null, customType = coneKotlinTypeType)
+field("originalType", typeRef)
+field("smartcastType", typeRef)
+smartcastStability
}
safeCallExpression.configure {
@@ -14,13 +14,13 @@ fun test(u: A?, x: A?, y: A?, z: A?, w: A, v: A?) {
u!!.b<!UNNECESSARY_SAFE_CALL!>?.<!>foo()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
x?.b!!.foo()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
// x?.b is not null
x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.b<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.foo()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
x!!.b<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.foo()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
y?.nb?.foo()!!
y!!.nb?.foo()!!
z?.nb!!.foo()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
// z?.nb is not null
z<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.nb!!.foo()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
z!!.nb!!.foo()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
w.b<!UNNECESSARY_SAFE_CALL!>?.<!>foo()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
w.b<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.foo()<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
@@ -17,7 +17,7 @@ import a.X
public fun X.gav(): Int {
if (x != null)
// Smart cast is not possible if definition is in another module
return x<!UNSAFE_CALL!>.<!>length
return x.length
else
return 0
}
@@ -29,7 +29,7 @@ package a
public fun X.gav(): Int {
if (x != null)
// Even if it's in the same package
return x<!UNSAFE_CALL!>.<!>length
return x.length
else
return 0
}
@@ -33,7 +33,7 @@ fun case_3(x: Int) = ""
fun case_3(x: Int?) = 10
fun case_3() {
if (case_3_prop != null) {
val z = case_3(<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int? & kotlin.Int?")!>case_3_prop<!>)
val z = case_3(<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int?")!>case_3_prop<!>)
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int")!>z<!>
}
}
@@ -89,7 +89,7 @@ fun case_7(x: Int) = ""
fun case_7(x: Int?) = 10
fun case_7() {
if (case_7_prop != null) {
val z = case_7(<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int? & kotlin.Int?")!>case_7_prop<!>)
val z = case_7(<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int?")!>case_7_prop<!>)
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int")!>z<!>
}
}