Skip to content

Make value capture of optionals more robust. #277

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

Merged
merged 1 commit into from
Mar 11, 2024

Conversation

grynspan
Copy link
Contributor

@grynspan grynspan commented Mar 11, 2024

When an expression is optional and is passed through #require(), and that requirement fails, we capture the expression's subexpressions and record them as an expectation-failed event that is eventually propagated to stderr. Yay.

The underlying value-capturing machinery accepts optional values as input so that they can be lazily evaluated: if a value is nil at this layer, that means that it wasn't evaluated and we present "<not evaluated>" instead of a description of it or "nil".

In the case of #require() unwrapping optionals, these values need to be boxed in a second optional (i.e. T?? instead of T?, or Optional<Optional<T>> instead of Optional<T>) so that if the value is nil, it isn't confused with "no value". See the following table:

Expression Value of x as String?? Presented As
try #require(x) .some(.some("Hello World")) "Hello World"
try #require(x) .some(.none) nil
try #require("Goodbye Venus" ?? x) .none "<not evaluated>"

(This maybe suggests we should use a different enum than Optional here, but that's a debate for another PR I think…)

This PR fixes a couple of spots where we weren't casting our values, known to be optionals, to double-optionals, resulting in incorrect output that incorrectly included "<not evaluated>".

Checklist:

  • Code and documentation should follow the style of the Style Guide.
  • If public symbols are renamed or modified, DocC references should be updated.

When an expression is optional and is passed through `#require()`, and that
requirement fails, we capture the expression's subexpressions and record them as
an expectation-failed event that is eventually propagated to `stderr`. Yay.

The underlying value-capturing machinery accepts optional values as input so
that they can be lazily evaluated: if a value is `nil` at this layer, that means
that it wasn't evaluated and we present `"<not evaluated>"` instead of a
description of it or `"nil"`.

In the case of `#require()` unwrapping optionals, these values need to be boxed
in a second optional (i.e. `T??` instead of `T?`, or `Optional<Optional<T>>`
instead of `Optional<T>`) so that if the value is `nil`, it isn't confused with
"no value". See the following table:

| Expression | Value of `x: String?` | Presented As |
|-|-|-|
| `try #require(x)` | `.some("Hello World")` | `"Hello World"` |
| `try #require(x)` | `.some(.none)` | `nil` |
| `try #require("Goodbye Venus" ?? x)` | `.none` | `"<not evaluated>"` |

(This maybe suggests we should use a different enum than `Optional` here, but
that's a debate for another PR I think…)

This PR fixes a couple of spots where we weren't casting our values, known to be
optionals, to double-optionals, resulting in incorrect output that incorrectly
included `"<not evaluated>"`.
@grynspan
Copy link
Contributor Author

@swift-ci please test

@grynspan grynspan self-assigned this Mar 11, 2024
@grynspan grynspan added the bug 🪲 Something isn't working label Mar 11, 2024
@grynspan grynspan merged commit c0e4f59 into main Mar 11, 2024
@grynspan grynspan deleted the jgrynspan/optional-checking-more-robust branch March 11, 2024 18:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug 🪲 Something isn't working
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants