]>
Commit | Line | Data |
---|---|---|
a945c346 | 1 | // Copyright (C) 2020-2024 Free Software Foundation, Inc. |
06688fe4 PH |
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-hir-type-check.h" | |
20 | ||
21 | namespace Rust { | |
22 | namespace Resolver { | |
23 | ||
24 | TypeCheckContext * | |
25 | TypeCheckContext::get () | |
26 | { | |
27 | static TypeCheckContext *instance; | |
28 | if (instance == nullptr) | |
29 | instance = new TypeCheckContext (); | |
30 | ||
31 | return instance; | |
32 | } | |
33 | ||
34 | TypeCheckContext::TypeCheckContext () {} | |
35 | ||
36 | TypeCheckContext::~TypeCheckContext () {} | |
37 | ||
38 | bool | |
39 | TypeCheckContext::lookup_builtin (NodeId id, TyTy::BaseType **type) | |
40 | { | |
41 | auto ref_it = node_id_refs.find (id); | |
42 | if (ref_it == node_id_refs.end ()) | |
43 | return false; | |
44 | ||
45 | auto it = resolved.find (ref_it->second); | |
46 | if (it == resolved.end ()) | |
47 | return false; | |
48 | ||
49 | *type = it->second; | |
50 | return true; | |
51 | } | |
52 | ||
53 | bool | |
54 | TypeCheckContext::lookup_builtin (std::string name, TyTy::BaseType **type) | |
55 | { | |
56 | for (auto &builtin : builtins) | |
57 | { | |
58 | if (name.compare (builtin->as_string ()) == 0) | |
59 | { | |
60 | *type = builtin.get (); | |
61 | return true; | |
62 | } | |
63 | } | |
64 | return false; | |
65 | } | |
66 | ||
67 | void | |
68 | TypeCheckContext::insert_builtin (HirId id, NodeId ref, TyTy::BaseType *type) | |
69 | { | |
70 | node_id_refs[ref] = id; | |
71 | resolved[id] = type; | |
72 | builtins.push_back (std::unique_ptr<TyTy::BaseType> (type)); | |
73 | } | |
74 | ||
75 | void | |
76 | TypeCheckContext::insert_type (const Analysis::NodeMapping &mappings, | |
77 | TyTy::BaseType *type) | |
78 | { | |
79 | rust_assert (type != nullptr); | |
80 | NodeId ref = mappings.get_nodeid (); | |
81 | HirId id = mappings.get_hirid (); | |
82 | node_id_refs[ref] = id; | |
83 | resolved[id] = type; | |
84 | } | |
85 | ||
86 | void | |
87 | TypeCheckContext::insert_implicit_type (TyTy::BaseType *type) | |
88 | { | |
89 | rust_assert (type != nullptr); | |
90 | resolved[type->get_ref ()] = type; | |
91 | } | |
92 | ||
93 | void | |
94 | TypeCheckContext::insert_implicit_type (HirId id, TyTy::BaseType *type) | |
95 | { | |
96 | rust_assert (type != nullptr); | |
97 | resolved[id] = type; | |
98 | } | |
99 | ||
100 | bool | |
101 | TypeCheckContext::lookup_type (HirId id, TyTy::BaseType **type) const | |
102 | { | |
103 | auto it = resolved.find (id); | |
104 | if (it == resolved.end ()) | |
105 | return false; | |
106 | ||
107 | *type = it->second; | |
108 | return true; | |
109 | } | |
110 | ||
111 | void | |
112 | TypeCheckContext::insert_type_by_node_id (NodeId ref, HirId id) | |
113 | { | |
114 | rust_assert (node_id_refs.find (ref) == node_id_refs.end ()); | |
115 | node_id_refs[ref] = id; | |
116 | } | |
117 | ||
118 | bool | |
119 | TypeCheckContext::lookup_type_by_node_id (NodeId ref, HirId *id) | |
120 | { | |
121 | auto it = node_id_refs.find (ref); | |
122 | if (it == node_id_refs.end ()) | |
123 | return false; | |
124 | ||
125 | *id = it->second; | |
126 | return true; | |
127 | } | |
128 | ||
129 | TyTy::BaseType * | |
130 | TypeCheckContext::peek_return_type () | |
131 | { | |
7ad24d80 | 132 | rust_assert (!return_type_stack.empty ()); |
06688fe4 PH |
133 | return return_type_stack.back ().second; |
134 | } | |
135 | ||
136 | void | |
137 | TypeCheckContext::push_return_type (TypeCheckContextItem item, | |
138 | TyTy::BaseType *return_type) | |
139 | { | |
140 | return_type_stack.push_back ({std::move (item), return_type}); | |
141 | } | |
142 | ||
143 | void | |
144 | TypeCheckContext::pop_return_type () | |
145 | { | |
245ce6f2 | 146 | rust_assert (!return_type_stack.empty ()); |
06688fe4 PH |
147 | return_type_stack.pop_back (); |
148 | } | |
149 | ||
150 | TypeCheckContextItem & | |
151 | TypeCheckContext::peek_context () | |
152 | { | |
245ce6f2 | 153 | rust_assert (!return_type_stack.empty ()); |
06688fe4 PH |
154 | return return_type_stack.back ().first; |
155 | } | |
156 | ||
615ee14c PH |
157 | void |
158 | TypeCheckContext::iterate (std::function<bool (HirId, TyTy::BaseType *)> cb) | |
159 | { | |
160 | for (auto it = resolved.begin (); it != resolved.end (); it++) | |
161 | { | |
162 | if (!cb (it->first, it->second)) | |
163 | return; | |
164 | } | |
165 | } | |
166 | ||
167 | bool | |
168 | TypeCheckContext::have_loop_context () const | |
169 | { | |
170 | return !loop_type_stack.empty (); | |
171 | } | |
172 | ||
173 | void | |
174 | TypeCheckContext::push_new_loop_context (HirId id, Location locus) | |
175 | { | |
176 | TyTy::BaseType *infer_var | |
177 | = new TyTy::InferType (id, TyTy::InferType::InferTypeKind::GENERAL, locus); | |
178 | loop_type_stack.push_back (infer_var); | |
179 | } | |
180 | ||
181 | void | |
182 | TypeCheckContext::push_new_while_loop_context (HirId id) | |
183 | { | |
184 | TyTy::BaseType *infer_var = new TyTy::ErrorType (id); | |
185 | loop_type_stack.push_back (infer_var); | |
186 | } | |
187 | ||
188 | TyTy::BaseType * | |
189 | TypeCheckContext::peek_loop_context () | |
190 | { | |
191 | return loop_type_stack.back (); | |
192 | } | |
193 | ||
194 | TyTy::BaseType * | |
195 | TypeCheckContext::pop_loop_context () | |
196 | { | |
197 | auto back = peek_loop_context (); | |
198 | loop_type_stack.pop_back (); | |
199 | return back; | |
200 | } | |
201 | ||
202 | void | |
203 | TypeCheckContext::swap_head_loop_context (TyTy::BaseType *val) | |
204 | { | |
205 | loop_type_stack.pop_back (); | |
206 | loop_type_stack.push_back (val); | |
207 | } | |
208 | ||
209 | void | |
210 | TypeCheckContext::insert_trait_reference (DefId id, TraitReference &&ref) | |
211 | { | |
212 | rust_assert (trait_context.find (id) == trait_context.end ()); | |
213 | trait_context.emplace (id, std::move (ref)); | |
214 | } | |
215 | ||
216 | bool | |
217 | TypeCheckContext::lookup_trait_reference (DefId id, TraitReference **ref) | |
218 | { | |
219 | auto it = trait_context.find (id); | |
220 | if (it == trait_context.end ()) | |
221 | return false; | |
222 | ||
223 | *ref = &it->second; | |
224 | return true; | |
225 | } | |
226 | ||
227 | void | |
228 | TypeCheckContext::insert_receiver (HirId id, TyTy::BaseType *t) | |
229 | { | |
230 | receiver_context[id] = t; | |
231 | } | |
232 | ||
233 | bool | |
234 | TypeCheckContext::lookup_receiver (HirId id, TyTy::BaseType **ref) | |
235 | { | |
236 | auto it = receiver_context.find (id); | |
237 | if (it == receiver_context.end ()) | |
238 | return false; | |
239 | ||
240 | *ref = it->second; | |
241 | return true; | |
242 | } | |
243 | ||
244 | void | |
245 | TypeCheckContext::insert_associated_trait_impl ( | |
246 | HirId id, AssociatedImplTrait &&associated) | |
247 | { | |
248 | rust_assert (associated_impl_traits.find (id) | |
249 | == associated_impl_traits.end ()); | |
250 | associated_impl_traits.emplace (id, std::move (associated)); | |
251 | } | |
252 | ||
253 | bool | |
254 | TypeCheckContext::lookup_associated_trait_impl ( | |
255 | HirId id, AssociatedImplTrait **associated) | |
256 | { | |
257 | auto it = associated_impl_traits.find (id); | |
258 | if (it == associated_impl_traits.end ()) | |
259 | return false; | |
260 | ||
261 | *associated = &it->second; | |
262 | return true; | |
263 | } | |
264 | ||
265 | void | |
266 | TypeCheckContext::insert_associated_type_mapping (HirId id, HirId mapping) | |
267 | { | |
268 | associated_type_mappings[id] = mapping; | |
269 | } | |
270 | ||
271 | void | |
272 | TypeCheckContext::clear_associated_type_mapping (HirId id) | |
273 | { | |
274 | auto it = associated_type_mappings.find (id); | |
275 | if (it != associated_type_mappings.end ()) | |
276 | associated_type_mappings.erase (it); | |
277 | } | |
278 | ||
279 | // lookup any associated type mappings, the out parameter of mapping is | |
280 | // allowed to be nullptr which allows this interface to do a simple does exist | |
281 | // check | |
282 | bool | |
283 | TypeCheckContext::lookup_associated_type_mapping (HirId id, HirId *mapping) | |
284 | { | |
285 | auto it = associated_type_mappings.find (id); | |
286 | if (it == associated_type_mappings.end ()) | |
287 | return false; | |
288 | ||
289 | if (mapping != nullptr) | |
290 | *mapping = it->second; | |
291 | ||
292 | return true; | |
293 | } | |
294 | ||
295 | void | |
296 | TypeCheckContext::insert_associated_impl_mapping ( | |
297 | HirId trait_id, const TyTy::BaseType *impl_type, HirId impl_id) | |
298 | { | |
299 | auto it = associated_traits_to_impls.find (trait_id); | |
300 | if (it == associated_traits_to_impls.end ()) | |
301 | { | |
302 | associated_traits_to_impls[trait_id] = {}; | |
303 | } | |
304 | ||
305 | associated_traits_to_impls[trait_id].push_back ({impl_type, impl_id}); | |
306 | } | |
307 | ||
308 | bool | |
309 | TypeCheckContext::lookup_associated_impl_mapping_for_self ( | |
310 | HirId trait_id, const TyTy::BaseType *self, HirId *mapping) | |
311 | { | |
312 | auto it = associated_traits_to_impls.find (trait_id); | |
313 | if (it == associated_traits_to_impls.end ()) | |
314 | return false; | |
315 | ||
316 | for (auto &item : it->second) | |
317 | { | |
318 | if (item.first->can_eq (self, false)) | |
319 | { | |
320 | *mapping = item.second; | |
321 | return true; | |
322 | } | |
323 | } | |
324 | return false; | |
325 | } | |
326 | ||
327 | void | |
328 | TypeCheckContext::insert_autoderef_mappings ( | |
329 | HirId id, std::vector<Adjustment> &&adjustments) | |
330 | { | |
331 | rust_assert (autoderef_mappings.find (id) == autoderef_mappings.end ()); | |
332 | autoderef_mappings.emplace (id, std::move (adjustments)); | |
333 | } | |
334 | ||
335 | bool | |
336 | TypeCheckContext::lookup_autoderef_mappings ( | |
337 | HirId id, std::vector<Adjustment> **adjustments) | |
338 | { | |
339 | auto it = autoderef_mappings.find (id); | |
340 | if (it == autoderef_mappings.end ()) | |
341 | return false; | |
342 | ||
343 | *adjustments = &it->second; | |
344 | return true; | |
345 | } | |
346 | ||
347 | void | |
348 | TypeCheckContext::insert_cast_autoderef_mappings ( | |
349 | HirId id, std::vector<Adjustment> &&adjustments) | |
350 | { | |
351 | rust_assert (cast_autoderef_mappings.find (id) | |
352 | == cast_autoderef_mappings.end ()); | |
353 | cast_autoderef_mappings.emplace (id, std::move (adjustments)); | |
354 | } | |
355 | ||
356 | bool | |
357 | TypeCheckContext::lookup_cast_autoderef_mappings ( | |
358 | HirId id, std::vector<Adjustment> **adjustments) | |
359 | { | |
360 | auto it = cast_autoderef_mappings.find (id); | |
361 | if (it == cast_autoderef_mappings.end ()) | |
362 | return false; | |
363 | ||
364 | *adjustments = &it->second; | |
365 | return true; | |
366 | } | |
367 | ||
368 | void | |
369 | TypeCheckContext::insert_variant_definition (HirId id, HirId variant) | |
370 | { | |
371 | auto it = variants.find (id); | |
372 | rust_assert (it == variants.end ()); | |
373 | ||
374 | variants[id] = variant; | |
375 | } | |
376 | ||
377 | bool | |
378 | TypeCheckContext::lookup_variant_definition (HirId id, HirId *variant) | |
379 | { | |
380 | auto it = variants.find (id); | |
381 | if (it == variants.end ()) | |
382 | return false; | |
383 | ||
384 | *variant = it->second; | |
385 | return true; | |
386 | } | |
387 | ||
388 | void | |
389 | TypeCheckContext::insert_operator_overload (HirId id, TyTy::FnType *call_site) | |
390 | { | |
391 | auto it = operator_overloads.find (id); | |
392 | rust_assert (it == operator_overloads.end ()); | |
393 | ||
394 | operator_overloads[id] = call_site; | |
395 | } | |
396 | ||
397 | bool | |
398 | TypeCheckContext::lookup_operator_overload (HirId id, TyTy::FnType **call) | |
399 | { | |
400 | auto it = operator_overloads.find (id); | |
401 | if (it == operator_overloads.end ()) | |
402 | return false; | |
403 | ||
404 | *call = it->second; | |
405 | return true; | |
406 | } | |
407 | ||
408 | void | |
409 | TypeCheckContext::insert_unconstrained_check_marker (HirId id, bool status) | |
410 | { | |
411 | unconstrained[id] = status; | |
412 | } | |
413 | ||
414 | bool | |
415 | TypeCheckContext::have_checked_for_unconstrained (HirId id, bool *result) | |
416 | { | |
417 | auto it = unconstrained.find (id); | |
418 | bool found = it != unconstrained.end (); | |
419 | if (!found) | |
420 | return false; | |
421 | ||
422 | *result = it->second; | |
423 | return true; | |
424 | } | |
425 | ||
426 | void | |
427 | TypeCheckContext::insert_resolved_predicate (HirId id, | |
428 | TyTy::TypeBoundPredicate predicate) | |
429 | { | |
430 | auto it = predicates.find (id); | |
431 | rust_assert (it == predicates.end ()); | |
432 | ||
433 | predicates.insert ({id, predicate}); | |
434 | } | |
435 | ||
436 | bool | |
437 | TypeCheckContext::lookup_predicate (HirId id, TyTy::TypeBoundPredicate *result) | |
438 | { | |
439 | auto it = predicates.find (id); | |
440 | bool found = it != predicates.end (); | |
441 | if (!found) | |
442 | return false; | |
443 | ||
444 | *result = it->second; | |
445 | return true; | |
446 | } | |
447 | ||
448 | void | |
449 | TypeCheckContext::insert_query (HirId id) | |
450 | { | |
451 | querys_in_progress.insert (id); | |
452 | } | |
453 | ||
454 | void | |
455 | TypeCheckContext::query_completed (HirId id) | |
456 | { | |
457 | querys_in_progress.erase (id); | |
458 | } | |
459 | ||
460 | bool | |
461 | TypeCheckContext::query_in_progress (HirId id) const | |
462 | { | |
463 | return querys_in_progress.find (id) != querys_in_progress.end (); | |
464 | } | |
465 | ||
466 | void | |
467 | TypeCheckContext::insert_trait_query (DefId id) | |
468 | { | |
469 | trait_queries_in_progress.insert (id); | |
470 | } | |
471 | ||
472 | void | |
473 | TypeCheckContext::trait_query_completed (DefId id) | |
474 | { | |
475 | trait_queries_in_progress.erase (id); | |
476 | } | |
477 | ||
478 | bool | |
479 | TypeCheckContext::trait_query_in_progress (DefId id) const | |
480 | { | |
481 | return trait_queries_in_progress.find (id) | |
482 | != trait_queries_in_progress.end (); | |
483 | } | |
484 | ||
740a1997 PH |
485 | // TypeCheckContextItem |
486 | ||
615ee14c PH |
487 | TypeCheckContextItem::Item::Item (HIR::Function *item) : item (item) {} |
488 | ||
489 | TypeCheckContextItem::Item::Item (HIR::ImplBlock *impl_block, | |
490 | HIR::Function *item) | |
491 | : impl_item ({impl_block, item}) | |
492 | {} | |
493 | ||
494 | TypeCheckContextItem::Item::Item (HIR::TraitItemFunc *trait_item) | |
495 | : trait_item (trait_item) | |
496 | {} | |
497 | ||
498 | TypeCheckContextItem::TypeCheckContextItem (HIR::Function *item) | |
499 | : type (ItemType::ITEM), item (item) | |
500 | {} | |
501 | ||
502 | TypeCheckContextItem::TypeCheckContextItem (HIR::ImplBlock *impl_block, | |
503 | HIR::Function *item) | |
504 | : type (ItemType::IMPL_ITEM), item (impl_block, item) | |
505 | {} | |
506 | ||
507 | TypeCheckContextItem::TypeCheckContextItem (HIR::TraitItemFunc *trait_item) | |
508 | : type (ItemType::TRAIT_ITEM), item (trait_item) | |
509 | {} | |
510 | ||
511 | HIR::Function * | |
512 | TypeCheckContextItem::get_item () | |
513 | { | |
514 | rust_assert (get_type () == ItemType::ITEM); | |
515 | return item.item; | |
516 | } | |
517 | ||
518 | std::pair<HIR::ImplBlock *, HIR::Function *> & | |
519 | TypeCheckContextItem::get_impl_item () | |
520 | { | |
521 | rust_assert (get_type () == ItemType::IMPL_ITEM); | |
522 | return item.impl_item; | |
523 | } | |
524 | ||
525 | HIR::TraitItemFunc * | |
526 | TypeCheckContextItem::get_trait_item () | |
527 | { | |
528 | rust_assert (get_type () == ItemType::TRAIT_ITEM); | |
529 | return item.trait_item; | |
530 | } | |
531 | ||
532 | TypeCheckContextItem::ItemType | |
533 | TypeCheckContextItem::get_type () const | |
534 | { | |
535 | return type; | |
536 | } | |
537 | ||
740a1997 PH |
538 | TyTy::FnType * |
539 | TypeCheckContextItem::get_context_type () | |
540 | { | |
541 | auto &context = *TypeCheckContext::get (); | |
542 | ||
543 | HirId reference = UNKNOWN_HIRID; | |
544 | switch (get_type ()) | |
545 | { | |
546 | case ITEM: | |
547 | reference = get_item ()->get_mappings ().get_hirid (); | |
548 | break; | |
549 | ||
550 | case IMPL_ITEM: | |
551 | reference = get_impl_item ().second->get_mappings ().get_hirid (); | |
552 | break; | |
553 | ||
554 | case TRAIT_ITEM: | |
555 | reference = get_trait_item ()->get_mappings ().get_hirid (); | |
556 | break; | |
557 | } | |
558 | ||
559 | rust_assert (reference != UNKNOWN_HIRID); | |
560 | ||
561 | TyTy::BaseType *lookup = nullptr; | |
562 | bool ok = context.lookup_type (reference, &lookup); | |
563 | rust_assert (ok); | |
564 | rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF); | |
565 | return static_cast<TyTy::FnType *> (lookup); | |
566 | } | |
567 | ||
06688fe4 PH |
568 | } // namespace Resolver |
569 | } // namespace Rust |