12
12
* @module
13
13
*/
14
14
15
- import { fail } from 'assert '
15
+ import { ErrorTree , buildErrorLeaf } from '../errorTree '
16
16
import { FreshVarGenerator } from '../FreshVarGenerator'
17
+
17
18
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'
20
21
import { QuintAppType , QuintType , QuintVarType , Row } from '../ir/quintTypes'
21
22
import { LookupTable } from '../names/base'
22
23
import { zip } from '../util'
23
24
import { Substitutions , applySubstitution } from './substitutions'
25
+ import assert from 'assert'
24
26
25
27
/** Resolves all type applications in an IR object */
26
28
export class TypeApplicationResolver implements IRTransformer {
29
+ // Errors found during type application resolution
30
+ private errors : Map < bigint , ErrorTree > = new Map < bigint , ErrorTree > ( )
27
31
// Fresh variable generator, shared with the TypeInferrer
28
32
private freshVarGenerator : FreshVarGenerator
29
33
// Lookup table from the parser
30
34
private table : LookupTable
31
35
32
- constructor ( table : LookupTable , freshVarGenerator : FreshVarGenerator ) {
36
+ constructor ( table : LookupTable ) {
33
37
this . table = table
34
- this . freshVarGenerator = freshVarGenerator
38
+ this . freshVarGenerator = new FreshVarGenerator ( )
39
+
40
+ this . table . forEach ( ( def , id ) => {
41
+ const resolvedLookupDef = transformLookupDefinition ( this , def )
42
+ this . table . set ( id , resolvedLookupDef )
43
+ } )
44
+ }
45
+
46
+ resolveTypeApplications ( decls : QuintDeclaration [ ] ) : [ Map < bigint , ErrorTree > , QuintDeclaration [ ] ] {
47
+ const resolvedDecls = decls . map ( decl => transformDeclaration ( this , decl ) )
48
+ const errors = this . errors
49
+ return [ errors , resolvedDecls ]
35
50
}
36
51
37
52
exitType ( t : QuintType ) : QuintType {
38
- return this . resolveTypeApplications ( t )
53
+ return this . resolveTypeApplicationsForType ( t )
39
54
}
40
55
41
56
// Transforms `t` by resolving all the type applications in all its sub-terms
@@ -46,33 +61,46 @@ export class TypeApplicationResolver implements IRTransformer {
46
61
// type Bar[x, y] = {i: x, j: y}
47
62
//
48
63
//
49
- // resolveTypeApplications (Foo[a, {f: Bar[int, str]}]) = (a, {f: {i: int, j: str}})
50
- resolveTypeApplications ( t : QuintType ) : QuintType {
64
+ // resolveTypeApplicationsForType (Foo[a, {f: Bar[int, str]}]) = (a, {f: {i: int, j: str}})
65
+ private resolveTypeApplicationsForType ( t : QuintType ) : QuintType {
51
66
const f : ( _ : QuintType ) => QuintType = x => ( x . kind !== 'app' ? x : this . resolveTypeApp ( x ) )
52
67
return mapType ( f , t )
53
68
}
54
69
55
70
private resolveTypeApp ( t : QuintAppType ) : QuintType {
56
- if ( ! t . ctor . id ) {
57
- // This should be ensured by parsing
58
- fail (
59
- `invalid IR node: type constructor ${ t . ctor . name } in type application ${ typeToString ( t ) } id ${ t . id } has no id`
60
- )
61
- }
71
+ // Ensured by parsing
72
+ assert ( t . id , `invalid IR node: type application ${ typeToString ( t ) } has no id` )
73
+ // Ensured by parsing
74
+ assert (
75
+ t . ctor . id ,
76
+ `invalid IR node: type constructor ${ t . ctor . name } in type application ${ typeToString ( t ) } id ${ t . id } has no id`
77
+ )
62
78
63
79
const typeDef = this . table . get ( t . ctor . id )
64
- if ( ! typeDef ) {
65
- // This should be ensured by name resolution
66
- fail ( `invalid IR reference: type constructor ${ t . ctor . name } with id ${ t . ctor . id } has no type definition` )
67
- }
68
-
69
- if ( typeDef . kind !== 'typedef' || ! typeDef . type ) {
70
- // This should be ensured by the grammar and by name resolution
71
- fail ( `invalid kind looked up for constructor of type application with id ${ t . ctor . id } ` )
72
- }
80
+ // Ensured by name resolution
81
+ assert ( typeDef , `invalid IR reference: type constructor ${ t . ctor . name } with id ${ t . ctor . id } has no type definition` )
82
+ // Ensured by the grammar and by name resolution
83
+ assert (
84
+ typeDef . kind === 'typedef' && typeDef . type ,
85
+ `invalid kind looked up for constructor of type application with id ${ t . ctor . id } `
86
+ )
73
87
74
88
const { params, type } = this . freshTypeFromDef ( typeDef as QuintTypeAlias )
75
89
90
+ // NOTE: Early exit on error
91
+ // Check for arity mismatch in type application
92
+ if ( params . length !== t . args . length ) {
93
+ const ctorMsg = typeToString ( t . ctor )
94
+ const typeArgsMsg = t . args . map ( typeToString ) . join ( ', ' )
95
+ const manyOrFew = params . length > t . args . length ? 'few' : 'many'
96
+ const err = buildErrorLeaf (
97
+ `applying type constructor ${ ctorMsg } to arguments ${ typeArgsMsg } ` ,
98
+ `too ${ manyOrFew } arguments supplied: ${ ctorMsg } only accepts ${ params . length } parameters`
99
+ )
100
+ this . errors . set ( t . id , err )
101
+ return t
102
+ }
103
+
76
104
// Substitute the type `args` for each corresponding fresh variable
77
105
const subs : Substitutions = zip ( params , t . args ) . map ( ( [ param , arg ] ) => ( {
78
106
kind : 'type' ,
0 commit comments