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