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 : 41349 : ResolvePathRef::Compile (HIR::PathInExpression &expr, Context *ctx)
44 : : {
45 : 41349 : ResolvePathRef resolver (ctx);
46 : 41349 : return resolver.resolve_path_like (expr);
47 : 41349 : }
48 : :
49 : 41462 : ResolvePathRef::ResolvePathRef (Context *ctx) : HIRCompileBase (ctx) {}
50 : :
51 : : template <typename T>
52 : : tree
53 : 41462 : ResolvePathRef::resolve_path_like (T &expr)
54 : : {
55 : 41462 : 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 : 41428 : return resolve (expr.get_final_segment ().get_segment (),
69 : 41428 : expr.get_mappings (), expr.get_locus (), true);
70 : : }
71 : :
72 : : tree
73 : 1272 : 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 : 1272 : if (lookup->get_kind () != TyTy::TypeKind::ADT)
79 : 0 : return error_mark_node;
80 : :
81 : 1272 : TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (lookup);
82 : 1272 : if (adt->is_unit ())
83 : 181 : 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 : 41462 : 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 : 41462 : TyTy::BaseType *lookup = nullptr;
129 : 41462 : bool ok = ctx->get_tyctx ()->lookup_type (mappings.get_hirid (), &lookup);
130 : 41462 : rust_assert (ok);
131 : :
132 : 41462 : tl::optional<HirId> hid
133 : 41462 : = ctx->get_mappings ().lookup_node_to_hir (resolved_node_id);
134 : 41462 : if (!hid.has_value ())
135 : 0 : return error_mark_node;
136 : :
137 : 41462 : auto ref = hid.value ();
138 : :
139 : : // might be a constant
140 : 41462 : tree constant_expr;
141 : 41462 : 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 : 40886 : tree closure_binding = error_mark_node;
149 : 40886 : 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 : 40872 : Bvariable *var = nullptr;
157 : 40872 : if (ctx->lookup_var_decl (ref, &var))
158 : : {
159 : : // TREE_USED is setup in the gcc abstraction here
160 : 29618 : return Backend::var_expression (var, expr_locus);
161 : : }
162 : :
163 : : // might be a match pattern binding
164 : 11254 : tree binding = error_mark_node;
165 : 11254 : if (ctx->lookup_pattern_binding (ref, &binding))
166 : : {
167 : 824 : TREE_USED (binding) = 1;
168 : 824 : return binding;
169 : : }
170 : :
171 : : // it might be a function call
172 : 10430 : if (lookup->get_kind () == TyTy::TypeKind::FNDEF)
173 : : {
174 : 9014 : TyTy::FnType *fntype = static_cast<TyTy::FnType *> (lookup);
175 : 9014 : tree fn = NULL_TREE;
176 : 9014 : if (ctx->lookup_function_decl (fntype->get_ty_ref (), &fn))
177 : : {
178 : 4882 : TREE_USED (fn) = 1;
179 : 7061 : 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 : 3369 : 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 : 3334 : tree resolved_item = error_mark_node;
203 : 3334 : if (lookup->get_kind () == TyTy::TypeKind::ADT)
204 : 1272 : resolved_item
205 : 1272 : = attempt_constructor_expression_lookup (lookup, ctx, mappings,
206 : : expr_locus);
207 : :
208 : 3334 : 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 : 41428 : ResolvePathRef::resolve (const HIR::PathIdentSegment &final_segment,
222 : : const Analysis::NodeMapping &mappings,
223 : : location_t expr_locus, bool is_qualified_path)
224 : : {
225 : 41428 : TyTy::BaseType *lookup = nullptr;
226 : 41428 : bool ok = ctx->get_tyctx ()->lookup_type (mappings.get_hirid (), &lookup);
227 : 41428 : 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 : 41428 : auto &nr_ctx
235 : 41428 : = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
236 : :
237 : 41428 : auto resolved = nr_ctx.lookup (mappings.get_nodeid ());
238 : :
239 : 41428 : if (!resolved)
240 : 0 : return attempt_constructor_expression_lookup (lookup, ctx, mappings,
241 : 0 : expr_locus);
242 : :
243 : 41428 : return resolve_with_node_id (final_segment, mappings, expr_locus,
244 : 82856 : 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
|