Line data Source code
1 : // Copyright (C) 2020-2026 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 1985983 : query_type (HirId reference, TyTy::BaseType **result)
39 : {
40 1985983 : auto &mappings = Analysis::Mappings::get ();
41 1985983 : TypeCheckContext *context = TypeCheckContext::get ();
42 :
43 1985983 : if (context->lookup_type (reference, result))
44 : return true;
45 :
46 14188 : if (context->query_in_progress (reference))
47 : return false;
48 :
49 11177 : context->insert_query (reference);
50 :
51 11177 : std::pair<HIR::Enum *, HIR::EnumItem *> enum_candidiate
52 11177 : = mappings.lookup_hir_enumitem (reference);
53 22354 : bool enum_candidiate_ok
54 11177 : = enum_candidiate.first != nullptr && enum_candidiate.second != nullptr;
55 11177 : if (enum_candidiate_ok)
56 : {
57 4239 : HIR::Enum *parent = enum_candidiate.first;
58 4239 : HIR::EnumItem *enum_item = enum_candidiate.second;
59 4239 : rust_debug_loc (enum_item->get_locus (), "resolved item {%u} to",
60 : reference);
61 :
62 4239 : *result = TypeCheckItem::Resolve (*parent);
63 :
64 4239 : context->query_completed (reference);
65 4239 : return true;
66 : }
67 :
68 6938 : if (auto item = mappings.lookup_hir_item (reference))
69 : {
70 1001 : rust_debug_loc (item.value ()->get_locus (), "resolved item {%u} to",
71 : reference);
72 1001 : *result = TypeCheckItem::Resolve (*item.value ());
73 1001 : context->query_completed (reference);
74 1001 : 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 1886863 : types_compatable (TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
155 : location_t unify_locus, bool emit_errors, bool check_bounds)
156 : {
157 1886863 : TyTy::BaseType *result
158 1886863 : = unify_site_and (UNKNOWN_HIRID, lhs, rhs, unify_locus, emit_errors,
159 : false /*commit*/, true /*infer*/, true /*cleanup*/,
160 : check_bounds);
161 1886863 : return result->get_kind () != TyTy::TypeKind::ERROR;
162 : }
163 :
164 : TyTy::BaseType *
165 29056 : unify_site (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
166 : location_t unify_locus)
167 : {
168 29056 : TyTy::BaseType *expected = lhs.get_ty ();
169 29056 : TyTy::BaseType *expr = rhs.get_ty ();
170 :
171 29056 : rust_debug ("unify_site id={%u} expected={%s} expr={%s}", id,
172 : expected->debug_str ().c_str (), expr->debug_str ().c_str ());
173 :
174 29056 : std::vector<UnifyRules::CommitSite> commits;
175 29056 : std::vector<UnifyRules::InferenceSite> infers;
176 29056 : return UnifyRules::Resolve (lhs, rhs, unify_locus, true /*commit*/,
177 : true /*emit_error*/, false /*infer*/,
178 29056 : true /*check_bounds*/, commits, infers);
179 29056 : }
180 :
181 : TyTy::BaseType *
182 2008793 : 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 2008793 : TypeCheckContext &context = *TypeCheckContext::get ();
187 :
188 2008793 : TyTy::BaseType *expected = lhs.get_ty ();
189 2008793 : TyTy::BaseType *expr = rhs.get_ty ();
190 :
191 7682431 : 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 4017586 : expected->debug_str ().c_str (), expr->debug_str ().c_str ());
198 :
199 2008793 : std::vector<UnifyRules::CommitSite> commits;
200 2008793 : std::vector<UnifyRules::InferenceSite> infers;
201 2008793 : TyTy::BaseType *result
202 2008793 : = UnifyRules::Resolve (lhs, rhs, unify_locus, false /*commit inline*/,
203 : emit_errors, implicit_infer_vars, check_bounds,
204 : commits, infers);
205 2008793 : bool ok = result->get_kind () != TyTy::TypeKind::ERROR;
206 :
207 3587378 : 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 4017586 : id == UNKNOWN_HIRID ? 0 : id, expected->debug_str ().c_str (),
213 2008793 : expr->debug_str ().c_str ());
214 :
215 2008793 : if (ok && commit_if_ok)
216 : {
217 196459 : for (auto &c : commits)
218 : {
219 115503 : UnifyRules::commit (c.lhs, c.rhs, c.resolved);
220 : }
221 : }
222 1927837 : else if (cleanup)
223 : {
224 2012339 : for (auto &i : infers)
225 : {
226 84982 : if (i.param != nullptr)
227 : {
228 84933 : i.param->set_ref (i.pref);
229 84933 : i.param->set_ty_ref (i.ptyref);
230 : }
231 :
232 : // remove the inference variable
233 84982 : context.clear_type (i.infer);
234 : // FIXME: Don't delete - result might point to this
235 : // delete i.infer;
236 : }
237 : }
238 2008793 : return result;
239 2008793 : }
240 :
241 : TyTy::BaseType *
242 38313 : coercion_site (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
243 : location_t locus)
244 : {
245 38313 : TyTy::BaseType *expected = lhs.get_ty ();
246 38313 : TyTy::BaseType *expr = rhs.get_ty ();
247 :
248 38313 : rust_debug ("coercion_site id={%u} expected={%s} expr={%s}", id,
249 : expected->debug_str ().c_str (), expr->debug_str ().c_str ());
250 :
251 38313 : auto context = TypeCheckContext::get ();
252 38313 : if (expected->get_kind () == TyTy::TypeKind::ERROR
253 38313 : || expr->get_kind () == TyTy::TypeKind::ERROR)
254 20 : return expr;
255 :
256 : // can we autoderef it?
257 38293 : auto result = TypeCoercionRules::Coerce (expr, expected, locus,
258 38293 : true /*allow-autodref*/);
259 :
260 : // the result needs to be unified
261 38293 : TyTy::BaseType *receiver = expr;
262 38293 : if (!result.is_error ())
263 : {
264 38236 : receiver = result.tyty;
265 : }
266 :
267 38293 : rust_debug ("coerce_default_unify(a={%s}, b={%s})",
268 : receiver->debug_str ().c_str (), expected->debug_str ().c_str ());
269 38293 : TyTy::BaseType *coerced
270 38293 : = unify_site_and (id, lhs,
271 38293 : TyTy::TyWithLocation (receiver, rhs.get_locus ()), locus,
272 : true /*emit_error*/, true /*commit*/, true /*infer*/,
273 : true /*cleanup*/);
274 38293 : context->insert_autoderef_mappings (id, std::move (result.adjustments));
275 38293 : return coerced;
276 38293 : }
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 5177 : cast_site (HirId id, TyTy::TyWithLocation from, TyTy::TyWithLocation to,
298 : location_t cast_locus)
299 : {
300 5177 : 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 5177 : auto context = TypeCheckContext::get ();
305 5177 : if (from.get_ty ()->get_kind () == TyTy::TypeKind::ERROR
306 5177 : || to.get_ty ()->get_kind () == TyTy::TypeKind::ERROR)
307 : return to.get_ty ();
308 :
309 : // do the cast
310 5177 : auto result = TypeCastRules::resolve (cast_locus, from, to);
311 :
312 : // we assume error has already been emitted
313 5177 : if (result.is_error ())
314 : return to.get_ty ();
315 :
316 : // the result needs to be unified
317 5161 : TyTy::BaseType *casted_result = result.tyty;
318 5161 : 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 5161 : TyTy::BaseType *casted
323 5161 : = unify_site (id, to,
324 5161 : TyTy::TyWithLocation (casted_result, from.get_locus ()),
325 : cast_locus);
326 5161 : context->insert_cast_autoderef_mappings (id, std::move (result.adjustments));
327 5161 : return casted;
328 5177 : }
329 :
330 : AssociatedImplTrait *
331 8555 : lookup_associated_impl_block (const TyTy::TypeBoundPredicate &bound,
332 : TyTy::BaseType *binding, bool *ambigious)
333 : {
334 8555 : auto context = TypeCheckContext::get ();
335 :
336 : // setup any associated type mappings for the specified bonds and this
337 : // type
338 8555 : auto candidates = TypeBoundsProbe::Probe (binding);
339 8555 : std::vector<AssociatedImplTrait *> associated_impl_traits;
340 49765 : for (auto &probed_bound : candidates)
341 : {
342 41210 : HIR::ImplBlock *associated_impl = probed_bound.second;
343 :
344 41210 : HirId impl_block_id = associated_impl->get_mappings ().get_hirid ();
345 41210 : AssociatedImplTrait *associated = nullptr;
346 41210 : bool found_impl_trait
347 41210 : = context->lookup_associated_trait_impl (impl_block_id, &associated);
348 41210 : if (found_impl_trait)
349 : {
350 : // compare the bounds from here i think is what we can do:
351 20536 : if (bound.is_equal (associated->get_predicate ()))
352 : {
353 2136 : associated_impl_traits.push_back (associated);
354 : }
355 : }
356 : }
357 :
358 8555 : 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 2114 : bool is_infer_var = binding->get_kind () == TyTy::TypeKind::INFER;
381 2114 : bool is_integer_infervar
382 : = is_infer_var
383 2114 : && static_cast<const TyTy::InferType *> (binding)->get_infer_kind ()
384 2184 : == 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 2114 : == TyTy::InferType::InferTypeKind::FLOAT;
389 :
390 2114 : AssociatedImplTrait *associate_impl_trait = nullptr;
391 2114 : if (associated_impl_traits.size () == 1)
392 : {
393 : // just go for it
394 2092 : 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 2114 : if (associate_impl_trait == nullptr && ambigious != nullptr)
430 : {
431 22 : *ambigious = true;
432 : }
433 :
434 : return associate_impl_trait;
435 8555 : }
436 :
437 : } // namespace Resolver
438 : } // namespace Rust
|