Skip to content

Commit 06c24e7

Browse files
committed
Resolve type applications at the IR level
1 parent 62d6b55 commit 06c24e7

File tree

3 files changed

+31
-27
lines changed

3 files changed

+31
-27
lines changed

quint/src/quintAnalyzer.ts

+12-5
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { ModeChecker } from './effects/modeChecker'
2222
import { QuintError } from './quintError'
2323
import { errorTreeToString } from './errorTree'
2424
import { MultipleUpdatesChecker } from './effects/MultipleUpdatesChecker'
25+
import { TypeApplicationResolver } from './types/typeApplicationResolution'
2526

2627
/* Products from static analysis */
2728
export type AnalysisOutput = {
@@ -42,7 +43,7 @@ export type AnalysisResult = [QuintError[], AnalysisOutput]
4243
*/
4344
export function analyzeModules(lookupTable: LookupTable, quintModules: QuintModule[]): AnalysisResult {
4445
const analyzer = new QuintAnalyzer(lookupTable)
45-
quintModules.map(m => analyzer.analyzeDeclarations(m.declarations))
46+
quintModules.forEach(m => (m.declarations = analyzer.analyzeDeclarations(m.declarations)))
4647
return analyzer.getResult()
4748
}
4849

@@ -75,6 +76,7 @@ export function analyzeInc(
7576
* @param previousOutput - The previous analysis output to be used as a starting point.
7677
*/
7778
class QuintAnalyzer {
79+
private typeApplicationResolver: TypeApplicationResolver
7880
private effectInferrer: EffectInferrer
7981
private typeInferrer: TypeInferrer
8082
private modeChecker: ModeChecker
@@ -84,17 +86,20 @@ class QuintAnalyzer {
8486
private output: AnalysisOutput = { types: new Map(), effects: new Map(), modes: new Map() }
8587

8688
constructor(lookupTable: LookupTable, previousOutput?: AnalysisOutput) {
89+
this.typeApplicationResolver = new TypeApplicationResolver(lookupTable)
8790
this.typeInferrer = new TypeInferrer(lookupTable, previousOutput?.types)
8891
this.effectInferrer = new EffectInferrer(lookupTable, previousOutput?.effects)
8992
this.multipleUpdatesChecker = new MultipleUpdatesChecker()
9093
this.modeChecker = new ModeChecker(previousOutput?.modes)
9194
}
9295

93-
analyzeDeclarations(decls: QuintDeclaration[]): void {
94-
const [typeErrMap, types] = this.typeInferrer.inferTypes(decls)
95-
const [effectErrMap, effects] = this.effectInferrer.inferEffects(decls)
96+
analyzeDeclarations(decls: QuintDeclaration[]): QuintDeclaration[] {
97+
const resolvedDecls = this.typeApplicationResolver.resolveTypeApplications(decls)
98+
99+
const [typeErrMap, types] = this.typeInferrer.inferTypes(resolvedDecls)
100+
const [effectErrMap, effects] = this.effectInferrer.inferEffects(resolvedDecls)
96101
const updatesErrMap = this.multipleUpdatesChecker.checkEffects([...effects.values()])
97-
const [modeErrMap, modes] = this.modeChecker.checkModes(decls, effects)
102+
const [modeErrMap, modes] = this.modeChecker.checkModes(resolvedDecls, effects)
98103

99104
const errorTrees = [...typeErrMap, ...effectErrMap]
100105

@@ -114,6 +119,8 @@ class QuintAnalyzer {
114119
effects: new Map([...this.output.effects, ...effects]),
115120
modes: new Map([...this.output.modes, ...modes]),
116121
}
122+
123+
return resolvedDecls
117124
}
118125

119126
getResult(): AnalysisResult {

quint/src/types/inferrer.ts

+2-15
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,17 @@
1616
import { ErrorTree } from '../errorTree'
1717
import { walkDeclaration } from '../ir/IRVisitor'
1818
import { LookupTable } from '../names/base'
19-
import { QuintDeclaration } from '../ir/quintIr'
19+
import { QuintDeclaration, isDef } from '../ir/quintIr'
2020
import { TypeScheme } from './base'
2121
import { ConstraintGeneratorVisitor } from './constraintGenerator'
2222
import { solveConstraint } from './constraintSolver'
2323
import { simplify } from './simplification'
24-
import { TypeApplicationResolver } from './typeApplicationResolution'
25-
import { transformDeclaration, transformLookupDefinition } from '../ir/IRTransformer'
2624

2725
export type TypeInferenceResult = [Map<bigint, ErrorTree>, Map<bigint, TypeScheme>]
2826

2927
export class TypeInferrer extends ConstraintGeneratorVisitor {
30-
private resolver: TypeApplicationResolver
3128
constructor(table: LookupTable, types?: Map<bigint, TypeScheme>) {
3229
super(solveConstraint, table, types)
33-
this.resolver = new TypeApplicationResolver(this.table, this.freshVarGenerator)
3430
}
3531

3632
/**
@@ -43,17 +39,8 @@ export class TypeInferrer extends ConstraintGeneratorVisitor {
4339
*/
4440
inferTypes(declarations: QuintDeclaration[]): TypeInferenceResult {
4541
// Resolve all type applications used in expressions in the lookup table
46-
this.table.forEach((def, id) => {
47-
// Don't resolve type definitions, since those should keep their original type variable names
48-
// They are our source of truth for all resolutions
49-
if (def.kind !== 'typedef') {
50-
const resolvedLookupDef = transformLookupDefinition(this.resolver, def)
51-
this.table.set(id, resolvedLookupDef)
52-
}
53-
})
5442
declarations.forEach(decl => {
55-
const resolvedDecl = transformDeclaration(this.resolver, decl)
56-
walkDeclaration(this, resolvedDecl)
43+
walkDeclaration(this, decl)
5744
})
5845
const simplifiedTypes = new Map([...this.types.entries()].map(([id, t]) => [id, simplify(t)]))
5946
return [this.errors, simplifiedTypes]

quint/src/types/typeApplicationResolution.ts

+17-7
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@
1414

1515
import { fail } from 'assert'
1616
import { FreshVarGenerator } from '../FreshVarGenerator'
17+
1718
import { typeToString } from '../ir/IRprinting'
18-
import { IRTransformer, transformType } from '../ir/IRTransformer'
19-
import { QuintTypeAlias } from '../ir/quintIr'
19+
import { IRTransformer, transformDeclaration, transformLookupDefinition, transformType } from '../ir/IRTransformer'
20+
import { QuintDeclaration, QuintTypeAlias } from '../ir/quintIr'
2021
import { QuintAppType, QuintType, QuintVarType, Row } from '../ir/quintTypes'
2122
import { LookupTable } from '../names/base'
2223
import { zip } from '../util'
@@ -29,13 +30,22 @@ export class TypeApplicationResolver implements IRTransformer {
2930
// Lookup table from the parser
3031
private table: LookupTable
3132

32-
constructor(table: LookupTable, freshVarGenerator: FreshVarGenerator) {
33+
constructor(table: LookupTable) {
3334
this.table = table
34-
this.freshVarGenerator = freshVarGenerator
35+
this.freshVarGenerator = new FreshVarGenerator()
36+
37+
this.table.forEach((def, id) => {
38+
const resolvedLookupDef = transformLookupDefinition(this, def)
39+
this.table.set(id, resolvedLookupDef)
40+
})
41+
}
42+
43+
resolveTypeApplications(decls: QuintDeclaration[]): QuintDeclaration[] {
44+
return decls.map(decl => transformDeclaration(this, decl))
3545
}
3646

3747
exitType(t: QuintType): QuintType {
38-
return this.resolveTypeApplications(t)
48+
return this.resolveTypeApplicationsForType(t)
3949
}
4050

4151
// Transforms `t` by resolving all the type applications in all its sub-terms
@@ -46,8 +56,8 @@ export class TypeApplicationResolver implements IRTransformer {
4656
// type Bar[x, y] = {i: x, j: y}
4757
//
4858
//
49-
// resolveTypeApplications(Foo[a, {f: Bar[int, str]}]) = (a, {f: {i: int, j: str}})
50-
resolveTypeApplications(t: QuintType): QuintType {
59+
// resolveTypeApplicationsForType(Foo[a, {f: Bar[int, str]}]) = (a, {f: {i: int, j: str}})
60+
private resolveTypeApplicationsForType(t: QuintType): QuintType {
5161
const f: (_: QuintType) => QuintType = x => (x.kind !== 'app' ? x : this.resolveTypeApp(x))
5262
return mapType(f, t)
5363
}

0 commit comments

Comments
 (0)