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