Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Package invariants #810

Open
wants to merge 55 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
2707ddb
backup
jcp19 Sep 15, 2024
5040a93
parsing-related changes
jcp19 Sep 22, 2024
34d880e
backup
jcp19 Sep 23, 2024
9d92e50
more parsing shennanigans
jcp19 Sep 23, 2024
e92a034
backup
jcp19 Sep 23, 2024
ee1f467
improve syntax for 'openDupPkgInv'
jcp19 Sep 23, 2024
6bea45a
backup
jcp19 Sep 23, 2024
72a6949
allow ghost globals
jcp19 Sep 26, 2024
fe93135
backup
jcp19 Sep 28, 2024
37e8fc5
fix resources from friend pkgs
jcp19 Sep 30, 2024
c8c5766
add missing proof obligation
jcp19 Nov 14, 2024
3e093a9
backup
jcp19 Nov 14, 2024
392e122
backup
jcp19 Nov 15, 2024
1925f79
fix soundness bug
jcp19 Nov 15, 2024
0936126
make desugarer sequential again
jcp19 Nov 15, 2024
fa4dd6a
backup
jcp19 Dec 1, 2024
1ecf40d
new parser
jcp19 Dec 1, 2024
f0ff303
continue cleaning up
jcp19 Dec 17, 2024
ff165ba
Merge branch 'master' into continue-msinit
jcp19 Dec 17, 2024
4a7b5b9
backup
jcp19 Dec 18, 2024
642fd28
merge master
jcp19 Jan 19, 2025
22c5f86
fix cyclical type-checking dependency
jcp19 Jan 20, 2025
5ce6644
cleanup
jcp19 Jan 20, 2025
fb2e9ab
add examples
jcp19 Jan 20, 2025
899e1e2
start adapting some tests
jcp19 Jan 20, 2025
a3ef935
cleanup
jcp19 Jan 20, 2025
c836330
fix location of pkg init tests
jcp19 Jan 20, 2025
5ef3294
add check for global variable decls that prevent calling interface me…
jcp19 Jan 23, 2025
91dd34f
cleanup
jcp19 Jan 23, 2025
fb6a51e
backup
jcp19 Jan 23, 2025
0eb628d
merge with master
jcp19 Jan 23, 2025
a9e5998
improve error messages
jcp19 Jan 23, 2025
40a6132
backup
jcp19 Jan 28, 2025
23a3977
cleanup
jcp19 Jan 28, 2025
a10bb09
Merge branch 'master' into continue-msinit
jcp19 Jan 28, 2025
6d2a575
reorganize files
jcp19 Jan 28, 2025
0b09914
backup
jcp19 Jan 29, 2025
e92f444
delete temp file
jcp19 Jan 29, 2025
eddaf6a
cleanup tests
jcp19 Jan 29, 2025
9b38dd6
cleanup, bug fixing
jcp19 Jan 29, 2025
a758613
fix test file
jcp19 Jan 29, 2025
264796a
fix more tests
jcp19 Jan 29, 2025
047d14b
fix viperserver function
jcp19 Jan 29, 2025
244e8a5
ignore failing tests
jcp19 Jan 29, 2025
45c2a54
fix tests
jcp19 Jan 29, 2025
75903ac
cleanup
jcp19 Jan 30, 2025
05b4504
cleanup
jcp19 Jan 30, 2025
c6bda4b
add doc to expr typing
jcp19 Jan 30, 2025
0ce62fc
add doc
jcp19 Jan 30, 2025
7691215
add missing check
jcp19 Jan 30, 2025
819a929
clean up unnecessary file
jcp19 Jan 31, 2025
430cfb3
merge with master
jcp19 Feb 21, 2025
57336dc
Apply suggestions from code review
jcp19 Feb 21, 2025
60693ae
fix member unit tests
jcp19 Feb 21, 2025
aa47be1
Merge branch 'master' into continue-msinit
jcp19 Feb 26, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ project/target/
target/
tmp/
sync/
gobra_tmp/

