Branch data Line data Source code
1 : : // Copyright (C) 2020-2025 Free Software Foundation, Inc.
2 : :
3 : : // This file is part of GCC.
4 : :
5 : : // GCC is free software; you can redistribute it and/or modify it under
6 : : // the terms of the GNU General Public License as published by the Free
7 : : // Software Foundation; either version 3, or (at your option) any later
8 : : // version.
9 : :
10 : : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11 : : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 : : // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 : : // for more details.
14 : :
15 : : // You should have received a copy of the GNU General Public License
16 : : // along with GCC; see the file COPYING3. If not see
17 : : // <http://www.gnu.org/licenses/>.
18 : :
19 : : #include "rust-compile-resolve-path.h"
20 : : #include "options.h"
21 : : #include "rust-compile-intrinsic.h"
22 : : #include "rust-compile-item.h"
23 : : #include "rust-compile-implitem.h"
24 : : #include "rust-compile-expr.h"
25 : : #include "rust-hir-map.h"
26 : : #include "rust-hir-trait-resolve.h"
27 : : #include "rust-hir-path-probe.h"
28 : : #include "rust-compile-extern.h"
29 : : #include "rust-constexpr.h"
30 : : #include "rust-tyty.h"
31 : :
32 : : namespace Rust {
33 : : namespace Compile {
34 : :
35 : : tree
36 : 113 : ResolvePathRef::Compile (HIR::QualifiedPathInExpression &expr, Context *ctx)
37 : : {
38 : 113 : ResolvePathRef resolver (ctx);
39 : 113 : return resolver.resolve_path_like (expr);
40 : 113 : }
41 : :
42 : : tree
43 : 40898 : ResolvePathRef::Compile (HIR::PathInExpression &expr, Context *ctx)
44 : : {
45 : 40898 : ResolvePathRef resolver (ctx);
46 : 40898 : return resolver.resolve_path_like (expr);
47 : 40898 : }
48 : :
49 : 41011 : ResolvePathRef::ResolvePathRef (Context *ctx) : HIRCompileBase (ctx) {}
50 : :
51 : : template <typename T>
52 : : tree
53 : 41011 : ResolvePathRef::resolve_path_like (T &expr)
54 : : {
55 : 41011 : if (expr.is_lang_item ())
56 : : {
57 : : auto lang_item
58 : 34 : = Analysis::Mappings::get ().get_lang_item_node (expr.get_lang_item ());
59 : :
60 : : // FIXME: Is that correct? :/
61 : 34 : auto final_segment
62 : 68 : = HIR::PathIdentSegment (LangItem::ToString (expr.get_lang_item ()));
63 : :
64 : 34 : return resolve_with_node_id (final_segment, expr.get_mappings (),
65 : : expr.get_locus (), true, lang_item);
66 : 34 : }
67 : :
68 : 40977 : return resolve (expr.get_final_segment ().get_segment (),
69 : 40977 : expr.get_mappings (), expr.get_locus (), true);
70 : : }
71 : :
72 : : tree
73 : 1268 : ResolvePathRef::attempt_constructor_expression_lookup (
74 : : TyTy::BaseType *lookup, Context *ctx, const Analysis::NodeMapping &mappings,
75 : : location_t expr_locus)
76 : : {
77 : : // it might be an enum data-less enum variant
78 : 1268 : if (lookup->get_kind () != TyTy::TypeKind::ADT)
79 : 0 : return error_mark_node;
80 : :
81 : 1268 : TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (lookup);
82 : 1268 : if (adt->is_unit ())
83 : 178 : return unit_expression (expr_locus);
84 : :
85 : 1090 : if (!adt->is_enum ())
86 : 1 : return error_mark_node;
87 : :
88 : 1089 : HirId variant_id;
89 : 1089 : if (!ctx->get_tyctx ()->lookup_variant_definition (mappings.get_hirid (),
90 : : &variant_id))
91 : 0 : return error_mark_node;
92 : :
93 : 1089 : int union_disriminator = -1;
94 : 1089 : TyTy::VariantDef *variant = nullptr;
95 : 1089 : if (!adt->lookup_variant_by_id (variant_id, &variant, &union_disriminator))
96 : 0 : return error_mark_node;
97 : :
98 : : // this can only be for discriminant variants the others are built up
99 : : // using call-expr or struct-init
100 : 1089 : rust_assert (variant->get_variant_type ()
101 : : == TyTy::VariantDef::VariantType::NUM);
102 : :
103 : : // we need the actual gcc type
104 : 1089 : tree compiled_adt_type = TyTyResolveCompile::compile (ctx, adt);
105 : :
106 : : // make the ctor for the union
107 : 1089 : HIR::Expr &discrim_expr = variant->get_discriminant ();
108 : 1089 : ctx->push_const_context ();
109 : 1089 : tree discrim_expr_node = CompileExpr::Compile (discrim_expr, ctx);
110 : 1089 : ctx->pop_const_context ();
111 : 1089 : tree folded_discrim_expr = fold_expr (discrim_expr_node);
112 : 1089 : tree qualifier = folded_discrim_expr;
113 : :
114 : : // false for is enum but this is an enum but we have a new layout
115 : 1089 : return Backend::constructor_expression (compiled_adt_type, false, {qualifier},
116 : : -1, expr_locus);
117 : : }
118 : :
119 : : tree
120 : 41011 : ResolvePathRef::resolve_with_node_id (
121 : : const HIR::PathIdentSegment &final_segment,
122 : : const Analysis::NodeMapping &mappings, location_t expr_locus,
123 : : bool is_qualified_path, NodeId resolved_node_id)
124 : : {
125 : 41011 : TyTy::BaseType *lookup = nullptr;
126 : 41011 : bool ok = ctx->get_tyctx ()->lookup_type (mappings.get_hirid (), &lookup);
127 : 41011 : rust_assert (ok);
128 : :
129 : 41011 : tl::optional<HirId> hid
130 : 41011 : = ctx->get_mappings ().lookup_node_to_hir (resolved_node_id);
131 : 41011 : if (!hid.has_value ())
132 : : {
133 : 0 : rust_error_at (expr_locus, "reverse call path lookup failure");
134 : 0 : return error_mark_node;
135 : : }
136 : 41011 : auto ref = hid.value ();
137 : :
138 : : // might be a constant
139 : 41011 : tree constant_expr;
140 : 41011 : if (ctx->lookup_const_decl (ref, &constant_expr))
141 : : {
142 : 617 : TREE_USED (constant_expr) = 1;
143 : 617 : return constant_expr;
144 : : }
145 : :
146 : : // maybe closure binding
147 : 40394 : tree closure_binding = error_mark_node;
148 : 40394 : if (ctx->lookup_closure_binding (ref, &closure_binding))
149 : : {
150 : 14 : TREE_USED (closure_binding) = 1;
151 : 14 : return closure_binding;
152 : : }
153 : :
154 : : // this might be a variable reference or a function reference
155 : 40380 : Bvariable *var = nullptr;
156 : 40380 : if (ctx->lookup_var_decl (ref, &var))
157 : : {
158 : : // TREE_USED is setup in the gcc abstraction here
159 : 29330 : return Backend::var_expression (var, expr_locus);
160 : : }
161 : :
162 : : // might be a match pattern binding
163 : 11050 : tree binding = error_mark_node;
164 : 11050 : if (ctx->lookup_pattern_binding (ref, &binding))
165 : : {
166 : 796 : TREE_USED (binding) = 1;
167 : 796 : return binding;
168 : : }
169 : :
170 : : // it might be a function call
171 : 10254 : if (lookup->get_kind () == TyTy::TypeKind::FNDEF)
172 : : {
173 : 8877 : TyTy::FnType *fntype = static_cast<TyTy::FnType *> (lookup);
174 : 8877 : tree fn = NULL_TREE;
175 : 8877 : if (ctx->lookup_function_decl (fntype->get_ty_ref (), &fn))
176 : : {
177 : 4789 : TREE_USED (fn) = 1;
178 : 6961 : return address_expression (fn, expr_locus);
179 : : }
180 : 4088 : else if (fntype->get_abi () == ABI::INTRINSIC)
181 : : {
182 : 2172 : Intrinsics compile (ctx);
183 : 2172 : fn = compile.compile (fntype);
184 : 2172 : TREE_USED (fn) = 1;
185 : 2172 : return address_expression (fn, expr_locus);
186 : : }
187 : : }
188 : :
189 : : // Handle unit struct
190 : 3293 : tree resolved_item = error_mark_node;
191 : 3293 : if (lookup->get_kind () == TyTy::TypeKind::ADT)
192 : 1268 : resolved_item
193 : 1268 : = attempt_constructor_expression_lookup (lookup, ctx, mappings,
194 : : expr_locus);
195 : :
196 : 3293 : if (!error_operand_p (resolved_item))
197 : : return resolved_item;
198 : :
199 : : // let the query system figure it out
200 : 2026 : resolved_item = query_compile (ref, lookup, final_segment, mappings,
201 : : expr_locus, is_qualified_path);
202 : 2026 : if (resolved_item != error_mark_node)
203 : : {
204 : 2022 : TREE_USED (resolved_item) = 1;
205 : : }
206 : :
207 : : return resolved_item;
208 : : }
209 : :
210 : : tree
211 : 40977 : ResolvePathRef::resolve (const HIR::PathIdentSegment &final_segment,
212 : : const Analysis::NodeMapping &mappings,
213 : : location_t expr_locus, bool is_qualified_path)
214 : : {
215 : 40977 : TyTy::BaseType *lookup = nullptr;
216 : 40977 : bool ok = ctx->get_tyctx ()->lookup_type (mappings.get_hirid (), &lookup);
217 : 40977 : if (!ok)
218 : 0 : return error_mark_node;
219 : :
220 : : // need to look up the reference for this identifier
221 : :
222 : : // this can fail because it might be a Constructor for something
223 : : // in that case the caller should attempt ResolvePathType::Compile
224 : 40977 : auto &nr_ctx
225 : 40977 : = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
226 : :
227 : 40977 : auto resolved = nr_ctx.lookup (mappings.get_nodeid ());
228 : :
229 : 40977 : if (!resolved)
230 : 0 : return attempt_constructor_expression_lookup (lookup, ctx, mappings,
231 : 0 : expr_locus);
232 : :
233 : 40977 : return resolve_with_node_id (final_segment, mappings, expr_locus,
234 : 81954 : is_qualified_path, *resolved);
235 : : }
236 : :
237 : : tree
238 : 2026 : HIRCompileBase::query_compile (HirId ref, TyTy::BaseType *lookup,
239 : : const HIR::PathIdentSegment &final_segment,
240 : : const Analysis::NodeMapping &mappings,
241 : : location_t expr_locus, bool is_qualified_path)
242 : : {
243 : 2026 : bool is_fn = lookup->get_kind () == TyTy::TypeKind::FNDEF;
244 : 2026 : if (auto resolved_item = ctx->get_mappings ().lookup_hir_item (ref))
245 : : {
246 : 878 : if (!lookup->has_substitutions_defined ())
247 : 2023 : return CompileItem::compile (*resolved_item, ctx, nullptr, expr_locus);
248 : : else
249 : 686 : return CompileItem::compile (*resolved_item, ctx, lookup, expr_locus);
250 : : }
251 : 1148 : else if (auto hir_extern_item
252 : 1148 : = ctx->get_mappings ().lookup_hir_extern_item (ref))
253 : : {
254 : 23 : HIR::ExternalItem *resolved_extern_item = hir_extern_item->first;
255 : 23 : if (!lookup->has_substitutions_defined ())
256 : 23 : return CompileExternItem::compile (resolved_extern_item, ctx, nullptr,
257 : 1145 : expr_locus);
258 : : else
259 : 0 : return CompileExternItem::compile (resolved_extern_item, ctx, lookup,
260 : 0 : expr_locus);
261 : : }
262 : : else
263 : : {
264 : 1125 : if (is_fn)
265 : : {
266 : 1121 : TyTy::FnType *fn = static_cast<TyTy::FnType *> (lookup);
267 : 1121 : TyTy::BaseType *receiver = nullptr;
268 : :
269 : 2115 : if (fn->is_method ())
270 : : {
271 : 382 : receiver = fn->get_self_type ();
272 : 382 : receiver = receiver->destructure ();
273 : :
274 : 382 : return resolve_method_address (fn, receiver, expr_locus);
275 : : }
276 : : }
277 : :
278 : 743 : if (auto resolved_item = ctx->get_mappings ().lookup_hir_implitem (ref))
279 : : {
280 : 496 : if (!lookup->has_substitutions_defined ())
281 : 314 : return CompileInherentImplItem::Compile (resolved_item->first, ctx,
282 : 740 : nullptr, expr_locus);
283 : : else
284 : 182 : return CompileInherentImplItem::Compile (resolved_item->first, ctx,
285 : 182 : lookup, expr_locus);
286 : : }
287 : 247 : else if (auto trait_item
288 : 247 : = ctx->get_mappings ().lookup_hir_trait_item (ref))
289 : : {
290 : 244 : HIR::Trait *trait = ctx->get_mappings ().lookup_trait_item_mapping (
291 : 244 : trait_item.value ()->get_mappings ().get_hirid ());
292 : :
293 : 244 : Resolver::TraitReference *trait_ref
294 : 244 : = &Resolver::TraitReference::error_node ();
295 : 244 : bool ok = ctx->get_tyctx ()->lookup_trait_reference (
296 : 244 : trait->get_mappings ().get_defid (), &trait_ref);
297 : 244 : rust_assert (ok);
298 : :
299 : 244 : if (trait_item.value ()->get_item_kind ()
300 : : == HIR::TraitItem::TraitItemKind::CONST)
301 : : {
302 : 1 : auto &c
303 : 1 : = *static_cast<HIR::TraitItemConst *> (trait_item.value ());
304 : 1 : if (!c.has_expr ())
305 : : {
306 : 1 : rich_location r (line_table, expr_locus);
307 : 1 : r.add_range (trait->get_locus ());
308 : 1 : r.add_range (c.get_locus ());
309 : 1 : rust_error_at (r, "no default expression on trait constant");
310 : 1 : return error_mark_node;
311 : 1 : }
312 : :
313 : 0 : return CompileExpr::Compile (c.get_expr (), ctx);
314 : : }
315 : :
316 : 243 : if (trait_item.value ()->get_item_kind ()
317 : : != HIR::TraitItem::TraitItemKind::FUNC)
318 : 0 : return error_mark_node;
319 : :
320 : : // the type resolver can only resolve type bounds to their trait
321 : : // item so its up to us to figure out if this path should resolve
322 : : // to an trait-impl-block-item or if it can be defaulted to the
323 : : // trait-impl-item's definition
324 : : //
325 : : // because we know this is resolved to a trait item we can actually
326 : : // just grab the Self type parameter here for the receiver to match
327 : : // the appropriate impl block
328 : :
329 : 243 : rust_assert (lookup->is<TyTy::FnType> ());
330 : 243 : auto fn = lookup->as<TyTy::FnType> ();
331 : 243 : rust_assert (fn->get_num_type_params () > 0);
332 : 243 : TyTy::SubstitutionParamMapping &self = fn->get_substs ().at (0);
333 : 243 : TyTy::BaseGeneric *receiver = self.get_param_ty ();
334 : 243 : TyTy::BaseType *r = receiver;
335 : 243 : if (!receiver->can_resolve ())
336 : : {
337 : 110 : bool ok
338 : 110 : = ctx->get_tyctx ()->lookup_type (receiver->get_ref (), &r);
339 : 110 : rust_assert (ok);
340 : : }
341 : :
342 : 243 : auto candidates
343 : 243 : = Resolver::PathProbeImplTrait::Probe (r, final_segment, trait_ref);
344 : 243 : if (candidates.size () == 0)
345 : : {
346 : : // this means we are defaulting back to the trait_item if
347 : : // possible
348 : 110 : Resolver::TraitItemReference *trait_item_ref = nullptr;
349 : 110 : bool ok = trait_ref->lookup_hir_trait_item (*trait_item.value (),
350 : : &trait_item_ref);
351 : 110 : rust_assert (ok); // found
352 : 110 : rust_assert (trait_item_ref->is_optional ()); // has definition
353 : :
354 : 110 : return CompileTraitItem::Compile (
355 : : trait_item_ref->get_hir_trait_item (), ctx, lookup, true,
356 : : expr_locus);
357 : : }
358 : : else
359 : : {
360 : 133 : rust_assert (candidates.size () == 1);
361 : :
362 : 133 : auto candidate = *candidates.begin ();
363 : 133 : rust_assert (candidate.is_impl_candidate ());
364 : :
365 : 133 : HIR::ImplBlock *impl = candidate.item.impl.parent;
366 : 133 : HIR::ImplItem *impl_item = candidate.item.impl.impl_item;
367 : :
368 : 133 : TyTy::BaseType *self = nullptr;
369 : 266 : bool ok = ctx->get_tyctx ()->lookup_type (
370 : 133 : impl->get_type ().get_mappings ().get_hirid (), &self);
371 : 133 : rust_assert (ok);
372 : :
373 : 133 : if (!lookup->has_substitutions_defined ())
374 : 0 : return CompileInherentImplItem::Compile (impl_item, ctx,
375 : 0 : nullptr, expr_locus);
376 : : else
377 : 133 : return CompileInherentImplItem::Compile (impl_item, ctx, lookup,
378 : 133 : expr_locus);
379 : : }
380 : 243 : }
381 : : }
382 : :
383 : 3 : return error_mark_node;
384 : : }
385 : :
386 : : } // namespace Compile
387 : : } // namespace Rust
|