]>
Commit | Line | Data |
---|---|---|
6441eb6d | 1 | // Copyright (C) 2020-2025 Free Software Foundation, Inc. |
019b2f15 PH |
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-compile-expr.h" | |
20 | #include "rust-compile-struct-field-expr.h" | |
019b2f15 PH |
21 | #include "rust-compile-pattern.h" |
22 | #include "rust-compile-resolve-path.h" | |
23 | #include "rust-compile-block.h" | |
24 | #include "rust-compile-implitem.h" | |
25 | #include "rust-constexpr.h" | |
385a03ae | 26 | #include "rust-compile-type.h" |
9c87dc0a | 27 | #include "rust-gcc.h" |
d7e88ed1 | 28 | #include "rust-compile-asm.h" |
019b2f15 PH |
29 | #include "fold-const.h" |
30 | #include "realmpfr.h" | |
31 | #include "convert.h" | |
c9600aa5 | 32 | #include "print-tree.h" |
709371a1 | 33 | #include "rust-system.h" |
561ef90a | 34 | #include "rust-tyty.h" |
019b2f15 PH |
35 | |
36 | namespace Rust { | |
37 | namespace Compile { | |
38 | ||
39 | CompileExpr::CompileExpr (Context *ctx) | |
40 | : HIRCompileBase (ctx), translated (error_mark_node) | |
41 | {} | |
42 | ||
43 | tree | |
c29a3bc9 | 44 | CompileExpr::Compile (HIR::Expr &expr, Context *ctx) |
019b2f15 PH |
45 | { |
46 | CompileExpr compiler (ctx); | |
c29a3bc9 | 47 | expr.accept_vis (compiler); |
019b2f15 PH |
48 | return compiler.translated; |
49 | } | |
50 | ||
51 | void | |
52 | CompileExpr::visit (HIR::TupleIndexExpr &expr) | |
53 | { | |
c29a3bc9 | 54 | HIR::Expr &tuple_expr = expr.get_tuple_expr (); |
019b2f15 PH |
55 | TupleIndex index = expr.get_tuple_index (); |
56 | ||
57 | tree receiver_ref = CompileExpr::Compile (tuple_expr, ctx); | |
58 | ||
59 | TyTy::BaseType *tuple_expr_ty = nullptr; | |
60 | bool ok | |
c29a3bc9 | 61 | = ctx->get_tyctx ()->lookup_type (tuple_expr.get_mappings ().get_hirid (), |
019b2f15 PH |
62 | &tuple_expr_ty); |
63 | rust_assert (ok); | |
64 | ||
65 | // do we need to add an indirect reference | |
66 | if (tuple_expr_ty->get_kind () == TyTy::TypeKind::REF) | |
67 | { | |
68 | tree indirect = indirect_expression (receiver_ref, expr.get_locus ()); | |
69 | receiver_ref = indirect; | |
70 | } | |
71 | ||
72 | translated | |
f14cbab8 | 73 | = Backend::struct_field_expression (receiver_ref, index, expr.get_locus ()); |
019b2f15 PH |
74 | } |
75 | ||
76 | void | |
77 | CompileExpr::visit (HIR::TupleExpr &expr) | |
78 | { | |
79 | if (expr.is_unit ()) | |
80 | { | |
40b40970 | 81 | translated = unit_expression (expr.get_locus ()); |
019b2f15 PH |
82 | return; |
83 | } | |
84 | ||
85 | TyTy::BaseType *tyty = nullptr; | |
86 | if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (), | |
87 | &tyty)) | |
88 | { | |
89 | rust_fatal_error (expr.get_locus (), | |
90 | "did not resolve type for this TupleExpr"); | |
91 | return; | |
92 | } | |
93 | ||
94 | tree tuple_type = TyTyResolveCompile::compile (ctx, tyty); | |
95 | rust_assert (tuple_type != nullptr); | |
96 | ||
97 | // this assumes all fields are in order from type resolution | |
98 | std::vector<tree> vals; | |
99 | for (auto &elem : expr.get_tuple_elems ()) | |
100 | { | |
c29a3bc9 | 101 | auto e = CompileExpr::Compile (*elem, ctx); |
019b2f15 PH |
102 | vals.push_back (e); |
103 | } | |
104 | ||
f14cbab8 OA |
105 | translated = Backend::constructor_expression (tuple_type, false, vals, -1, |
106 | expr.get_locus ()); | |
019b2f15 PH |
107 | } |
108 | ||
109 | void | |
110 | CompileExpr::visit (HIR::ReturnExpr &expr) | |
111 | { | |
112 | auto fncontext = ctx->peek_fn (); | |
113 | ||
cf046027 | 114 | tree return_value = expr.has_return_expr () |
c29a3bc9 | 115 | ? CompileExpr::Compile (expr.get_expr (), ctx) |
40b40970 | 116 | : unit_expression (expr.get_locus ()); |
b90dc2bd PH |
117 | |
118 | if (expr.has_return_expr ()) | |
119 | { | |
120 | HirId id = expr.get_mappings ().get_hirid (); | |
1ed62a2b | 121 | location_t rvalue_locus = expr.return_expr->get_locus (); |
b90dc2bd PH |
122 | |
123 | TyTy::BaseType *expected = fncontext.retty; | |
1ed62a2b | 124 | location_t lvalue_locus |
fd788dd5 | 125 | = ctx->get_mappings ().lookup_location (expected->get_ref ()); |
b90dc2bd PH |
126 | |
127 | TyTy::BaseType *actual = nullptr; | |
128 | bool ok = ctx->get_tyctx ()->lookup_type ( | |
129 | expr.return_expr->get_mappings ().get_hirid (), &actual); | |
130 | rust_assert (ok); | |
131 | ||
132 | return_value = coercion_site (id, return_value, actual, expected, | |
133 | lvalue_locus, rvalue_locus); | |
134 | } | |
135 | ||
f14cbab8 OA |
136 | tree return_stmt = Backend::return_statement (fncontext.fndecl, return_value, |
137 | expr.get_locus ()); | |
cf046027 | 138 | ctx->add_statement (return_stmt); |
019b2f15 PH |
139 | } |
140 | ||
141 | void | |
142 | CompileExpr::visit (HIR::ArithmeticOrLogicalExpr &expr) | |
143 | { | |
144 | auto op = expr.get_expr_type (); | |
c29a3bc9 PEP |
145 | auto lhs = CompileExpr::Compile (expr.get_lhs (), ctx); |
146 | auto rhs = CompileExpr::Compile (expr.get_rhs (), ctx); | |
019b2f15 PH |
147 | |
148 | // this might be an operator overload situation lets check | |
149 | TyTy::FnType *fntype; | |
150 | bool is_op_overload = ctx->get_tyctx ()->lookup_operator_overload ( | |
151 | expr.get_mappings ().get_hirid (), &fntype); | |
152 | if (is_op_overload) | |
153 | { | |
154 | auto lang_item_type | |
bf6d216f | 155 | = LangItem::OperatorToLangItem (expr.get_expr_type ()); |
db179293 PEP |
156 | translated = resolve_operator_overload ( |
157 | lang_item_type, expr, lhs, rhs, expr.get_lhs (), | |
158 | tl::optional<std::reference_wrapper<HIR::Expr>> (expr.get_rhs ())); | |
019b2f15 PH |
159 | return; |
160 | } | |
161 | ||
dda64731 PH |
162 | bool can_generate_overflow_checks |
163 | = (ctx->in_fn () && !ctx->const_context_p ()) && flag_overflow_checks; | |
164 | if (!can_generate_overflow_checks) | |
9c87dc0a | 165 | { |
f14cbab8 OA |
166 | translated |
167 | = Backend::arithmetic_or_logical_expression (op, lhs, rhs, | |
168 | expr.get_locus ()); | |
dda64731 | 169 | return; |
9c87dc0a | 170 | } |
dda64731 PH |
171 | |
172 | auto receiver_tmp = NULL_TREE; | |
173 | auto receiver | |
174 | = Backend::temporary_variable (ctx->peek_fn ().fndecl, NULL_TREE, | |
175 | TREE_TYPE (lhs), lhs, true, | |
176 | expr.get_locus (), &receiver_tmp); | |
177 | auto check | |
178 | = Backend::arithmetic_or_logical_expression_checked (op, lhs, rhs, | |
179 | expr.get_locus (), | |
180 | receiver); | |
181 | ||
182 | ctx->add_statement (check); | |
183 | translated = receiver->get_tree (expr.get_locus ()); | |
019b2f15 PH |
184 | } |
185 | ||
186 | void | |
187 | CompileExpr::visit (HIR::CompoundAssignmentExpr &expr) | |
188 | { | |
189 | auto op = expr.get_expr_type (); | |
c29a3bc9 PEP |
190 | auto lhs = CompileExpr::Compile (expr.get_lhs (), ctx); |
191 | auto rhs = CompileExpr::Compile (expr.get_rhs (), ctx); | |
019b2f15 PH |
192 | |
193 | // this might be an operator overload situation lets check | |
194 | TyTy::FnType *fntype; | |
195 | bool is_op_overload = ctx->get_tyctx ()->lookup_operator_overload ( | |
196 | expr.get_mappings ().get_hirid (), &fntype); | |
197 | if (is_op_overload) | |
198 | { | |
bf6d216f AC |
199 | auto lang_item_type = LangItem::CompoundAssignmentOperatorToLangItem ( |
200 | expr.get_expr_type ()); | |
019b2f15 PH |
201 | auto compound_assignment |
202 | = resolve_operator_overload (lang_item_type, expr, lhs, rhs, | |
c29a3bc9 | 203 | expr.get_lhs (), expr.get_rhs ()); |
019b2f15 PH |
204 | ctx->add_statement (compound_assignment); |
205 | ||
206 | return; | |
207 | } | |
208 | ||
9c87dc0a AC |
209 | if (ctx->in_fn () && !ctx->const_context_p ()) |
210 | { | |
211 | auto tmp = NULL_TREE; | |
212 | auto receiver | |
f14cbab8 OA |
213 | = Backend::temporary_variable (ctx->peek_fn ().fndecl, NULL_TREE, |
214 | TREE_TYPE (lhs), lhs, true, | |
215 | expr.get_locus (), &tmp); | |
9c87dc0a | 216 | auto check |
f14cbab8 OA |
217 | = Backend::arithmetic_or_logical_expression_checked (op, lhs, rhs, |
218 | expr.get_locus (), | |
219 | receiver); | |
9c87dc0a AC |
220 | ctx->add_statement (check); |
221 | ||
f14cbab8 OA |
222 | translated |
223 | = Backend::assignment_statement (lhs, | |
224 | receiver->get_tree (expr.get_locus ()), | |
225 | expr.get_locus ()); | |
9c87dc0a AC |
226 | } |
227 | else | |
228 | { | |
f14cbab8 OA |
229 | translated |
230 | = Backend::arithmetic_or_logical_expression (op, lhs, rhs, | |
231 | expr.get_locus ()); | |
9c87dc0a | 232 | } |
019b2f15 PH |
233 | } |
234 | ||
235 | void | |
236 | CompileExpr::visit (HIR::NegationExpr &expr) | |
237 | { | |
238 | auto op = expr.get_expr_type (); | |
5db515e5 | 239 | |
c29a3bc9 | 240 | auto &literal_expr = expr.get_expr (); |
8ca55013 J |
241 | |
242 | // If it's a negated integer/float literal, we can return early | |
5db515e5 | 243 | if (op == NegationOperator::NEGATE |
c29a3bc9 | 244 | && literal_expr.get_expression_type () == HIR::Expr::ExprType::Lit) |
5db515e5 | 245 | { |
c29a3bc9 PEP |
246 | auto &new_literal_expr = static_cast<HIR::LiteralExpr &> (literal_expr); |
247 | auto lit_type = new_literal_expr.get_lit_type (); | |
5db515e5 J |
248 | if (lit_type == HIR::Literal::LitType::INT |
249 | || lit_type == HIR::Literal::LitType::FLOAT) | |
250 | { | |
c29a3bc9 | 251 | new_literal_expr.set_negative (); |
8ca55013 J |
252 | translated = CompileExpr::Compile (literal_expr, ctx); |
253 | return; | |
5db515e5 J |
254 | } |
255 | } | |
5db515e5 | 256 | |
8ca55013 | 257 | auto negated_expr = CompileExpr::Compile (literal_expr, ctx); |
019b2f15 PH |
258 | auto location = expr.get_locus (); |
259 | ||
260 | // this might be an operator overload situation lets check | |
261 | TyTy::FnType *fntype; | |
262 | bool is_op_overload = ctx->get_tyctx ()->lookup_operator_overload ( | |
263 | expr.get_mappings ().get_hirid (), &fntype); | |
264 | if (is_op_overload) | |
265 | { | |
bf6d216f | 266 | auto lang_item_type = LangItem::NegationOperatorToLangItem (op); |
019b2f15 PH |
267 | translated |
268 | = resolve_operator_overload (lang_item_type, expr, negated_expr, | |
c29a3bc9 | 269 | nullptr, expr.get_expr (), tl::nullopt); |
019b2f15 PH |
270 | return; |
271 | } | |
272 | ||
f14cbab8 | 273 | translated = Backend::negation_expression (op, negated_expr, location); |
019b2f15 PH |
274 | } |
275 | ||
276 | void | |
277 | CompileExpr::visit (HIR::ComparisonExpr &expr) | |
278 | { | |
279 | auto op = expr.get_expr_type (); | |
c29a3bc9 PEP |
280 | auto lhs = CompileExpr::Compile (expr.get_lhs (), ctx); |
281 | auto rhs = CompileExpr::Compile (expr.get_rhs (), ctx); | |
019b2f15 PH |
282 | auto location = expr.get_locus (); |
283 | ||
ef4028cd PH |
284 | // this might be an operator overload situation lets check |
285 | TyTy::FnType *fntype; | |
286 | bool is_op_overload = ctx->get_tyctx ()->lookup_operator_overload ( | |
287 | expr.get_mappings ().get_hirid (), &fntype); | |
288 | if (is_op_overload) | |
289 | { | |
290 | auto seg_name = LangItem::ComparisonToSegment (expr.get_expr_type ()); | |
291 | auto segment = HIR::PathIdentSegment (seg_name); | |
292 | auto lang_item_type | |
293 | = LangItem::ComparisonToLangItem (expr.get_expr_type ()); | |
294 | ||
295 | rhs = address_expression (rhs, EXPR_LOCATION (rhs)); | |
296 | ||
297 | translated = resolve_operator_overload ( | |
298 | lang_item_type, expr, lhs, rhs, expr.get_lhs (), | |
299 | tl::optional<std::reference_wrapper<HIR::Expr>> (expr.get_rhs ()), | |
300 | segment); | |
301 | return; | |
302 | } | |
303 | ||
f14cbab8 | 304 | translated = Backend::comparison_expression (op, lhs, rhs, location); |
019b2f15 PH |
305 | } |
306 | ||
307 | void | |
308 | CompileExpr::visit (HIR::LazyBooleanExpr &expr) | |
309 | { | |
310 | auto op = expr.get_expr_type (); | |
c29a3bc9 PEP |
311 | auto lhs = CompileExpr::Compile (expr.get_lhs (), ctx); |
312 | auto rhs = CompileExpr::Compile (expr.get_rhs (), ctx); | |
019b2f15 PH |
313 | auto location = expr.get_locus (); |
314 | ||
f14cbab8 | 315 | translated = Backend::lazy_boolean_expression (op, lhs, rhs, location); |
019b2f15 PH |
316 | } |
317 | ||
318 | void | |
319 | CompileExpr::visit (HIR::TypeCastExpr &expr) | |
320 | { | |
321 | TyTy::BaseType *type_to_cast_to_ty = nullptr; | |
322 | if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (), | |
323 | &type_to_cast_to_ty)) | |
324 | { | |
325 | translated = error_mark_node; | |
326 | return; | |
327 | } | |
328 | ||
329 | TyTy::BaseType *casted_tyty = nullptr; | |
330 | if (!ctx->get_tyctx ()->lookup_type ( | |
c29a3bc9 | 331 | expr.get_casted_expr ().get_mappings ().get_hirid (), &casted_tyty)) |
019b2f15 PH |
332 | { |
333 | translated = error_mark_node; | |
334 | return; | |
335 | } | |
336 | ||
337 | auto type_to_cast_to = TyTyResolveCompile::compile (ctx, type_to_cast_to_ty); | |
c29a3bc9 | 338 | auto casted_expr = CompileExpr::Compile (expr.get_casted_expr (), ctx); |
019b2f15 PH |
339 | |
340 | std::vector<Resolver::Adjustment> *adjustments = nullptr; | |
341 | bool ok = ctx->get_tyctx ()->lookup_cast_autoderef_mappings ( | |
342 | expr.get_mappings ().get_hirid (), &adjustments); | |
343 | if (ok) | |
344 | { | |
345 | casted_expr | |
346 | = resolve_adjustements (*adjustments, casted_expr, expr.get_locus ()); | |
347 | } | |
348 | ||
349 | translated | |
350 | = type_cast_expression (type_to_cast_to, casted_expr, expr.get_locus ()); | |
351 | } | |
352 | ||
353 | void | |
354 | CompileExpr::visit (HIR::IfExpr &expr) | |
355 | { | |
356 | auto stmt = CompileConditionalBlocks::compile (&expr, ctx, nullptr); | |
357 | ctx->add_statement (stmt); | |
358 | } | |
359 | ||
51f430a4 | 360 | void |
361 | CompileExpr::visit (HIR::InlineAsm &expr) | |
12703f67 | 362 | { |
f4f546c9 | 363 | CompileAsm asm_codegen (ctx); |
364 | ctx->add_statement (asm_codegen.tree_codegen_asm (expr)); | |
d7e88ed1 | 365 | // translated = build_asm_expr (0, NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE, |
366 | // NULL_TREE, true, true); | |
367 | // CompileAsm::asm_build_expr (expr); | |
12703f67 | 368 | } |
51f430a4 | 369 | |
7f3050bd PEP |
370 | void |
371 | CompileExpr::visit (HIR::LlvmInlineAsm &expr) | |
372 | { | |
373 | CompileLlvmAsm asm_codegen (ctx); | |
374 | ctx->add_statement (asm_codegen.tree_codegen_asm (expr)); | |
375 | } | |
376 | ||
019b2f15 PH |
377 | void |
378 | CompileExpr::visit (HIR::IfExprConseqElse &expr) | |
019b2f15 PH |
379 | { |
380 | TyTy::BaseType *if_type = nullptr; | |
381 | if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (), | |
382 | &if_type)) | |
383 | { | |
384 | rust_error_at (expr.get_locus (), | |
385 | "failed to lookup type of IfExprConseqElse"); | |
386 | return; | |
387 | } | |
388 | ||
389 | Bvariable *tmp = NULL; | |
cf046027 PH |
390 | fncontext fnctx = ctx->peek_fn (); |
391 | tree enclosing_scope = ctx->peek_enclosing_scope (); | |
392 | tree block_type = TyTyResolveCompile::compile (ctx, if_type); | |
019b2f15 | 393 | |
cf046027 PH |
394 | bool is_address_taken = false; |
395 | tree ret_var_stmt = nullptr; | |
f14cbab8 OA |
396 | tmp = Backend::temporary_variable (fnctx.fndecl, enclosing_scope, block_type, |
397 | NULL, is_address_taken, expr.get_locus (), | |
398 | &ret_var_stmt); | |
cf046027 | 399 | ctx->add_statement (ret_var_stmt); |
019b2f15 PH |
400 | |
401 | auto stmt = CompileConditionalBlocks::compile (&expr, ctx, tmp); | |
402 | ctx->add_statement (stmt); | |
403 | ||
f14cbab8 | 404 | translated = Backend::var_expression (tmp, expr.get_locus ()); |
019b2f15 PH |
405 | } |
406 | ||
407 | void | |
408 | CompileExpr::visit (HIR::BlockExpr &expr) | |
409 | { | |
4331ce69 JD |
410 | if (expr.has_label ()) |
411 | { | |
412 | rust_error_at (expr.get_locus (), "labeled blocks are not supported"); | |
413 | return; | |
414 | } | |
415 | ||
019b2f15 PH |
416 | TyTy::BaseType *block_tyty = nullptr; |
417 | if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (), | |
418 | &block_tyty)) | |
419 | { | |
420 | rust_error_at (expr.get_locus (), "failed to lookup type of BlockExpr"); | |
421 | return; | |
422 | } | |
423 | ||
424 | Bvariable *tmp = NULL; | |
cf046027 PH |
425 | fncontext fnctx = ctx->peek_fn (); |
426 | tree enclosing_scope = ctx->peek_enclosing_scope (); | |
427 | tree block_type = TyTyResolveCompile::compile (ctx, block_tyty); | |
019b2f15 | 428 | |
cf046027 PH |
429 | bool is_address_taken = false; |
430 | tree ret_var_stmt = nullptr; | |
f14cbab8 OA |
431 | tmp = Backend::temporary_variable (fnctx.fndecl, enclosing_scope, block_type, |
432 | NULL, is_address_taken, expr.get_locus (), | |
433 | &ret_var_stmt); | |
cf046027 | 434 | ctx->add_statement (ret_var_stmt); |
019b2f15 | 435 | |
c29a3bc9 | 436 | auto block_stmt = CompileBlock::compile (expr, ctx, tmp); |
019b2f15 PH |
437 | rust_assert (TREE_CODE (block_stmt) == BIND_EXPR); |
438 | ctx->add_statement (block_stmt); | |
439 | ||
f14cbab8 | 440 | translated = Backend::var_expression (tmp, expr.get_locus ()); |
019b2f15 PH |
441 | } |
442 | ||
443 | void | |
444 | CompileExpr::visit (HIR::UnsafeBlockExpr &expr) | |
445 | { | |
c29a3bc9 | 446 | expr.get_block_expr ().accept_vis (*this); |
019b2f15 PH |
447 | } |
448 | ||
449 | void | |
450 | CompileExpr::visit (HIR::StructExprStruct &struct_expr) | |
451 | { | |
452 | TyTy::BaseType *tyty = nullptr; | |
453 | if (!ctx->get_tyctx ()->lookup_type (struct_expr.get_mappings ().get_hirid (), | |
454 | &tyty)) | |
455 | { | |
456 | rust_error_at (struct_expr.get_locus (), "unknown type"); | |
457 | return; | |
458 | } | |
459 | ||
460 | rust_assert (tyty->is_unit ()); | |
40b40970 | 461 | translated = unit_expression (struct_expr.get_locus ()); |
019b2f15 PH |
462 | } |
463 | ||
464 | void | |
465 | CompileExpr::visit (HIR::StructExprStructFields &struct_expr) | |
466 | { | |
467 | TyTy::BaseType *tyty = nullptr; | |
468 | if (!ctx->get_tyctx ()->lookup_type (struct_expr.get_mappings ().get_hirid (), | |
469 | &tyty)) | |
470 | { | |
471 | rust_error_at (struct_expr.get_locus (), "unknown type"); | |
472 | return; | |
473 | } | |
474 | ||
475 | // it must be an ADT | |
476 | rust_assert (tyty->get_kind () == TyTy::TypeKind::ADT); | |
477 | TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (tyty); | |
478 | ||
479 | // what variant is it? | |
480 | int union_disriminator = struct_expr.union_index; | |
481 | TyTy::VariantDef *variant = nullptr; | |
482 | if (!adt->is_enum ()) | |
483 | { | |
484 | rust_assert (adt->number_of_variants () == 1); | |
485 | variant = adt->get_variants ().at (0); | |
486 | } | |
487 | else | |
488 | { | |
489 | HirId variant_id; | |
490 | bool ok = ctx->get_tyctx ()->lookup_variant_definition ( | |
491 | struct_expr.get_struct_name ().get_mappings ().get_hirid (), | |
492 | &variant_id); | |
493 | rust_assert (ok); | |
494 | ||
495 | ok | |
496 | = adt->lookup_variant_by_id (variant_id, &variant, &union_disriminator); | |
497 | rust_assert (ok); | |
498 | } | |
499 | ||
500 | // compile it | |
501 | tree compiled_adt_type = TyTyResolveCompile::compile (ctx, tyty); | |
502 | ||
503 | std::vector<tree> arguments; | |
504 | if (adt->is_union ()) | |
505 | { | |
506 | rust_assert (struct_expr.get_fields ().size () == 1); | |
507 | ||
508 | // assignments are coercion sites so lets convert the rvalue if | |
509 | // necessary | |
510 | auto respective_field = variant->get_field_at_index (union_disriminator); | |
511 | auto expected = respective_field->get_field_type (); | |
512 | ||
513 | // process arguments | |
514 | auto &argument = struct_expr.get_fields ().at (0); | |
515 | auto lvalue_locus | |
fd788dd5 | 516 | = ctx->get_mappings ().lookup_location (expected->get_ty_ref ()); |
019b2f15 | 517 | auto rvalue_locus = argument->get_locus (); |
c29a3bc9 | 518 | auto rvalue = CompileStructExprField::Compile (*argument, ctx); |
019b2f15 PH |
519 | |
520 | TyTy::BaseType *actual = nullptr; | |
521 | bool ok = ctx->get_tyctx ()->lookup_type ( | |
522 | argument->get_mappings ().get_hirid (), &actual); | |
523 | ||
524 | if (ok) | |
525 | { | |
526 | rvalue | |
527 | = coercion_site (argument->get_mappings ().get_hirid (), rvalue, | |
528 | actual, expected, lvalue_locus, rvalue_locus); | |
529 | } | |
530 | ||
531 | // add it to the list | |
532 | arguments.push_back (rvalue); | |
533 | } | |
534 | else | |
535 | { | |
536 | // this assumes all fields are in order from type resolution and if a | |
b9a046cf | 537 | // base struct was specified those fields are filed via accessors |
019b2f15 PH |
538 | for (size_t i = 0; i < struct_expr.get_fields ().size (); i++) |
539 | { | |
540 | // assignments are coercion sites so lets convert the rvalue if | |
541 | // necessary | |
542 | auto respective_field = variant->get_field_at_index (i); | |
543 | auto expected = respective_field->get_field_type (); | |
544 | ||
545 | // process arguments | |
546 | auto &argument = struct_expr.get_fields ().at (i); | |
547 | auto lvalue_locus | |
fd788dd5 | 548 | = ctx->get_mappings ().lookup_location (expected->get_ty_ref ()); |
019b2f15 | 549 | auto rvalue_locus = argument->get_locus (); |
c29a3bc9 | 550 | auto rvalue = CompileStructExprField::Compile (*argument, ctx); |
019b2f15 PH |
551 | |
552 | TyTy::BaseType *actual = nullptr; | |
553 | bool ok = ctx->get_tyctx ()->lookup_type ( | |
554 | argument->get_mappings ().get_hirid (), &actual); | |
555 | ||
556 | // coerce it if required/possible see | |
557 | // compile/torture/struct_base_init_1.rs | |
558 | if (ok) | |
559 | { | |
560 | rvalue | |
561 | = coercion_site (argument->get_mappings ().get_hirid (), rvalue, | |
562 | actual, expected, lvalue_locus, rvalue_locus); | |
563 | } | |
564 | ||
565 | // add it to the list | |
566 | arguments.push_back (rvalue); | |
567 | } | |
568 | } | |
569 | ||
f821a513 | 570 | if (!adt->is_enum ()) |
019b2f15 | 571 | { |
f821a513 PH |
572 | translated |
573 | = Backend::constructor_expression (compiled_adt_type, adt->is_enum (), | |
574 | arguments, union_disriminator, | |
575 | struct_expr.get_locus ()); | |
576 | return; | |
019b2f15 | 577 | } |
f821a513 PH |
578 | |
579 | HIR::Expr &discrim_expr = variant->get_discriminant (); | |
580 | tree discrim_expr_node = CompileExpr::Compile (discrim_expr, ctx); | |
581 | tree folded_discrim_expr = fold_expr (discrim_expr_node); | |
582 | tree qualifier = folded_discrim_expr; | |
583 | ||
584 | tree enum_root_files = TYPE_FIELDS (compiled_adt_type); | |
585 | tree payload_root = DECL_CHAIN (enum_root_files); | |
586 | ||
587 | tree payload = Backend::constructor_expression (TREE_TYPE (payload_root), | |
588 | adt->is_enum (), arguments, | |
589 | union_disriminator, | |
590 | struct_expr.get_locus ()); | |
591 | ||
592 | std::vector<tree> ctor_arguments = {qualifier, payload}; | |
019b2f15 | 593 | |
f14cbab8 | 594 | translated |
f821a513 | 595 | = Backend::constructor_expression (compiled_adt_type, 0, ctor_arguments, -1, |
f14cbab8 | 596 | struct_expr.get_locus ()); |
019b2f15 PH |
597 | } |
598 | ||
599 | void | |
600 | CompileExpr::visit (HIR::GroupedExpr &expr) | |
601 | { | |
c29a3bc9 | 602 | translated = CompileExpr::Compile (expr.get_expr_in_parens (), ctx); |
019b2f15 PH |
603 | } |
604 | ||
605 | void | |
606 | CompileExpr::visit (HIR::FieldAccessExpr &expr) | |
607 | { | |
c29a3bc9 | 608 | HIR::Expr &receiver_expr = expr.get_receiver_expr (); |
019b2f15 PH |
609 | tree receiver_ref = CompileExpr::Compile (receiver_expr, ctx); |
610 | ||
611 | // resolve the receiver back to ADT type | |
612 | TyTy::BaseType *receiver = nullptr; | |
613 | if (!ctx->get_tyctx ()->lookup_type ( | |
c29a3bc9 | 614 | expr.get_receiver_expr ().get_mappings ().get_hirid (), &receiver)) |
019b2f15 | 615 | { |
c29a3bc9 | 616 | rust_error_at (expr.get_receiver_expr ().get_locus (), |
019b2f15 PH |
617 | "unresolved type for receiver"); |
618 | return; | |
619 | } | |
620 | ||
621 | size_t field_index = 0; | |
622 | if (receiver->get_kind () == TyTy::TypeKind::ADT) | |
623 | { | |
624 | TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (receiver); | |
625 | rust_assert (!adt->is_enum ()); | |
626 | rust_assert (adt->number_of_variants () == 1); | |
627 | ||
628 | TyTy::VariantDef *variant = adt->get_variants ().at (0); | |
fcb228d1 PEP |
629 | bool ok = variant->lookup_field (expr.get_field_name ().as_string (), |
630 | nullptr, &field_index); | |
019b2f15 PH |
631 | rust_assert (ok); |
632 | } | |
633 | else if (receiver->get_kind () == TyTy::TypeKind::REF) | |
634 | { | |
635 | TyTy::ReferenceType *r = static_cast<TyTy::ReferenceType *> (receiver); | |
636 | TyTy::BaseType *b = r->get_base (); | |
637 | rust_assert (b->get_kind () == TyTy::TypeKind::ADT); | |
638 | ||
639 | TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (b); | |
640 | rust_assert (!adt->is_enum ()); | |
641 | rust_assert (adt->number_of_variants () == 1); | |
642 | ||
643 | TyTy::VariantDef *variant = adt->get_variants ().at (0); | |
fcb228d1 PEP |
644 | bool ok = variant->lookup_field (expr.get_field_name ().as_string (), |
645 | nullptr, &field_index); | |
019b2f15 PH |
646 | rust_assert (ok); |
647 | ||
648 | tree indirect = indirect_expression (receiver_ref, expr.get_locus ()); | |
649 | receiver_ref = indirect; | |
650 | } | |
651 | ||
f14cbab8 OA |
652 | translated = Backend::struct_field_expression (receiver_ref, field_index, |
653 | expr.get_locus ()); | |
019b2f15 PH |
654 | } |
655 | ||
656 | void | |
657 | CompileExpr::visit (HIR::QualifiedPathInExpression &expr) | |
658 | { | |
659 | translated = ResolvePathRef::Compile (expr, ctx); | |
660 | } | |
661 | ||
662 | void | |
663 | CompileExpr::visit (HIR::PathInExpression &expr) | |
664 | { | |
665 | translated = ResolvePathRef::Compile (expr, ctx); | |
666 | } | |
667 | ||
668 | void | |
669 | CompileExpr::visit (HIR::LoopExpr &expr) | |
670 | { | |
671 | TyTy::BaseType *block_tyty = nullptr; | |
672 | if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (), | |
673 | &block_tyty)) | |
674 | { | |
675 | rust_error_at (expr.get_locus (), "failed to lookup type of BlockExpr"); | |
676 | return; | |
677 | } | |
678 | ||
679 | fncontext fnctx = ctx->peek_fn (); | |
680 | tree enclosing_scope = ctx->peek_enclosing_scope (); | |
681 | tree block_type = TyTyResolveCompile::compile (ctx, block_tyty); | |
682 | ||
683 | bool is_address_taken = false; | |
684 | tree ret_var_stmt = NULL_TREE; | |
f14cbab8 OA |
685 | Bvariable *tmp |
686 | = Backend::temporary_variable (fnctx.fndecl, enclosing_scope, block_type, | |
687 | NULL, is_address_taken, expr.get_locus (), | |
688 | &ret_var_stmt); | |
019b2f15 PH |
689 | ctx->add_statement (ret_var_stmt); |
690 | ctx->push_loop_context (tmp); | |
691 | ||
692 | if (expr.has_loop_label ()) | |
693 | { | |
694 | HIR::LoopLabel &loop_label = expr.get_loop_label (); | |
695 | tree label | |
f14cbab8 OA |
696 | = Backend::label (fnctx.fndecl, loop_label.get_lifetime ().get_name (), |
697 | loop_label.get_locus ()); | |
698 | tree label_decl = Backend::label_definition_statement (label); | |
019b2f15 PH |
699 | ctx->add_statement (label_decl); |
700 | ctx->insert_label_decl ( | |
701 | loop_label.get_lifetime ().get_mappings ().get_hirid (), label); | |
702 | } | |
703 | ||
f14cbab8 | 704 | tree loop_begin_label = Backend::label (fnctx.fndecl, "", expr.get_locus ()); |
019b2f15 | 705 | tree loop_begin_label_decl |
f14cbab8 | 706 | = Backend::label_definition_statement (loop_begin_label); |
019b2f15 PH |
707 | ctx->add_statement (loop_begin_label_decl); |
708 | ctx->push_loop_begin_label (loop_begin_label); | |
709 | ||
710 | tree code_block | |
c29a3bc9 | 711 | = CompileBlock::compile (expr.get_loop_block (), ctx, nullptr); |
f14cbab8 | 712 | tree loop_expr = Backend::loop_expression (code_block, expr.get_locus ()); |
019b2f15 PH |
713 | ctx->add_statement (loop_expr); |
714 | ||
715 | ctx->pop_loop_context (); | |
f14cbab8 | 716 | translated = Backend::var_expression (tmp, expr.get_locus ()); |
019b2f15 PH |
717 | |
718 | ctx->pop_loop_begin_label (); | |
719 | } | |
720 | ||
721 | void | |
722 | CompileExpr::visit (HIR::WhileLoopExpr &expr) | |
723 | { | |
724 | fncontext fnctx = ctx->peek_fn (); | |
725 | if (expr.has_loop_label ()) | |
726 | { | |
727 | HIR::LoopLabel &loop_label = expr.get_loop_label (); | |
728 | tree label | |
f14cbab8 OA |
729 | = Backend::label (fnctx.fndecl, loop_label.get_lifetime ().get_name (), |
730 | loop_label.get_locus ()); | |
731 | tree label_decl = Backend::label_definition_statement (label); | |
019b2f15 PH |
732 | ctx->add_statement (label_decl); |
733 | ctx->insert_label_decl ( | |
734 | loop_label.get_lifetime ().get_mappings ().get_hirid (), label); | |
735 | } | |
736 | ||
737 | std::vector<Bvariable *> locals; | |
c29a3bc9 PEP |
738 | location_t start_location = expr.get_loop_block ().get_locus (); |
739 | location_t end_location = expr.get_loop_block ().get_locus (); // FIXME | |
019b2f15 PH |
740 | |
741 | tree enclosing_scope = ctx->peek_enclosing_scope (); | |
f14cbab8 OA |
742 | tree loop_block = Backend::block (fnctx.fndecl, enclosing_scope, locals, |
743 | start_location, end_location); | |
019b2f15 PH |
744 | ctx->push_block (loop_block); |
745 | ||
f14cbab8 | 746 | tree loop_begin_label = Backend::label (fnctx.fndecl, "", expr.get_locus ()); |
019b2f15 | 747 | tree loop_begin_label_decl |
f14cbab8 | 748 | = Backend::label_definition_statement (loop_begin_label); |
019b2f15 PH |
749 | ctx->add_statement (loop_begin_label_decl); |
750 | ctx->push_loop_begin_label (loop_begin_label); | |
751 | ||
c29a3bc9 | 752 | tree condition = CompileExpr::Compile (expr.get_predicate_expr (), ctx); |
d8a697a6 OA |
753 | tree exit_condition = fold_build1_loc (expr.get_locus (), TRUTH_NOT_EXPR, |
754 | boolean_type_node, condition); | |
f14cbab8 | 755 | tree exit_expr = Backend::exit_expression (exit_condition, expr.get_locus ()); |
019b2f15 PH |
756 | ctx->add_statement (exit_expr); |
757 | ||
758 | tree code_block_stmt | |
c29a3bc9 | 759 | = CompileBlock::compile (expr.get_loop_block (), ctx, nullptr); |
019b2f15 PH |
760 | rust_assert (TREE_CODE (code_block_stmt) == BIND_EXPR); |
761 | ctx->add_statement (code_block_stmt); | |
762 | ||
763 | ctx->pop_loop_begin_label (); | |
764 | ctx->pop_block (); | |
765 | ||
f14cbab8 | 766 | tree loop_expr = Backend::loop_expression (loop_block, expr.get_locus ()); |
019b2f15 PH |
767 | ctx->add_statement (loop_expr); |
768 | } | |
769 | ||
770 | void | |
771 | CompileExpr::visit (HIR::BreakExpr &expr) | |
772 | { | |
773 | if (expr.has_break_expr ()) | |
774 | { | |
c29a3bc9 | 775 | tree compiled_expr = CompileExpr::Compile (expr.get_expr (), ctx); |
019b2f15 PH |
776 | |
777 | Bvariable *loop_result_holder = ctx->peek_loop_context (); | |
778 | tree result_reference | |
f14cbab8 | 779 | = Backend::var_expression (loop_result_holder, |
c29a3bc9 | 780 | expr.get_expr ().get_locus ()); |
019b2f15 PH |
781 | |
782 | tree assignment | |
f14cbab8 OA |
783 | = Backend::assignment_statement (result_reference, compiled_expr, |
784 | expr.get_locus ()); | |
019b2f15 PH |
785 | ctx->add_statement (assignment); |
786 | } | |
787 | ||
788 | if (expr.has_label ()) | |
789 | { | |
790 | NodeId resolved_node_id = UNKNOWN_NODEID; | |
15b1c031 OA |
791 | if (flag_name_resolution_2_0) |
792 | { | |
793 | auto &nr_ctx | |
794 | = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); | |
795 | ||
796 | if (auto id | |
797 | = nr_ctx.lookup (expr.get_label ().get_mappings ().get_nodeid ())) | |
798 | resolved_node_id = *id; | |
799 | } | |
800 | else | |
801 | { | |
802 | NodeId tmp = UNKNOWN_NODEID; | |
803 | if (ctx->get_resolver ()->lookup_resolved_label ( | |
804 | expr.get_label ().get_mappings ().get_nodeid (), &tmp)) | |
805 | resolved_node_id = tmp; | |
806 | } | |
807 | ||
808 | if (resolved_node_id == UNKNOWN_NODEID) | |
019b2f15 PH |
809 | { |
810 | rust_error_at ( | |
811 | expr.get_label ().get_locus (), | |
812 | "failed to resolve compiled label for label %s", | |
813 | expr.get_label ().get_mappings ().as_string ().c_str ()); | |
814 | return; | |
815 | } | |
816 | ||
709371a1 PEP |
817 | tl::optional<HirId> hid |
818 | = ctx->get_mappings ().lookup_node_to_hir (resolved_node_id); | |
819 | if (!hid.has_value ()) | |
019b2f15 PH |
820 | { |
821 | rust_fatal_error (expr.get_locus (), "reverse lookup label failure"); | |
822 | return; | |
823 | } | |
709371a1 | 824 | auto ref = hid.value (); |
019b2f15 PH |
825 | |
826 | tree label = NULL_TREE; | |
827 | if (!ctx->lookup_label_decl (ref, &label)) | |
828 | { | |
829 | rust_error_at (expr.get_label ().get_locus (), | |
830 | "failed to lookup compiled label"); | |
831 | return; | |
832 | } | |
833 | ||
f14cbab8 | 834 | tree goto_label = Backend::goto_statement (label, expr.get_locus ()); |
019b2f15 PH |
835 | ctx->add_statement (goto_label); |
836 | } | |
837 | else | |
838 | { | |
f14cbab8 OA |
839 | tree exit_expr |
840 | = Backend::exit_expression (Backend::boolean_constant_expression (true), | |
841 | expr.get_locus ()); | |
019b2f15 PH |
842 | ctx->add_statement (exit_expr); |
843 | } | |
844 | } | |
845 | ||
846 | void | |
847 | CompileExpr::visit (HIR::ContinueExpr &expr) | |
848 | { | |
849 | tree label = ctx->peek_loop_begin_label (); | |
850 | if (expr.has_label ()) | |
851 | { | |
852 | NodeId resolved_node_id = UNKNOWN_NODEID; | |
15b1c031 OA |
853 | if (flag_name_resolution_2_0) |
854 | { | |
855 | auto &nr_ctx | |
856 | = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); | |
857 | ||
858 | if (auto id | |
859 | = nr_ctx.lookup (expr.get_label ().get_mappings ().get_nodeid ())) | |
860 | resolved_node_id = *id; | |
861 | } | |
862 | else | |
863 | { | |
864 | NodeId tmp = UNKNOWN_NODEID; | |
865 | ||
866 | if (ctx->get_resolver ()->lookup_resolved_label ( | |
867 | expr.get_label ().get_mappings ().get_nodeid (), &tmp)) | |
868 | resolved_node_id = tmp; | |
869 | } | |
870 | ||
871 | if (resolved_node_id == UNKNOWN_NODEID) | |
019b2f15 PH |
872 | { |
873 | rust_error_at ( | |
874 | expr.get_label ().get_locus (), | |
875 | "failed to resolve compiled label for label %s", | |
876 | expr.get_label ().get_mappings ().as_string ().c_str ()); | |
877 | return; | |
878 | } | |
879 | ||
709371a1 PEP |
880 | tl::optional<HirId> hid |
881 | = ctx->get_mappings ().lookup_node_to_hir (resolved_node_id); | |
882 | if (!hid.has_value ()) | |
019b2f15 PH |
883 | { |
884 | rust_fatal_error (expr.get_locus (), "reverse lookup label failure"); | |
885 | return; | |
886 | } | |
709371a1 | 887 | auto ref = hid.value (); |
019b2f15 PH |
888 | |
889 | if (!ctx->lookup_label_decl (ref, &label)) | |
890 | { | |
891 | rust_error_at (expr.get_label ().get_locus (), | |
892 | "failed to lookup compiled label"); | |
893 | return; | |
894 | } | |
895 | } | |
896 | ||
f14cbab8 | 897 | translated = Backend::goto_statement (label, expr.get_locus ()); |
019b2f15 PH |
898 | } |
899 | ||
900 | void | |
901 | CompileExpr::visit (HIR::BorrowExpr &expr) | |
902 | { | |
c29a3bc9 | 903 | tree main_expr = CompileExpr::Compile (expr.get_expr (), ctx); |
c9600aa5 | 904 | if (RS_DST_FLAG_P (TREE_TYPE (main_expr))) |
019b2f15 PH |
905 | { |
906 | translated = main_expr; | |
907 | return; | |
908 | } | |
909 | ||
910 | TyTy::BaseType *tyty = nullptr; | |
911 | if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (), | |
912 | &tyty)) | |
913 | return; | |
914 | ||
f7fc9043 PH |
915 | tree expected_type = TyTyResolveCompile::compile (ctx, tyty); |
916 | translated = address_expression (main_expr, expr.get_locus (), expected_type); | |
019b2f15 PH |
917 | } |
918 | ||
919 | void | |
920 | CompileExpr::visit (HIR::DereferenceExpr &expr) | |
921 | { | |
922 | TyTy::BaseType *tyty = nullptr; | |
923 | if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (), | |
924 | &tyty)) | |
925 | { | |
926 | rust_fatal_error (expr.get_locus (), | |
927 | "did not resolve type for this TupleExpr"); | |
928 | return; | |
929 | } | |
930 | ||
c29a3bc9 | 931 | tree main_expr = CompileExpr::Compile (expr.get_expr (), ctx); |
019b2f15 PH |
932 | |
933 | // this might be an operator overload situation lets check | |
934 | TyTy::FnType *fntype; | |
935 | bool is_op_overload = ctx->get_tyctx ()->lookup_operator_overload ( | |
936 | expr.get_mappings ().get_hirid (), &fntype); | |
937 | if (is_op_overload) | |
938 | { | |
bf6d216f | 939 | auto lang_item_type = LangItem::Kind::DEREF; |
019b2f15 PH |
940 | tree operator_overload_call |
941 | = resolve_operator_overload (lang_item_type, expr, main_expr, nullptr, | |
c29a3bc9 | 942 | expr.get_expr (), tl::nullopt); |
019b2f15 PH |
943 | |
944 | // rust deref always returns a reference from this overload then we can | |
945 | // actually do the indirection | |
946 | main_expr = operator_overload_call; | |
947 | } | |
948 | ||
949 | tree expected_type = TyTyResolveCompile::compile (ctx, tyty); | |
c9600aa5 | 950 | if (RS_DST_FLAG_P (TREE_TYPE (main_expr)) && RS_DST_FLAG_P (expected_type)) |
019b2f15 PH |
951 | { |
952 | translated = main_expr; | |
953 | return; | |
954 | } | |
955 | ||
956 | translated = indirect_expression (main_expr, expr.get_locus ()); | |
957 | } | |
958 | ||
959 | void | |
960 | CompileExpr::visit (HIR::LiteralExpr &expr) | |
961 | { | |
962 | TyTy::BaseType *tyty = nullptr; | |
963 | if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (), | |
964 | &tyty)) | |
965 | return; | |
966 | ||
967 | switch (expr.get_lit_type ()) | |
968 | { | |
969 | case HIR::Literal::BOOL: | |
970 | translated = compile_bool_literal (expr, tyty); | |
971 | return; | |
972 | ||
973 | case HIR::Literal::INT: | |
974 | translated = compile_integer_literal (expr, tyty); | |
975 | return; | |
976 | ||
977 | case HIR::Literal::FLOAT: | |
978 | translated = compile_float_literal (expr, tyty); | |
979 | return; | |
980 | ||
981 | case HIR::Literal::CHAR: | |
982 | translated = compile_char_literal (expr, tyty); | |
983 | return; | |
984 | ||
985 | case HIR::Literal::BYTE: | |
986 | translated = compile_byte_literal (expr, tyty); | |
987 | return; | |
988 | ||
989 | case HIR::Literal::STRING: | |
990 | translated = compile_string_literal (expr, tyty); | |
991 | return; | |
992 | ||
993 | case HIR::Literal::BYTE_STRING: | |
994 | translated = compile_byte_string_literal (expr, tyty); | |
995 | return; | |
996 | } | |
997 | } | |
998 | ||
999 | void | |
1000 | CompileExpr::visit (HIR::AssignmentExpr &expr) | |
1001 | { | |
c29a3bc9 PEP |
1002 | auto lvalue = CompileExpr::Compile (expr.get_lhs (), ctx); |
1003 | auto rvalue = CompileExpr::Compile (expr.get_rhs (), ctx); | |
019b2f15 PH |
1004 | |
1005 | // assignments are coercion sites so lets convert the rvalue if necessary | |
1006 | TyTy::BaseType *expected = nullptr; | |
1007 | TyTy::BaseType *actual = nullptr; | |
1008 | ||
1009 | bool ok; | |
1010 | ok = ctx->get_tyctx ()->lookup_type ( | |
c29a3bc9 | 1011 | expr.get_lhs ().get_mappings ().get_hirid (), &expected); |
019b2f15 PH |
1012 | rust_assert (ok); |
1013 | ||
1014 | ok = ctx->get_tyctx ()->lookup_type ( | |
c29a3bc9 | 1015 | expr.get_rhs ().get_mappings ().get_hirid (), &actual); |
019b2f15 PH |
1016 | rust_assert (ok); |
1017 | ||
1018 | rvalue = coercion_site (expr.get_mappings ().get_hirid (), rvalue, actual, | |
c29a3bc9 PEP |
1019 | expected, expr.get_lhs ().get_locus (), |
1020 | expr.get_rhs ().get_locus ()); | |
019b2f15 | 1021 | |
c9600aa5 PH |
1022 | // rust_debug_loc (expr.get_locus (), "XXXXXX assignment"); |
1023 | // debug_tree (rvalue); | |
1024 | // debug_tree (lvalue); | |
1025 | ||
019b2f15 | 1026 | tree assignment |
f14cbab8 | 1027 | = Backend::assignment_statement (lvalue, rvalue, expr.get_locus ()); |
019b2f15 PH |
1028 | |
1029 | ctx->add_statement (assignment); | |
1030 | } | |
1031 | ||
019b2f15 PH |
1032 | // Helper for CompileExpr::visit (HIR::MatchExpr). |
1033 | // Check that the scrutinee of EXPR is a valid kind of expression to match on. | |
1034 | // Return the TypeKind of the scrutinee if it is valid, or TyTy::TypeKind::ERROR | |
1035 | // if not. | |
1036 | static TyTy::TypeKind | |
1037 | check_match_scrutinee (HIR::MatchExpr &expr, Context *ctx) | |
1038 | { | |
1039 | TyTy::BaseType *scrutinee_expr_tyty = nullptr; | |
1040 | if (!ctx->get_tyctx ()->lookup_type ( | |
c29a3bc9 | 1041 | expr.get_scrutinee_expr ().get_mappings ().get_hirid (), |
019b2f15 PH |
1042 | &scrutinee_expr_tyty)) |
1043 | { | |
1044 | return TyTy::TypeKind::ERROR; | |
1045 | } | |
1046 | ||
1047 | TyTy::TypeKind scrutinee_kind = scrutinee_expr_tyty->get_kind (); | |
019b2f15 | 1048 | |
e4a92d70 | 1049 | if (scrutinee_kind == TyTy::TypeKind::FLOAT) |
019b2f15 PH |
1050 | { |
1051 | // FIXME: CASE_LABEL_EXPR does not support floating point types. | |
1052 | // Find another way to compile these. | |
1053 | rust_sorry_at (expr.get_locus (), | |
1054 | "match on floating-point types is not yet supported"); | |
1055 | } | |
1056 | ||
1057 | TyTy::BaseType *expr_tyty = nullptr; | |
1058 | if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (), | |
1059 | &expr_tyty)) | |
1060 | { | |
1061 | return TyTy::TypeKind::ERROR; | |
1062 | } | |
1063 | ||
1064 | return scrutinee_kind; | |
1065 | } | |
1066 | ||
1067 | void | |
1068 | CompileExpr::visit (HIR::MatchExpr &expr) | |
1069 | { | |
1070 | // https://gcc.gnu.org/onlinedocs/gccint/Basic-Statements.html#Basic-Statements | |
1071 | // TODO | |
1072 | // SWITCH_ALL_CASES_P is true if the switch includes a default label or the | |
1073 | // case label ranges cover all possible values of the condition expression | |
1074 | ||
019b2f15 PH |
1075 | TyTy::TypeKind scrutinee_kind = check_match_scrutinee (expr, ctx); |
1076 | if (scrutinee_kind == TyTy::TypeKind::ERROR) | |
1077 | { | |
1078 | translated = error_mark_node; | |
1079 | return; | |
1080 | } | |
1081 | ||
1082 | TyTy::BaseType *expr_tyty = nullptr; | |
1083 | if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (), | |
1084 | &expr_tyty)) | |
1085 | { | |
1086 | translated = error_mark_node; | |
1087 | return; | |
1088 | } | |
1089 | ||
e4a92d70 PH |
1090 | // if the result of this expression is meant to be never type then we can |
1091 | // optimise this away but there is the case where match arms resolve to ! | |
1092 | // because of return statements we need to special case this | |
1093 | if (!expr.has_match_arms () && expr_tyty->is<TyTy::NeverType> ()) | |
1094 | { | |
1095 | translated = unit_expression (expr.get_locus ()); | |
1096 | return; | |
1097 | } | |
1098 | ||
019b2f15 PH |
1099 | fncontext fnctx = ctx->peek_fn (); |
1100 | Bvariable *tmp = NULL; | |
cf046027 PH |
1101 | tree enclosing_scope = ctx->peek_enclosing_scope (); |
1102 | tree block_type = TyTyResolveCompile::compile (ctx, expr_tyty); | |
019b2f15 | 1103 | |
cf046027 PH |
1104 | bool is_address_taken = false; |
1105 | tree ret_var_stmt = nullptr; | |
f14cbab8 OA |
1106 | tmp = Backend::temporary_variable (fnctx.fndecl, enclosing_scope, block_type, |
1107 | NULL, is_address_taken, expr.get_locus (), | |
1108 | &ret_var_stmt); | |
cf046027 | 1109 | ctx->add_statement (ret_var_stmt); |
019b2f15 PH |
1110 | |
1111 | // lets compile the scrutinee expression | |
3afb921c | 1112 | tree match_scrutinee_rval |
c29a3bc9 | 1113 | = CompileExpr::Compile (expr.get_scrutinee_expr (), ctx); |
019b2f15 | 1114 | |
f14cbab8 OA |
1115 | Bvariable *match_scrutinee_tmp_var |
1116 | = Backend::temporary_variable (fnctx.fndecl, enclosing_scope, | |
1117 | TREE_TYPE (match_scrutinee_rval), NULL, | |
1118 | is_address_taken, expr.get_locus (), | |
1119 | &ret_var_stmt); | |
3afb921c PH |
1120 | ctx->add_statement (ret_var_stmt); |
1121 | ||
1122 | tree match_scrutinee_expr = match_scrutinee_tmp_var->get_tree ( | |
c29a3bc9 | 1123 | expr.get_scrutinee_expr ().get_locus ()); |
3afb921c PH |
1124 | |
1125 | tree assignment | |
f14cbab8 OA |
1126 | = Backend::assignment_statement (match_scrutinee_expr, match_scrutinee_rval, |
1127 | expr.get_locus ()); | |
3afb921c PH |
1128 | ctx->add_statement (assignment); |
1129 | ||
019b2f15 PH |
1130 | // setup the end label so the cases can exit properly |
1131 | tree fndecl = fnctx.fndecl; | |
1ed62a2b | 1132 | location_t end_label_locus = expr.get_locus (); // FIXME |
019b2f15 | 1133 | tree end_label |
f14cbab8 OA |
1134 | = Backend::label (fndecl, "" /* empty creates an artificial label */, |
1135 | end_label_locus); | |
019b2f15 | 1136 | tree end_label_decl_statement |
f14cbab8 | 1137 | = Backend::label_definition_statement (end_label); |
019b2f15 | 1138 | |
019b2f15 PH |
1139 | for (auto &kase : expr.get_match_cases ()) |
1140 | { | |
1141 | // for now lets just get single pattern's working | |
1142 | HIR::MatchArm &kase_arm = kase.get_arm (); | |
1143 | rust_assert (kase_arm.get_patterns ().size () > 0); | |
1144 | ||
019b2f15 PH |
1145 | for (auto &kase_pattern : kase_arm.get_patterns ()) |
1146 | { | |
da87ef4d OA |
1147 | // setup the match-arm-body-block |
1148 | location_t start_location = UNKNOWN_LOCATION; // FIXME | |
1149 | location_t end_location = UNKNOWN_LOCATION; // FIXME | |
1150 | tree arm_body_block = Backend::block (fndecl, enclosing_scope, {}, | |
1151 | start_location, end_location); | |
1152 | ||
1153 | ctx->push_block (arm_body_block); | |
019b2f15 | 1154 | |
da87ef4d | 1155 | // setup the bindings for the block |
c29a3bc9 PEP |
1156 | CompilePatternBindings::Compile (*kase_pattern, match_scrutinee_expr, |
1157 | ctx); | |
019b2f15 | 1158 | |
da87ef4d OA |
1159 | // compile the expr and setup the assignment if required when tmp != |
1160 | // NULL | |
1161 | location_t arm_locus = kase_arm.get_locus (); | |
c29a3bc9 | 1162 | tree kase_expr_tree = CompileExpr::Compile (kase.get_expr (), ctx); |
da87ef4d | 1163 | tree result_reference = Backend::var_expression (tmp, arm_locus); |
8ce8781f PH |
1164 | |
1165 | TyTy::BaseType *actual = nullptr; | |
1166 | bool ok = ctx->get_tyctx ()->lookup_type ( | |
1167 | kase.get_expr ().get_mappings ().get_hirid (), &actual); | |
1168 | rust_assert (ok); | |
1169 | ||
1170 | tree coerced_result | |
1171 | = coercion_site (kase.get_expr ().get_mappings ().get_hirid (), | |
1172 | kase_expr_tree, actual, expr_tyty, | |
1173 | expr.get_locus (), arm_locus); | |
1174 | ||
da87ef4d | 1175 | tree assignment |
8ce8781f | 1176 | = Backend::assignment_statement (result_reference, coerced_result, |
da87ef4d OA |
1177 | arm_locus); |
1178 | ctx->add_statement (assignment); | |
1179 | ||
1180 | // go to end label | |
1181 | tree goto_end_label | |
1182 | = build1_loc (arm_locus, GOTO_EXPR, void_type_node, end_label); | |
1183 | ctx->add_statement (goto_end_label); | |
1184 | ||
1185 | ctx->pop_block (); | |
1186 | ||
1187 | tree check_expr | |
c29a3bc9 | 1188 | = CompilePatternCheckExpr::Compile (*kase_pattern, |
da87ef4d OA |
1189 | match_scrutinee_expr, ctx); |
1190 | ||
1191 | tree check_stmt | |
1192 | = Backend::if_statement (NULL_TREE, check_expr, arm_body_block, | |
1193 | NULL_TREE, kase_pattern->get_locus ()); | |
1194 | ||
1195 | ctx->add_statement (check_stmt); | |
1196 | } | |
019b2f15 PH |
1197 | } |
1198 | ||
1199 | // setup the switch expression | |
019b2f15 PH |
1200 | ctx->add_statement (end_label_decl_statement); |
1201 | ||
f14cbab8 | 1202 | translated = Backend::var_expression (tmp, expr.get_locus ()); |
019b2f15 PH |
1203 | } |
1204 | ||
1205 | void | |
1206 | CompileExpr::visit (HIR::CallExpr &expr) | |
1207 | { | |
1208 | TyTy::BaseType *tyty = nullptr; | |
1209 | if (!ctx->get_tyctx ()->lookup_type ( | |
c29a3bc9 | 1210 | expr.get_fnexpr ().get_mappings ().get_hirid (), &tyty)) |
019b2f15 PH |
1211 | { |
1212 | rust_error_at (expr.get_locus (), "unknown type"); | |
1213 | return; | |
1214 | } | |
1215 | ||
1216 | // must be a tuple constructor | |
699e7e86 | 1217 | bool is_adt_ctor = tyty->get_kind () == TyTy::TypeKind::ADT; |
019b2f15 PH |
1218 | if (is_adt_ctor) |
1219 | { | |
1220 | rust_assert (tyty->get_kind () == TyTy::TypeKind::ADT); | |
1221 | TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (tyty); | |
1222 | tree compiled_adt_type = TyTyResolveCompile::compile (ctx, tyty); | |
1223 | ||
1224 | // what variant is it? | |
1225 | int union_disriminator = -1; | |
1226 | TyTy::VariantDef *variant = nullptr; | |
1227 | if (!adt->is_enum ()) | |
1228 | { | |
1229 | rust_assert (adt->number_of_variants () == 1); | |
1230 | variant = adt->get_variants ().at (0); | |
1231 | } | |
1232 | else | |
1233 | { | |
1234 | HirId variant_id; | |
1235 | bool ok = ctx->get_tyctx ()->lookup_variant_definition ( | |
c29a3bc9 | 1236 | expr.get_fnexpr ().get_mappings ().get_hirid (), &variant_id); |
019b2f15 PH |
1237 | rust_assert (ok); |
1238 | ||
1239 | ok = adt->lookup_variant_by_id (variant_id, &variant, | |
1240 | &union_disriminator); | |
1241 | rust_assert (ok); | |
1242 | } | |
1243 | ||
1244 | // this assumes all fields are in order from type resolution and if a | |
b9a046cf | 1245 | // base struct was specified those fields are filed via accessors |
019b2f15 | 1246 | std::vector<tree> arguments; |
6246f658 | 1247 | for (size_t i = 0; i < expr.num_params (); i++) |
019b2f15 PH |
1248 | { |
1249 | auto &argument = expr.get_arguments ().at (i); | |
c29a3bc9 | 1250 | auto rvalue = CompileExpr::Compile (*argument, ctx); |
019b2f15 PH |
1251 | |
1252 | // assignments are coercion sites so lets convert the rvalue if | |
1253 | // necessary | |
1254 | auto respective_field = variant->get_field_at_index (i); | |
1255 | auto expected = respective_field->get_field_type (); | |
1256 | ||
1257 | TyTy::BaseType *actual = nullptr; | |
1258 | bool ok = ctx->get_tyctx ()->lookup_type ( | |
1259 | argument->get_mappings ().get_hirid (), &actual); | |
1260 | rust_assert (ok); | |
1261 | ||
1262 | // coerce it if required | |
1ed62a2b | 1263 | location_t lvalue_locus |
fd788dd5 | 1264 | = ctx->get_mappings ().lookup_location (expected->get_ty_ref ()); |
1ed62a2b | 1265 | location_t rvalue_locus = argument->get_locus (); |
019b2f15 PH |
1266 | rvalue |
1267 | = coercion_site (argument->get_mappings ().get_hirid (), rvalue, | |
1268 | actual, expected, lvalue_locus, rvalue_locus); | |
1269 | ||
1270 | // add it to the list | |
1271 | arguments.push_back (rvalue); | |
1272 | } | |
1273 | ||
f821a513 | 1274 | if (!adt->is_enum ()) |
019b2f15 | 1275 | { |
f821a513 PH |
1276 | translated |
1277 | = Backend::constructor_expression (compiled_adt_type, | |
1278 | adt->is_enum (), arguments, | |
1279 | union_disriminator, | |
1280 | expr.get_locus ()); | |
1281 | return; | |
019b2f15 | 1282 | } |
019b2f15 | 1283 | |
f821a513 PH |
1284 | HIR::Expr &discrim_expr = variant->get_discriminant (); |
1285 | tree discrim_expr_node = CompileExpr::Compile (discrim_expr, ctx); | |
1286 | tree folded_discrim_expr = fold_expr (discrim_expr_node); | |
1287 | tree qualifier = folded_discrim_expr; | |
1288 | ||
1289 | tree enum_root_files = TYPE_FIELDS (compiled_adt_type); | |
1290 | tree payload_root = DECL_CHAIN (enum_root_files); | |
1291 | ||
1292 | tree payload | |
1293 | = Backend::constructor_expression (TREE_TYPE (payload_root), true, | |
1294 | {arguments}, union_disriminator, | |
f14cbab8 | 1295 | expr.get_locus ()); |
019b2f15 | 1296 | |
f821a513 PH |
1297 | std::vector<tree> ctor_arguments = {qualifier, payload}; |
1298 | translated = Backend::constructor_expression (compiled_adt_type, false, | |
1299 | ctor_arguments, -1, | |
1300 | expr.get_locus ()); | |
1301 | ||
019b2f15 PH |
1302 | return; |
1303 | } | |
1304 | ||
1305 | auto get_parameter_tyty_at_index | |
1306 | = [] (const TyTy::BaseType *base, size_t index, | |
1307 | TyTy::BaseType **result) -> bool { | |
1308 | bool is_fn = base->get_kind () == TyTy::TypeKind::FNDEF | |
1309 | || base->get_kind () == TyTy::TypeKind::FNPTR; | |
1310 | rust_assert (is_fn); | |
1311 | ||
1312 | if (base->get_kind () == TyTy::TypeKind::FNPTR) | |
1313 | { | |
1314 | const TyTy::FnPtr *fn = static_cast<const TyTy::FnPtr *> (base); | |
14025f73 | 1315 | *result = fn->get_param_type_at (index); |
019b2f15 PH |
1316 | |
1317 | return true; | |
1318 | } | |
1319 | ||
1320 | const TyTy::FnType *fn = static_cast<const TyTy::FnType *> (base); | |
c29a3bc9 | 1321 | auto ¶m = fn->param_at (index); |
d123f43e | 1322 | *result = param.get_type (); |
019b2f15 PH |
1323 | |
1324 | return true; | |
1325 | }; | |
1326 | ||
c29a3bc9 | 1327 | auto fn_address = CompileExpr::Compile (expr.get_fnexpr (), ctx); |
699e7e86 PH |
1328 | |
1329 | // is this a closure call? | |
21d19d2c PH |
1330 | bool possible_trait_call |
1331 | = generate_possible_fn_trait_call (expr, fn_address, &translated); | |
1332 | if (possible_trait_call) | |
1333 | return; | |
699e7e86 | 1334 | |
0a99bfe1 | 1335 | bool is_variadic = false; |
699e7e86 | 1336 | size_t required_num_args = expr.get_arguments ().size (); |
08b78560 | 1337 | |
019b2f15 PH |
1338 | if (tyty->get_kind () == TyTy::TypeKind::FNDEF) |
1339 | { | |
1340 | const TyTy::FnType *fn = static_cast<const TyTy::FnType *> (tyty); | |
1341 | required_num_args = fn->num_params (); | |
08b78560 | 1342 | is_variadic = fn->is_variadic (); |
019b2f15 | 1343 | } |
699e7e86 | 1344 | else if (tyty->get_kind () == TyTy::TypeKind::FNPTR) |
019b2f15 PH |
1345 | { |
1346 | const TyTy::FnPtr *fn = static_cast<const TyTy::FnPtr *> (tyty); | |
1347 | required_num_args = fn->num_params (); | |
1348 | } | |
1349 | ||
1350 | std::vector<tree> args; | |
1351 | for (size_t i = 0; i < expr.get_arguments ().size (); i++) | |
1352 | { | |
1353 | auto &argument = expr.get_arguments ().at (i); | |
c29a3bc9 | 1354 | auto rvalue = CompileExpr::Compile (*argument, ctx); |
019b2f15 | 1355 | |
0a99bfe1 | 1356 | if (is_variadic && i >= required_num_args) |
019b2f15 PH |
1357 | { |
1358 | args.push_back (rvalue); | |
1359 | continue; | |
1360 | } | |
1361 | ||
1362 | // assignments are coercion sites so lets convert the rvalue if | |
1363 | // necessary | |
1364 | bool ok; | |
1365 | TyTy::BaseType *expected = nullptr; | |
1366 | ok = get_parameter_tyty_at_index (tyty, i, &expected); | |
1367 | rust_assert (ok); | |
1368 | ||
1369 | TyTy::BaseType *actual = nullptr; | |
1370 | ok = ctx->get_tyctx ()->lookup_type ( | |
1371 | argument->get_mappings ().get_hirid (), &actual); | |
1372 | rust_assert (ok); | |
1373 | ||
1374 | // coerce it if required | |
1ed62a2b | 1375 | location_t lvalue_locus |
fd788dd5 | 1376 | = ctx->get_mappings ().lookup_location (expected->get_ty_ref ()); |
1ed62a2b | 1377 | location_t rvalue_locus = argument->get_locus (); |
019b2f15 PH |
1378 | rvalue = coercion_site (argument->get_mappings ().get_hirid (), rvalue, |
1379 | actual, expected, lvalue_locus, rvalue_locus); | |
1380 | ||
1381 | // add it to the list | |
1382 | args.push_back (rvalue); | |
1383 | } | |
1384 | ||
699e7e86 | 1385 | // must be a regular call to a function |
f14cbab8 OA |
1386 | translated |
1387 | = Backend::call_expression (fn_address, args, nullptr, expr.get_locus ()); | |
019b2f15 PH |
1388 | } |
1389 | ||
1390 | void | |
1391 | CompileExpr::visit (HIR::MethodCallExpr &expr) | |
1392 | { | |
1393 | // method receiver | |
c29a3bc9 | 1394 | tree self = CompileExpr::Compile (expr.get_receiver (), ctx); |
019b2f15 | 1395 | |
019b2f15 PH |
1396 | // lookup the expected function type |
1397 | TyTy::BaseType *lookup_fntype = nullptr; | |
1398 | bool ok = ctx->get_tyctx ()->lookup_type ( | |
1399 | expr.get_method_name ().get_mappings ().get_hirid (), &lookup_fntype); | |
1400 | rust_assert (ok); | |
1401 | rust_assert (lookup_fntype->get_kind () == TyTy::TypeKind::FNDEF); | |
1402 | TyTy::FnType *fntype = static_cast<TyTy::FnType *> (lookup_fntype); | |
1403 | ||
1404 | TyTy::BaseType *receiver = nullptr; | |
6711c731 PH |
1405 | ok = ctx->get_tyctx ()->lookup_type ( |
1406 | expr.get_receiver ().get_mappings ().get_hirid (), &receiver); | |
019b2f15 PH |
1407 | rust_assert (ok); |
1408 | ||
1409 | bool is_dyn_dispatch | |
1410 | = receiver->get_root ()->get_kind () == TyTy::TypeKind::DYNAMIC; | |
1411 | bool is_generic_receiver = receiver->get_kind () == TyTy::TypeKind::PARAM; | |
1412 | if (is_generic_receiver) | |
1413 | { | |
1414 | TyTy::ParamType *p = static_cast<TyTy::ParamType *> (receiver); | |
1415 | receiver = p->resolve (); | |
1416 | } | |
1417 | ||
1418 | tree fn_expr = error_mark_node; | |
1419 | if (is_dyn_dispatch) | |
1420 | { | |
1421 | const TyTy::DynamicObjectType *dyn | |
1422 | = static_cast<const TyTy::DynamicObjectType *> (receiver->get_root ()); | |
019b2f15 PH |
1423 | fn_expr |
1424 | = get_fn_addr_from_dyn (dyn, receiver, fntype, self, expr.get_locus ()); | |
1425 | self = get_receiver_from_dyn (dyn, receiver, fntype, self, | |
1426 | expr.get_locus ()); | |
1427 | } | |
1428 | else | |
c827177a KP |
1429 | // lookup compiled functions since it may have already been compiled |
1430 | fn_expr = resolve_method_address (fntype, receiver, expr.get_locus ()); | |
019b2f15 PH |
1431 | |
1432 | // lookup the autoderef mappings | |
1433 | HirId autoderef_mappings_id | |
c29a3bc9 | 1434 | = expr.get_receiver ().get_mappings ().get_hirid (); |
019b2f15 PH |
1435 | std::vector<Resolver::Adjustment> *adjustments = nullptr; |
1436 | ok = ctx->get_tyctx ()->lookup_autoderef_mappings (autoderef_mappings_id, | |
1437 | &adjustments); | |
1438 | rust_assert (ok); | |
1439 | ||
1440 | // apply adjustments for the fn call | |
1441 | self = resolve_adjustements (*adjustments, self, | |
c29a3bc9 | 1442 | expr.get_receiver ().get_locus ()); |
019b2f15 PH |
1443 | |
1444 | std::vector<tree> args; | |
1445 | args.push_back (self); // adjusted self | |
1446 | ||
1447 | // normal args | |
1448 | for (size_t i = 0; i < expr.get_arguments ().size (); i++) | |
1449 | { | |
1450 | auto &argument = expr.get_arguments ().at (i); | |
c29a3bc9 | 1451 | auto rvalue = CompileExpr::Compile (*argument, ctx); |
019b2f15 PH |
1452 | |
1453 | // assignments are coercion sites so lets convert the rvalue if | |
1454 | // necessary, offset from the already adjusted implicit self | |
1455 | bool ok; | |
d123f43e | 1456 | TyTy::BaseType *expected = fntype->param_at (i + 1).get_type (); |
019b2f15 PH |
1457 | |
1458 | TyTy::BaseType *actual = nullptr; | |
1459 | ok = ctx->get_tyctx ()->lookup_type ( | |
1460 | argument->get_mappings ().get_hirid (), &actual); | |
1461 | rust_assert (ok); | |
1462 | ||
1463 | // coerce it if required | |
1ed62a2b | 1464 | location_t lvalue_locus |
fd788dd5 | 1465 | = ctx->get_mappings ().lookup_location (expected->get_ty_ref ()); |
1ed62a2b | 1466 | location_t rvalue_locus = argument->get_locus (); |
019b2f15 PH |
1467 | rvalue = coercion_site (argument->get_mappings ().get_hirid (), rvalue, |
1468 | actual, expected, lvalue_locus, rvalue_locus); | |
1469 | ||
1470 | // add it to the list | |
1471 | args.push_back (rvalue); | |
1472 | } | |
1473 | ||
f14cbab8 OA |
1474 | translated |
1475 | = Backend::call_expression (fn_expr, args, nullptr, expr.get_locus ()); | |
019b2f15 PH |
1476 | } |
1477 | ||
1478 | tree | |
1479 | CompileExpr::get_fn_addr_from_dyn (const TyTy::DynamicObjectType *dyn, | |
1480 | TyTy::BaseType *receiver, | |
1481 | TyTy::FnType *fntype, tree receiver_ref, | |
1ed62a2b | 1482 | location_t expr_locus) |
019b2f15 PH |
1483 | { |
1484 | size_t offs = 0; | |
1485 | const Resolver::TraitItemReference *ref = nullptr; | |
1486 | for (auto &bound : dyn->get_object_items ()) | |
1487 | { | |
1488 | const Resolver::TraitItemReference *item = bound.first; | |
1489 | auto t = item->get_tyty (); | |
1490 | rust_assert (t->get_kind () == TyTy::TypeKind::FNDEF); | |
1491 | auto ft = static_cast<TyTy::FnType *> (t); | |
1492 | ||
1493 | if (ft->get_id () == fntype->get_id ()) | |
1494 | { | |
1495 | ref = item; | |
1496 | break; | |
1497 | } | |
1498 | offs++; | |
1499 | } | |
1500 | ||
1501 | if (ref == nullptr) | |
1502 | return error_mark_node; | |
1503 | ||
019b2f15 PH |
1504 | // cast it to the correct fntype |
1505 | tree expected_fntype = TyTyResolveCompile::compile (ctx, fntype, true); | |
1506 | tree idx = build_int_cst (size_type_node, offs); | |
1507 | ||
1508 | tree vtable_ptr | |
f14cbab8 | 1509 | = Backend::struct_field_expression (receiver_ref, 1, expr_locus); |
d8a697a6 OA |
1510 | tree vtable_array_access |
1511 | = build4_loc (expr_locus, ARRAY_REF, TREE_TYPE (TREE_TYPE (vtable_ptr)), | |
1512 | vtable_ptr, idx, NULL_TREE, NULL_TREE); | |
019b2f15 | 1513 | |
d8a697a6 OA |
1514 | tree vcall = build3_loc (expr_locus, OBJ_TYPE_REF, expected_fntype, |
1515 | vtable_array_access, receiver_ref, idx); | |
019b2f15 PH |
1516 | |
1517 | return vcall; | |
1518 | } | |
1519 | ||
1520 | tree | |
1521 | CompileExpr::get_receiver_from_dyn (const TyTy::DynamicObjectType *dyn, | |
1522 | TyTy::BaseType *receiver, | |
1523 | TyTy::FnType *fntype, tree receiver_ref, | |
1ed62a2b | 1524 | location_t expr_locus) |
019b2f15 | 1525 | { |
019b2f15 | 1526 | // access the offs + 1 for the fnptr and offs=0 for the reciever obj |
f14cbab8 | 1527 | return Backend::struct_field_expression (receiver_ref, 0, expr_locus); |
019b2f15 PH |
1528 | } |
1529 | ||
019b2f15 | 1530 | tree |
db179293 PEP |
1531 | CompileExpr::resolve_operator_overload ( |
1532 | LangItem::Kind lang_item_type, HIR::OperatorExprMeta expr, tree lhs, tree rhs, | |
ef4028cd PH |
1533 | HIR::Expr &lhs_expr, tl::optional<std::reference_wrapper<HIR::Expr>> rhs_expr, |
1534 | HIR::PathIdentSegment specified_segment) | |
019b2f15 PH |
1535 | { |
1536 | TyTy::FnType *fntype; | |
1537 | bool is_op_overload = ctx->get_tyctx ()->lookup_operator_overload ( | |
1538 | expr.get_mappings ().get_hirid (), &fntype); | |
1539 | rust_assert (is_op_overload); | |
1540 | ||
019b2f15 | 1541 | TyTy::BaseType *receiver = nullptr; |
e07cb0b0 | 1542 | bool ok |
6711c731 PH |
1543 | = ctx->get_tyctx ()->lookup_type (lhs_expr.get_mappings ().get_hirid (), |
1544 | &receiver); | |
019b2f15 PH |
1545 | rust_assert (ok); |
1546 | ||
1547 | bool is_generic_receiver = receiver->get_kind () == TyTy::TypeKind::PARAM; | |
1548 | if (is_generic_receiver) | |
1549 | { | |
1550 | TyTy::ParamType *p = static_cast<TyTy::ParamType *> (receiver); | |
1551 | receiver = p->resolve (); | |
1552 | } | |
1553 | ||
1554 | // lookup compiled functions since it may have already been compiled | |
ef4028cd PH |
1555 | HIR::PathIdentSegment segment_name |
1556 | = specified_segment.is_error () | |
1557 | ? HIR::PathIdentSegment (LangItem::ToString (lang_item_type)) | |
1558 | : specified_segment; | |
636e9b41 | 1559 | tree fn_expr = resolve_method_address (fntype, receiver, expr.get_locus ()); |
019b2f15 PH |
1560 | |
1561 | // lookup the autoderef mappings | |
1562 | std::vector<Resolver::Adjustment> *adjustments = nullptr; | |
1563 | ok = ctx->get_tyctx ()->lookup_autoderef_mappings ( | |
1564 | expr.get_lvalue_mappings ().get_hirid (), &adjustments); | |
1565 | rust_assert (ok); | |
1566 | ||
1567 | // apply adjustments for the fn call | |
c29a3bc9 | 1568 | tree self = resolve_adjustements (*adjustments, lhs, lhs_expr.get_locus ()); |
019b2f15 PH |
1569 | |
1570 | std::vector<tree> args; | |
1571 | args.push_back (self); // adjusted self | |
1572 | if (rhs != nullptr) // can be null for negation_expr (unary ones) | |
1573 | args.push_back (rhs); | |
1574 | ||
f14cbab8 | 1575 | return Backend::call_expression (fn_expr, args, nullptr, expr.get_locus ()); |
019b2f15 PH |
1576 | } |
1577 | ||
1578 | tree | |
1579 | CompileExpr::compile_bool_literal (const HIR::LiteralExpr &expr, | |
1580 | const TyTy::BaseType *tyty) | |
1581 | { | |
1582 | rust_assert (expr.get_lit_type () == HIR::Literal::BOOL); | |
1583 | ||
1584 | const auto literal_value = expr.get_literal (); | |
1585 | bool bval = literal_value.as_string ().compare ("true") == 0; | |
f14cbab8 | 1586 | return Backend::boolean_constant_expression (bval); |
019b2f15 PH |
1587 | } |
1588 | ||
1589 | tree | |
1590 | CompileExpr::compile_integer_literal (const HIR::LiteralExpr &expr, | |
1591 | const TyTy::BaseType *tyty) | |
1592 | { | |
1593 | rust_assert (expr.get_lit_type () == HIR::Literal::INT); | |
1594 | const auto literal_value = expr.get_literal (); | |
1595 | ||
1596 | tree type = TyTyResolveCompile::compile (ctx, tyty); | |
1597 | ||
1598 | mpz_t ival; | |
1599 | if (mpz_init_set_str (ival, literal_value.as_string ().c_str (), 10) != 0) | |
1600 | { | |
1601 | rust_error_at (expr.get_locus (), "bad number in literal"); | |
1602 | return error_mark_node; | |
1603 | } | |
1604 | ||
1605 | mpz_t type_min; | |
1606 | mpz_t type_max; | |
1607 | mpz_init (type_min); | |
1608 | mpz_init (type_max); | |
1609 | get_type_static_bounds (type, type_min, type_max); | |
1610 | ||
5db515e5 J |
1611 | if (expr.is_negative ()) |
1612 | { | |
1613 | mpz_neg (ival, ival); | |
1614 | } | |
019b2f15 PH |
1615 | if (mpz_cmp (ival, type_min) < 0 || mpz_cmp (ival, type_max) > 0) |
1616 | { | |
1617 | rust_error_at (expr.get_locus (), | |
9f06b910 | 1618 | "integer overflows the respective type %qs", |
019b2f15 PH |
1619 | tyty->get_name ().c_str ()); |
1620 | return error_mark_node; | |
1621 | } | |
1622 | ||
1623 | tree result = wide_int_to_tree (type, wi::from_mpz (type, ival, true)); | |
1624 | ||
1625 | mpz_clear (type_min); | |
1626 | mpz_clear (type_max); | |
1627 | mpz_clear (ival); | |
1628 | ||
1629 | return result; | |
1630 | } | |
1631 | ||
1632 | tree | |
1633 | CompileExpr::compile_float_literal (const HIR::LiteralExpr &expr, | |
1634 | const TyTy::BaseType *tyty) | |
1635 | { | |
1636 | rust_assert (expr.get_lit_type () == HIR::Literal::FLOAT); | |
1637 | const auto literal_value = expr.get_literal (); | |
1638 | ||
5db515e5 J |
1639 | tree type = TyTyResolveCompile::compile (ctx, tyty); |
1640 | ||
019b2f15 PH |
1641 | mpfr_t fval; |
1642 | if (mpfr_init_set_str (fval, literal_value.as_string ().c_str (), 10, | |
1643 | MPFR_RNDN) | |
1644 | != 0) | |
1645 | { | |
1646 | rust_error_at (expr.get_locus (), "bad number in literal"); | |
1647 | return error_mark_node; | |
1648 | } | |
1649 | ||
019b2f15 PH |
1650 | // taken from: |
1651 | // see go/gofrontend/expressions.cc:check_float_type | |
5db515e5 J |
1652 | bool real_value_overflow; |
1653 | ||
1654 | if (mpfr_regular_p (fval) != 0) | |
1655 | { | |
1656 | mpfr_exp_t exp = mpfr_get_exp (fval); | |
1657 | mpfr_exp_t min_exp; | |
1658 | mpfr_exp_t max_exp; | |
1659 | ||
1660 | /* | |
1661 | * By convention, the radix point of the significand is just before the | |
1662 | * first digit (which is always 1 due to normalization), like in the C | |
1663 | * language, but unlike in IEEE 754 (thus, for a given number, the | |
1664 | * exponent values in MPFR and in IEEE 754 differ by 1). | |
1665 | */ | |
1666 | switch (TYPE_PRECISION (type)) | |
1667 | { | |
1668 | case 32: | |
1669 | min_exp = -128 + 1; | |
1670 | max_exp = 127 + 1; | |
1671 | break; | |
1672 | case 64: | |
1673 | min_exp = -1024 + 1; | |
1674 | max_exp = 1023 + 1; | |
1675 | break; | |
1676 | default: | |
1677 | rust_error_at (expr.get_locus (), | |
1678 | "precision of type %<%s%> not supported", | |
1679 | tyty->get_name ().c_str ()); | |
1680 | return error_mark_node; | |
1681 | } | |
1682 | real_value_overflow = exp < min_exp || exp > max_exp; | |
1683 | } | |
1684 | else | |
1685 | { | |
1686 | real_value_overflow = false; | |
1687 | } | |
019b2f15 PH |
1688 | |
1689 | REAL_VALUE_TYPE r1; | |
1690 | real_from_mpfr (&r1, fval, type, GMP_RNDN); | |
1691 | REAL_VALUE_TYPE r2; | |
1692 | real_convert (&r2, TYPE_MODE (type), &r1); | |
1693 | ||
1694 | tree real_value = build_real (type, r2); | |
1695 | if (TREE_OVERFLOW (real_value) || real_value_overflow) | |
1696 | { | |
1697 | rust_error_at (expr.get_locus (), | |
9f06b910 | 1698 | "decimal overflows the respective type %qs", |
019b2f15 PH |
1699 | tyty->get_name ().c_str ()); |
1700 | return error_mark_node; | |
1701 | } | |
1702 | ||
1703 | return real_value; | |
1704 | } | |
1705 | ||
1706 | tree | |
1707 | CompileExpr::compile_char_literal (const HIR::LiteralExpr &expr, | |
1708 | const TyTy::BaseType *tyty) | |
1709 | { | |
1710 | rust_assert (expr.get_lit_type () == HIR::Literal::CHAR); | |
1711 | const auto literal_value = expr.get_literal (); | |
1712 | ||
1713 | // FIXME needs wchar_t | |
1714 | char c = literal_value.as_string ().c_str ()[0]; | |
f14cbab8 | 1715 | return Backend::wchar_constant_expression (c); |
019b2f15 PH |
1716 | } |
1717 | ||
1718 | tree | |
1719 | CompileExpr::compile_byte_literal (const HIR::LiteralExpr &expr, | |
1720 | const TyTy::BaseType *tyty) | |
1721 | { | |
1722 | rust_assert (expr.get_lit_type () == HIR::Literal::BYTE); | |
1723 | const auto literal_value = expr.get_literal (); | |
1724 | ||
1725 | tree type = TyTyResolveCompile::compile (ctx, tyty); | |
1726 | char c = literal_value.as_string ().c_str ()[0]; | |
1727 | return build_int_cst (type, c); | |
1728 | } | |
1729 | ||
1730 | tree | |
1731 | CompileExpr::compile_string_literal (const HIR::LiteralExpr &expr, | |
1732 | const TyTy::BaseType *tyty) | |
1733 | { | |
1734 | tree fat_pointer = TyTyResolveCompile::compile (ctx, tyty); | |
1735 | ||
1736 | rust_assert (expr.get_lit_type () == HIR::Literal::STRING); | |
1737 | const auto literal_value = expr.get_literal (); | |
1738 | ||
f14cbab8 | 1739 | auto base = Backend::string_constant_expression (literal_value.as_string ()); |
019b2f15 PH |
1740 | tree data = address_expression (base, expr.get_locus ()); |
1741 | ||
1742 | TyTy::BaseType *usize = nullptr; | |
1743 | bool ok = ctx->get_tyctx ()->lookup_builtin ("usize", &usize); | |
1744 | rust_assert (ok); | |
1745 | tree type = TyTyResolveCompile::compile (ctx, usize); | |
1746 | ||
1747 | tree size = build_int_cstu (type, literal_value.as_string ().size ()); | |
1748 | ||
f14cbab8 OA |
1749 | return Backend::constructor_expression (fat_pointer, false, {data, size}, -1, |
1750 | expr.get_locus ()); | |
019b2f15 PH |
1751 | } |
1752 | ||
1753 | tree | |
1754 | CompileExpr::compile_byte_string_literal (const HIR::LiteralExpr &expr, | |
1755 | const TyTy::BaseType *tyty) | |
1756 | { | |
1757 | rust_assert (expr.get_lit_type () == HIR::Literal::BYTE_STRING); | |
1758 | ||
1759 | // the type here is &[ty; capacity] | |
1760 | rust_assert (tyty->get_kind () == TyTy::TypeKind::REF); | |
1761 | const auto ref_tyty = static_cast<const TyTy::ReferenceType *> (tyty); | |
1762 | auto base_tyty = ref_tyty->get_base (); | |
1763 | rust_assert (base_tyty->get_kind () == TyTy::TypeKind::ARRAY); | |
1764 | auto array_tyty = static_cast<TyTy::ArrayType *> (base_tyty); | |
1765 | ||
1766 | std::string value_str = expr.get_literal ().as_string (); | |
1767 | std::vector<tree> vals; | |
1768 | std::vector<unsigned long> indexes; | |
1769 | for (size_t i = 0; i < value_str.size (); i++) | |
1770 | { | |
1771 | char b = value_str.at (i); | |
f14cbab8 | 1772 | tree bb = Backend::char_constant_expression (b); |
019b2f15 PH |
1773 | vals.push_back (bb); |
1774 | indexes.push_back (i); | |
1775 | } | |
1776 | ||
1777 | tree array_type = TyTyResolveCompile::compile (ctx, array_tyty); | |
1778 | tree constructed | |
f14cbab8 OA |
1779 | = Backend::array_constructor_expression (array_type, indexes, vals, |
1780 | expr.get_locus ()); | |
019b2f15 PH |
1781 | |
1782 | return address_expression (constructed, expr.get_locus ()); | |
1783 | } | |
1784 | ||
1785 | tree | |
1786 | CompileExpr::type_cast_expression (tree type_to_cast_to, tree expr_tree, | |
dd15fff3 | 1787 | location_t location) |
019b2f15 PH |
1788 | { |
1789 | if (type_to_cast_to == error_mark_node || expr_tree == error_mark_node | |
1790 | || TREE_TYPE (expr_tree) == error_mark_node) | |
1791 | return error_mark_node; | |
1792 | ||
f14cbab8 | 1793 | if (Backend::type_size (type_to_cast_to) == 0 |
019b2f15 PH |
1794 | || TREE_TYPE (expr_tree) == void_type_node) |
1795 | { | |
1796 | // Do not convert zero-sized types. | |
1797 | return expr_tree; | |
1798 | } | |
1799 | else if (TREE_CODE (type_to_cast_to) == INTEGER_TYPE) | |
1800 | { | |
1801 | tree cast = convert_to_integer (type_to_cast_to, expr_tree); | |
1802 | // FIXME check for TREE_OVERFLOW? | |
1803 | return cast; | |
1804 | } | |
1805 | else if (TREE_CODE (type_to_cast_to) == REAL_TYPE) | |
1806 | { | |
1807 | tree cast = convert_to_real (type_to_cast_to, expr_tree); | |
1808 | // FIXME | |
1809 | // We might need to check that the tree is MAX val and thusly saturate it | |
1810 | // to inf. we can get the bounds and check the value if its >= or <= to | |
1811 | // the min and max bounds | |
1812 | // | |
1813 | // https://github.com/Rust-GCC/gccrs/issues/635 | |
1814 | return cast; | |
1815 | } | |
1816 | else if (TREE_CODE (type_to_cast_to) == COMPLEX_TYPE) | |
1817 | { | |
1818 | return convert_to_complex (type_to_cast_to, expr_tree); | |
1819 | } | |
1820 | else if (TREE_CODE (type_to_cast_to) == POINTER_TYPE | |
1821 | && TREE_CODE (TREE_TYPE (expr_tree)) == INTEGER_TYPE) | |
1822 | { | |
1823 | return convert_to_pointer (type_to_cast_to, expr_tree); | |
1824 | } | |
1825 | else if (TREE_CODE (type_to_cast_to) == RECORD_TYPE | |
1826 | || TREE_CODE (type_to_cast_to) == ARRAY_TYPE) | |
1827 | { | |
d8a697a6 OA |
1828 | return fold_build1_loc (location, VIEW_CONVERT_EXPR, type_to_cast_to, |
1829 | expr_tree); | |
019b2f15 PH |
1830 | } |
1831 | else if (TREE_CODE (type_to_cast_to) == POINTER_TYPE | |
c9600aa5 | 1832 | && RS_DST_FLAG (TREE_TYPE (expr_tree))) |
019b2f15 PH |
1833 | { |
1834 | // returning a raw cast using NOP_EXPR seems to resut in an ICE: | |
1835 | // | |
1836 | // Analyzing compilation unit | |
1837 | // Performing interprocedural optimizations | |
1838 | // <*free_lang_data> {heap 2644k} <visibility> {heap 2644k} | |
1839 | // <build_ssa_passes> {heap 2644k} <opt_local_passes> {heap 2644k}during | |
1840 | // GIMPLE pass: cddce | |
1841 | // In function ‘*T::as_ptr<i32>’: | |
1842 | // rust1: internal compiler error: in propagate_necessity, at | |
1843 | // tree-ssa-dce.cc:984 0x1d5b43e propagate_necessity | |
1844 | // ../../gccrs/gcc/tree-ssa-dce.cc:984 | |
1845 | // 0x1d5e180 perform_tree_ssa_dce | |
1846 | // ../../gccrs/gcc/tree-ssa-dce.cc:1876 | |
1847 | // 0x1d5e2c8 tree_ssa_cd_dce | |
1848 | // ../../gccrs/gcc/tree-ssa-dce.cc:1920 | |
1849 | // 0x1d5e49a execute | |
1850 | // ../../gccrs/gcc/tree-ssa-dce.cc:1992 | |
1851 | ||
1852 | // this is returning the direct raw pointer of the slice an assumes a very | |
1853 | // specific layout | |
f14cbab8 | 1854 | return Backend::struct_field_expression (expr_tree, 0, location); |
019b2f15 PH |
1855 | } |
1856 | ||
d8a697a6 | 1857 | return fold_convert_loc (location, type_to_cast_to, expr_tree); |
019b2f15 PH |
1858 | } |
1859 | ||
1860 | void | |
1861 | CompileExpr::visit (HIR::ArrayExpr &expr) | |
1862 | { | |
1863 | TyTy::BaseType *tyty = nullptr; | |
1864 | if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (), | |
1865 | &tyty)) | |
1866 | { | |
1867 | rust_fatal_error (expr.get_locus (), | |
1868 | "did not resolve type for this array expr"); | |
1869 | return; | |
1870 | } | |
1871 | ||
1872 | tree array_type = TyTyResolveCompile::compile (ctx, tyty); | |
1873 | if (TREE_CODE (array_type) != ARRAY_TYPE) | |
1874 | { | |
1875 | translated = error_mark_node; | |
1876 | return; | |
1877 | } | |
1878 | ||
1879 | rust_assert (tyty->get_kind () == TyTy::TypeKind::ARRAY); | |
1880 | const TyTy::ArrayType &array_tyty | |
1881 | = static_cast<const TyTy::ArrayType &> (*tyty); | |
1882 | ||
c29a3bc9 | 1883 | HIR::ArrayElems &elements = expr.get_internal_elements (); |
019b2f15 PH |
1884 | switch (elements.get_array_expr_type ()) |
1885 | { | |
1886 | case HIR::ArrayElems::ArrayExprType::VALUES: { | |
1887 | HIR::ArrayElemsValues &elems | |
1888 | = static_cast<HIR::ArrayElemsValues &> (elements); | |
1889 | translated | |
1890 | = array_value_expr (expr.get_locus (), array_tyty, array_type, elems); | |
1891 | } | |
1892 | return; | |
1893 | ||
1894 | case HIR::ArrayElems::ArrayExprType::COPIED: | |
1895 | HIR::ArrayElemsCopied &elems | |
1896 | = static_cast<HIR::ArrayElemsCopied &> (elements); | |
1897 | translated | |
1898 | = array_copied_expr (expr.get_locus (), array_tyty, array_type, elems); | |
1899 | } | |
1900 | } | |
1901 | ||
1902 | tree | |
1ed62a2b | 1903 | CompileExpr::array_value_expr (location_t expr_locus, |
019b2f15 PH |
1904 | const TyTy::ArrayType &array_tyty, |
1905 | tree array_type, HIR::ArrayElemsValues &elems) | |
1906 | { | |
1907 | std::vector<unsigned long> indexes; | |
1908 | std::vector<tree> constructor; | |
1909 | size_t i = 0; | |
1910 | for (auto &elem : elems.get_values ()) | |
1911 | { | |
c29a3bc9 | 1912 | tree translated_expr = CompileExpr::Compile (*elem, ctx); |
e60632a2 PH |
1913 | if (translated_expr == error_mark_node) |
1914 | { | |
1915 | rich_location r (line_table, expr_locus); | |
1916 | r.add_fixit_replace (elem->get_locus (), "not a value"); | |
1917 | rust_error_at (r, ErrorCode::E0423, "expected value"); | |
1918 | return error_mark_node; | |
1919 | } | |
1920 | ||
019b2f15 PH |
1921 | constructor.push_back (translated_expr); |
1922 | indexes.push_back (i++); | |
1923 | } | |
1924 | ||
f14cbab8 OA |
1925 | return Backend::array_constructor_expression (array_type, indexes, |
1926 | constructor, expr_locus); | |
019b2f15 PH |
1927 | } |
1928 | ||
1929 | tree | |
1ed62a2b | 1930 | CompileExpr::array_copied_expr (location_t expr_locus, |
019b2f15 PH |
1931 | const TyTy::ArrayType &array_tyty, |
1932 | tree array_type, HIR::ArrayElemsCopied &elems) | |
1933 | { | |
1934 | // see gcc/cp/typeck2.cc:1369-1401 | |
1935 | gcc_assert (TREE_CODE (array_type) == ARRAY_TYPE); | |
1936 | tree domain = TYPE_DOMAIN (array_type); | |
1937 | if (!domain) | |
1938 | return error_mark_node; | |
1939 | ||
1940 | if (!TREE_CONSTANT (TYPE_MAX_VALUE (domain))) | |
1941 | { | |
1942 | rust_error_at (expr_locus, "non const capacity domain %qT", array_type); | |
1943 | return error_mark_node; | |
1944 | } | |
1945 | ||
9c87dc0a | 1946 | ctx->push_const_context (); |
c29a3bc9 | 1947 | tree capacity_expr = CompileExpr::Compile (elems.get_num_copies_expr (), ctx); |
9c87dc0a AC |
1948 | ctx->pop_const_context (); |
1949 | ||
019b2f15 PH |
1950 | if (!TREE_CONSTANT (capacity_expr)) |
1951 | { | |
1952 | rust_error_at (expr_locus, "non const num copies %qT", array_type); | |
1953 | return error_mark_node; | |
1954 | } | |
1955 | ||
1956 | // get the compiled value | |
c29a3bc9 | 1957 | tree translated_expr = CompileExpr::Compile (elems.get_elem_to_copy (), ctx); |
019b2f15 PH |
1958 | |
1959 | tree max_domain = TYPE_MAX_VALUE (domain); | |
1960 | tree min_domain = TYPE_MIN_VALUE (domain); | |
1961 | ||
1962 | auto max = wi::to_offset (max_domain); | |
1963 | auto min = wi::to_offset (min_domain); | |
1964 | auto precision = TYPE_PRECISION (TREE_TYPE (domain)); | |
1965 | auto sign = TYPE_SIGN (TREE_TYPE (domain)); | |
1966 | unsigned HOST_WIDE_INT len | |
1967 | = wi::ext (max - min + 1, precision, sign).to_uhwi (); | |
1968 | ||
1969 | // In a const context we must initialize the entire array, which entails | |
1970 | // allocating for each element. If the user wants a huge array, we will OOM | |
1971 | // and die horribly. | |
1972 | if (ctx->const_context_p ()) | |
1973 | { | |
1974 | size_t idx = 0; | |
e186cea1 | 1975 | |
019b2f15 PH |
1976 | std::vector<unsigned long> indexes; |
1977 | std::vector<tree> constructor; | |
e186cea1 PH |
1978 | |
1979 | indexes.reserve (len); | |
1980 | constructor.reserve (len); | |
019b2f15 PH |
1981 | for (unsigned HOST_WIDE_INT i = 0; i < len; i++) |
1982 | { | |
1983 | constructor.push_back (translated_expr); | |
1984 | indexes.push_back (idx++); | |
1985 | } | |
1986 | ||
f14cbab8 OA |
1987 | return Backend::array_constructor_expression (array_type, indexes, |
1988 | constructor, expr_locus); | |
019b2f15 PH |
1989 | } |
1990 | ||
1991 | else | |
1992 | { | |
1993 | // Create a new block scope in which to initialize the array | |
1994 | tree fndecl = NULL_TREE; | |
1995 | if (ctx->in_fn ()) | |
1996 | fndecl = ctx->peek_fn ().fndecl; | |
1997 | ||
1998 | std::vector<Bvariable *> locals; | |
1999 | tree enclosing_scope = ctx->peek_enclosing_scope (); | |
f14cbab8 OA |
2000 | tree init_block = Backend::block (fndecl, enclosing_scope, locals, |
2001 | expr_locus, expr_locus); | |
019b2f15 PH |
2002 | ctx->push_block (init_block); |
2003 | ||
2004 | tree tmp; | |
f14cbab8 OA |
2005 | tree stmts = Backend::array_initializer (fndecl, init_block, array_type, |
2006 | capacity_expr, translated_expr, | |
2007 | &tmp, expr_locus); | |
019b2f15 PH |
2008 | ctx->add_statement (stmts); |
2009 | ||
2010 | tree block = ctx->pop_block (); | |
2011 | ||
2012 | // The result is a compound expression which creates a temporary array, | |
2013 | // initializes all the elements in a loop, and then yeilds the array. | |
f14cbab8 | 2014 | return Backend::compound_expression (block, tmp, expr_locus); |
019b2f15 PH |
2015 | } |
2016 | } | |
2017 | ||
2018 | tree | |
2019 | HIRCompileBase::resolve_adjustements ( | |
2020 | std::vector<Resolver::Adjustment> &adjustments, tree expression, | |
d991a3f1 | 2021 | location_t locus) |
019b2f15 PH |
2022 | { |
2023 | tree e = expression; | |
2024 | for (auto &adjustment : adjustments) | |
2025 | { | |
e60632a2 PH |
2026 | if (e == error_mark_node) |
2027 | return error_mark_node; | |
2028 | ||
019b2f15 PH |
2029 | switch (adjustment.get_type ()) |
2030 | { | |
2031 | case Resolver::Adjustment::AdjustmentType::ERROR: | |
2032 | return error_mark_node; | |
2033 | ||
2034 | case Resolver::Adjustment::AdjustmentType::IMM_REF: | |
2035 | case Resolver::Adjustment::AdjustmentType::MUT_REF: { | |
c9600aa5 | 2036 | if (!RS_DST_FLAG (TREE_TYPE (e))) |
019b2f15 PH |
2037 | { |
2038 | e = address_expression (e, locus); | |
2039 | } | |
2040 | } | |
2041 | break; | |
2042 | ||
2043 | case Resolver::Adjustment::AdjustmentType::DEREF: | |
2044 | case Resolver::Adjustment::AdjustmentType::DEREF_MUT: | |
2045 | e = resolve_deref_adjustment (adjustment, e, locus); | |
2046 | break; | |
2047 | ||
2048 | case Resolver::Adjustment::AdjustmentType::INDIRECTION: | |
2049 | e = resolve_indirection_adjustment (adjustment, e, locus); | |
2050 | break; | |
2051 | ||
2052 | case Resolver::Adjustment::AdjustmentType::UNSIZE: | |
2053 | e = resolve_unsized_adjustment (adjustment, e, locus); | |
2054 | break; | |
2055 | } | |
2056 | } | |
2057 | ||
2058 | return e; | |
2059 | } | |
2060 | ||
2061 | tree | |
2062 | HIRCompileBase::resolve_deref_adjustment (Resolver::Adjustment &adjustment, | |
d991a3f1 | 2063 | tree expression, location_t locus) |
019b2f15 PH |
2064 | { |
2065 | rust_assert (adjustment.is_deref_adjustment () | |
2066 | || adjustment.is_deref_mut_adjustment ()); | |
2067 | rust_assert (adjustment.has_operator_overload ()); | |
2068 | ||
2069 | TyTy::FnType *lookup = adjustment.get_deref_operator_fn (); | |
6ed987d5 PH |
2070 | TyTy::BaseType *receiver = adjustment.get_actual (); |
2071 | tree fn_address = resolve_method_address (lookup, receiver, locus); | |
019b2f15 PH |
2072 | |
2073 | // does it need a reference to call | |
2074 | tree adjusted_argument = expression; | |
2075 | bool needs_borrow = adjustment.get_deref_adjustment_type () | |
2076 | != Resolver::Adjustment::AdjustmentType::ERROR; | |
2077 | if (needs_borrow) | |
2078 | { | |
2079 | adjusted_argument = address_expression (expression, locus); | |
2080 | } | |
2081 | ||
2082 | // make the call | |
f14cbab8 OA |
2083 | return Backend::call_expression (fn_address, {adjusted_argument}, nullptr, |
2084 | locus); | |
019b2f15 PH |
2085 | } |
2086 | ||
2087 | tree | |
2088 | HIRCompileBase::resolve_indirection_adjustment ( | |
d991a3f1 | 2089 | Resolver::Adjustment &adjustment, tree expression, location_t locus) |
019b2f15 PH |
2090 | { |
2091 | return indirect_expression (expression, locus); | |
2092 | } | |
2093 | ||
2094 | tree | |
2095 | HIRCompileBase::resolve_unsized_adjustment (Resolver::Adjustment &adjustment, | |
d991a3f1 | 2096 | tree expression, location_t locus) |
019b2f15 PH |
2097 | { |
2098 | bool expect_slice | |
2099 | = adjustment.get_expected ()->get_kind () == TyTy::TypeKind::SLICE; | |
2100 | bool expect_dyn | |
2101 | = adjustment.get_expected ()->get_kind () == TyTy::TypeKind::DYNAMIC; | |
2102 | ||
2103 | // assumes this is an array | |
2104 | tree expr_type = TREE_TYPE (expression); | |
2105 | if (expect_slice) | |
2106 | { | |
2107 | rust_assert (TREE_CODE (expr_type) == ARRAY_TYPE); | |
2108 | return resolve_unsized_slice_adjustment (adjustment, expression, locus); | |
2109 | } | |
2110 | ||
2111 | rust_assert (expect_dyn); | |
2112 | return resolve_unsized_dyn_adjustment (adjustment, expression, locus); | |
2113 | } | |
2114 | ||
2115 | tree | |
2116 | HIRCompileBase::resolve_unsized_slice_adjustment ( | |
d991a3f1 | 2117 | Resolver::Adjustment &adjustment, tree expression, location_t locus) |
019b2f15 PH |
2118 | { |
2119 | // assumes this is an array | |
2120 | tree expr_type = TREE_TYPE (expression); | |
2121 | rust_assert (TREE_CODE (expr_type) == ARRAY_TYPE); | |
2122 | ||
2123 | // takes an array and returns a fat-pointer so this becomes a constructor | |
2124 | // expression | |
2125 | rust_assert (adjustment.get_expected ()->get_kind () | |
2126 | == TyTy::TypeKind::SLICE); | |
2127 | tree fat_pointer | |
2128 | = TyTyResolveCompile::compile (ctx, adjustment.get_expected ()); | |
2129 | ||
2130 | // make a constructor for this | |
2131 | tree data = address_expression (expression, locus); | |
2132 | ||
2133 | // fetch the size from the domain | |
2134 | tree domain = TYPE_DOMAIN (expr_type); | |
2135 | unsigned HOST_WIDE_INT array_size | |
2136 | = wi::ext (wi::to_offset (TYPE_MAX_VALUE (domain)) | |
2137 | - wi::to_offset (TYPE_MIN_VALUE (domain)) + 1, | |
2138 | TYPE_PRECISION (TREE_TYPE (domain)), | |
2139 | TYPE_SIGN (TREE_TYPE (domain))) | |
2140 | .to_uhwi (); | |
2141 | tree size = build_int_cstu (size_type_node, array_size); | |
2142 | ||
f14cbab8 OA |
2143 | return Backend::constructor_expression (fat_pointer, false, {data, size}, -1, |
2144 | locus); | |
019b2f15 PH |
2145 | } |
2146 | ||
2147 | tree | |
2148 | HIRCompileBase::resolve_unsized_dyn_adjustment ( | |
d991a3f1 | 2149 | Resolver::Adjustment &adjustment, tree expression, location_t locus) |
019b2f15 PH |
2150 | { |
2151 | tree rvalue = expression; | |
1ed62a2b | 2152 | location_t rvalue_locus = locus; |
019b2f15 PH |
2153 | |
2154 | const TyTy::BaseType *actual = adjustment.get_actual (); | |
2155 | const TyTy::BaseType *expected = adjustment.get_expected (); | |
2156 | ||
2157 | const TyTy::DynamicObjectType *dyn | |
2158 | = static_cast<const TyTy::DynamicObjectType *> (expected); | |
2159 | ||
2160 | rust_debug ("resolve_unsized_dyn_adjustment actual={%s} dyn={%s}", | |
2161 | actual->debug_str ().c_str (), dyn->debug_str ().c_str ()); | |
2162 | ||
2163 | return coerce_to_dyn_object (rvalue, actual, dyn, rvalue_locus); | |
2164 | } | |
2165 | ||
2166 | void | |
2167 | CompileExpr::visit (HIR::RangeFromToExpr &expr) | |
2168 | { | |
c29a3bc9 PEP |
2169 | tree from = CompileExpr::Compile (expr.get_from_expr (), ctx); |
2170 | tree to = CompileExpr::Compile (expr.get_to_expr (), ctx); | |
019b2f15 PH |
2171 | if (from == error_mark_node || to == error_mark_node) |
2172 | { | |
2173 | translated = error_mark_node; | |
2174 | return; | |
2175 | } | |
2176 | ||
2177 | TyTy::BaseType *tyty = nullptr; | |
2178 | bool ok | |
2179 | = ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (), &tyty); | |
2180 | rust_assert (ok); | |
2181 | ||
2182 | tree adt = TyTyResolveCompile::compile (ctx, tyty); | |
2183 | ||
2184 | // make the constructor | |
f14cbab8 OA |
2185 | translated = Backend::constructor_expression (adt, false, {from, to}, -1, |
2186 | expr.get_locus ()); | |
019b2f15 PH |
2187 | } |
2188 | ||
2189 | void | |
2190 | CompileExpr::visit (HIR::RangeFromExpr &expr) | |
2191 | { | |
c29a3bc9 | 2192 | tree from = CompileExpr::Compile (expr.get_from_expr (), ctx); |
019b2f15 PH |
2193 | if (from == error_mark_node) |
2194 | { | |
2195 | translated = error_mark_node; | |
2196 | return; | |
2197 | } | |
2198 | ||
2199 | TyTy::BaseType *tyty = nullptr; | |
2200 | bool ok | |
2201 | = ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (), &tyty); | |
2202 | rust_assert (ok); | |
2203 | ||
2204 | tree adt = TyTyResolveCompile::compile (ctx, tyty); | |
2205 | ||
2206 | // make the constructor | |
f14cbab8 OA |
2207 | translated = Backend::constructor_expression (adt, false, {from}, -1, |
2208 | expr.get_locus ()); | |
019b2f15 PH |
2209 | } |
2210 | ||
2211 | void | |
2212 | CompileExpr::visit (HIR::RangeToExpr &expr) | |
2213 | { | |
c29a3bc9 | 2214 | tree to = CompileExpr::Compile (expr.get_to_expr (), ctx); |
019b2f15 PH |
2215 | if (to == error_mark_node) |
2216 | { | |
2217 | translated = error_mark_node; | |
2218 | return; | |
2219 | } | |
2220 | ||
2221 | TyTy::BaseType *tyty = nullptr; | |
2222 | bool ok | |
2223 | = ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (), &tyty); | |
2224 | rust_assert (ok); | |
2225 | ||
2226 | tree adt = TyTyResolveCompile::compile (ctx, tyty); | |
2227 | ||
2228 | // make the constructor | |
2229 | translated | |
f14cbab8 | 2230 | = Backend::constructor_expression (adt, false, {to}, -1, expr.get_locus ()); |
019b2f15 PH |
2231 | } |
2232 | ||
2233 | void | |
2234 | CompileExpr::visit (HIR::RangeFullExpr &expr) | |
2235 | { | |
2236 | TyTy::BaseType *tyty = nullptr; | |
2237 | bool ok | |
2238 | = ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (), &tyty); | |
2239 | rust_assert (ok); | |
2240 | ||
2241 | tree adt = TyTyResolveCompile::compile (ctx, tyty); | |
f14cbab8 OA |
2242 | translated |
2243 | = Backend::constructor_expression (adt, false, {}, -1, expr.get_locus ()); | |
019b2f15 PH |
2244 | } |
2245 | ||
2246 | void | |
2247 | CompileExpr::visit (HIR::RangeFromToInclExpr &expr) | |
2248 | { | |
c29a3bc9 PEP |
2249 | tree from = CompileExpr::Compile (expr.get_from_expr (), ctx); |
2250 | tree to = CompileExpr::Compile (expr.get_to_expr (), ctx); | |
019b2f15 PH |
2251 | if (from == error_mark_node || to == error_mark_node) |
2252 | { | |
2253 | translated = error_mark_node; | |
2254 | return; | |
2255 | } | |
2256 | ||
2257 | TyTy::BaseType *tyty = nullptr; | |
2258 | bool ok | |
2259 | = ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (), &tyty); | |
2260 | rust_assert (ok); | |
2261 | ||
2262 | tree adt = TyTyResolveCompile::compile (ctx, tyty); | |
2263 | ||
2264 | // make the constructor | |
f14cbab8 OA |
2265 | translated = Backend::constructor_expression (adt, false, {from, to}, -1, |
2266 | expr.get_locus ()); | |
019b2f15 PH |
2267 | } |
2268 | ||
2269 | void | |
2270 | CompileExpr::visit (HIR::ArrayIndexExpr &expr) | |
2271 | { | |
c29a3bc9 PEP |
2272 | tree array_reference = CompileExpr::Compile (expr.get_array_expr (), ctx); |
2273 | tree index = CompileExpr::Compile (expr.get_index_expr (), ctx); | |
019b2f15 PH |
2274 | |
2275 | // this might be an core::ops::index lang item situation | |
2276 | TyTy::FnType *fntype; | |
2277 | bool is_op_overload = ctx->get_tyctx ()->lookup_operator_overload ( | |
2278 | expr.get_mappings ().get_hirid (), &fntype); | |
2279 | if (is_op_overload) | |
2280 | { | |
bf6d216f | 2281 | auto lang_item_type = LangItem::Kind::INDEX; |
019b2f15 PH |
2282 | tree operator_overload_call |
2283 | = resolve_operator_overload (lang_item_type, expr, array_reference, | |
c29a3bc9 PEP |
2284 | index, expr.get_array_expr (), |
2285 | expr.get_index_expr ()); | |
019b2f15 PH |
2286 | |
2287 | tree actual_type = TREE_TYPE (operator_overload_call); | |
2288 | bool can_indirect = TYPE_PTR_P (actual_type) || TYPE_REF_P (actual_type); | |
2289 | if (!can_indirect) | |
2290 | { | |
2291 | // nothing to do | |
2292 | translated = operator_overload_call; | |
2293 | return; | |
2294 | } | |
2295 | ||
2296 | // rust deref always returns a reference from this overload then we can | |
2297 | // actually do the indirection | |
2298 | translated | |
2299 | = indirect_expression (operator_overload_call, expr.get_locus ()); | |
2300 | return; | |
2301 | } | |
2302 | ||
2303 | // lets check if the array is a reference type then we can add an | |
2304 | // indirection if required | |
2305 | TyTy::BaseType *array_expr_ty = nullptr; | |
2306 | bool ok = ctx->get_tyctx ()->lookup_type ( | |
c29a3bc9 | 2307 | expr.get_array_expr ().get_mappings ().get_hirid (), &array_expr_ty); |
019b2f15 PH |
2308 | rust_assert (ok); |
2309 | ||
2310 | // do we need to add an indirect reference | |
2311 | if (array_expr_ty->get_kind () == TyTy::TypeKind::REF) | |
2312 | { | |
2313 | array_reference | |
2314 | = indirect_expression (array_reference, expr.get_locus ()); | |
2315 | } | |
2316 | ||
f14cbab8 OA |
2317 | translated = Backend::array_index_expression (array_reference, index, |
2318 | expr.get_locus ()); | |
019b2f15 PH |
2319 | } |
2320 | ||
870dd9d5 PH |
2321 | void |
2322 | CompileExpr::visit (HIR::ClosureExpr &expr) | |
2323 | { | |
699e7e86 PH |
2324 | TyTy::BaseType *closure_expr_ty = nullptr; |
2325 | if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (), | |
2326 | &closure_expr_ty)) | |
2327 | { | |
2328 | rust_fatal_error (expr.get_locus (), | |
2329 | "did not resolve type for this ClosureExpr"); | |
2330 | return; | |
2331 | } | |
2332 | rust_assert (closure_expr_ty->get_kind () == TyTy::TypeKind::CLOSURE); | |
2333 | TyTy::ClosureType *closure_tyty | |
2334 | = static_cast<TyTy::ClosureType *> (closure_expr_ty); | |
2335 | tree compiled_closure_tyty = TyTyResolveCompile::compile (ctx, closure_tyty); | |
2336 | ||
2337 | // generate closure function | |
2338 | generate_closure_function (expr, *closure_tyty, compiled_closure_tyty); | |
2339 | ||
2340 | // lets ignore state capture for now we need to instantiate the struct anyway | |
2341 | // then generate the function | |
699e7e86 | 2342 | std::vector<tree> vals; |
92389b46 PH |
2343 | for (const auto &capture : closure_tyty->get_captures ()) |
2344 | { | |
2345 | // lookup the HirId | |
709371a1 PEP |
2346 | if (auto hid = ctx->get_mappings ().lookup_node_to_hir (capture)) |
2347 | { | |
2348 | // lookup the var decl | |
2349 | Bvariable *var = nullptr; | |
2350 | bool found = ctx->lookup_var_decl (*hid, &var); | |
2351 | rust_assert (found); | |
2352 | ||
2353 | // FIXME | |
2354 | // this should bes based on the closure move-ability | |
2355 | tree var_expr = var->get_tree (expr.get_locus ()); | |
2356 | tree val = address_expression (var_expr, expr.get_locus ()); | |
2357 | vals.push_back (val); | |
2358 | } | |
2359 | else | |
2360 | rust_unreachable (); | |
92389b46 | 2361 | } |
699e7e86 | 2362 | |
f14cbab8 OA |
2363 | translated = Backend::constructor_expression (compiled_closure_tyty, false, |
2364 | vals, -1, expr.get_locus ()); | |
699e7e86 PH |
2365 | } |
2366 | ||
2367 | tree | |
2368 | CompileExpr::generate_closure_function (HIR::ClosureExpr &expr, | |
2369 | TyTy::ClosureType &closure_tyty, | |
2370 | tree compiled_closure_tyty) | |
2371 | { | |
2372 | TyTy::FnType *fn_tyty = nullptr; | |
2373 | tree compiled_fn_type | |
2374 | = generate_closure_fntype (expr, closure_tyty, compiled_closure_tyty, | |
2375 | &fn_tyty); | |
2376 | if (compiled_fn_type == error_mark_node) | |
2377 | return error_mark_node; | |
2378 | ||
2379 | const Resolver::CanonicalPath &parent_canonical_path | |
2380 | = closure_tyty.get_ident ().path; | |
af34aa18 PEP |
2381 | |
2382 | tl::optional<NodeId> nid = ctx->get_mappings ().lookup_hir_to_node ( | |
2383 | expr.get_mappings ().get_hirid ()); | |
2384 | rust_assert (nid.has_value ()); | |
2385 | auto node_id = nid.value (); | |
2386 | ||
699e7e86 | 2387 | Resolver::CanonicalPath path = parent_canonical_path.append ( |
4bd9f115 | 2388 | Resolver::CanonicalPath::new_seg (node_id, "{{closure}}")); |
699e7e86 PH |
2389 | |
2390 | std::string ir_symbol_name = path.get (); | |
2391 | std::string asm_name = ctx->mangle_item (&closure_tyty, path); | |
2392 | ||
2393 | unsigned int flags = 0; | |
f14cbab8 OA |
2394 | tree fndecl = Backend::function (compiled_fn_type, ir_symbol_name, asm_name, |
2395 | flags, expr.get_locus ()); | |
699e7e86 PH |
2396 | |
2397 | // insert into the context | |
2398 | ctx->insert_function_decl (fn_tyty, fndecl); | |
2399 | ctx->insert_closure_decl (&closure_tyty, fndecl); | |
2400 | ||
2401 | // setup the parameters | |
2402 | std::vector<Bvariable *> param_vars; | |
2403 | ||
2404 | // closure self | |
2405 | Bvariable *self_param | |
f14cbab8 OA |
2406 | = Backend::parameter_variable (fndecl, "$closure", compiled_closure_tyty, |
2407 | expr.get_locus ()); | |
699e7e86 PH |
2408 | DECL_ARTIFICIAL (self_param->get_decl ()) = 1; |
2409 | param_vars.push_back (self_param); | |
2410 | ||
92389b46 PH |
2411 | // push a new context |
2412 | ctx->push_closure_context (expr.get_mappings ().get_hirid ()); | |
2413 | ||
699e7e86 | 2414 | // setup the implicit argument captures |
92389b46 PH |
2415 | size_t idx = 0; |
2416 | for (const auto &capture : closure_tyty.get_captures ()) | |
2417 | { | |
2418 | // lookup the HirId | |
709371a1 PEP |
2419 | if (auto hid = ctx->get_mappings ().lookup_node_to_hir (capture)) |
2420 | { | |
2421 | // get the assessor | |
2422 | tree binding = Backend::struct_field_expression ( | |
2423 | self_param->get_tree (expr.get_locus ()), idx, expr.get_locus ()); | |
2424 | tree indirection = indirect_expression (binding, expr.get_locus ()); | |
92389b46 | 2425 | |
709371a1 PEP |
2426 | // insert bindings |
2427 | ctx->insert_closure_binding (*hid, indirection); | |
92389b46 | 2428 | |
709371a1 PEP |
2429 | // continue |
2430 | idx++; | |
2431 | } | |
2432 | else | |
2433 | rust_unreachable (); | |
92389b46 | 2434 | } |
699e7e86 PH |
2435 | |
2436 | // args tuple | |
2437 | tree args_type | |
2438 | = TyTyResolveCompile::compile (ctx, &closure_tyty.get_parameters ()); | |
2439 | Bvariable *args_param | |
f14cbab8 OA |
2440 | = Backend::parameter_variable (fndecl, "args", args_type, |
2441 | expr.get_locus ()); | |
699e7e86 PH |
2442 | param_vars.push_back (args_param); |
2443 | ||
2444 | // setup the implicit mappings for the arguments. Since argument passing to | |
2445 | // closure functions is done via passing a tuple but the closure body expects | |
2446 | // just normal arguments this means we need to destructure them similar to | |
2447 | // what we do in MatchExpr's. This means when we have a closure-param of a we | |
2448 | // actually setup the destructure to take from the args tuple | |
2449 | ||
2450 | tree args_param_expr = args_param->get_tree (expr.get_locus ()); | |
2451 | size_t i = 0; | |
2452 | for (auto &closure_param : expr.get_params ()) | |
2453 | { | |
f14cbab8 OA |
2454 | tree compiled_param_var |
2455 | = Backend::struct_field_expression (args_param_expr, i, | |
2456 | closure_param.get_locus ()); | |
699e7e86 | 2457 | |
c29a3bc9 | 2458 | CompilePatternBindings::Compile (closure_param.get_pattern (), |
1b793f2a | 2459 | compiled_param_var, ctx); |
699e7e86 PH |
2460 | i++; |
2461 | } | |
2462 | ||
f14cbab8 | 2463 | if (!Backend::function_set_parameters (fndecl, param_vars)) |
92389b46 PH |
2464 | { |
2465 | ctx->pop_closure_context (); | |
2466 | return error_mark_node; | |
2467 | } | |
699e7e86 PH |
2468 | |
2469 | // lookup locals | |
c29a3bc9 | 2470 | HIR::Expr &function_body = expr.get_expr (); |
fc2ba3b9 | 2471 | bool is_block_expr |
c29a3bc9 | 2472 | = function_body.get_expression_type () == HIR::Expr::ExprType::Block; |
fc2ba3b9 | 2473 | |
fc2ba3b9 PH |
2474 | if (is_block_expr) |
2475 | { | |
c29a3bc9 | 2476 | auto body_mappings = function_body.get_mappings (); |
786bc62f AC |
2477 | if (flag_name_resolution_2_0) |
2478 | { | |
9a97fa81 | 2479 | auto &nr_ctx |
786bc62f AC |
2480 | = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); |
2481 | ||
2482 | auto candidate = nr_ctx.values.to_rib (body_mappings.get_nodeid ()); | |
2483 | ||
2484 | rust_assert (candidate.has_value ()); | |
2485 | } | |
2486 | else | |
2487 | { | |
2488 | Resolver::Rib *rib = nullptr; | |
2489 | bool ok | |
2490 | = ctx->get_resolver ()->find_name_rib (body_mappings.get_nodeid (), | |
2491 | &rib); | |
2492 | rust_assert (ok); | |
2493 | } | |
fc2ba3b9 | 2494 | } |
699e7e86 PH |
2495 | |
2496 | tree enclosing_scope = NULL_TREE; | |
c29a3bc9 PEP |
2497 | location_t start_location = function_body.get_locus (); |
2498 | location_t end_location = function_body.get_locus (); | |
699e7e86 PH |
2499 | if (is_block_expr) |
2500 | { | |
c29a3bc9 PEP |
2501 | auto &body = static_cast<HIR::BlockExpr &> (function_body); |
2502 | start_location = body.get_locus (); | |
2503 | end_location = body.get_end_locus (); | |
699e7e86 PH |
2504 | } |
2505 | ||
b4fc851e | 2506 | tree code_block = Backend::block (fndecl, enclosing_scope, {} /*locals*/, |
f14cbab8 | 2507 | start_location, end_location); |
699e7e86 PH |
2508 | ctx->push_block (code_block); |
2509 | ||
2510 | TyTy::BaseType *tyret = &closure_tyty.get_result_type (); | |
699e7e86 | 2511 | Bvariable *return_address = nullptr; |
699e7e86 | 2512 | |
cf046027 PH |
2513 | tree return_type = TyTyResolveCompile::compile (ctx, tyret); |
2514 | bool address_is_taken = false; | |
2515 | tree ret_var_stmt = NULL_TREE; | |
699e7e86 | 2516 | |
cf046027 | 2517 | return_address |
f14cbab8 OA |
2518 | = Backend::temporary_variable (fndecl, code_block, return_type, NULL, |
2519 | address_is_taken, expr.get_locus (), | |
2520 | &ret_var_stmt); | |
699e7e86 | 2521 | |
cf046027 | 2522 | ctx->add_statement (ret_var_stmt); |
699e7e86 | 2523 | |
b90dc2bd | 2524 | ctx->push_fn (fndecl, return_address, tyret); |
699e7e86 PH |
2525 | |
2526 | if (is_block_expr) | |
2527 | { | |
c29a3bc9 PEP |
2528 | auto &body = static_cast<HIR::BlockExpr &> (function_body); |
2529 | compile_function_body (fndecl, body, tyret); | |
699e7e86 PH |
2530 | } |
2531 | else | |
2532 | { | |
2533 | tree value = CompileExpr::Compile (function_body, ctx); | |
2534 | tree return_expr | |
c29a3bc9 | 2535 | = Backend::return_statement (fndecl, value, function_body.get_locus ()); |
699e7e86 PH |
2536 | ctx->add_statement (return_expr); |
2537 | } | |
2538 | ||
2539 | tree bind_tree = ctx->pop_block (); | |
2540 | ||
2541 | gcc_assert (TREE_CODE (bind_tree) == BIND_EXPR); | |
2542 | DECL_SAVED_TREE (fndecl) = bind_tree; | |
2543 | ||
92389b46 | 2544 | ctx->pop_closure_context (); |
699e7e86 PH |
2545 | ctx->pop_fn (); |
2546 | ctx->push_function (fndecl); | |
2547 | ||
2548 | return fndecl; | |
2549 | } | |
2550 | ||
2551 | tree | |
2552 | CompileExpr::generate_closure_fntype (HIR::ClosureExpr &expr, | |
2553 | const TyTy::ClosureType &closure_tyty, | |
2554 | tree compiled_closure_tyty, | |
2555 | TyTy::FnType **fn_tyty) | |
2556 | { | |
2557 | // grab the specified_bound | |
2558 | rust_assert (closure_tyty.num_specified_bounds () == 1); | |
2559 | const TyTy::TypeBoundPredicate &predicate | |
2560 | = *closure_tyty.get_specified_bounds ().begin (); | |
2561 | ||
2562 | // ensure the fn_once_output associated type is set | |
2563 | closure_tyty.setup_fn_once_output (); | |
2564 | ||
2565 | // the function signature is based on the trait bound that the closure | |
2566 | // implements which is determined at the type resolution time | |
2567 | // | |
2568 | // https://github.com/rust-lang/rust/blob/7807a694c2f079fd3f395821bcc357eee8650071/library/core/src/ops/function.rs#L54-L71 | |
2569 | ||
2570 | TyTy::TypeBoundPredicateItem item = TyTy::TypeBoundPredicateItem::error (); | |
2571 | if (predicate.get_name ().compare ("FnOnce") == 0) | |
2572 | { | |
2573 | item = predicate.lookup_associated_item ("call_once"); | |
2574 | } | |
2575 | else if (predicate.get_name ().compare ("FnMut") == 0) | |
2576 | { | |
2577 | item = predicate.lookup_associated_item ("call_mut"); | |
2578 | } | |
2579 | else if (predicate.get_name ().compare ("Fn") == 0) | |
2580 | { | |
2581 | item = predicate.lookup_associated_item ("call"); | |
2582 | } | |
2583 | else | |
2584 | { | |
2585 | // FIXME error message? | |
93866b6a | 2586 | rust_unreachable (); |
699e7e86 PH |
2587 | return error_mark_node; |
2588 | } | |
2589 | ||
2590 | rust_assert (!item.is_error ()); | |
2591 | ||
2592 | TyTy::BaseType *item_tyty = item.get_tyty_for_receiver (&closure_tyty); | |
2593 | rust_assert (item_tyty->get_kind () == TyTy::TypeKind::FNDEF); | |
2594 | *fn_tyty = static_cast<TyTy::FnType *> (item_tyty); | |
2595 | return TyTyResolveCompile::compile (ctx, item_tyty); | |
870dd9d5 PH |
2596 | } |
2597 | ||
21d19d2c PH |
2598 | bool |
2599 | CompileExpr::generate_possible_fn_trait_call (HIR::CallExpr &expr, | |
2600 | tree receiver, tree *result) | |
2601 | { | |
2602 | TyTy::FnType *fn_sig = nullptr; | |
2603 | bool found_overload = ctx->get_tyctx ()->lookup_operator_overload ( | |
2604 | expr.get_mappings ().get_hirid (), &fn_sig); | |
2605 | if (!found_overload) | |
2606 | return false; | |
2607 | ||
2608 | auto id = fn_sig->get_ty_ref (); | |
2609 | auto dId = fn_sig->get_id (); | |
2610 | ||
2611 | tree function = error_mark_node; | |
2612 | bool found_closure = ctx->lookup_function_decl (id, &function, dId, fn_sig); | |
2613 | if (!found_closure) | |
2614 | { | |
2615 | // something went wrong we still return true as this was meant to be an fn | |
2616 | // trait call | |
2617 | *result = error_mark_node; | |
2618 | return true; | |
2619 | } | |
2620 | ||
2621 | // need to apply any autoderef's to the self argument | |
c29a3bc9 PEP |
2622 | HIR::Expr &fnexpr = expr.get_fnexpr (); |
2623 | HirId autoderef_mappings_id = fnexpr.get_mappings ().get_hirid (); | |
21d19d2c PH |
2624 | std::vector<Resolver::Adjustment> *adjustments = nullptr; |
2625 | bool ok = ctx->get_tyctx ()->lookup_autoderef_mappings (autoderef_mappings_id, | |
2626 | &adjustments); | |
2627 | rust_assert (ok); | |
2628 | ||
2629 | // apply adjustments for the fn call | |
2630 | tree self = resolve_adjustements (*adjustments, receiver, expr.get_locus ()); | |
2631 | ||
2632 | // resolve the arguments | |
2633 | std::vector<tree> tuple_arg_vals; | |
2634 | for (auto &argument : expr.get_arguments ()) | |
2635 | { | |
c29a3bc9 | 2636 | auto rvalue = CompileExpr::Compile (*argument, ctx); |
21d19d2c PH |
2637 | tuple_arg_vals.push_back (rvalue); |
2638 | } | |
2639 | ||
2640 | // this is always the 2nd argument in the function signature | |
2641 | tree fnty = TREE_TYPE (function); | |
2642 | tree fn_arg_tys = TYPE_ARG_TYPES (fnty); | |
2643 | tree tuple_args_tyty_chain = TREE_CHAIN (fn_arg_tys); | |
2644 | tree tuple_args_tyty = TREE_VALUE (tuple_args_tyty_chain); | |
2645 | ||
2646 | tree tuple_args | |
f14cbab8 OA |
2647 | = Backend::constructor_expression (tuple_args_tyty, false, tuple_arg_vals, |
2648 | -1, expr.get_locus ()); | |
21d19d2c PH |
2649 | |
2650 | // args are always self, and the tuple of the args we are passing where | |
2651 | // self is the path of the call-expr in this case the fn_address | |
2652 | std::vector<tree> args; | |
2653 | args.push_back (self); | |
2654 | args.push_back (tuple_args); | |
2655 | ||
2656 | tree call_address = address_expression (function, expr.get_locus ()); | |
f14cbab8 OA |
2657 | *result |
2658 | = Backend::call_expression (call_address, args, nullptr /* static chain ?*/, | |
2659 | expr.get_locus ()); | |
21d19d2c PH |
2660 | return true; |
2661 | } | |
2662 | ||
019b2f15 PH |
2663 | } // namespace Compile |
2664 | } // namespace Rust |