Branch data Line data Source code
1 : : // Copyright (C) 2020-2024 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-casts.h"
26 : : #include "rust-unify.h"
27 : : #include "rust-coercion.h"
28 : : #include "rust-hir-type-bounds.h"
29 : :
30 : : namespace Rust {
31 : : namespace Resolver {
32 : :
33 : : bool
34 : 242527 : query_type (HirId reference, TyTy::BaseType **result)
35 : : {
36 : 242527 : Analysis::Mappings *mappings = Analysis::Mappings::get ();
37 : 242527 : TypeCheckContext *context = TypeCheckContext::get ();
38 : :
39 : 242527 : if (context->query_in_progress (reference))
40 : : return false;
41 : :
42 : 240962 : if (context->lookup_type (reference, result))
43 : : return true;
44 : :
45 : 3014 : context->insert_query (reference);
46 : :
47 : 3014 : std::pair<HIR::Enum *, HIR::EnumItem *> enum_candidiate
48 : 3014 : = mappings->lookup_hir_enumitem (reference);
49 : 6028 : bool enum_candidiate_ok
50 : 3014 : = enum_candidiate.first != nullptr && enum_candidiate.second != nullptr;
51 : 3014 : if (enum_candidiate_ok)
52 : : {
53 : 660 : HIR::Enum *parent = enum_candidiate.first;
54 : 660 : HIR::EnumItem *enum_item = enum_candidiate.second;
55 : 660 : rust_debug_loc (enum_item->get_locus (), "resolved item {%u} to",
56 : : reference);
57 : :
58 : 660 : *result = TypeCheckItem::Resolve (*parent);
59 : :
60 : 660 : context->query_completed (reference);
61 : 660 : return true;
62 : : }
63 : :
64 : 2354 : HIR::Item *item = mappings->lookup_hir_item (reference);
65 : 2354 : if (item != nullptr)
66 : : {
67 : 368 : rust_debug_loc (item->get_locus (), "resolved item {%u} to", reference);
68 : 368 : *result = TypeCheckItem::Resolve (*item);
69 : 368 : context->query_completed (reference);
70 : 368 : return true;
71 : : }
72 : :
73 : 1986 : HirId parent_impl_id = UNKNOWN_HIRID;
74 : 1986 : HIR::ImplItem *impl_item
75 : 1986 : = mappings->lookup_hir_implitem (reference, &parent_impl_id);
76 : 1986 : if (impl_item != nullptr)
77 : : {
78 : 1392 : HIR::ImplBlock *impl_block
79 : 1392 : = mappings->lookup_hir_impl_block (parent_impl_id);
80 : 1392 : rust_assert (impl_block != nullptr);
81 : :
82 : : // found an impl item
83 : 1392 : rust_debug_loc (impl_item->get_locus (), "resolved impl-item {%u} to",
84 : : reference);
85 : :
86 : 1392 : *result = TypeCheckItem::ResolveImplItem (*impl_block, *impl_item);
87 : 1392 : context->query_completed (reference);
88 : 1392 : return true;
89 : : }
90 : :
91 : : // is it an impl_type?
92 : 594 : HIR::ImplBlock *impl_block_by_type = nullptr;
93 : 594 : bool found_impl_block_type
94 : 594 : = mappings->lookup_impl_block_type (reference, &impl_block_by_type);
95 : 594 : if (found_impl_block_type)
96 : : {
97 : 581 : *result = TypeCheckItem::ResolveImplBlockSelf (*impl_block_by_type);
98 : 581 : context->query_completed (reference);
99 : 581 : return true;
100 : : }
101 : :
102 : : // is it an extern item?
103 : 13 : HirId parent_extern_block_id = UNKNOWN_HIRID;
104 : 13 : HIR::ExternalItem *extern_item
105 : 13 : = mappings->lookup_hir_extern_item (reference, &parent_extern_block_id);
106 : 13 : if (extern_item != nullptr)
107 : : {
108 : 12 : HIR::ExternBlock *block
109 : 12 : = mappings->lookup_hir_extern_block (parent_extern_block_id);
110 : 12 : rust_assert (block != nullptr);
111 : :
112 : 12 : *result = TypeCheckTopLevelExternItem::Resolve (extern_item, *block);
113 : 12 : context->query_completed (reference);
114 : 12 : return true;
115 : : }
116 : :
117 : : // more?
118 : 1 : location_t possible_locus = mappings->lookup_location (reference);
119 : 1 : rust_debug_loc (possible_locus, "query system failed to resolve: [%u]",
120 : : reference);
121 : 1 : context->query_completed (reference);
122 : :
123 : 1 : return false;
124 : : }
125 : :
126 : : bool
127 : 2500 : types_compatable (TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
128 : : location_t unify_locus, bool emit_errors)
129 : : {
130 : 2500 : TyTy::BaseType *result
131 : 2500 : = unify_site_and (UNKNOWN_HIRID, lhs, rhs, unify_locus, emit_errors,
132 : : false /*commit*/, true /*infer*/, true /*cleanup*/);
133 : 2500 : return result->get_kind () != TyTy::TypeKind::ERROR;
134 : : }
135 : :
136 : : TyTy::BaseType *
137 : 68088 : unify_site (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
138 : : location_t unify_locus)
139 : : {
140 : 68088 : TyTy::BaseType *expected = lhs.get_ty ();
141 : 68088 : TyTy::BaseType *expr = rhs.get_ty ();
142 : :
143 : 68088 : rust_debug ("unify_site id={%u} expected={%s} expr={%s}", id,
144 : : expected->debug_str ().c_str (), expr->debug_str ().c_str ());
145 : :
146 : 68088 : std::vector<UnifyRules::CommitSite> commits;
147 : 68088 : std::vector<UnifyRules::InferenceSite> infers;
148 : 68088 : return UnifyRules::Resolve (lhs, rhs, unify_locus, true /*commit*/,
149 : : true /*emit_error*/, false /*infer*/, commits,
150 : 68088 : infers);
151 : 68088 : }
152 : :
153 : : TyTy::BaseType *
154 : 35710 : 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)
157 : : {
158 : 35710 : TypeCheckContext &context = *TypeCheckContext::get ();
159 : :
160 : 35710 : TyTy::BaseType *expected = lhs.get_ty ();
161 : 35710 : TyTy::BaseType *expr = rhs.get_ty ();
162 : :
163 : 74037 : 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 ());
167 : :
168 : 35710 : std::vector<UnifyRules::CommitSite> commits;
169 : 35710 : std::vector<UnifyRules::InferenceSite> infers;
170 : 35710 : TyTy::BaseType *result
171 : 35710 : = UnifyRules::Resolve (lhs, rhs, unify_locus, false /*commit inline*/,
172 : : emit_errors, implicit_infer_vars, commits, infers);
173 : 35710 : bool ok = result->get_kind () != TyTy::TypeKind::ERROR;
174 : 35710 : if (ok && commit_if_ok)
175 : : {
176 : 54619 : for (auto &c : commits)
177 : : {
178 : 31662 : UnifyRules::commit (c.lhs, c.rhs, c.resolved);
179 : : }
180 : : }
181 : 12753 : else if (cleanup)
182 : : {
183 : : // FIXME
184 : : // reset the get_next_hir_id
185 : :
186 : 13993 : for (auto &i : infers)
187 : : {
188 : 1270 : i.param->set_ref (i.pref);
189 : 1270 : i.param->set_ty_ref (i.ptyref);
190 : :
191 : : // remove the inference variable
192 : 1270 : context.clear_type (i.infer);
193 : 1270 : delete i.infer;
194 : : }
195 : : }
196 : 35710 : return result;
197 : 35710 : }
198 : :
199 : : TyTy::BaseType *
200 : 21257 : coercion_site (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
201 : : location_t locus)
202 : : {
203 : 21257 : TyTy::BaseType *expected = lhs.get_ty ();
204 : 21257 : TyTy::BaseType *expr = rhs.get_ty ();
205 : :
206 : 21257 : rust_debug ("coercion_site id={%u} expected={%s} expr={%s}", id,
207 : : expected->debug_str ().c_str (), expr->debug_str ().c_str ());
208 : :
209 : 21257 : auto context = TypeCheckContext::get ();
210 : 21257 : if (expected->get_kind () == TyTy::TypeKind::ERROR
211 : 21257 : || expr->get_kind () == TyTy::TypeKind::ERROR)
212 : 8 : return expr;
213 : :
214 : : // can we autoderef it?
215 : 21249 : auto result = TypeCoercionRules::Coerce (expr, expected, locus,
216 : 21249 : true /*allow-autodref*/);
217 : :
218 : : // the result needs to be unified
219 : 21249 : TyTy::BaseType *receiver = expr;
220 : 21249 : if (!result.is_error ())
221 : : {
222 : 21217 : receiver = result.tyty;
223 : : }
224 : :
225 : 21249 : rust_debug ("coerce_default_unify(a={%s}, b={%s})",
226 : : receiver->debug_str ().c_str (), expected->debug_str ().c_str ());
227 : 21249 : TyTy::BaseType *coerced
228 : 21249 : = unify_site (id, lhs, TyTy::TyWithLocation (receiver, rhs.get_locus ()),
229 : : locus);
230 : 21249 : context->insert_autoderef_mappings (id, std::move (result.adjustments));
231 : 21249 : return coerced;
232 : 21249 : }
233 : :
234 : : TyTy::BaseType *
235 : 289 : try_coercion (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
236 : : location_t locus)
237 : : {
238 : 289 : TyTy::BaseType *expected = lhs.get_ty ();
239 : 289 : TyTy::BaseType *expr = rhs.get_ty ();
240 : :
241 : 289 : rust_debug ("try_coercion_site id={%u} expected={%s} expr={%s}", id,
242 : : expected->debug_str ().c_str (), expr->debug_str ().c_str ());
243 : :
244 : 289 : auto result = TypeCoercionRules::TryCoerce (expr, expected, locus,
245 : 289 : true /*allow-autodref*/);
246 : 289 : if (result.is_error ())
247 : 17 : return new TyTy::ErrorType (id);
248 : :
249 : 272 : return result.tyty;
250 : 289 : }
251 : :
252 : : TyTy::BaseType *
253 : 3313 : cast_site (HirId id, TyTy::TyWithLocation from, TyTy::TyWithLocation to,
254 : : location_t cast_locus)
255 : : {
256 : 3313 : 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 ());
259 : :
260 : 3313 : auto context = TypeCheckContext::get ();
261 : 3313 : if (from.get_ty ()->get_kind () == TyTy::TypeKind::ERROR
262 : 3313 : || to.get_ty ()->get_kind () == TyTy::TypeKind::ERROR)
263 : : return to.get_ty ();
264 : :
265 : : // do the cast
266 : 3313 : auto result = TypeCastRules::resolve (cast_locus, from, to);
267 : :
268 : : // we assume error has already been emitted
269 : 3313 : if (result.is_error ())
270 : : return to.get_ty ();
271 : :
272 : : // the result needs to be unified
273 : 3297 : TyTy::BaseType *casted_result = result.tyty;
274 : 3297 : rust_debug ("cast_default_unify(a={%s}, b={%s})",
275 : : casted_result->debug_str ().c_str (),
276 : : to.get_ty ()->debug_str ().c_str ());
277 : :
278 : 3297 : TyTy::BaseType *casted
279 : 3297 : = unify_site (id, to,
280 : 3297 : TyTy::TyWithLocation (casted_result, from.get_locus ()),
281 : : cast_locus);
282 : 3297 : context->insert_cast_autoderef_mappings (id, std::move (result.adjustments));
283 : 3297 : return casted;
284 : 3313 : }
285 : :
286 : : AssociatedImplTrait *
287 : 4622 : lookup_associated_impl_block (const TyTy::TypeBoundPredicate &bound,
288 : : const TyTy::BaseType *binding, bool *ambigious)
289 : : {
290 : 4622 : auto context = TypeCheckContext::get ();
291 : :
292 : : // setup any associated type mappings for the specified bonds and this
293 : : // type
294 : 4622 : auto candidates = TypeBoundsProbe::Probe (binding);
295 : 4622 : std::vector<AssociatedImplTrait *> associated_impl_traits;
296 : 20005 : for (auto &probed_bound : candidates)
297 : : {
298 : 15383 : HIR::ImplBlock *associated_impl = probed_bound.second;
299 : :
300 : 15383 : HirId impl_block_id = associated_impl->get_mappings ().get_hirid ();
301 : 15383 : AssociatedImplTrait *associated = nullptr;
302 : 15383 : bool found_impl_trait
303 : 15383 : = context->lookup_associated_trait_impl (impl_block_id, &associated);
304 : 15383 : if (found_impl_trait)
305 : : {
306 : : // compare the bounds from here i think is what we can do:
307 : 6983 : if (bound.is_equal (associated->get_predicate ()))
308 : : {
309 : 910 : associated_impl_traits.push_back (associated);
310 : : }
311 : : }
312 : : }
313 : :
314 : 4622 : if (associated_impl_traits.empty ())
315 : : return nullptr;
316 : :
317 : : // This code is important when you look at slices for example when
318 : : // you have a slice such as:
319 : : //
320 : : // let slice = &array[1..3]
321 : : //
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
326 : : //
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
333 : :
334 : : // if we have a non-general inference variable we need to be
335 : : // careful about the selection here
336 : 910 : bool is_infer_var = binding->get_kind () == TyTy::TypeKind::INFER;
337 : 910 : bool is_integer_infervar
338 : : = is_infer_var
339 : 910 : && static_cast<const TyTy::InferType *> (binding)->get_infer_kind ()
340 : 939 : == TyTy::InferType::InferTypeKind::INTEGRAL;
341 : 29 : bool is_float_infervar
342 : : = is_infer_var
343 : 29 : && static_cast<const TyTy::InferType *> (binding)->get_infer_kind ()
344 : 910 : == TyTy::InferType::InferTypeKind::FLOAT;
345 : :
346 : 910 : AssociatedImplTrait *associate_impl_trait = nullptr;
347 : 910 : if (associated_impl_traits.size () == 1)
348 : : {
349 : : // just go for it
350 : 910 : associate_impl_trait = associated_impl_traits.at (0);
351 : : }
352 : 0 : else if (is_integer_infervar)
353 : : {
354 : 0 : TyTy::BaseType *type = nullptr;
355 : 0 : bool ok = context->lookup_builtin ("i32", &type);
356 : 0 : rust_assert (ok);
357 : :
358 : 0 : for (auto &impl : associated_impl_traits)
359 : : {
360 : 0 : bool found = impl->get_self ()->is_equal (*type);
361 : 0 : if (found)
362 : : {
363 : 0 : associate_impl_trait = impl;
364 : 0 : break;
365 : : }
366 : : }
367 : : }
368 : 0 : else if (is_float_infervar)
369 : : {
370 : 0 : TyTy::BaseType *type = nullptr;
371 : 0 : bool ok = context->lookup_builtin ("f64", &type);
372 : 0 : rust_assert (ok);
373 : :
374 : 0 : for (auto &impl : associated_impl_traits)
375 : : {
376 : 0 : bool found = impl->get_self ()->is_equal (*type);
377 : 0 : if (found)
378 : : {
379 : 0 : associate_impl_trait = impl;
380 : 0 : break;
381 : : }
382 : : }
383 : : }
384 : :
385 : 910 : if (associate_impl_trait == nullptr && ambigious != nullptr)
386 : : {
387 : 0 : *ambigious = true;
388 : : }
389 : :
390 : : return associate_impl_trait;
391 : 4622 : }
392 : :
393 : : } // namespace Resolver
394 : : } // namespace Rust
|