[IR] Add isAssignable property to IrValueParameter.

Use it to check that only the value parameters that are explicitly
marked assignable are assigned.

Currently, the only parameters marked assignable are those for
default argument stubs.
This commit is contained in:
Mads Ager
2020-09-15 13:42:42 +02:00
committed by Alexander Udalov
parent 8d791ca98e
commit 1f2ca606a5
26 changed files with 55 additions and 34 deletions
@@ -356,7 +356,7 @@ internal fun IrDeclarationParent.declareThisReceiverParameter(
symbolTable.irFactory.createValueParameter( symbolTable.irFactory.createValueParameter(
startOffset, endOffset, thisOrigin, symbol, startOffset, endOffset, thisOrigin, symbol,
Name.special("<this>"), -1, thisType, Name.special("<this>"), -1, thisType,
varargElementType = null, isCrossinline = false, isNoinline = false varargElementType = null, isCrossinline = false, isNoinline = false, isAssignable = false
).apply { ).apply {
this.parent = this@declareThisReceiverParameter this.parent = this@declareThisReceiverParameter
receiverDescriptor.bind(this) receiverDescriptor.bind(this)
@@ -256,7 +256,7 @@ class Fir2IrDeclarationStorage(
startOffset, endOffset, IrDeclarationOrigin.DEFINED, symbol, startOffset, endOffset, IrDeclarationOrigin.DEFINED, symbol,
Name.special("<set-?>"), 0, type, Name.special("<set-?>"), 0, type,
varargElementType = null, varargElementType = null,
isCrossinline = false, isNoinline = false isCrossinline = false, isNoinline = false, isAssignable = false
).apply { ).apply {
this.parent = parent this.parent = parent
descriptor.bind(this) descriptor.bind(this)
@@ -843,7 +843,7 @@ class Fir2IrDeclarationStorage(
valueParameter.name, index, type, valueParameter.name, index, type,
if (!valueParameter.isVararg) null if (!valueParameter.isVararg) null
else valueParameter.returnTypeRef.coneType.arrayElementType()?.toIrType(typeContext), else valueParameter.returnTypeRef.coneType.arrayElementType()?.toIrType(typeContext),
valueParameter.isCrossinline, valueParameter.isNoinline valueParameter.isCrossinline, valueParameter.isNoinline, false
).apply { ).apply {
descriptor.bind(this) descriptor.bind(this)
if (valueParameter.defaultValue.let { if (valueParameter.defaultValue.let {
@@ -274,7 +274,8 @@ internal class AdapterGenerator(
type, type,
varargElementType = null, varargElementType = null,
isCrossinline = false, isCrossinline = false,
isNoinline = false isNoinline = false,
isAssignable = false
).also { irAdapterValueParameter -> ).also { irAdapterValueParameter ->
descriptor.bind(irAdapterValueParameter) descriptor.bind(irAdapterValueParameter)
irAdapterValueParameter.parent = adapterFunction irAdapterValueParameter.parent = adapterFunction
@@ -281,7 +281,7 @@ class DataClassMembersGenerator(val components: Fir2IrComponents) {
) { symbol -> ) { symbol ->
components.irFactory.createValueParameter( components.irFactory.createValueParameter(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, origin, symbol, name, index, type, null, UNDEFINED_OFFSET, UNDEFINED_OFFSET, origin, symbol, name, index, type, null,
isCrossinline = false, isNoinline = false isCrossinline = false, isNoinline = false, isAssignable = false
) )
}.apply { }.apply {
parent = irFunction parent = irFunction
@@ -137,7 +137,10 @@ class CheckIrElementVisitor(
override fun visitSetValue(expression: IrSetValue) { override fun visitSetValue(expression: IrSetValue) {
super.visitSetValue(expression) super.visitSetValue(expression)
val declaration = expression.symbol.owner
if (declaration is IrValueParameter && !declaration.isAssignable) {
reportError(expression, "Assignment to value parameters not marked assignable")
}
expression.ensureTypeIs(irBuiltIns.unitType) expression.ensureTypeIs(irBuiltIns.unitType)
} }
@@ -126,7 +126,8 @@ fun IrValueParameter.copyTo(
varargElementType: IrType? = this.varargElementType, // TODO: remapTypeParameters here as well varargElementType: IrType? = this.varargElementType, // TODO: remapTypeParameters here as well
defaultValue: IrExpressionBody? = this.defaultValue, defaultValue: IrExpressionBody? = this.defaultValue,
isCrossinline: Boolean = this.isCrossinline, isCrossinline: Boolean = this.isCrossinline,
isNoinline: Boolean = this.isNoinline isNoinline: Boolean = this.isNoinline,
isAssignable: Boolean = this.isAssignable
): IrValueParameter { ): IrValueParameter {
val descriptor = if (index < 0) { val descriptor = if (index < 0) {
WrappedReceiverParameterDescriptor() WrappedReceiverParameterDescriptor()
@@ -143,7 +144,7 @@ fun IrValueParameter.copyTo(
} }
return factory.createValueParameter( return factory.createValueParameter(
startOffset, endOffset, origin, symbol, startOffset, endOffset, origin, symbol,
name, index, type, varargElementType, isCrossinline, isNoinline name, index, type, varargElementType, isCrossinline, isNoinline, isAssignable = isAssignable
).also { ).also {
descriptor.bind(it) descriptor.bind(it)
it.parent = irFunction it.parent = irFunction
@@ -171,7 +172,7 @@ fun IrFunction.copyReceiverParametersFrom(from: IrFunction) {
startOffset, endOffset, origin, startOffset, endOffset, origin,
IrValueParameterSymbolImpl(newDescriptor), IrValueParameterSymbolImpl(newDescriptor),
name, name,
index, type, varargElementType, isCrossinline, isNoinline index, type, varargElementType, isCrossinline, isNoinline, false
).also { parameter -> ).also { parameter ->
parameter.parent = this@copyReceiverParametersFrom parameter.parent = this@copyReceiverParametersFrom
newDescriptor.bind(this) newDescriptor.bind(this)
@@ -422,6 +423,7 @@ fun IrFunction.createDispatchReceiverParameter(origin: IrDeclarationOrigin? = nu
parentAsClass.defaultType, parentAsClass.defaultType,
null, null,
false, false,
false,
false false
).apply { ).apply {
parent = this@createDispatchReceiverParameter parent = this@createDispatchReceiverParameter
@@ -586,7 +586,8 @@ private fun IrFunction.generateDefaultsFunctionImpl(
type = if (makeNullable) newType.makeNullable() else newType, type = if (makeNullable) newType.makeNullable() else newType,
defaultValue = if (it.defaultValue != null) { defaultValue = if (it.defaultValue != null) {
factory.createExpressionBody(IrErrorExpressionImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, it.type, "Default Stub")) factory.createExpressionBody(IrErrorExpressionImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, it.type, "Default Stub"))
} else null } else null,
isAssignable = it.defaultValue != null
) )
} }
@@ -18,7 +18,6 @@ import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.defaultType import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.parentAsClass import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DescriptorWithContainerSource
import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.Variance
@PublishedApi @PublishedApi
@@ -213,7 +212,7 @@ fun <D> buildReceiverParameter(
parent.factory.createValueParameter( parent.factory.createValueParameter(
startOffset, endOffset, origin, startOffset, endOffset, origin,
IrValueParameterSymbolImpl(wrappedDescriptor), IrValueParameterSymbolImpl(wrappedDescriptor),
RECEIVER_PARAMETER_NAME, -1, type, null, isCrossinline = false, isNoinline = false RECEIVER_PARAMETER_NAME, -1, type, null, isCrossinline = false, isNoinline = false, isAssignable = false
).also { ).also {
wrappedDescriptor.bind(it) wrappedDescriptor.bind(it)
it.parent = parent it.parent = parent
@@ -227,7 +226,7 @@ internal fun IrFactory.buildValueParameter(builder: IrValueParameterBuilder, par
return createValueParameter( return createValueParameter(
startOffset, endOffset, origin, startOffset, endOffset, origin,
IrValueParameterSymbolImpl(wrappedDescriptor), IrValueParameterSymbolImpl(wrappedDescriptor),
name, index, type, varargElementType, isCrossInline, isNoinline, isHidden name, index, type, varargElementType, isCrossInline, isNoinline, isHidden, false
).also { ).also {
wrappedDescriptor.bind(it) wrappedDescriptor.bind(it)
it.parent = parent it.parent = parent
@@ -415,7 +415,7 @@ private fun StatementGenerator.createFunctionForSuspendConversion(
Name.identifier("p$index"), Name.identifier("p$index"),
index, index,
irParameterType, irParameterType,
varargElementType = null, isCrossinline = false, isNoinline = false varargElementType = null, isCrossinline = false, isNoinline = false, isAssignable = false
) )
}.also { }.also {
adaptedParameterDescriptor.bind(it) adaptedParameterDescriptor.bind(it)
@@ -392,7 +392,7 @@ class ReflectionReferencesGenerator(statementGenerator: StatementGenerator) : St
name, name,
index, index,
type.toIrType(), type.toIrType(),
varargElementType = null, isCrossinline = false, isNoinline = false varargElementType = null, isCrossinline = false, isNoinline = false, isAssignable = false
).also { irAdapterValueParameter -> ).also { irAdapterValueParameter ->
descriptor.bind(irAdapterValueParameter) descriptor.bind(irAdapterValueParameter)
} }
@@ -235,10 +235,11 @@ object IrFactoryImpl : IrFactory {
varargElementType: IrType?, varargElementType: IrType?,
isCrossinline: Boolean, isCrossinline: Boolean,
isNoinline: Boolean, isNoinline: Boolean,
isHidden: Boolean isHidden: Boolean,
isAssignable: Boolean,
): IrValueParameter = ): IrValueParameter =
IrValueParameterImpl( IrValueParameterImpl(
startOffset, endOffset, origin, symbol, name, index, type, varargElementType, isCrossinline, isNoinline, isHidden startOffset, endOffset, origin, symbol, name, index, type, varargElementType, isCrossinline, isNoinline, isHidden, isAssignable
) )
override fun createExpressionBody( override fun createExpressionBody(
@@ -39,7 +39,8 @@ class IrValueParameterImpl(
override var varargElementType: IrType?, override var varargElementType: IrType?,
override val isCrossinline: Boolean, override val isCrossinline: Boolean,
override val isNoinline: Boolean, override val isNoinline: Boolean,
override val isHidden: Boolean = false override val isHidden: Boolean = false,
override val isAssignable: Boolean = false
) : IrValueParameter() { ) : IrValueParameter() {
@ObsoleteDescriptorBasedAPI @ObsoleteDescriptorBasedAPI
override val descriptor: ParameterDescriptor override val descriptor: ParameterDescriptor
@@ -237,10 +237,11 @@ object PersistentIrFactory : IrFactory {
varargElementType: IrType?, varargElementType: IrType?,
isCrossinline: Boolean, isCrossinline: Boolean,
isNoinline: Boolean, isNoinline: Boolean,
isHidden: Boolean isHidden: Boolean,
isAssignable: Boolean
): IrValueParameter = ): IrValueParameter =
PersistentIrValueParameter( PersistentIrValueParameter(
startOffset, endOffset, origin, symbol, name, index, type, varargElementType, isCrossinline, isNoinline, isHidden startOffset, endOffset, origin, symbol, name, index, type, varargElementType, isCrossinline, isNoinline, isHidden, isAssignable
) )
override fun createExpressionBody( override fun createExpressionBody(
@@ -41,7 +41,8 @@ internal class PersistentIrValueParameter(
varargElementType: IrType?, varargElementType: IrType?,
override val isCrossinline: Boolean, override val isCrossinline: Boolean,
override val isNoinline: Boolean, override val isNoinline: Boolean,
override val isHidden: Boolean = false override val isHidden: Boolean = false,
override val isAssignable: Boolean
) : IrValueParameter(), ) : IrValueParameter(),
PersistentIrDeclarationBase<ValueParameterCarrier>, PersistentIrDeclarationBase<ValueParameterCarrier>,
ValueParameterCarrier { ValueParameterCarrier {
@@ -199,7 +199,8 @@ interface IrFactory {
varargElementType: IrType?, varargElementType: IrType?,
isCrossinline: Boolean, isCrossinline: Boolean,
isNoinline: Boolean, isNoinline: Boolean,
isHidden: Boolean = false isHidden: Boolean = false,
isAssignable: Boolean = false
): IrValueParameter ): IrValueParameter
// Bodies // Bodies
@@ -39,6 +39,11 @@ abstract class IrValueParameter : IrValueDeclaration(), IrSymbolDeclaration<IrVa
// Once we are able to load any top-level declaration from klib this hack should be deprecated and removed. // Once we are able to load any top-level declaration from klib this hack should be deprecated and removed.
abstract val isHidden: Boolean abstract val isHidden: Boolean
// Parameters are not assignable by default. However, in the IR, assignments to parameters are used
// to implement default argument stubs. If the default value is to be used, the value is assigned
// to the parameter.
abstract val isAssignable: Boolean
abstract var defaultValue: IrExpressionBody? abstract var defaultValue: IrExpressionBody?
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R = override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
@@ -32,7 +32,7 @@ interface IrLazyDeclarationBase : IrDeclaration {
fun ReceiverParameterDescriptor.generateReceiverParameterStub(): IrValueParameter = fun ReceiverParameterDescriptor.generateReceiverParameterStub(): IrValueParameter =
factory.createValueParameter( factory.createValueParameter(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, origin, IrValueParameterSymbolImpl(this), UNDEFINED_OFFSET, UNDEFINED_OFFSET, origin, IrValueParameterSymbolImpl(this),
name, -1, type.toIrType(), null, isCrossinline = false, isNoinline = false name, -1, type.toIrType(), null, isCrossinline = false, isNoinline = false, isAssignable = false
) )
fun generateMemberStubs(memberScope: MemberScope, container: MutableList<IrDeclaration>) { fun generateMemberStubs(memberScope: MemberScope, container: MutableList<IrDeclaration>) {
@@ -80,7 +80,7 @@ class IrBuiltIns(
val valueParameterSymbol = IrValueParameterSymbolImpl(valueParameterDescriptor) val valueParameterSymbol = IrValueParameterSymbolImpl(valueParameterDescriptor)
irFactory.createValueParameter( irFactory.createValueParameter(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, BUILTIN_OPERATOR, valueParameterSymbol, Name.identifier("arg$i"), i, UNDEFINED_OFFSET, UNDEFINED_OFFSET, BUILTIN_OPERATOR, valueParameterSymbol, Name.identifier("arg$i"), i,
valueParameterType, null, isCrossinline = false, isNoinline = false valueParameterType, null, isCrossinline = false, isNoinline = false, isAssignable = false
).apply { ).apply {
parent = operator parent = operator
} }
@@ -165,7 +165,7 @@ class IrBuiltIns(
val valueParameterSymbol = IrValueParameterSymbolImpl(valueParameterDescriptor) val valueParameterSymbol = IrValueParameterSymbolImpl(valueParameterDescriptor)
val valueParameter = irFactory.createValueParameter( val valueParameter = irFactory.createValueParameter(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, BUILTIN_OPERATOR, valueParameterSymbol, Name.identifier("arg0"), 0, UNDEFINED_OFFSET, UNDEFINED_OFFSET, BUILTIN_OPERATOR, valueParameterSymbol, Name.identifier("arg0"), 0,
valueIrType, null, isCrossinline = false, isNoinline = false valueIrType, null, isCrossinline = false, isNoinline = false, isAssignable = false
) )
valueParameter.parent = operator valueParameter.parent = operator
@@ -268,7 +268,8 @@ class IrFunctionFactory(private val irBuiltIns: IrBuiltIns, private val symbolTa
val vDeclaration = irFactory.createValueParameter( val vDeclaration = irFactory.createValueParameter(
offset, offset, classOrigin, vSymbol, Name.special("<this>"), -1, type, null, offset, offset, classOrigin, vSymbol, Name.special("<this>"), -1, type, null,
isCrossinline = false, isCrossinline = false,
isNoinline = false isNoinline = false,
isAssignable = false
) )
if (vDescriptor is WrappedReceiverParameterDescriptor) vDescriptor.bind(vDeclaration) if (vDescriptor is WrappedReceiverParameterDescriptor) vDescriptor.bind(vDeclaration)
@@ -332,7 +333,8 @@ class IrFunctionFactory(private val irBuiltIns: IrBuiltIns, private val symbolTa
val vDeclaration = irFactory.createValueParameter( val vDeclaration = irFactory.createValueParameter(
offset, offset, memberOrigin, vSymbol, Name.identifier("p$i"), i - 1, vType, null, offset, offset, memberOrigin, vSymbol, Name.identifier("p$i"), i - 1, vType, null,
isCrossinline = false, isCrossinline = false,
isNoinline = false isNoinline = false,
isAssignable = false
) )
vDeclaration.parent = fDeclaration vDeclaration.parent = fDeclaration
if (vDescriptor is WrappedValueParameterDescriptor) vDescriptor.bind(vDeclaration) if (vDescriptor is WrappedValueParameterDescriptor) vDescriptor.bind(vDeclaration)
@@ -95,7 +95,8 @@ class FakeOverrideCopier(
declaration.type.remapType(), declaration.type.remapType(),
declaration.varargElementType?.remapType(), declaration.varargElementType?.remapType(),
declaration.isCrossinline, declaration.isCrossinline,
declaration.isNoinline declaration.isNoinline,
false
).apply { ).apply {
transformAnnotations(declaration) transformAnnotations(declaration)
// Don't set the default value for fake overrides. // Don't set the default value for fake overrides.
@@ -242,7 +242,7 @@ class DeclarationStubGenerator(
internal fun generateValueParameterStub(descriptor: ValueParameterDescriptor): IrValueParameter = with(descriptor) { internal fun generateValueParameterStub(descriptor: ValueParameterDescriptor): IrValueParameter = with(descriptor) {
symbolTable.irFactory.createValueParameter( symbolTable.irFactory.createValueParameter(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, computeOrigin(this), IrValueParameterSymbolImpl(this), name, index, type.toIrType(), UNDEFINED_OFFSET, UNDEFINED_OFFSET, computeOrigin(this), IrValueParameterSymbolImpl(this), name, index, type.toIrType(),
varargElementType?.toIrType(), isCrossinline, isNoinline varargElementType?.toIrType(), isCrossinline, isNoinline, false
).also { irValueParameter -> ).also { irValueParameter ->
if (descriptor.declaresDefaultValue()) { if (descriptor.declaresDefaultValue()) {
irValueParameter.defaultValue = irValueParameter.defaultValue =
@@ -348,7 +348,8 @@ open class DeepCopyIrTreeWithSymbols(
declaration.type.remapType(), declaration.type.remapType(),
declaration.varargElementType?.remapType(), declaration.varargElementType?.remapType(),
declaration.isCrossinline, declaration.isCrossinline,
declaration.isNoinline declaration.isNoinline,
false
).apply { ).apply {
transformAnnotations(declaration) transformAnnotations(declaration)
defaultValue = declaration.defaultValue?.transform() defaultValue = declaration.defaultValue?.transform()
@@ -524,7 +524,7 @@ class RenderIrElementVisitor(private val normalizeNames: Boolean = false) : IrEl
renderFlagsList( renderFlagsList(
"vararg".takeIf { varargElementType != null }, "vararg".takeIf { varargElementType != null },
"crossinline".takeIf { isCrossinline }, "crossinline".takeIf { isCrossinline },
"noinline".takeIf { isNoinline } "noinline".takeIf { isNoinline },
) )
override fun visitLocalDelegatedProperty(declaration: IrLocalDelegatedProperty, data: Nothing?): String = override fun visitLocalDelegatedProperty(declaration: IrLocalDelegatedProperty, data: Nothing?): String =
@@ -896,7 +896,7 @@ class SymbolTable(
valueParameterFactory: (IrValueParameterSymbol) -> IrValueParameter = { valueParameterFactory: (IrValueParameterSymbol) -> IrValueParameter = {
irFactory.createValueParameter( irFactory.createValueParameter(
startOffset, endOffset, origin, it, nameProvider.nameForDeclaration(descriptor), startOffset, endOffset, origin, it, nameProvider.nameForDeclaration(descriptor),
descriptor.indexOrMinusOne, type, varargElementType, descriptor.isCrossinline, descriptor.isNoinline descriptor.indexOrMinusOne, type, varargElementType, descriptor.isCrossinline, descriptor.isNoinline, false
) )
} }
): IrValueParameter = ): IrValueParameter =
@@ -1009,7 +1009,8 @@ abstract class IrFileDeserializer(
if (proto.hasVarargElementType()) deserializeIrType(proto.varargElementType) else null, if (proto.hasVarargElementType()) deserializeIrType(proto.varargElementType) else null,
flags.isCrossInline, flags.isCrossInline,
flags.isNoInline, flags.isNoInline,
flags.isHidden flags.isHidden,
false
).apply { ).apply {
if (proto.hasDefaultValue()) if (proto.hasDefaultValue())
defaultValue = irFactory.createExpressionBody(deserializeExpressionBody(proto.defaultValue)) defaultValue = irFactory.createExpressionBody(deserializeExpressionBody(proto.defaultValue))
@@ -379,7 +379,7 @@ interface IrBuilderExtension {
fun irValueParameter(descriptor: ParameterDescriptor): IrValueParameter = with(descriptor) { fun irValueParameter(descriptor: ParameterDescriptor): IrValueParameter = with(descriptor) {
factory.createValueParameter( factory.createValueParameter(
function.startOffset, function.endOffset, SERIALIZABLE_PLUGIN_ORIGIN, IrValueParameterSymbolImpl(this), function.startOffset, function.endOffset, SERIALIZABLE_PLUGIN_ORIGIN, IrValueParameterSymbolImpl(this),
name, indexOrMinusOne, type.toIrType(), varargElementType?.toIrType(), isCrossinline, isNoinline name, indexOrMinusOne, type.toIrType(), varargElementType?.toIrType(), isCrossinline, isNoinline, false
).also { ).also {
it.parent = function it.parent = function
} }