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