Daily bump.
[official-gcc.git] / gcc / rust / typecheck / rust-type-util.cc
blob97defa4c1e9db1bb8f0ed444185a1d0d0c8c69fe
1 // Copyright (C) 2020-2025 Free Software Foundation, Inc.
3 // This file is part of GCC.
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.
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.
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/>.
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-casts.h"
26 #include "rust-unify.h"
27 #include "rust-coercion.h"
28 #include "rust-hir-type-bounds.h"
30 namespace Rust {
31 namespace Resolver {
33 bool
34 query_type (HirId reference, TyTy::BaseType **result)
36 Analysis::Mappings *mappings = Analysis::Mappings::get ();
37 TypeCheckContext *context = TypeCheckContext::get ();
39 if (context->query_in_progress (reference))
40 return false;
42 if (context->lookup_type (reference, result))
43 return true;
45 context->insert_query (reference);
47 std::pair<HIR::Enum *, HIR::EnumItem *> enum_candidiate
48 = mappings->lookup_hir_enumitem (reference);
49 bool enum_candidiate_ok
50 = enum_candidiate.first != nullptr && enum_candidiate.second != nullptr;
51 if (enum_candidiate_ok)
53 HIR::Enum *parent = enum_candidiate.first;
54 HIR::EnumItem *enum_item = enum_candidiate.second;
55 rust_debug_loc (enum_item->get_locus (), "resolved item {%u} to",
56 reference);
58 *result = TypeCheckItem::Resolve (*parent);
60 context->query_completed (reference);
61 return true;
64 HIR::Item *item = mappings->lookup_hir_item (reference);
65 if (item != nullptr)
67 rust_debug_loc (item->get_locus (), "resolved item {%u} to", reference);
68 *result = TypeCheckItem::Resolve (*item);
69 context->query_completed (reference);
70 return true;
73 HirId parent_impl_id = UNKNOWN_HIRID;
74 HIR::ImplItem *impl_item
75 = mappings->lookup_hir_implitem (reference, &parent_impl_id);
76 if (impl_item != nullptr)
78 HIR::ImplBlock *impl_block
79 = mappings->lookup_hir_impl_block (parent_impl_id);
80 rust_assert (impl_block != nullptr);
82 // found an impl item
83 rust_debug_loc (impl_item->get_locus (), "resolved impl-item {%u} to",
84 reference);
86 *result = TypeCheckItem::ResolveImplItem (*impl_block, *impl_item);
87 context->query_completed (reference);
88 return true;
91 // is it an impl_type?
92 HIR::ImplBlock *impl_block_by_type = nullptr;
93 bool found_impl_block_type
94 = mappings->lookup_impl_block_type (reference, &impl_block_by_type);
95 if (found_impl_block_type)
97 *result = TypeCheckItem::ResolveImplBlockSelf (*impl_block_by_type);
98 context->query_completed (reference);
99 return true;
102 // is it an extern item?
103 HirId parent_extern_block_id = UNKNOWN_HIRID;
104 HIR::ExternalItem *extern_item
105 = mappings->lookup_hir_extern_item (reference, &parent_extern_block_id);
106 if (extern_item != nullptr)
108 HIR::ExternBlock *block
109 = mappings->lookup_hir_extern_block (parent_extern_block_id);
110 rust_assert (block != nullptr);
112 *result = TypeCheckTopLevelExternItem::Resolve (extern_item, *block);
113 context->query_completed (reference);
114 return true;
117 // more?
118 location_t possible_locus = mappings->lookup_location (reference);
119 rust_debug_loc (possible_locus, "query system failed to resolve: [%u]",
120 reference);
121 context->query_completed (reference);
123 return false;
126 bool
127 types_compatable (TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
128 location_t unify_locus, bool emit_errors)
130 TyTy::BaseType *result
131 = unify_site_and (UNKNOWN_HIRID, lhs, rhs, unify_locus, emit_errors,
132 false /*commit*/, true /*infer*/, true /*cleanup*/);
133 return result->get_kind () != TyTy::TypeKind::ERROR;
136 TyTy::BaseType *
137 unify_site (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
138 location_t unify_locus)
140 TyTy::BaseType *expected = lhs.get_ty ();
141 TyTy::BaseType *expr = rhs.get_ty ();
143 rust_debug ("unify_site id={%u} expected={%s} expr={%s}", id,
144 expected->debug_str ().c_str (), expr->debug_str ().c_str ());
146 std::vector<UnifyRules::CommitSite> commits;
147 std::vector<UnifyRules::InferenceSite> infers;
148 return UnifyRules::Resolve (lhs, rhs, unify_locus, true /*commit*/,
149 true /*emit_error*/, false /*infer*/, commits,
150 infers);
153 TyTy::BaseType *
154 unify_site_and (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
155 location_t unify_locus, bool emit_errors, bool commit_if_ok,
156 bool implicit_infer_vars, bool cleanup)
158 TypeCheckContext &context = *TypeCheckContext::get ();
160 TyTy::BaseType *expected = lhs.get_ty ();
161 TyTy::BaseType *expr = rhs.get_ty ();
163 rust_debug (
164 "unify_site_and commit %s infer %s id={%u} expected={%s} expr={%s}",
165 commit_if_ok ? "true" : "false", implicit_infer_vars ? "true" : "false", id,
166 expected->debug_str ().c_str (), expr->debug_str ().c_str ());
168 std::vector<UnifyRules::CommitSite> commits;
169 std::vector<UnifyRules::InferenceSite> infers;
170 TyTy::BaseType *result
171 = UnifyRules::Resolve (lhs, rhs, unify_locus, false /*commit inline*/,
172 emit_errors, implicit_infer_vars, commits, infers);
173 bool ok = result->get_kind () != TyTy::TypeKind::ERROR;
174 if (ok && commit_if_ok)
176 for (auto &c : commits)
178 UnifyRules::commit (c.lhs, c.rhs, c.resolved);
181 else if (cleanup)
183 // FIXME
184 // reset the get_next_hir_id
186 for (auto &i : infers)
188 i.param->set_ref (i.pref);
189 i.param->set_ty_ref (i.ptyref);
191 // remove the inference variable
192 context.clear_type (i.infer);
193 delete i.infer;
196 return result;
199 TyTy::BaseType *
200 coercion_site (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
201 location_t locus)
203 TyTy::BaseType *expected = lhs.get_ty ();
204 TyTy::BaseType *expr = rhs.get_ty ();
206 rust_debug ("coercion_site id={%u} expected={%s} expr={%s}", id,
207 expected->debug_str ().c_str (), expr->debug_str ().c_str ());
209 auto context = TypeCheckContext::get ();
210 if (expected->get_kind () == TyTy::TypeKind::ERROR
211 || expr->get_kind () == TyTy::TypeKind::ERROR)
212 return expr;
214 // can we autoderef it?
215 auto result = TypeCoercionRules::Coerce (expr, expected, locus,
216 true /*allow-autodref*/);
218 // the result needs to be unified
219 TyTy::BaseType *receiver = expr;
220 if (!result.is_error ())
222 receiver = result.tyty;
225 rust_debug ("coerce_default_unify(a={%s}, b={%s})",
226 receiver->debug_str ().c_str (), expected->debug_str ().c_str ());
227 TyTy::BaseType *coerced
228 = unify_site (id, lhs, TyTy::TyWithLocation (receiver, rhs.get_locus ()),
229 locus);
230 context->insert_autoderef_mappings (id, std::move (result.adjustments));
231 return coerced;
234 TyTy::BaseType *
235 try_coercion (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
236 location_t locus)
238 TyTy::BaseType *expected = lhs.get_ty ();
239 TyTy::BaseType *expr = rhs.get_ty ();
241 rust_debug ("try_coercion_site id={%u} expected={%s} expr={%s}", id,
242 expected->debug_str ().c_str (), expr->debug_str ().c_str ());
244 auto result = TypeCoercionRules::TryCoerce (expr, expected, locus,
245 true /*allow-autodref*/);
246 if (result.is_error ())
247 return new TyTy::ErrorType (id);
249 return result.tyty;
252 TyTy::BaseType *
253 cast_site (HirId id, TyTy::TyWithLocation from, TyTy::TyWithLocation to,
254 location_t cast_locus)
256 rust_debug ("cast_site id={%u} from={%s} to={%s}", id,
257 from.get_ty ()->debug_str ().c_str (),
258 to.get_ty ()->debug_str ().c_str ());
260 auto context = TypeCheckContext::get ();
261 if (from.get_ty ()->get_kind () == TyTy::TypeKind::ERROR
262 || to.get_ty ()->get_kind () == TyTy::TypeKind::ERROR)
263 return to.get_ty ();
265 // do the cast
266 auto result = TypeCastRules::resolve (cast_locus, from, to);
268 // we assume error has already been emitted
269 if (result.is_error ())
270 return to.get_ty ();
272 // the result needs to be unified
273 TyTy::BaseType *casted_result = result.tyty;
274 rust_debug ("cast_default_unify(a={%s}, b={%s})",
275 casted_result->debug_str ().c_str (),
276 to.get_ty ()->debug_str ().c_str ());
278 TyTy::BaseType *casted
279 = unify_site (id, to,
280 TyTy::TyWithLocation (casted_result, from.get_locus ()),
281 cast_locus);
282 context->insert_cast_autoderef_mappings (id, std::move (result.adjustments));
283 return casted;
286 AssociatedImplTrait *
287 lookup_associated_impl_block (const TyTy::TypeBoundPredicate &bound,
288 const TyTy::BaseType *binding, bool *ambigious)
290 auto context = TypeCheckContext::get ();
292 // setup any associated type mappings for the specified bonds and this
293 // type
294 auto candidates = TypeBoundsProbe::Probe (binding);
295 std::vector<AssociatedImplTrait *> associated_impl_traits;
296 for (auto &probed_bound : candidates)
298 HIR::ImplBlock *associated_impl = probed_bound.second;
300 HirId impl_block_id = associated_impl->get_mappings ().get_hirid ();
301 AssociatedImplTrait *associated = nullptr;
302 bool found_impl_trait
303 = context->lookup_associated_trait_impl (impl_block_id, &associated);
304 if (found_impl_trait)
306 // compare the bounds from here i think is what we can do:
307 if (bound.is_equal (associated->get_predicate ()))
309 associated_impl_traits.push_back (associated);
314 if (associated_impl_traits.empty ())
315 return nullptr;
317 // This code is important when you look at slices for example when
318 // you have a slice such as:
320 // let slice = &array[1..3]
322 // the higher ranked bounds will end up having an Index trait
323 // implementation for Range<usize> so we need this code to resolve
324 // that we have an integer inference variable that needs to become
325 // a usize
327 // The other complicated issue is that we might have an intrinsic
328 // which requires the :Clone or Copy bound but the libcore adds
329 // implementations for all the integral types so when there are
330 // multiple candidates we need to resolve to the default
331 // implementation for that type otherwise its an error for
332 // ambiguous type bounds
334 // if we have a non-general inference variable we need to be
335 // careful about the selection here
336 bool is_infer_var = binding->get_kind () == TyTy::TypeKind::INFER;
337 bool is_integer_infervar
338 = is_infer_var
339 && static_cast<const TyTy::InferType *> (binding)->get_infer_kind ()
340 == TyTy::InferType::InferTypeKind::INTEGRAL;
341 bool is_float_infervar
342 = is_infer_var
343 && static_cast<const TyTy::InferType *> (binding)->get_infer_kind ()
344 == TyTy::InferType::InferTypeKind::FLOAT;
346 AssociatedImplTrait *associate_impl_trait = nullptr;
347 if (associated_impl_traits.size () == 1)
349 // just go for it
350 associate_impl_trait = associated_impl_traits.at (0);
352 else if (is_integer_infervar)
354 TyTy::BaseType *type = nullptr;
355 bool ok = context->lookup_builtin ("i32", &type);
356 rust_assert (ok);
358 for (auto &impl : associated_impl_traits)
360 bool found = impl->get_self ()->is_equal (*type);
361 if (found)
363 associate_impl_trait = impl;
364 break;
368 else if (is_float_infervar)
370 TyTy::BaseType *type = nullptr;
371 bool ok = context->lookup_builtin ("f64", &type);
372 rust_assert (ok);
374 for (auto &impl : associated_impl_traits)
376 bool found = impl->get_self ()->is_equal (*type);
377 if (found)
379 associate_impl_trait = impl;
380 break;
385 if (associate_impl_trait == nullptr && ambigious != nullptr)
387 *ambigious = true;
390 return associate_impl_trait;
393 } // namespace Resolver
394 } // namespace Rust