Skip to content

Commit

Permalink
Merge branch 'gabriela/fixes-for-paxos' into gabriela/erc20-sum-types
Browse files Browse the repository at this point in the history
  • Loading branch information
bugarela committed Nov 29, 2023
2 parents aa7147b + 6c735fd commit 3dc9bcc
Show file tree
Hide file tree
Showing 14 changed files with 130 additions and 73 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Topological sorting of modules (#1268)
- The effect checker will now check for consistency of updates across different
cases inside `match` (#1272)
- Fix problems in the integration of sum types in `run` and `test` commands (#1276)
- Fix some corner cases with the usage of complex expressions inside `assume`
and `import (...)` (#1276)

### Security

Expand Down
12 changes: 7 additions & 5 deletions examples/.scripts/run-example.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ result () {

# Skip tests for parameterized modules
if [[ "$cmd" == "test" && (
"$file" == "classic/distributed/Paxos/Voting.qnt" ||
"$file" == "cosmos/tendermint/Tendermint.qnt" ||
"$file" == "cosmos/tendermint/TendermintTest.qnt" ||
"$file" == "cosmos/lightclient/Blockchain.qnt" ||
Expand All @@ -24,6 +25,7 @@ result () {
fi
# Skip verification for specs that do not define a state machine
if [[ "$cmd" == "verify" && (
"$file" == "classic/distributed/Paxos/Voting.qnt" ||
"$file" == "cosmos/lightclient/Blockchain.qnt" ||
"$file" == "cosmos/lightclient/LCVerificationApi.qnt" ||
"$file" == "cosmos/lightclient/typedefs.qnt" ||
Expand All @@ -46,12 +48,10 @@ result () {
fi

# Print additional explanations
if [[ "$file" == "classic/distributed/Paxos/Paxos.qnt" && ( "$cmd" == "test" || "$cmd" == "verify" )]] ; then
printf "<sup>https://github.com/informalsystems/quint/issues/244</sup>"
elif [[ "$file" == "classic/distributed/Paxos/Voting.qnt" && ( "$cmd" == "test" || "$cmd" == "verify" )]] ; then
printf "<sup>https://github.com/informalsystems/quint/issues/244</sup>"
if [[ "$file" == "classic/distributed/Paxos/Paxos.qnt" && "$cmd" == "verify" ]] ; then
printf "<sup>https://github.com/informalsystems/quint/issues/1034</sup>"
elif [[ "$file" == "language-features/option.qnt" && "$cmd" == verify ]] ; then
printf "<sup>https://github.com/informalsystems/quint/issues/244</sup>"
printf "<sup>https://github.com/informalsystems/quint/issues/1034</sup>"
elif [[ "$file" == "solidity/icse23-fig7/lottery.qnt" && "$cmd" == "verify" ]] ; then
printf "<sup>https://github.com/informalsystems/quint/issues/1019</sup>"
fi
Expand All @@ -66,6 +66,8 @@ get_main () {
main="--main=ReadersWriters_5"
elif [[ "$file" == "classic/distributed/ewd840/ewd840.qnt" ]] ; then
main="--main=ewd840_3"
elif [[ "$file" == "classic/distributed/Paxos/Paxos.qnt" ]] ; then
main="--main=Paxos_val2_accept3_quorum2"
elif [[ "$file" == "classic/sequential/BinSearch/BinSearch.qnt" ]] ; then
main="--main=BinSearch10"
elif [[ "$file" == "cosmos/ics20/bank.qnt" ]] ; then
Expand Down
6 changes: 3 additions & 3 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ listed without any additional command line arguments.
| [classic/distributed/ClockSync/clockSync3.qnt](./classic/distributed/ClockSync/clockSync3.qnt) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| [classic/distributed/ewd840/ewd840.qnt](./classic/distributed/ewd840/ewd840.qnt) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| [classic/distributed/LamportMutex/LamportMutex.qnt](./classic/distributed/LamportMutex/LamportMutex.qnt) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| [classic/distributed/Paxos/Paxos.qnt](./classic/distributed/Paxos/Paxos.qnt) | :white_check_mark: | :white_check_mark: | :x:<sup>https://github.com/informalsystems/quint/issues/244</sup> | :x:<sup>https://github.com/informalsystems/quint/issues/244</sup> |
| [classic/distributed/Paxos/Voting.qnt](./classic/distributed/Paxos/Voting.qnt) | :white_check_mark: | :white_check_mark: | :x:<sup>https://github.com/informalsystems/quint/issues/244</sup> | :x:<sup>https://github.com/informalsystems/quint/issues/244</sup> |
| [classic/distributed/Paxos/Paxos.qnt](./classic/distributed/Paxos/Paxos.qnt) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x:<sup>https://github.com/informalsystems/quint/issues/1034</sup> |
| [classic/distributed/Paxos/Voting.qnt](./classic/distributed/Paxos/Voting.qnt) | :white_check_mark: | :white_check_mark: | N/A[^parameterized] | N/A[^nostatemachine] |
| [classic/distributed/ReadersWriters/ReadersWriters.qnt](./classic/distributed/ReadersWriters/ReadersWriters.qnt) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| [classic/sequential/BinSearch/BinSearch.qnt](./classic/sequential/BinSearch/BinSearch.qnt) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| [cosmos/ics20/bank.qnt](./cosmos/ics20/bank.qnt) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
Expand Down Expand Up @@ -80,7 +80,7 @@ listed without any additional command line arguments.
| [language-features/lists.qnt](./language-features/lists.qnt) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| [language-features/maps.qnt](./language-features/maps.qnt) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| [language-features/nondetEx.qnt](./language-features/nondetEx.qnt) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| [language-features/option.qnt](./language-features/option.qnt) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x:<sup>https://github.com/informalsystems/quint/issues/244</sup> |
| [language-features/option.qnt](./language-features/option.qnt) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x:<sup>https://github.com/informalsystems/quint/issues/1034</sup> |
| [language-features/records.qnt](./language-features/records.qnt) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| [language-features/sets.qnt](./language-features/sets.qnt) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| [language-features/tuples.qnt](./language-features/tuples.qnt) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
Expand Down
7 changes: 1 addition & 6 deletions quint/src/effects/inferrer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export class EffectInferrer implements IRVisitor {
private freeNames: { effectVariables: Set<string>; entityVariables: Set<string> }[] = []

// the current depth of operator definitions: top-level defs are depth 0
private definitionDepth: number = 0
definitionDepth: number = -1

enterExpr(e: QuintEx) {
this.location = `Inferring effect for ${expressionToString(e)}`
Expand Down Expand Up @@ -221,10 +221,6 @@ export class EffectInferrer implements IRVisitor {
)
}

enterOpDef(_def: QuintOpDef): void {
this.definitionDepth++
}

// Γ ⊢ expr: E
// ---------------------------------- (OPDEF)
// Γ ⊢ (def op(params) = expr): E
Expand All @@ -238,7 +234,6 @@ export class EffectInferrer implements IRVisitor {
this.addToResults(def.id, right(this.quantify(e.effect)))
})

this.definitionDepth--
// When exiting top-level definitions, clear the substitutions
if (this.definitionDepth === 0) {
this.substitutions = []
Expand Down
20 changes: 14 additions & 6 deletions quint/src/ir/IRTransformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,14 +238,22 @@ export function transformType(transformer: IRTransformer, type: t.QuintType): t.
break

case 'sum':
if (transformer.enterSumType) {
newType = transformer.enterSumType(newType)
}
if (transformer.exitSumType) {
newType = transformer.exitSumType(newType)
{
if (transformer.enterSumType) {
newType = transformer.enterSumType(newType)
}
// Sum types, transform all types
const newFields = transformRow(transformer, newType.fields)
if (newFields.kind !== 'row') {
throw new Error('Impossible: sum type fields transformed into non-row')
}
newType.fields = newFields

if (transformer.exitSumType) {
newType = transformer.exitSumType(newType)
}
}
break

default:
unreachable(newType)
}
Expand Down
24 changes: 23 additions & 1 deletion quint/src/ir/IRVisitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ import { unreachable } from '../util'
* Optionally defines functions for each IR component.
*/
export interface IRVisitor {
/* Keeps track of the depth of the current definition, to be updated by the
* walk* functions and used by implementations of the interface */
definitionDepth?: number

enterModule?: (_module: ir.QuintModule) => void
exitModule?: (_module: ir.QuintModule) => void

Expand Down Expand Up @@ -261,14 +265,23 @@ export function walkDeclaration(visitor: IRVisitor, decl: ir.QuintDeclaration):
visitor.enterDecl(decl)
}

// The standard depth starts at 0, so definitions inside delclarations (i.e.
// assume and instance overrides) are not considered top-level
visitor.definitionDepth = 0

switch (decl.kind) {
case 'const':
case 'var':
case 'def':
case 'typedef':
case 'assume':
walkDefinition(visitor, decl)
break
case 'def':
// depth will be increased inside `walkDefinition`, so we set it to -1 in
// order for it to be 0 there
visitor.definitionDepth = -1
walkDefinition(visitor, decl)
break
case 'instance':
if (visitor.enterInstance) {
visitor.enterInstance(decl)
Expand Down Expand Up @@ -312,9 +325,14 @@ export function walkDeclaration(visitor: IRVisitor, decl: ir.QuintDeclaration):
* @returns nothing, any collected information has to be a state inside the IRVisitor instance.
*/
export function walkDefinition(visitor: IRVisitor, def: ir.QuintDef): void {
if (visitor.definitionDepth !== undefined) {
visitor.definitionDepth++
}

if (visitor.enterDef) {
visitor.enterDef(def)
}

if (ir.isAnnotatedDef(def)) {
walkType(visitor, def.typeAnnotation)
} else if (ir.isTypeAlias(def)) {
Expand Down Expand Up @@ -372,6 +390,10 @@ export function walkDefinition(visitor: IRVisitor, def: ir.QuintDef): void {
if (visitor.exitDef) {
visitor.exitDef(def)
}

if (visitor.definitionDepth !== undefined) {
visitor.definitionDepth--
}
}

export function walkExpression(visitor: IRVisitor, expr: ir.QuintEx): void {
Expand Down
29 changes: 15 additions & 14 deletions quint/src/ir/IRprinting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
*/

import { OpQualifier, QuintDeclaration, QuintDef, QuintEx, QuintModule, isAnnotatedDef } from './quintIr'
import { QuintSumType, QuintType, Row, RowField, isUnitType } from './quintTypes'
import { ConcreteRow, QuintSumType, QuintType, Row, RowField, isUnitType } from './quintTypes'
import { TypeScheme } from '../types/base'
import { typeSchemeToString } from '../types/printing'

Expand Down Expand Up @@ -210,19 +210,20 @@ export function rowToString(r: Row): string {
* @returns a string with the pretty printed sum
*/
export function sumToString(s: QuintSumType): string {
return (
'(' +
s.fields.fields
.map((f: RowField) => {
if (isUnitType(f.fieldType)) {
return `${f.fieldName}`
} else {
return `${f.fieldName}(${typeToString(f.fieldType)})`
}
})
.join(' | ') +
')'
)
return '(' + sumFieldsToString(s.fields) + ')'
}

function sumFieldsToString(r: ConcreteRow): string {
return r.fields
.map((f: RowField) => {
if (isUnitType(f.fieldType)) {
return `${f.fieldName}`
} else {
return `${f.fieldName}(${typeToString(f.fieldType)})`
}
})
.concat(r.other.kind === 'row' ? [sumFieldsToString(r.other)] : [])
.join(' | ')
}

/**
Expand Down
9 changes: 2 additions & 7 deletions quint/src/names/collector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,9 @@ export class NameCollector implements IRVisitor {
definitionsByModule: DefinitionsByModule = new Map()
errors: QuintError[] = []
table: LookupTable = new Map()
definitionDepth: number = -1

private currentModuleName: string = ''
private definitionDepth: number = 0

enterModule(module: QuintModule): void {
this.currentModuleName = module.name
Expand Down Expand Up @@ -87,12 +88,6 @@ export class NameCollector implements IRVisitor {
// collect only top-level definitions
this.collectDefinition({ ...def, typeAnnotation: undefined, depth: this.definitionDepth })
}

this.definitionDepth++
}

exitOpDef(_def: QuintOpDef): void {
this.definitionDepth--
}

enterTypeDef(def: QuintTypeDef): void {
Expand Down
8 changes: 1 addition & 7 deletions quint/src/names/resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class NameResolver implements IRVisitor {
collector: NameCollector
errors: QuintError[] = []
table: LookupTable = new Map()
private definitionDepth: number = 0
definitionDepth: number = -1

constructor() {
this.collector = new NameCollector()
Expand Down Expand Up @@ -73,12 +73,6 @@ class NameResolver implements IRVisitor {
if (this.definitionDepth > 0) {
this.collector.collectDefinition({ ...def, depth: this.definitionDepth })
}

this.definitionDepth++
}

exitOpDef(_def: QuintOpDef): void {
this.definitionDepth--
}

exitLet(expr: QuintLet): void {
Expand Down
7 changes: 1 addition & 6 deletions quint/src/runtime/impl/compilerImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ export class CompilerVisitor implements IRVisitor {
// execution listener
private execListener: ExecutionListener
// the current depth of operator definitions: top-level defs are depth 0
private definitionDepth: number = 0
definitionDepth: number = -1

constructor(
lookupTable: LookupTable,
Expand Down Expand Up @@ -230,12 +230,7 @@ export class CompilerVisitor implements IRVisitor {
return this.errorTracker.runtimeErrors
}

enterOpDef(_: ir.QuintOpDef) {
this.definitionDepth++
}

exitOpDef(opdef: ir.QuintOpDef) {
this.definitionDepth--
// Either a runtime value, or a def, action, etc.
// All of them are compiled to callables, which may have zero parameters.
let boundValue = this.compStack.pop()
Expand Down
2 changes: 1 addition & 1 deletion quint/src/types/simplification.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export function simplify(typeScheme: TypeScheme): TypeScheme {
* A row like `{ a: int | { b: bool | r } }` becomes
* `{ a: int, b: bool | r }`.
*
* @param row - The tow to be simplified
* @param row - The row to be simplified
*
* @returns The simplified row
*/
Expand Down
20 changes: 20 additions & 0 deletions quint/test/names/collector.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,26 @@ describe('NameCollector', () => {
{ 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', () => {
Expand Down
26 changes: 24 additions & 2 deletions quint/test/types/aliasInliner.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ function inlineModule(text: string): { modules: QuintModule[]; table: LookupTabl
}

describe('inlineAliases', () => {
it('should inline aliases in a simple module', () => {
it('inlines aliases in a simple module', () => {
const quintModule = `module A {
type MY_ALIAS = int
var x: MY_ALIAS
Expand All @@ -42,7 +42,7 @@ describe('inlineAliases', () => {
assert.deepEqual(analysisOutput.types.get(4n)?.type.kind, 'int')
})

it('should handle nested aliases', () => {
it('handles nested aliases', () => {
const quintModule = `module A {
type MY_ALIAS = int
type MY_OTHER_ALIAS = MY_ALIAS
Expand All @@ -59,4 +59,26 @@ describe('inlineAliases', () => {

assert.deepEqual(moduleToString(modules[0]), expectedModule)
})

it('handles nested sum types constructors', () => {
const quintModule = `module A {
type T1 = B | C
type T2 = Some(T1) | None
var x: T2
}`

const { modules } = inlineModule(quintModule)

const expectedModule = dedent(`module A {
| type T1 = (B({}) | C({}))
| val C: (B({}) | C({})) = variant("C", Rec())
| type T2 = (Some((B({}) | C({}))) | None({}))
| val B: (B({}) | C({})) = variant("B", Rec())
| def Some: ((B({}) | C({}))) => (Some((B({}) | C({}))) | None({})) = ((__SomeParam) => variant("Some", __SomeParam))
| val None: (Some((B({}) | C({}))) | None({})) = variant("None", Rec())
| var x: (Some((B({}) | C({}))) | None({}))
|}`)

assert.deepEqual(moduleToString(modules[0]), expectedModule)
})
})
Loading

0 comments on commit 3dc9bcc

Please sign in to comment.