Skip to content
Closed
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
2 changes: 1 addition & 1 deletion docs/contracts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@ contemporaneous 156, **retroactive 132** (shrink-only ceiling 132), unmeasured 1
| C-342 | bytes.copy_from with a negative length or offset copies nothing on both targets | 0.62.0 | active | fixture | 1 |
| C-343 | A tail `!` over a declared-Result plain callee yields the payload in a lifted effect fn | 0.63.0 | active | fixture | 1 |
| C-344 | guard-else-err inside a call-argument block after a Result bind runs on every leg | 0.63.0 | active | fixture | 1 |
| C-345 | An effect call passed as a Result/Option parameter keeps its Result at every parameter index | 0.63.0 | active | fixture | 1 |
| C-345 | A Result passed as a call argument keeps its Result at every parameter index, generic parameters included | 0.63.0 | active | fixture | 2 |
| C-346 | A heap-payload ?? lowers on the incumbent leg as a call argument and as a match subject | 0.63.0 | active | fixture | 1 |
| C-347 | Operator round trips over a known literal print that literal on both targets | 0.63.0 | active | fixture | 1 |
| C-348 | Byte-indexed string slices validate UTF-8 boundaries | 0.63.0 | active | fixture | 1 |
Expand Down
4 changes: 2 additions & 2 deletions docs/contracts/conformance.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
> (spec-coverage + evidence-class >= fixture for every active contract), so this
> page cannot legitimately contain an empty Fixtures cell.

134 normative sections; 823 distinct executable fixtures.
134 normative sections; 824 distinct executable fixtures.

