Attach contracts to definitions

Contracts now live directly on definitions via @ / =@ annotations and
travel automatically with exported values.

- Remove !export from lexer/parser/AST/evaluator/manifest/resolver and CLI.
- Simplify workspace module export logic: export all top-level local
  definitions by default.
- Update Frontend.ContractDesugar:
  - Named binder annotations (x@nat?) expand to per-argument withContract.
  - Phantom annotations (@nat?) expand to a local raw helper plus a wrapper,
    keeping fixed points shared and only depending on withContract.
- Merge lib/guardedBase.tri into lib/base.tri and annotate partial/sensitive
  base functions: head, tail, last, add, sub, mul, div, mod, pow, min,
  max, length, sum, product.
- Add check contract helper to lib/base.tri.
- Update demos/contractBasics.tri and README to reflect @/=@-only design.
- Update test suite: remove guardedBase import, replace explicit !export
  test with a test verifying that contract annotations on an exported
  definition are enforced on import.
- Fix remaining base.tri definitions (div/mod/pow) to stay point-free.
This commit is contained in:
2026-09-01 10:33:54 -05:00
parent 229ba34af4
commit e595763f91
15 changed files with 105 additions and 198 deletions

View File

@@ -190,14 +190,14 @@ pred = y (self : triage
isZero? = triage true (_ : false) (_ _ : false)
add = y (self x y :
add @nat? @nat? =@nat? (y (self x y :
triage
y
(_ : succ y)
(_ _ : succ (self (pred x) y))
x)
x))
sub = y (self a b :
sub @nat? @nat? =@nat? y (self a b :
ifLazy
(isZero? b)
(_ : a)
@@ -222,13 +222,13 @@ lt? = a b :
gt? = a b :
lt? b a
mul = y (self a b :
mul @nat? @nat? =@nat? y (self a b :
ifLazy
(isZero? b)
(_ : 0)
(_ : add a (self a (pred b))))
div = y (self a b :
div @nat? @nat? =@nat? y (self a b :
ifLazy
(isZero? b)
(_ : 0)
@@ -237,7 +237,7 @@ div = y (self a b :
(_ : 0)
(_ : succ (self (sub a b) b))))
mod = y (self a b :
mod @nat? @nat? =@nat? y (self a b :
ifLazy
(isZero? b)
(_ : 0)
@@ -246,7 +246,7 @@ mod = y (self a b :
(_ : a)
(_ : self (sub a b) b)))
pow = y (self a b :
pow @nat? @nat? =@nat? y (self a b :
ifLazy
(isZero? b)
(_ : 1)
@@ -260,9 +260,9 @@ even? n = (triage
odd? = (n : not? (even? n))
min = (a b : ifLazy (lte? a b) (_ : a) (_ : b))
min @nat? @nat? =@nat? (a b : ifLazy (lte? a b) (_ : a) (_ : b))
max = (a b : ifLazy (lte? a b) (_ : b) (_ : a))
max @nat? @nat? =@nat? (a b : ifLazy (lte? a b) (_ : b) (_ : a))
-- ---------------------------------------------------------------------------
-- Result combinators
@@ -299,8 +299,8 @@ resultMapErr = (f result :
matchList = a b : triage a _ b
emptyList? = matchList true (_ _ : false)
head = matchList t (head _ : head)
tail = matchList t (_ tail : tail)
head xs@(nonEmptyListOf anyC) =@anyC matchList t (h _ : h) xs
tail xs@(nonEmptyListOf anyC) =@(listOf anyC) matchList t (_ r : r) xs
append_ self xs ys =
matchList
@@ -353,7 +353,7 @@ length_ self xs =
0
(_ r : succ (self r))
xs
length = xs : y length_ xs
length @(listOf anyC) =@nat? y length_
reverse_ self xs acc =
matchList
@@ -389,7 +389,7 @@ last_ self xs =
(self r)
(emptyList? r))
xs
last = xs : y last_ xs
last @(nonEmptyListOf anyC) =@anyC y last_
all?_ self pred xs =
matchList
@@ -526,8 +526,8 @@ contains?_ self needle haystack =
(startsWith? needle haystack)
contains? = needle haystack : y contains?_ needle haystack
sum = foldl (acc x : add x acc) 0
product = foldl (acc x : mul x acc) 1
sum @(listOf nat?) =@nat? foldl (acc x : add x acc) 0
product @(listOf nat?) =@nat? foldl (acc x : mul x acc) 1
-- ---------------------------------------------------------------------------
-- Generic separators
@@ -634,6 +634,11 @@ zipWith = f xs ys : y zipWith_ f xs ys
contractOk = (value : (rest : ok value rest))
contractErr = (msg : (rest : err msg rest))
check contract value =
withContract contract value
(x : x)
(msg : msg)
-- Apply a contract with the conventional rest slot and return the raw Result.
checkContract = (contract value : contract value t)