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