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
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
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"
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
))
42 if (context
->lookup_type (reference
, result
))
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",
58 *result
= TypeCheckItem::Resolve (*parent
);
60 context
->query_completed (reference
);
64 HIR::Item
*item
= mappings
->lookup_hir_item (reference
);
67 rust_debug_loc (item
->get_locus (), "resolved item {%u} to", reference
);
68 *result
= TypeCheckItem::Resolve (*item
);
69 context
->query_completed (reference
);
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);
83 rust_debug_loc (impl_item
->get_locus (), "resolved impl-item {%u} to",
86 *result
= TypeCheckItem::ResolveImplItem (*impl_block
, *impl_item
);
87 context
->query_completed (reference
);
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
);
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
);
118 location_t possible_locus
= mappings
->lookup_location (reference
);
119 rust_debug_loc (possible_locus
, "query system failed to resolve: [%u]",
121 context
->query_completed (reference
);
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
;
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
,
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 ();
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
);
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
);
200 coercion_site (HirId id
, TyTy::TyWithLocation lhs
, TyTy::TyWithLocation rhs
,
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
)
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 ()),
230 context
->insert_autoderef_mappings (id
, std::move (result
.adjustments
));
235 try_coercion (HirId id
, TyTy::TyWithLocation lhs
, TyTy::TyWithLocation rhs
,
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
);
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
)
266 auto result
= TypeCastRules::resolve (cast_locus
, from
, to
);
268 // we assume error has already been emitted
269 if (result
.is_error ())
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 ()),
282 context
->insert_cast_autoderef_mappings (id
, std::move (result
.adjustments
));
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
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 ())
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
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
339 && static_cast<const TyTy::InferType
*> (binding
)->get_infer_kind ()
340 == TyTy::InferType::InferTypeKind::INTEGRAL
;
341 bool is_float_infervar
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)
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
);
358 for (auto &impl
: associated_impl_traits
)
360 bool found
= impl
->get_self ()->is_equal (*type
);
363 associate_impl_trait
= impl
;
368 else if (is_float_infervar
)
370 TyTy::BaseType
*type
= nullptr;
371 bool ok
= context
->lookup_builtin ("f64", &type
);
374 for (auto &impl
: associated_impl_traits
)
376 bool found
= impl
->get_self ()->is_equal (*type
);
379 associate_impl_trait
= impl
;
385 if (associate_impl_trait
== nullptr && ambigious
!= nullptr)
390 return associate_impl_trait
;
393 } // namespace Resolver