Skip to content

Commit

Permalink
Merge pull request #1493 from informalsystems/romac/qualified-type
Browse files Browse the repository at this point in the history
Relax uppercase check for types qualified with a namespace
  • Loading branch information
romac authored Sep 4, 2024
2 parents 351b52a + 56976cf commit ae27080
Show file tree
Hide file tree
Showing 6 changed files with 31 additions and 19 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Bumped GRPC message sizes to 1G (#1480)
- Fix format of ITF trace emitted by `verify` command (#1448)
- Relax uppercase check for types qualified with a namespace (#1494)

### Security

Expand Down Expand Up @@ -148,7 +149,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- The latest supported node version is now bounded at <= 20, which covers the
latest LTS. (#1380)
- Shadowing names are now supported, which means that the same name can be redefined
- Shadowing names are now supported, which means that the same name can be redefined
in nested scopes. (#1394)
- The canonical unit type is now the empty tuple, `()`, rather than the empty
record, `{}`. This should only affect invisible things to do with sum type
Expand Down
18 changes: 12 additions & 6 deletions quint/src/parsing/ToIrListener.ts
Original file line number Diff line number Diff line change
Expand Up @@ -294,9 +294,7 @@ export class ToIrListener implements QuintListener {
const name = ctx.qualId()!.text
const id = this.getId(ctx)

if (name[0].match('[a-z]')) {
this.errors.push(lowercaseTypeError(id, name))
}
this.checkForUppercaseTypeName(id, name)

const def: QuintTypeDef = {
id,
Expand All @@ -319,9 +317,8 @@ export class ToIrListener implements QuintListener {
const type = this.popType().unwrap(() =>
fail('internal error: type alias declaration parsed with no right hand side')
)
if (name[0].match('[a-z]')) {
this.errors.push(lowercaseTypeError(id, name))
}

this.checkForUppercaseTypeName(id, name)

let defWithoutParams: QuintTypeDef = { id: id, kind: 'typedef', name, type }
const def: QuintTypeDef =
Expand Down Expand Up @@ -1297,6 +1294,15 @@ export class ToIrListener implements QuintListener {
}
}
}

private checkForUppercaseTypeName(id: bigint, qualifiedName: string) {
const parts = qualifiedName.split('::')
const unqualifiedName = parts.pop()!

if (unqualifiedName[0].match('[a-z]')) {
this.errors.push(lowercaseTypeError(id, unqualifiedName, parts))
}
}
}

function popMany<T>(stack: T[], n: number, defaultGen: () => T): T[] {
Expand Down
22 changes: 12 additions & 10 deletions quint/src/parsing/parseErrors.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
import { QuintError } from '../quintError'

export function lowercaseTypeError(id: bigint, name: string): QuintError {
export function lowercaseTypeError(id: bigint, name: string, prefix: string[]): QuintError {
const original = [...prefix, name].join('::')
const newName = name[0].toUpperCase() + name.slice(1)
const replacement = [...prefix, newName].join('::')

return {
code: 'QNT007',
message: 'type names must start with an uppercase letter',
reference: id,
data: name[0].match('[a-z]')
? {
fix: {
kind: 'replace',
original: `type ${name[0]}`,
replacement: `type ${name[0].toUpperCase()}`,
},
}
: {},
data: {
fix: {
kind: 'replace',
original: `type ${original}`,
replacement: `type ${replacement}`,
},
},
}
}

Expand Down
2 changes: 1 addition & 1 deletion quint/testFixture/SuperSpec.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion quint/testFixture/SuperSpec.map.json

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions quint/testFixture/SuperSpec.qnt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ module withConsts {
const MyRecord: { i: int, b: bool, s: str }
const MyRecordWithComma: { i: int, b: bool, s: str, }

// A type prefixed with a namespace
type some::namespace::MyType = int

// a disjoint union is a common pattern in TLA+
type MyUnionType =
| Circle(int)
Expand Down

0 comments on commit ae27080

Please sign in to comment.