Scope and ownership
СсылкаUse this chapter to inspect error propagation and locate incompatible operand or return types.
This page owns postfix Result propagation and callable-local Result or Option propagation. Types owns general type compatibility. Pattern matching owns case syntax. Blocks and control flow owns explicit returns and cleanup ordering. Functions and generics owns return annotations and inference. Diagnostic entries own code-specific explanations. Command entries own process results.
Propagation syntax
СсылкаPropagation = PostfixExpression "?" ;
Expression precedence is specified by Expressions and operators.
Postfix operand
Postfix ? takes the preceding postfix expression as its operand.
Причина
Postfix placement keeps the operation that may fail next to the point that forwards its error. It follows the binding order of calls and member access.
Values and early return
СсылкаOperand evaluation
In a named function, ? evaluates its Result operand once.
The corresponding lambda and callback behavior follows lambda and callback propagation.
Причина
Repeated evaluation could repeat input, output, or mutation before deciding whether to return an error.
Successful operand
When the operand produces Ok(value), ? yields value and evaluation continues in the enclosing named function.
The corresponding lambda and callback behavior follows lambda and callback propagation.
Причина
A successful operation supplies the value needed by later expressions without ending the function.
Error return
When the operand produces Err(error), ? returns that Result with its error payload from the enclosing named function. Subsequent expressions in its body are skipped.
The corresponding lambda and callback behavior follows lambda and callback propagation.
Причина
Preserving the error payload keeps failure information intact. Skipping the remaining body prevents later work from using a value that was not produced.
Propagation returns from the current callable
Postfix ? in a lambda or callback targets that callable's own return. Each function boundary has one propagation destination. For a Result-returning lambda, an Ok yields its payload and an Err returns the original error Result from that invocation. In an Option-returning lambda, Some yields its payload and None returns None from that invocation. The remaining lambda body is skipped on either return. The surrounding function continues after the call and can propagate the returned value with its own ?.
A lambda using ? must return Result or Option. Propagating a Result from a lambda returning another type uses the same TPZ5001 rejection as the named function return rule. The expected callback type still applies. A Result-returning lambda does not satisfy a bool callback slot such as filter. An undetermined Result error type requires an annotation with TPZ5022 under the error annotation rule.
Причина
Each function boundary gives ? one return destination. A standard function such as map or filter can call a callback without handling nonlocal control transfer.
Operand fault
A runtime fault raised while evaluating the operand continues as a runtime fault.
An ordinary runtime fault follows fault termination.
A runtime fault remains a fault inside a lambda or callback. It is not a returned Err or None under lambda and callback propagation.
Причина
A runtime fault interrupts evaluation, while an Err is an ordinary value. Keeping these paths distinct prevents propagation from silently converting a fault into a Result.
Operand and return types
СсылкаSuccess type
For an operand of type Result<T, E>, operand? has type T.
Причина
Successful propagation supplies the payload to the next expression. Its type is the success type because the Result wrapper has been handled.
Result operand requirement
In a named function returning Result, a propagation operand with a resolved non-Result type is rejected during checking with TPZ5001. Option-returning lambdas follow the callable propagation rule.
Option-returning lambdas follow lambda and callback propagation.
Причина
A Result return needs an error Result to forward. An Option operand supplies no error payload for that Result return.
Enclosing function
Using ? without an enclosing function return context is rejected during checking with TPZ5001.
The corresponding lambda and callback behavior follows lambda and callback propagation.
Причина
Propagation needs a function return target. Without one, the error has no destination.
Result return requirement
Propagating a Result from a function with a resolved non-Result return type is rejected during checking with TPZ5001.
An undetermined Result error type follows the annotation requirement.
The corresponding lambda and callback behavior follows lambda and callback propagation.
Причина
The enclosing return type must admit the error Result that propagation returns. Otherwise the function could produce a value outside its declared type.
Error type compatibility
For an operand of type Result<T, E> in a function returning Result<U, F>, E must be assignable to F. Incompatible resolved error types produce TPZ5001 during checking. The propagation step does not compare T with U.
Причина
An error can leave the function at this point, so it must fit the declared error type. The success payload remains local and can be transformed before return.
Annotating an unresolved Result error type
If the Result error type cannot be determined, checking rejects the expression with TPZ5022 and requires a type annotation. Inference does not substitute a broad fallback type. This is the same diagnostic as the return annotation requirement.
This uses the same diagnostic as return annotation requirements. Lambda and callback propagation gives each lambda and callback its own return destination.
The corresponding lambda and callback behavior follows lambda and callback propagation.
Причина
Return inference and Result error inference use the same annotation rule and diagnostic. The program therefore has a determined error type before emission.
Examples and counterexamples
СсылкаThe checking examples pair rejected files with complete repairs. The execution example makes operand evaluation and continuation visible.
Option operand
Ссылкаfunction advance(value: Option<int>) -> Result<int, string> {let number: int = value?Ok(number + 1)}
Нет стандартного вывода.error[TPZ5001]: `?` requires a Result value, found `Option<int>`
--> example.tpz:2:23
|
2 | let number: int = value?
| ^^^^^^
example.tpz: 1 type diagnostic
Ожидаемый результат
Ожидаемый результат
Этап отклонения check. Ненулевой код завершения.
result-required-for-propagation at
example.tpz:2:23
Наблюдаемые утверждения · Пройдено · 5.21.3
Код завершения 1.
Нет стандартного вывода.
error[TPZ5001]: `?` requires a Result value, found `Option<int>`--> example.tpz:2:23|2 | let number: int = value?| ^^^^^^example.tpz: 1 type diagnostic
- Пройдено · expected nonzero; observed 1
- Пройдено · checking TPZ5001; cause result-required-for-propagation; primary location asserted; additional diagnostics allow
- Пройдено · stdout matches the authored expectation
Result operand
Ссылкаfunction advance(value: Result<int, string>) -> Result<int, string> {let number: int = value?Ok(number + 1)}let success: Result<int, string> = advance(Ok(4))let failure: Result<int, string> = advance(Err("missing"))
Нет стандартного вывода.Ожидаемый результат
Ожидаемый результат
Проверка принимает программу. Код завершения 0.
Наблюдаемые утверждения · Пройдено · 5.21.3
Код завершения 0.
Нет стандартного вывода.
Нет вывода ошибок.
- Пройдено · expected 0; observed 0
- Пройдено · expected 0; observed 0
- Пройдено · stdout matches the authored expectation
- Пройдено · stderr matches the authored expectation
Integer return type
Ссылкаfunction read(value: Result<int, string>) -> int {value?}
Нет стандартного вывода.error[TPZ5001]: `?` propagates an error, but the function returns `int`, not a Result
--> example.tpz:2:5
|
2 | value?
| ^^^^^^
example.tpz: 1 type diagnostic
Ожидаемый результат
Ожидаемый результат
Этап отклонения check. Ненулевой код завершения.
propagation-requires-result-return at
example.tpz:2:5
Наблюдаемые утверждения · Пройдено · 5.21.3
Код завершения 1.
Нет стандартного вывода.
error[TPZ5001]: `?` propagates an error, but the function returns `int`, not a Result--> example.tpz:2:5|2 | value?| ^^^^^^example.tpz: 1 type diagnostic
- Пройдено · expected nonzero; observed 1
- Пройдено · checking TPZ5001; cause propagation-requires-result-return; primary location asserted; additional diagnostics allow
- Пройдено · stdout matches the authored expectation
Result return type
Ссылкаfunction read(value: Result<int, string>) -> Result<int, string> {let number: int = value?Ok(number)}
Нет стандартного вывода.Ожидаемый результат
Ожидаемый результат
Проверка принимает программу. Код завершения 0.
Наблюдаемые утверждения · Пройдено · 5.21.3
Код завершения 0.
Нет стандартного вывода.
Нет вывода ошибок.
- Пройдено · expected 0; observed 0
- Пройдено · stdout matches the authored expectation
- Пройдено · stderr matches the authored expectation
Incompatible error types
Ссылкаfunction relay(value: Result<int, string>) -> Result<int, int> {let number: int = value?Ok(number)}
Нет стандартного вывода.error[TPZ5001]: expected `int`, found `string`
--> example.tpz:2:23
|
2 | let number: int = value?
| ^^^^^^
example.tpz: 1 type diagnostic
Ожидаемый результат
Ожидаемый результат
Этап отклонения check. Ненулевой код завершения.
propagated-error-type-not-assignable at
example.tpz:2:23
Наблюдаемые утверждения · Пройдено · 5.21.3
Код завершения 1.
Нет стандартного вывода.
error[TPZ5001]: expected `int`, found `string`--> example.tpz:2:23|2 | let number: int = value?| ^^^^^^example.tpz: 1 type diagnostic
- Пройдено · expected nonzero; observed 1
- Пройдено · checking TPZ5001; cause propagated-error-type-not-assignable; primary location asserted; additional diagnostics allow
- Пройдено · stdout matches the authored expectation
Matching error types
Ссылкаfunction relay(value: Result<int, string>) -> Result<int, string> {let number: int = value?Ok(number)}
Нет стандартного вывода.Ожидаемый результат
Ожидаемый результат
Проверка принимает программу. Код завершения 0.
Наблюдаемые утверждения · Пройдено · 5.21.3
Код завершения 0.
Нет стандартного вывода.
Нет вывода ошибок.
- Пройдено · expected 0; observed 0
- Пройдено · stdout matches the authored expectation
- Пройдено · stderr matches the authored expectation
Propagation at top level
Ссылкаlet value: Result<int, string> = Ok(1)let number: int = value?
Нет стандартного вывода.error[TPZ5001]: `return` outside a function
--> example.tpz:2:19
|
2 | let number: int = value?
| ^^^^^^
example.tpz: 1 type diagnostic
Ожидаемый результат
Ожидаемый результат
Этап отклонения check. Ненулевой код завершения.
propagation-outside-function at
example.tpz:2:19
Наблюдаемые утверждения · Пройдено · 5.21.3
Код завершения 1.
Нет стандартного вывода.
error[TPZ5001]: `return` outside a function--> example.tpz:2:19|2 | let number: int = value?| ^^^^^^example.tpz: 1 type diagnostic
- Пройдено · expected nonzero; observed 1
- Пройдено · checking TPZ5001; cause propagation-outside-function; primary location asserted; additional diagnostics allow
- Пройдено · stdout matches the authored expectation
Observe success and early error return
Ссылкаimport std.iofunction observe(value: Result<int, string>) -> Result<int, string> {io.writeLine("operand")value}function advance(value: Result<int, string>) -> Result<int, string> {let number: int = observe(value)?io.writeLine("continued")Ok(number + 1)}let success: Result<int, string> = advance(Ok(4))match (success) {case Ok(number) => io.writeLine("ok {number}")case Err(error) => io.writeLine("unexpected {error}")}let failure: Result<int, string> = advance(Err("missing"))match (failure) {case Ok(number) => io.writeLine("unexpected {number}")case Err(error) => io.writeLine("error {error}")}
operand
continued
ok 5
operand
error missing
Ожидаемый результат
Ожидаемый результат
Выполнение завершается. Код завершения 0.
operandcontinuedok 5operanderror missing
Наблюдаемые утверждения · Пройдено · 5.21.3
Код завершения 0.
operandcontinuedok 5operanderror missing
Нет вывода ошибок.
- Пройдено · expected 0; observed 0
- Пройдено · stdout matches the authored expectation
- Пройдено · stdout matches the authored expectation
- Пройдено · stdout matches the authored expectation
- Пройдено · stderr matches the authored expectation
An unknown Result error type requires an annotation
Ссылкаfunction value() { Ok(1) }let result = value()
Нет стандартного вывода.Ожидаемый результат
Ожидаемый результат
Этап отклонения check. Ненулевой код завершения.
result-error-annotation-required at
main.tpz:1:10
A Result return annotation fixes the error type
Ссылкаimport std.iofunction value() -> Result<int, string> { Ok(1) }let result = match (value()) {case Ok(number) => numbercase Err(_) => 0}io.writeLine("{result}")
1
Ожидаемый результат
Ожидаемый результат
Выполнение завершается. Код завершения 0.
1
Mapping a propagating lambda produces an array of Results
Ссылкаimport std.iofunction surrounding() -> int {let inputs: Array<Result<int, string>> = [Ok(1), Err("stop"), Ok(3)]let advance: (Result<int, string>) -> Result<int, string> = (value) => {let number = value?io.writeLine("lambda {number}")Ok(number + 1)}let results: Array<Result<int, string>> = inputs.map(advance)io.writeLine("after map")for result in (results) {match (result) {case Ok(number) => io.writeLine("ok {number}")case Err(error) => io.writeLine("err {error}")}}7}io.writeLine("{surrounding()}")
lambda 1
lambda 3
after map
ok 2
err stop
ok 4
7
Ожидаемый результат
Ожидаемый результат
Выполнение завершается. Код завершения 0.
lambda 1lambda 3after mapok 2err stopok 47
Наблюдаемые утверждения · Пройдено · 5.21.3
Код завершения 0.
lambda 1lambda 3after mapok 2err stopok 47
Нет вывода ошибок.
- Пройдено · expected 0; observed 0
- Пройдено · stdout matches the authored expectation
- Пройдено · stderr matches the authored expectation
None returns from its lambda while the caller continues
Ссылкаimport std.iolet advance: (Option<int>) -> Option<int> = (value) => {let number = value?io.writeLine("some {number}")Some(number + 1)}let missing = advance(None())io.writeLine("after none")match (missing) {case Some(number) => io.writeLine("{number}")case None() => io.writeLine("none")}let present = advance(Some(2))match (present) {case Some(number) => io.writeLine("{number}")case None() => io.writeLine("none")}
Нет стандартного вывода.error[TPZ5001]: `?` requires a Result value, found `Option<int>`
--> main.tpz:3:18
|
3 | let number = value?
| ^^^^^^
main.tpz: 1 type diagnostic
Ожидаемый результат
Ожидаемый результат
Выполнение завершается. Код завершения 0.
after nonenonesome 23
Наблюдаемые утверждения · Не пройдено · 5.21.3
Код завершения 1.
Нет стандартного вывода.
error[TPZ5001]: `?` requires a Result value, found `Option<int>`--> main.tpz:3:18|3 | let number = value?| ^^^^^^main.tpz: 1 type diagnostic
- Не пройдено · expected 0; observed 1
- Не пройдено · stdout matches the authored expectation
- Не пройдено · stderr matches the authored expectation
An integer-returning lambda cannot propagate a Result
Ссылкаlet read: (Result<int, string>) -> int = (value) => {value?}
Нет стандартного вывода.error[TPZ5001]: `?` propagates an error, but the function returns `int`, not a Result
--> main.tpz:2:5
|
2 | value?
| ^^^^^^
main.tpz: 1 type diagnostic
Ожидаемый результат
Ожидаемый результат
Этап отклонения check. Ненулевой код завершения.
propagation-requires-result-return at
main.tpz:2:5
Наблюдаемые утверждения · Пройдено · 5.21.3
Код завершения 1.
Нет стандартного вывода.
error[TPZ5001]: `?` propagates an error, but the function returns `int`, not a Result--> main.tpz:2:5|2 | value?| ^^^^^^main.tpz: 1 type diagnostic
- Пройдено · expected nonzero; observed 1
- Пройдено · stdout matches the authored expectation
- Пройдено · checking TPZ5001; cause propagation-requires-result-return; primary location asserted; additional diagnostics allow
A propagating lambda needs a determined Result error type
Ссылкаlet lift = () => {let value = Ok(1)?Ok(value)}
main.tpz: types-ok (1 module)
main.tpz: resolve-ok (1 module)
Ожидаемый результат
Ожидаемый результат
Этап отклонения check. Ненулевой код завершения.
result-error-annotation-required at
main.tpz:1:12
Наблюдаемые утверждения · Не пройдено · 5.21.3
Код завершения 0.
main.tpz: types-ok (1 module)main.tpz: resolve-ok (1 module)
Нет вывода ошибок.
- Не пройдено · expected nonzero; observed 0
- Не пройдено · stdout matches the authored expectation
- Не пройдено · checking TPZ5022; cause result-error-annotation-required; primary location asserted; additional diagnostics allow
Filter rejects a Result-returning callback where bool is required
Ссылкаlet predicate: (Result<int, string>) -> Result<bool, string> = (value) => {let number = value?Ok(number > 0)}let inputs: Array<Result<int, string>> = [Ok(1)]let selected = inputs.filter(predicate)
Нет стандартного вывода.error[TPZ5001]: expected `(Result<int, string>) -> bool`, found `(Result<int, string>) -> Result<bool, string>`
--> main.tpz:6:30
|
6 | let selected = inputs.filter(predicate)
| ^^^^^^^^^
main.tpz: 1 type diagnostic
Ожидаемый результат
Ожидаемый результат
Этап отклонения check. Ненулевой код завершения.
callback-return-type-mismatch at
main.tpz:6:30
Наблюдаемые утверждения · Пройдено · 5.21.3
Код завершения 1.
Нет стандартного вывода.
error[TPZ5001]: expected `(Result<int, string>) -> bool`, found `(Result<int, string>) -> Result<bool, string>`--> main.tpz:6:30|6 | let selected = inputs.filter(predicate)| ^^^^^^^^^main.tpz: 1 type diagnostic
- Пройдено · expected nonzero; observed 1
- Пройдено · stdout matches the authored expectation
- Пройдено · checking TPZ5001; cause callback-return-type-mismatch; primary location asserted; additional diagnostics allow