Skip to content

PoC of let? #7582

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

Open
wants to merge 20 commits into
base: master
Choose a base branch
from
Open

PoC of let? #7582

wants to merge 20 commits into from

Conversation

zth
Copy link
Member

@zth zth commented Jun 30, 2025

npm i https://pkg.pr.new/rescript-lang/rescript@7582
let getXWithResultAsync = async s => {
  let? Ok({s} as res) = await doStuffResultAsync(s)
  Console.log(s)
  let? Ok(x) = await decodeResAsync(res)
  Ok(x ++ "test")
}

EDIT: This is now hidden behind a new concept of "experimental features". Therefore, this is ready to be reviewed and merged as experimental, if we want to,

TODO

  • Make sure error messages make sense and are well covered
  • Make sure editor tooling works as expected

Copy link

pkg-pr-new bot commented Jun 30, 2025

Open in StackBlitz

rescript

npm i https://pkg.pr.new/rescript-lang/rescript@7582

@rescript/darwin-arm64

npm i https://pkg.pr.new/rescript-lang/rescript/@rescript/darwin-arm64@7582

@rescript/darwin-x64

npm i https://pkg.pr.new/rescript-lang/rescript/@rescript/darwin-x64@7582

@rescript/linux-arm64

npm i https://pkg.pr.new/rescript-lang/rescript/@rescript/linux-arm64@7582

@rescript/linux-x64

npm i https://pkg.pr.new/rescript-lang/rescript/@rescript/linux-x64@7582

@rescript/win32-x64

npm i https://pkg.pr.new/rescript-lang/rescript/@rescript/win32-x64@7582

commit: 9236e6f

@leoliu
Copy link

leoliu commented Jul 2, 2025

Looks like a great feature in development!

BTW some languages place ? around the = like ?= or =?. I wonder if this has been considered. This can potentially also be used with if.

@zth
Copy link
Member Author

zth commented Jul 2, 2025

@leoliu thank you! There's now a forum post for the proposal where you can add your thoughts if you want: https://forum.rescript-lang.org/t/proposing-new-syntax-for-zero-cost-unwrapping-options-results/6227

@cknitt cknitt added this to the v12.1 milestone Jul 3, 2025
@zth zth marked this pull request as ready for review August 23, 2025 06:47
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR implements the "let?" syntax (LetUnwrap) as an experimental feature for ReScript, providing syntactic sugar for early-return patterns with Result and Option types. The implementation hides this functionality behind an experimental feature flag that must be explicitly enabled.

Key changes:

  • Adds the let? syntax that automatically unwraps Result/Option types with early return behavior
  • Implements experimental feature infrastructure with configuration support in rescript.json
  • Provides comprehensive error handling and validation for the new syntax

Reviewed Changes

Copilot reviewed 40 out of 40 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests/tests/src/LetUnwrap.res Test cases demonstrating let? syntax with Result, Option, and async patterns
tests/tests/src/LetUnwrap.mjs Generated JavaScript output showing the transformation logic
tests/syntax_tests/res_test.ml Parser test update for new Let token structure
tests/syntax_tests/data/printer/expr/letUnwrap.res Printer test cases for let? syntax
tests/syntax_tests/data/parsing/grammar/expressions/letUnwrap.res Grammar parsing test cases
tests/syntax_tests/data/parsing/errors/signature/letUnwrap.resi Error test for let? in signatures
tests/syntax_tests/data/parsing/errors/expressions/letUnwrapRec.res Error test for let? with rec
tests/build_tests/super_errors/fixtures/* Error handling test fixtures
rewatch/src/config.rs Configuration support for experimental features in rescript.json
rewatch/src/build/compile.rs Compiler argument generation for experimental features
compiler/syntax/src/res_token.ml Token definition updates to support let?
compiler/syntax/src/res_scanner.ml Scanner updates to recognize let? syntax
compiler/syntax/src/res_printer.ml Pretty printer support for let?
compiler/syntax/src/res_grammar.ml Grammar updates for let? parsing
compiler/syntax/src/res_core.ml Core parsing logic for let? with validation
compiler/ml/experimental_features.ml Experimental feature management system
compiler/frontend/bs_syntaxerr.ml Error message definitions for let?
compiler/frontend/bs_builtin_ppx.ml AST transformation logic for let? to switch expressions
compiler/frontend/ast_attributes.ml Attribute handling for let.unwrap marker
compiler/bsc/rescript_compiler_main.ml Command line flag support for experimental features

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Comment on lines +18 to +21
let enable_from_string (s : string) =
match from_string s with
| Some f -> enabled_features := FeatureSet.add f !enabled_features
| None -> ()
Copy link
Preview

Copilot AI Aug 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The enable_from_string function silently ignores unknown feature names. This could lead to configuration errors being missed. Consider logging a warning or returning a result type to indicate failure.

Suggested change
let enable_from_string (s : string) =
match from_string s with
| Some f -> enabled_features := FeatureSet.add f !enabled_features
| None -> ()
let enable_from_string (s : string) : bool =
match from_string s with
| Some f ->
enabled_features := FeatureSet.add f !enabled_features;
true
| None ->
Printf.eprintf "Warning: Unknown feature name '%s' (ignored)\n" s;
false

Copilot uses AI. Check for mistakes.

@@ -0,0 +1,11 @@

Copy link
Member

@mediremi mediremi Aug 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another super error test that I think we could have is for the case where let? is used in a function whose return type is not result/option:

@@config({flags: ["-enable-experimental", "LetUnwrap"]})

let fn = (): int => {
  let? Some(x) = None
  42
}

Copy link
Member Author

@zth zth Aug 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! I added one: 47b70bb

...and the error is terrible. I gave it a quick shot to improve it:
5f196a0

@mediremi can you think of a good error message here?

EDIT: This is the current error:

  We've found a bug for you!
  tst.res:6:8-14

  45let fn = (): int => {
  6let? Some(x) = x
  7Some(x)
  8 │ }

  This has type: option<'a>
  But this let? is used in a context expecting the type: int

  let? can only be used in a context that expects option or result.

Copy link
Member

@mediremi mediremi Aug 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new error is a nice improvement to the original error message mentioning a switch 💪

Would it be possible to detect if the context is a function? That way we can have a clearer error message for that case where we say something along the lines of let? can only be used in a function that returns option or result - since context that expects may be confusing.

Copy link
Member

@mediremi mediremi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried this out in a bsb project with "bsc-flags": ["-enable-experimental", "LetUnwrap"] and it all works perfectly 🎉

Great work @zth 😁

@zth
Copy link
Member Author

zth commented Aug 23, 2025

@mediremi would you have another look at all the error messages now?

@mediremi
Copy link
Member

The new error messages for let? being used in the wrong context look good to me ✔️

@zth
Copy link
Member Author

zth commented Aug 24, 2025

Please feel free to add any other feedback in the coming days. We'll merge this under the experimental flag before the next beta release if nothing more comes up.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants