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-impl-trait.h"
28 : #include "rust-compile-extern.h"
29 : #include "rust-constexpr.h"
30 : #include "rust-rib.h"
31 : #include "rust-tyty.h"
32 :
33 : namespace Rust {
34 : namespace Compile {
35 :
36 : tree
37 121 : ResolvePathRef::Compile (HIR::QualifiedPathInExpression &expr, Context *ctx)
38 : {
39 121 : ResolvePathRef resolver (ctx);
40 121 : return resolver.resolve_path_like (expr);
41 121 : }
42 :
43 : tree
44 46822 : ResolvePathRef::Compile (HIR::PathInExpression &expr, Context *ctx)
45 : {
46 46822 : ResolvePathRef resolver (ctx);
47 46822 : return resolver.resolve_path_like (expr);
48 46822 : }
49 :
50 46943 : ResolvePathRef::ResolvePathRef (Context *ctx) : HIRCompileBase (ctx) {}
51 :
52 : template <typename T>
53 : tree
54 46943 : ResolvePathRef::resolve_path_like (T &expr)
55 : {
56 46943 : if (expr.is_lang_item ())
57 : {
58 : auto lang_item
59 55 : = Analysis::Mappings::get ().get_lang_item_node (expr.get_lang_item ());
60 :
61 : // FIXME: Is that correct? :/
62 55 : auto final_segment
63 110 : = HIR::PathIdentSegment (LangItem::ToString (expr.get_lang_item ()));
64 :
65 55 : return resolve_with_node_id (final_segment, expr.get_mappings (),
66 : expr.get_locus (), true, lang_item);
67 55 : }
68 :
69 46888 : return resolve (expr.get_final_segment ().get_segment (),
70 46888 : expr.get_mappings (), expr.get_locus (), true);
71 : }
72 :
73 : tree
74 1398 : ResolvePathRef::attempt_constructor_expression_lookup (
75 : TyTy::BaseType *lookup, Context *ctx, const Analysis::NodeMapping &mappings,
76 : location_t expr_locus)
77 : {
78 : // it might be an enum data-less enum variant
79 1398 : if (lookup->get_kind () != TyTy::TypeKind::ADT)
80 2 : return error_mark_node;
81 :
82 1396 : TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (lookup);
83 1396 : if (adt->is_unit ())
84 : {
85 228 : tree compiled_adt_type = TyTyResolveCompile::compile (ctx, adt);
86 228 : return Backend::constructor_expression (compiled_adt_type, false, {}, -1,
87 : expr_locus);
88 : }
89 :
90 1168 : if (!adt->is_enum ())
91 3 : return error_mark_node;
92 :
93 1165 : HirId variant_id;
94 1165 : if (!ctx->get_tyctx ()->lookup_variant_definition (mappings.get_hirid (),
95 : &variant_id))
96 0 : return error_mark_node;
97 :
98 1165 : int union_disriminator = -1;
99 1165 : TyTy::VariantDef *variant = nullptr;
100 1165 : if (!adt->lookup_variant_by_id (variant_id, &variant, &union_disriminator))
101 0 : return error_mark_node;
102 :
103 : // this can only be for discriminant variants the others are built up
104 : // using call-expr or struct-init
105 1165 : if (variant->get_variant_type () != TyTy::VariantDef::VariantType::NUM)
106 : {
107 1 : rust_error_at (expr_locus, "variant expected constructor call");
108 1 : return error_mark_node;
109 : }
110 :
111 : // we need the actual gcc type
112 1164 : tree compiled_adt_type = TyTyResolveCompile::compile (ctx, adt);
113 :
114 : // make the ctor for the union
115 1164 : HIR::Expr &discrim_expr = variant->get_discriminant ();
116 1164 : ctx->push_const_context ();
117 1164 : tree discrim_expr_node = CompileExpr::Compile (discrim_expr, ctx);
118 1164 : ctx->pop_const_context ();
119 1164 : tree folded_discrim_expr = fold_expr (discrim_expr_node);
120 1164 : tree qualifier = folded_discrim_expr;
121 :
122 : // false for is enum but this is an enum but we have a new layout
123 1164 : return Backend::constructor_expression (compiled_adt_type, false, {qualifier},
124 : -1, expr_locus);
125 : }
126 :
127 : tree
128 46941 : ResolvePathRef::resolve_with_node_id (
129 : const HIR::PathIdentSegment &final_segment,
130 : const Analysis::NodeMapping &mappings, location_t expr_locus,
131 : bool is_qualified_path, NodeId resolved_node_id)
132 : {
133 46941 : TyTy::BaseType *lookup = nullptr;
134 46941 : bool ok = ctx->get_tyctx ()->lookup_type (mappings.get_hirid (), &lookup);
135 46941 : rust_assert (ok);
136 :
137 46941 : tl::optional<HirId> hid
138 46941 : = ctx->get_mappings ().lookup_node_to_hir (resolved_node_id);
139 46941 : if (!hid.has_value ())
140 0 : return error_mark_node;
141 :
142 46941 : auto ref = hid.value ();
143 :
144 : // might be a constant
145 46941 : tree constant_expr;
146 46941 : if (ctx->lookup_const_decl (ref, &constant_expr))
147 : {
148 588 : TREE_USED (constant_expr) = 1;
149 588 : return constant_expr;
150 : }
151 :
152 : // maybe closure binding
153 46353 : tree closure_binding = error_mark_node;
154 46353 : if (ctx->lookup_closure_binding (ref, &closure_binding))
155 : {
156 14 : TREE_USED (closure_binding) = 1;
157 14 : return closure_binding;
158 : }
159 :
160 : // this might be a variable reference or a function reference
161 46339 : Bvariable *var = nullptr;
162 46339 : if (ctx->lookup_var_decl (ref, &var))
163 : {
164 : // TREE_USED is setup in the gcc abstraction here
165 32498 : return Backend::var_expression (var, expr_locus);
166 : }
167 :
168 : // might be a match pattern binding
169 13841 : tree binding = error_mark_node;
170 13841 : if (ctx->lookup_pattern_binding (ref, &binding))
171 : {
172 877 : TREE_USED (binding) = 1;
173 877 : return binding;
174 : }
175 :
176 : // it might be a function call
177 12964 : if (lookup->get_kind () == TyTy::TypeKind::FNDEF)
178 : {
179 11414 : TyTy::FnType *fntype = static_cast<TyTy::FnType *> (lookup);
180 11414 : tree fn = NULL_TREE;
181 11414 : if (ctx->lookup_function_decl (fntype->get_ty_ref (), &fn))
182 : {
183 5871 : TREE_USED (fn) = 1;
184 9202 : return address_expression (fn, expr_locus);
185 : }
186 5543 : else if (fntype->get_abi () == ABI::INTRINSIC)
187 : {
188 3331 : Intrinsics compile (ctx);
189 3331 : fn = compile.compile (fntype, expr_locus);
190 3331 : TREE_USED (fn) = 1;
191 3331 : return address_expression (fn, expr_locus);
192 : }
193 : }
194 :
195 : // possibly a const expr value
196 3762 : if (lookup->get_kind () == TyTy::TypeKind::CONST)
197 : {
198 37 : auto d = lookup->destructure ();
199 37 : rust_assert (d->get_kind () == TyTy::TypeKind::CONST);
200 37 : auto c = d->as_const_type ();
201 37 : if (c->const_kind () != TyTy::BaseConstType::ConstKind::Value)
202 1 : return error_mark_node;
203 :
204 36 : auto val = static_cast<TyTy::ConstValueType *> (c);
205 36 : return val->get_value ();
206 : }
207 :
208 : // Handle unit struct
209 3725 : tree resolved_item = error_mark_node;
210 3725 : if (lookup->get_kind () == TyTy::TypeKind::ADT)
211 1396 : resolved_item
212 1396 : = attempt_constructor_expression_lookup (lookup, ctx, mappings,
213 : expr_locus);
214 :
215 3725 : if (!error_operand_p (resolved_item))
216 : return resolved_item;
217 :
218 : // let the query system figure it out
219 2334 : resolved_item = query_compile (ref, lookup, final_segment, mappings,
220 : expr_locus, is_qualified_path);
221 2334 : if (resolved_item != error_mark_node)
222 2328 : TREE_USED (resolved_item) = 1;
223 :
224 : return resolved_item;
225 : }
226 :
227 : tree
228 46888 : ResolvePathRef::resolve (const HIR::PathIdentSegment &final_segment,
229 : const Analysis::NodeMapping &mappings,
230 : location_t expr_locus, bool is_qualified_path)
231 : {
232 46888 : TyTy::BaseType *lookup = nullptr;
233 46888 : bool ok = ctx->get_tyctx ()->lookup_type (mappings.get_hirid (), &lookup);
234 46888 : if (!ok)
235 0 : return error_mark_node;
236 :
237 : // need to look up the reference for this identifier
238 :
239 : // this can fail because it might be a Constructor for something
240 : // in that case the caller should attempt ResolvePathType::Compile
241 46888 : auto &nr_ctx = Resolver2_0::FinalizedNameResolutionContext::get ();
242 :
243 : // TODO: Is Values the correct NS here?
244 46888 : auto resolved
245 46888 : = nr_ctx.lookup (mappings.get_nodeid (), Resolver2_0::Namespace::Values);
246 :
247 46888 : if (!resolved)
248 2 : return attempt_constructor_expression_lookup (lookup, ctx, mappings,
249 2 : expr_locus);
250 :
251 46886 : return resolve_with_node_id (final_segment, mappings, expr_locus,
252 93772 : is_qualified_path, *resolved);
253 : }
254 :
255 : tree
256 2334 : HIRCompileBase::query_compile (HirId ref, TyTy::BaseType *lookup,
257 : const HIR::PathIdentSegment &final_segment,
258 : const Analysis::NodeMapping &mappings,
259 : location_t expr_locus, bool is_qualified_path)
260 : {
261 2334 : bool is_fn = lookup->get_kind () == TyTy::TypeKind::FNDEF;
262 2334 : if (auto resolved_item = ctx->get_mappings ().hir.items.lookup (ref))
263 : {
264 1012 : if (!lookup->has_substitutions_defined ())
265 2332 : return CompileItem::compile (*resolved_item, ctx, nullptr, expr_locus);
266 : else
267 785 : return CompileItem::compile (*resolved_item, ctx, lookup, expr_locus);
268 : }
269 1322 : else if (auto hir_extern_item
270 1322 : = ctx->get_mappings ().lookup_hir_extern_item (ref))
271 : {
272 30 : HIR::ExternalItem *resolved_extern_item = hir_extern_item->first;
273 30 : if (!lookup->has_substitutions_defined ())
274 30 : return CompileExternItem::compile (resolved_extern_item, ctx, nullptr,
275 1320 : expr_locus);
276 : else
277 0 : return CompileExternItem::compile (resolved_extern_item, ctx, lookup,
278 0 : expr_locus);
279 : }
280 : else
281 : {
282 1292 : if (is_fn)
283 : {
284 1288 : TyTy::FnType *fn = static_cast<TyTy::FnType *> (lookup);
285 1288 : TyTy::BaseType *receiver = nullptr;
286 :
287 2421 : if (fn->is_method ())
288 : {
289 419 : receiver = fn->get_self_type ();
290 419 : receiver = receiver->destructure ();
291 :
292 419 : return resolve_method_address (fn, receiver, expr_locus);
293 : }
294 : }
295 :
296 873 : if (auto resolved_item = ctx->get_mappings ().lookup_hir_implitem (ref))
297 : {
298 618 : if (!lookup->has_substitutions_defined ())
299 384 : return CompileInherentImplItem::Compile (resolved_item->first, ctx,
300 871 : nullptr, expr_locus);
301 : else
302 234 : return CompileInherentImplItem::Compile (resolved_item->first, ctx,
303 234 : lookup, expr_locus);
304 : }
305 255 : else if (auto trait_item
306 255 : = ctx->get_mappings ().hir.trait_items.lookup (ref))
307 : {
308 253 : HIR::Trait *trait = ctx->get_mappings ().lookup_trait_item_mapping (
309 253 : trait_item.value ()->get_mappings ().get_hirid ());
310 :
311 253 : Resolver::TraitReference *trait_ref
312 253 : = &Resolver::TraitReference::error_node ();
313 253 : bool ok = ctx->get_tyctx ()->lookup_trait_reference (
314 253 : trait->get_mappings ().get_defid (), &trait_ref);
315 253 : rust_assert (ok);
316 :
317 253 : if (trait_item.value ()->get_item_kind ()
318 : == HIR::TraitItem::TraitItemKind::CONST)
319 : {
320 2 : auto &c
321 2 : = *static_cast<HIR::TraitItemConst *> (trait_item.value ());
322 2 : if (!c.has_expr ())
323 : {
324 2 : rich_location r (line_table, expr_locus);
325 2 : r.add_range (trait->get_locus ());
326 2 : r.add_range (c.get_locus ());
327 2 : rust_error_at (r, "no default expression on trait constant");
328 2 : return error_mark_node;
329 2 : }
330 :
331 0 : return CompileExpr::Compile (c.get_expr (), ctx);
332 : }
333 :
334 251 : if (trait_item.value ()->get_item_kind ()
335 : != HIR::TraitItem::TraitItemKind::FUNC)
336 0 : return error_mark_node;
337 :
338 : // the type resolver can only resolve type bounds to their trait
339 : // item so its up to us to figure out if this path should resolve
340 : // to an trait-impl-block-item or if it can be defaulted to the
341 : // trait-impl-item's definition
342 : //
343 : // because we know this is resolved to a trait item we can actually
344 : // just grab the Self type parameter here for the receiver to match
345 : // the appropriate impl block
346 :
347 251 : rust_assert (lookup->is<TyTy::FnType> ());
348 251 : auto fn = lookup->as<TyTy::FnType> ();
349 251 : rust_assert (fn->get_num_type_params () > 0);
350 251 : TyTy::SubstitutionParamMapping &self = fn->get_substs ().at (0);
351 251 : TyTy::BaseGeneric *receiver = self.get_param_ty ();
352 251 : TyTy::BaseType *r = receiver;
353 251 : if (!receiver->can_resolve ())
354 : {
355 117 : bool ok
356 117 : = ctx->get_tyctx ()->lookup_type (receiver->get_ref (), &r);
357 117 : rust_assert (ok);
358 : }
359 :
360 251 : auto candidates
361 251 : = Resolver::PathProbeImplTrait::Probe (r, final_segment, trait_ref);
362 251 : if (candidates.size () == 0)
363 : {
364 : // this means we are defaulting back to the trait_item if
365 : // possible
366 110 : Resolver::TraitItemReference *trait_item_ref = nullptr;
367 110 : bool ok = trait_ref->lookup_hir_trait_item (*trait_item.value (),
368 : &trait_item_ref);
369 110 : rust_assert (ok); // found
370 110 : rust_assert (trait_item_ref->is_optional ()); // has definition
371 :
372 110 : return CompileTraitItem::Compile (
373 : trait_item_ref->get_hir_trait_item (), ctx, lookup, true,
374 : expr_locus);
375 : }
376 : else
377 : {
378 141 : rust_assert (candidates.size () == 1);
379 :
380 141 : auto candidate = *candidates.begin ();
381 141 : rust_assert (candidate.is_impl_candidate ());
382 :
383 141 : HIR::ImplBlock *impl = candidate.item.impl.parent;
384 141 : HIR::ImplItem *impl_item = candidate.item.impl.impl_item;
385 :
386 141 : TyTy::BaseType *self = nullptr;
387 282 : bool ok = ctx->get_tyctx ()->lookup_type (
388 141 : impl->get_type ().get_mappings ().get_hirid (), &self);
389 141 : rust_assert (ok);
390 :
391 141 : if (!lookup->has_substitutions_defined ())
392 0 : return CompileInherentImplItem::Compile (impl_item, ctx,
393 0 : nullptr, expr_locus);
394 : else
395 141 : return CompileInherentImplItem::Compile (impl_item, ctx, lookup,
396 141 : expr_locus);
397 : }
398 251 : }
399 : }
400 :
401 2 : return error_mark_node;
402 : }
403 :
404 : } // namespace Compile
405 : } // namespace Rust
|