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