logger.log
.DS_Store
Expand Down
7 changes: 6 additions & 1 deletion src/main/antlr4/GobraLexer.g4
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,17 @@ WRITEPERM : 'writePerm' -> mode(NLSEMI);
NOPERM : 'noPerm' -> mode(NLSEMI);
TRUSTED : 'trusted' -> mode(NLSEMI);
OUTLINE : 'outline';
DUPLICABLE : 'dup';
PKG_INV : 'pkgInvariant';
OPEN_DUP_SINV : 'openDupPkgInv' -> mode(NLSEMI);
INIT_POST : 'initEnsures';
IMPORT_PRE : 'importRequires';
PROOF : 'proof';
GHOST_EQUALS : '===';
GHOST_NOT_EQUALS : '!==';
WITH : 'with';
OPAQUE : 'opaque' -> mode(NLSEMI);
MAYINIT : 'mayInit' -> mode(NLSEMI);
REVEAL : 'reveal';
BACKEND : '#backend';
BACKEND : '#backend';
FRIENDPKG : 'friendPkg';
14 changes: 9 additions & 5 deletions src/main/antlr4/GobraParser.g4
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,24 @@ maybeAddressableIdentifierList: maybeAddressableIdentifier (COMMA maybeAddressab

maybeAddressableIdentifier: IDENTIFIER ADDR_MOD?;

// Ghost members
friendPkgDecl: FRIENDPKG importPath assertion;

// Ghost members
sourceFile:
(initPost eos)* packageClause eos (importDecl eos)* (
(pkgInvariant eos)* (initPost eos)* packageClause eos (friendPkgDecl eos)* (importDecl eos)* (
member eos
)* EOF;

// `preamble` is a second entry point allowing us to parse only the top of a source.
// That's also why we don not enforce EOF at the end.
preamble: (initPost eos)* packageClause eos (importDecl eos)*;
preamble: (pkgInvariant eos)* (initPost eos)* packageClause eos (friendPkgDecl eos)* (importDecl eos)*;

initPost: INIT_POST expression;

importPre: IMPORT_PRE expression;

pkgInvariant: DUPLICABLE? PKG_INV assertion;

importSpec: (importPre eos)* alias = (DOT | IDENTIFIER)? importPath;

importDecl: (importPre eos)* (IMPORT importSpec | IMPORT L_PAREN (importSpec eos)* R_PAREN);
Expand All @@ -64,6 +67,7 @@ ghostStatement:
| fold_stmt=(FOLD | UNFOLD) predicateAccess #foldStatement
| kind=(ASSUME | ASSERT | REFUTE | INHALE | EXHALE) expression #proofStatement
| matchStmt #matchStmt_
| OPEN_DUP_SINV #pkgInvStatement
;

// Auxiliary statements
Expand Down Expand Up @@ -172,9 +176,9 @@ sqType: (kind=(SEQ | SET | MSET | OPT) L_BRACKET type_ R_BRACKET)

// Specifications

specification returns[boolean trusted = false, boolean pure = false, boolean opaque = false;]:
specification returns[boolean trusted = false, boolean pure = false, boolean mayInit = false, boolean opaque = false;]:
// Non-greedily match PURE to avoid missing eos errors.
((specStatement | OPAQUE {$opaque = true;} | PURE {$pure = true;} | TRUSTED {$trusted = true;}) eos)*? (PURE {$pure = true;})? backendAnnotation?
((specStatement | OPAQUE {$opaque = true;} | PURE {$pure = true;} | MAYINIT {$mayInit = true;} | TRUSTED {$trusted = true;}) eos)*? (PURE {$pure = true;})? backendAnnotation?
;

backendAnnotationEntry: ~('('|')'|',')+;
Expand Down
16 changes: 10 additions & 6 deletions src/main/scala/viper/gobra/ast/frontend/Ast.scala
Original file line number Diff line number Diff line change
Expand Up @@ -53,23 +53,22 @@ case class PPackage(

case class PProgram(
packageClause: PPackageClause,
// init postconditions describe the state and resources right
// after this program is initialized
initPosts: Vector[PExpression],
pkgInvariants: Vector[PPkgInvariant],
imports: Vector[PImport],
friends: Vector[PFriendPkgDecl],
declarations: Vector[PMember]
) extends PNode with PUnorderedScope // imports are in program scopes


case class PPreamble(
packageClause: PPackageClause,
// init postconditions describe the state and resources right
// after this program is initialized
initPosts: Vector[PExpression],
pkgInvariants: Vector[PPkgInvariant],
imports: Vector[PImport],
friends: Vector[PFriendPkgDecl],
positions: PositionManager,
) extends PNode with PUnorderedScope

case class PPkgInvariant(inv: PExpression, duplicable: Boolean) extends PNode

class PositionManager(val positions: Positions) extends Messaging(positions) {

Expand Down Expand Up @@ -124,6 +123,8 @@ case class PImplicitQualifiedImport(importPath: String, importPres: Vector[PExpr

case class PUnqualifiedImport(importPath: String, importPres: Vector[PExpression]) extends PImport

case class PFriendPkgDecl(path: String, assertion: PExpression) extends PNode

sealed trait PGhostifiable extends PNode

sealed trait PMember extends PNode
Expand Down Expand Up @@ -893,6 +894,7 @@ case class PFunctionSpec(
isPure: Boolean = false,
isTrusted: Boolean = false,
isOpaque: Boolean = false,
mayBeUsedInInit: Boolean = false,
) extends PSpecification

case class PBackendAnnotation(key: String, values: Vector[String]) extends PGhostMisc
Expand Down Expand Up @@ -981,6 +983,8 @@ case class PFold(exp: PPredicateAccess) extends PGhostStatement with PDeferrable

case class PUnfold(exp: PPredicateAccess) extends PGhostStatement with PDeferrable

case class POpenDupPkgInv() extends PGhostStatement with PDeferrable

case class PPackageWand(wand: PMagicWand, proofScript: Option[PBlock]) extends PGhostStatement

case class PApplyWand(wand: PMagicWand) extends PGhostStatement
Expand Down
36 changes: 29 additions & 7 deletions src/main/scala/viper/gobra/ast/frontend/PrettyPrinter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ class DefaultPrettyPrinter extends PrettyPrinter with kiama.output.PrettyPrinter
case n: PInterfaceClause => showInterfaceClause(n)
case n: PBodyParameterInfo => showBodyParameterInfo(n)
case n: PTerminationMeasure => showTerminationMeasure(n)
case n: PPkgInvariant => showPkgInvariant(n)
case n: PFriendPkgDecl => showFriend(n)
case PPos(_) => emptyDoc
}

Expand All @@ -61,23 +63,35 @@ class DefaultPrettyPrinter extends PrettyPrinter with kiama.output.PrettyPrinter
// program

def showProgram(p: PProgram): Doc = p match {
case PProgram(packageClause, progPosts, imports, declarations) =>
showPreamble(packageClause, progPosts, imports) <>
case PProgram(packageClause, pkgInvs, imports, friends, declarations) =>
showPreamble(packageClause, pkgInvs, imports, friends) <>
ssep(declarations map showMember, line <> line) <> line
}

// preamble

def showPreamble(p: PPreamble): Doc = p match {
case PPreamble(packageClause, progPosts, imports, _) =>
showPreamble(packageClause, progPosts, imports)
case PPreamble(packageClause, pkgInvs, imports, friends, _) =>
showPreamble(packageClause, pkgInvs, imports, friends)
}

private def showPreamble(packageClause: PPackageClause, progPosts: Vector[PExpression], imports: Vector[PImport]): Doc =
vcat(progPosts.map("initEnsures" <+> showExpr(_))) <>
private def showPreamble(
packageClause: PPackageClause,
pkgInvs: Vector[PPkgInvariant],
imports: Vector[PImport],
friends: Vector[PFriendPkgDecl]
): Doc =
vcat(pkgInvs.map(showPkgInvariant)) <>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
vcat(pkgInvs.map(showPkgInvariant)) <>
vcat(pkgInvs.map(showPkgInvariant)) <> line <>

Not entirely sure what line does but if this adds a newline, I think we probably want this, right?

showPackageClause(packageClause) <> line <> line <>
ssep(friends map showFriend, line) <> line <>
ssep(imports map showImport, line) <> line

private def showPkgInvariant(inv: PPkgInvariant): Doc = {
val dup: Doc = if (inv.duplicable) "dup" else emptyDoc
val expr = showExpr(inv.inv)
dup <+> "pkgInvariant" <+> expr
}

// package

def showPackageClause(node: PPackageClause): Doc = "package" <+> showPackageId(node.id)
Expand All @@ -99,6 +113,11 @@ class DefaultPrettyPrinter extends PrettyPrinter with kiama.output.PrettyPrinter
}
}

// friend pkgs
def showFriend(decl: PFriendPkgDecl): Doc = {
"friendPkg" <+> decl.path <+> showExpr(decl.assertion)
}

// members

def showMember(mem: PMember): Doc = mem match {
Expand Down Expand Up @@ -130,6 +149,7 @@ class DefaultPrettyPrinter extends PrettyPrinter with kiama.output.PrettyPrinter
def showPure: Doc = "pure" <> line
def showOpaque: Doc = "opaque" <> line
def showTrusted: Doc = "trusted" <> line
def showMayInit: Doc = "mayInit" <> line
def showPre(pre: PExpression): Doc = "requires" <+> showExpr(pre)
def showPreserves(preserves: PExpression): Doc = "preserves" <+> showExpr(preserves)
def showPost(post: PExpression): Doc = "ensures" <+> showExpr(post)
Expand All @@ -144,10 +164,11 @@ class DefaultPrettyPrinter extends PrettyPrinter with kiama.output.PrettyPrinter
}

def showSpec(spec: PSpecification): Doc = spec match {
case PFunctionSpec(pres, preserves, posts, measures, backendAnnotations, isPure, isTrusted, isOpaque) =>
case PFunctionSpec(pres, preserves, posts, measures, backendAnnotations, isPure, isTrusted, isOpaque, mayInit) =>
(if (isPure) showPure else emptyDoc) <>
(if (isOpaque) showOpaque else emptyDoc) <>
(if (isTrusted) showTrusted else emptyDoc) <>
(if (mayInit) showMayInit else emptyDoc) <>
hcat(pres map (showPre(_) <> line)) <>
hcat(preserves map (showPreserves(_) <> line)) <>
hcat(posts map (showPost(_) <> line)) <>
Expand Down Expand Up @@ -292,6 +313,7 @@ class DefaultPrettyPrinter extends PrettyPrinter with kiama.output.PrettyPrinter
case PFold(exp) => "fold" <+> showExpr(exp)
case PPackageWand(wand, blockOpt) => "package" <+> showExpr(wand) <+> opt(blockOpt)(showStmt)
case PApplyWand(wand) => "apply" <+> showExpr(wand)
case POpenDupPkgInv() => "openDupPkgInv"
case PMatchStatement(exp, clauses, _) => "match" <+>
showExpr(exp) <+> block(ssep(clauses map showMatchClauseStatement, line))
}
Expand Down
6 changes: 6 additions & 0 deletions src/main/scala/viper/gobra/ast/internal/Program.scala
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,12 @@ case class MethodBody(
postprocessing: Vector[Stmt] = Vector.empty,
)(val info: Source.Parser.Info) extends Stmt

object MethodBody {
def empty(info: Source.Parser.Info): MethodBody = {
MethodBody(Vector.empty, MethodBodySeqn(Vector.empty)(info), Vector.empty)(info)
}
}

/**
* This node serves as a target of encoding extensions. See [[viper.gobra.translator.encodings.combinators.TypeEncoding.Extension]]
* Return statements jump exactly to the end of the encoding of this statement.
Expand Down
15 changes: 10 additions & 5 deletions src/main/scala/viper/gobra/frontend/Config.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import org.bitbucket.inkytonik.kiama.util.{FileSource, Source}
import org.rogach.scallop.{ScallopConf, ScallopOption, singleArgConverter}
import viper.gobra.backend.{ViperBackend, ViperBackends}
import viper.gobra.GoVerifier
import viper.gobra.frontend.Config.enableLazyImportOptionPrettyPrinted
import viper.gobra.frontend.PackageResolver.FileResource
import viper.gobra.frontend.Source.getPackageInfo
import viper.gobra.util.TaskManagerMode.{Lazy, Parallel, Sequential, TaskManagerMode}
Expand Down Expand Up @@ -164,7 +165,6 @@ case class Config(
z3APIMode: Boolean = ConfigDefaults.DefaultZ3APIMode,
disableNL: Boolean = ConfigDefaults.DefaultDisableNL,
mceMode: MCE.Mode = ConfigDefaults.DefaultMCEMode,
enableLazyImports: Boolean = ConfigDefaults.DefaultEnableLazyImports,
noVerify: Boolean = ConfigDefaults.DefaultNoVerify,
noStreamErrors: Boolean = ConfigDefaults.DefaultNoStreamErrors,
parseAndTypeCheckMode: TaskManagerMode = ConfigDefaults.DefaultParseAndTypeCheckMode,
Expand Down Expand Up @@ -225,7 +225,6 @@ case class Config(
z3APIMode = z3APIMode || other.z3APIMode,
disableNL = disableNL || other.disableNL,
mceMode = mceMode,
enableLazyImports = enableLazyImports || other.enableLazyImports,
noVerify = noVerify || other.noVerify,
noStreamErrors = noStreamErrors || other.noStreamErrors,
parseAndTypeCheckMode = parseAndTypeCheckMode,
Expand Down Expand Up @@ -286,7 +285,6 @@ case class BaseConfig(gobraDirectory: Path = ConfigDefaults.DefaultGobraDirector
z3APIMode: Boolean = ConfigDefaults.DefaultZ3APIMode,
disableNL: Boolean = ConfigDefaults.DefaultDisableNL,
mceMode: MCE.Mode = ConfigDefaults.DefaultMCEMode,
enableLazyImports: Boolean = ConfigDefaults.DefaultEnableLazyImports,
noVerify: Boolean = ConfigDefaults.DefaultNoVerify,
noStreamErrors: Boolean = ConfigDefaults.DefaultNoStreamErrors,
parseAndTypeCheckMode: TaskManagerMode = ConfigDefaults.DefaultParseAndTypeCheckMode,
Expand Down Expand Up @@ -349,7 +347,6 @@ trait RawConfig {
z3APIMode = baseConfig.z3APIMode,
disableNL = baseConfig.disableNL,
mceMode = baseConfig.mceMode,
enableLazyImports = baseConfig.enableLazyImports,
noVerify = baseConfig.noVerify,
noStreamErrors = baseConfig.noStreamErrors,
parseAndTypeCheckMode = baseConfig.parseAndTypeCheckMode,
Expand Down Expand Up @@ -887,6 +884,15 @@ class ScallopGobraConfig(arguments: Seq[String], isInputOptional: Boolean = fals
case _ => false
}

addValidation {
val lazyImportsSet = enableLazyImports.toOption.nonEmpty
if (lazyImportsSet) {
Left(s"The flag $enableLazyImportOptionPrettyPrinted was removed in Gobra's PR #797.")
} else {
Right(())
}
}

// `parallelizeBranches` requires a backend that supports branch parallelization (i.e., a silicon-based backend)
addValidation {
val parallelizeBranchesOn = parallelizeBranches.toOption.contains(true)
Expand Down Expand Up @@ -1052,7 +1058,6 @@ class ScallopGobraConfig(arguments: Seq[String], isInputOptional: Boolean = fals
z3APIMode = z3APIMode(),
disableNL = disableNL(),
mceMode = mceMode(),
enableLazyImports = enableLazyImports(),
noVerify = noVerify(),
noStreamErrors = noStreamErrors(),
parseAndTypeCheckMode = parseAndTypeCheckMode(),
Expand Down
Loading
Loading