[FIR] Fix transforming value parameters of anonymous functions

This commit is contained in:
Dmitriy Novozhilov
2019-08-19 18:24:14 +03:00
parent d841090866
commit e3e1f3c2aa
18 changed files with 117 additions and 35 deletions
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirConstructor
import org.jetbrains.kotlin.fir.declarations.FirFunction
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
import org.jetbrains.kotlin.fir.declarations.impl.FirAbstractCallableMember
@@ -17,7 +18,9 @@ import org.jetbrains.kotlin.fir.declarations.impl.FirConstructorImpl.Companion.N
import org.jetbrains.kotlin.fir.expressions.FirBlock
import org.jetbrains.kotlin.fir.expressions.FirDelegatedConstructorCall
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
import org.jetbrains.kotlin.fir.transformInplace
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.visitors.FirTransformer
class FirJavaConstructor(
session: FirSession,
@@ -51,4 +54,9 @@ class FirJavaConstructor(
get() = null
override val valueParameters = mutableListOf<FirValueParameter>()
override fun <D> transformValueParameters(transformer: FirTransformer<D>, data: D): FirFunction {
valueParameters.transformInplace(transformer, data)
return this
}
}
@@ -276,7 +276,7 @@ open class FirBodyResolveTransformer(
it.type, it, anonymousFunction
)
}
var af = super.transformAnonymousFunction(anonymousFunction, data).single as FirAnonymousFunction
var af = anonymousFunction
val valueParameters =
if (resolvedLambdaAtom == null) af.valueParameters
else {
@@ -314,14 +314,20 @@ open class FirBodyResolveTransformer(
}
}
val returnTypeRefFromResolvedAtom = resolvedLambdaAtom?.returnType?.let { af.returnTypeRef.resolvedTypeFromPrototype(it) }
af = af.copy(
receiverTypeRef = af.receiverTypeRef?.takeIf { it !is FirImplicitTypeRef }
?: resolvedLambdaAtom?.receiver?.let { af.receiverTypeRef?.resolvedTypeFromPrototype(it) },
valueParameters = valueParameters,
returnTypeRef = (af.returnTypeRef as? FirResolvedTypeRef)
?: resolvedLambdaAtom?.returnType?.let { af.returnTypeRef.resolvedTypeFromPrototype(it) }
?: af.body?.resultType?.takeIf { af.returnTypeRef is FirImplicitTypeRef }
?: FirErrorTypeRefImpl(af.psi, "No result type for lambda")
?: returnTypeRefFromResolvedAtom
?: af.returnTypeRef
)
af = af.transformValueParameters(ImplicitToErrorTypeTransformer, null) as FirAnonymousFunction
val bodyExpectedType = returnTypeRefFromResolvedAtom ?: data
af = super.transformAnonymousFunction(af, bodyExpectedType).single as FirAnonymousFunction
af = af.copy(
returnTypeRef = af.body?.resultType ?: FirErrorTypeRefImpl(af.psi, "No result type for lambda")
)
af.replaceTypeRef(af.constructFunctionalTypeRef(session))
af.compose()
@@ -332,6 +338,22 @@ open class FirBodyResolveTransformer(
}
}
private object ImplicitToErrorTypeTransformer : FirTransformer<Nothing?>() {
override fun <E : FirElement> transformElement(element: E, data: Nothing?): CompositeTransformResult<E> {
return element.compose()
}
override fun transformValueParameter(valueParameter: FirValueParameter, data: Nothing?): CompositeTransformResult<FirDeclaration> {
if (valueParameter.returnTypeRef is FirImplicitTypeRef) {
valueParameter.transformReturnTypeRef(
StoreType,
valueParameter.returnTypeRef.resolvedTypeFromPrototype(ConeKotlinErrorType("No type for parameter"))
)
}
return valueParameter.compose()
}
}
private fun transformAnonymousFunctionWithLambdaResolution(
anonymousFunction: FirAnonymousFunction, lambdaResolution: LambdaResolution
): FirAnonymousFunction {
+2 -2
View File
@@ -13,12 +13,12 @@ FILE: cast.kt
}
public get(): R|kotlin/Function0<kotlin/Unit>|
public final val h: R|kotlin/Function1<kotlin/String, kotlin/Boolean>| = fun R|kotlin/Function1<kotlin/String, kotlin/Boolean>|.<anonymous>(_: R|kotlin/String|): R|kotlin/Function1<kotlin/String, kotlin/Boolean>| {
public final val h: R|kotlin/Function1<kotlin/String, kotlin/Boolean>| = fun <anonymous>(_: R|kotlin/String|): R|kotlin/Boolean| {
Boolean(false)
}
public get(): R|kotlin/Function1<kotlin/String, kotlin/Boolean>|
public final val hError: R|kotlin/Function1<class error: No type for parameter, kotlin/Boolean>| = fun <anonymous>(_: <implicit>): R|kotlin/Boolean| {
public final val hError: R|kotlin/Function1<class error: No type for parameter, kotlin/Boolean>| = fun <anonymous>(_: R|class error: No type for parameter|): R|kotlin/Boolean| {
Boolean(true)
}
+3 -3
View File
@@ -1,11 +1,11 @@
FILE: functionX.kt
public final val x: R|kotlin/jvm/functions/Function0<kotlin/Int>| = fun R|kotlin/jvm/functions/Function0<kotlin/Int>|.<anonymous>(): R|kotlin/jvm/functions/Function0<kotlin/Int>| {
public final val x: R|kotlin/jvm/functions/Function0<kotlin/Int>| = fun <anonymous>(): R|kotlin/jvm/functions/Function0<kotlin/Int>| {
Int(42)
}
public get(): R|kotlin/jvm/functions/Function0<kotlin/Int>|
public final val y: R|kotlin/Function1<kotlin/String, kotlin/String>| = fun R|kotlin/Function1<kotlin/String, kotlin/String>|.<anonymous>(it: R|kotlin/String|): R|kotlin/Function1<kotlin/String, kotlin/String>| {
<Unresolved name: it>#
public final val y: R|kotlin/Function1<kotlin/String, kotlin/String>| = fun <anonymous>(it: R|kotlin/String|): R|kotlin/String| {
R|<local>/it|
}
public get(): R|kotlin/Function1<kotlin/String, kotlin/String>|
@@ -33,4 +33,6 @@ abstract class FirAnonymousFunction(
typeRef.accept(visitor, data)
// Don't call super<FirExpression>.acceptChildren (annotations & typeRef are already processed)
}
abstract fun replaceReceiverTypeRef(receiverTypeRef: FirTypeRef)
}
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.fir.FirTargetElement
import org.jetbrains.kotlin.fir.VisitedSupertype
import org.jetbrains.kotlin.fir.expressions.FirAnnotationContainer
import org.jetbrains.kotlin.fir.expressions.FirStatement
import org.jetbrains.kotlin.fir.visitors.FirTransformer
import org.jetbrains.kotlin.fir.visitors.FirVisitor
// May be should inherit FirTypeParameterContainer
@@ -25,4 +26,6 @@ interface FirFunction : @VisitedSupertype FirDeclarationWithBody, FirAnnotationC
}
super<FirDeclarationWithBody>.acceptChildren(visitor, data)
}
fun <D> transformValueParameters(transformer: FirTransformer<D>, data: D): FirFunction
}
@@ -41,4 +41,13 @@ class FirAnonymousFunctionImpl(
override fun <D> transformReturnTypeRef(transformer: FirTransformer<D>, data: D) {
returnTypeRef = returnTypeRef.transformSingle(transformer, data)
}
override fun replaceReceiverTypeRef(receiverTypeRef: FirTypeRef) {
this.receiverTypeRef = receiverTypeRef
}
override fun <D> transformValueParameters(transformer: FirTransformer<D>, data: D): FirAnonymousFunction {
valueParameters.transformInplace(transformer, data)
return this
}
}
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.fir.transformInplace
import org.jetbrains.kotlin.fir.transformSingle
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.visitors.FirTransformer
import org.jetbrains.kotlin.fir.visitors.FirVisitor
import org.jetbrains.kotlin.name.Name
open class FirConstructorImpl : FirAbstractCallableMember<FirConstructor>, FirConstructor {
@@ -71,6 +72,20 @@ open class FirConstructorImpl : FirAbstractCallableMember<FirConstructor>, FirCo
return this
}
override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {
annotations.forEach { it.accept(visitor, data) }
valueParameters.forEach { it.accept(visitor, data) }
returnTypeRef.accept(visitor, data)
status.accept(visitor, data)
delegatedConstructor?.accept(visitor, data)
body?.accept(visitor, data)
}
override fun <D> transformValueParameters(transformer: FirTransformer<D>, data: D): FirConstructorImpl {
valueParameters.transformInplace(transformer, data)
return this
}
companion object {
val NAME = Name.special("<init>")
}
@@ -45,6 +45,10 @@ abstract class FirDefaultPropertyAccessor(
override fun <D> transformReturnTypeRef(transformer: FirTransformer<D>, data: D) {
returnTypeRef = returnTypeRef.transformSingle(transformer, data)
}
override fun <D> transformValueParameters(transformer: FirTransformer<D>, data: D): FirDefaultPropertyAccessor {
return this
}
}
class FirDefaultPropertyGetter(
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.expressions.FirBlock
import org.jetbrains.kotlin.fir.visitors.FirTransformer
import org.jetbrains.kotlin.fir.visitors.FirVisitor
class FirErrorFunction(
@@ -34,4 +35,8 @@ class FirErrorFunction(
override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R =
super<FirFunction>.accept(visitor, data)
override fun <D> transformValueParameters(transformer: FirTransformer<D>, data: D): FirFunction {
return this
}
}
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirFunction
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.FirBlock
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
@@ -79,4 +80,9 @@ open class FirMemberFunctionImpl : FirAbstractCallableMember<FirNamedFunction>,
return super<FirAbstractCallableMember>.transformChildren(transformer, data)
}
override fun <D> transformValueParameters(transformer: FirTransformer<D>, data: D): FirFunction {
valueParameters.transformInplace(transformer, data)
return this
}
}
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirFunction
import org.jetbrains.kotlin.fir.declarations.FirPropertyAccessor
import org.jetbrains.kotlin.fir.transformSingle
import org.jetbrains.kotlin.fir.types.FirTypeRef
@@ -34,4 +35,8 @@ class FirPropertyAccessorImpl(
override fun <D> transformReturnTypeRef(transformer: FirTransformer<D>, data: D) {
returnTypeRef = returnTypeRef.transformSingle(transformer, data)
}
override fun <D> transformValueParameters(transformer: FirTransformer<D>, data: D): FirFunction {
return this
}
}
@@ -4,8 +4,8 @@ FILE fqName:<root> fileName:/lambdaInDataClassDefaultParameter.kt
CONSTRUCTOR visibility:public <> (runA:kotlin.Function2<<root>.A, kotlin.String, kotlin.Unit>) returnType:<root>.A [primary]
VALUE_PARAMETER name:runA index:0 type:kotlin.Function2<<root>.A, kotlin.String, kotlin.Unit>
EXPRESSION_BODY
FUN_EXPR type=kotlin.Function1<kotlin.Function2<<root>.A, kotlin.String, kotlin.Unit>, kotlin.Function2<<root>.A, kotlin.String, kotlin.Unit>> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> () returnType:kotlin.Function2<<root>.A, kotlin.String, kotlin.Unit>
FUN_EXPR type=kotlin.Function0<kotlin.Unit> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> () returnType:kotlin.Unit
BLOCK_BODY
GET_OBJECT 'CLASS IR_EXTERNAL_DECLARATION_STUB OBJECT name:Unit modality:FINAL visibility:public superTypes:[kotlin.Any]' type=kotlin.Unit
BLOCK_BODY
@@ -2,11 +2,11 @@ FILE fqName:<root> fileName:/lambdas.kt
PROPERTY name:test1 visibility:public modality:FINAL [val]
FIELD PROPERTY_BACKING_FIELD name:test1 type:kotlin.Function1<kotlin.String, kotlin.String> visibility:public [final,static]
EXPRESSION_BODY
FUN_EXPR type=kotlin.Function2<kotlin.Function1<kotlin.String, kotlin.String>, kotlin.String, kotlin.Function1<kotlin.String, kotlin.String>> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> (it:kotlin.String) returnType:kotlin.Function1<kotlin.String, kotlin.String>
FUN_EXPR type=kotlin.Function1<kotlin.String, kotlin.String> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> (it:kotlin.String) returnType:kotlin.String
VALUE_PARAMETER name:it index:0 type:kotlin.String
BLOCK_BODY
ERROR_CALL 'Unresolved reference: <Unresolved name: it>#' type=IrErrorType
GET_VAR 'it: kotlin.String declared in <root>.test1.<anonymous>' type=kotlin.String origin=null
FUN DEFAULT_PROPERTY_ACCESSOR name:<get-test1> visibility:public modality:FINAL <> () returnType:kotlin.Function1<kotlin.String, kotlin.String>
correspondingProperty: PROPERTY name:test1 visibility:public modality:FINAL [val]
BLOCK_BODY
@@ -15,8 +15,8 @@ FILE fqName:<root> fileName:/lambdas.kt
PROPERTY name:test2 visibility:public modality:FINAL [val]
FIELD PROPERTY_BACKING_FIELD name:test2 type:kotlin.Function2<kotlin.Any, kotlin.Any, kotlin.Any> visibility:public [final,static]
EXPRESSION_BODY
FUN_EXPR type=kotlin.Function1<kotlin.Function2<kotlin.Any, kotlin.Any, kotlin.Any>, kotlin.Function2<kotlin.Any, kotlin.Any, kotlin.Any>> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> () returnType:kotlin.Function2<kotlin.Any, kotlin.Any, kotlin.Any>
FUN_EXPR type=kotlin.Function0<IrErrorType> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> () returnType:IrErrorType
BLOCK_BODY
ERROR_CALL 'Unresolved reference: <Unresolved name: hashCode>#' type=IrErrorType
FUN DEFAULT_PROPERTY_ACCESSOR name:<get-test2> visibility:public modality:FINAL <> () returnType:kotlin.Function2<kotlin.Any, kotlin.Any, kotlin.Any>
@@ -2,10 +2,10 @@ FILE fqName:<root> fileName:/coercionToUnit.kt
PROPERTY name:test1 visibility:public modality:FINAL [val]
FIELD PROPERTY_BACKING_FIELD name:test1 type:kotlin.Function0<kotlin.Unit> visibility:public [final,static]
EXPRESSION_BODY
FUN_EXPR type=kotlin.Function1<kotlin.Function0<kotlin.Unit>, kotlin.Function0<kotlin.Unit>> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> () returnType:kotlin.Function0<kotlin.Unit>
FUN_EXPR type=kotlin.Function0<kotlin.Unit> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> () returnType:kotlin.Unit
BLOCK_BODY
CONST Int type=kotlin.Function0<kotlin.Unit> value=42
CONST Int type=kotlin.Unit value=42
FUN DEFAULT_PROPERTY_ACCESSOR name:<get-test1> visibility:public modality:FINAL <> () returnType:kotlin.Function0<kotlin.Unit>
correspondingProperty: PROPERTY name:test1 visibility:public modality:FINAL [val]
BLOCK_BODY
@@ -3,8 +3,8 @@ FILE fqName:<root> fileName:/variableAsFunctionCall.kt
$receiver: VALUE_PARAMETER name:<this> type:kotlin.String
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun k (): kotlin.Function0<kotlin.String> declared in <root>'
FUN_EXPR type=kotlin.Function1<kotlin.Function0<kotlin.String>, kotlin.Function0<kotlin.String>> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> () returnType:kotlin.Function0<kotlin.String>
FUN_EXPR type=kotlin.Function0<kotlin.String> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> () returnType:kotlin.String
BLOCK_BODY
ERROR_CALL 'Unresolved reference: this#' type=kotlin.String
FUN name:test1 visibility:public modality:FINAL <> (f:kotlin.Function0<kotlin.Unit>) returnType:kotlin.Unit
@@ -4,8 +4,8 @@ FILE fqName:<root> fileName:/variableAsFunctionCallWithGenerics.kt
correspondingProperty: PROPERTY name:gk visibility:public modality:FINAL [val]
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun <get-gk> (): kotlin.Function0<T of <uninitialized parent>> declared in <root>'
FUN_EXPR type=kotlin.Function1<kotlin.Function0<T of <uninitialized parent>>, kotlin.Function0<T of <uninitialized parent>>> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> () returnType:kotlin.Function0<T of <uninitialized parent>>
FUN_EXPR type=kotlin.Function0<IrErrorType> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> () returnType:IrErrorType
BLOCK_BODY
ERROR_CALL 'Unresolved reference: this#' type=IrErrorType
FUN name:testGeneric1 visibility:public modality:FINAL <> (x:kotlin.String) returnType:T of <uninitialized parent>
@@ -19,10 +19,10 @@ FILE fqName:<root> fileName:/variableAsFunctionCallWithGenerics.kt
correspondingProperty: PROPERTY name:kt26531Val visibility:public modality:FINAL [val]
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun <get-kt26531Val> (): kotlin.Function0<T of <uninitialized parent>> declared in <root>'
FUN_EXPR type=kotlin.Function0<kotlin.Function0<T of <uninitialized parent>>> origin=LAMBDA
FUN name:<no name provided> visibility:local modality:FINAL <> () returnType:kotlin.Function0<T of <uninitialized parent>>
FUN_EXPR type=kotlin.Function0<IrErrorType> origin=LAMBDA
FUN name:<no name provided> visibility:local modality:FINAL <> () returnType:IrErrorType
BLOCK_BODY
RETURN type=kotlin.Nothing from='local final fun <no name provided> (): kotlin.Function0<T of <uninitialized parent>> declared in <root>.<get-kt26531Val>'
RETURN type=kotlin.Nothing from='local final fun <no name provided> (): IrErrorType declared in <root>.<get-kt26531Val>'
ERROR_CALL 'Unresolved reference: this#' type=IrErrorType
FUN name:kt26531 visibility:public modality:FINAL <> () returnType:T of <uninitialized parent>
BLOCK_BODY
@@ -64,16 +64,19 @@ FILE fqName:<root> fileName:/destructuringInLambda.kt
PROPERTY name:fn visibility:public modality:FINAL [var]
FIELD PROPERTY_BACKING_FIELD name:fn type:kotlin.Function1<<root>.A, kotlin.Int> visibility:public [static]
EXPRESSION_BODY
FUN_EXPR type=kotlin.Function2<kotlin.Function1<<root>.A, kotlin.Int>, IrErrorType, kotlin.Function1<<root>.A, kotlin.Int>> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> (<destruct>:IrErrorType) returnType:kotlin.Function1<<root>.A, kotlin.Int>
VALUE_PARAMETER name:<destruct> index:0 type:IrErrorType
FUN_EXPR type=kotlin.Function1<<root>.A, kotlin.Int> origin=LAMBDA
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> (<destruct>:<root>.A) returnType:kotlin.Int
VALUE_PARAMETER name:<destruct> index:0 type:<root>.A
BLOCK_BODY
VAR name:_ type:IrErrorType [val]
ERROR_CALL 'Unresolved reference: <Unresolved name: component1>#' type=IrErrorType
VAR name:y type:IrErrorType [val]
ERROR_CALL 'Unresolved reference: <Unresolved name: component2>#' type=IrErrorType
ERROR_CALL 'Unresolved reference: <Ambiguity: plus, [kotlin/Int.plus, kotlin/Int.plus, kotlin/Int.plus, kotlin/Int.plus, kotlin/Int.plus, kotlin/Int.plus]>#' type=IrErrorType
GET_VAR 'val y: IrErrorType [val] declared in <root>.fn.<anonymous>' type=IrErrorType origin=null
VAR name:_ type:kotlin.Int [val]
CALL 'public final fun component1 (): kotlin.Int declared in <root>.A' type=kotlin.Int origin=null
$this: GET_VAR '<destruct>: <root>.A declared in <root>.fn.<anonymous>' type=<root>.A origin=null
VAR name:y type:kotlin.Int [val]
CALL 'public final fun component2 (): kotlin.Int declared in <root>.A' type=kotlin.Int origin=null
$this: GET_VAR '<destruct>: <root>.A declared in <root>.fn.<anonymous>' type=<root>.A origin=null
CALL 'public final fun plus (other: kotlin.Int): kotlin.Int declared in kotlin.Int' type=kotlin.Int origin=null
$this: CONST Int type=kotlin.Int value=42
other: GET_VAR 'val y: kotlin.Int [val] declared in <root>.fn.<anonymous>' type=kotlin.Int origin=null
FUN DEFAULT_PROPERTY_ACCESSOR name:<get-fn> visibility:public modality:FINAL <> () returnType:kotlin.Function1<<root>.A, kotlin.Int>
correspondingProperty: PROPERTY name:fn visibility:public modality:FINAL [var]
BLOCK_BODY