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-hir-path-probe-expr.h"
20 : #include "rust-hir-item.h"
21 : #include "rust-type-util.h"
22 : #include "rust-hir-type-bounds.h"
23 :
24 : namespace Rust {
25 : namespace Resolver {
26 :
27 1555 : PathProbeExpr::PathProbeExpr (TyTy::BaseType *receiver,
28 : const HIR::PathIdentSegment &query)
29 1555 : : TypeCheckBase (), receiver (receiver), search (query)
30 1555 : {}
31 :
32 : std::set<PathProbeCandidate>
33 1555 : PathProbeExpr::Probe (TyTy::BaseType *receiver,
34 : const HIR::PathIdentSegment &segment_name)
35 : {
36 1555 : PathProbeExpr probe (receiver, segment_name);
37 1555 : return probe.probe ();
38 1555 : }
39 :
40 : std::set<PathProbeCandidate>
41 1555 : PathProbeExpr::probe ()
42 : {
43 1555 : switch (receiver->get_kind ())
44 : {
45 92 : case TyTy::TypeKind::PARAM:
46 92 : probe_bounds ();
47 92 : return std::move (candidates);
48 :
49 617 : case TyTy::TypeKind::ADT:
50 617 : {
51 617 : auto *adt = static_cast<TyTy::ADTType *> (receiver);
52 617 : if (adt->is_enum ())
53 4 : process_enum_item_for_candidates (adt);
54 617 : probe_adt_impls (adt);
55 617 : break;
56 : }
57 :
58 846 : default:
59 846 : probe_fallback_impls ();
60 846 : break;
61 : }
62 :
63 1463 : if (candidates.empty ())
64 462 : probe_bounds ();
65 :
66 1463 : return std::move (candidates);
67 : }
68 :
69 : void
70 617 : PathProbeExpr::probe_adt_impls (TyTy::ADTType *adt)
71 : {
72 617 : auto adt_item = mappings.lookup_defid (adt->get_id ());
73 617 : if (!adt_item.has_value ())
74 : {
75 0 : probe_fallback_impls ();
76 478 : return;
77 : }
78 :
79 617 : DefId adt_id = adt_item.value ()->get_mappings ().get_defid ();
80 617 : mappings.iterate_adt_impl_items (
81 : adt_id,
82 617 : [this] (HirId id, HIR::ImplItem *item, HIR::ImplBlock *impl) -> bool {
83 3158 : if (impl->has_trait_ref ())
84 : return true;
85 :
86 1625 : return process_impl_item_candidate (id, item, impl);
87 : });
88 :
89 617 : if (!candidates.empty ())
90 : return;
91 :
92 139 : mappings.iterate_adt_impl_items (
93 : adt_id,
94 278 : [this] (HirId id, HIR::ImplItem *item, HIR::ImplBlock *impl) -> bool {
95 247 : if (!impl->has_trait_ref ())
96 : return true;
97 :
98 247 : return process_impl_item_candidate (id, item, impl);
99 : });
100 : }
101 :
102 : void
103 846 : PathProbeExpr::probe_fallback_impls ()
104 : {
105 846 : mappings.iterate_impl_items (
106 846 : [this] (HirId id, HIR::ImplItem *item, HIR::ImplBlock *impl) -> bool {
107 54654 : if (impl->has_trait_ref ())
108 : return true;
109 :
110 24040 : return process_impl_item_candidate (id, item, impl);
111 : });
112 :
113 846 : if (!candidates.empty ())
114 : return;
115 :
116 445 : mappings.iterate_impl_items (
117 890 : [this] (HirId id, HIR::ImplItem *item, HIR::ImplBlock *impl) -> bool {
118 18203 : if (!impl->has_trait_ref ())
119 : return true;
120 :
121 13246 : return process_impl_item_candidate (id, item, impl);
122 : });
123 : }
124 :
125 : void
126 4 : PathProbeExpr::process_enum_item_for_candidates (const TyTy::ADTType *adt)
127 : {
128 4 : TyTy::VariantDef *v;
129 8 : if (!adt->lookup_variant (search.to_string (), &v))
130 : return;
131 :
132 1 : PathProbeCandidate::EnumItemCandidate enum_item_candidate{adt, v};
133 1 : PathProbeCandidate candidate{PathProbeCandidate::CandidateType::ENUM_VARIANT,
134 1 : receiver->clone (),
135 1 : mappings.lookup_location (adt->get_ty_ref ()),
136 1 : enum_item_candidate};
137 1 : candidates.insert (std::move (candidate));
138 : }
139 :
140 : bool
141 39158 : PathProbeExpr::process_impl_item_candidate (HirId id, HIR::ImplItem *item,
142 : HIR::ImplBlock *impl)
143 : {
144 78316 : if (search.to_string () != item->get_impl_item_name ())
145 : return true;
146 :
147 5770 : HirId impl_ty_id = impl->get_type ().get_mappings ().get_hirid ();
148 5770 : TyTy::BaseType *impl_block_ty = nullptr;
149 5770 : if (!query_type (impl_ty_id, &impl_block_ty))
150 : return true;
151 :
152 5770 : if (!types_compatable (TyTy::TyWithLocation (receiver),
153 5770 : TyTy::TyWithLocation (impl_block_ty),
154 : impl->get_locus (), false))
155 : return true;
156 :
157 1001 : PathProbeCandidate::CandidateType candidate_type;
158 1001 : switch (item->get_impl_item_type ())
159 : {
160 : case HIR::ImplItem::FUNCTION:
161 : candidate_type = PathProbeCandidate::CandidateType::IMPL_FUNC;
162 : break;
163 54 : case HIR::ImplItem::CONSTANT:
164 54 : candidate_type = PathProbeCandidate::CandidateType::IMPL_CONST;
165 54 : break;
166 : case HIR::ImplItem::TYPE_ALIAS:
167 : default:
168 : return true;
169 : }
170 :
171 1001 : TyTy::BaseType *item_ty = nullptr;
172 1001 : if (!query_type (id, &item_ty))
173 : return true;
174 :
175 1001 : PathProbeCandidate::ImplItemCandidate impl_candidate{item, impl};
176 1001 : insert_candidate (
177 1001 : {candidate_type, item_ty, item->get_locus (), impl_candidate});
178 :
179 1001 : return true;
180 : }
181 :
182 : void
183 554 : PathProbeExpr::probe_bounds ()
184 : {
185 554 : if (!is_receiver_generic ())
186 : {
187 61 : auto probed_bounds = TypeBoundsProbe::Probe (receiver);
188 206 : for (auto &candidate : probed_bounds)
189 : {
190 145 : const TraitReference *trait_ref = candidate.first;
191 145 : process_associated_trait_for_candidates (trait_ref, candidate.second);
192 : }
193 61 : }
194 :
195 579 : for (const TyTy::TypeBoundPredicate &predicate :
196 1133 : receiver->get_specified_bounds ())
197 : {
198 579 : process_predicate_for_candidates (predicate);
199 : }
200 554 : }
201 :
202 : void
203 145 : PathProbeExpr::process_associated_trait_for_candidates (
204 : const TraitReference *trait_ref, HIR::ImplBlock *impl)
205 : {
206 145 : const TraitItemReference *trait_item_ref = nullptr;
207 290 : if (!trait_ref->lookup_trait_item (search.to_string (), &trait_item_ref))
208 72 : return;
209 :
210 73 : PathProbeCandidate::CandidateType candidate_type;
211 73 : switch (trait_item_ref->get_trait_item_type ())
212 : {
213 : case TraitItemReference::TraitItemType::FN:
214 : candidate_type = PathProbeCandidate::CandidateType::TRAIT_FUNC;
215 : break;
216 0 : case TraitItemReference::TraitItemType::CONST:
217 0 : candidate_type = PathProbeCandidate::CandidateType::TRAIT_ITEM_CONST;
218 0 : break;
219 : case TraitItemReference::TraitItemType::TYPE:
220 : return;
221 :
222 0 : case TraitItemReference::TraitItemType::ERROR:
223 0 : default:
224 0 : rust_unreachable ();
225 73 : break;
226 : }
227 :
228 73 : const TyTy::TypeBoundPredicate p (*trait_ref, BoundPolarity::RegularBound,
229 73 : UNDEF_LOCATION);
230 146 : TyTy::TypeBoundPredicateItem item (p, trait_item_ref);
231 :
232 73 : TyTy::BaseType *trait_item_tyty = item.get_raw_item ()->get_tyty ();
233 73 : if (receiver->get_kind () != TyTy::DYNAMIC)
234 73 : trait_item_tyty = item.get_tyty_for_receiver (receiver);
235 :
236 73 : PathProbeCandidate::TraitItemCandidate trait_item_candidate{trait_ref,
237 : trait_item_ref,
238 73 : impl};
239 73 : PathProbeCandidate candidate{candidate_type, trait_item_tyty,
240 : trait_item_ref->get_locus (),
241 73 : trait_item_candidate};
242 73 : insert_candidate (std::move (candidate));
243 : }
244 :
245 : void
246 579 : PathProbeExpr::process_predicate_for_candidates (
247 : const TyTy::TypeBoundPredicate &predicate)
248 : {
249 579 : const TraitReference *trait_ref = predicate.get ();
250 :
251 579 : tl::optional<TyTy::TypeBoundPredicateItem> item
252 1158 : = predicate.lookup_associated_item (search.to_string ());
253 579 : if (!item.has_value ())
254 : return;
255 :
256 493 : const TraitItemReference *trait_item_ref = item->get_raw_item ();
257 493 : PathProbeCandidate::CandidateType candidate_type;
258 493 : switch (trait_item_ref->get_trait_item_type ())
259 : {
260 : case TraitItemReference::TraitItemType::FN:
261 : candidate_type = PathProbeCandidate::CandidateType::TRAIT_FUNC;
262 : break;
263 1 : case TraitItemReference::TraitItemType::CONST:
264 1 : candidate_type = PathProbeCandidate::CandidateType::TRAIT_ITEM_CONST;
265 1 : break;
266 : case TraitItemReference::TraitItemType::TYPE:
267 : return;
268 :
269 0 : case TraitItemReference::TraitItemType::ERROR:
270 0 : default:
271 0 : rust_unreachable ();
272 493 : break;
273 : }
274 :
275 493 : TyTy::BaseType *trait_item_tyty = item->get_raw_item ()->get_tyty ();
276 493 : if (receiver->get_kind () != TyTy::DYNAMIC)
277 92 : trait_item_tyty = item->get_tyty_for_receiver (receiver);
278 :
279 493 : PathProbeCandidate::TraitItemCandidate trait_item_candidate{trait_ref,
280 : trait_item_ref,
281 493 : nullptr};
282 493 : PathProbeCandidate candidate{candidate_type, trait_item_tyty,
283 : trait_item_ref->get_locus (),
284 493 : trait_item_candidate};
285 493 : insert_candidate (std::move (candidate));
286 579 : }
287 :
288 : void
289 1567 : PathProbeExpr::insert_candidate (PathProbeCandidate candidate)
290 : {
291 1567 : bool is_type
292 1567 : = candidate.type == PathProbeCandidate::CandidateType::IMPL_TYPE_ALIAS
293 1567 : || candidate.type == PathProbeCandidate::CandidateType::TRAIT_TYPE_ALIAS;
294 1567 : if (!candidate.is_error () && !is_type)
295 1567 : candidates.insert (std::move (candidate));
296 1567 : }
297 :
298 : bool
299 554 : PathProbeExpr::is_receiver_generic () const
300 : {
301 554 : const TyTy::BaseType *root = receiver->get_root ();
302 554 : bool receiver_is_type_param = root->get_kind () == TyTy::TypeKind::PARAM;
303 554 : bool receiver_is_dyn = root->get_kind () == TyTy::TypeKind::DYNAMIC;
304 554 : return receiver_is_type_param || receiver_is_dyn;
305 : }
306 :
307 : } // namespace Resolver
308 : } // namespace Rust
|