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
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
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"
26 TypeCheckPattern::TypeCheckPattern (TyTy::BaseType
*parent
)
27 : TypeCheckBase (), parent (parent
), infered (new TyTy::ErrorType (0))
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
;
44 TypeCheckPattern::visit (HIR::PathInExpression
&pattern
)
46 infered
= TypeCheckExpr::Resolve (&pattern
);
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
)
56 pattern
.get_locus (), ErrorCode::E0532
,
57 "expected tuple struct or tuple variant, found function %qs",
58 pattern_ty
->get_name ().c_str ());
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);
69 HirId variant_id
= UNKNOWN_HIRID
;
70 bool ok
= context
->lookup_variant_definition (
71 pattern
.get_path ().get_mappings ().get_hirid (), &variant_id
);
74 ok
= adt
->lookup_variant_by_id (variant_id
, &variant
);
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");
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 ());
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
: {
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 ())
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
126 // iterate the fields and set them up, I wish we had ZIP
128 for (auto &pattern
: items_no_range
.get_patterns ())
130 if (i
>= variant
->num_fields ())
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
);
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 ());
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 ());
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);
172 HirId variant_id
= UNKNOWN_HIRID
;
173 bool ok
= context
->lookup_variant_definition (
174 pattern
.get_path ().get_mappings ().get_hirid (), &variant_id
);
177 ok
= adt
->lookup_variant_by_id (variant_id
, &variant
);
181 // error[E0532]: expected tuple struct or tuple variant, found struct variant
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 ());
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
: {
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 (),
224 emit_invalid_field_error (ident
.get_locus (), variant
,
225 ident
.get_identifier ().as_string ());
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
);
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 (),
243 emit_invalid_field_error (ident
.get_locus (), variant
,
244 ident
.get_identifier ().as_string ());
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
);
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
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
? ", " : "");
279 rust_error_at (pattern
.get_locus (), ErrorCode::E0027
,
280 "pattern does not mention fields %s",
281 missing_fields_str
.c_str ());
286 TypeCheckPattern::visit (HIR::WildcardPattern
&pattern
)
288 // wildcard patterns within the MatchArm's are simply just the same type as
290 infered
= parent
->clone ();
291 infered
->set_ref (pattern
.get_mappings ().get_hirid ());
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 ());
313 const auto &patterns
= ref
.get_patterns ();
314 size_t nitems_to_resolve
= patterns
.size ();
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 (),
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
);
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
);
341 case HIR::TuplePatternItems::ItemType::RANGED
: {
342 // HIR::TuplePatternItemsRanged &ref
343 // = *static_cast<HIR::TuplePatternItemsRanged *> (
344 // pattern.get_items ().get ());
353 TypeCheckPattern::visit (HIR::LiteralPattern
&pattern
)
355 infered
= resolve_literal (pattern
.get_mappings (), pattern
.get_literal (),
356 pattern
.get_locus ());
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 ());
379 TypeCheckPattern::visit (HIR::IdentifierPattern
&)
385 TypeCheckPattern::visit (HIR::QualifiedPathInExpression
&pattern
)
387 rust_sorry_at (pattern
.get_locus (),
388 "type checking qualified path patterns not supported");
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 ());
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
412 TypeCheckPattern::visit (HIR::SlicePattern
&pattern
)
414 rust_sorry_at (pattern
.get_locus (),
415 "type checking qualified path patterns not supported");
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 ()));
426 "expected a tuple with %lu %s, found one "
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");
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
);
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 ());
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 ());
469 return resolved_bound
;
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
)
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
;
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))
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 ());
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 ());
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 ());
548 ClosureParamInfer::visit (HIR::PathInExpression
&pattern
)
550 rust_sorry_at (pattern
.get_locus (),
551 "unable to infer this kind of parameter pattern");
555 ClosureParamInfer::visit (HIR::StructPattern
&pattern
)
557 rust_sorry_at (pattern
.get_locus (),
558 "unable to infer this kind of parameter pattern");
562 ClosureParamInfer::visit (HIR::TupleStructPattern
&pattern
)
564 rust_sorry_at (pattern
.get_locus (),
565 "unable to infer this kind of parameter pattern");
569 ClosureParamInfer::visit (HIR::TuplePattern
&pattern
)
571 rust_sorry_at (pattern
.get_locus (),
572 "unable to infer this kind of parameter pattern");
576 ClosureParamInfer::visit (HIR::LiteralPattern
&pattern
)
578 rust_sorry_at (pattern
.get_locus (),
579 "unable to infer this kind of parameter pattern");
583 ClosureParamInfer::visit (HIR::RangePattern
&pattern
)
585 rust_sorry_at (pattern
.get_locus (),
586 "unable to infer this kind of parameter pattern");
590 ClosureParamInfer::visit (HIR::QualifiedPathInExpression
&pattern
)
592 rust_sorry_at (pattern
.get_locus (),
593 "unable to infer this kind of parameter pattern");
597 ClosureParamInfer::visit (HIR::SlicePattern
&pattern
)
599 rust_sorry_at (pattern
.get_locus (),
600 "unable to infer this kind of parameter pattern");
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