Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
746d119
Add domain-based encoding for bounded integer types
claude Apr 15, 2026
5204674
Fix two runtime bugs in BoundedIntEncoding and add regression tests
claude Apr 15, 2026
d7c3c65
Revert equal override in BoundedIntEncoding (fixed in base branch)
claude Apr 16, 2026
9dce304
Merge remote-tracking branch 'origin/claude/improve-int-type-inferenc…
claude Apr 16, 2026
4f0f2ab
Encode each bounded integer kind as its own Viper domain type
claude Apr 16, 2026
ce8fde6
Fix type mismatch: use partial FuncApp constructor with withSrc
claude Apr 16, 2026
1317e4e
Normalise unbounded-int operands to domain values
claude Apr 16, 2026
1292b3d
Fix MBQI divergence by making arithmetic functions return Int
claude Apr 16, 2026
161bf8f
Prefix bounded int domain names to avoid Silicon sort clash
claude Apr 16, 2026
d6b5557
fix byte.go
jcp19 Apr 19, 2026
83b7e4f
Merge branch 'master' into claude/integer-type-semantics-RUVTQ
jcp19 Apr 19, 2026
24166a6
Propagate IntegerKind through desugaring and align mixed-kind operands
jcp19 Apr 19, 2026
cf59992
Register `integer` as a built-in type so it resolves in conversions
jcp19 Apr 19, 2026
f5469bf
Add `from` injectivity axiom; require `integer` for perm operands; re…
jcp19 Apr 19, 2026
cba0e19
Emit well-founded order axioms for each bounded integer domain
jcp19 Apr 19, 2026
145530d
Distinguish typed `integer` from untyped int constant via separate kind
jcp19 Apr 19, 2026
cefbf0e
fix byte test
jcp19 Apr 19, 2026
51b592c
Make bounded arithmetic functions return the domain type, not Int+wrap
jcp19 Apr 19, 2026
682bf20
Replace pair-trigger from-injectivity with unary `to` domain axiom
jcp19 Apr 27, 2026
414bbb2
Merges branch 'claude/improve-int-type-inference-UFkBe' into 'claude/…
ArquintL Jun 2, 2026
5ef5407
Merges branch 'claude/improve-int-type-inference-UFkBe' into 'claude/…
ArquintL Jun 2, 2026
b61e057
Fix e-matching matching loop in bounded-int arithmetic encoding
claude Jun 13, 2026
dbcfe3f
Add INFO-level per-phase progress logging to the pipeline
jcp19 Jun 14, 2026
10823ed
Prevent e-matching blowups from bounded-int from-triggers and literal…
jcp19 Jul 18, 2026
10a4753
Reinstate loop-safe from-injectivity; handle bounded operands on eith…
jcp19 Jul 18, 2026
eb4c443
Align integer kinds at all remaining encoding boundaries
jcp19 Jul 18, 2026
deb220d
Type ghost-collection sizes, multiplicities, and range elements as `i…
jcp19 Jul 19, 2026
567b2d6
Keep from(to(c)) literal anchors; allow int-to-integer assignability
jcp19 Jul 19, 2026
d6d716b
Use Skolem-inverse form for the from-injectivity axiom
jcp19 Jul 19, 2026
5623067
Make small-operand multiplication robustly linear via sqrt-box lemmas
jcp19 Jul 19, 2026
745c1ed
Align integer kinds at channel-invariant args and the close built-in
jcp19 Jul 20, 2026
1e910cd
Add a math stub with the concrete-type integer limit constants
jcp19 Jul 20, 2026
5cf0a5b
Align set-multiplicity element kind; bound overflow-dependent test specs
jcp19 Jul 20, 2026
3834a82
Negate WaitGroup debt permission in exact integer arithmetic
jcp19 Jul 20, 2026
193ddab
Quantify bounded-integer variables over the mathematical integer sort
jcp19 Jul 20, 2026
a133aea
Bound example-2-1's incr spec against loop-counter and element overflow
jcp19 Jul 20, 2026
e834cdd
Align option element kinds in mixed comparisons
jcp19 Jul 20, 2026
de00d25
Bound n in the tutorial sum examples so the result cannot overflow
jcp19 Jul 20, 2026
d1404df
Bound quantified-permissions addToSlice against loop-counter/element …
jcp19 Jul 20, 2026
fc092aa
Rewrite tour/Test2 sum invariant to keep multiplication operands small
jcp19 Jul 20, 2026
5f626a6
Bound switch/channels examples against increment/negation overflow
jcp19 Jul 20, 2026
2e52e1e
Bound zune's day-conversion input so its year products stay exact
jcp19 Jul 20, 2026
62dcbce
Bound ghost-code's slice lengths so index arithmetic stays exact
jcp19 Jul 20, 2026
1486c3a
Type list_of_interfaces' recursion-depth result as ghost integer
jcp19 Jul 20, 2026
f45c953
Type visitor_pattern's permission-scaling depth as ghost integer
jcp19 Jul 20, 2026
4be64b5
Adapt collection feature tests to sound bounded-int + mathematical qu…
jcp19 Jul 20, 2026
9b70fe3
Use the configured int/uint kinds for explicit conversions
jcp19 Jul 20, 2026
965836f
Adapt misc feature tests to sound bounded-int + mathematical quantifiers
jcp19 Jul 20, 2026
1eb2f3c
Adapt closure tests to sound bounded-int semantics
jcp19 Jul 20, 2026
7fd380d
Fix unsigned-shift constant evaluation overflow; bound wand traversal…
jcp19 Jul 20, 2026
d2ab93c
Claim mixed comparisons only when both operands are integer-typed
jcp19 Jul 20, 2026
b2a098c
Mirror sound-semantics adaptations into impl_errors/spec_errors variants
jcp19 Jul 20, 2026
a48663b
Adapt suite-only failing tests: bounds, integer results, overflow ann…
jcp19 Jul 20, 2026
1b7610b
Maintain relaxed_prefix's prefix equalities at the sequence level
jcp19 Jul 21, 2026
7ac4d1c
Add --unboundedIntegers flag to restore unbounded integer encoding
claude Jul 21, 2026
d521500
Adapt seq-convert-fail3 to mathematical integer len result
claude Jul 21, 2026
73c5948
Opt 000659 and termination-fail-01 out of bounded-int semantics
claude Jul 21, 2026
cbb75bf
Opt trusted-functions out of bounded-int semantics
claude Jul 21, 2026
c3309c3
Opt evaluation examples out of bounded-int semantics
jcp19 Jul 22, 2026
bbfd2e0
Convert ghost-sequence length to int in parallel_search_replace
jcp19 Jul 22, 2026
e770cc7
Assert that no range axioms are emitted under --unboundedIntegers
jcp19 Jul 22, 2026
05a76fd
Quantify bounded-integer variables over their type's domain
jcp19 Aug 3, 2026
6d66c9b
Merge defined types with any integer kind in internal binary expressions
jcp19 Aug 3, 2026
097ab45
Type bit-negation with its operand's type
jcp19 Aug 3, 2026
e91239c
Keep existential bound variables at the domain sort
jcp19 Aug 4, 2026
015e1c8
Axiomatize that array, slice, and string lengths fit in int
jcp19 Aug 4, 2026
1614b6c
Exclude bounded-int arithmetic helpers from quantifier triggers
jcp19 Aug 4, 2026
ff51547
Normalize resolved package paths before deriving package ids
jcp19 Aug 4, 2026
99a0b08
Lower quantified domain occurrences via inv and add its surjectivity …
jcp19 Aug 4, 2026
47b2e1a
Add missing termination measures to closures-calldesc1
jcp19 Aug 4, 2026
220a909
Type let binders at the frontend type and align let bindings' sorts
jcp19 Aug 4, 2026
cd19c82
Require termination measure on closures-calldesc1's closure literal
jcp19 Aug 4, 2026
f24f0e7
Align pure function bodies with the declared result sort
jcp19 Aug 4, 2026
14a119c
push current pathc for scion
jcp19 Aug 6, 2026
32aa59b
backup intermediate changes
jcp19 Aug 6, 2026
84a7fe2
Merge branch 'master' into claude/new-ints-verifiedscion
jcp19 Aug 8, 2026
b77d775
Bridge bounded integers across int<->float conversions
jcp19 Aug 8, 2026
f19ccbf
Adapt integer unit tests to master's PFunctionSpec signature
jcp19 Aug 8, 2026
76d1161
Merge remote-tracking branch 'origin/claude/improve-int-type-inferenc…
jcp19 Aug 9, 2026
3b26447
Delete verified-scion-new-ints.patch
jcp19 Aug 9, 2026
7a7ea92
Merge remote-tracking branch 'origin/claude/unbounded-integers-flag-n…
jcp19 Aug 9, 2026
761f626
Merge branch 'claude/improve-int-type-inference-UFkBe' (PR #1083) int…
jcp19 Aug 9, 2026
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
31 changes: 31 additions & 0 deletions src/main/resources/stubs/math/const.gobra
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in https://golang.org/LICENSE

// Signatures for the public declarations in file
// https://github.com/golang/go/blob/master/src/math/const.go

package math

// Integer limit values.
//
// NOTE (Gobra): the architecture-dependent limits `MaxInt`, `MinInt`, and
// `MaxUint` are deliberately NOT provided. Their values depend on the size of
// the platform `int`/`uint` (32 or 64 bits), which the verifier does not fix,
// so a proof relying on them would be unsound on some target. Use the
// limits of a concrete sized type (e.g. `MaxInt64`, `MinInt32`, `MaxUint8`)
// instead.
const (
MaxInt8 = 1<<7 - 1 // 127
MinInt8 = -1 << 7 // -128
MaxInt16 = 1<<15 - 1 // 32767
MinInt16 = -1 << 15 // -32768
MaxInt32 = 1<<31 - 1 // 2147483647
MinInt32 = -1 << 31 // -2147483648
MaxInt64 = 1<<63 - 1 // 9223372036854775807
MinInt64 = -1 << 63 // -9223372036854775808
MaxUint8 = 1<<8 - 1 // 255
MaxUint16 = 1<<16 - 1 // 65535
MaxUint32 = 1<<32 - 1 // 4294967295
MaxUint64 = 1<<64 - 1 // 18446744073709551615
)
22 changes: 11 additions & 11 deletions src/main/scala/viper/gobra/Gobra.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import com.typesafe.scalalogging.StrictLogging
import org.slf4j.LoggerFactory
import scalaz.Scalaz.futureInstance
import viper.gobra.ast.internal.Program
import viper.gobra.ast.internal.transform.{CGEdgesTerminationTransform, ConstantPropagation, InternalTransform, OverflowChecksTransform}
import viper.gobra.ast.internal.transform.{CGEdgesTerminationTransform, ConstantPropagation, InternalTransform}
import viper.gobra.backend.BackendVerifier
import viper.gobra.frontend.PackageResolver.{AbstractPackage, RegularPackage}
import viper.gobra.frontend.Parser.ParseResult
Expand Down Expand Up @@ -50,6 +50,8 @@ object GoVerifier {

trait GoVerifier extends StrictLogging {

protected val timeFormatter: DateTimeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss")

def name: String = {
this.getClass.getSimpleName
}
Expand Down Expand Up @@ -86,7 +88,6 @@ trait GoVerifier extends StrictLogging {
}
})

val timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss");
config.packageInfoInputMap.keys.foreach(pkgInfo => {
val pkgId = pkgInfo.id
logger.info(s"Verifying package $pkgId [${LocalTime.now().format(timeFormatter)}]")
Expand Down Expand Up @@ -254,6 +255,7 @@ class Gobra extends GoVerifier with GoIdeVerifier {
// that all imported packages have been parsed successfully (this is only checked during type-checking)
private def performParsing(config: Config, pkgInfo: PackageInfo)(implicit executor: GobraExecutionContext): EitherT[Vector[VerifierError], Future, Map[AbstractPackage, ParseResult]] = {
if (config.shouldParse) {
logger.info(s"Phase 1/6: parsing [${LocalTime.now().format(timeFormatter)}]")
val startMs = System.currentTimeMillis()
val res = Parser.parse(config, pkgInfo)
logger.debug {
Expand All @@ -268,6 +270,7 @@ class Gobra extends GoVerifier with GoIdeVerifier {

private def performTypeChecking(config: Config, pkgInfo: PackageInfo, parseResults: Map[AbstractPackage, ParseResult])(implicit executor: GobraExecutionContext): EitherT[Vector[VerifierError], Future, TypeInfo] = {
if (config.shouldTypeCheck) {
logger.info(s"Phase 2/6: type-checking [${LocalTime.now().format(timeFormatter)}]")
Info.check(config, RegularPackage(pkgInfo.id), parseResults)
} else {
EitherT.left(Vector.empty)
Expand All @@ -276,6 +279,7 @@ class Gobra extends GoVerifier with GoIdeVerifier {

private def performDesugaring(config: Config, typeInfo: TypeInfo)(implicit executor: GobraExecutionContext): EitherT[Vector[VerifierError], Future, Program] = {
if (config.shouldDesugar) {
logger.info(s"Phase 3/6: desugaring [${LocalTime.now().format(timeFormatter)}]")
val startMs = System.currentTimeMillis()
val res = EitherT.right[Vector[VerifierError], Future, Program](Desugar.desugar(config, typeInfo)(executor))
logger.debug {
Expand All @@ -289,18 +293,12 @@ class Gobra extends GoVerifier with GoIdeVerifier {
}

/**
* Applies transformations to programs in the internal language. Currently, only adds overflow checks but it can
* be easily extended to perform more transformations
* Applies transformations to programs in the internal language.
*/
private def performInternalTransformations(config: Config, pkgInfo: PackageInfo, program: Program)(implicit executor: GobraExecutionContext): EitherT[Vector[VerifierError], Future, Program] = {
// constant propagation does not cause duplication of verification errors caused
// by overflow checks (if enabled) because all overflows in constant declarations
// can be found by the well-formedness checks.
logger.info(s"Phase 4/6: internal transformations [${LocalTime.now().format(timeFormatter)}]")
val startMs = System.currentTimeMillis()
var transformations: Vector[InternalTransform] = Vector(CGEdgesTerminationTransform, ConstantPropagation)
if (config.checkOverflows) {
transformations :+= OverflowChecksTransform
}
val transformations: Vector[InternalTransform] = Vector(CGEdgesTerminationTransform, ConstantPropagation)
val result = transformations.foldLeft(program)((prog, transf) => transf.transform(prog))
logger.debug {
val durationS = f"${(System.currentTimeMillis() - startMs) / 1000f}%.1f"
Expand All @@ -312,6 +310,7 @@ class Gobra extends GoVerifier with GoIdeVerifier {

private def performViperEncoding(config: Config, pkgInfo: PackageInfo, program: Program)(implicit executor: GobraExecutionContext): EitherT[Vector[VerifierError], Future, BackendVerifier.Task] = {
if (config.shouldViperEncode) {
logger.info(s"Phase 5/6: Viper encoding [${LocalTime.now().format(timeFormatter)}]")
val startMs = System.currentTimeMillis()
val res = EitherT.fromEither[Future, Vector[VerifierError], BackendVerifier.Task](Future.successful(Translator.translate(program, pkgInfo)(config)))
logger.debug {
Expand All @@ -328,6 +327,7 @@ class Gobra extends GoVerifier with GoIdeVerifier {
if (config.noVerify) {
Future(VerifierResult.Success)(executor)
} else {
logger.info(s"Phase 6/6: backend verification [${LocalTime.now().format(timeFormatter)}]")
verifyAst(config, pkgInfo, ast, backtrack)(executor)
}
}
Expand Down
23 changes: 15 additions & 8 deletions src/main/scala/viper/gobra/ast/internal/Program.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import viper.gobra.reporting.Source.Parser
import viper.gobra.theory.Addressability
import viper.gobra.translator.Names
import viper.gobra.util.{BackendAnnotation, Decimal, GoString, NumBase, TypeBounds, Violation}
import viper.gobra.util.TypeBounds.{IntegerKind, UnboundedInteger, UntypedConstInteger}
import viper.gobra.util.TypeBounds.{IntegerKind, UnboundedInteger}
import viper.gobra.util.Violation.violation

import scala.collection.SortedSet
Expand Down Expand Up @@ -996,8 +996,8 @@ case class MapKeys(exp : Expr, expUnderlyingType: Type)(val info : Source.Parser

case class MapValues(exp : Expr, expUnderlyingType: Type)(val info : Source.Parser.Info) extends Expr {
override val typ : Type = expUnderlyingType match {
case t: MathMapT => SetT(t.keys, Addressability.mathDataStructureElement)
case t: MapT => SetT(t.keys, Addressability.rValue)
case t: MathMapT => SetT(t.values, Addressability.mathDataStructureElement)
case t: MapT => SetT(t.values, Addressability.rValue)
case _ => violation(s"unexpected type ${exp.typ}")
}
}
Expand Down Expand Up @@ -1105,14 +1105,15 @@ sealed abstract class BinaryIntExpr(override val operator: String) extends Binar
// "kinds IntegerKind(integer) and IntegerKind(int) cannot be merged".
case (IntT(_, kind1), IntT(_, kind2)) => IntT(Addressability.Exclusive, TypeBounds.mergeLenient(kind1, kind2))

// A binary expression may have one operand of a defined type T and another operand that is an unbounded
// integer or an untyped integer constant.
// A binary expression may have one operand of a defined type T and another operand that is an integer
// (of any kind: a conversion like `AS(v)` yields the underlying bounded kind, an untyped constant may
// have been assigned a concrete kind by the type-checker, and internally synthesized nodes are unbounded).
// If T's underlying type is an integer type, then the result of the expression should be of type T.
// Here, the underlying type of a defined type is not checked, as the information is not available at this point.
// However, this should not pose a problem assuming that the original program has been type-checked before the
// translation to the internal language.
case (x, IntT(_, UnboundedInteger | UntypedConstInteger)) if x.isInstanceOf[DefinedT] => x.withAddressability(Addressability.Exclusive)
case (IntT(_, UnboundedInteger | UntypedConstInteger), y) if y.isInstanceOf[DefinedT] => y.withAddressability(Addressability.Exclusive)
case (x: DefinedT, _: IntT) => x.withAddressability(Addressability.Exclusive)
case (_: IntT, y: DefinedT) => y.withAddressability(Addressability.Exclusive)
case (x, y) if x.equalsWithoutMod(y) => x.withAddressability(Addressability.Exclusive)
case (l, r) => violation(s"cannot merge types $l and $r")

Expand Down Expand Up @@ -1153,7 +1154,13 @@ case class ShiftLeft(left: Expr, right: Expr)(val info: Source.Parser.Info) exte
case class ShiftRight(left: Expr, right: Expr)(val info: Source.Parser.Info) extends BinaryIntExpr(">>") {
override val typ: Type = left.typ
}
case class BitNeg(op: Expr)(val info: Source.Parser.Info) extends IntOperation
case class BitNeg(op: Expr)(val info: Source.Parser.Info) extends IntOperation {
// ^x has its operand's type. The inherited unbounded-Int typ would misreport the
// complement of a bounded operand: the encoding produces a domain-typed value for it,
// and enclosing operations decide based on this typ whether the value still needs the
// domain-to-Int projection.
override def typ: Type = op.typ.withAddressability(Addressability.rValue)
}

/*
* Convert 'expr' to non-interface type 'newType'. If 'newType' is
Expand Down

This file was deleted.

Loading
Loading