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 : 129 : ResolvePathRef::Compile (HIR::QualifiedPathInExpression &expr, Context *ctx)
37 : : {
38 : 129 : ResolvePathRef resolver (ctx);
39 : 129 : return resolver.resolve_path_like (expr);
40 : 129 : }
41 : :
42 : : tree
43 : 34483 : ResolvePathRef::Compile (HIR::PathInExpression &expr, Context *ctx)
44 : : {
45 : 34483 : ResolvePathRef resolver (ctx);
46 : 34483 : return resolver.resolve_path_like (expr);
47 : 34483 : }
48 : :
49 : 34612 : ResolvePathRef::ResolvePathRef (Context *ctx) : HIRCompileBase (ctx) {}
50 : :
51 : : template <typename T>
52 : : tree
53 : 34612 : ResolvePathRef::resolve_path_like (T &expr)
54 : : {
55 : 34612 : if (expr.is_lang_item ())
56 : : {
57 : : auto lang_item
58 : 38 : = Analysis::Mappings::get ().get_lang_item_node (expr.get_lang_item ());
59 : :
60 : : // FIXME: Is that correct? :/
61 : 38 : auto final_segment
62 : 76 : = HIR::PathIdentSegment (LangItem::ToString (expr.get_lang_item ()));
63 : :
64 : 38 : return resolve_with_node_id (final_segment, expr.get_mappings (),
65 : : expr.get_locus (), true, lang_item);
66 : 38 : }
67 : :
68 : 34574 : return resolve (expr.get_final_segment ().get_segment (),
69 : 34574 : expr.get_mappings (), expr.get_locus (), true);
70 : : }
71 : :
72 : : tree
73 : 624 : 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 : 624 : if (lookup->get_kind () != TyTy::TypeKind::ADT)
79 : 3 : return error_mark_node;
80 : :
81 : 621 : TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (lookup);
82 : 621 : if (adt->is_unit ())
83 : 177 : return unit_expression (expr_locus);
84 : :
85 : 444 : if (!adt->is_enum ())
86 : 0 : return error_mark_node;
87 : :
88 : 444 : HirId variant_id;
89 : 444 : if (!ctx->get_tyctx ()->lookup_variant_definition (mappings.get_hirid (),
90 : : &variant_id))
91 : 0 : return error_mark_node;
92 : :
93 : 444 : int union_disriminator = -1;
94 : 444 : TyTy::VariantDef *variant = nullptr;
95 : 444 : 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 : 444 : rust_assert (variant->get_variant_type ()
101 : : == TyTy::VariantDef::VariantType::NUM);
102 : :
103 : : // we need the actual gcc type
104 : 444 : tree compiled_adt_type = TyTyResolveCompile::compile (ctx, adt);
105 : :
106 : : // make the ctor for the union
107 : 444 : HIR::Expr &discrim_expr = variant->get_discriminant ();
108 : 444 : ctx->push_const_context ();
109 : 444 : tree discrim_expr_node = CompileExpr::Compile (discrim_expr, ctx);
110 : 444 : ctx->pop_const_context ();
111 : 444 : tree folded_discrim_expr = fold_expr (discrim_expr_node);
112 : 444 : tree qualifier = folded_discrim_expr;
113 : :
114 : : // false for is enum but this is an enum but we have a new layout
115 : 444 : return Backend::constructor_expression (compiled_adt_type, false, {qualifier},
116 : : -1, expr_locus);
117 : : }
118 : :
119 : : tree
120 : 34189 : 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 : 34189 : TyTy::BaseType *lookup = nullptr;
126 : 34189 : bool ok = ctx->get_tyctx ()->lookup_type (mappings.get_hirid (), &lookup);
127 : 34189 : rust_assert (ok);
128 : :
129 : 34189 : tl::optional<HirId> hid
130 : 34189 : = ctx->get_mappings ().lookup_node_to_hir (resolved_node_id);
131 : 34189 : 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 : 34189 : auto ref = hid.value ();
137 : :
138 : : // might be a constant
139 : 34189 : tree constant_expr;
140 : 34189 : if (ctx->lookup_const_decl (ref, &constant_expr))
141 : : {
142 : 903 : TREE_USED (constant_expr) = 1;
143 : 903 : return constant_expr;
144 : : }
145 : :
146 : : // maybe closure binding
147 : 33286 : tree closure_binding = error_mark_node;
148 : 33286 : if (ctx->lookup_closure_binding (ref, &closure_binding))
149 : : {
150 : 7 : TREE_USED (closure_binding) = 1;
151 : 7 : return closure_binding;
152 : : }
153 : :
154 : : // this might be a variable reference or a function reference
155 : 33279 : Bvariable *var = nullptr;
156 : 33279 : if (ctx->lookup_var_decl (ref, &var))
157 : : {
158 : : // TREE_USED is setup in the gcc abstraction here
159 : 22889 : return Backend::var_expression (var, expr_locus);
160 : : }
161 : :
162 : : // might be a match pattern binding
163 : 10390 : tree binding = error_mark_node;
164 : 10390 : if (ctx->lookup_pattern_binding (ref, &binding))
165 : : {
166 : 392 : TREE_USED (binding) = 1;
167 : 392 : return binding;
168 : : }
169 : :
170 : : // it might be a function call
171 : 9998 : if (lookup->get_kind () == TyTy::TypeKind::FNDEF)
172 : : {
173 : 9659 : TyTy::FnType *fntype = static_cast<TyTy::FnType *> (lookup);
174 : 9659 : tree fn = NULL_TREE;
175 : 9659 : if (ctx->lookup_function_decl (fntype->get_ty_ref (), &fn))
176 : : {
177 : 4227 : TREE_USED (fn) = 1;
178 : 7848 : return address_expression (fn, expr_locus);
179 : : }
180 : 5432 : else if (fntype->get_abi () == ABI::INTRINSIC)
181 : : {
182 : 3621 : Intrinsics compile (ctx);
183 : 3621 : fn = compile.compile (fntype);
184 : 3621 : TREE_USED (fn) = 1;
185 : 3621 : return address_expression (fn, expr_locus);
186 : : }
187 : : }
188 : :
189 : : // Handle unit struct
190 : 2150 : if (lookup->get_kind () == TyTy::TypeKind::ADT)
191 : 201 : return attempt_constructor_expression_lookup (lookup, ctx, mappings,
192 : 201 : expr_locus);
193 : :
194 : : // let the query system figure it out
195 : 1949 : tree resolved_item = query_compile (ref, lookup, final_segment, mappings,
196 : : expr_locus, is_qualified_path);
197 : 1949 : if (resolved_item != error_mark_node)
198 : : {
199 : 1878 : TREE_USED (resolved_item) = 1;
200 : : }
201 : :
202 : : return resolved_item;
203 : : }
204 : :
205 : : tree
206 : 34574 : ResolvePathRef::resolve (const HIR::PathIdentSegment &final_segment,
207 : : const Analysis::NodeMapping &mappings,
208 : : location_t expr_locus, bool is_qualified_path)
209 : : {
210 : 34574 : TyTy::BaseType *lookup = nullptr;
211 : 34574 : bool ok = ctx->get_tyctx ()->lookup_type (mappings.get_hirid (), &lookup);
212 : 34574 : rust_assert (ok);
213 : :
214 : : // need to look up the reference for this identifier
215 : :
216 : : // this can fail because it might be a Constructor for something
217 : : // in that case the caller should attempt ResolvePathType::Compile
218 : 34574 : NodeId ref_node_id = UNKNOWN_NODEID;
219 : 34574 : if (flag_name_resolution_2_0)
220 : : {
221 : 3587 : auto &nr_ctx
222 : 3587 : = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
223 : :
224 : 3587 : auto resolved = nr_ctx.lookup (mappings.get_nodeid ());
225 : :
226 : 3587 : if (!resolved)
227 : 0 : return attempt_constructor_expression_lookup (lookup, ctx, mappings,
228 : 0 : expr_locus);
229 : :
230 : 3587 : ref_node_id = *resolved;
231 : : }
232 : : else
233 : : {
234 : 30987 : if (!ctx->get_resolver ()->lookup_resolved_name (mappings.get_nodeid (),
235 : : &ref_node_id))
236 : 423 : return attempt_constructor_expression_lookup (lookup, ctx, mappings,
237 : 423 : expr_locus);
238 : : }
239 : :
240 : 34151 : return resolve_with_node_id (final_segment, mappings, expr_locus,
241 : 34151 : is_qualified_path, ref_node_id);
242 : : }
243 : :
244 : : tree
245 : 1949 : HIRCompileBase::query_compile (HirId ref, TyTy::BaseType *lookup,
246 : : const HIR::PathIdentSegment &final_segment,
247 : : const Analysis::NodeMapping &mappings,
248 : : location_t expr_locus, bool is_qualified_path)
249 : : {
250 : 1949 : bool is_fn = lookup->get_kind () == TyTy::TypeKind::FNDEF;
251 : 1949 : if (auto resolved_item = ctx->get_mappings ().lookup_hir_item (ref))
252 : : {
253 : 873 : if (!lookup->has_substitutions_defined ())
254 : 1880 : return CompileItem::compile (*resolved_item, ctx, nullptr, expr_locus);
255 : : else
256 : 715 : return CompileItem::compile (*resolved_item, ctx, lookup, expr_locus);
257 : : }
258 : 1076 : else if (auto hir_extern_item
259 : 1076 : = ctx->get_mappings ().lookup_hir_extern_item (ref))
260 : : {
261 : 18 : HIR::ExternalItem *resolved_extern_item = hir_extern_item->first;
262 : 18 : if (!lookup->has_substitutions_defined ())
263 : 18 : return CompileExternItem::compile (resolved_extern_item, ctx, nullptr,
264 : 1007 : expr_locus);
265 : : else
266 : 0 : return CompileExternItem::compile (resolved_extern_item, ctx, lookup,
267 : 0 : expr_locus);
268 : : }
269 : : else
270 : : {
271 : 1058 : if (is_fn)
272 : : {
273 : 987 : TyTy::FnType *fn = static_cast<TyTy::FnType *> (lookup);
274 : 987 : TyTy::BaseType *receiver = nullptr;
275 : :
276 : 1830 : if (fn->is_method ())
277 : : {
278 : 247 : receiver = fn->get_self_type ();
279 : 247 : receiver = receiver->destructure ();
280 : :
281 : 247 : return resolve_method_address (fn, receiver, expr_locus);
282 : : }
283 : : }
284 : :
285 : 811 : if (auto resolved_item = ctx->get_mappings ().lookup_hir_implitem (ref))
286 : : {
287 : 528 : if (!lookup->has_substitutions_defined ())
288 : 330 : return CompileInherentImplItem::Compile (resolved_item->first, ctx,
289 : 742 : nullptr, expr_locus);
290 : : else
291 : 198 : return CompileInherentImplItem::Compile (resolved_item->first, ctx,
292 : 198 : lookup, expr_locus);
293 : : }
294 : 283 : else if (auto trait_item
295 : 283 : = ctx->get_mappings ().lookup_hir_trait_item (ref))
296 : : {
297 : 214 : HIR::Trait *trait = ctx->get_mappings ().lookup_trait_item_mapping (
298 : 214 : trait_item.value ()->get_mappings ().get_hirid ());
299 : :
300 : 214 : Resolver::TraitReference *trait_ref
301 : 214 : = &Resolver::TraitReference::error_node ();
302 : 214 : bool ok = ctx->get_tyctx ()->lookup_trait_reference (
303 : 214 : trait->get_mappings ().get_defid (), &trait_ref);
304 : 214 : rust_assert (ok);
305 : :
306 : 214 : if (trait_item.value ()->get_item_kind ()
307 : : == HIR::TraitItem::TraitItemKind::CONST)
308 : : {
309 : 2 : auto &c
310 : 2 : = *static_cast<HIR::TraitItemConst *> (trait_item.value ());
311 : 2 : if (!c.has_expr ())
312 : : {
313 : 2 : rich_location r (line_table, expr_locus);
314 : 2 : r.add_range (trait->get_locus ());
315 : 2 : r.add_range (c.get_locus ());
316 : 2 : rust_error_at (r, "no default expression on trait constant");
317 : 2 : return error_mark_node;
318 : 2 : }
319 : :
320 : 0 : return CompileExpr::Compile (c.get_expr (), ctx);
321 : : }
322 : :
323 : 212 : if (trait_item.value ()->get_item_kind ()
324 : : != HIR::TraitItem::TraitItemKind::FUNC)
325 : 0 : return error_mark_node;
326 : :
327 : : // the type resolver can only resolve type bounds to their trait
328 : : // item so its up to us to figure out if this path should resolve
329 : : // to an trait-impl-block-item or if it can be defaulted to the
330 : : // trait-impl-item's definition
331 : : //
332 : : // because we know this is resolved to a trait item we can actually
333 : : // just grab the Self type parameter here for the receiver to match
334 : : // the appropriate impl block
335 : :
336 : 212 : rust_assert (lookup->is<TyTy::FnType> ());
337 : 212 : auto fn = lookup->as<TyTy::FnType> ();
338 : 212 : rust_assert (fn->get_num_type_params () > 0);
339 : 212 : auto &self = fn->get_substs ().at (0);
340 : 212 : auto receiver = self.get_param_ty ();
341 : 212 : auto candidates
342 : : = Resolver::PathProbeImplTrait::Probe (receiver, final_segment,
343 : 212 : trait_ref);
344 : 212 : if (candidates.size () == 0)
345 : : {
346 : : // this means we are defaulting back to the trait_item if
347 : : // possible
348 : 126 : Resolver::TraitItemReference *trait_item_ref = nullptr;
349 : 126 : bool ok = trait_ref->lookup_hir_trait_item (*trait_item.value (),
350 : : &trait_item_ref);
351 : 126 : rust_assert (ok); // found
352 : 126 : rust_assert (trait_item_ref->is_optional ()); // has definition
353 : :
354 : 126 : return CompileTraitItem::Compile (
355 : : trait_item_ref->get_hir_trait_item (), ctx, lookup, true,
356 : : expr_locus);
357 : : }
358 : : else
359 : : {
360 : 86 : rust_assert (candidates.size () == 1);
361 : :
362 : 86 : auto candidate = *candidates.begin ();
363 : 86 : rust_assert (candidate.is_impl_candidate ());
364 : :
365 : 86 : HIR::ImplBlock *impl = candidate.item.impl.parent;
366 : 86 : HIR::ImplItem *impl_item = candidate.item.impl.impl_item;
367 : :
368 : 86 : TyTy::BaseType *self = nullptr;
369 : 172 : bool ok = ctx->get_tyctx ()->lookup_type (
370 : 86 : impl->get_type ().get_mappings ().get_hirid (), &self);
371 : 86 : rust_assert (ok);
372 : :
373 : 86 : if (!lookup->has_substitutions_defined ())
374 : 0 : return CompileInherentImplItem::Compile (impl_item, ctx,
375 : 0 : nullptr, expr_locus);
376 : : else
377 : 86 : return CompileInherentImplItem::Compile (impl_item, ctx, lookup,
378 : 86 : expr_locus);
379 : : }
380 : 212 : }
381 : : }
382 : :
383 : 69 : return error_mark_node;
384 : : }
385 : :
386 : : } // namespace Compile
387 : : } // namespace Rust
|