UNPKG

@informalsystems/quint

Version:

Core tool for the Quint specification language

337 lines (255 loc) 11.7 kB
import { describe, it } from 'mocha' import { assert } from 'chai' import { buildModuleWithDecls } from '../builders/ir' import { QuintError, QuintModule } from '../../src' import { NameCollector } from '../../src/names/collector' import { walkModule } from '../../src/ir/IRVisitor' import { DefinitionsByName, getTopLevelDef } from '../../src/names/base' import { zerog } from '../../src/idGenerator' describe('NameCollector', () => { const baseModule = buildModuleWithDecls( ['def a = 1', 'def b = 2', 'def c = 3', 'const c1: int', 'const c2: int', 'type T = int', 'type R'], 'test_module', zerog ) function collect(module: QuintModule): [QuintError[], DefinitionsByName] { const collector = new NameCollector() walkModule(collector, baseModule) walkModule(collector, module) return [collector.errors, collector.definitionsByName] } describe('existing modules', () => { it('imports named definitions', () => { const quintModule = buildModuleWithDecls(['import test_module.a'], undefined, zerog) const [errors, definitions] = collect(quintModule) assert.isEmpty(errors) assert.deepInclude([...definitions.keys()], 'a') assert.notDeepInclude([...definitions.keys()], 'b') assert.deepEqual(getTopLevelDef(definitions, 'a')?.importedFrom?.kind, 'import') assert.deepEqual(getTopLevelDef(definitions, 'a')?.namespaces ?? [], []) }) it('imports all definitions', () => { const quintModule = buildModuleWithDecls(['import test_module.*'], undefined, zerog) const [errors, definitions] = collect(quintModule) assert.isEmpty(errors) assert.includeDeepMembers([...definitions.keys()], ['a', 'b', 'T']) }) it('imports definitions with namespace', () => { const quintModule = buildModuleWithDecls(['import test_module'], undefined, zerog) const [errors, definitions] = collect(quintModule) assert.isEmpty(errors) const def = getTopLevelDef(definitions, 'test_module::a') assert.isTrue(def!.hidden) assert.deepEqual(def?.kind, 'def') }) it('imports definitions with qualifier', () => { const quintModule = buildModuleWithDecls(['import test_module as my_import'], undefined, zerog) const [errors, definitions] = collect(quintModule) assert.isEmpty(errors) const def = getTopLevelDef(definitions, 'my_import::a') assert.isTrue(def!.hidden) assert.deepEqual(def?.kind, 'def') }) it('instantiates modules', () => { const quintModule = buildModuleWithDecls( ['import test_module(c1 = 3, c2 = 4) as test_module_instance'], undefined, zerog ) const [errors, definitions] = collect(quintModule) assert.isEmpty(errors) assert.includeDeepMembers([...definitions.keys()], ['test_module_instance::c1', 'test_module_instance::c2']) assert.includeDeepMembers([...definitions.keys()], ['test_module_instance::T']) assert.deepEqual(getTopLevelDef(definitions, 'test_module_instance::a')?.importedFrom?.kind, 'instance') assert.deepEqual(getTopLevelDef(definitions, 'test_module_instance::a')?.namespaces ?? [], [ 'test_module_instance', 'wrapper', ]) }) it('fails instantiating when a param does not exists', () => { const quintModule = buildModuleWithDecls( ['import test_module(c1 = 3, c2 = 4, other = 5) as test_module_instance'], undefined, zerog ) const [errors, _definitions] = collect(quintModule) assert.sameDeepMembers(errors, [ { code: 'QNT406', message: "Instantiation error: 'other' not found in 'test_module'", reference: 0n, data: {}, }, ]) }) it('fails instantiating when a param is not a constant', () => { const quintModule = buildModuleWithDecls( ['import test_module(c1 = 3, c2 = 4, a = 5) as test_module_instance'], undefined, zerog ) const [errors, definitions] = collect(quintModule) assert.sameDeepMembers(errors, [ { code: 'QNT406', message: "Instantiation error: 'a' is not a constant in 'test_module'", reference: 0n, data: {}, }, ]) assert.deepEqual(getTopLevelDef(definitions, 'test_module_instance::a')?.kind, 'def') }) it('fails importing itself', () => { const quintModule = buildModuleWithDecls( ['import wrapper.*', 'import wrapper(c1 = 1) as w', 'export wrapper.*'], undefined, zerog ) const [errors, _definitions] = collect(quintModule) assert.sameDeepMembers(errors, [ { code: 'QNT407', message: "Cannot import 'wrapper' inside 'wrapper'", reference: 0n, data: {} }, { code: 'QNT407', message: "Cannot instantiate 'wrapper' inside 'wrapper'", reference: 0n, data: {} }, { code: 'QNT407', message: "Cannot export 'wrapper' inside 'wrapper'", reference: 0n, data: {} }, ]) }) it('exports all definitions', () => { const quintModule = buildModuleWithDecls(['export test_module.*'], undefined, zerog) const [errors, definitions] = collect(quintModule) assert.isEmpty(errors) assert.isNotTrue(getTopLevelDef(definitions, 'a')!.hidden) assert.isNotTrue(getTopLevelDef(definitions, 'T')!.hidden) }) it('exports previously imported definitions', () => { const quintModule = buildModuleWithDecls(['import test_module.*', 'export test_module.*'], undefined, zerog) const [errors, definitions] = collect(quintModule) assert.isEmpty(errors) assert.isNotTrue(getTopLevelDef(definitions, 'a')!.hidden) assert.isNotTrue(getTopLevelDef(definitions, 'T')!.hidden) }) it('exports imported definitions that were previously qualified', () => { const quintModule = buildModuleWithDecls(['import test_module as T1', 'export T1.*'], undefined, zerog) const [errors, definitions] = collect(quintModule) assert.isEmpty(errors) assert.isNotTrue(getTopLevelDef(definitions, 'a')!.hidden) assert.isNotTrue(getTopLevelDef(definitions, 'T')!.hidden) }) it('exports specific definitions', () => { const quintModule = buildModuleWithDecls(['import test_module.*', 'export test_module.a'], undefined, zerog) const [errors, definitions] = collect(quintModule) assert.isEmpty(errors) // a is not hidden anymore assert.isNotTrue(getTopLevelDef(definitions, 'a')!.hidden) // T is still hidden assert.isTrue(getTopLevelDef(definitions, 'T')!.hidden) }) it('exports definitions with qualifier', () => { const quintModule = buildModuleWithDecls( ['import test_module.*', 'export test_module as my_export'], undefined, zerog ) const [errors, definitions] = collect(quintModule) assert.isEmpty(errors) assert.isTrue(getTopLevelDef(definitions, 'a')!.hidden) assert.isNotTrue(getTopLevelDef(definitions, 'my_export::a')!.hidden) }) it('exports definitions with namespace', () => { const quintModule = buildModuleWithDecls(['import test_module.*', 'export test_module'], undefined, zerog) const [errors, definitions] = collect(quintModule) assert.isEmpty(errors) assert.isTrue(getTopLevelDef(definitions, 'a')!.hidden) assert.isNotTrue(getTopLevelDef(definitions, 'test_module::a')!.hidden) assert.deepEqual(getTopLevelDef(definitions, 'a')?.importedFrom?.kind, 'import') assert.deepEqual(getTopLevelDef(definitions, 'test_module::a')?.importedFrom?.kind, 'export') assert.deepEqual(getTopLevelDef(definitions, 'a')?.namespaces ?? [], []) assert.deepEqual(getTopLevelDef(definitions, 'test_module::a')?.namespaces ?? [], ['test_module']) }) it('fails exporting unexisting definition', () => { const quintModule = buildModuleWithDecls(['import test_module.*', 'export test_module.other'], undefined, zerog) const [errors, _definitions] = collect(quintModule) assert.sameDeepMembers(errors, [ { code: 'QNT404', message: "Name 'test_module::other' not found", reference: 0n, data: {} }, ]) }) it('does not collect nested defs inside assume', () => { const quintModule = buildModuleWithDecls(['assume _ = val foo = 1 { foo }'], undefined, zerog) const [errors, definitions] = collect(quintModule) assert.isEmpty(errors) assert.isFalse(definitions.has('foo')) }) it('does not collect nested defs inside instances', () => { const quintModule = buildModuleWithDecls(['import test_module(c1 = (val foo = 1 { foo })).*'], undefined, zerog) const [errors, definitions] = collect(quintModule) assert.isEmpty(errors) assert.isFalse(definitions.has('foo')) }) }) describe('conflicts', () => { it('reports conflicts with builtin names', () => { const quintModule = buildModuleWithDecls(['def size(x) = 10'], undefined, zerog) const [errors, _definitions] = collect(quintModule) assert.sameDeepMembers(errors, [ { code: 'QNT101', message: "Built-in name 'size' is redefined in module 'wrapper'", reference: 0n, data: {} }, ]) }) it('reports conflicts with user defined names', () => { // Use the real id generator to have different references for each def const quintModule = buildModuleWithDecls(['def a = 10', 'import test_module.*']) const [errors, _definitions] = collect(quintModule) assert.sameDeepMembers(errors, [ { code: 'QNT101', message: "Conflicting definitions found for name 'a' in module 'wrapper'", reference: 2n, data: {}, }, { code: 'QNT101', message: "Conflicting definitions found for name 'a' in module 'wrapper'", reference: 0n, data: {}, }, ]) }) it('reports conflicts with module names', () => { // Setup already defines a module named 'test_module', see `baseDefs` const quintModule = buildModuleWithDecls(['def a = 10'], 'test_module') const [errors, _definitions] = collect(quintModule) assert.sameDeepMembers(errors, [ { code: 'QNT102', message: "Module with name 'test_module' was already defined", reference: 3n, data: {}, }, ]) }) }) describe('unexisting modules', () => { it('fails importing', () => { const quintModule = buildModuleWithDecls(['import unexisting_module.*'], undefined, zerog) const [errors, _definitions] = collect(quintModule) assert.sameDeepMembers(errors, [ { code: 'QNT405', message: "Module 'unexisting_module' not found", reference: 0n, data: {} }, ]) }) it('fails instantiating', () => { const quintModule = buildModuleWithDecls( ['import unexisting_module(c1 = c1, c2 = c2) as test_module_instance'], undefined, zerog ) const [errors, _definitions] = collect(quintModule) assert.sameDeepMembers(errors, [ { code: 'QNT405', message: "Module 'unexisting_module' not found", reference: 0n, data: {} }, ]) }) it('fails exporting', () => { const quintModule = buildModuleWithDecls(['export unexisting_module.*'], undefined, zerog) const [errors, _definitions] = collect(quintModule) assert.sameDeepMembers(errors, [ { code: 'QNT405', message: "Module 'unexisting_module' not found", reference: 0n, data: {} }, ]) }) }) })