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

Add more spacing to contract error messages #1767

Merged
merged 1 commit into from
Jan 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# capture = 'stderr'
# command = ['eval']
null | std.FailWith "\x1B[9;33;47m strike through with background \"and\" \"quotes\""
null | std.FailWith "\x1B[9;33;47mstrike through with background \"and\" \"quotes\""
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
source: cli/tests/snapshot/main.rs
expression: err
---
error: contract broken by the caller of `at`: invalid array indexing
error: contract broken by the caller of `at`
invalid array indexing
┌─ <stdlib/std.ncl>:162:9
162 │ | std.contract.unstable.IndexedArrayFun
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
source: cli/tests/snapshot/main.rs
expression: err
---
error: contract broken by the caller of `at`: invalid array indexing
error: contract broken by the caller of `at`
invalid array indexing
┌─ <stdlib/std.ncl>:162:9
162 │ | std.contract.unstable.IndexedArrayFun
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
source: cli/tests/snapshot/main.rs
expression: err
---
error: contract broken by a value: cannot merge unequal arrays
error: contract broken by a value
cannot merge unequal arrays
┌─ <unknown> (generated by evaluation):1:1
1 │ contract.Equal some_array
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
source: cli/tests/snapshot/main.rs
expression: err
---
error: contract broken by the caller of `range`: invalid range
error: contract broken by the caller of `range`
invalid range
┌─ <stdlib/std.ncl>:649:9
649 │ | std.contract.unstable.RangeFun Dyn
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
source: cli/tests/snapshot/main.rs
expression: err
---
error: contract broken by the caller of `range_step`: invalid range step
error: contract broken by the caller of `range_step`
invalid range step
┌─ <stdlib/std.ncl>:624:9
624 │ | std.contract.unstable.RangeFun (std.contract.unstable.RangeStep -> Dyn)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@
source: cli/tests/snapshot/main.rs
expression: err
---
error: contract broken by a value: strike through with background "and" "quotes"
error: contract broken by a value
strike through with background "and" "quotes"
┌─ [INPUTS_PATH]/errors/blame_custom_message_ansi_escaping.ncl:3:1
3 │ null | std.FailWith "\x1B[9;33;47m strike through with background \"and\" \"quotes\""
│ ^^^^ ------------------------------------------------------------------------------ expected type
3 │ null | std.FailWith "\x1B[9;33;47mstrike through with background \"and\" \"quotes\""
│ ^^^^ ----------------------------------------------------------------------------- expected type
│ │
│ applied to this expression

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
source: cli/tests/snapshot/main.rs
expression: err
---
error: contract broken by a value: main error message
error: contract broken by a value
main error message
┌─ [INPUTS_PATH]/errors/contract_with_custom_diagnostic.ncl:13:1
13 │ null | Contract
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
source: cli/tests/snapshot/main.rs
expression: err
---
error: contract broken by a value: extra field `b`
error: contract broken by a value
extra field `b`
┌─ [INPUTS_PATH]/errors/destructuring_closed_fail.ncl:3:11
3 │ let {a} = {a=1, b=2}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
source: cli/tests/snapshot/main.rs
expression: err
---
error: contract broken by the caller: field not allowed in tail: `x`
error: contract broken by the caller
field not allowed in tail: `x`
┌─ [INPUTS_PATH]/errors/record_forall_constraints_contract.ncl:3:19
3 │ let f | forall r. { ; r } -> { x: Number; r } = fun r => %record_insert% "x" r 1 in f { x = 0 }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
source: cli/tests/snapshot/main.rs
expression: err
---
error: contract broken by a value: child's message
error: contract broken by a value
child's message
┌─ [INPUTS_PATH]/errors/subcontract_nested_custom_diagnostics.ncl:19:8
19 │ null | ParentContract
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
source: cli/tests/snapshot/main.rs
expression: err
---
error: contract broken by the value of `foo`: no reason
error: contract broken by the value of `foo`
no reason
┌─ [INPUTS_PATH]/errors/value_contract_violation.ncl:3:36
3 │ { foo | std.FailWith "no reason" = 1 }.foo
Expand Down
15 changes: 13 additions & 2 deletions core/src/error/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1589,13 +1589,24 @@ is None but last_arrow_elem is Some"
.filter(|diag| !label::ContractDiagnostic::is_empty(diag));
let head_contract_diagnostic = contract_diagnostics.next();

let mut msg = format!("{}{msg_addendum}", title(&label));
// The addendum and the custom contract diagnostic are important, so we want to display
// them as part of the main error message. However, they can make the message quite long.
// To avoid clutter, we display each component on a new line, indented with respect to the
// initial "error: "
let new_msg_block = "\n ";
let mut msg = title(&label);

if !msg_addendum.is_empty() {
// unwrap(): write shouldn't fail on a String
write!(&mut msg, "{new_msg_block}{msg_addendum}").unwrap();
}

if let Some(contract_msg) = head_contract_diagnostic
.as_ref()
.and_then(|diag| diag.message.as_ref())
{
write!(&mut msg, ": {}", &super::escape(contract_msg)).unwrap();
// unwrap(): write shouldn't fail on a String
write!(&mut msg, "{new_msg_block}{}", &super::escape(contract_msg)).unwrap();
}

let contract_notes = head_contract_diagnostic
Expand Down
21 changes: 14 additions & 7 deletions doc/manual/contracts.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,11 +139,13 @@ appropriate error messages. Let us try:
std.contract.blame_with_message "not a string" label

> 1 | IsFoo
error: contract broken by a value: not a string
error: contract broken by a value
not a string
[...]

> "a" | IsFoo
error: contract broken by a value: not equal to "foo"
error: contract broken by a value
not equal to "foo"
[...]

> "foo" | IsFoo
Expand Down Expand Up @@ -421,7 +423,8 @@ By default, record contracts are closed, meaning that additional fields are forb
> let Contract = {foo | String}

> {foo = "a", bar = 1} | Contract
error: contract broken by a value: extra field `bar`
error: contract broken by a value
extra field `bar`
[...]
```

Expand Down Expand Up @@ -495,7 +498,8 @@ be what you want:
}

> {sub_field.foo = "a", sub_field.bar = "b"} | ContractPipe
error: contract broken by the value of `sub_field`: extra field `bar`
error: contract broken by the value of `sub_field`
extra field `bar`
[...]

> {sub_field.foo = "a", sub_field.bar = "b"} | ContractEq
Expand Down Expand Up @@ -653,7 +657,8 @@ always failing contract `std.FailWith` to observe where evaluation takes place:
* documentation: Some information

> config.fail
error: contract broken by the value of `fail`: ooch
error: contract broken by the value of `fail`
ooch
[...]
```

Expand Down Expand Up @@ -831,15 +836,17 @@ it check anything, though?
}

> config."0"
error: contract broken by a value: field name `not_a_number` is not a number
error: contract broken by a value
field name `not_a_number` is not a number
[...]

> let config | NumberBoolDict = {
"0" | doc "Some information" = "not a boolean",
}

> config."0"
error: contract broken by a value: field `0` is not a boolean
error: contract broken by a value
field `0` is not a boolean
[...]
```

Expand Down
Loading