Tricu 2.0.0
Sorry for squashing all of this but 🤷
This commit is contained in:
137
demos/viewContracts/README.md
Normal file
137
demos/viewContracts/README.md
Normal file
@@ -0,0 +1,137 @@
|
||||
# View Contract Demos
|
||||
|
||||
These demos exercise the finalized View Contract stack in `lib/view.tri`:
|
||||
portable View Trees/checkable typed-program nodes, structural View flow checks,
|
||||
runtime guarded Views, checked-exec, source annotations, and module-boundary
|
||||
View metadata.
|
||||
|
||||
## End-user guide
|
||||
|
||||
Start here. `demos/viewContracts.tri` is written with normal source annotation
|
||||
sugar and reads as a short guide to View Contracts: motivating structural
|
||||
mismatches, explaining plain Views, noting why this is not a full static type
|
||||
system, and building a custom `NonEmptyList` guarded View.
|
||||
|
||||
```bash
|
||||
tricu check demos/viewContracts.tri
|
||||
```
|
||||
|
||||
Expected output:
|
||||
|
||||
```text
|
||||
ok
|
||||
```
|
||||
|
||||
## Complete explicit demo
|
||||
|
||||
`demos/viewContracts/complete.tri` shows the same layer from the portable
|
||||
View Tree/checkable-program side. It uses explicit builders such as
|
||||
`typedValue`, `typedRequire`, and `typedApply`, and demonstrates contextual guard
|
||||
diagnostics, observation composition, reachability, and malformed guard output.
|
||||
|
||||
```bash
|
||||
tricu eval demos/viewContracts/complete.tri -f decode
|
||||
```
|
||||
|
||||
## Portable checker self-tests
|
||||
|
||||
Runs the checker self-test suite carried as ordinary `tricu` code.
|
||||
|
||||
```bash
|
||||
tricu eval demos/viewContracts/selfTests.tri -f decode
|
||||
```
|
||||
|
||||
Expected output is a list of `"ok"` strings.
|
||||
|
||||
## Diagnostic rendering
|
||||
|
||||
Shows a strict-mode structural View failure rendered for humans.
|
||||
|
||||
```bash
|
||||
tricu eval demos/viewContracts/diagnostic.tri -f decode
|
||||
```
|
||||
|
||||
Expected output:
|
||||
|
||||
```text
|
||||
"symbol 162 expected List Bool but got List String"
|
||||
```
|
||||
|
||||
## Stdlib-shaped contracts
|
||||
|
||||
Checks successful higher-order contracts shaped like common stdlib APIs.
|
||||
|
||||
```bash
|
||||
tricu eval demos/viewContracts/stdlibContracts.tri -f decode
|
||||
```
|
||||
|
||||
Expected output:
|
||||
|
||||
```text
|
||||
["ok", "ok", "ok", "ok", "ok"]
|
||||
```
|
||||
|
||||
These examples are structural View checks, not runtime guarded checks.
|
||||
|
||||
## Frontend emission layer
|
||||
|
||||
`frontendEmission/` documents the portable artifact shape a frontend can emit
|
||||
after parsing/elaboration. The `*.source.txt` files are pseudo-source; the
|
||||
matching `*.emitted.tri` files are explicit typed-program builder output.
|
||||
|
||||
This layer is still instructive because it shows the exact bridge between source
|
||||
syntax and portable View Tree/checkable metadata.
|
||||
|
||||
## Source syntax sugar
|
||||
|
||||
The `sourceSyntax/` demos use ergonomic annotations and the `tricu check`
|
||||
frontend. The frontend lowers annotations to the same typed-program nodes used by
|
||||
the explicit demos above, then executes checked-exec so guarded annotations fail
|
||||
through the portable runner.
|
||||
|
||||
Successful check:
|
||||
|
||||
```bash
|
||||
tricu check demos/viewContracts/sourceSyntax/success.tri
|
||||
```
|
||||
|
||||
Expected output:
|
||||
|
||||
```text
|
||||
ok
|
||||
```
|
||||
|
||||
Labeled diagnostic check:
|
||||
|
||||
```bash
|
||||
tricu check demos/viewContracts/sourceSyntax/failure.tri
|
||||
```
|
||||
|
||||
Expected first failing diagnostic:
|
||||
|
||||
```text
|
||||
symbol 4 (x) expected Bool but got String
|
||||
```
|
||||
|
||||
If the first definition is fixed or removed, the later application-result
|
||||
failure demonstrates callee-aware labels:
|
||||
|
||||
```text
|
||||
symbol 3 (g application result) expected String but got Bool
|
||||
```
|
||||
|
||||
## Module boundary layer
|
||||
|
||||
`modules/` shows producer-checked module export Views flowing into a consumer
|
||||
check as module-boundary evidence. During auto-build, annotated exports are
|
||||
checked before the module manifest alias is published. Consumers then use the
|
||||
manifest's View Contract metadata as assumptions, while compatibility is still
|
||||
judged by `lib/view.tri`.
|
||||
|
||||
```bash
|
||||
tricu check demos/viewContracts/modules/success.tri
|
||||
# ok
|
||||
|
||||
tricu check demos/viewContracts/modules/failure.tri
|
||||
# symbol 3 (Util.toString application result) expected Bool but got String
|
||||
```
|
||||
119
demos/viewContracts/complete.tri
Normal file
119
demos/viewContracts/complete.tri
Normal file
@@ -0,0 +1,119 @@
|
||||
!import "prelude" !Local
|
||||
!import "view" !Local
|
||||
|
||||
-- Complete explicit View Contract demo.
|
||||
-- Run with: tricu eval demos/viewContracts/complete.tri -f decode
|
||||
--
|
||||
-- This file uses the low-level portable typed-program builders directly. It is
|
||||
-- useful for understanding what source annotations lower to. For the end-user
|
||||
-- guide, see demos/viewContracts.tri.
|
||||
|
||||
requireNonEmpty = (xs :
|
||||
lazyBool
|
||||
(_ : guardFail)
|
||||
(_ : guardOk xs)
|
||||
(emptyList? xs))
|
||||
|
||||
NonEmptyList = (elemView :
|
||||
viewGuarded (viewList elemView) requireNonEmpty)
|
||||
|
||||
checkedResult = (result :
|
||||
matchResult
|
||||
(diag env : renderDiagnostic diag)
|
||||
(exec env :
|
||||
matchResult
|
||||
(runtimeDiag runtimeEnv : renderDiagnostic runtimeDiag)
|
||||
(value runtimeEnv : value)
|
||||
(runChecked exec))
|
||||
result)
|
||||
|
||||
checkedContract = (program :
|
||||
checkedResult (checkTypedProgramWith policyStrict program))
|
||||
|
||||
plainViewFailure =
|
||||
matchResult
|
||||
(diag env : renderDiagnostic diag)
|
||||
(exec env : "unexpected-ok")
|
||||
(checkTypedProgramWith
|
||||
policyStrict
|
||||
(typedProgram
|
||||
0
|
||||
[(typedValue 0 (viewList viewString) [("Ada")])
|
||||
(typedRequire 0 (viewList viewBool) t)]))
|
||||
|
||||
nonEmptyRootSuccess =
|
||||
matchBool
|
||||
"ok"
|
||||
"unexpected-value"
|
||||
(equal?
|
||||
(checkedContract
|
||||
(typedProgram
|
||||
0
|
||||
[(typedValue 0 (NonEmptyList viewString) [("Ada") ("Grace")])]))
|
||||
[("Ada") ("Grace")])
|
||||
|
||||
nonEmptyRootFailure =
|
||||
checkedContract
|
||||
(typedProgram
|
||||
0
|
||||
[(typedValue 0 (viewList viewString) [])
|
||||
(typedRequire 0 (NonEmptyList viewString) [])])
|
||||
|
||||
firstNameSuccess =
|
||||
checkedContract
|
||||
(typedProgram
|
||||
2
|
||||
[(typedValue 0 (viewFn [(NonEmptyList viewString)] viewString) (xs : head xs))
|
||||
(typedValue 1 (viewList viewString) [("Ada") ("Grace")])
|
||||
(typedApply 2 0 1 "Ada")
|
||||
(typedRequire 2 viewString "Ada")])
|
||||
|
||||
firstNameFailure =
|
||||
checkedContract
|
||||
(typedProgram
|
||||
2
|
||||
[(typedValue 0 (viewFn [(NonEmptyList viewString)] viewString) (xs : head xs))
|
||||
(typedValue 1 (viewList viewString) [])
|
||||
(typedApply 2 0 1 t)
|
||||
(typedRequire 2 viewString t)])
|
||||
|
||||
resultGuardFailure =
|
||||
checkedContract
|
||||
(typedProgram
|
||||
2
|
||||
[(typedValue 0 (viewFn [(viewString)] (NonEmptyList viewString)) (name : []))
|
||||
(typedValue 1 viewString "Ada")
|
||||
(typedApply 2 0 1 [])])
|
||||
|
||||
observationComposition =
|
||||
checkedContract
|
||||
(typedProgram
|
||||
0
|
||||
[(typedValue 0 viewString "Ada")
|
||||
(typedRequire 0 (viewGuarded viewString (x : guardOk (append x " Lovelace"))) "Ada")
|
||||
(typedRequire 0 (viewGuarded viewString (x : guardOk (append x "!"))) "Ada")])
|
||||
|
||||
unreachableGuard =
|
||||
checkedContract
|
||||
(typedProgram
|
||||
0
|
||||
[(typedValue 0 viewString "only the root is checked")
|
||||
(typedValue 1 (viewList viewString) [])
|
||||
(typedRequire 1 (NonEmptyList viewString) [])])
|
||||
|
||||
malformedGuard =
|
||||
checkedContract
|
||||
(typedProgram
|
||||
0
|
||||
[(typedValue 0 (viewGuarded viewString (x : record 99 t)) "bad guard")])
|
||||
|
||||
main = [
|
||||
(append "plain View structural failure: " plainViewFailure)
|
||||
(append "NonEmptyList root success: " nonEmptyRootSuccess)
|
||||
(append "NonEmptyList root failure: " nonEmptyRootFailure)
|
||||
(append "NonEmptyList function argument success: " firstNameSuccess)
|
||||
(append "NonEmptyList function argument failure: " firstNameFailure)
|
||||
(append "NonEmptyList function result failure: " resultGuardFailure)
|
||||
(append "guard observations compose: " observationComposition)
|
||||
(append "unreachable guard does not run: " unreachableGuard)
|
||||
(append "malformed guard result: " malformedGuard)]
|
||||
9
demos/viewContracts/diagnostic.tri
Normal file
9
demos/viewContracts/diagnostic.tri
Normal file
@@ -0,0 +1,9 @@
|
||||
!import "prelude" !Local
|
||||
!import "view" !Local
|
||||
!import "views.catalog" !Local
|
||||
|
||||
main =
|
||||
matchResult
|
||||
(diag env : renderDiagnostic diag)
|
||||
(env rest : "ok")
|
||||
(checkTypedProgramWith policyStrict listMapWrongListArgContract)
|
||||
116
demos/viewContracts/frontendEmission/README.md
Normal file
116
demos/viewContracts/frontendEmission/README.md
Normal file
@@ -0,0 +1,116 @@
|
||||
# Frontend Emission Demos
|
||||
|
||||
These examples show the layer between source-level View annotations and the
|
||||
portable View Contract checker.
|
||||
|
||||
Each `*.source.txt` file is pseudo-source: it is not parsed by `tricu`. It shows
|
||||
the information a frontend has after parsing/elaboration.
|
||||
|
||||
Each matching `*.emitted.tri` file shows the lowered typed-program metadata that
|
||||
a frontend can emit today. A successful check returns checked-exec; these demos
|
||||
focus on structural Views, so they report `"ok"` as soon as metadata checking
|
||||
succeeds. Guarded programs should run the returned checked-exec with
|
||||
`runChecked`, as shown in `demos/viewContracts.tri` and by `tricu check`.
|
||||
|
||||
## Successful map use
|
||||
|
||||
Pseudo-source:
|
||||
|
||||
```text
|
||||
map : Fn [Fn [Bool] String, List Bool] (List String)
|
||||
f : Fn [Bool] String
|
||||
xs : List Bool
|
||||
|
||||
partial = map f
|
||||
out = partial xs
|
||||
|
||||
require out : List String
|
||||
```
|
||||
|
||||
Run the emitted artifact:
|
||||
|
||||
```bash
|
||||
tricu eval demos/viewContracts/frontendEmission/map-success.emitted.tri -f decode
|
||||
```
|
||||
|
||||
Expected output:
|
||||
|
||||
```text
|
||||
"ok"
|
||||
```
|
||||
|
||||
## Wrong list argument
|
||||
|
||||
Pseudo-source:
|
||||
|
||||
```text
|
||||
map : Fn [Fn [Bool] String, List Bool] (List String)
|
||||
f : Fn [Bool] String
|
||||
xs : List String
|
||||
|
||||
partial = map f
|
||||
out = partial xs
|
||||
```
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
tricu eval demos/viewContracts/frontendEmission/map-wrong-list.emitted.tri -f decode
|
||||
```
|
||||
|
||||
Expected output:
|
||||
|
||||
```text
|
||||
"symbol 162 expected List Bool but got List String"
|
||||
```
|
||||
|
||||
## Wrong filter predicate
|
||||
|
||||
Pseudo-source:
|
||||
|
||||
```text
|
||||
filter : Fn [Fn [Bool] Bool, List Bool] (List Bool)
|
||||
pred : Fn [Bool] String
|
||||
xs : List Bool
|
||||
|
||||
partial = filter pred
|
||||
out = partial xs
|
||||
```
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
tricu eval demos/viewContracts/frontendEmission/filter-wrong-predicate.emitted.tri -f decode
|
||||
```
|
||||
|
||||
Expected output:
|
||||
|
||||
```text
|
||||
"symbol 181 expected Fn [Bool] Bool but got Fn [Bool] String"
|
||||
```
|
||||
|
||||
## Lowering shape
|
||||
|
||||
A frontend does not need to expose `tricu` syntax internally. It only needs to
|
||||
emit portable typed-program nodes:
|
||||
|
||||
```text
|
||||
typedValue symbol view term
|
||||
typedApply out callee arg term
|
||||
typedRequire symbol view term
|
||||
```
|
||||
|
||||
The source-level flow:
|
||||
|
||||
```text
|
||||
out = map f xs
|
||||
```
|
||||
|
||||
lowers to curried Tree Calculus application nodes:
|
||||
|
||||
```text
|
||||
typedApply partial map f partialTerm
|
||||
typedApply out partial xs outTerm
|
||||
```
|
||||
|
||||
Function Views drive argument checking and result inference.
|
||||
@@ -0,0 +1,17 @@
|
||||
!import "prelude" !Local
|
||||
!import "view" !Local
|
||||
!import "views.catalog" !Local
|
||||
|
||||
-- Lowering of filter-wrong-predicate.source.txt to portable typed-program metadata.
|
||||
-- Symbols:
|
||||
-- 180 filter
|
||||
-- 181 pred
|
||||
-- 182 partial
|
||||
|
||||
program = listFilterWrongPredicateContract
|
||||
|
||||
main =
|
||||
matchResult
|
||||
(diag env : renderDiagnostic diag)
|
||||
(env rest : "unexpected-ok")
|
||||
(checkTypedProgramWith policyStrict program)
|
||||
20
demos/viewContracts/frontendEmission/map-success.emitted.tri
Normal file
20
demos/viewContracts/frontendEmission/map-success.emitted.tri
Normal file
@@ -0,0 +1,20 @@
|
||||
!import "prelude" !Local
|
||||
!import "view" !Local
|
||||
!import "views.catalog" !Local
|
||||
|
||||
-- Lowering of map-success.source.txt to portable typed-program metadata.
|
||||
-- Symbols:
|
||||
-- 100 map
|
||||
-- 101 f
|
||||
-- 102 xs
|
||||
-- 103 partial
|
||||
-- 104 out
|
||||
|
||||
program =
|
||||
listMapUseContract viewBool viewString 100 101 102 103 104
|
||||
|
||||
main =
|
||||
matchResult
|
||||
(diag env : renderDiagnostic diag)
|
||||
(env rest : "ok")
|
||||
(checkTypedProgramWith policyStrict program)
|
||||
@@ -0,0 +1,19 @@
|
||||
!import "prelude" !Local
|
||||
!import "view" !Local
|
||||
!import "views.catalog" !Local
|
||||
|
||||
-- Lowering of map-wrong-list.source.txt to portable typed-program metadata.
|
||||
-- Symbols:
|
||||
-- 160 map
|
||||
-- 161 f
|
||||
-- 162 xs
|
||||
-- 163 partial
|
||||
-- 164 out
|
||||
|
||||
program = listMapWrongListArgContract
|
||||
|
||||
main =
|
||||
matchResult
|
||||
(diag env : renderDiagnostic diag)
|
||||
(env rest : "unexpected-ok")
|
||||
(checkTypedProgramWith policyStrict program)
|
||||
30
demos/viewContracts/io-continuation.tri
Normal file
30
demos/viewContracts/io-continuation.tri
Normal file
@@ -0,0 +1,30 @@
|
||||
!import "prelude" !Local
|
||||
!import "io" !Local
|
||||
!import "view" !Local
|
||||
|
||||
-- View Contracts inside IO continuations
|
||||
-- Run with:
|
||||
--
|
||||
-- tricu eval demos/viewContracts/io-continuation.tri --io -f decode
|
||||
--
|
||||
-- Checked IO evaluation instruments continuation bodies once from source
|
||||
-- annotations. The IO runtime still executes ordinary interaction-tree actions;
|
||||
-- the returned continuations already contain the checked-exec guard boundaries.
|
||||
|
||||
requireNonEmpty = (xs :
|
||||
lazyBool
|
||||
(_ : guardFail)
|
||||
(_ : guardOk xs)
|
||||
(emptyList? xs))
|
||||
|
||||
NonEmptyList elem = viewGuarded (viewList elem) requireNonEmpty
|
||||
|
||||
acceptNames xs@(NonEmptyList String) =@String "accepted"
|
||||
|
||||
useHandler handler@(Fn [(NonEmptyList String)] String) xs@(List String) =@String
|
||||
handler xs
|
||||
|
||||
-- The IO action yields an empty list. The higher-order boundary requires a
|
||||
-- handler that accepts NonEmptyList String, so the continuation-internal pure
|
||||
-- call fails before returning the next IO value.
|
||||
main = io (bind (pure []) (xs : pure (useHandler acceptNames xs)))
|
||||
51
demos/viewContracts/io.tri
Normal file
51
demos/viewContracts/io.tri
Normal file
@@ -0,0 +1,51 @@
|
||||
!import "prelude" !Local
|
||||
!import "io" !Local
|
||||
!import "view" !Local
|
||||
|
||||
-- View Contracts + IO interaction trees
|
||||
-- Run with:
|
||||
--
|
||||
-- tricu eval demos/viewContracts/io.tri --io -f decode
|
||||
--
|
||||
-- The IO runtime expects the top-level value to be an interaction tree wrapped
|
||||
-- by the `io` sentinel:
|
||||
--
|
||||
-- pair "tricuIO" (pair version action)
|
||||
--
|
||||
-- View Contracts can validate that boundary before the IO driver starts. The IO
|
||||
-- value is still just an interaction tree; this demo only checks how it was
|
||||
-- exposed.
|
||||
|
||||
ioSentinel? = (value :
|
||||
and?
|
||||
(equal? (fst value) "tricuIO")
|
||||
(equal? (fst (snd value)) 1))
|
||||
|
||||
requireIO = (value :
|
||||
lazyBool
|
||||
(_ : guardOk value)
|
||||
(_ : guardFail)
|
||||
(ioSentinel? value))
|
||||
|
||||
-- A first useful IO View is intentionally shallow:
|
||||
--
|
||||
-- viewAny -- accept any payload structurally
|
||||
-- requireIO sentinel -- require the top-level IO wrapper at runtime
|
||||
--
|
||||
-- This does not prove every future continuation step is well-formed. It proves
|
||||
-- the checked program exposes an IO interaction tree to the host driver.
|
||||
viewIO = viewGuarded viewAny requireIO
|
||||
|
||||
checkedIO = (action :
|
||||
matchResult
|
||||
(diag env : io (pure (renderDiagnostic diag)))
|
||||
(exec env :
|
||||
matchResult
|
||||
(runtimeDiag runtimeEnv : io (pure (renderDiagnostic runtimeDiag)))
|
||||
(value runtimeEnv : value)
|
||||
(runChecked exec))
|
||||
(checkTypedProgramWith
|
||||
policyStrict
|
||||
(typedProgram 0 [(typedValue 0 viewIO action)])))
|
||||
|
||||
main = checkedIO (io (pure "checked interaction tree"))
|
||||
17
demos/viewContracts/modules/README.md
Normal file
17
demos/viewContracts/modules/README.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# Module View Contract demo
|
||||
|
||||
This demo shows producer-checked module export Views flowing into a consumer
|
||||
check as trusted View Contract evidence.
|
||||
|
||||
```sh
|
||||
tricu check demos/viewContracts/modules/success.tri
|
||||
# ok
|
||||
|
||||
tricu check demos/viewContracts/modules/failure.tri
|
||||
# symbol 3 (Util.toString application result) expected Bool but got String
|
||||
```
|
||||
|
||||
`util.tri` is a local workspace module. During auto-build, its annotated exports
|
||||
are checked before the module manifest alias is published. The consumer then
|
||||
uses the manifest's View Contract metadata and View Tree export artifacts as
|
||||
module-boundary assumptions; compatibility is still judged by `lib/view.tri`.
|
||||
3
demos/viewContracts/modules/failure.tri
Normal file
3
demos/viewContracts/modules/failure.tri
Normal file
@@ -0,0 +1,3 @@
|
||||
!import "vc.demo.util" Util
|
||||
|
||||
foo x@Bool =@Bool Util.toString x
|
||||
3
demos/viewContracts/modules/success.tri
Normal file
3
demos/viewContracts/modules/success.tri
Normal file
@@ -0,0 +1,3 @@
|
||||
!import "vc.demo.util" Util
|
||||
|
||||
foo x@Bool =@Bool Util.id x
|
||||
1
demos/viewContracts/modules/tricu.workspace
Normal file
1
demos/viewContracts/modules/tricu.workspace
Normal file
@@ -0,0 +1 @@
|
||||
module vc.demo.util = util.tri
|
||||
2
demos/viewContracts/modules/util.tri
Normal file
2
demos/viewContracts/modules/util.tri
Normal file
@@ -0,0 +1,2 @@
|
||||
id x@Bool =@Bool x
|
||||
toString x@Bool =@String "ok"
|
||||
3
demos/viewContracts/selfTests.tri
Normal file
3
demos/viewContracts/selfTests.tri
Normal file
@@ -0,0 +1,3 @@
|
||||
!import "views.catalog" !Local
|
||||
|
||||
main = viewCatalogSelfTests
|
||||
9
demos/viewContracts/sourceSyntax/failure.tri
Normal file
9
demos/viewContracts/sourceSyntax/failure.tri
Normal file
@@ -0,0 +1,9 @@
|
||||
-- Source-level View Contract diagnostic demo.
|
||||
-- Run with: tricu check demos/viewContracts/sourceSyntax/failure.tri
|
||||
|
||||
makeBool x@String =@Bool x
|
||||
|
||||
xs =@(List String) [(g "hi")]
|
||||
g y@String =@Bool y
|
||||
|
||||
main = "if you're seeing this instead of an error, you ran the file unchecked"
|
||||
10
demos/viewContracts/sourceSyntax/success.tri
Normal file
10
demos/viewContracts/sourceSyntax/success.tri
Normal file
@@ -0,0 +1,10 @@
|
||||
-- Source-level View Contract syntax sugar demo.
|
||||
-- Run with: tricu check demos/viewContracts/sourceSyntax/success.tri
|
||||
|
||||
message =@String "hello"
|
||||
|
||||
boxedMessages =@(Maybe (List String)) just [(message) ("world")]
|
||||
|
||||
chooseFirst x@String y@Byte =@String x
|
||||
|
||||
fromLambda =@(Fn [String] String) (x : x)
|
||||
10
demos/viewContracts/stdlibContracts.tri
Normal file
10
demos/viewContracts/stdlibContracts.tri
Normal file
@@ -0,0 +1,10 @@
|
||||
!import "prelude" !Local
|
||||
!import "view" !Local
|
||||
!import "views.catalog" !Local
|
||||
|
||||
main = [
|
||||
(typedContractCheck listMapBoolStringContract)
|
||||
(typedContractCheck headMaybeBoolContract)
|
||||
(typedContractCheck listFilterBoolContract)
|
||||
(typedContractCheck listFoldStringBoolContract)
|
||||
(typedContractCheck listMapMaybeBoolStringContract)]
|
||||
Reference in New Issue
Block a user