Skip to content

Commit 5367f6d

Browse files
mcpiromanSpace Team
authored andcommitted
[IR] Dynamically dispatch by IR element class in IrValidator
This commit allows checkers to be defined and added to the validator from other modules independently of the core validator code. Also removes some boilerplate code. KT-76601
1 parent a46bee0 commit 5367f6d

File tree

6 files changed

+72
-235
lines changed

6 files changed

+72
-235
lines changed

compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/IrValidator.kt

Lines changed: 52 additions & 214 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,27 @@
55

66
package org.jetbrains.kotlin.backend.common
77

8-
import org.jetbrains.kotlin.backend.common.checkers.*
8+
import org.jetbrains.kotlin.backend.common.checkers.IrElementChecker
9+
import org.jetbrains.kotlin.backend.common.checkers.IrValidationError
10+
import org.jetbrains.kotlin.backend.common.checkers.TreeConsistencyError
11+
import org.jetbrains.kotlin.backend.common.checkers.checkTreeConsistency
912
import org.jetbrains.kotlin.backend.common.checkers.context.*
1013
import org.jetbrains.kotlin.backend.common.checkers.declaration.*
1114
import org.jetbrains.kotlin.backend.common.checkers.expression.*
1215
import org.jetbrains.kotlin.backend.common.checkers.symbol.IrSymbolChecker
1316
import org.jetbrains.kotlin.backend.common.checkers.symbol.IrVisibilityChecker
14-
import org.jetbrains.kotlin.backend.common.checkers.symbol.check
1517
import org.jetbrains.kotlin.backend.common.checkers.type.IrTypeChecker
1618
import org.jetbrains.kotlin.backend.common.checkers.type.IrTypeParameterScopeChecker
17-
import org.jetbrains.kotlin.backend.common.checkers.type.check
1819
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
1920
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
2021
import org.jetbrains.kotlin.config.IrVerificationMode
2122
import org.jetbrains.kotlin.ir.IrBuiltIns
2223
import org.jetbrains.kotlin.ir.IrElement
23-
import org.jetbrains.kotlin.ir.declarations.*
24-
import org.jetbrains.kotlin.ir.expressions.*
24+
import org.jetbrains.kotlin.ir.declarations.IrDeclarationBase
25+
import org.jetbrains.kotlin.ir.declarations.IrFile
26+
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
27+
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
28+
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
2529
import org.jetbrains.kotlin.ir.symbols.IrSymbol
2630
import org.jetbrains.kotlin.ir.types.IrType
2731
import org.jetbrains.kotlin.ir.util.IrTreeSymbolsVisitor
@@ -93,258 +97,92 @@ private class IrFileValidator(
9397
private val context: CheckerContext
9498
) : IrTreeSymbolsVisitor() {
9599
private val contextUpdaters: MutableList<ContextUpdater> = mutableListOf(ParentChainUpdater)
96-
97-
private val fieldCheckers: MutableList<IrElementChecker<IrField>> = mutableListOf()
98-
private val fieldAccessExpressionCheckers: MutableList<IrElementChecker<IrFieldAccessExpression>> = mutableListOf()
99-
private val typeCheckers: MutableList<IrTypeChecker> = mutableListOf()
100-
private val symbolCheckers: MutableList<IrSymbolChecker> = mutableListOf()
101-
private val declarationReferenceCheckers: MutableList<IrElementChecker<IrDeclarationReference>> = mutableListOf()
102-
private val varargCheckers: MutableList<IrElementChecker<IrVararg>> = mutableListOf()
103-
private val valueParameterCheckers: MutableList<IrElementChecker<IrValueParameter>> = mutableListOf()
104-
private val valueAccessCheckers: MutableList<IrElementChecker<IrValueAccessExpression>> = mutableListOf()
105-
private val functionAccessCheckers: MutableList<IrElementChecker<IrFunctionAccessExpression>> = mutableListOf(IrNoInlineUseSitesChecker)
106-
private val functionReferenceCheckers: MutableList<IrElementChecker<IrFunctionReference>> = mutableListOf()
107-
private val constCheckers: MutableList<IrElementChecker<IrConst>> = mutableListOf()
108-
private val stringConcatenationCheckers: MutableList<IrElementChecker<IrStringConcatenation>> = mutableListOf()
109-
private val getObjectValueCheckers: MutableList<IrElementChecker<IrGetObjectValue>> = mutableListOf()
110-
private val getValueCheckers: MutableList<IrElementChecker<IrGetValue>> = mutableListOf()
111-
private val setValueCheckers: MutableList<IrElementChecker<IrSetValue>> = mutableListOf(IrSetValueAssignabilityChecker)
112-
private val getFieldCheckers: MutableList<IrElementChecker<IrGetField>> = mutableListOf()
113-
private val setFieldCheckers: MutableList<IrElementChecker<IrSetField>> = mutableListOf()
114-
private val delegatingConstructorCallCheckers: MutableList<IrElementChecker<IrDelegatingConstructorCall>> = mutableListOf()
115-
private val instanceInitializerCallCheckers: MutableList<IrElementChecker<IrInstanceInitializerCall>> = mutableListOf()
116-
private val loopCheckers: MutableList<IrElementChecker<IrLoop>> = mutableListOf()
117-
private val breakContinueCheckers: MutableList<IrElementChecker<IrBreakContinue>> = mutableListOf()
118-
private val returnCheckers: MutableList<IrElementChecker<IrReturn>> = mutableListOf()
119-
private val throwCheckers: MutableList<IrElementChecker<IrThrow>> = mutableListOf()
120-
private val functionCheckers: MutableList<IrElementChecker<IrFunction>> = mutableListOf(
121-
IrFunctionDispatchReceiverChecker, IrFunctionParametersChecker, IrConstructorReceiverChecker, IrFunctionPropertiesChecker
100+
private val elementCheckers: MutableList<IrElementChecker<*>> = mutableListOf(
101+
IrNoInlineUseSitesChecker, IrSetValueAssignabilityChecker,
102+
IrFunctionDispatchReceiverChecker, IrFunctionParametersChecker, IrConstructorReceiverChecker,
103+
IrTypeOperatorTypeOperandChecker,
104+
IrPropertyAccessorsChecker, IrFunctionPropertiesChecker,
122105
)
123-
private val declarationBaseCheckers: MutableList<IrElementChecker<IrDeclaration>> = mutableListOf()
124-
private val propertyReferenceCheckers: MutableList<IrElementChecker<IrPropertyReference>> = mutableListOf()
125-
private val localDelegatedPropertyReferenceCheckers: MutableList<IrElementChecker<IrLocalDelegatedPropertyReference>> = mutableListOf()
126-
private val expressionCheckers: MutableList<IrElementChecker<IrExpression>> = mutableListOf()
127-
private val typeOperatorCheckers: MutableList<IrElementChecker<IrTypeOperatorCall>> = mutableListOf(IrTypeOperatorTypeOperandChecker)
128-
private val propertyCheckers: MutableList<IrElementChecker<IrProperty>> = mutableListOf(IrPropertyAccessorsChecker)
129-
130-
private val callCheckers: MutableList<IrElementChecker<IrCall>> = mutableListOf()
106+
private val symbolCheckers: MutableList<IrSymbolChecker> = mutableListOf()
107+
private val typeCheckers: MutableList<IrTypeChecker> = mutableListOf()
131108

132109
init {
133110
if (config.checkValueScopes) {
134111
contextUpdaters.add(ValueScopeUpdater)
135-
valueAccessCheckers.add(IrValueAccessScopeChecker)
112+
elementCheckers.add(IrValueAccessScopeChecker)
136113
}
137114
if (config.checkTypeParameterScopes) {
138115
contextUpdaters.add(TypeParameterScopeUpdater)
139116
typeCheckers.add(IrTypeParameterScopeChecker)
140117
}
141118
if (config.checkAllKotlinFieldsArePrivate) {
142-
fieldCheckers.add(IrFieldVisibilityChecker)
119+
elementCheckers.add(IrFieldVisibilityChecker)
143120
}
144121
if (config.checkCrossFileFieldUsage) {
145-
fieldAccessExpressionCheckers.add(IrCrossFileFieldUsageChecker)
122+
elementCheckers.add(IrCrossFileFieldUsageChecker)
146123
}
147124
if (config.checkVisibilities) {
148125
symbolCheckers.add(IrVisibilityChecker)
149126
}
150127
if (config.checkVarargTypes) {
151-
varargCheckers.add(IrVarargTypesChecker)
152-
valueParameterCheckers.add(IrValueParameterVarargTypesChecker)
128+
elementCheckers.add(IrVarargTypesChecker)
129+
elementCheckers.add(IrValueParameterVarargTypesChecker)
153130
}
154131
if (config.checkTypes) {
155-
constCheckers.add(IrConstTypeChecker)
156-
stringConcatenationCheckers.add(IrStringConcatenationTypeChecker)
157-
getObjectValueCheckers.add(IrGetObjectValueTypeChecker)
158-
getValueCheckers.add(IrGetValueTypeChecker)
159-
setValueCheckers.add(IrUnitTypeExpressionChecker)
160-
getFieldCheckers.add(IrGetFieldTypeChecker)
161-
setFieldCheckers.add(IrUnitTypeExpressionChecker)
162-
callCheckers.add(IrCallTypeChecker)
163-
delegatingConstructorCallCheckers.add(IrUnitTypeExpressionChecker)
164-
instanceInitializerCallCheckers.add(IrUnitTypeExpressionChecker)
165-
typeOperatorCheckers.add(IrTypeOperatorTypeChecker)
166-
loopCheckers.add(IrUnitTypeExpressionChecker)
167-
breakContinueCheckers.add(IrNothingTypeExpressionChecker)
168-
returnCheckers.add(IrNothingTypeExpressionChecker)
169-
throwCheckers.add(IrNothingTypeExpressionChecker)
170-
fieldAccessExpressionCheckers.add(IrDynamicTypeFieldAccessChecker)
132+
elementCheckers.add(IrConstTypeChecker)
133+
elementCheckers.add(IrStringConcatenationTypeChecker)
134+
elementCheckers.add(IrGetObjectValueTypeChecker)
135+
elementCheckers.add(IrGetValueTypeChecker)
136+
elementCheckers.add(IrUnitTypeExpressionChecker)
137+
elementCheckers.add(IrNothingTypeExpressionChecker)
138+
elementCheckers.add(IrGetFieldTypeChecker)
139+
elementCheckers.add(IrCallTypeChecker)
140+
elementCheckers.add(IrTypeOperatorTypeChecker)
141+
elementCheckers.add(IrDynamicTypeFieldAccessChecker)
171142
}
172143
if (config.checkIrExpressionBodyInFunction) {
173-
functionCheckers.add(IrExpressionBodyInFunctionChecker)
144+
elementCheckers.add(IrExpressionBodyInFunctionChecker)
174145
}
175146
if (config.checkOverridePrivateDeclaration) {
176-
declarationBaseCheckers.add(IrPrivateDeclarationOverrideChecker)
147+
elementCheckers.add(IrPrivateDeclarationOverrideChecker)
177148
}
178149
}
179150

151+
private val checkersPerElement = object : ClassValue<List<IrElementChecker<*>>>() {
152+
override fun computeValue(type: Class<*>): List<IrElementChecker<*>> =
153+
elementCheckers.filter { it.elementClass.isAssignableFrom(type) }
154+
}
155+
180156
override fun visitElement(element: IrElement) {
181157
var block = { element.acceptChildrenVoid(this) }
182158
for (contextUpdater in contextUpdaters) {
183159
val currentBlock = block
184160
block = { contextUpdater.runInNewContext(context, element, currentBlock) }
185161
}
186162
block()
187-
}
188-
189-
override fun visitConst(expression: IrConst) {
190-
super.visitConst(expression)
191-
constCheckers.check(expression, context)
192-
}
193-
194-
override fun visitStringConcatenation(expression: IrStringConcatenation) {
195-
super.visitStringConcatenation(expression)
196-
stringConcatenationCheckers.check(expression, context)
197-
}
198-
199-
override fun visitGetObjectValue(expression: IrGetObjectValue) {
200-
super.visitGetObjectValue(expression)
201-
getObjectValueCheckers.check(expression, context)
202-
}
203-
204-
// TODO: visitGetEnumValue
205-
206-
override fun visitGetValue(expression: IrGetValue) {
207-
super.visitGetValue(expression)
208-
getValueCheckers.check(expression, context)
209-
}
210-
211-
override fun visitSetValue(expression: IrSetValue) {
212-
super.visitSetValue(expression)
213-
setValueCheckers.check(expression, context)
214-
}
215-
216-
override fun visitGetField(expression: IrGetField) {
217-
super.visitGetField(expression)
218-
getFieldCheckers.check(expression, context)
219-
}
220-
221-
override fun visitSetField(expression: IrSetField) {
222-
super.visitSetField(expression)
223-
setFieldCheckers.check(expression, context)
224-
}
225-
226-
override fun visitCall(expression: IrCall) {
227-
super.visitCall(expression)
228-
callCheckers.check(expression, context)
229-
}
230-
231-
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall) {
232-
super.visitDelegatingConstructorCall(expression)
233-
delegatingConstructorCallCheckers.check(expression, context)
234-
}
235-
236-
override fun visitInstanceInitializerCall(expression: IrInstanceInitializerCall) {
237-
super.visitInstanceInitializerCall(expression)
238-
instanceInitializerCallCheckers.check(expression, context)
239-
}
240-
241-
override fun visitTypeOperator(expression: IrTypeOperatorCall) {
242-
super.visitTypeOperator(expression)
243-
typeOperatorCheckers.check(expression, context)
244-
}
245-
246-
override fun visitLoop(loop: IrLoop) {
247-
super.visitLoop(loop)
248-
loopCheckers.check(loop, context)
249-
}
250-
251-
override fun visitBreakContinue(jump: IrBreakContinue) {
252-
super.visitBreakContinue(jump)
253-
breakContinueCheckers.check(jump, context)
254-
}
255-
256-
override fun visitReturn(expression: IrReturn) {
257-
super.visitReturn(expression)
258-
returnCheckers.check(expression, context)
259-
}
260-
261-
override fun visitThrow(expression: IrThrow) {
262-
super.visitThrow(expression)
263-
throwCheckers.check(expression, context)
264-
}
265-
266-
override fun visitFunction(declaration: IrFunction) {
267-
super.visitFunction(declaration)
268-
functionCheckers.check(declaration, context)
269-
}
270163

271-
override fun visitValueAccess(expression: IrValueAccessExpression) {
272-
super.visitValueAccess(expression)
273-
valueAccessCheckers.check(expression, context)
164+
for (checker in checkersPerElement.get(element.javaClass)) {
165+
@Suppress("UNCHECKED_CAST")
166+
(checker as IrElementChecker<IrElement>).check(element, context)
167+
}
274168
}
275169

276-
override fun visitField(declaration: IrField) {
277-
super.visitField(declaration)
278-
fieldCheckers.check(declaration, context)
170+
override fun visitAnnotationUsage(annotationUsage: IrConstructorCall) {
171+
context.withinAnnotationUsageSubTree {
172+
super.visitAnnotationUsage(annotationUsage)
173+
}
279174
}
280175

281-
override fun visitFieldAccess(expression: IrFieldAccessExpression) {
282-
super.visitFieldAccess(expression)
283-
fieldAccessExpressionCheckers.check(expression, context)
176+
override fun visitSymbol(container: IrElement, symbol: IrSymbol) {
177+
for (checker in symbolCheckers) {
178+
checker.check(symbol, container, context)
179+
}
284180
}
285181

286182
override fun visitType(container: IrElement, type: IrType) {
287183
super.visitType(container, type)
288-
typeCheckers.check(type, container, context)
289-
}
290-
291-
override fun visitSymbol(container: IrElement, symbol: IrSymbol) {
292-
symbolCheckers.check(symbol, container, context)
293-
}
294-
295-
override fun visitDeclarationReference(expression: IrDeclarationReference) {
296-
super.visitDeclarationReference(expression)
297-
declarationReferenceCheckers.check(expression, context)
298-
}
299-
300-
override fun visitDeclaration(declaration: IrDeclarationBase) {
301-
super.visitDeclaration(declaration)
302-
declarationBaseCheckers.check(declaration, context)
303-
}
304-
305-
override fun visitPropertyReference(expression: IrPropertyReference) {
306-
super.visitPropertyReference(expression)
307-
propertyReferenceCheckers.check(expression, context)
308-
}
309-
310-
override fun visitLocalDelegatedPropertyReference(expression: IrLocalDelegatedPropertyReference) {
311-
super.visitLocalDelegatedPropertyReference(expression)
312-
localDelegatedPropertyReferenceCheckers.check(expression, context)
313-
}
314-
315-
override fun visitExpression(expression: IrExpression) {
316-
super.visitExpression(expression)
317-
expressionCheckers.check(expression, context)
318-
}
319-
320-
override fun visitVararg(expression: IrVararg) {
321-
super.visitVararg(expression)
322-
varargCheckers.check(expression, context)
323-
}
324-
325-
override fun visitValueParameter(declaration: IrValueParameter) {
326-
super.visitValueParameter(declaration)
327-
valueParameterCheckers.check(declaration, context)
328-
}
329-
330-
override fun visitFunctionReference(expression: IrFunctionReference) {
331-
super.visitFunctionReference(expression)
332-
functionReferenceCheckers.check(expression, context)
333-
}
334-
335-
override fun visitFunctionAccess(expression: IrFunctionAccessExpression) {
336-
super.visitFunctionAccess(expression)
337-
functionAccessCheckers.check(expression, context)
338-
}
339-
340-
override fun visitProperty(declaration: IrProperty) {
341-
super.visitProperty(declaration)
342-
propertyCheckers.check(declaration, context)
343-
}
344-
345-
override fun visitAnnotationUsage(annotationUsage: IrConstructorCall) {
346-
context.withinAnnotationUsageSubTree {
347-
super.visitAnnotationUsage(annotationUsage)
184+
for (checker in typeCheckers) {
185+
checker.check(type, container, context)
348186
}
349187
}
350188
}

compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/checkers/IrElementChecker.kt

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,12 @@ package org.jetbrains.kotlin.backend.common.checkers
77

88
import org.jetbrains.kotlin.backend.common.checkers.context.CheckerContext
99
import org.jetbrains.kotlin.ir.IrElement
10-
import org.jetbrains.kotlin.ir.expressions.IrExpression
1110
import kotlin.reflect.KClass
1211

1312
abstract class IrElementChecker<in E : IrElement>(
1413
elementClass: KClass<in E>,
1514
) {
16-
abstract fun check(element: E, context: CheckerContext)
17-
}
15+
internal val elementClass: Class<in E> = elementClass.java
1816

19-
internal fun <E : IrElement> List<IrElementChecker<E>>.check(element: E, context: CheckerContext) {
20-
for (checker in this) {
21-
checker.check(element, context)
22-
}
17+
abstract fun check(element: E, context: CheckerContext)
2318
}

compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/checkers/expression/IrNothingTypeExpressionChecker.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,16 @@ package org.jetbrains.kotlin.backend.common.checkers.expression
88
import org.jetbrains.kotlin.backend.common.checkers.IrElementChecker
99
import org.jetbrains.kotlin.backend.common.checkers.context.CheckerContext
1010
import org.jetbrains.kotlin.backend.common.checkers.ensureTypeIs
11+
import org.jetbrains.kotlin.ir.expressions.IrBreakContinue
1112
import org.jetbrains.kotlin.ir.expressions.IrExpression
13+
import org.jetbrains.kotlin.ir.expressions.IrReturn
14+
import org.jetbrains.kotlin.ir.expressions.IrThrow
1215

1316
object IrNothingTypeExpressionChecker : IrElementChecker<IrExpression>(IrExpression::class) {
1417
override fun check(element: IrExpression, context: CheckerContext) {
15-
element.ensureTypeIs(context.irBuiltIns.nothingType, context)
18+
when (element) {
19+
is IrBreakContinue, is IrReturn, is IrThrow
20+
-> element.ensureTypeIs(context.irBuiltIns.nothingType, context)
21+
}
1622
}
1723
}

compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/checkers/expression/IrUnitTypeExpressionChecker.kt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,20 @@ package org.jetbrains.kotlin.backend.common.checkers.expression
88
import org.jetbrains.kotlin.backend.common.checkers.IrElementChecker
99
import org.jetbrains.kotlin.backend.common.checkers.context.CheckerContext
1010
import org.jetbrains.kotlin.backend.common.checkers.ensureTypeIs
11+
import org.jetbrains.kotlin.ir.expressions.IrDelegatingConstructorCall
1112
import org.jetbrains.kotlin.ir.expressions.IrExpression
13+
import org.jetbrains.kotlin.ir.expressions.IrInstanceInitializerCall
14+
import org.jetbrains.kotlin.ir.expressions.IrLoop
15+
import org.jetbrains.kotlin.ir.expressions.IrSetField
16+
import org.jetbrains.kotlin.ir.expressions.IrSetValue
1217

1318
object IrUnitTypeExpressionChecker : IrElementChecker<IrExpression>(IrExpression::class) {
1419
override fun check(element: IrExpression, context: CheckerContext) {
15-
element.ensureTypeIs(context.irBuiltIns.unitType, context)
20+
when (element) {
21+
is IrSetValue, is IrSetField,
22+
is IrLoop,
23+
is IrDelegatingConstructorCall, is IrInstanceInitializerCall,
24+
-> element.ensureTypeIs(context.irBuiltIns.unitType, context)
25+
}
1626
}
1727
}

0 commit comments

Comments
 (0)