[PR testsuite/116860] Testsuite adjustment for recently added tests
[official-gcc.git] / gcc / rust / typecheck / rust-hir-type-check-pattern.cc
blobaa0efdac7bf809c52050bb06444427cfcf0a87f8
1 // Copyright (C) 2020-2025 Free Software Foundation, Inc.
3 // This file is part of GCC.
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.
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.
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/>.
19 #include "rust-hir-type-check-pattern.h"
20 #include "rust-hir-type-check-expr.h"
21 #include "rust-type-util.h"
23 namespace Rust {
24 namespace Resolver {
26 TypeCheckPattern::TypeCheckPattern (TyTy::BaseType *parent)
27 : TypeCheckBase (), parent (parent), infered (new TyTy::ErrorType (0))
30 TyTy::BaseType *
31 TypeCheckPattern::Resolve (HIR::Pattern *pattern, TyTy::BaseType *parent)
33 TypeCheckPattern resolver (parent);
34 pattern->accept_vis (resolver);
36 if (resolver.infered == nullptr)
37 return new TyTy::ErrorType (pattern->get_mappings ().get_hirid ());
39 resolver.context->insert_type (pattern->get_mappings (), resolver.infered);
40 return resolver.infered;
43 void
44 TypeCheckPattern::visit (HIR::PathInExpression &pattern)
46 infered = TypeCheckExpr::Resolve (&pattern);
49 void
50 TypeCheckPattern::visit (HIR::TupleStructPattern &pattern)
52 TyTy::BaseType *pattern_ty = TypeCheckExpr::Resolve (&pattern.get_path ());
53 if (pattern_ty->get_kind () != TyTy::TypeKind::ADT)
55 rust_error_at (
56 pattern.get_locus (), ErrorCode::E0532,
57 "expected tuple struct or tuple variant, found function %qs",
58 pattern_ty->get_name ().c_str ());
59 return;
62 infered = pattern_ty;
63 TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (infered);
64 rust_assert (adt->number_of_variants () > 0);
66 TyTy::VariantDef *variant = adt->get_variants ().at (0);
67 if (adt->is_enum ())
69 HirId variant_id = UNKNOWN_HIRID;
70 bool ok = context->lookup_variant_definition (
71 pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
72 rust_assert (ok);
74 ok = adt->lookup_variant_by_id (variant_id, &variant);
75 rust_assert (ok);
78 // error[E0532]: expected tuple struct or tuple variant, found struct variant
79 // `Foo::D`, E0532 by rustc 1.49.0 , E0164 by rustc 1.71.0
80 if (variant->get_variant_type () != TyTy::VariantDef::VariantType::TUPLE)
82 std::string variant_type
83 = TyTy::VariantDef::variant_type_string (variant->get_variant_type ());
85 rich_location rich_locus (line_table, pattern.get_locus ());
86 rich_locus.add_fixit_replace ("not a tuple struct or tuple variant");
87 rust_error_at (
88 rich_locus, ErrorCode::E0164,
89 "expected tuple struct or tuple variant, found %s variant %<%s::%s%>",
90 variant_type.c_str (), adt->get_name ().c_str (),
91 variant->get_identifier ().c_str ());
92 return;
95 // check the elements
96 // error[E0023]: this pattern has 2 fields, but the corresponding tuple
97 // variant has 1 field
98 // error[E0023]: this pattern has 0 fields, but the corresponding tuple
99 // variant has 1 field
101 std::unique_ptr<HIR::TupleStructItems> &items = pattern.get_items ();
102 switch (items->get_item_type ())
104 case HIR::TupleStructItems::RANGED: {
105 // TODO
106 rust_unreachable ();
108 break;
110 case HIR::TupleStructItems::MULTIPLE: {
111 HIR::TupleStructItemsNoRange &items_no_range
112 = static_cast<HIR::TupleStructItemsNoRange &> (*items.get ());
114 if (items_no_range.get_patterns ().size () != variant->num_fields ())
116 rust_error_at (
117 pattern.get_locus (), ErrorCode::E0023,
118 "this pattern has %lu fields but the corresponding "
119 "tuple variant has %lu field",
120 (unsigned long) items_no_range.get_patterns ().size (),
121 (unsigned long) variant->num_fields ());
122 // we continue on to try and setup the types as best we can for
123 // type checking
126 // iterate the fields and set them up, I wish we had ZIP
127 size_t i = 0;
128 for (auto &pattern : items_no_range.get_patterns ())
130 if (i >= variant->num_fields ())
131 break;
133 TyTy::StructFieldType *field = variant->get_field_at_index (i++);
134 TyTy::BaseType *fty = field->get_field_type ();
136 // setup the type on this pattern type
137 context->insert_type (pattern->get_mappings (), fty);
140 break;
144 void
145 emit_invalid_field_error (location_t loc, Rust::TyTy::VariantDef *variant,
146 const std::string &name)
148 rust_error_at (loc, ErrorCode::E0026,
149 "variant %s does not have a field named %s",
150 variant->get_identifier ().c_str (), name.c_str ());
153 void
154 TypeCheckPattern::visit (HIR::StructPattern &pattern)
156 TyTy::BaseType *pattern_ty = TypeCheckExpr::Resolve (&pattern.get_path ());
157 if (pattern_ty->get_kind () != TyTy::TypeKind::ADT)
159 rust_error_at (pattern.get_locus (),
160 "expected tuple struct/variant, found: %s",
161 pattern_ty->get_name ().c_str ());
162 return;
165 infered = pattern_ty;
166 TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (infered);
167 rust_assert (adt->number_of_variants () > 0);
169 TyTy::VariantDef *variant = adt->get_variants ().at (0);
170 if (adt->is_enum ())
172 HirId variant_id = UNKNOWN_HIRID;
173 bool ok = context->lookup_variant_definition (
174 pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
175 rust_assert (ok);
177 ok = adt->lookup_variant_by_id (variant_id, &variant);
178 rust_assert (ok);
181 // error[E0532]: expected tuple struct or tuple variant, found struct variant
182 // `Foo::D`
183 if (variant->get_variant_type () != TyTy::VariantDef::VariantType::STRUCT)
185 std::string variant_type
186 = TyTy::VariantDef::variant_type_string (variant->get_variant_type ());
188 rich_location rich_locus (line_table, pattern.get_locus ());
189 std::string rich_msg = "use the tuple variant pattern syntax instead "
190 + variant->get_identifier () + "(_)";
191 rich_locus.add_fixit_replace (rich_msg.c_str ());
193 rust_error_at (rich_locus, ErrorCode::E0769,
194 "%s variant %qs written as struct variant",
195 variant_type.c_str (),
196 variant->get_identifier ().c_str ());
197 return;
200 // check the elements
201 // error[E0027]: pattern does not mention fields `x`, `y`
202 // error[E0026]: variant `Foo::D` does not have a field named `b`
204 std::vector<std::string> named_fields;
205 auto &struct_pattern_elems = pattern.get_struct_pattern_elems ();
206 for (auto &field : struct_pattern_elems.get_struct_pattern_fields ())
208 switch (field->get_item_type ())
210 case HIR::StructPatternField::ItemType::TUPLE_PAT: {
211 // TODO
212 rust_unreachable ();
214 break;
216 case HIR::StructPatternField::ItemType::IDENT_PAT: {
217 HIR::StructPatternFieldIdentPat &ident
218 = static_cast<HIR::StructPatternFieldIdentPat &> (*field.get ());
220 TyTy::StructFieldType *field = nullptr;
221 if (!variant->lookup_field (ident.get_identifier ().as_string (),
222 &field, nullptr))
224 emit_invalid_field_error (ident.get_locus (), variant,
225 ident.get_identifier ().as_string ());
226 break;
228 named_fields.push_back (ident.get_identifier ().as_string ());
230 TyTy::BaseType *fty = field->get_field_type ();
231 TypeCheckPattern::Resolve (ident.get_pattern ().get (), fty);
233 break;
235 case HIR::StructPatternField::ItemType::IDENT: {
236 HIR::StructPatternFieldIdent &ident
237 = static_cast<HIR::StructPatternFieldIdent &> (*field.get ());
239 TyTy::StructFieldType *field = nullptr;
240 if (!variant->lookup_field (ident.get_identifier ().as_string (),
241 &field, nullptr))
243 emit_invalid_field_error (ident.get_locus (), variant,
244 ident.get_identifier ().as_string ());
245 break;
247 named_fields.push_back (ident.get_identifier ().as_string ());
249 // setup the type on this pattern
250 TyTy::BaseType *fty = field->get_field_type ();
251 context->insert_type (ident.get_mappings (), fty);
253 break;
257 if (named_fields.size () != variant->num_fields ())
259 std::map<std::string, bool> missing_names;
261 // populate with all fields
262 for (auto &field : variant->get_fields ())
263 missing_names[field->get_name ()] = true;
265 // then eliminate with named_fields
266 for (auto &named : named_fields)
267 missing_names.erase (named);
269 // then get the list of missing names
270 size_t i = 0;
271 std::string missing_fields_str;
272 for (auto it = missing_names.begin (); it != missing_names.end (); it++)
274 bool has_next = (i + 1) < missing_names.size ();
275 missing_fields_str += it->first + (has_next ? ", " : "");
276 i++;
279 rust_error_at (pattern.get_locus (), ErrorCode::E0027,
280 "pattern does not mention fields %s",
281 missing_fields_str.c_str ());
285 void
286 TypeCheckPattern::visit (HIR::WildcardPattern &pattern)
288 // wildcard patterns within the MatchArm's are simply just the same type as
289 // the parent
290 infered = parent->clone ();
291 infered->set_ref (pattern.get_mappings ().get_hirid ());
294 void
295 TypeCheckPattern::visit (HIR::TuplePattern &pattern)
297 std::unique_ptr<HIR::TuplePatternItems> items;
298 switch (pattern.get_items ()->get_item_type ())
300 case HIR::TuplePatternItems::ItemType::MULTIPLE: {
301 HIR::TuplePatternItemsMultiple &ref
302 = *static_cast<HIR::TuplePatternItemsMultiple *> (
303 pattern.get_items ().get ());
305 auto resolved_parent = parent->destructure ();
306 if (resolved_parent->get_kind () != TyTy::TUPLE)
308 rust_error_at (pattern.get_locus (), "expected %s, found tuple",
309 parent->as_string ().c_str ());
310 break;
313 const auto &patterns = ref.get_patterns ();
314 size_t nitems_to_resolve = patterns.size ();
316 TyTy::TupleType &par
317 = *static_cast<TyTy::TupleType *> (resolved_parent);
318 if (patterns.size () != par.get_fields ().size ())
320 emit_pattern_size_error (pattern, par.get_fields ().size (),
321 patterns.size ());
322 nitems_to_resolve
323 = std::min (nitems_to_resolve, par.get_fields ().size ());
326 std::vector<TyTy::TyVar> pattern_elems;
327 for (size_t i = 0; i < nitems_to_resolve; i++)
329 auto &p = patterns[i];
330 TyTy::BaseType *par_type = par.get_field (i);
332 TyTy::BaseType *elem
333 = TypeCheckPattern::Resolve (p.get (), par_type);
334 pattern_elems.push_back (TyTy::TyVar (elem->get_ref ()));
336 infered = new TyTy::TupleType (pattern.get_mappings ().get_hirid (),
337 pattern.get_locus (), pattern_elems);
339 break;
341 case HIR::TuplePatternItems::ItemType::RANGED: {
342 // HIR::TuplePatternItemsRanged &ref
343 // = *static_cast<HIR::TuplePatternItemsRanged *> (
344 // pattern.get_items ().get ());
345 // TODO
346 rust_unreachable ();
348 break;
352 void
353 TypeCheckPattern::visit (HIR::LiteralPattern &pattern)
355 infered = resolve_literal (pattern.get_mappings (), pattern.get_literal (),
356 pattern.get_locus ());
359 void
360 TypeCheckPattern::visit (HIR::RangePattern &pattern)
362 // Resolve the upper and lower bounds, and ensure they are compatible types
363 TyTy::BaseType *upper = nullptr, *lower = nullptr;
365 upper = typecheck_range_pattern_bound (pattern.get_upper_bound (),
366 pattern.get_mappings (),
367 pattern.get_locus ());
369 lower = typecheck_range_pattern_bound (pattern.get_lower_bound (),
370 pattern.get_mappings (),
371 pattern.get_locus ());
373 infered = unify_site (pattern.get_mappings ().get_hirid (),
374 TyTy::TyWithLocation (upper),
375 TyTy::TyWithLocation (lower), pattern.get_locus ());
378 void
379 TypeCheckPattern::visit (HIR::IdentifierPattern &)
381 infered = parent;
384 void
385 TypeCheckPattern::visit (HIR::QualifiedPathInExpression &pattern)
387 rust_sorry_at (pattern.get_locus (),
388 "type checking qualified path patterns not supported");
391 void
392 TypeCheckPattern::visit (HIR::ReferencePattern &pattern)
394 if (parent->get_kind () != TyTy::TypeKind::REF)
396 rust_error_at (pattern.get_locus (), "expected %s, found reference",
397 parent->as_string ().c_str ());
398 return;
401 TyTy::ReferenceType *ref_ty_ty = static_cast<TyTy::ReferenceType *> (parent);
402 TyTy::BaseType *infered_base
403 = TypeCheckPattern::Resolve (pattern.get_referenced_pattern ().get (),
404 ref_ty_ty->get_base ());
405 infered = new TyTy::ReferenceType (pattern.get_mappings ().get_hirid (),
406 TyTy::TyVar (infered_base->get_ref ()),
407 pattern.is_mut () ? Mutability::Mut
408 : Mutability::Imm);
411 void
412 TypeCheckPattern::visit (HIR::SlicePattern &pattern)
414 rust_sorry_at (pattern.get_locus (),
415 "type checking qualified path patterns not supported");
418 void
419 TypeCheckPattern::emit_pattern_size_error (const HIR::Pattern &pattern,
420 size_t expected_field_count,
421 size_t got_field_count)
423 rich_location r (line_table, pattern.get_locus ());
424 r.add_range (mappings->lookup_location (parent->get_ref ()));
425 rust_error_at (r,
426 "expected a tuple with %lu %s, found one "
427 "with %lu %s",
428 (unsigned long) expected_field_count,
429 expected_field_count == 1 ? "element" : "elements",
430 (unsigned long) got_field_count,
431 got_field_count == 1 ? "element" : "elements");
434 TyTy::BaseType *
435 TypeCheckPattern::typecheck_range_pattern_bound (
436 std::unique_ptr<Rust::HIR::RangePatternBound> &bound,
437 Analysis::NodeMapping mappings, location_t locus)
439 TyTy::BaseType *resolved_bound = nullptr;
440 switch (bound->get_bound_type ())
442 case HIR::RangePatternBound::RangePatternBoundType::LITERAL: {
443 HIR::RangePatternBoundLiteral &ref
444 = *static_cast<HIR::RangePatternBoundLiteral *> (bound.get ());
446 HIR::Literal lit = ref.get_literal ();
448 resolved_bound = resolve_literal (mappings, lit, locus);
450 break;
452 case HIR::RangePatternBound::RangePatternBoundType::PATH: {
453 HIR::RangePatternBoundPath &ref
454 = *static_cast<HIR::RangePatternBoundPath *> (bound.get ());
456 resolved_bound = TypeCheckExpr::Resolve (&ref.get_path ());
458 break;
460 case HIR::RangePatternBound::RangePatternBoundType::QUALPATH: {
461 HIR::RangePatternBoundQualPath &ref
462 = *static_cast<HIR::RangePatternBoundQualPath *> (bound.get ());
464 resolved_bound = TypeCheckExpr::Resolve (&ref.get_qualified_path ());
466 break;
469 return resolved_bound;
472 void
473 TypeCheckPattern::visit (HIR::AltPattern &pattern)
475 const auto &alts = pattern.get_alts ();
477 // lub - taken from TypeCheckExpr::visit(ArrayExpr)
478 std::vector<TyTy::BaseType *> types;
479 for (auto &alt_pattern : alts)
481 types.push_back (TypeCheckPattern::Resolve (alt_pattern.get (), parent));
484 TyTy::BaseType *alt_pattern_type
485 = TyTy::TyVar::get_implicit_infer_var (pattern.get_locus ()).get_tyty ();
487 for (auto &type : types)
489 alt_pattern_type
490 = unify_site (pattern.get_mappings ().get_hirid (),
491 TyTy::TyWithLocation (alt_pattern_type),
492 TyTy::TyWithLocation (type, type->get_locus ()),
493 pattern.get_locus ());
496 infered = alt_pattern_type;
499 TyTy::BaseType *
500 ClosureParamInfer::Resolve (HIR::Pattern *pattern)
502 ClosureParamInfer resolver;
503 pattern->accept_vis (resolver);
505 if (resolver.infered->get_kind () != TyTy::TypeKind::ERROR)
507 resolver.context->insert_implicit_type (resolver.infered);
508 resolver.mappings->insert_location (resolver.infered->get_ref (),
509 pattern->get_locus ());
511 return resolver.infered;
514 ClosureParamInfer::ClosureParamInfer ()
515 : TypeCheckBase (), infered (new TyTy::ErrorType (0))
518 void
519 ClosureParamInfer::visit (HIR::WildcardPattern &pattern)
521 HirId id = pattern.get_mappings ().get_hirid ();
522 infered = new TyTy::InferType (id, TyTy::InferType::InferTypeKind::GENERAL,
523 TyTy::InferType::TypeHint::Default (),
524 pattern.get_locus ());
527 void
528 ClosureParamInfer::visit (HIR::IdentifierPattern &pattern)
530 HirId id = pattern.get_mappings ().get_hirid ();
531 infered = new TyTy::InferType (id, TyTy::InferType::InferTypeKind::GENERAL,
532 TyTy::InferType::TypeHint::Default (),
533 pattern.get_locus ());
536 void
537 ClosureParamInfer::visit (HIR::ReferencePattern &pattern)
539 TyTy::BaseType *element
540 = ClosureParamInfer::Resolve (pattern.get_referenced_pattern ().get ());
542 HirId id = pattern.get_mappings ().get_hirid ();
543 infered = new TyTy::ReferenceType (id, TyTy::TyVar (element->get_ref ()),
544 pattern.get_mutability ());
547 void
548 ClosureParamInfer::visit (HIR::PathInExpression &pattern)
550 rust_sorry_at (pattern.get_locus (),
551 "unable to infer this kind of parameter pattern");
554 void
555 ClosureParamInfer::visit (HIR::StructPattern &pattern)
557 rust_sorry_at (pattern.get_locus (),
558 "unable to infer this kind of parameter pattern");
561 void
562 ClosureParamInfer::visit (HIR::TupleStructPattern &pattern)
564 rust_sorry_at (pattern.get_locus (),
565 "unable to infer this kind of parameter pattern");
568 void
569 ClosureParamInfer::visit (HIR::TuplePattern &pattern)
571 rust_sorry_at (pattern.get_locus (),
572 "unable to infer this kind of parameter pattern");
575 void
576 ClosureParamInfer::visit (HIR::LiteralPattern &pattern)
578 rust_sorry_at (pattern.get_locus (),
579 "unable to infer this kind of parameter pattern");
582 void
583 ClosureParamInfer::visit (HIR::RangePattern &pattern)
585 rust_sorry_at (pattern.get_locus (),
586 "unable to infer this kind of parameter pattern");
589 void
590 ClosureParamInfer::visit (HIR::QualifiedPathInExpression &pattern)
592 rust_sorry_at (pattern.get_locus (),
593 "unable to infer this kind of parameter pattern");
596 void
597 ClosureParamInfer::visit (HIR::SlicePattern &pattern)
599 rust_sorry_at (pattern.get_locus (),
600 "unable to infer this kind of parameter pattern");
603 void
604 ClosureParamInfer::visit (HIR::AltPattern &pattern)
606 rust_sorry_at (pattern.get_locus (),
607 "unable to infer this kind of parameter pattern");
610 } // namespace Resolver
611 } // namespace Rust