Support isInitialized intrinsic for lateinit properties
See https://github.com/Kotlin/KEEP/pull/73 #KT-9327 Fixed
This commit is contained in:
@@ -1722,7 +1722,8 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
receiver = StackValue.receiverWithoutReceiverArgument(receiver);
|
receiver = StackValue.receiverWithoutReceiverArgument(receiver);
|
||||||
}
|
}
|
||||||
|
|
||||||
return intermediateValueForProperty(propertyDescriptor, directToField, directToField, superCallTarget, false, receiver, resolvedCall);
|
return intermediateValueForProperty(propertyDescriptor, directToField, directToField, superCallTarget, false, receiver,
|
||||||
|
resolvedCall, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (descriptor instanceof TypeAliasDescriptor) {
|
if (descriptor instanceof TypeAliasDescriptor) {
|
||||||
@@ -1874,7 +1875,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
@Nullable ClassDescriptor superCallTarget,
|
@Nullable ClassDescriptor superCallTarget,
|
||||||
@NotNull StackValue receiver
|
@NotNull StackValue receiver
|
||||||
) {
|
) {
|
||||||
return intermediateValueForProperty(propertyDescriptor, forceField, false, superCallTarget, false, receiver, null);
|
return intermediateValueForProperty(propertyDescriptor, forceField, false, superCallTarget, false, receiver, null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CodegenContext getBackingFieldContext(
|
private CodegenContext getBackingFieldContext(
|
||||||
@@ -1892,9 +1893,14 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
return context.getParentContext();
|
return context.getParentContext();
|
||||||
// For companion object property, backing field lives in object containing class
|
// For companion object property, backing field lives in object containing class
|
||||||
// Otherwise, it lives in its containing declaration
|
// Otherwise, it lives in its containing declaration
|
||||||
case IN_CLASS_COMPANION: return context.findParentContextWithDescriptor(containingDeclaration.getContainingDeclaration());
|
case IN_CLASS_COMPANION:
|
||||||
case FIELD_FROM_LOCAL: return context.findParentContextWithDescriptor(containingDeclaration);
|
return context.findParentContextWithDescriptor(containingDeclaration.getContainingDeclaration());
|
||||||
default: throw new IllegalStateException();
|
case FIELD_FROM_LOCAL:
|
||||||
|
return context.findParentContextWithDescriptor(containingDeclaration);
|
||||||
|
case LATEINIT_INTRINSIC:
|
||||||
|
return context.findParentContextWithDescriptor(containingDeclaration);
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("Unknown field accessor kind: " + accessorKind);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1905,7 +1911,8 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
@Nullable ClassDescriptor superCallTarget,
|
@Nullable ClassDescriptor superCallTarget,
|
||||||
boolean skipAccessorsForPrivateFieldInOuterClass,
|
boolean skipAccessorsForPrivateFieldInOuterClass,
|
||||||
@NotNull StackValue receiver,
|
@NotNull StackValue receiver,
|
||||||
@Nullable ResolvedCall resolvedCall
|
@Nullable ResolvedCall resolvedCall,
|
||||||
|
boolean skipLateinitAssertion
|
||||||
) {
|
) {
|
||||||
if (propertyDescriptor instanceof SyntheticJavaPropertyDescriptor) {
|
if (propertyDescriptor instanceof SyntheticJavaPropertyDescriptor) {
|
||||||
return intermediateValueForSyntheticExtensionProperty((SyntheticJavaPropertyDescriptor) propertyDescriptor, receiver);
|
return intermediateValueForSyntheticExtensionProperty((SyntheticJavaPropertyDescriptor) propertyDescriptor, receiver);
|
||||||
@@ -1917,14 +1924,22 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
|
|
||||||
DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration();
|
DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration();
|
||||||
|
|
||||||
FieldAccessorKind fieldAccessorKind = FieldAccessorKind.NORMAL;
|
|
||||||
boolean isBackingFieldInClassCompanion = JvmAbi.isPropertyWithBackingFieldInOuterClass(propertyDescriptor);
|
boolean isBackingFieldInClassCompanion = JvmAbi.isPropertyWithBackingFieldInOuterClass(propertyDescriptor);
|
||||||
if (isBackingFieldInClassCompanion && (forceField || propertyDescriptor.isConst() && Visibilities.isPrivate(propertyDescriptor.getVisibility()))) {
|
FieldAccessorKind fieldAccessorKind;
|
||||||
|
if (skipLateinitAssertion) {
|
||||||
|
fieldAccessorKind = FieldAccessorKind.LATEINIT_INTRINSIC;
|
||||||
|
}
|
||||||
|
else if (isBackingFieldInClassCompanion &&
|
||||||
|
(forceField || propertyDescriptor.isConst() && Visibilities.isPrivate(propertyDescriptor.getVisibility()))) {
|
||||||
fieldAccessorKind = FieldAccessorKind.IN_CLASS_COMPANION;
|
fieldAccessorKind = FieldAccessorKind.IN_CLASS_COMPANION;
|
||||||
}
|
}
|
||||||
else if (syntheticBackingField && context.getFirstCrossInlineOrNonInlineContext().getParentContext().getContextDescriptor() != containingDeclaration) {
|
else if ((syntheticBackingField &&
|
||||||
|
context.getFirstCrossInlineOrNonInlineContext().getParentContext().getContextDescriptor() != containingDeclaration)) {
|
||||||
fieldAccessorKind = FieldAccessorKind.FIELD_FROM_LOCAL;
|
fieldAccessorKind = FieldAccessorKind.FIELD_FROM_LOCAL;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
fieldAccessorKind = FieldAccessorKind.NORMAL;
|
||||||
|
}
|
||||||
boolean isStaticBackingField = DescriptorUtils.isStaticDeclaration(propertyDescriptor) ||
|
boolean isStaticBackingField = DescriptorUtils.isStaticDeclaration(propertyDescriptor) ||
|
||||||
AsmUtil.isInstancePropertyWithStaticBackingField(propertyDescriptor);
|
AsmUtil.isInstancePropertyWithStaticBackingField(propertyDescriptor);
|
||||||
boolean isSuper = superCallTarget != null;
|
boolean isSuper = superCallTarget != null;
|
||||||
@@ -1937,15 +1952,24 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
CallableMethod callableSetter = null;
|
CallableMethod callableSetter = null;
|
||||||
|
|
||||||
CodegenContext backingFieldContext = getBackingFieldContext(fieldAccessorKind, containingDeclaration);
|
CodegenContext backingFieldContext = getBackingFieldContext(fieldAccessorKind, containingDeclaration);
|
||||||
DeclarationDescriptor ownerDescriptor = containingDeclaration;
|
boolean isPrivateProperty = (AsmUtil.getVisibilityForBackingField(propertyDescriptor, isDelegatedProperty) & ACC_PRIVATE) != 0;
|
||||||
|
DeclarationDescriptor ownerDescriptor;
|
||||||
boolean skipPropertyAccessors;
|
boolean skipPropertyAccessors;
|
||||||
|
|
||||||
PropertyDescriptor originalPropertyDescriptor = DescriptorUtils.unwrapFakeOverride(propertyDescriptor);
|
PropertyDescriptor originalPropertyDescriptor = DescriptorUtils.unwrapFakeOverride(propertyDescriptor);
|
||||||
|
|
||||||
if (fieldAccessorKind != FieldAccessorKind.NORMAL) {
|
if (fieldAccessorKind == FieldAccessorKind.LATEINIT_INTRINSIC) {
|
||||||
int flags = AsmUtil.getVisibilityForBackingField(propertyDescriptor, isDelegatedProperty);
|
skipPropertyAccessors = !isPrivateProperty || context.getClassOrPackageParentContext() == backingFieldContext;
|
||||||
|
|
||||||
|
if (!skipPropertyAccessors) {
|
||||||
|
propertyDescriptor = (AccessorForPropertyBackingField)
|
||||||
|
backingFieldContext.getAccessor(propertyDescriptor, fieldAccessorKind, delegateType, superCallTarget);
|
||||||
|
}
|
||||||
|
ownerDescriptor = propertyDescriptor;
|
||||||
|
}
|
||||||
|
else if (fieldAccessorKind == FieldAccessorKind.IN_CLASS_COMPANION || fieldAccessorKind == FieldAccessorKind.FIELD_FROM_LOCAL) {
|
||||||
boolean isInlinedConst = propertyDescriptor.isConst() && state.getShouldInlineConstVals();
|
boolean isInlinedConst = propertyDescriptor.isConst() && state.getShouldInlineConstVals();
|
||||||
skipPropertyAccessors = isInlinedConst || (flags & ACC_PRIVATE) == 0 || skipAccessorsForPrivateFieldInOuterClass;
|
skipPropertyAccessors = isInlinedConst || !isPrivateProperty || skipAccessorsForPrivateFieldInOuterClass;
|
||||||
|
|
||||||
if (!skipPropertyAccessors) {
|
if (!skipPropertyAccessors) {
|
||||||
//noinspection ConstantConditions
|
//noinspection ConstantConditions
|
||||||
@@ -1956,12 +1980,13 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
"Unexpected accessor descriptor: " + propertyDescriptor;
|
"Unexpected accessor descriptor: " + propertyDescriptor;
|
||||||
ownerDescriptor = propertyDescriptor;
|
ownerDescriptor = propertyDescriptor;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
ownerDescriptor = containingDeclaration;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!isBackingFieldInClassCompanion) {
|
|
||||||
ownerDescriptor = propertyDescriptor;
|
|
||||||
}
|
|
||||||
skipPropertyAccessors = forceField;
|
skipPropertyAccessors = forceField;
|
||||||
|
ownerDescriptor = isBackingFieldInClassCompanion ? containingDeclaration : propertyDescriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!skipPropertyAccessors) {
|
if (!skipPropertyAccessors) {
|
||||||
@@ -2005,10 +2030,11 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
fieldName = KotlinTypeMapper.mapDefaultFieldName(propertyDescriptor, isDelegatedProperty);
|
fieldName = KotlinTypeMapper.mapDefaultFieldName(propertyDescriptor, isDelegatedProperty);
|
||||||
}
|
}
|
||||||
|
|
||||||
return StackValue.property(propertyDescriptor, backingFieldOwner,
|
return StackValue.property(
|
||||||
typeMapper.mapType(
|
propertyDescriptor, backingFieldOwner,
|
||||||
isDelegatedProperty && forceField ? delegateType : propertyDescriptor.getOriginal().getType()),
|
typeMapper.mapType(isDelegatedProperty && forceField ? delegateType : propertyDescriptor.getOriginal().getType()),
|
||||||
isStaticBackingField, fieldName, callableGetter, callableSetter, receiver, this, resolvedCall);
|
isStaticBackingField, fieldName, callableGetter, callableSetter, receiver, this, resolvedCall, skipLateinitAssertion
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -2022,7 +2048,8 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
FunctionDescriptor setMethod = propertyDescriptor.getSetMethod();
|
FunctionDescriptor setMethod = propertyDescriptor.getSetMethod();
|
||||||
CallableMethod callableSetter =
|
CallableMethod callableSetter =
|
||||||
setMethod != null ? typeMapper.mapToCallableMethod(context.accessibleDescriptor(setMethod, null), false) : null;
|
setMethod != null ? typeMapper.mapToCallableMethod(context.accessibleDescriptor(setMethod, null), false) : null;
|
||||||
return StackValue.property(propertyDescriptor, null, type, false, null, callableGetter, callableSetter, receiver, this, null);
|
return StackValue.property(propertyDescriptor, null, type, false, null, callableGetter, callableSetter, receiver, this,
|
||||||
|
null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -2226,7 +2253,9 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
) {
|
) {
|
||||||
boolean isSuspendCall = CoroutineCodegenUtilKt.isSuspendNoInlineCall(resolvedCall);
|
boolean isSuspendCall = CoroutineCodegenUtilKt.isSuspendNoInlineCall(resolvedCall);
|
||||||
boolean isConstructor = resolvedCall.getResultingDescriptor() instanceof ConstructorDescriptor;
|
boolean isConstructor = resolvedCall.getResultingDescriptor() instanceof ConstructorDescriptor;
|
||||||
putReceiverAndInlineMarkerIfNeeded(callableMethod, resolvedCall, receiver, isSuspendCall, isConstructor);
|
if (!(callableMethod instanceof IntrinsicWithSpecialReceiver)) {
|
||||||
|
putReceiverAndInlineMarkerIfNeeded(callableMethod, resolvedCall, receiver, isSuspendCall, isConstructor);
|
||||||
|
}
|
||||||
|
|
||||||
callGenerator.processAndPutHiddenParameters(false);
|
callGenerator.processAndPutHiddenParameters(false);
|
||||||
|
|
||||||
@@ -2356,12 +2385,15 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
) {
|
) {
|
||||||
if (callElement == null) return defaultCallGenerator;
|
if (callElement == null) return defaultCallGenerator;
|
||||||
|
|
||||||
|
boolean isIntrinsic = descriptor instanceof CallableMemberDescriptor &&
|
||||||
|
state.getIntrinsics().getIntrinsic((CallableMemberDescriptor) descriptor) != null;
|
||||||
|
|
||||||
|
boolean isInline = (InlineUtil.isInline(descriptor) && !isIntrinsic) || InlineUtil.isArrayConstructorWithLambda(descriptor);
|
||||||
|
|
||||||
// We should inline callable containing reified type parameters even if inline is disabled
|
// We should inline callable containing reified type parameters even if inline is disabled
|
||||||
// because they may contain something to reify and straight call will probably fail at runtime
|
// because they may contain something to reify and straight call will probably fail at runtime
|
||||||
boolean isInline = (!state.isInlineDisabled() || InlineUtil.containsReifiedTypeParameters(descriptor)) &&
|
boolean shouldInline = isInline && (!state.isInlineDisabled() || InlineUtil.containsReifiedTypeParameters(descriptor));
|
||||||
(InlineUtil.isInline(descriptor) || InlineUtil.isArrayConstructorWithLambda(descriptor));
|
if (!shouldInline) return defaultCallGenerator;
|
||||||
|
|
||||||
if (!isInline) return defaultCallGenerator;
|
|
||||||
|
|
||||||
FunctionDescriptor original =
|
FunctionDescriptor original =
|
||||||
CoroutineCodegenUtilKt.getOriginalSuspendFunctionView(
|
CoroutineCodegenUtilKt.getOriginalSuspendFunctionView(
|
||||||
@@ -3606,13 +3638,8 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
|
|
||||||
if (asProperty && variableDescriptor instanceof PropertyDescriptor) {
|
if (asProperty && variableDescriptor instanceof PropertyDescriptor) {
|
||||||
StackValue.Property propertyValue = intermediateValueForProperty(
|
StackValue.Property propertyValue = intermediateValueForProperty(
|
||||||
(PropertyDescriptor) variableDescriptor,
|
(PropertyDescriptor) variableDescriptor, true, false, null, true, StackValue.LOCAL_0, null, false
|
||||||
true,
|
);
|
||||||
false,
|
|
||||||
null,
|
|
||||||
true,
|
|
||||||
StackValue.LOCAL_0,
|
|
||||||
null);
|
|
||||||
|
|
||||||
propertyValue.store(invokeFunction(call, resolvedCall, receiverStackValue), v);
|
propertyValue.store(invokeFunction(call, resolvedCall, receiverStackValue), v);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -835,7 +835,9 @@ public class FunctionCodegen {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String renderByteCodeIfAvailable(MethodVisitor mv) {
|
@SuppressWarnings("WeakerAccess") // Useful in debug
|
||||||
|
@Nullable
|
||||||
|
public static String renderByteCodeIfAvailable(@NotNull MethodVisitor mv) {
|
||||||
String bytecode = null;
|
String bytecode = null;
|
||||||
|
|
||||||
if (mv instanceof TransformationMethodVisitor) {
|
if (mv instanceof TransformationMethodVisitor) {
|
||||||
|
|||||||
@@ -522,7 +522,8 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
|
|||||||
assert initializer != null : "shouldInitializeProperty must return false if initializer is null";
|
assert initializer != null : "shouldInitializeProperty must return false if initializer is null";
|
||||||
|
|
||||||
StackValue.Property propValue = codegen.intermediateValueForProperty(
|
StackValue.Property propValue = codegen.intermediateValueForProperty(
|
||||||
propertyDescriptor, true, false, null, true, StackValue.LOCAL_0, null);
|
propertyDescriptor, true, false, null, true, StackValue.LOCAL_0, null, false
|
||||||
|
);
|
||||||
|
|
||||||
ResolvedCall<FunctionDescriptor> provideDelegateResolvedCall = bindingContext.get(PROVIDE_DELEGATE_RESOLVED_CALL, propertyDescriptor);
|
ResolvedCall<FunctionDescriptor> provideDelegateResolvedCall = bindingContext.get(PROVIDE_DELEGATE_RESOLVED_CALL, propertyDescriptor);
|
||||||
if (provideDelegateResolvedCall == null) {
|
if (provideDelegateResolvedCall == null) {
|
||||||
@@ -743,9 +744,9 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
|
public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
|
||||||
boolean syntheticBackingField =
|
FieldAccessorKind fieldAccessorKind = accessor instanceof AccessorForPropertyBackingField
|
||||||
accessor instanceof AccessorForPropertyBackingField &&
|
? ((AccessorForPropertyBackingField) accessor).getFieldAccessorKind() : null;
|
||||||
((AccessorForPropertyBackingField) accessor).getFieldAccessorKind() == FieldAccessorKind.FIELD_FROM_LOCAL;
|
boolean syntheticBackingField = fieldAccessorKind == FieldAccessorKind.FIELD_FROM_LOCAL;
|
||||||
boolean forceFieldForCompanionProperty = JvmAbi.isPropertyWithBackingFieldInOuterClass(original) &&
|
boolean forceFieldForCompanionProperty = JvmAbi.isPropertyWithBackingFieldInOuterClass(original) &&
|
||||||
!isCompanionObject(accessor.getContainingDeclaration());
|
!isCompanionObject(accessor.getContainingDeclaration());
|
||||||
boolean forceField = forceFieldForCompanionProperty ||
|
boolean forceField = forceFieldForCompanionProperty ||
|
||||||
@@ -753,7 +754,8 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
|
|||||||
original.getVisibility() == JavaVisibilities.PROTECTED_STATIC_VISIBILITY;
|
original.getVisibility() == JavaVisibilities.PROTECTED_STATIC_VISIBILITY;
|
||||||
StackValue property = codegen.intermediateValueForProperty(
|
StackValue property = codegen.intermediateValueForProperty(
|
||||||
original, forceField, syntheticBackingField, accessor.getSuperCallTarget(),
|
original, forceField, syntheticBackingField, accessor.getSuperCallTarget(),
|
||||||
forceFieldForCompanionProperty, StackValue.none(), null
|
forceFieldForCompanionProperty, StackValue.none(), null,
|
||||||
|
fieldAccessorKind == FieldAccessorKind.LATEINIT_INTRINSIC
|
||||||
);
|
);
|
||||||
|
|
||||||
InstructionAdapter iv = codegen.v;
|
InstructionAdapter iv = codegen.v;
|
||||||
|
|||||||
@@ -306,9 +306,11 @@ public abstract class StackValue {
|
|||||||
@Nullable CallableMethod setter,
|
@Nullable CallableMethod setter,
|
||||||
@NotNull StackValue receiver,
|
@NotNull StackValue receiver,
|
||||||
@NotNull ExpressionCodegen codegen,
|
@NotNull ExpressionCodegen codegen,
|
||||||
@Nullable ResolvedCall resolvedCall
|
@Nullable ResolvedCall resolvedCall,
|
||||||
|
boolean skipLateinitAssertion
|
||||||
) {
|
) {
|
||||||
return new Property(descriptor, backingFieldOwner, getter, setter, isStaticBackingField, fieldName, type, receiver, codegen, resolvedCall);
|
return new Property(descriptor, backingFieldOwner, getter, setter, isStaticBackingField, fieldName, type, receiver, codegen,
|
||||||
|
resolvedCall, skipLateinitAssertion);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -1187,20 +1189,17 @@ public abstract class StackValue {
|
|||||||
private final CallableMethod getter;
|
private final CallableMethod getter;
|
||||||
private final CallableMethod setter;
|
private final CallableMethod setter;
|
||||||
private final Type backingFieldOwner;
|
private final Type backingFieldOwner;
|
||||||
|
|
||||||
private final PropertyDescriptor descriptor;
|
private final PropertyDescriptor descriptor;
|
||||||
|
|
||||||
private final String fieldName;
|
private final String fieldName;
|
||||||
@NotNull private final ExpressionCodegen codegen;
|
private final ExpressionCodegen codegen;
|
||||||
@Nullable private final ResolvedCall resolvedCall;
|
private final ResolvedCall resolvedCall;
|
||||||
|
private final boolean skipLateinitAssertion;
|
||||||
|
|
||||||
public Property(
|
public Property(
|
||||||
@NotNull PropertyDescriptor descriptor, @Nullable Type backingFieldOwner,
|
@NotNull PropertyDescriptor descriptor, @Nullable Type backingFieldOwner, @Nullable CallableMethod getter,
|
||||||
@Nullable CallableMethod getter, @Nullable CallableMethod setter, boolean isStaticBackingField,
|
@Nullable CallableMethod setter, boolean isStaticBackingField, @Nullable String fieldName, @NotNull Type type,
|
||||||
@Nullable String fieldName, @NotNull Type type,
|
@NotNull StackValue receiver, @NotNull ExpressionCodegen codegen, @Nullable ResolvedCall resolvedCall,
|
||||||
@NotNull StackValue receiver,
|
boolean skipLateinitAssertion
|
||||||
@NotNull ExpressionCodegen codegen,
|
|
||||||
@Nullable ResolvedCall resolvedCall
|
|
||||||
) {
|
) {
|
||||||
super(type, isStatic(isStaticBackingField, getter), isStatic(isStaticBackingField, setter), receiver, true);
|
super(type, isStatic(isStaticBackingField, getter), isStatic(isStaticBackingField, setter), receiver, true);
|
||||||
this.backingFieldOwner = backingFieldOwner;
|
this.backingFieldOwner = backingFieldOwner;
|
||||||
@@ -1210,6 +1209,7 @@ public abstract class StackValue {
|
|||||||
this.fieldName = fieldName;
|
this.fieldName = fieldName;
|
||||||
this.codegen = codegen;
|
this.codegen = codegen;
|
||||||
this.resolvedCall = resolvedCall;
|
this.resolvedCall = resolvedCall;
|
||||||
|
this.skipLateinitAssertion = skipLateinitAssertion;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -1221,7 +1221,9 @@ public abstract class StackValue {
|
|||||||
|
|
||||||
v.visitFieldInsn(isStaticPut ? GETSTATIC : GETFIELD,
|
v.visitFieldInsn(isStaticPut ? GETSTATIC : GETFIELD,
|
||||||
backingFieldOwner.getInternalName(), fieldName, this.type.getDescriptor());
|
backingFieldOwner.getInternalName(), fieldName, this.type.getDescriptor());
|
||||||
genNotNullAssertionForLateInitIfNeeded(v);
|
if (!skipLateinitAssertion) {
|
||||||
|
genNotNullAssertionForLateInitIfNeeded(v);
|
||||||
|
}
|
||||||
coerceTo(type, v);
|
coerceTo(type, v);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
@@ -109,3 +109,8 @@ fun createIntrinsicCallable(
|
|||||||
): IntrinsicCallable {
|
): IntrinsicCallable {
|
||||||
return IntrinsicCallable(callable, invoke)
|
return IntrinsicCallable(callable, invoke)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A marker interface that signifies that this [IntrinsicCallable] instance generates the receiver of the intrinsic function call itself.
|
||||||
|
*/
|
||||||
|
interface IntrinsicWithSpecialReceiver : Callable
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||||
import org.jetbrains.kotlin.builtins.PrimitiveType;
|
import org.jetbrains.kotlin.builtins.PrimitiveType;
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
|
||||||
import org.jetbrains.kotlin.config.JvmTarget;
|
import org.jetbrains.kotlin.config.JvmTarget;
|
||||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor;
|
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor;
|
||||||
import org.jetbrains.kotlin.name.FqName;
|
import org.jetbrains.kotlin.name.FqName;
|
||||||
@@ -70,6 +69,8 @@ public class IntrinsicMethods {
|
|||||||
intrinsicsMap.registerIntrinsic(new FqName("kotlin.jvm.internal.unsafe"), null, "monitorExit", 1, MonitorInstruction.MONITOR_EXIT);
|
intrinsicsMap.registerIntrinsic(new FqName("kotlin.jvm.internal.unsafe"), null, "monitorExit", 1, MonitorInstruction.MONITOR_EXIT);
|
||||||
intrinsicsMap.registerIntrinsic(KOTLIN_JVM, KotlinBuiltIns.FQ_NAMES.array, "isArrayOf", 0, new IsArrayOf());
|
intrinsicsMap.registerIntrinsic(KOTLIN_JVM, KotlinBuiltIns.FQ_NAMES.array, "isArrayOf", 0, new IsArrayOf());
|
||||||
|
|
||||||
|
intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, KotlinBuiltIns.FQ_NAMES.kProperty0, "isInitialized", -1, LateinitIsInitialized.INSTANCE);
|
||||||
|
|
||||||
intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, null, "arrayOf", 1, new ArrayOf());
|
intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, null, "arrayOf", 1, new ArrayOf());
|
||||||
|
|
||||||
ImmutableList<Name> primitiveCastMethods = OperatorConventions.NUMBER_CONVERSIONS.asList();
|
ImmutableList<Name> primitiveCastMethods = OperatorConventions.NUMBER_CONVERSIONS.asList();
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* 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.codegen.intrinsics
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||||
|
import org.jetbrains.kotlin.codegen.StackValue
|
||||||
|
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||||
|
import org.jetbrains.kotlin.psi.KtCallableReferenceExpression
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCallWithAssert
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||||
|
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||||
|
import org.jetbrains.org.objectweb.asm.Type
|
||||||
|
|
||||||
|
object LateinitIsInitialized : IntrinsicPropertyGetter() {
|
||||||
|
override fun generate(resolvedCall: ResolvedCall<*>?, codegen: ExpressionCodegen, returnType: Type, receiver: StackValue): StackValue? {
|
||||||
|
val value = getStackValue(resolvedCall ?: return null, codegen) ?: return null
|
||||||
|
return StackValue.compareWithNull(value, Opcodes.IFNULL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getStackValue(resolvedCall: ResolvedCall<*>, codegen: ExpressionCodegen): StackValue? {
|
||||||
|
val expression =
|
||||||
|
(resolvedCall.extensionReceiver as? ExpressionReceiver)?.expression as? KtCallableReferenceExpression ?: return null
|
||||||
|
|
||||||
|
// TODO: support properties imported from objects as soon as KT-18982 is fixed
|
||||||
|
val receiver = expression.receiverExpression?.let(codegen::gen) ?: StackValue.none()
|
||||||
|
|
||||||
|
val target = expression.callableReference.getResolvedCallWithAssert(codegen.bindingContext).resultingDescriptor
|
||||||
|
return codegen.intermediateValueForProperty(target as PropertyDescriptor, true, false, null, false, receiver, null, true)
|
||||||
|
}
|
||||||
@@ -23,6 +23,7 @@ enum class FieldAccessorKind(val suffix: String) {
|
|||||||
NORMAL("p"),
|
NORMAL("p"),
|
||||||
IN_CLASS_COMPANION("cp"),
|
IN_CLASS_COMPANION("cp"),
|
||||||
FIELD_FROM_LOCAL("lp"),
|
FIELD_FROM_LOCAL("lp"),
|
||||||
|
LATEINIT_INTRINSIC("li"),
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun CallableMemberDescriptor.getJvmName() =
|
private fun CallableMemberDescriptor.getJvmName() =
|
||||||
|
|||||||
@@ -484,6 +484,10 @@ public interface Errors {
|
|||||||
DiagnosticFactory0<KtProperty> BACKING_FIELD_IN_INTERFACE = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
|
DiagnosticFactory0<KtProperty> BACKING_FIELD_IN_INTERFACE = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
|
||||||
|
|
||||||
DiagnosticFactory1<PsiElement, String> INAPPLICABLE_LATEINIT_MODIFIER = DiagnosticFactory1.create(ERROR);
|
DiagnosticFactory1<PsiElement, String> INAPPLICABLE_LATEINIT_MODIFIER = DiagnosticFactory1.create(ERROR);
|
||||||
|
DiagnosticFactory0<PsiElement> LATEINIT_INTRINSIC_CALL_ON_NON_LITERAL = DiagnosticFactory0.create(ERROR);
|
||||||
|
DiagnosticFactory0<PsiElement> LATEINIT_INTRINSIC_CALL_ON_NON_LATEINIT = DiagnosticFactory0.create(ERROR);
|
||||||
|
DiagnosticFactory0<PsiElement> LATEINIT_INTRINSIC_CALL_IN_INLINE_FUNCTION = DiagnosticFactory0.create(ERROR);
|
||||||
|
DiagnosticFactory1<PsiElement, PropertyDescriptor> LATEINIT_INTRINSIC_CALL_ON_NON_ACCESSIBLE_PROPERTY = DiagnosticFactory1.create(ERROR);
|
||||||
|
|
||||||
DiagnosticFactory2<KtModifierListOwner, String, ClassDescriptor> ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS = DiagnosticFactory2.create(ERROR, ABSTRACT_MODIFIER);
|
DiagnosticFactory2<KtModifierListOwner, String, ClassDescriptor> ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS = DiagnosticFactory2.create(ERROR, ABSTRACT_MODIFIER);
|
||||||
|
|
||||||
|
|||||||
+4
@@ -227,6 +227,10 @@ public class DefaultErrorMessages {
|
|||||||
MAP.put(DELEGATED_PROPERTY_IN_INTERFACE, "Delegated properties are not allowed in interfaces");
|
MAP.put(DELEGATED_PROPERTY_IN_INTERFACE, "Delegated properties are not allowed in interfaces");
|
||||||
|
|
||||||
MAP.put(INAPPLICABLE_LATEINIT_MODIFIER, "''lateinit'' modifier {0}", STRING);
|
MAP.put(INAPPLICABLE_LATEINIT_MODIFIER, "''lateinit'' modifier {0}", STRING);
|
||||||
|
MAP.put(LATEINIT_INTRINSIC_CALL_ON_NON_LITERAL, "This declaration can only be called on a property literal (e.g. 'Foo::bar')");
|
||||||
|
MAP.put(LATEINIT_INTRINSIC_CALL_ON_NON_LATEINIT, "This declaration can only be called on a reference to a lateinit property");
|
||||||
|
MAP.put(LATEINIT_INTRINSIC_CALL_IN_INLINE_FUNCTION, "This declaration can not be used inside an inline function");
|
||||||
|
MAP.put(LATEINIT_INTRINSIC_CALL_ON_NON_ACCESSIBLE_PROPERTY, "Backing field of ''{0}'' is not accessible at this point", COMPACT);
|
||||||
|
|
||||||
MAP.put(GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY, "Getter visibility must be the same as property visibility");
|
MAP.put(GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY, "Getter visibility must be the same as property visibility");
|
||||||
MAP.put(SETTER_VISIBILITY_INCONSISTENT_WITH_PROPERTY_VISIBILITY, "Setter visibility must be the same or less permissive than property visibility");
|
MAP.put(SETTER_VISIBILITY_INCONSISTENT_WITH_PROPERTY_VISIBILITY, "Setter visibility must be the same or less permissive than property visibility");
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ private val DEFAULT_CALL_CHECKERS = listOf(
|
|||||||
DeprecatedCallChecker, CallReturnsArrayOfNothingChecker(), InfixCallChecker(), OperatorCallChecker(),
|
DeprecatedCallChecker, CallReturnsArrayOfNothingChecker(), InfixCallChecker(), OperatorCallChecker(),
|
||||||
ConstructorHeaderCallChecker, ProtectedConstructorCallChecker, ApiVersionCallChecker,
|
ConstructorHeaderCallChecker, ProtectedConstructorCallChecker, ApiVersionCallChecker,
|
||||||
CoroutineSuspendCallChecker, BuilderFunctionsCallChecker, DslScopeViolationCallChecker, MissingDependencyClassChecker,
|
CoroutineSuspendCallChecker, BuilderFunctionsCallChecker, DslScopeViolationCallChecker, MissingDependencyClassChecker,
|
||||||
CallableReferenceCompatibilityChecker(),
|
CallableReferenceCompatibilityChecker(), LateinitIntrinsicApplicabilityChecker,
|
||||||
UnderscoreUsageChecker
|
UnderscoreUsageChecker
|
||||||
)
|
)
|
||||||
private val DEFAULT_TYPE_CHECKERS = emptyList<AdditionalTypeChecker>()
|
private val DEFAULT_TYPE_CHECKERS = emptyList<AdditionalTypeChecker>()
|
||||||
|
|||||||
+81
@@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
* 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.resolve.calls.checkers
|
||||||
|
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||||
|
import org.jetbrains.kotlin.diagnostics.Errors.*
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.psi.KtCallableReferenceExpression
|
||||||
|
import org.jetbrains.kotlin.psi.KtPsiUtil
|
||||||
|
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||||
|
import org.jetbrains.kotlin.resolve.OverridingUtil
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||||
|
|
||||||
|
object LateinitIntrinsicApplicabilityChecker : CallChecker {
|
||||||
|
private val ACCESSIBLE_LATEINIT_PROPERTY_LITERAL = FqName("kotlin.internal.AccessibleLateinitPropertyLiteral")
|
||||||
|
|
||||||
|
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
|
||||||
|
val descriptor = resolvedCall.resultingDescriptor
|
||||||
|
|
||||||
|
// An optimization
|
||||||
|
if (descriptor.name.asString() != "isInitialized") return
|
||||||
|
|
||||||
|
// TODO: store "@receiver:..." annotations in ReceiverParameterDescriptor
|
||||||
|
val annotations = descriptor.extensionReceiverParameter?.value?.type?.annotations?.getUseSiteTargetedAnnotations() ?: return
|
||||||
|
if (annotations.none { it.annotation.fqName == ACCESSIBLE_LATEINIT_PROPERTY_LITERAL }) return
|
||||||
|
|
||||||
|
val expression = (resolvedCall.extensionReceiver as? ExpressionReceiver)?.expression?.let(KtPsiUtil::safeDeparenthesize)
|
||||||
|
if (expression !is KtCallableReferenceExpression) {
|
||||||
|
context.trace.report(LATEINIT_INTRINSIC_CALL_ON_NON_LITERAL.on(reportOn))
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
val propertyReferenceResolvedCall = expression.callableReference.getResolvedCall(context.trace.bindingContext) ?: return
|
||||||
|
val referencedProperty = propertyReferenceResolvedCall.resultingDescriptor
|
||||||
|
if (referencedProperty !is PropertyDescriptor) {
|
||||||
|
error("Lateinit intrinsic is incorrectly resolved not to a property: $referencedProperty")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!referencedProperty.isLateInit) {
|
||||||
|
context.trace.report(LATEINIT_INTRINSIC_CALL_ON_NON_LATEINIT.on(reportOn))
|
||||||
|
}
|
||||||
|
else if (!isBackingFieldAccessible(referencedProperty, context)) {
|
||||||
|
context.trace.report(LATEINIT_INTRINSIC_CALL_ON_NON_ACCESSIBLE_PROPERTY.on(reportOn, referencedProperty))
|
||||||
|
}
|
||||||
|
else if ((context.scope.ownerDescriptor as? FunctionDescriptor)?.isInline == true) {
|
||||||
|
context.trace.report(LATEINIT_INTRINSIC_CALL_IN_INLINE_FUNCTION.on(reportOn))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isBackingFieldAccessible(descriptor: PropertyDescriptor, context: CallCheckerContext): Boolean {
|
||||||
|
// We can generate direct access to the backing field only if the property is defined in the same source file,
|
||||||
|
// and the property is originally declared in a scope that is a parent of the usage scope
|
||||||
|
val declaration =
|
||||||
|
OverridingUtil.filterOutOverridden(OverridingUtil.getOverriddenDeclarations(descriptor)).singleOrNull() ?: return false
|
||||||
|
val declarationSourceFile = DescriptorToSourceUtils.getContainingFile(declaration) ?: return false
|
||||||
|
val usageSourceFile = DescriptorToSourceUtils.getContainingFile(context.scope.ownerDescriptor) ?: return false
|
||||||
|
if (declarationSourceFile != usageSourceFile) return false
|
||||||
|
|
||||||
|
return declaration.containingDeclaration in
|
||||||
|
generateSequence(context.scope.ownerDescriptor, DeclarationDescriptor::getContainingDeclaration)
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
+35
@@ -0,0 +1,35 @@
|
|||||||
|
// TARGET_BACKEND: JVM
|
||||||
|
// LANGUAGE_VERSION: 1.2
|
||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
open class Foo {
|
||||||
|
lateinit var bar: String
|
||||||
|
|
||||||
|
private lateinit var baz: String
|
||||||
|
|
||||||
|
fun test(): String {
|
||||||
|
val isBarInitialized: () -> Boolean = { this::bar.isInitialized }
|
||||||
|
if (isBarInitialized()) return "Fail 1"
|
||||||
|
bar = "bar"
|
||||||
|
if (!isBarInitialized()) return "Fail 2"
|
||||||
|
baz = "baz"
|
||||||
|
return InnerSubclass().testInner()
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class InnerSubclass : Foo() {
|
||||||
|
fun testInner(): String {
|
||||||
|
// This is access to InnerSubclass.bar which is inherited from Foo.bar
|
||||||
|
if (this::bar.isInitialized) return "Fail 3"
|
||||||
|
bar = "OK"
|
||||||
|
if (!this::bar.isInitialized) return "Fail 4"
|
||||||
|
|
||||||
|
// This is access to Foo.bar declared lexically above
|
||||||
|
if (!this@Foo::bar.isInitialized) return "Fail 5"
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
return Foo().test()
|
||||||
|
}
|
||||||
Vendored
+21
@@ -0,0 +1,21 @@
|
|||||||
|
// TARGET_BACKEND: JVM
|
||||||
|
// LANGUAGE_VERSION: 1.2
|
||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
class Foo {
|
||||||
|
lateinit var bar: String
|
||||||
|
|
||||||
|
fun test(): String {
|
||||||
|
var state = 0
|
||||||
|
if (run { state++; this }::bar.isInitialized) return "Fail 1"
|
||||||
|
|
||||||
|
bar = "A"
|
||||||
|
if (!run { state++; this }::bar.isInitialized) return "Fail 3"
|
||||||
|
|
||||||
|
return if (state == 2) "OK" else "Fail: state=$state"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
return Foo().test()
|
||||||
|
}
|
||||||
+36
@@ -0,0 +1,36 @@
|
|||||||
|
// TARGET_BACKEND: JVM
|
||||||
|
// LANGUAGE_VERSION: 1.2
|
||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
// FILE: J.java
|
||||||
|
|
||||||
|
public class J {
|
||||||
|
public static void deinitialize(Foo foo) {
|
||||||
|
foo.bar = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: main.kt
|
||||||
|
|
||||||
|
class Foo {
|
||||||
|
lateinit var bar: String
|
||||||
|
|
||||||
|
fun test(): String {
|
||||||
|
if (this::bar.isInitialized) return "Fail 1"
|
||||||
|
J.deinitialize(this)
|
||||||
|
if (this::bar.isInitialized) return "Fail 2"
|
||||||
|
|
||||||
|
bar = "A"
|
||||||
|
if (!this::bar.isInitialized) return "Fail 3"
|
||||||
|
J.deinitialize(this)
|
||||||
|
if (this::bar.isInitialized) return "Fail 4"
|
||||||
|
|
||||||
|
bar = "OK"
|
||||||
|
if (!this::bar.isInitialized) return "Fail 5"
|
||||||
|
return bar
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
return Foo().test()
|
||||||
|
}
|
||||||
Vendored
+12
@@ -0,0 +1,12 @@
|
|||||||
|
// TARGET_BACKEND: JVM
|
||||||
|
// LANGUAGE_VERSION: 1.2
|
||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
lateinit var bar: String
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
if (::bar.isInitialized) return "Fail 1"
|
||||||
|
bar = "OK"
|
||||||
|
if (!::bar.isInitialized) return "Fail 2"
|
||||||
|
return bar
|
||||||
|
}
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
// !DIAGNOSTICS: -UNUSED_VARIABLE -NOTHING_TO_INLINE
|
||||||
|
// !API_VERSION: 1.2
|
||||||
|
// FILE: test.kt
|
||||||
|
|
||||||
|
interface Base {
|
||||||
|
var x: String
|
||||||
|
}
|
||||||
|
|
||||||
|
open class Foo : Base {
|
||||||
|
override lateinit var x: String
|
||||||
|
private lateinit var y: String
|
||||||
|
|
||||||
|
var nonLateInit: Int = 1
|
||||||
|
|
||||||
|
fun ok() {
|
||||||
|
val b: Boolean = this::x.isInitialized
|
||||||
|
|
||||||
|
val otherInstance = Foo()
|
||||||
|
otherInstance::x.isInitialized
|
||||||
|
|
||||||
|
(this::x).isInitialized
|
||||||
|
(@Suppress("ALL") (this::x)).isInitialized
|
||||||
|
|
||||||
|
object {
|
||||||
|
fun local() {
|
||||||
|
class Local {
|
||||||
|
val xx = this@Foo::x.isInitialized
|
||||||
|
val yy = this@Foo::y.isInitialized
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onLiteral() {
|
||||||
|
val p = this::x
|
||||||
|
p.<!LATEINIT_INTRINSIC_CALL_ON_NON_LITERAL!>isInitialized<!>
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onNonLateinit() {
|
||||||
|
this::nonLateInit.<!LATEINIT_INTRINSIC_CALL_ON_NON_LATEINIT!>isInitialized<!>
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun inlineFun() {
|
||||||
|
this::x.<!LATEINIT_INTRINSIC_CALL_IN_INLINE_FUNCTION!>isInitialized<!>
|
||||||
|
|
||||||
|
object {
|
||||||
|
val z = this@Foo::x.isInitialized
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class InnerSubclass : Foo() {
|
||||||
|
fun innerOk() {
|
||||||
|
// This is access to Foo.x declared lexically above
|
||||||
|
this@Foo::x.isInitialized
|
||||||
|
|
||||||
|
// This is access to InnerSubclass.x which is inherited from Foo.x
|
||||||
|
this::x.isInitialized
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onNonAccessible() {
|
||||||
|
Foo()::x.<!LATEINIT_INTRINSIC_CALL_ON_NON_ACCESSIBLE_PROPERTY!>isInitialized<!>
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onNonLateinit() {
|
||||||
|
Foo()::nonLateInit.<!LATEINIT_INTRINSIC_CALL_ON_NON_LATEINIT!>isInitialized<!>
|
||||||
|
}
|
||||||
|
|
||||||
|
object Unrelated {
|
||||||
|
fun onNonAccessible() {
|
||||||
|
Foo()::x.<!LATEINIT_INTRINSIC_CALL_ON_NON_ACCESSIBLE_PROPERTY!>isInitialized<!>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class FooImpl : Foo() {
|
||||||
|
fun onNonAccessible() {
|
||||||
|
this::x.<!LATEINIT_INTRINSIC_CALL_ON_NON_ACCESSIBLE_PROPERTY!>isInitialized<!>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: other.kt
|
||||||
|
|
||||||
|
class OtherFooImpl : Foo() {
|
||||||
|
fun onNonAccessible() {
|
||||||
|
this::x.<!LATEINIT_INTRINSIC_CALL_ON_NON_ACCESSIBLE_PROPERTY!>isInitialized<!>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public fun onNonAccessible(): kotlin.Unit
|
||||||
|
public fun onNonLateinit(): kotlin.Unit
|
||||||
|
|
||||||
|
public interface Base {
|
||||||
|
public abstract var x: kotlin.String
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
public open class Foo : Base {
|
||||||
|
public constructor Foo()
|
||||||
|
public final var nonLateInit: kotlin.Int
|
||||||
|
public open override /*1*/ lateinit var x: kotlin.String
|
||||||
|
private final lateinit var y: kotlin.String
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public final inline fun inlineFun(): kotlin.Unit
|
||||||
|
public final fun ok(): kotlin.Unit
|
||||||
|
public final fun onLiteral(): kotlin.Unit
|
||||||
|
public final fun onNonLateinit(): kotlin.Unit
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
|
||||||
|
public final inner class InnerSubclass : Foo {
|
||||||
|
public constructor InnerSubclass()
|
||||||
|
public final override /*1*/ /*fake_override*/ var nonLateInit: kotlin.Int
|
||||||
|
public open override /*1*/ lateinit /*fake_override*/ var x: kotlin.String
|
||||||
|
invisible_fake final override /*1*/ lateinit /*fake_override*/ var y: kotlin.String
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public final inline override /*1*/ /*fake_override*/ fun inlineFun(): kotlin.Unit
|
||||||
|
public final fun innerOk(): kotlin.Unit
|
||||||
|
public final override /*1*/ /*fake_override*/ fun ok(): kotlin.Unit
|
||||||
|
public final override /*1*/ /*fake_override*/ fun onLiteral(): kotlin.Unit
|
||||||
|
public final override /*1*/ /*fake_override*/ fun onNonLateinit(): kotlin.Unit
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class FooImpl : Foo {
|
||||||
|
public constructor FooImpl()
|
||||||
|
public final override /*1*/ /*fake_override*/ var nonLateInit: kotlin.Int
|
||||||
|
public open override /*1*/ lateinit /*fake_override*/ var x: kotlin.String
|
||||||
|
invisible_fake final override /*1*/ lateinit /*fake_override*/ var y: kotlin.String
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public final inline override /*1*/ /*fake_override*/ fun inlineFun(): kotlin.Unit
|
||||||
|
public final override /*1*/ /*fake_override*/ fun ok(): kotlin.Unit
|
||||||
|
public final override /*1*/ /*fake_override*/ fun onLiteral(): kotlin.Unit
|
||||||
|
public final fun onNonAccessible(): kotlin.Unit
|
||||||
|
public final override /*1*/ /*fake_override*/ fun onNonLateinit(): kotlin.Unit
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class OtherFooImpl : Foo {
|
||||||
|
public constructor OtherFooImpl()
|
||||||
|
public final override /*1*/ /*fake_override*/ var nonLateInit: kotlin.Int
|
||||||
|
public open override /*1*/ lateinit /*fake_override*/ var x: kotlin.String
|
||||||
|
invisible_fake final override /*1*/ lateinit /*fake_override*/ var y: kotlin.String
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public final inline override /*1*/ /*fake_override*/ fun inlineFun(): kotlin.Unit
|
||||||
|
public final override /*1*/ /*fake_override*/ fun ok(): kotlin.Unit
|
||||||
|
public final override /*1*/ /*fake_override*/ fun onLiteral(): kotlin.Unit
|
||||||
|
public final fun onNonAccessible(): kotlin.Unit
|
||||||
|
public final override /*1*/ /*fake_override*/ fun onNonLateinit(): kotlin.Unit
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
public object Unrelated {
|
||||||
|
private constructor Unrelated()
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public final fun onNonAccessible(): kotlin.Unit
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
+33
@@ -13576,6 +13576,39 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class IsInitializedAndDeinitialize extends AbstractIrBlackBoxCodegenTest {
|
||||||
|
public void testAllFilesPresentInIsInitializedAndDeinitialize() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("innerSubclass.kt")
|
||||||
|
public void testInnerSubclass() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/innerSubclass.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("sideEffects.kt")
|
||||||
|
public void testSideEffects() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/sideEffects.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("simpleIsInitialized.kt")
|
||||||
|
public void testSimpleIsInitialized() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/simpleIsInitialized.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("topLevelProperty.kt")
|
||||||
|
public void testTopLevelProperty() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/topLevelProperty.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/box/properties/lateinit/local")
|
@TestMetadata("compiler/testData/codegen/box/properties/lateinit/local")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
@@ -1356,6 +1356,21 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/testData/diagnostics/testsWithStdLib/lateinit")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class Lateinit extends AbstractDiagnosticsTestWithStdLib {
|
||||||
|
public void testAllFilesPresentInLateinit() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/testsWithStdLib/lateinit"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("isInitialized.kt")
|
||||||
|
public void testIsInitialized() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/lateinit/isInitialized.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/diagnostics/testsWithStdLib/native")
|
@TestMetadata("compiler/testData/diagnostics/testsWithStdLib/native")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
+15
@@ -1356,6 +1356,21 @@ public class DiagnosticsTestWithStdLibUsingJavacGenerated extends AbstractDiagno
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/testData/diagnostics/testsWithStdLib/lateinit")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class Lateinit extends AbstractDiagnosticsTestWithStdLibUsingJavac {
|
||||||
|
public void testAllFilesPresentInLateinit() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/testsWithStdLib/lateinit"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("isInitialized.kt")
|
||||||
|
public void testIsInitialized() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/lateinit/isInitialized.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/diagnostics/testsWithStdLib/native")
|
@TestMetadata("compiler/testData/diagnostics/testsWithStdLib/native")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
@@ -13576,6 +13576,39 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class IsInitializedAndDeinitialize extends AbstractBlackBoxCodegenTest {
|
||||||
|
public void testAllFilesPresentInIsInitializedAndDeinitialize() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("innerSubclass.kt")
|
||||||
|
public void testInnerSubclass() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/innerSubclass.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("sideEffects.kt")
|
||||||
|
public void testSideEffects() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/sideEffects.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("simpleIsInitialized.kt")
|
||||||
|
public void testSimpleIsInitialized() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/simpleIsInitialized.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("topLevelProperty.kt")
|
||||||
|
public void testTopLevelProperty() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/topLevelProperty.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/box/properties/lateinit/local")
|
@TestMetadata("compiler/testData/codegen/box/properties/lateinit/local")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
@@ -13576,6 +13576,39 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class IsInitializedAndDeinitialize extends AbstractLightAnalysisModeTest {
|
||||||
|
public void testAllFilesPresentInIsInitializedAndDeinitialize() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("innerSubclass.kt")
|
||||||
|
public void testInnerSubclass() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/innerSubclass.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("sideEffects.kt")
|
||||||
|
public void testSideEffects() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/sideEffects.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("simpleIsInitialized.kt")
|
||||||
|
public void testSimpleIsInitialized() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/simpleIsInitialized.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("topLevelProperty.kt")
|
||||||
|
public void testTopLevelProperty() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize/topLevelProperty.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/box/properties/lateinit/local")
|
@TestMetadata("compiler/testData/codegen/box/properties/lateinit/local")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
@@ -15052,6 +15052,15 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class IsInitializedAndDeinitialize extends AbstractJsCodegenBoxTest {
|
||||||
|
public void testAllFilesPresentInIsInitializedAndDeinitialize() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/properties/lateinit/isInitializedAndDeinitialize"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/box/properties/lateinit/local")
|
@TestMetadata("compiler/testData/codegen/box/properties/lateinit/local")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
@@ -64,4 +64,13 @@ internal annotation class InlineOnly
|
|||||||
*/
|
*/
|
||||||
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY)
|
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY)
|
||||||
@Retention(AnnotationRetention.BINARY)
|
@Retention(AnnotationRetention.BINARY)
|
||||||
internal annotation class DynamicExtension
|
internal annotation class DynamicExtension
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The value of this parameter should be a property reference expression (`this::foo`), referencing a `lateinit` property,
|
||||||
|
* the backing field of which is accessible at the point where the corresponding argument is passed.
|
||||||
|
*/
|
||||||
|
@Target(AnnotationTarget.VALUE_PARAMETER)
|
||||||
|
@Retention(AnnotationRetention.BINARY)
|
||||||
|
@SinceKotlin("1.2")
|
||||||
|
internal annotation class AccessibleLateinitPropertyLiteral
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
@file:kotlin.jvm.JvmName("LateinitKt")
|
||||||
|
@file:kotlin.jvm.JvmVersion
|
||||||
|
@file:Suppress("unused")
|
||||||
|
|
||||||
|
package kotlin
|
||||||
|
|
||||||
|
import kotlin.internal.InlineOnly
|
||||||
|
import kotlin.internal.AccessibleLateinitPropertyLiteral
|
||||||
|
import kotlin.reflect.KProperty0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns `true` if this lateinit property has been assigned a value, and `false` otherwise.
|
||||||
|
*
|
||||||
|
* Cannot be used in an inline function, to avoid binary compatibility issues.
|
||||||
|
*/
|
||||||
|
@SinceKotlin("1.2")
|
||||||
|
@InlineOnly
|
||||||
|
inline val @receiver:AccessibleLateinitPropertyLiteral KProperty0<*>.isInitialized: Boolean
|
||||||
|
get() = throw NotImplementedError("Implementation is intrinsic")
|
||||||
Reference in New Issue
Block a user