Line data Source code
1 : // Copyright (C) 2025-2026 Free Software Foundation, Inc.
2 :
3 : // This file is part of GCC.
4 :
5 : // GCC is free software; you can redistribute it and/or modify it under
6 : // the terms of the GNU General Public License as published by the Free
7 : // Software Foundation; either version 3, or (at your option) any later
8 : // version.
9 :
10 : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11 : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 : // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 : // for more details.
14 :
15 : // You should have received a copy of the GNU General Public License
16 : // along with GCC; see the file COPYING3. If not see
17 : // <http://www.gnu.org/licenses/>.
18 :
19 : #include "rust-desugar-question-mark.h"
20 : #include "rust-ast-builder.h"
21 :
22 : namespace Rust {
23 : namespace AST {
24 :
25 1 : DesugarQuestionMark::DesugarQuestionMark () {}
26 :
27 : void
28 1 : DesugarQuestionMark::go (std::unique_ptr<Expr> &ptr)
29 : {
30 1 : rust_assert (ptr->get_expr_kind () == Expr::Kind::ErrorPropagation);
31 :
32 1 : auto original = static_cast<ErrorPropagationExpr &> (*ptr);
33 1 : auto desugared = DesugarQuestionMark ().desugar (original);
34 :
35 1 : ptr = std::move (desugared);
36 1 : }
37 :
38 : MatchArm
39 2 : make_match_arm (std::unique_ptr<Pattern> &&pattern)
40 : {
41 2 : auto loc = pattern->get_locus ();
42 2 : return MatchArm (std::move (pattern), loc);
43 : }
44 :
45 : MatchCase
46 1 : ok_case (Builder &builder)
47 : {
48 1 : auto val = builder.identifier_pattern ("val");
49 :
50 1 : auto patterns = std::vector<std::unique_ptr<Pattern>> ();
51 1 : patterns.emplace_back (std::move (val));
52 :
53 1 : auto pattern_item = std::unique_ptr<TupleStructItems> (
54 1 : new TupleStructItemsNoRest (std::move (patterns)));
55 1 : auto pattern = std::unique_ptr<Pattern> (new TupleStructPattern (
56 2 : builder.path_in_expression (LangItem::Kind::RESULT_OK),
57 1 : std::move (pattern_item)));
58 :
59 1 : auto arm = make_match_arm (std::move (pattern));
60 :
61 1 : auto ret_val = builder.identifier ("val");
62 :
63 1 : return MatchCase (std::move (arm), std::move (ret_val));
64 1 : }
65 :
66 : MatchCase
67 1 : err_case (Builder &builder)
68 : {
69 : // TODO: We need to handle the case where there is an enclosing `try {}`
70 : // block, as that will create an additional block label that we can break to.
71 : // This allows try blocks to use the question mark operator without having the
72 : // offending statement early return from the enclosing function
73 : // FIXME: How to mark that there is an enclosing block label?
74 :
75 1 : auto val = builder.identifier_pattern ("err");
76 :
77 1 : auto patterns = std::vector<std::unique_ptr<Pattern>> ();
78 1 : patterns.emplace_back (std::move (val));
79 :
80 1 : auto pattern_item = std::unique_ptr<TupleStructItems> (
81 1 : new TupleStructItemsNoRest (std::move (patterns)));
82 1 : auto pattern = std::unique_ptr<Pattern> (new TupleStructPattern (
83 2 : builder.path_in_expression (LangItem::Kind::RESULT_ERR),
84 1 : std::move (pattern_item)));
85 :
86 1 : auto arm = make_match_arm (std::move (pattern));
87 :
88 1 : auto try_from_err = std::make_unique<PathInExpression> (
89 1 : builder.path_in_expression (LangItem::Kind::TRY_FROM_ERROR));
90 1 : auto from_from = std::make_unique<PathInExpression> (
91 1 : builder.path_in_expression (LangItem::Kind::FROM_FROM));
92 :
93 1 : auto early_return = builder.return_expr (
94 2 : builder.call (std::move (try_from_err),
95 2 : builder.call (std::move (from_from),
96 3 : builder.identifier ("err"))));
97 :
98 1 : return MatchCase (std::move (arm), std::move (early_return));
99 1 : }
100 :
101 : std::unique_ptr<Expr>
102 1 : DesugarQuestionMark::desugar (ErrorPropagationExpr &expr)
103 : {
104 1 : auto builder = Builder (expr.get_locus ());
105 :
106 : // Try::into_result(<expr>)
107 1 : auto try_into = std::make_unique<PathInExpression> (
108 1 : builder.path_in_expression (LangItem::Kind::TRY_INTO_RESULT));
109 1 : auto call = builder.call (std::move (try_into),
110 3 : expr.get_propagating_expr ().clone_expr ());
111 :
112 : // Ok(val) => val,
113 1 : auto ok_match_case = ok_case (builder);
114 : // Err(err) => return Try::from_error(From::from(err)),
115 1 : auto err_match_case = err_case (builder);
116 :
117 1 : auto cases = std::vector<MatchCase> ();
118 1 : cases.emplace_back (ok_match_case);
119 1 : cases.emplace_back (err_match_case);
120 :
121 : // match <call> {
122 : // <ok_arm>
123 : // <err_arm>
124 : // }
125 1 : return std::unique_ptr<MatchExpr> (new MatchExpr (std::move (call),
126 : std::move (cases), {}, {},
127 1 : expr.get_locus ()));
128 3 : }
129 :
130 : } // namespace AST
131 : } // namespace Rust
|