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-hir-dot-operator.h"
20 : : #include "rust-hir-path-probe.h"
21 : : #include "rust-hir-trait-resolve.h"
22 : : #include "rust-hir-type-check-item.h"
23 : : #include "rust-type-util.h"
24 : : #include "rust-coercion.h"
25 : :
26 : : namespace Rust {
27 : : namespace Resolver {
28 : :
29 : 5854 : MethodResolver::MethodResolver (bool autoderef_flag,
30 : 5854 : const HIR::PathIdentSegment &segment_name)
31 : 5854 : : AutoderefCycle (autoderef_flag), segment_name (segment_name), result ()
32 : 5854 : {}
33 : :
34 : : std::set<MethodCandidate>
35 : 5854 : MethodResolver::Probe (TyTy::BaseType *receiver,
36 : : const HIR::PathIdentSegment &segment_name,
37 : : bool autoderef_flag)
38 : : {
39 : 5854 : MethodResolver resolver (autoderef_flag, segment_name);
40 : 5854 : resolver.cycle (receiver);
41 : 5854 : return resolver.result;
42 : 5854 : }
43 : :
44 : : std::set<MethodCandidate>
45 : 2817 : MethodResolver::Select (std::set<MethodCandidate> &candidates,
46 : : TyTy::BaseType *receiver,
47 : : std::vector<TyTy::BaseType *> arguments)
48 : : {
49 : 2817 : std::set<MethodCandidate> selected;
50 : 4475 : for (auto &candidate : candidates)
51 : : {
52 : 1658 : TyTy::BaseType *candidate_type = candidate.candidate.ty;
53 : 1658 : rust_assert (candidate_type->get_kind () == TyTy::TypeKind::FNDEF);
54 : 1658 : if (candidate_type == nullptr
55 : 1658 : || candidate_type->get_kind () != TyTy::TypeKind::FNDEF)
56 : 0 : continue;
57 : 1658 : TyTy::FnType &fn = *static_cast<TyTy::FnType *> (candidate_type);
58 : :
59 : : // match the number of arguments
60 : 1658 : if (fn.num_params () != (arguments.size () + 1))
61 : 0 : continue;
62 : :
63 : : // match the arguments
64 : 2957 : bool failed = false;
65 : 2957 : for (size_t i = 0; i < arguments.size (); i++)
66 : : {
67 : 1326 : TyTy::BaseType *arg = arguments.at (i);
68 : 1326 : TyTy::BaseType *param = fn.get_params ().at (i + 1).get_type ();
69 : 1326 : TyTy::BaseType *coerced
70 : 1326 : = try_coercion (0, TyTy::TyWithLocation (param),
71 : 1326 : TyTy::TyWithLocation (arg), UNDEF_LOCATION);
72 : 1326 : if (coerced->get_kind () == TyTy::TypeKind::ERROR)
73 : : {
74 : : failed = true;
75 : : break;
76 : : }
77 : : }
78 : :
79 : 1658 : if (!failed)
80 : 1631 : selected.insert (candidate);
81 : : }
82 : :
83 : 2817 : return selected;
84 : : }
85 : :
86 : : void
87 : 6011 : MethodResolver::try_hook (const TyTy::BaseType &r)
88 : : {
89 : 6011 : rust_debug ("MethodResolver::try_hook get_predicate_items: [%s]",
90 : : r.debug_str ().c_str ());
91 : 6011 : const auto &specified_bounds = r.get_specified_bounds ();
92 : 6011 : predicate_items = get_predicate_items (segment_name, r, specified_bounds);
93 : :
94 : 6011 : if (predicate_items.size () > 0)
95 : : return;
96 : :
97 : 5619 : if (r.get_kind () == TyTy::TypeKind::REF)
98 : : {
99 : 1159 : const auto &ref = static_cast<const TyTy::ReferenceType &> (r);
100 : 1159 : const auto &element = ref.get_var_element_type ();
101 : 1159 : const auto &element_ty = *element.get_tyty ();
102 : 1159 : const auto &specified_bounds = element_ty.get_specified_bounds ();
103 : 1159 : predicate_items
104 : 1159 : = get_predicate_items (segment_name, element_ty, specified_bounds);
105 : : }
106 : : }
107 : :
108 : : std::vector<MethodResolver::impl_item_candidate>
109 : 8939 : MethodResolver::assemble_inherent_impl_candidates (
110 : : const TyTy::BaseType &receiver)
111 : : {
112 : 8939 : std::vector<impl_item_candidate> inherent_impl_fns;
113 : 8939 : const TyTy::BaseType *raw = receiver.destructure ();
114 : 8939 : bool receiver_is_raw_ptr = raw->get_kind () == TyTy::TypeKind::POINTER;
115 : 8939 : bool receiver_is_ref = raw->get_kind () == TyTy::TypeKind::REF;
116 : :
117 : : // Assemble inherent impl items (non-trait impl blocks)
118 : 8939 : mappings.iterate_impl_items (
119 : 8939 : [&] (HirId id, HIR::ImplItem *item, HIR::ImplBlock *impl) mutable -> bool {
120 : 237323 : bool is_trait_impl = impl->has_trait_ref ();
121 : 237323 : if (is_trait_impl)
122 : : return true;
123 : :
124 : 77266 : bool is_fn
125 : 77266 : = item->get_impl_item_type () == HIR::ImplItem::ImplItemType::FUNCTION;
126 : 77266 : if (!is_fn)
127 : : return true;
128 : :
129 : 77266 : HIR::Function *func = static_cast<HIR::Function *> (item);
130 : 77266 : if (!func->is_method ())
131 : : return true;
132 : :
133 : 59788 : bool name_matches = func->get_function_name ().as_string ().compare (
134 : 119576 : segment_name.as_string ())
135 : 59788 : == 0;
136 : 59788 : if (!name_matches)
137 : : return true;
138 : :
139 : 6869 : TyTy::BaseType *ty = nullptr;
140 : 6869 : if (!query_type (func->get_mappings ().get_hirid (), &ty))
141 : : return true;
142 : 6869 : if (ty == nullptr || ty->get_kind () == TyTy::TypeKind::ERROR)
143 : 0 : return true;
144 : 6869 : if (ty->get_kind () != TyTy::TypeKind::FNDEF)
145 : : return true;
146 : :
147 : 6869 : TyTy::FnType *fnty = static_cast<TyTy::FnType *> (ty);
148 : 6869 : const TyTy::BaseType *impl_self
149 : 6869 : = TypeCheckItem::ResolveImplBlockSelf (*impl);
150 : :
151 : : // see:
152 : : // https://gcc-rust.zulipchat.com/#narrow/stream/266897-general/topic/Method.20Resolution/near/338646280
153 : : // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/method/probe.rs#L650-L660
154 : 6869 : bool impl_self_is_ptr = impl_self->get_kind () == TyTy::TypeKind::POINTER;
155 : 6869 : bool impl_self_is_ref = impl_self->get_kind () == TyTy::TypeKind::REF;
156 : 6869 : if (receiver_is_raw_ptr && impl_self_is_ptr)
157 : : {
158 : 493 : const TyTy::PointerType &sptr
159 : : = *static_cast<const TyTy::PointerType *> (impl_self);
160 : 493 : const TyTy::PointerType &ptr
161 : 493 : = *static_cast<const TyTy::PointerType *> (raw);
162 : :
163 : : // we could do this via lang-item assemblies if we refactor this
164 : 493 : bool mut_match = sptr.mutability () == ptr.mutability ();
165 : 493 : if (!mut_match)
166 : : return true;
167 : : }
168 : 6376 : else if (receiver_is_ref && impl_self_is_ref)
169 : : {
170 : 0 : const TyTy::ReferenceType &sptr
171 : : = *static_cast<const TyTy::ReferenceType *> (impl_self);
172 : 0 : const TyTy::ReferenceType &ptr
173 : 0 : = *static_cast<const TyTy::ReferenceType *> (raw);
174 : :
175 : : // we could do this via lang-item assemblies if we refactor this
176 : 0 : bool mut_match = sptr.mutability () == ptr.mutability ();
177 : 0 : if (!mut_match)
178 : : return true;
179 : : }
180 : :
181 : 6760 : inherent_impl_fns.emplace_back (func, impl, fnty);
182 : :
183 : 6760 : return true;
184 : : });
185 : :
186 : 8939 : return inherent_impl_fns;
187 : : }
188 : :
189 : : void
190 : 8939 : MethodResolver::assemble_trait_impl_candidates (
191 : : const TyTy::BaseType &receiver,
192 : : std::vector<impl_item_candidate> &impl_candidates,
193 : : std::vector<trait_item_candidate> &trait_candidates)
194 : : {
195 : 8939 : const TyTy::BaseType *raw = receiver.destructure ();
196 : 8939 : bool receiver_is_raw_ptr = raw->get_kind () == TyTy::TypeKind::POINTER;
197 : 8939 : bool receiver_is_ref = raw->get_kind () == TyTy::TypeKind::REF;
198 : :
199 : 8939 : mappings.iterate_impl_blocks ([&] (HirId id,
200 : : HIR::ImplBlock *impl) mutable -> bool {
201 : 131987 : bool is_trait_impl = impl->has_trait_ref ();
202 : 131987 : if (!is_trait_impl)
203 : : return true;
204 : :
205 : : // look for impl implementation else lookup the associated trait item
206 : 242221 : for (auto &impl_item : impl->get_impl_items ())
207 : : {
208 : 149617 : bool is_fn = impl_item->get_impl_item_type ()
209 : 149617 : == HIR::ImplItem::ImplItemType::FUNCTION;
210 : 149617 : if (!is_fn)
211 : 129930 : continue;
212 : :
213 : 115448 : HIR::Function *func = static_cast<HIR::Function *> (impl_item.get ());
214 : 115448 : if (!func->is_method ())
215 : 6742 : continue;
216 : :
217 : 108706 : bool name_matches = func->get_function_name ().as_string ().compare (
218 : 217412 : segment_name.as_string ())
219 : 108706 : == 0;
220 : 108706 : if (!name_matches)
221 : 88764 : continue;
222 : :
223 : 19942 : TyTy::BaseType *ty = nullptr;
224 : 19942 : if (!query_type (func->get_mappings ().get_hirid (), &ty))
225 : 0 : continue;
226 : 19942 : if (ty == nullptr || ty->get_kind () == TyTy::TypeKind::ERROR)
227 : 0 : continue;
228 : 19942 : if (ty->get_kind () != TyTy::TypeKind::FNDEF)
229 : 0 : continue;
230 : :
231 : 19942 : TyTy::FnType *fnty = static_cast<TyTy::FnType *> (ty);
232 : 19942 : const TyTy::BaseType *impl_self
233 : 19942 : = TypeCheckItem::ResolveImplBlockSelf (*impl);
234 : :
235 : : // see:
236 : : // https://gcc-rust.zulipchat.com/#narrow/stream/266897-general/topic/Method.20Resolution/near/338646280
237 : : // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/method/probe.rs#L650-L660
238 : 19942 : bool impl_self_is_ptr
239 : 19942 : = impl_self->get_kind () == TyTy::TypeKind::POINTER;
240 : 19942 : bool impl_self_is_ref = impl_self->get_kind () == TyTy::TypeKind::REF;
241 : 19942 : if (receiver_is_raw_ptr && impl_self_is_ptr)
242 : : {
243 : 0 : const TyTy::PointerType &sptr
244 : : = *static_cast<const TyTy::PointerType *> (impl_self);
245 : 0 : const TyTy::PointerType &ptr
246 : 0 : = *static_cast<const TyTy::PointerType *> (raw);
247 : :
248 : : // we could do this via lang-item assemblies if we refactor this
249 : 0 : bool mut_match = sptr.mutability () == ptr.mutability ();
250 : 0 : if (!mut_match)
251 : 0 : continue;
252 : : }
253 : 19942 : else if (receiver_is_ref && impl_self_is_ref)
254 : : {
255 : 545 : const TyTy::ReferenceType &sptr
256 : : = *static_cast<const TyTy::ReferenceType *> (impl_self);
257 : 545 : const TyTy::ReferenceType &ptr
258 : 545 : = *static_cast<const TyTy::ReferenceType *> (raw);
259 : :
260 : : // we could do this via lang-item assemblies if we refactor this
261 : 545 : bool mut_match = sptr.mutability () == ptr.mutability ();
262 : 545 : if (!mut_match)
263 : 255 : continue;
264 : : }
265 : :
266 : 19687 : impl_candidates.emplace_back (func, impl, fnty);
267 : 19687 : return true;
268 : : }
269 : :
270 : 92604 : TraitReference *trait_ref = TraitResolver::Resolve (impl->get_trait_ref ());
271 : 92604 : rust_assert (!trait_ref->is_error ());
272 : :
273 : 92604 : auto item_ref
274 : 185208 : = trait_ref->lookup_trait_item (segment_name.as_string (),
275 : 92604 : TraitItemReference::TraitItemType::FN);
276 : 92604 : if (item_ref->is_error ())
277 : : return true;
278 : :
279 : 15564 : const HIR::Trait *trait = trait_ref->get_hir_trait_ref ();
280 : 15564 : HIR::TraitItem *item = item_ref->get_hir_trait_item ();
281 : 15564 : if (item->get_item_kind () != HIR::TraitItem::TraitItemKind::FUNC)
282 : : return true;
283 : :
284 : 15564 : HIR::TraitItemFunc *func = static_cast<HIR::TraitItemFunc *> (item);
285 : 15564 : if (!func->get_decl ().is_method ())
286 : : return true;
287 : :
288 : 15561 : TyTy::BaseType *ty = item_ref->get_tyty ();
289 : 15561 : if (ty == nullptr || ty->get_kind () != TyTy::TypeKind::FNDEF)
290 : 0 : return true;
291 : 15561 : TyTy::FnType *fnty = static_cast<TyTy::FnType *> (ty);
292 : :
293 : 15561 : trait_candidates.emplace_back (func, trait, fnty, trait_ref, item_ref);
294 : :
295 : 15561 : return true;
296 : : });
297 : 8939 : }
298 : :
299 : : bool
300 : 8939 : MethodResolver::try_select_predicate_candidates (TyTy::BaseType &receiver)
301 : : {
302 : 8939 : bool found_possible_candidate = false;
303 : 10439 : for (const auto &predicate : predicate_items)
304 : : {
305 : 1500 : const TyTy::FnType *fn = predicate.fntype;
306 : 3000 : if (!fn->is_method ())
307 : 0 : continue;
308 : :
309 : 1500 : TyTy::BaseType *fn_self = fn->get_self_type ();
310 : 1500 : rust_debug ("dot-operator predicate fn_self={%s} can_eq receiver={%s}",
311 : : fn_self->debug_str ().c_str (),
312 : : receiver.debug_str ().c_str ());
313 : :
314 : 1500 : auto res
315 : : = TypeCoercionRules::TryCoerce (&receiver, fn_self, UNDEF_LOCATION,
316 : 1500 : false /*allow-autoderef*/);
317 : 1500 : bool ok = !res.is_error ();
318 : 1500 : if (ok)
319 : : {
320 : 1262 : std::vector<Adjustment> adjs = append_adjustments (res.adjustments);
321 : 1262 : const TraitReference *trait_ref
322 : 1262 : = predicate.lookup.get_parent ()->get ();
323 : 1262 : const TraitItemReference *trait_item
324 : 1262 : = predicate.lookup.get_raw_item ();
325 : :
326 : 1262 : PathProbeCandidate::TraitItemCandidate c{trait_ref, trait_item,
327 : 1262 : nullptr};
328 : 1262 : auto try_result = MethodCandidate{
329 : : PathProbeCandidate (PathProbeCandidate::CandidateType::TRAIT_FUNC,
330 : : fn->clone (), trait_item->get_locus (), c),
331 : 1262 : adjs};
332 : 1262 : result.insert (std::move (try_result));
333 : 1262 : found_possible_candidate = true;
334 : 1262 : }
335 : 1500 : }
336 : 8939 : return found_possible_candidate;
337 : : }
338 : :
339 : : bool
340 : 13810 : MethodResolver::try_select_inherent_impl_candidates (
341 : : TyTy::BaseType &receiver, const std::vector<impl_item_candidate> &candidates,
342 : : bool trait_impl_blocks_only)
343 : : {
344 : 13810 : bool found_possible_candidate = false;
345 : 54365 : for (auto &impl_item : candidates)
346 : : {
347 : 40555 : bool is_trait_impl_block = impl_item.impl_block->has_trait_ref ();
348 : 40555 : if (trait_impl_blocks_only && !is_trait_impl_block)
349 : 17529 : continue;
350 : 39692 : if (!trait_impl_blocks_only && is_trait_impl_block)
351 : 16666 : continue;
352 : :
353 : 23026 : TyTy::FnType *fn = impl_item.ty;
354 : 46052 : if (!fn->is_method ())
355 : 0 : continue;
356 : :
357 : 23026 : TyTy::BaseType *fn_self = fn->get_self_type ();
358 : :
359 : 6760 : const char *debug_prefix
360 : 23026 : = trait_impl_blocks_only ? "trait_impl_item" : "impl_item";
361 : 23026 : rust_debug ("dot-operator %s fn_self={%s} can_eq receiver={%s}",
362 : : debug_prefix, fn_self->debug_str ().c_str (),
363 : : receiver.debug_str ().c_str ());
364 : :
365 : 23026 : auto res
366 : : = TypeCoercionRules::TryCoerce (&receiver, fn_self, UNDEF_LOCATION,
367 : 23026 : false /*allow-autoderef*/);
368 : 23026 : bool ok = !res.is_error ();
369 : 23026 : if (ok)
370 : : {
371 : 4512 : std::vector<Adjustment> adjs = append_adjustments (res.adjustments);
372 : 4512 : PathProbeCandidate::ImplItemCandidate c{impl_item.item,
373 : 4512 : impl_item.impl_block};
374 : 4512 : auto try_result = MethodCandidate{
375 : : PathProbeCandidate (PathProbeCandidate::CandidateType::IMPL_FUNC,
376 : 4512 : fn, impl_item.item->get_locus (), c),
377 : 4512 : adjs};
378 : 4512 : result.insert (std::move (try_result));
379 : 4512 : found_possible_candidate = true;
380 : 4512 : }
381 : 23026 : }
382 : 13810 : return found_possible_candidate;
383 : : }
384 : :
385 : : bool
386 : 3318 : MethodResolver::try_select_trait_impl_candidates (
387 : : TyTy::BaseType &receiver, const std::vector<trait_item_candidate> &candidates)
388 : : {
389 : 3318 : bool found_possible_candidate = false;
390 : 10518 : for (auto trait_item : candidates)
391 : : {
392 : 7200 : TyTy::FnType *fn = trait_item.ty;
393 : 14400 : if (!fn->is_method ())
394 : 0 : continue;
395 : :
396 : 7200 : TyTy::BaseType *fn_self = fn->get_self_type ();
397 : 7200 : rust_debug ("dot-operator trait_item fn_self={%s} can_eq receiver={%s}",
398 : : fn_self->debug_str ().c_str (),
399 : : receiver.debug_str ().c_str ());
400 : :
401 : 7200 : auto res
402 : : = TypeCoercionRules::TryCoerce (&receiver, fn_self, UNDEF_LOCATION,
403 : 7200 : false /*allow-autoderef*/);
404 : 7200 : bool ok = !res.is_error ();
405 : 7200 : if (ok)
406 : : {
407 : 531 : std::vector<Adjustment> adjs = append_adjustments (res.adjustments);
408 : 531 : PathProbeCandidate::TraitItemCandidate c{trait_item.reference,
409 : : trait_item.item_ref,
410 : 531 : nullptr};
411 : 531 : auto try_result = MethodCandidate{
412 : : PathProbeCandidate (PathProbeCandidate::CandidateType::TRAIT_FUNC,
413 : 531 : fn, trait_item.item->get_locus (), c),
414 : 531 : adjs};
415 : 531 : result.insert (std::move (try_result));
416 : 531 : found_possible_candidate = true;
417 : 531 : }
418 : 7200 : }
419 : 3318 : return found_possible_candidate;
420 : : }
421 : :
422 : : bool
423 : 8939 : MethodResolver::select (TyTy::BaseType &receiver)
424 : : {
425 : 17878 : rust_debug ("MethodResolver::select reciever=[%s] path=[%s]",
426 : : receiver.debug_str ().c_str (),
427 : : segment_name.as_string ().c_str ());
428 : :
429 : : // Assemble candidates
430 : 8939 : std::vector<impl_item_candidate> inherent_impl_fns
431 : 8939 : = assemble_inherent_impl_candidates (receiver);
432 : 8939 : std::vector<impl_item_candidate> trait_impl_fns;
433 : 8939 : std::vector<trait_item_candidate> trait_fns;
434 : 8939 : assemble_trait_impl_candidates (receiver, trait_impl_fns, trait_fns);
435 : :
436 : : // Combine inherent and trait impl functions
437 : 8939 : inherent_impl_fns.insert (inherent_impl_fns.end (), trait_impl_fns.begin (),
438 : : trait_impl_fns.end ());
439 : :
440 : : // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/method/probe.rs#L580-L694
441 : :
442 : 8939 : rust_debug ("inherent_impl_fns found {%lu}, trait_fns found {%lu}, "
443 : : "predicate_items found {%lu}",
444 : : (unsigned long) inherent_impl_fns.size (),
445 : : (unsigned long) trait_fns.size (),
446 : : (unsigned long) predicate_items.size ());
447 : :
448 : : // Try selection in the priority order defined by Rust's method resolution:
449 : :
450 : : // 1. Try predicate candidates first (highest priority)
451 : 8939 : if (try_select_predicate_candidates (receiver))
452 : : return true;
453 : :
454 : : // 2. Try inherent impl functions (non-trait impl blocks)
455 : 7677 : if (try_select_inherent_impl_candidates (receiver, inherent_impl_fns, false))
456 : : return true;
457 : :
458 : : // 3. Try inherent impl functions from trait impl blocks
459 : 6133 : if (try_select_inherent_impl_candidates (receiver, inherent_impl_fns, true))
460 : : return true;
461 : :
462 : : // 4. Try trait functions (lowest priority)
463 : 3318 : return try_select_trait_impl_candidates (receiver, trait_fns);
464 : 8939 : }
465 : :
466 : : std::vector<MethodResolver::predicate_candidate>
467 : 7170 : MethodResolver::get_predicate_items (
468 : : const HIR::PathIdentSegment &segment_name, const TyTy::BaseType &receiver,
469 : : const std::vector<TyTy::TypeBoundPredicate> &specified_bounds)
470 : : {
471 : 7170 : std::vector<predicate_candidate> predicate_items;
472 : 9418 : for (auto &bound : specified_bounds)
473 : : {
474 : 2248 : tl::optional<TyTy::TypeBoundPredicateItem> lookup
475 : 2248 : = bound.lookup_associated_item (segment_name.as_string ());
476 : 2248 : if (!lookup.has_value ())
477 : 982 : continue;
478 : :
479 : 1266 : TyTy::BaseType *ty = lookup->get_tyty_for_receiver (&receiver);
480 : 1266 : if (ty->get_kind () == TyTy::TypeKind::FNDEF)
481 : : {
482 : 1266 : TyTy::FnType *fnty = static_cast<TyTy::FnType *> (ty);
483 : 3794 : if (fnty->is_method ())
484 : 1262 : predicate_items.emplace_back (lookup.value (), fnty);
485 : : }
486 : 2248 : }
487 : :
488 : 7170 : return predicate_items;
489 : : }
490 : :
491 : : std::vector<Adjustment>
492 : 6305 : MethodResolver::append_adjustments (const std::vector<Adjustment> &adjs) const
493 : : {
494 : 6305 : std::vector<Adjustment> combined;
495 : 6305 : combined.reserve (adjustments.size () + adjs.size ());
496 : :
497 : 9200 : for (const auto &a : adjustments)
498 : 2895 : combined.push_back (a);
499 : 6375 : for (const auto &a : adjs)
500 : 70 : combined.push_back (a);
501 : :
502 : 6305 : return combined;
503 : : }
504 : :
505 : : } // namespace Resolver
506 : : } // namespace Rust
|