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