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 :
21 : namespace Rust {
22 : namespace AST {
23 :
24 194 : DesugarQuestionMark::DesugarQuestionMark () {}
25 :
26 : void
27 194 : DesugarQuestionMark::go (std::unique_ptr<Expr> &ptr,
28 : Builder::Source node_source)
29 : {
30 194 : rust_assert (ptr->get_expr_kind () == Expr::Kind::ErrorPropagation);
31 :
32 194 : auto original = static_cast<ErrorPropagationExpr &> (*ptr);
33 194 : auto desugared = DesugarQuestionMark ().desugar (original, node_source);
34 :
35 194 : ptr = std::move (desugared);
36 194 : }
37 :
38 : MatchArm
39 388 : make_match_arm (std::unique_ptr<Pattern> &&pattern)
40 : {
41 388 : auto loc = pattern->get_locus ();
42 388 : return MatchArm (std::move (pattern), loc);
43 : }
44 :
45 : MatchCase
46 194 : ok_case (Builder &builder)
47 : {
48 194 : auto val = builder.identifier_pattern ("val");
49 :
50 194 : auto patterns = std::vector<std::unique_ptr<Pattern>> ();
51 194 : patterns.emplace_back (std::move (val));
52 :
53 194 : auto pattern_item = std::unique_ptr<TupleStructItems> (
54 194 : new TupleStructItemsNoRest (std::move (patterns)));
55 194 : auto pattern = std::unique_ptr<Pattern> (new TupleStructPattern (
56 388 : builder.path_in_expression (LangItem::Kind::RESULT_OK),
57 194 : std::move (pattern_item)));
58 :
59 194 : auto arm = make_match_arm (std::move (pattern));
60 :
61 194 : auto ret_val = builder.identifier ("val");
62 :
63 194 : return MatchCase (std::move (arm), std::move (ret_val));
64 194 : }
65 :
66 : MatchCase
67 194 : 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 194 : auto val = builder.identifier_pattern ("err");
76 :
77 194 : auto patterns = std::vector<std::unique_ptr<Pattern>> ();
78 194 : patterns.emplace_back (std::move (val));
79 :
80 194 : auto pattern_item = std::unique_ptr<TupleStructItems> (
81 194 : new TupleStructItemsNoRest (std::move (patterns)));
82 194 : auto pattern = std::unique_ptr<Pattern> (new TupleStructPattern (
83 388 : builder.path_in_expression (LangItem::Kind::RESULT_ERR),
84 194 : std::move (pattern_item)));
85 :
86 194 : auto arm = make_match_arm (std::move (pattern));
87 :
88 194 : auto try_from_err = std::make_unique<PathInExpression> (
89 194 : builder.path_in_expression (LangItem::Kind::TRY_FROM_ERROR));
90 194 : auto from_from = std::make_unique<PathInExpression> (
91 194 : builder.path_in_expression (LangItem::Kind::FROM_FROM));
92 :
93 194 : auto early_return = builder.return_expr (
94 388 : builder.call (std::move (try_from_err),
95 388 : builder.call (std::move (from_from),
96 582 : builder.identifier ("err"))));
97 :
98 194 : return MatchCase (std::move (arm), std::move (early_return));
99 194 : }
100 :
101 : std::unique_ptr<Expr>
102 194 : DesugarQuestionMark::desugar (ErrorPropagationExpr &expr,
103 : Builder::Source node_source)
104 : {
105 194 : auto builder = Builder (expr.get_locus (), node_source);
106 :
107 : // Try::into_result(<expr>)
108 194 : auto try_into = std::make_unique<PathInExpression> (
109 194 : builder.path_in_expression (LangItem::Kind::TRY_INTO_RESULT));
110 194 : auto call = builder.call (std::move (try_into),
111 582 : expr.get_propagating_expr ().clone_expr ());
112 :
113 : // Ok(val) => val,
114 194 : auto ok_match_case = ok_case (builder);
115 : // Err(err) => return Try::from_error(From::from(err)),
116 194 : auto err_match_case = err_case (builder);
117 :
118 194 : auto cases = std::vector<MatchCase> ();
119 194 : cases.emplace_back (ok_match_case);
120 194 : cases.emplace_back (err_match_case);
121 :
122 : // match <call> {
123 : // <ok_arm>
124 : // <err_arm>
125 : // }
126 194 : return std::unique_ptr<MatchExpr> (new MatchExpr (std::move (call),
127 : std::move (cases), {}, {},
128 194 : expr.get_locus ()));
129 582 : }
130 :
131 : } // namespace AST
132 : } // namespace Rust
|