| Section | Contracts | Fixtures (how CI runs each) |
|---------|-----------|------------------------------|
Expand All @@ -30,7 +30,7 @@
| ALS-C2 | C-014 | `spec/wasm_cross/set_insertion_order.almd` (byte-compare)<br>`spec/wasm_cross/set_index_order.almd` (byte-compare)<br>`spec/wasm_cross/map_set_index_threshold.almd` (byte-compare) |
| ALS-C3 | C-015, C-124, C-185 | `spec/wasm_cross/compound_eq.almd` (byte-compare)<br>`spec/wasm_cross/deep_eq_heap.almd` (byte-compare)<br>`spec/wasm_cross/map_set_eq.almd` (byte-compare)<br>`spec/wasm_cross/variant_record_literal_equality.almd` (byte-compare)<br>`spec/wasm_cross/unique_non_flat_element.almd` (byte-compare)<br>`spec/wasm_cross/list_of_tuples_equality.almd` (byte-compare)<br>`spec/wasm_cross/map_rich_variant_key.almd` (byte-compare)<br>`spec/wasm_cross/value_deep_eq.almd` (byte-compare)<br>`spec/wasm_cross/fan_any_early_winner.almd` (byte-compare) |
| ALS-C4 | C-034, C-354 | `spec/wasm_cross/list_insert_clamp.almd` (byte-compare)<br>`spec/wasm_cross/list_remove_at_oob.almd` (byte-compare)<br>`spec/wasm_cross/list_swap_oob.almd` (byte-compare)<br>`spec/wasm_cross/list_slice_oob.almd` (byte-compare)<br>`spec/wasm_cross/list_sort_short.almd` (byte-compare)<br>`spec/wasm_cross/list_with_capacity.almd` (byte-compare)<br>`spec/wasm_cross/negative_offset_and_width_totality.almd` (byte-compare)<br>`spec/wasm_cross/repeat_size_ceiling.almd` (byte-compare)<br>`spec/wasm_cross/matrix_slice_rows_domain.almd` (byte-compare)<br>`spec/wasm_fail/matrix_conv1d_stride_aborts.almd` (both-target test) |
| ALS-C5 | C-033, C-125, C-131, C-150, C-213, C-337, C-340, C-342, C-343, C-344, C-345, C-346 | `spec/wasm_cross/alias_cow.almd` (byte-compare)<br>`spec/lang/alias_cow_test.almd` (both-target test)<br>`spec/wasm_cross/module_var_alias_cow.almd` (byte-compare)<br>`spec/wasm_cross/witness_straightline.almd` (byte-compare)<br>`spec/wasm_cross/map_set_in_place.almd` (byte-compare)<br>`spec/wasm_cross/list_push_on_record_field.almd` (byte-compare)<br>`spec/wasm_cross/bytes_set_value_semantics.almd` (byte-compare)<br>`spec/wasm_cross/loop_buffer_churn.almd` (byte-compare)<br>`spec/wasm_cross/loop_push_trailing_increment.almd` (byte-compare)<br>`spec/wasm_cross/ctor_var_copy_semantics.almd` (byte-compare)<br>`spec/wasm_cross/bytes_writer_family.almd` (byte-compare)<br>`spec/wasm_cross/bytes_temp_receiver.almd` (byte-compare)<br>`spec/wasm_cross/endian_auto_import.almd` (byte-compare)<br>`spec/wasm_cross/bytes_copy_within_offset_domain.almd` (byte-compare)<br>`spec/wasm_cross/bytes_search_edit_family.almd` (byte-compare)<br>`spec/wasm_cross/unwrap_or_strict_default.almd` (byte-compare)<br>`spec/wasm_cross/get_or_strict_default.almd` (byte-compare)<br>`spec/wasm_cross/bytes_copy_from_negative_len.almd` (byte-compare)<br>`spec/wasm_cross/tail_bang_over_declared_result_callee.almd` (byte-compare)<br>`spec/wasm_cross/guard_err_in_call_arg_block.almd` (byte-compare)<br>`spec/wasm_cross/result_param_not_first.almd` (byte-compare)<br>`spec/wasm_cross/unwrap_or_heap_arg_and_subject.almd` (byte-compare) |
| ALS-C5 | C-033, C-125, C-131, C-150, C-213, C-337, C-340, C-342, C-343, C-344, C-345, C-346 | `spec/wasm_cross/alias_cow.almd` (byte-compare)<br>`spec/lang/alias_cow_test.almd` (both-target test)<br>`spec/wasm_cross/module_var_alias_cow.almd` (byte-compare)<br>`spec/wasm_cross/witness_straightline.almd` (byte-compare)<br>`spec/wasm_cross/map_set_in_place.almd` (byte-compare)<br>`spec/wasm_cross/list_push_on_record_field.almd` (byte-compare)<br>`spec/wasm_cross/bytes_set_value_semantics.almd` (byte-compare)<br>`spec/wasm_cross/loop_buffer_churn.almd` (byte-compare)<br>`spec/wasm_cross/loop_push_trailing_increment.almd` (byte-compare)<br>`spec/wasm_cross/ctor_var_copy_semantics.almd` (byte-compare)<br>`spec/wasm_cross/bytes_writer_family.almd` (byte-compare)<br>`spec/wasm_cross/bytes_temp_receiver.almd` (byte-compare)<br>`spec/wasm_cross/endian_auto_import.almd` (byte-compare)<br>`spec/wasm_cross/bytes_copy_within_offset_domain.almd` (byte-compare)<br>`spec/wasm_cross/bytes_search_edit_family.almd` (byte-compare)<br>`spec/wasm_cross/unwrap_or_strict_default.almd` (byte-compare)<br>`spec/wasm_cross/get_or_strict_default.almd` (byte-compare)<br>`spec/wasm_cross/bytes_copy_from_negative_len.almd` (byte-compare)<br>`spec/wasm_cross/tail_bang_over_declared_result_callee.almd` (byte-compare)<br>`spec/wasm_cross/guard_err_in_call_arg_block.almd` (byte-compare)<br>`spec/wasm_cross/result_param_not_first.almd` (byte-compare)<br>`spec/wasm_cross/result_generic_param_arg.almd` (byte-compare)<br>`spec/wasm_cross/unwrap_or_heap_arg_and_subject.almd` (byte-compare) |
| ALS-C6 | C-039 | `spec/wasm_cross/map_set_typechange.almd` (byte-compare)<br>`spec/wasm_cross/map_set_ops.almd` (byte-compare) |
| ALS-C7 | C-036, C-224, C-226 | `spec/wasm_cross/records_variants.almd` (byte-compare)<br>`spec/wasm_cross/match_result.almd` (byte-compare)<br>`spec/wasm_cross/closures_and_variants.almd` (byte-compare)<br>`spec/wasm_cross/playground_default.almd` (byte-compare)<br>`spec/wasm_cross/match_container_literal.almd` (byte-compare)<br>`spec/wasm_cross/match_payload_string_literal.almd` (byte-compare)<br>`spec/wasm_cross/record_default_field_omitted.almd` (byte-compare)<br>`spec/wasm_cross/if_let_guard_let.almd` (byte-compare)<br>`spec/wasm_cross/mut_param_call_chain.almd` (byte-compare)<br>`spec/wasm_cross/mut_param_writeback_growth.almd` (byte-compare)<br>`spec/wasm_cross/list_push_on_record_field.almd` (byte-compare) |
| ALS-C8 | C-038 | `spec/wasm_cross/sized_int_record_fields.almd` (byte-compare)<br>`spec/wasm_cross/sized_numeric_literals.almd` (byte-compare) |
Expand Down
5 changes: 3 additions & 2 deletions docs/contracts/contracts.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4227,12 +4227,13 @@ evidence = [
[[contract]]
id = "C-345"
spec = "ALS-C5"
title = "An effect call passed as a Result/Option parameter keeps its Result at every parameter index"
statement = "When an effect fn call is the argument for a parameter declared `Result[..]` or `T?`, the callee receives the CARRIER (Ok/Err, some/none) on every leg, whatever the parameter's index: `show(\"a\", f(1))` with `show(tag: String, r: Result[Int, String])` prints `a=ok 1`, and `f(-1)` in the same position prints the Err. The auto-`?` desugar exempted only ARGUMENT 0 of a callee whose FIRST param is Result/Option (#558), so a Result param at index ≥ 1 had its effect-call argument unwrapped to the payload — native emitted `show(tag, f(1)?)` (rustc E0308, a build failure), the incumbent wasm leg failed validation (`expected i32, found i64`) and the structural leg walled `ty-mismatch` — an accepted program no leg could build (#1970). The exemption is a per-parameter flag derived from the signature table now, consulted at every argument index; the `result.*`/`option.*` intrinsic fallback still covers argument 0."
title = "A Result passed as a call argument keeps its Result at every parameter index, generic parameters included"
statement = "When a call's Result is the argument for a parameter that accepts a Result — one declared `Result[..]` or `T?`, or a type variable instantiated at Result (`id(int.parse(\"7\"))` with `fn id[T](x: T) -> T`, a `list.fold` seeded with a Result-returning call) — the callee receives the CARRIER (Ok/Err, some/none) on every leg, whatever the parameter's index: `show(\"a\", f(1))` with `show(tag: String, r: Result[Int, String])` prints `a=ok 1`, and `f(-1)` in the same position prints the Err. The auto-`?` desugar exempted only ARGUMENT 0 of a callee whose FIRST param is Result/Option (#558), so a Result param at index ≥ 1 had its effect-call argument unwrapped to the payload — native emitted `show(tag, f(1)?)` (rustc E0308, a build failure), the incumbent wasm leg failed validation (`expected i32, found i64`) and the structural leg walled `ty-mismatch` — an accepted program no leg could build (#1970). The per-parameter flag that replaced it still read only DECLARED Result/Option parameters, so inside an effect fn a type-variable parameter instantiated at Result had its argument unwrapped the same way (`id(int.parse(\"7\")?)`: rustc E0308, an E082 ty-mismatch wall on wasm) though the checker accepted the program (#3646). No call argument takes the auto-`?` now: the checker constrains every argument against its parameter (a Result where `Int` is expected is E005; propagation is the explicit `!`), so an argument still Result-typed is one its parameter accepts."
since = "0.63.0"
status = "active"
evidence = [
{ path = "spec/wasm_cross/result_param_not_first.almd", class = "fixture" },
{ path = "spec/wasm_cross/result_generic_param_arg.almd", class = "fixture" },
]
[[contract]]
id = "C-346"
Expand Down
39 changes: 39 additions & 0 deletions spec/wasm_cross/result_generic_param_arg.almd
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// @contract: C-345
// A Result-returning call passed where a TYPE-VARIABLE parameter is
// instantiated at Result keeps its Result, as a declared Result parameter's
// argument does (result_param_not_first). The auto-`?` desugar kept an
// argument's Result only where the callee DECLARED the parameter Result /
// Option, so in an effect fn `id(int.parse("7"))`, a fold seeded with a
// Result call, or `map.get_or(m, k, int.parse(s))` lowered with a `?` on
// the argument — rustc E0308 natively, an E082 ty-mismatch wall on wasm —
// though `almide check` accepted the program. Found by the counted stdlib
// inspection (#3646).
fn id[T](x: T) -> T = x

fn mk(n: Int) -> Result[Int, String] = if n > 0 then ok(n) else err("neg ${n}")

effect fn step(n: Int) -> Int = if n < 0 then err("neg ${n}")!
else n

fn show(tag: String, r: Result[Int, String]) -> String = match r {
ok(v) => "${tag}=ok ${v}",
err(e) => "${tag}=err ${e}",
}

effect fn main() -> Unit = {
let a: Result[Int, String] = id(int.parse("7"))
println(show("id", a))
let b: Result[Int, String] = id(mk(-1))
println(show("id-err", b))
let c: Result[Int, String] = list.fold([1, 2], mk(5), (acc, x) => acc)
println(show("fold", c))
let m: Map[String, Result[Int, String]] = map.new()
let d: Result[Int, String] = map.get_or(m, "k", int.parse("x"))
println(show("map.get_or", d))
let e: Result[Int, String] = list.get_or([mk(1)], 3, mk(9))
println(show("get_or", e))
let f: Result[Int, String] = id(step(-2))
println(show("id-effect", f))
let g: Result[Int, String] = list.fold([1], step(4), (acc, x) => acc)
println(show("fold-effect", g))
}
Loading