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-type-util.h"
20 : : #include "rust-diagnostics.h"
21 : : #include "rust-hir-map.h"
22 : : #include "rust-hir-type-check-implitem.h"
23 : : #include "rust-hir-type-check-item.h"
24 : : #include "rust-hir-type-check.h"
25 : : #include "rust-hir-type-check-type.h"
26 : : #include "rust-casts.h"
27 : : #include "rust-mapping-common.h"
28 : : #include "rust-unify.h"
29 : : #include "rust-coercion.h"
30 : : #include "rust-hir-type-bounds.h"
31 : : #include "rust-immutable-name-resolution-context.h"
32 : : #include "options.h"
33 : :
34 : : namespace Rust {
35 : : namespace Resolver {
36 : :
37 : : bool
38 : 888040 : query_type (HirId reference, TyTy::BaseType **result)
39 : : {
40 : 888040 : auto &mappings = Analysis::Mappings::get ();
41 : 888040 : TypeCheckContext *context = TypeCheckContext::get ();
42 : :
43 : 888040 : if (context->lookup_type (reference, result))
44 : : return true;
45 : :
46 : 11648 : if (context->query_in_progress (reference))
47 : : return false;
48 : :
49 : 8638 : context->insert_query (reference);
50 : :
51 : 8638 : std::pair<HIR::Enum *, HIR::EnumItem *> enum_candidiate
52 : 8638 : = mappings.lookup_hir_enumitem (reference);
53 : 17276 : bool enum_candidiate_ok
54 : 8638 : = enum_candidiate.first != nullptr && enum_candidiate.second != nullptr;
55 : 8638 : if (enum_candidiate_ok)
56 : : {
57 : 1957 : HIR::Enum *parent = enum_candidiate.first;
58 : 1957 : HIR::EnumItem *enum_item = enum_candidiate.second;
59 : 1957 : rust_debug_loc (enum_item->get_locus (), "resolved item {%u} to",
60 : : reference);
61 : :
62 : 1957 : *result = TypeCheckItem::Resolve (*parent);
63 : :
64 : 1957 : context->query_completed (reference);
65 : 1957 : return true;
66 : : }
67 : :
68 : 6681 : if (auto item = mappings.lookup_hir_item (reference))
69 : : {
70 : 993 : rust_debug_loc (item.value ()->get_locus (), "resolved item {%u} to",
71 : : reference);
72 : 993 : *result = TypeCheckItem::Resolve (*item.value ());
73 : 993 : context->query_completed (reference);
74 : 993 : return true;
75 : : }
76 : :
77 : 5688 : if (auto impl_item = mappings.lookup_hir_implitem (reference))
78 : : {
79 : 3041 : auto impl_block
80 : 3041 : = mappings.lookup_hir_impl_block (impl_item->second).value ();
81 : :
82 : : // found an impl item
83 : 3041 : rust_debug_loc (impl_item->first->get_locus (),
84 : : "resolved impl-item {%u} to", reference);
85 : :
86 : 3041 : *result = TypeCheckItem::ResolveImplItem (*impl_block, *impl_item->first);
87 : 3041 : context->query_completed (reference);
88 : 3041 : return true;
89 : : }
90 : :
91 : : // is it an impl_type?
92 : 2647 : if (auto impl_block_by_type = mappings.lookup_impl_block_type (reference))
93 : : {
94 : : // found an impl item
95 : 2586 : HIR::ImplBlock *impl = impl_block_by_type.value ();
96 : 2586 : rust_debug_loc (impl->get_locus (), "resolved impl block type {%u} to",
97 : : reference);
98 : :
99 : : // this could be recursive to the root type
100 : 2586 : if (impl->has_type ())
101 : : {
102 : 2586 : HIR::Type &ty = impl->get_type ();
103 : 2586 : NodeId ref_node_id = UNKNOWN_NODEID;
104 : 2586 : NodeId ast_node_id = ty.get_mappings ().get_nodeid ();
105 : :
106 : 2586 : auto &nr_ctx
107 : 2586 : = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
108 : :
109 : : // assign the ref_node_id if we've found something
110 : 2586 : nr_ctx.lookup (ast_node_id).map ([&ref_node_id] (NodeId resolved) {
111 : 2520 : ref_node_id = resolved;
112 : : });
113 : :
114 : 2586 : if (ref_node_id != UNKNOWN_NODEID)
115 : : {
116 : 2520 : tl::optional<HirId> hid
117 : 2520 : = mappings.lookup_node_to_hir (ref_node_id);
118 : 2520 : if (hid.has_value () && context->query_in_progress (hid.value ()))
119 : : {
120 : 2 : context->query_completed (reference);
121 : 2 : return false;
122 : : }
123 : : }
124 : : }
125 : :
126 : 2584 : *result = TypeCheckItem::ResolveImplBlockSelf (*impl);
127 : 2584 : context->query_completed (reference);
128 : 2584 : return true;
129 : : }
130 : :
131 : : // is it an extern item?
132 : 61 : if (auto extern_item = mappings.lookup_hir_extern_item (reference))
133 : : {
134 : 58 : auto block = mappings.lookup_hir_extern_block (extern_item->second);
135 : 58 : rust_assert (block.has_value ());
136 : :
137 : 58 : *result
138 : 58 : = TypeCheckTopLevelExternItem::Resolve (*extern_item.value ().first,
139 : 58 : *block.value ());
140 : 58 : context->query_completed (reference);
141 : 58 : return true;
142 : : }
143 : :
144 : : // more?
145 : 3 : location_t possible_locus = mappings.lookup_location (reference);
146 : 3 : rust_debug_loc (possible_locus, "query system failed to resolve: [%u]",
147 : : reference);
148 : 3 : context->query_completed (reference);
149 : :
150 : 3 : return false;
151 : : }
152 : :
153 : : bool
154 : 11171 : types_compatable (TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
155 : : location_t unify_locus, bool emit_errors)
156 : : {
157 : 11171 : TyTy::BaseType *result
158 : 11171 : = unify_site_and (UNKNOWN_HIRID, lhs, rhs, unify_locus, emit_errors,
159 : : false /*commit*/, true /*infer*/, true /*cleanup*/);
160 : 11171 : return result->get_kind () != TyTy::TypeKind::ERROR;
161 : : }
162 : :
163 : : TyTy::BaseType *
164 : 28128 : unify_site (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
165 : : location_t unify_locus)
166 : : {
167 : 28128 : TyTy::BaseType *expected = lhs.get_ty ();
168 : 28128 : TyTy::BaseType *expr = rhs.get_ty ();
169 : :
170 : 28128 : rust_debug ("unify_site id={%u} expected={%s} expr={%s}", id,
171 : : expected->debug_str ().c_str (), expr->debug_str ().c_str ());
172 : :
173 : 28128 : std::vector<UnifyRules::CommitSite> commits;
174 : 28128 : std::vector<UnifyRules::InferenceSite> infers;
175 : 28128 : return UnifyRules::Resolve (lhs, rhs, unify_locus, true /*commit*/,
176 : : true /*emit_error*/, false /*infer*/, commits,
177 : 28128 : infers);
178 : 28128 : }
179 : :
180 : : TyTy::BaseType *
181 : 130950 : unify_site_and (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
182 : : location_t unify_locus, bool emit_errors, bool commit_if_ok,
183 : : bool implicit_infer_vars, bool cleanup)
184 : : {
185 : 130950 : TypeCheckContext &context = *TypeCheckContext::get ();
186 : :
187 : 130950 : TyTy::BaseType *expected = lhs.get_ty ();
188 : 130950 : TyTy::BaseType *expr = rhs.get_ty ();
189 : :
190 : 234045 : rust_debug_loc (
191 : : unify_locus,
192 : : "begin unify_site_and commit %s infer %s id={%u} expected={%s} expr={%s}",
193 : : commit_if_ok ? "true" : "false", implicit_infer_vars ? "true" : "false",
194 : 261900 : id == UNKNOWN_HIRID ? 0 : id, expected->debug_str ().c_str (),
195 : 130950 : expr->debug_str ().c_str ());
196 : :
197 : 130950 : std::vector<UnifyRules::CommitSite> commits;
198 : 130950 : std::vector<UnifyRules::InferenceSite> infers;
199 : 130950 : TyTy::BaseType *result
200 : 130950 : = UnifyRules::Resolve (lhs, rhs, unify_locus, false /*commit inline*/,
201 : : emit_errors, implicit_infer_vars, commits, infers);
202 : 130950 : bool ok = result->get_kind () != TyTy::TypeKind::ERROR;
203 : :
204 : 164594 : rust_debug_loc (unify_locus,
205 : : "unify_site_and done ok=%s commit %s infer %s id={%u} "
206 : : "expected={%s} expr={%s}",
207 : : ok ? "true" : "false", commit_if_ok ? "true" : "false",
208 : : implicit_infer_vars ? "true" : "false",
209 : 261900 : id == UNKNOWN_HIRID ? 0 : id, expected->debug_str ().c_str (),
210 : 130950 : expr->debug_str ().c_str ());
211 : :
212 : 130950 : if (ok && commit_if_ok)
213 : : {
214 : 182456 : for (auto &c : commits)
215 : : {
216 : 106150 : UnifyRules::commit (c.lhs, c.rhs, c.resolved);
217 : : }
218 : : }
219 : 54644 : else if (cleanup)
220 : : {
221 : : // FIXME
222 : : // reset the get_next_hir_id
223 : :
224 : 56678 : for (auto &i : infers)
225 : : {
226 : 2086 : i.param->set_ref (i.pref);
227 : 2086 : i.param->set_ty_ref (i.ptyref);
228 : :
229 : : // remove the inference variable
230 : 2086 : context.clear_type (i.infer);
231 : 2086 : delete i.infer;
232 : : }
233 : : }
234 : 130950 : return result;
235 : 130950 : }
236 : :
237 : : TyTy::BaseType *
238 : 37531 : coercion_site (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
239 : : location_t locus)
240 : : {
241 : 37531 : TyTy::BaseType *expected = lhs.get_ty ();
242 : 37531 : TyTy::BaseType *expr = rhs.get_ty ();
243 : :
244 : 37531 : rust_debug ("coercion_site id={%u} expected={%s} expr={%s}", id,
245 : : expected->debug_str ().c_str (), expr->debug_str ().c_str ());
246 : :
247 : 37531 : auto context = TypeCheckContext::get ();
248 : 37531 : if (expected->get_kind () == TyTy::TypeKind::ERROR
249 : 37531 : || expr->get_kind () == TyTy::TypeKind::ERROR)
250 : 20 : return expr;
251 : :
252 : : // can we autoderef it?
253 : 37511 : auto result = TypeCoercionRules::Coerce (expr, expected, locus,
254 : 37511 : true /*allow-autodref*/);
255 : :
256 : : // the result needs to be unified
257 : 37511 : TyTy::BaseType *receiver = expr;
258 : 37511 : if (!result.is_error ())
259 : : {
260 : 37456 : receiver = result.tyty;
261 : : }
262 : :
263 : 37511 : rust_debug ("coerce_default_unify(a={%s}, b={%s})",
264 : : receiver->debug_str ().c_str (), expected->debug_str ().c_str ());
265 : 37511 : TyTy::BaseType *coerced
266 : 37511 : = unify_site_and (id, lhs,
267 : 37511 : TyTy::TyWithLocation (receiver, rhs.get_locus ()), locus,
268 : : true /*emit_error*/, true /*commit*/, true /*infer*/,
269 : : true /*cleanup*/);
270 : 37511 : context->insert_autoderef_mappings (id, std::move (result.adjustments));
271 : 37511 : return coerced;
272 : 37511 : }
273 : :
274 : : TyTy::BaseType *
275 : 1324 : try_coercion (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
276 : : location_t locus)
277 : : {
278 : 1324 : TyTy::BaseType *expected = lhs.get_ty ();
279 : 1324 : TyTy::BaseType *expr = rhs.get_ty ();
280 : :
281 : 1324 : rust_debug ("try_coercion_site id={%u} expected={%s} expr={%s}", id,
282 : : expected->debug_str ().c_str (), expr->debug_str ().c_str ());
283 : :
284 : 1324 : auto result = TypeCoercionRules::TryCoerce (expr, expected, locus,
285 : 1324 : true /*allow-autodref*/);
286 : 1324 : if (result.is_error ())
287 : 27 : return new TyTy::ErrorType (id);
288 : :
289 : 1297 : return result.tyty;
290 : 1324 : }
291 : :
292 : : TyTy::BaseType *
293 : 4942 : cast_site (HirId id, TyTy::TyWithLocation from, TyTy::TyWithLocation to,
294 : : location_t cast_locus)
295 : : {
296 : 4942 : rust_debug ("cast_site id={%u} from={%s} to={%s}", id,
297 : : from.get_ty ()->debug_str ().c_str (),
298 : : to.get_ty ()->debug_str ().c_str ());
299 : :
300 : 4942 : auto context = TypeCheckContext::get ();
301 : 4942 : if (from.get_ty ()->get_kind () == TyTy::TypeKind::ERROR
302 : 4942 : || to.get_ty ()->get_kind () == TyTy::TypeKind::ERROR)
303 : : return to.get_ty ();
304 : :
305 : : // do the cast
306 : 4942 : auto result = TypeCastRules::resolve (cast_locus, from, to);
307 : :
308 : : // we assume error has already been emitted
309 : 4942 : if (result.is_error ())
310 : : return to.get_ty ();
311 : :
312 : : // the result needs to be unified
313 : 4926 : TyTy::BaseType *casted_result = result.tyty;
314 : 4926 : rust_debug ("cast_default_unify(a={%s}, b={%s})",
315 : : casted_result->debug_str ().c_str (),
316 : : to.get_ty ()->debug_str ().c_str ());
317 : :
318 : 4926 : TyTy::BaseType *casted
319 : 4926 : = unify_site (id, to,
320 : 4926 : TyTy::TyWithLocation (casted_result, from.get_locus ()),
321 : : cast_locus);
322 : 4926 : context->insert_cast_autoderef_mappings (id, std::move (result.adjustments));
323 : 4926 : return casted;
324 : 4942 : }
325 : :
326 : : AssociatedImplTrait *
327 : 8542 : lookup_associated_impl_block (const TyTy::TypeBoundPredicate &bound,
328 : : const TyTy::BaseType *binding, bool *ambigious)
329 : : {
330 : 8542 : auto context = TypeCheckContext::get ();
331 : :
332 : : // setup any associated type mappings for the specified bonds and this
333 : : // type
334 : 8542 : auto candidates = TypeBoundsProbe::Probe (binding);
335 : 8542 : std::vector<AssociatedImplTrait *> associated_impl_traits;
336 : 49725 : for (auto &probed_bound : candidates)
337 : : {
338 : 41183 : HIR::ImplBlock *associated_impl = probed_bound.second;
339 : :
340 : 41183 : HirId impl_block_id = associated_impl->get_mappings ().get_hirid ();
341 : 41183 : AssociatedImplTrait *associated = nullptr;
342 : 41183 : bool found_impl_trait
343 : 41183 : = context->lookup_associated_trait_impl (impl_block_id, &associated);
344 : 41183 : if (found_impl_trait)
345 : : {
346 : : // compare the bounds from here i think is what we can do:
347 : 20526 : if (bound.is_equal (associated->get_predicate ()))
348 : : {
349 : 2128 : associated_impl_traits.push_back (associated);
350 : : }
351 : : }
352 : : }
353 : :
354 : 8542 : if (associated_impl_traits.empty ())
355 : : return nullptr;
356 : :
357 : : // This code is important when you look at slices for example when
358 : : // you have a slice such as:
359 : : //
360 : : // let slice = &array[1..3]
361 : : //
362 : : // the higher ranked bounds will end up having an Index trait
363 : : // implementation for Range<usize> so we need this code to resolve
364 : : // that we have an integer inference variable that needs to become
365 : : // a usize
366 : : //
367 : : // The other complicated issue is that we might have an intrinsic
368 : : // which requires the :Clone or Copy bound but the libcore adds
369 : : // implementations for all the integral types so when there are
370 : : // multiple candidates we need to resolve to the default
371 : : // implementation for that type otherwise its an error for
372 : : // ambiguous type bounds
373 : :
374 : : // if we have a non-general inference variable we need to be
375 : : // careful about the selection here
376 : 2107 : bool is_infer_var = binding->get_kind () == TyTy::TypeKind::INFER;
377 : 2107 : bool is_integer_infervar
378 : : = is_infer_var
379 : 2107 : && static_cast<const TyTy::InferType *> (binding)->get_infer_kind ()
380 : 2177 : == TyTy::InferType::InferTypeKind::INTEGRAL;
381 : 70 : bool is_float_infervar
382 : : = is_infer_var
383 : 70 : && static_cast<const TyTy::InferType *> (binding)->get_infer_kind ()
384 : 2107 : == TyTy::InferType::InferTypeKind::FLOAT;
385 : :
386 : 2107 : AssociatedImplTrait *associate_impl_trait = nullptr;
387 : 2107 : if (associated_impl_traits.size () == 1)
388 : : {
389 : : // just go for it
390 : 2086 : associate_impl_trait = associated_impl_traits.at (0);
391 : : }
392 : 21 : else if (is_integer_infervar)
393 : : {
394 : 0 : TyTy::BaseType *type = nullptr;
395 : 0 : bool ok = context->lookup_builtin ("i32", &type);
396 : 0 : rust_assert (ok);
397 : :
398 : 0 : for (auto &impl : associated_impl_traits)
399 : : {
400 : 0 : bool found = impl->get_self ()->is_equal (*type);
401 : 0 : if (found)
402 : : {
403 : 0 : associate_impl_trait = impl;
404 : 0 : break;
405 : : }
406 : : }
407 : : }
408 : 21 : else if (is_float_infervar)
409 : : {
410 : 0 : TyTy::BaseType *type = nullptr;
411 : 0 : bool ok = context->lookup_builtin ("f64", &type);
412 : 0 : rust_assert (ok);
413 : :
414 : 0 : for (auto &impl : associated_impl_traits)
415 : : {
416 : 0 : bool found = impl->get_self ()->is_equal (*type);
417 : 0 : if (found)
418 : : {
419 : 0 : associate_impl_trait = impl;
420 : 0 : break;
421 : : }
422 : : }
423 : : }
424 : :
425 : 2107 : if (associate_impl_trait == nullptr && ambigious != nullptr)
426 : : {
427 : 21 : *ambigious = true;
428 : : }
429 : :
430 : : return associate_impl_trait;
431 : 8542 : }
432 : :
433 : : } // namespace Resolver
434 : : } // namespace Rust
|