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-hir-type-check-pattern.h"
20 : #include "rust-hir-pattern.h"
21 : #include "rust-hir-type-check-expr.h"
22 : #include "rust-token.h"
23 : #include "rust-type-util.h"
24 : #include "rust-immutable-name-resolution-context.h"
25 : #include "rust-tyty.h"
26 : #include "tree.h"
27 :
28 : namespace Rust {
29 : namespace Resolver {
30 :
31 43793 : TypeCheckPattern::TypeCheckPattern (TyTy::BaseType *parent)
32 43793 : : TypeCheckBase (), parent (parent), infered (new TyTy::ErrorType (0))
33 43793 : {}
34 :
35 : TyTy::BaseType *
36 43793 : TypeCheckPattern::Resolve (HIR::Pattern &pattern, TyTy::BaseType *parent)
37 : {
38 43793 : TypeCheckPattern resolver (parent);
39 43793 : pattern.accept_vis (resolver);
40 :
41 43793 : if (resolver.infered == nullptr)
42 0 : return new TyTy::ErrorType (pattern.get_mappings ().get_hirid ());
43 :
44 43793 : resolver.context->insert_type (pattern.get_mappings (), resolver.infered);
45 43793 : return resolver.infered;
46 43793 : }
47 :
48 : void
49 1112 : TypeCheckPattern::visit (HIR::PathInExpression &pattern)
50 : {
51 : // Pattern must be enum variants, sturcts, constants, or associated constansts
52 1112 : TyTy::BaseType *pattern_ty = TypeCheckExpr::Resolve (pattern);
53 :
54 1112 : NodeId ref_node_id = UNKNOWN_NODEID;
55 1112 : bool maybe_item = false;
56 :
57 1112 : auto &nr_ctx
58 1112 : = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
59 :
60 1112 : if (auto id = nr_ctx.lookup (pattern.get_mappings ().get_nodeid ()))
61 : {
62 1110 : ref_node_id = *id;
63 1110 : maybe_item = true;
64 : }
65 :
66 1112 : bool path_is_const_item = false;
67 :
68 1112 : if (maybe_item)
69 : {
70 1110 : tl::optional<HirId> definition_id
71 1110 : = mappings.lookup_node_to_hir (ref_node_id);
72 1110 : rust_assert (definition_id.has_value ());
73 1110 : HirId def_id = definition_id.value ();
74 :
75 1110 : tl::optional<HIR::Item *> hir_item = mappings.lookup_hir_item (def_id);
76 : // If the path references an item, it must be constants or structs.
77 1110 : if (hir_item.has_value ())
78 : {
79 7 : HIR::Item *item = hir_item.value ();
80 7 : if (item->get_item_kind () == HIR::Item::ItemKind::Constant)
81 : {
82 : path_is_const_item = true;
83 : }
84 6 : else if (item->get_item_kind () != HIR::Item::ItemKind::Struct)
85 : {
86 4 : HIR::Item *item = hir_item.value ();
87 4 : std::string item_kind
88 4 : = HIR::Item::item_kind_string (item->get_item_kind ());
89 :
90 4 : std::string path_buf;
91 12 : for (size_t i = 0; i < pattern.get_segments ().size (); i++)
92 : {
93 8 : HIR::PathExprSegment &seg = pattern.get_segments ().at (i);
94 16 : path_buf += seg.to_string ();
95 8 : if (i != pattern.get_segments ().size () - 1)
96 4 : path_buf += "::";
97 : }
98 :
99 4 : rich_location rich_locus (
100 4 : line_table, pattern.get_final_segment ().get_locus ());
101 4 : rich_locus.add_fixit_replace (
102 : "not a unit struct, unit variant or constant");
103 4 : rust_error_at (rich_locus, ErrorCode::E0532,
104 : "expected unit struct, unit variant or constant, "
105 : "found %s %<%s%>",
106 : item_kind.c_str (), path_buf.c_str ());
107 4 : return;
108 4 : }
109 : }
110 : }
111 :
112 : // If the path is a constructor, it must be a unit struct or unit variants.
113 1108 : if (!path_is_const_item && pattern_ty->get_kind () == TyTy::TypeKind::ADT)
114 : {
115 1105 : TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (pattern_ty);
116 1105 : rust_assert (adt->get_variants ().size () > 0);
117 :
118 1105 : TyTy::VariantDef *variant = adt->get_variants ().at (0);
119 1105 : if (adt->is_enum ())
120 : {
121 1103 : HirId variant_id = UNKNOWN_HIRID;
122 1103 : bool ok = context->lookup_variant_definition (
123 1103 : pattern.get_mappings ().get_hirid (), &variant_id);
124 1103 : rust_assert (ok);
125 :
126 1103 : ok = adt->lookup_variant_by_id (variant_id, &variant);
127 1103 : rust_assert (ok);
128 : }
129 :
130 1105 : if (variant->get_variant_type () != TyTy::VariantDef::VariantType::NUM
131 1105 : && variant->get_variant_type ()
132 : != TyTy::VariantDef::VariantType::UNIT)
133 : {
134 3 : std::string variant_type = TyTy::VariantDef::variant_type_string (
135 3 : variant->get_variant_type ());
136 :
137 3 : rich_location rich_locus (line_table,
138 3 : pattern.get_final_segment ().get_locus ());
139 3 : rich_locus.add_fixit_replace (
140 : "not a unit struct, unit variant or constant");
141 3 : rust_error_at (rich_locus, ErrorCode::E0532,
142 : "expected unit struct, unit variant or constant, "
143 : "found %s variant %<%s::%s%>",
144 6 : variant_type.c_str (), adt->get_name ().c_str (),
145 3 : variant->get_identifier ().c_str ());
146 3 : return;
147 3 : }
148 :
149 1102 : infered = pattern_ty;
150 : }
151 : }
152 :
153 : void
154 1005 : TypeCheckPattern::visit (HIR::TupleStructPattern &pattern)
155 : {
156 1005 : TyTy::BaseType *pattern_ty = TypeCheckExpr::Resolve (pattern.get_path ());
157 1005 : if (pattern_ty->get_kind () != TyTy::TypeKind::ADT)
158 : {
159 2 : rust_error_at (
160 2 : pattern.get_locus (), ErrorCode::E0532,
161 : "expected tuple struct or tuple variant, found function %qs",
162 2 : pattern_ty->get_name ().c_str ());
163 6 : return;
164 : }
165 :
166 1003 : infered = pattern_ty;
167 1003 : TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (infered);
168 :
169 1003 : TyTy::VariantDef *variant = nullptr;
170 1003 : if (adt->is_enum ())
171 : {
172 939 : HirId variant_id = UNKNOWN_HIRID;
173 939 : bool ok = context->lookup_variant_definition (
174 939 : pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
175 939 : if (!ok)
176 : {
177 3 : rust_error_at (
178 3 : pattern.get_locus (), ErrorCode::E0532,
179 : "expected tuple struct or tuple variant, found enum %qs",
180 3 : pattern_ty->get_name ().c_str ());
181 3 : return;
182 : }
183 :
184 936 : ok = adt->lookup_variant_by_id (variant_id, &variant);
185 936 : rust_assert (ok);
186 : }
187 : else
188 : {
189 64 : rust_assert (adt->number_of_variants () > 0);
190 64 : variant = adt->get_variants ().at (0);
191 : }
192 :
193 1000 : rust_assert (variant != nullptr);
194 :
195 : // error[E0532]: expected tuple struct or tuple variant, found struct
196 : // variant `Foo::D`, E0532 by rustc 1.49.0 , E0164 by rustc 1.71.0
197 1000 : if (variant->get_variant_type () != TyTy::VariantDef::VariantType::TUPLE)
198 : {
199 1 : std::string variant_type
200 1 : = TyTy::VariantDef::variant_type_string (variant->get_variant_type ());
201 :
202 1 : rich_location rich_locus (line_table, pattern.get_locus ());
203 1 : rich_locus.add_fixit_replace ("not a tuple struct or tuple variant");
204 1 : rust_error_at (
205 : rich_locus, ErrorCode::E0164,
206 : "expected tuple struct or tuple variant, found %s variant %<%s::%s%>",
207 2 : variant_type.c_str (), adt->get_name ().c_str (),
208 1 : variant->get_identifier ().c_str ());
209 1 : return;
210 1 : }
211 :
212 : // check the elements
213 : // error[E0023]: this pattern has 2 fields, but the corresponding tuple
214 : // variant has 1 field
215 : // error[E0023]: this pattern has 0 fields, but the corresponding tuple
216 : // variant has 1 field
217 :
218 999 : auto &items = pattern.get_items ();
219 999 : switch (items.get_item_type ())
220 : {
221 38 : case HIR::TupleStructItems::HAS_REST:
222 38 : {
223 38 : HIR::TupleStructItemsHasRest &items_has_rest
224 : = static_cast<HIR::TupleStructItemsHasRest &> (items);
225 38 : auto &lower_patterns = items_has_rest.get_lower_patterns ();
226 38 : auto &upper_patterns = items_has_rest.get_upper_patterns ();
227 38 : size_t pattern_min_cap
228 38 : = lower_patterns.size () + upper_patterns.size ();
229 38 : if (variant->num_fields () < pattern_min_cap)
230 : {
231 2 : if (!lower_patterns.empty ())
232 : {
233 : // TODO initialize rich_locus with loc of ADT definition instead
234 1 : rich_location rich_locus (line_table,
235 1 : lower_patterns[0]->get_locus ());
236 3 : for (auto &pattern : lower_patterns)
237 : {
238 2 : if (pattern == lower_patterns[0])
239 1 : continue;
240 1 : rich_locus.add_range (pattern->get_locus (),
241 : SHOW_RANGE_WITH_CARET);
242 : }
243 3 : for (auto &pattern : upper_patterns)
244 : {
245 2 : rich_locus.add_range (pattern->get_locus (),
246 : SHOW_RANGE_WITH_CARET);
247 : }
248 3 : rust_error_at (rich_locus, ErrorCode::E0023,
249 : "this pattern has %lu %s but the corresponding "
250 : "tuple variant has %lu %s",
251 : (unsigned long) (pattern_min_cap),
252 : pattern_min_cap == 1 ? "field" : "fields",
253 1 : (unsigned long) variant->num_fields (),
254 1 : variant->num_fields () == 1 ? "field"
255 : : "fields");
256 1 : }
257 : else
258 : {
259 : // TODO initialize rich_locus with loc of ADT definition instead
260 1 : rich_location rich_locus (line_table,
261 1 : upper_patterns[0]->get_locus ());
262 4 : for (auto &pattern : upper_patterns)
263 : {
264 3 : if (pattern == upper_patterns[0])
265 1 : continue;
266 2 : rich_locus.add_range (pattern->get_locus (),
267 : SHOW_RANGE_WITH_CARET);
268 : }
269 3 : rust_error_at (rich_locus, ErrorCode::E0023,
270 : "this pattern has %lu %s but the corresponding "
271 : "tuple variant has %lu %s",
272 : (unsigned long) (pattern_min_cap),
273 : pattern_min_cap == 1 ? "field" : "fields",
274 1 : (unsigned long) variant->num_fields (),
275 1 : variant->num_fields () == 1 ? "field"
276 : : "fields");
277 1 : }
278 : // we continue on to try and setup the types as best we can for
279 : // type checking
280 : }
281 :
282 : // iterate the fields manually to set them up
283 38 : size_t i = 0;
284 69 : for (auto &pattern : lower_patterns)
285 : {
286 31 : if (i >= variant->num_fields ())
287 : break;
288 :
289 31 : TyTy::StructFieldType *field = variant->get_field_at_index (i++);
290 31 : TyTy::BaseType *fty = field->get_field_type ();
291 :
292 : // setup the type on this pattern type
293 31 : context->insert_type (pattern->get_mappings (), fty);
294 31 : TypeCheckPattern::Resolve (*pattern, fty);
295 : }
296 :
297 38 : i = variant->num_fields () - upper_patterns.size ();
298 54 : for (auto &pattern : upper_patterns)
299 : {
300 17 : if (i >= variant->num_fields ())
301 : break;
302 :
303 16 : TyTy::StructFieldType *field = variant->get_field_at_index (i++);
304 16 : TyTy::BaseType *fty = field->get_field_type ();
305 :
306 : // setup the type on this pattern type
307 16 : context->insert_type (pattern->get_mappings (), fty);
308 16 : TypeCheckPattern::Resolve (*pattern, fty);
309 : }
310 : }
311 : break;
312 :
313 961 : case HIR::TupleStructItems::NO_REST:
314 961 : {
315 961 : HIR::TupleStructItemsNoRest &items_no_rest
316 : = static_cast<HIR::TupleStructItemsNoRest &> (items);
317 961 : auto &patterns = items_no_rest.get_patterns ();
318 :
319 961 : if (patterns.size () != variant->num_fields ())
320 : {
321 2 : if (patterns.empty ())
322 : {
323 0 : rust_error_at (pattern.get_locus (), ErrorCode::E0023,
324 : "this pattern has %lu %s but the corresponding "
325 : "tuple variant has %lu %s",
326 0 : (unsigned long) patterns.size (),
327 0 : patterns.size () == 1 ? "field" : "fields",
328 0 : (unsigned long) variant->num_fields (),
329 0 : variant->num_fields () == 1 ? "field"
330 : : "fields");
331 : }
332 : else
333 : {
334 2 : rich_location rich_locus (line_table,
335 2 : patterns[0]->get_locus ());
336 8 : for (auto &pattern : items_no_rest.get_patterns ())
337 : {
338 6 : if (pattern == patterns[0])
339 2 : continue;
340 4 : rich_locus.add_range (pattern->get_locus (),
341 : SHOW_RANGE_WITH_CARET);
342 : }
343 2 : rust_error_at (rich_locus, ErrorCode::E0023,
344 : "this pattern has %lu %s but the corresponding "
345 : "tuple variant has %lu %s",
346 2 : (unsigned long) patterns.size (),
347 2 : patterns.size () == 1 ? "field" : "fields",
348 2 : (unsigned long) variant->num_fields (),
349 2 : variant->num_fields () == 1 ? "field"
350 : : "fields");
351 2 : }
352 : // we continue on to try and setup the types as best we can for
353 : // type checking
354 : }
355 :
356 : // iterate the fields and set them up, I wish we had ZIP
357 961 : size_t i = 0;
358 1998 : for (auto &pattern : items_no_rest.get_patterns ())
359 : {
360 1039 : if (i >= variant->num_fields ())
361 : break;
362 :
363 1037 : TyTy::StructFieldType *field = variant->get_field_at_index (i++);
364 1037 : TyTy::BaseType *fty = field->get_field_type ();
365 :
366 : // setup the type on this pattern type
367 1037 : context->insert_type (pattern->get_mappings (), fty);
368 1037 : TypeCheckPattern::Resolve (*pattern, fty);
369 : }
370 : }
371 : break;
372 : }
373 : }
374 :
375 : void
376 3 : emit_invalid_field_error (location_t loc, Rust::TyTy::VariantDef *variant,
377 : const std::string &name)
378 : {
379 3 : rust_error_at (loc, ErrorCode::E0026,
380 : "variant %s does not have a field named %s",
381 3 : variant->get_identifier ().c_str (), name.c_str ());
382 3 : }
383 :
384 : void
385 164 : TypeCheckPattern::visit (HIR::StructPattern &pattern)
386 : {
387 164 : TyTy::BaseType *pattern_ty = TypeCheckExpr::Resolve (pattern.get_path ());
388 164 : if (pattern_ty->get_kind () != TyTy::TypeKind::ADT)
389 : {
390 0 : rust_error_at (pattern.get_locus (),
391 : "expected tuple struct/variant, found: %s",
392 0 : pattern_ty->get_name ().c_str ());
393 3 : return;
394 : }
395 :
396 164 : infered = pattern_ty;
397 164 : TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (infered);
398 164 : if (adt->number_of_variants () == 0)
399 : {
400 0 : HIR::PathInExpression &path = pattern.get_path ();
401 0 : const AST::SimplePath &sp = path.as_simple_path ();
402 0 : rust_error_at (pattern.get_locus (), ErrorCode::E0574,
403 : "expected struct, variant or union type, found enum %qs",
404 0 : sp.as_string ().c_str ());
405 0 : return;
406 0 : }
407 :
408 164 : TyTy::VariantDef *variant = adt->get_variants ().at (0);
409 164 : if (adt->is_enum ())
410 : {
411 118 : HirId variant_id = UNKNOWN_HIRID;
412 118 : bool ok = context->lookup_variant_definition (
413 118 : pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
414 118 : if (!ok)
415 : {
416 1 : HIR::PathInExpression &path = pattern.get_path ();
417 1 : const AST::SimplePath &sp = path.as_simple_path ();
418 1 : rust_error_at (
419 1 : pattern.get_locus (), ErrorCode::E0574,
420 : "expected struct, variant or union type, found enum %qs",
421 1 : sp.as_string ().c_str ());
422 1 : return;
423 1 : }
424 :
425 117 : ok = adt->lookup_variant_by_id (variant_id, &variant);
426 117 : rust_assert (ok);
427 : }
428 :
429 : // error[E0532]: expected tuple struct or tuple variant, found struct
430 : // variant `Foo::D`
431 163 : bool error_E0532 = false;
432 163 : if (variant->get_variant_type () == TyTy::VariantDef::VariantType::TUPLE)
433 : {
434 : // Tuple structs can still be matched with struct patterns via index
435 : // numbers e.g. Foo {0: a, .., 3: b}, so check whether the fields are of
436 : // type TUPLE_PAT. Throw E0532 if not.
437 16 : auto &struct_pattern_elems = pattern.get_struct_pattern_elems ();
438 39 : for (auto &field : struct_pattern_elems.get_struct_pattern_fields ())
439 : {
440 25 : if (field->get_item_type ()
441 : != HIR::StructPatternField::ItemType::TUPLE_PAT)
442 : {
443 : error_E0532 = true;
444 : break;
445 : }
446 : }
447 : }
448 147 : else if (variant->get_variant_type ()
449 : != TyTy::VariantDef::VariantType::STRUCT)
450 : {
451 : error_E0532 = true;
452 : }
453 :
454 16 : if (error_E0532)
455 : {
456 2 : std::string variant_type
457 2 : = TyTy::VariantDef::variant_type_string (variant->get_variant_type ());
458 :
459 2 : rich_location rich_locus (line_table, pattern.get_locus ());
460 2 : std::string rich_msg = "use the tuple variant pattern syntax instead "
461 4 : + variant->get_identifier () + "(_)";
462 2 : rich_locus.add_fixit_replace (rich_msg.c_str ());
463 :
464 2 : rust_error_at (rich_locus, ErrorCode::E0769,
465 : "%s variant %qs written as struct variant",
466 : variant_type.c_str (),
467 2 : variant->get_identifier ().c_str ());
468 2 : return;
469 2 : }
470 :
471 161 : std::vector<std::string> named_fields;
472 161 : auto &struct_pattern_elems = pattern.get_struct_pattern_elems ();
473 432 : for (auto &field : struct_pattern_elems.get_struct_pattern_fields ())
474 : {
475 271 : switch (field->get_item_type ())
476 : {
477 23 : case HIR::StructPatternField::ItemType::TUPLE_PAT:
478 23 : {
479 23 : HIR::StructPatternFieldTuplePat &tuple_pat
480 23 : = static_cast<HIR::StructPatternFieldTuplePat &> (*field.get ());
481 :
482 23 : if ((size_t) tuple_pat.get_index () >= variant->num_fields ())
483 : {
484 2 : emit_invalid_field_error (tuple_pat.get_locus (), variant,
485 2 : std::to_string (
486 : tuple_pat.get_index ()));
487 2 : break;
488 : }
489 21 : named_fields.push_back (std::to_string (tuple_pat.get_index ()));
490 21 : TyTy::StructFieldType *field
491 21 : = variant->get_field_at_index (tuple_pat.get_index ());
492 21 : TyTy::BaseType *fty = field->get_field_type ();
493 21 : TypeCheckPattern::Resolve (tuple_pat.get_tuple_pattern (), fty);
494 : }
495 21 : break;
496 :
497 150 : case HIR::StructPatternField::ItemType::IDENT_PAT:
498 150 : {
499 150 : HIR::StructPatternFieldIdentPat &ident
500 150 : = static_cast<HIR::StructPatternFieldIdentPat &> (*field);
501 :
502 150 : TyTy::StructFieldType *field = nullptr;
503 150 : if (!variant->lookup_field (ident.get_identifier ().as_string (),
504 : &field, nullptr))
505 : {
506 0 : emit_invalid_field_error (ident.get_locus (), variant,
507 0 : ident.get_identifier ().as_string ());
508 0 : break;
509 : }
510 150 : named_fields.push_back (ident.get_identifier ().as_string ());
511 :
512 150 : TyTy::BaseType *fty = field->get_field_type ();
513 150 : TypeCheckPattern::Resolve (ident.get_pattern (), fty);
514 : }
515 150 : break;
516 :
517 98 : case HIR::StructPatternField::ItemType::IDENT:
518 98 : {
519 98 : HIR::StructPatternFieldIdent &ident
520 98 : = static_cast<HIR::StructPatternFieldIdent &> (*field);
521 :
522 98 : TyTy::StructFieldType *field = nullptr;
523 98 : if (!variant->lookup_field (ident.get_identifier ().as_string (),
524 : &field, nullptr))
525 : {
526 1 : emit_invalid_field_error (ident.get_locus (), variant,
527 1 : ident.get_identifier ().as_string ());
528 1 : break;
529 : }
530 97 : named_fields.push_back (ident.get_identifier ().as_string ());
531 :
532 : // setup the type on this pattern
533 97 : TyTy::BaseType *fty = field->get_field_type ();
534 97 : context->insert_type (ident.get_mappings (), fty);
535 : }
536 97 : break;
537 : }
538 : }
539 :
540 : // check the elements
541 161 : if (adt->is_union ())
542 : {
543 5 : auto &struct_pattern_elems = pattern.get_struct_pattern_elems ();
544 5 : if (struct_pattern_elems.get_struct_pattern_fields ().size () != 1)
545 2 : rust_error_at (pattern.get_locus (),
546 : "union patterns should have exactly one field");
547 :
548 : else
549 : {
550 6 : switch (struct_pattern_elems.get_struct_pattern_fields ()
551 3 : .at (0)
552 3 : ->get_item_type ())
553 : {
554 : case HIR::StructPatternField::ItemType::IDENT:
555 : case HIR::StructPatternField::ItemType::IDENT_PAT:
556 : break;
557 0 : default:
558 0 : {
559 0 : auto first_elem
560 0 : = struct_pattern_elems.get_struct_pattern_fields ()
561 0 : .at (0)
562 0 : ->to_string ();
563 0 : rust_error_at (pattern.get_locus (),
564 : "%qs cannot be used in union patterns",
565 : first_elem.c_str ());
566 0 : }
567 : }
568 : }
569 : }
570 : else
571 : {
572 : // Expects enum struct or struct struct.
573 : // error[E0027]: pattern does not mention fields `x`, `y`
574 : // error[E0026]: variant `Foo::D` does not have a field named `b`
575 156 : if (!pattern.get_struct_pattern_elems ().has_rest ()
576 307 : && named_fields.size () != variant->num_fields ())
577 : {
578 3 : std::map<std::string, bool> missing_names;
579 :
580 : // populate with all fields
581 9 : for (auto &field : variant->get_fields ())
582 6 : missing_names[field->get_name ()] = true;
583 :
584 : // then eliminate with named_fields
585 4 : for (auto &named : named_fields)
586 1 : missing_names.erase (named);
587 :
588 : // then get the list of missing names
589 3 : size_t i = 0;
590 3 : std::string missing_fields_str;
591 8 : for (auto it = missing_names.begin (); it != missing_names.end ();
592 5 : it++)
593 : {
594 5 : bool has_next = (i + 1) < missing_names.size ();
595 13 : missing_fields_str += it->first + (has_next ? ", " : "");
596 5 : i++;
597 : }
598 :
599 3 : rust_error_at (pattern.get_locus (), ErrorCode::E0027,
600 : "pattern does not mention fields %s",
601 : missing_fields_str.c_str ());
602 3 : }
603 : }
604 161 : }
605 :
606 : void
607 1261 : TypeCheckPattern::visit (HIR::WildcardPattern &pattern)
608 : {
609 : // wildcard patterns within the MatchArm's are simply just the same type as
610 : // the parent
611 1261 : infered = parent->clone ();
612 1261 : infered->set_ref (pattern.get_mappings ().get_hirid ());
613 1261 : }
614 :
615 : void
616 425 : TypeCheckPattern::visit (HIR::TuplePattern &pattern)
617 : {
618 425 : std::unique_ptr<HIR::TuplePatternItems> items;
619 :
620 : // Check whether parent is tuple
621 425 : auto resolved_parent = parent->destructure ();
622 425 : if (resolved_parent->get_kind () != TyTy::TUPLE)
623 : {
624 3 : rust_error_at (pattern.get_locus (), "expected %s, found tuple",
625 3 : parent->as_string ().c_str ());
626 3 : return;
627 : }
628 422 : TyTy::TupleType &par = *static_cast<TyTy::TupleType *> (resolved_parent);
629 :
630 422 : switch (pattern.get_items ().get_item_type ())
631 : {
632 394 : case HIR::TuplePatternItems::ItemType::NO_REST:
633 394 : {
634 394 : auto &ref
635 394 : = static_cast<HIR::TuplePatternItemsNoRest &> (pattern.get_items ());
636 :
637 394 : const auto &patterns = ref.get_patterns ();
638 394 : size_t nitems_to_resolve = patterns.size ();
639 :
640 394 : if (patterns.size () != par.get_fields ().size ())
641 : {
642 4 : emit_pattern_size_error (pattern, par.get_fields ().size (),
643 : patterns.size ());
644 4 : nitems_to_resolve
645 4 : = std::min (nitems_to_resolve, par.get_fields ().size ());
646 : }
647 :
648 394 : std::vector<TyTy::TyVar> pattern_elems;
649 1197 : for (size_t i = 0; i < nitems_to_resolve; i++)
650 : {
651 803 : auto &p = patterns[i];
652 803 : TyTy::BaseType *par_type = par.get_field (i);
653 :
654 803 : TyTy::BaseType *elem = TypeCheckPattern::Resolve (*p, par_type);
655 803 : pattern_elems.emplace_back (elem->get_ref ());
656 : }
657 788 : infered = new TyTy::TupleType (pattern.get_mappings ().get_hirid (),
658 788 : pattern.get_locus (), pattern_elems);
659 394 : }
660 394 : break;
661 :
662 28 : case HIR::TuplePatternItems::ItemType::HAS_REST:
663 28 : {
664 28 : HIR::TuplePatternItemsHasRest &ref
665 28 : = static_cast<HIR::TuplePatternItemsHasRest &> (pattern.get_items ());
666 :
667 28 : const auto &lower = ref.get_lower_patterns ();
668 28 : const auto &upper = ref.get_upper_patterns ();
669 28 : size_t min_size_required = lower.size () + upper.size ();
670 :
671 : // Ensure that size of lower and upper patterns <= parent size
672 28 : if (min_size_required > par.get_fields ().size ())
673 : {
674 3 : emit_pattern_size_error (pattern, par.get_fields ().size (),
675 : min_size_required);
676 : // continue and attempt to resolve individual items in the pattern
677 : }
678 :
679 : // Resolve lower patterns
680 28 : std::vector<TyTy::TyVar> pattern_elems;
681 28 : size_t nlower_items_to_resolve
682 28 : = std::min (lower.size (), par.get_fields ().size ());
683 57 : for (size_t i = 0; i < nlower_items_to_resolve; i++)
684 : {
685 29 : auto &p = lower[i];
686 29 : TyTy::BaseType *par_type = par.get_field (i);
687 :
688 29 : TyTy::BaseType *elem = TypeCheckPattern::Resolve (*p, par_type);
689 29 : pattern_elems.emplace_back (elem->get_ref ());
690 : }
691 :
692 28 : if (lower.size () > par.get_fields ().size ())
693 : break;
694 :
695 : // Pad pattern_elems until needing to resolve upper patterns
696 28 : size_t rest_end
697 28 : = std::max (par.get_fields ().size () - upper.size (), lower.size ());
698 74 : for (size_t i = lower.size (); i < rest_end; i++)
699 : {
700 46 : TyTy::BaseType *par_type = par.get_field (i);
701 46 : pattern_elems.emplace_back (par_type->get_ref ());
702 : }
703 :
704 28 : size_t nupper_items_to_resolve
705 28 : = std::min (upper.size (),
706 28 : par.get_fields ().size () - pattern_elems.size ());
707 : // Resolve upper patterns
708 56 : for (size_t i = 0; i < nupper_items_to_resolve; i++)
709 : {
710 28 : auto &p = upper[i];
711 28 : TyTy::BaseType *par_type = par.get_field (rest_end + i);
712 :
713 28 : TyTy::BaseType *elem = TypeCheckPattern::Resolve (*p, par_type);
714 28 : pattern_elems.emplace_back (elem->get_ref ());
715 : }
716 :
717 56 : infered = new TyTy::TupleType (pattern.get_mappings ().get_hirid (),
718 56 : pattern.get_locus (), pattern_elems);
719 0 : }
720 28 : break;
721 : }
722 425 : }
723 :
724 : void
725 425 : TypeCheckPattern::visit (HIR::LiteralPattern &pattern)
726 : {
727 425 : TyTy::BaseType *resolved
728 425 : = resolve_literal (pattern.get_mappings (), pattern.get_literal (),
729 425 : pattern.get_locus ());
730 425 : if (resolved->get_kind () == TyTy::TypeKind::ERROR)
731 : {
732 0 : infered = resolved;
733 0 : return;
734 : }
735 :
736 425 : infered = unify_site (pattern.get_mappings ().get_hirid (),
737 425 : TyTy::TyWithLocation (parent),
738 425 : TyTy::TyWithLocation (resolved), pattern.get_locus ());
739 : }
740 :
741 : void
742 40 : TypeCheckPattern::visit (HIR::RangePattern &pattern)
743 : {
744 : // Resolve the upper and lower bounds, and ensure they are compatible types
745 40 : TyTy::BaseType *upper = nullptr, *lower = nullptr;
746 :
747 40 : upper = typecheck_range_pattern_bound (pattern.get_upper_bound (),
748 40 : pattern.get_mappings (),
749 40 : pattern.get_locus ());
750 :
751 120 : lower = typecheck_range_pattern_bound (pattern.get_lower_bound (),
752 40 : pattern.get_mappings (),
753 40 : pattern.get_locus ());
754 :
755 40 : infered = unify_site (pattern.get_mappings ().get_hirid (),
756 40 : TyTy::TyWithLocation (upper),
757 40 : TyTy::TyWithLocation (lower), pattern.get_locus ());
758 40 : }
759 :
760 : void
761 38941 : TypeCheckPattern::visit (HIR::IdentifierPattern &pattern)
762 : {
763 38941 : if (pattern.has_subpattern ())
764 : {
765 17 : TypeCheckPattern::Resolve (pattern.get_subpattern (), parent);
766 : }
767 :
768 38941 : if (!pattern.get_is_ref ())
769 : {
770 38938 : infered = parent;
771 38938 : return;
772 : }
773 :
774 9 : infered = new TyTy::ReferenceType (pattern.get_mappings ().get_hirid (),
775 3 : TyTy::TyVar (parent->get_ref ()),
776 3 : pattern.is_mut () ? Mutability::Mut
777 6 : : Mutability::Imm);
778 : }
779 :
780 : void
781 0 : TypeCheckPattern::visit (HIR::QualifiedPathInExpression &pattern)
782 : {
783 0 : rust_sorry_at (pattern.get_locus (),
784 : "type checking qualified path patterns not supported");
785 0 : }
786 :
787 : void
788 199 : TypeCheckPattern::visit (HIR::ReferencePattern &pattern)
789 : {
790 199 : if (parent->get_kind () != TyTy::TypeKind::REF)
791 : {
792 1 : rust_error_at (pattern.get_locus (), "expected %s, found reference",
793 1 : parent->as_string ().c_str ());
794 1 : return;
795 : }
796 :
797 198 : auto &ref_ty_ty = static_cast<TyTy::ReferenceType &> (*parent);
798 198 : TyTy::BaseType *infered_base
799 198 : = TypeCheckPattern::Resolve (pattern.get_referenced_pattern (),
800 : ref_ty_ty.get_base ());
801 594 : infered = new TyTy::ReferenceType (pattern.get_mappings ().get_hirid (),
802 198 : TyTy::TyVar (infered_base->get_ref ()),
803 198 : pattern.is_mut () ? Mutability::Mut
804 396 : : Mutability::Imm);
805 : }
806 :
807 : void
808 76 : TypeCheckPattern::visit (HIR::SlicePattern &pattern)
809 : {
810 76 : auto resolved_parent = parent->destructure ();
811 76 : TyTy::BaseType *parent_element_ty = nullptr;
812 76 : switch (resolved_parent->get_kind ())
813 : {
814 37 : case TyTy::ARRAY:
815 37 : {
816 37 : auto &array_ty_ty = static_cast<TyTy::ArrayType &> (*parent);
817 37 : parent_element_ty = array_ty_ty.get_element_type ();
818 37 : auto capacity = array_ty_ty.get_capacity ();
819 :
820 37 : tree cap = error_mark_node;
821 37 : if (capacity->get_kind () != TyTy::TypeKind::CONST)
822 : {
823 : // Error case - capacity is not a const type
824 : break;
825 : }
826 :
827 37 : auto *capacity_const = capacity->as_const_type ();
828 37 : switch (capacity_const->const_kind ())
829 : {
830 37 : case TyTy::BaseConstType::ConstKind::Value:
831 37 : {
832 37 : const auto &const_value
833 : = *static_cast<TyTy::ConstValueType *> (capacity);
834 37 : cap = const_value.get_value ();
835 : }
836 37 : break;
837 :
838 0 : case TyTy::BaseConstType::ConstKind::Decl:
839 0 : case TyTy::BaseConstType::ConstKind::Infer:
840 0 : case TyTy::BaseConstType::ConstKind::Error:
841 0 : cap = error_mark_node;
842 0 : break;
843 : }
844 :
845 37 : if (error_operand_p (cap))
846 : {
847 0 : rust_error_at (parent->get_locus (),
848 : "capacity of array %qs is not known at compile time",
849 0 : array_ty_ty.get_name ().c_str ());
850 0 : break;
851 : }
852 37 : auto cap_wi = wi::to_wide (cap).to_uhwi ();
853 :
854 : // size check during compile time
855 37 : switch (pattern.get_items ().get_item_type ())
856 : {
857 16 : case HIR::SlicePatternItems::ItemType::NO_REST:
858 16 : {
859 16 : auto &ref = static_cast<HIR::SlicePatternItemsNoRest &> (
860 16 : pattern.get_items ());
861 16 : if (cap_wi != ref.get_patterns ().size ())
862 : {
863 2 : rust_error_at (
864 1 : pattern.get_locus (), ErrorCode::E0527,
865 : "pattern requires %lu elements but array has %lu",
866 1 : (unsigned long) ref.get_patterns ().size (),
867 : (unsigned long) cap_wi);
868 1 : break;
869 : }
870 : }
871 : break;
872 21 : case HIR::SlicePatternItems::ItemType::HAS_REST:
873 21 : {
874 21 : auto &ref = static_cast<HIR::SlicePatternItemsHasRest &> (
875 21 : pattern.get_items ());
876 21 : auto pattern_min_cap = ref.get_lower_patterns ().size ()
877 21 : + ref.get_upper_patterns ().size ();
878 :
879 21 : if (cap_wi < pattern_min_cap)
880 : {
881 0 : rust_error_at (pattern.get_locus (), ErrorCode::E0528,
882 : "pattern requires at least %lu elements but "
883 : "array has %lu",
884 : (unsigned long) pattern_min_cap,
885 : (unsigned long) cap_wi);
886 0 : break;
887 : }
888 : }
889 : break;
890 : }
891 :
892 : break;
893 : }
894 0 : case TyTy::SLICE:
895 0 : {
896 0 : auto &slice_ty_ty = static_cast<TyTy::SliceType &> (*parent);
897 0 : parent_element_ty = slice_ty_ty.get_element_type ();
898 0 : break;
899 : }
900 39 : case TyTy::REF:
901 39 : {
902 39 : auto &ref_ty_ty = static_cast<TyTy::ReferenceType &> (*parent);
903 39 : const TyTy::SliceType *slice = nullptr;
904 39 : if (!ref_ty_ty.is_dyn_slice_type (&slice))
905 : {
906 0 : rust_error_at (pattern.get_locus (), "expected %s, found slice",
907 0 : parent->as_string ().c_str ());
908 0 : return;
909 : }
910 39 : parent_element_ty = slice->get_element_type ();
911 39 : break;
912 : }
913 0 : default:
914 0 : {
915 0 : rust_error_at (pattern.get_locus (), "expected %s, found slice",
916 0 : parent->as_string ().c_str ());
917 0 : return;
918 : }
919 : }
920 :
921 76 : rust_assert (parent_element_ty != nullptr);
922 : // infered inherits array/slice typing from parent
923 76 : infered = parent->clone ();
924 76 : infered->set_ref (pattern.get_mappings ().get_hirid ());
925 :
926 : // Type check every item in the SlicePattern against parent's element ty
927 76 : switch (pattern.get_items ().get_item_type ())
928 : {
929 32 : case HIR::SlicePatternItems::ItemType::NO_REST:
930 32 : {
931 32 : auto &ref
932 32 : = static_cast<HIR::SlicePatternItemsNoRest &> (pattern.get_items ());
933 96 : for (const auto &pattern_member : ref.get_patterns ())
934 : {
935 64 : TypeCheckPattern::Resolve (*pattern_member, parent_element_ty);
936 : }
937 : break;
938 : }
939 44 : case HIR::SlicePatternItems::ItemType::HAS_REST:
940 44 : {
941 44 : auto &ref
942 44 : = static_cast<HIR::SlicePatternItemsHasRest &> (pattern.get_items ());
943 87 : for (const auto &pattern_member : ref.get_lower_patterns ())
944 : {
945 43 : TypeCheckPattern::Resolve (*pattern_member, parent_element_ty);
946 : }
947 87 : for (const auto &pattern_member : ref.get_upper_patterns ())
948 : {
949 43 : TypeCheckPattern::Resolve (*pattern_member, parent_element_ty);
950 : }
951 : break;
952 : }
953 : }
954 : }
955 :
956 : void
957 7 : TypeCheckPattern::emit_pattern_size_error (const HIR::Pattern &pattern,
958 : size_t expected_field_count,
959 : size_t got_field_count)
960 : {
961 7 : rich_location r (line_table, pattern.get_locus ());
962 7 : r.add_range (mappings.lookup_location (parent->get_ref ()));
963 18 : rust_error_at (r,
964 : "expected a tuple with %lu %s, found one "
965 : "with %lu %s",
966 : (unsigned long) expected_field_count,
967 : expected_field_count == 1 ? "element" : "elements",
968 : (unsigned long) got_field_count,
969 : got_field_count == 1 ? "element" : "elements");
970 7 : }
971 :
972 : TyTy::BaseType *
973 80 : TypeCheckPattern::typecheck_range_pattern_bound (
974 : Rust::HIR::RangePatternBound &bound, Analysis::NodeMapping mappings,
975 : location_t locus)
976 : {
977 80 : TyTy::BaseType *resolved_bound = nullptr;
978 80 : switch (bound.get_bound_type ())
979 : {
980 59 : case HIR::RangePatternBound::RangePatternBoundType::LITERAL:
981 59 : {
982 59 : auto &ref = static_cast<HIR::RangePatternBoundLiteral &> (bound);
983 :
984 59 : HIR::Literal lit = ref.get_literal ();
985 :
986 59 : resolved_bound = resolve_literal (mappings, lit, locus);
987 59 : }
988 59 : break;
989 :
990 21 : case HIR::RangePatternBound::RangePatternBoundType::PATH:
991 21 : {
992 21 : auto &ref = static_cast<HIR::RangePatternBoundPath &> (bound);
993 :
994 21 : resolved_bound = TypeCheckExpr::Resolve (ref.get_path ());
995 : }
996 21 : break;
997 :
998 0 : case HIR::RangePatternBound::RangePatternBoundType::QUALPATH:
999 0 : {
1000 0 : auto &ref = static_cast<HIR::RangePatternBoundQualPath &> (bound);
1001 :
1002 0 : resolved_bound = TypeCheckExpr::Resolve (ref.get_qualified_path ());
1003 : }
1004 0 : break;
1005 : }
1006 :
1007 80 : return resolved_bound;
1008 : }
1009 :
1010 : void
1011 145 : TypeCheckPattern::visit (HIR::AltPattern &pattern)
1012 : {
1013 145 : const auto &alts = pattern.get_alts ();
1014 :
1015 : // lub - taken from TypeCheckExpr::visit(ArrayExpr)
1016 145 : std::vector<TyTy::BaseType *> types;
1017 436 : for (auto &alt_pattern : alts)
1018 : {
1019 291 : types.push_back (TypeCheckPattern::Resolve (*alt_pattern, parent));
1020 : }
1021 :
1022 145 : TyTy::BaseType *alt_pattern_type
1023 145 : = TyTy::TyVar::get_implicit_infer_var (pattern.get_locus ()).get_tyty ();
1024 :
1025 436 : for (auto &type : types)
1026 : {
1027 291 : alt_pattern_type
1028 291 : = unify_site (pattern.get_mappings ().get_hirid (),
1029 291 : TyTy::TyWithLocation (alt_pattern_type),
1030 291 : TyTy::TyWithLocation (type, type->get_locus ()),
1031 291 : pattern.get_locus ());
1032 : }
1033 :
1034 145 : infered = alt_pattern_type;
1035 145 : }
1036 :
1037 : TyTy::BaseType *
1038 3 : ClosureParamInfer::Resolve (HIR::Pattern &pattern)
1039 : {
1040 3 : ClosureParamInfer resolver;
1041 3 : pattern.accept_vis (resolver);
1042 :
1043 3 : if (resolver.infered->get_kind () != TyTy::TypeKind::ERROR)
1044 : {
1045 3 : resolver.context->insert_implicit_type (resolver.infered->get_ref (),
1046 : resolver.infered);
1047 3 : resolver.mappings.insert_location (resolver.infered->get_ref (),
1048 3 : pattern.get_locus ());
1049 : }
1050 3 : return resolver.infered;
1051 3 : }
1052 :
1053 3 : ClosureParamInfer::ClosureParamInfer ()
1054 3 : : TypeCheckBase (), infered (new TyTy::ErrorType (0))
1055 3 : {}
1056 :
1057 : void
1058 1 : ClosureParamInfer::visit (HIR::WildcardPattern &pattern)
1059 : {
1060 1 : HirId id = pattern.get_mappings ().get_hirid ();
1061 1 : infered = new TyTy::InferType (id, TyTy::InferType::InferTypeKind::GENERAL,
1062 : TyTy::InferType::TypeHint::Default (),
1063 1 : pattern.get_locus ());
1064 1 : }
1065 :
1066 : void
1067 1 : ClosureParamInfer::visit (HIR::IdentifierPattern &pattern)
1068 : {
1069 1 : if (pattern.has_subpattern ())
1070 : {
1071 0 : ClosureParamInfer::Resolve (pattern.get_subpattern ());
1072 : }
1073 :
1074 1 : HirId id = pattern.get_mappings ().get_hirid ();
1075 1 : infered = new TyTy::InferType (id, TyTy::InferType::InferTypeKind::GENERAL,
1076 : TyTy::InferType::TypeHint::Default (),
1077 1 : pattern.get_locus ());
1078 1 : }
1079 :
1080 : void
1081 1 : ClosureParamInfer::visit (HIR::ReferencePattern &pattern)
1082 : {
1083 1 : TyTy::BaseType *element
1084 1 : = ClosureParamInfer::Resolve (pattern.get_referenced_pattern ());
1085 :
1086 1 : HirId id = pattern.get_mappings ().get_hirid ();
1087 1 : infered = new TyTy::ReferenceType (id, TyTy::TyVar (element->get_ref ()),
1088 2 : pattern.get_mutability ());
1089 1 : }
1090 :
1091 : void
1092 0 : ClosureParamInfer::visit (HIR::PathInExpression &pattern)
1093 : {
1094 0 : rust_sorry_at (pattern.get_locus (),
1095 : "unable to infer this kind of parameter pattern");
1096 0 : }
1097 :
1098 : void
1099 0 : ClosureParamInfer::visit (HIR::StructPattern &pattern)
1100 : {
1101 0 : rust_sorry_at (pattern.get_locus (),
1102 : "unable to infer this kind of parameter pattern");
1103 0 : }
1104 :
1105 : void
1106 0 : ClosureParamInfer::visit (HIR::TupleStructPattern &pattern)
1107 : {
1108 0 : rust_sorry_at (pattern.get_locus (),
1109 : "unable to infer this kind of parameter pattern");
1110 0 : }
1111 :
1112 : void
1113 0 : ClosureParamInfer::visit (HIR::TuplePattern &pattern)
1114 : {
1115 0 : rust_sorry_at (pattern.get_locus (),
1116 : "unable to infer this kind of parameter pattern");
1117 0 : }
1118 :
1119 : void
1120 0 : ClosureParamInfer::visit (HIR::LiteralPattern &pattern)
1121 : {
1122 0 : rust_sorry_at (pattern.get_locus (),
1123 : "unable to infer this kind of parameter pattern");
1124 0 : }
1125 :
1126 : void
1127 0 : ClosureParamInfer::visit (HIR::RangePattern &pattern)
1128 : {
1129 0 : rust_sorry_at (pattern.get_locus (),
1130 : "unable to infer this kind of parameter pattern");
1131 0 : }
1132 :
1133 : void
1134 0 : ClosureParamInfer::visit (HIR::QualifiedPathInExpression &pattern)
1135 : {
1136 0 : rust_sorry_at (pattern.get_locus (),
1137 : "unable to infer this kind of parameter pattern");
1138 0 : }
1139 :
1140 : void
1141 0 : ClosureParamInfer::visit (HIR::SlicePattern &pattern)
1142 : {
1143 0 : rust_sorry_at (pattern.get_locus (),
1144 : "unable to infer this kind of parameter pattern");
1145 0 : }
1146 :
1147 : void
1148 0 : ClosureParamInfer::visit (HIR::AltPattern &pattern)
1149 : {
1150 0 : rust_sorry_at (pattern.get_locus (),
1151 : "unable to infer this kind of parameter pattern");
1152 0 : }
1153 :
1154 : } // namespace Resolver
1155 : } // namespace Rust
|