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