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
기대 결과
관측한 단언 · 통과 · 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
기대 결과
관측한 단언 · 통과 · 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
기대 결과
관측한 단언 · 통과 · 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
기대 결과
관측한 단언 · 통과 · 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()
표준 출력 없음.기대 결과
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
기대 결과
관측한 단언 · 통과 · 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)
기대 결과
관측한 단언 · 실패 · 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
기대 결과
관측한 단언 · 통과 · 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