@informalsystems/quint
Version:
Core tool for the Quint specification language
150 lines • 9.1 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const mocha_1 = require("mocha");
const chai_1 = require("chai");
const resolver_1 = require("../../src/names/resolver");
const ir_1 = require("../builders/ir");
const idGenerator_1 = require("../../src/idGenerator");
(0, mocha_1.describe)('resolveNames', () => {
const baseDefs = [
'const TEST_CONSTANT: int',
'val unscoped_def = val scoped_def = 10 scoped_def ',
'type MY_TYPE = int',
];
function resolveNamesForExprs(exprs, idGenerator) {
const idGen = idGenerator ?? idGenerator_1.zerog;
const module = (0, ir_1.buildModule)(baseDefs, exprs, undefined, idGen);
return (0, resolver_1.resolveNames)([module]);
}
function resolveNamesForDefs(defs, idGenerator) {
const idGen = idGenerator ?? idGenerator_1.zerog;
const module = (0, ir_1.buildModuleWithDecls)(baseDefs.concat(defs), undefined, idGen);
return (0, resolver_1.resolveNames)([module]);
}
(0, mocha_1.describe)('operator definitions', () => {
(0, mocha_1.it)('finds top level definitions', () => {
const result = resolveNamesForExprs(['TEST_CONSTANT.filter(a => unscoped_def > 0)']);
chai_1.assert.isEmpty(result.errors);
});
(0, mocha_1.it)('finds scoped definitions inside of scope', () => {
const result = resolveNamesForExprs(['TEST_CONSTANT.filter(a => a > 0)']);
chai_1.assert.isEmpty(result.errors);
});
(0, mocha_1.it)('finds unused definitions', () => {
const module = (0, ir_1.buildModule)(baseDefs, ['1 + TEST_CONSTANT'], undefined, idGenerator_1.zerog);
const result = (0, resolver_1.resolveNames)([module]);
chai_1.assert.isEmpty(result.errors);
chai_1.assert.sameDeepMembers(Array.from(result.unusedDefinitions('wrapper')).map(d => d.name), ['unscoped_def', 'MY_TYPE', 'd0']);
});
(0, mocha_1.it)('does not find scoped definitions outside of scope', () => {
const result = resolveNamesForExprs(['TEST_CONSTANT', 'scoped_def']);
chai_1.assert.deepEqual(result.errors, [
{ code: 'QNT404', message: "Name 'scoped_def' not found", reference: 0n, data: {} },
]);
});
(0, mocha_1.it)('find unresolved names inside application', () => {
const result = resolveNamesForExprs(['head(x)', 'x(true)']);
chai_1.assert.deepEqual(result.errors, [
{ code: 'QNT404', message: "Name 'x' not found", reference: 0n, data: {} },
{ code: 'QNT404', message: "Name 'x' not found", reference: 0n, data: {} },
]);
});
(0, mocha_1.it)('find unresolved names inside lambdas', () => {
const result = resolveNamesForExprs(['Nat.filter(a => x > 1)']);
chai_1.assert.deepEqual(result.errors, [{ code: 'QNT404', message: "Name 'x' not found", reference: 0n, data: {} }]);
});
(0, mocha_1.it)('find unresolved names inside lets', () => {
const result = resolveNamesForExprs(['val a = x { true }', 'val b = true { x }']);
chai_1.assert.deepEqual(result.errors, [
{ code: 'QNT404', message: "Name 'x' not found", reference: 0n, data: {} },
{ code: 'QNT404', message: "Name 'x' not found", reference: 0n, data: {} },
]);
});
(0, mocha_1.it)('finds a definition itself with depth information', () => {
const result = resolveNamesForExprs([], (0, idGenerator_1.newIdGenerator)());
chai_1.assert.isEmpty(result.errors);
const def = [...result.table.values()].find(def => def.name === 'unscoped_def' || def.kind === 'def');
chai_1.assert.isNotNull(def);
chai_1.assert.deepEqual(result.table.get(def.id)?.depth, 0);
});
});
(0, mocha_1.describe)('shadowing', () => {
(0, mocha_1.it)('resolves shadowed names', () => {
const result = resolveNamesForDefs(['val shadowing = def foo = (shadowing) => shadowing { foo(1) }', 'val a = shadowing'], (0, idGenerator_1.newIdGenerator)());
chai_1.assert.isEmpty(result.errors);
chai_1.assert.isTrue([...result.table.values()].some(def => def.name === 'shadowing' && def.kind === 'def'));
chai_1.assert.isTrue([...result.table.values()].some(def => def.name === 'shadowing' && def.kind === 'param'));
});
(0, mocha_1.it)('collects depth and shadowing information properly', () => {
const result = resolveNamesForDefs(['val shadowing = val a = 1 { val a = 2 { a } }'], (0, idGenerator_1.newIdGenerator)());
chai_1.assert.isEmpty(result.errors);
chai_1.assert.isTrue([...result.table.values()].some(def => def.name === 'a' && def.depth === 2), 'Could not find first a');
chai_1.assert.isTrue([...result.table.values()].some(def => def.name === 'a' && def.depth === 3 && def.shadowing === true), 'Could not find second a');
});
});
(0, mocha_1.describe)('type aliases', () => {
(0, mocha_1.it)('resolves defined aliases', () => {
const result = resolveNamesForDefs(['const a: MY_TYPE', 'var b: a -> Set[a]']);
chai_1.assert.isEmpty(result.errors);
});
(0, mocha_1.it)('finds unresolved aliases under typed definitions', () => {
const result = resolveNamesForDefs([
'const a: UNKNOWN_TYPE_0',
'var b: UNKNOWN_TYPE_1',
'type C[t] = Set[t]',
'assume d = 1',
]);
chai_1.assert.deepEqual(result.errors, [
{ code: 'QNT404', message: "Type alias 'UNKNOWN_TYPE_0' not found", reference: 0n, data: {} },
{ code: 'QNT404', message: "Type alias 'UNKNOWN_TYPE_1' not found", reference: 0n, data: {} },
]);
});
(0, mocha_1.it)('finds unresolved aliases under chained lets', () => {
const result = resolveNamesForExprs(['val x = 1 { val y: Set[UNKNOWN_TYPE] = 1 { Set(0) } }']);
chai_1.assert.deepEqual(result.errors, [
{ code: 'QNT404', message: "Type alias 'UNKNOWN_TYPE' not found", reference: 0n, data: {} },
]);
});
(0, mocha_1.it)('finds unresolved aliases under Set', () => {
const result = resolveNamesForExprs(['val x: Set[UNKNOWN_TYPE] = 1 { 0 }']);
chai_1.assert.deepEqual(result.errors, [
{ code: 'QNT404', message: "Type alias 'UNKNOWN_TYPE' not found", reference: 0n, data: {} },
]);
});
(0, mocha_1.it)('finds unresolved aliases under List', () => {
const result = resolveNamesForExprs(['val x: List[UNKNOWN_TYPE] = 1 { 0 }']);
chai_1.assert.deepEqual(result.errors, [
{ code: 'QNT404', message: "Type alias 'UNKNOWN_TYPE' not found", reference: 0n, data: {} },
]);
});
(0, mocha_1.it)('finds unresolved aliases under functions', () => {
const result = resolveNamesForExprs(['val x: UNKNOWN_TYPE -> OTHER_UNKNOWN_TYPE = 1 { 0 }']);
chai_1.assert.deepEqual(result.errors, [
{ code: 'QNT404', message: "Type alias 'UNKNOWN_TYPE' not found", reference: 0n, data: {} },
{ code: 'QNT404', message: "Type alias 'OTHER_UNKNOWN_TYPE' not found", reference: 0n, data: {} },
]);
});
(0, mocha_1.it)('finds unresolved aliases under operators', () => {
const result = resolveNamesForExprs(['val f(x): (UNKNOWN_TYPE) => OTHER_UNKNOWN_TYPE = { unscoped_def } { 0 }']);
chai_1.assert.deepEqual(result.errors, [
{ code: 'QNT404', message: "Type alias 'UNKNOWN_TYPE' not found", reference: 0n, data: {} },
{ code: 'QNT404', message: "Type alias 'OTHER_UNKNOWN_TYPE' not found", reference: 0n, data: {} },
]);
});
(0, mocha_1.it)('finds unresolved aliases under tuples', () => {
const result = resolveNamesForExprs(['val x: (UNKNOWN_TYPE, OTHER_UNKNOWN_TYPE) = (1, 2) { 0 }']);
chai_1.assert.deepEqual(result.errors, [
{ code: 'QNT404', message: "Type alias 'UNKNOWN_TYPE' not found", reference: 0n, data: {} },
{ code: 'QNT404', message: "Type alias 'OTHER_UNKNOWN_TYPE' not found", reference: 0n, data: {} },
]);
});
(0, mocha_1.it)('finds unresolved aliases under records', () => {
const result = resolveNamesForExprs(['val x: { a: UNKNOWN_TYPE, b: OTHER_UNKNOWN_TYPE } = { a: 1, b: 2 } { 0 }']);
chai_1.assert.deepEqual(result.errors, [
{ code: 'QNT404', message: "Type alias 'UNKNOWN_TYPE' not found", reference: 0n, data: {} },
{ code: 'QNT404', message: "Type alias 'OTHER_UNKNOWN_TYPE' not found", reference: 0n, data: {} },
]);
});
});
});
//# sourceMappingURL=resolver.test.js.map