From e13277e56ec2c19b2cbc598ea5bbc31747367600 Mon Sep 17 00:00:00 2001 From: Yap Zhi Heng Date: Sun, 28 Sep 2025 19:11:31 +0800 Subject: [PATCH] gccrs: Fix StructPattern type checking rejecting tuple struct scrutinee Previously, type checking of StructPattern will throw an error if it is used to match against a tuple struct, even though it is possible to do so in rustc. gcc/rust/ChangeLog: * typecheck/rust-hir-type-check-pattern.cc (visit(StructPattern)): Add type check support for StructPatterns matching against a TUPLE type ADT. * backend/rust-compile-pattern.cc(CompilePatternBindings::visit(StructPattern)): Update assert to allow TUPLE type ADTs. * hir/tree/rust-hir.cc (StructPatternField::as_string()): Improve info dumped. Signed-off-by: Yap Zhi Heng --- gcc/rust/backend/rust-compile-pattern.cc | 5 ++- gcc/rust/hir/tree/rust-hir.cc | 21 ++++++++++- .../typecheck/rust-hir-type-check-pattern.cc | 37 ++++++++++++++++--- 3 files changed, 54 insertions(+), 9 deletions(-) diff --git a/gcc/rust/backend/rust-compile-pattern.cc b/gcc/rust/backend/rust-compile-pattern.cc index 149f6b07411..9ebb4d1dd63 100644 --- a/gcc/rust/backend/rust-compile-pattern.cc +++ b/gcc/rust/backend/rust-compile-pattern.cc @@ -885,8 +885,9 @@ CompilePatternBindings::visit (HIR::StructPattern &pattern) rust_assert (ok); } - rust_assert (variant->get_variant_type () - == TyTy::VariantDef::VariantType::STRUCT); + rust_assert ( + variant->get_variant_type () == TyTy::VariantDef::VariantType::STRUCT + || variant->get_variant_type () == TyTy::VariantDef::VariantType::TUPLE); auto &struct_pattern_elems = pattern.get_struct_pattern_elems (); for (auto &field : struct_pattern_elems.get_struct_pattern_fields ()) diff --git a/gcc/rust/hir/tree/rust-hir.cc b/gcc/rust/hir/tree/rust-hir.cc index 7aad4ef2730..ce10b02303c 100644 --- a/gcc/rust/hir/tree/rust-hir.cc +++ b/gcc/rust/hir/tree/rust-hir.cc @@ -2519,10 +2519,29 @@ StructPatternField::as_string () const * just the body */ for (const auto &attr : outer_attrs) { - str += "\n " + attr.as_string (); + str += "\n " + attr.as_string (); } } + str += "\n item type: "; + switch (get_item_type ()) + { + case ItemType::TUPLE_PAT: + str += "TUPLE_PAT"; + break; + case ItemType::IDENT_PAT: + str += "IDENT_PAT"; + break; + case ItemType::IDENT: + str += "IDENT"; + break; + default: + str += "UNKNOWN"; + break; + } + + str += "\n mapping: " + mappings.as_string (); + return str; } diff --git a/gcc/rust/typecheck/rust-hir-type-check-pattern.cc b/gcc/rust/typecheck/rust-hir-type-check-pattern.cc index 7b405510bb3..e964318bf7c 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-pattern.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-pattern.cc @@ -299,7 +299,30 @@ TypeCheckPattern::visit (HIR::StructPattern &pattern) // error[E0532]: expected tuple struct or tuple variant, found struct // variant `Foo::D` - if (variant->get_variant_type () != TyTy::VariantDef::VariantType::STRUCT) + bool error_E0532 = false; + if (variant->get_variant_type () == TyTy::VariantDef::VariantType::TUPLE) + { + // Tuple structs can still be matched with struct patterns via index + // numbers e.g. Foo {0: a, .., 3: b}, so check whether the fields are of + // type TUPLE_PAT. Throw E0532 if not. + auto &struct_pattern_elems = pattern.get_struct_pattern_elems (); + for (auto &field : struct_pattern_elems.get_struct_pattern_fields ()) + { + if (field->get_item_type () + != HIR::StructPatternField::ItemType::TUPLE_PAT) + { + error_E0532 = true; + break; + } + } + } + else if (variant->get_variant_type () + != TyTy::VariantDef::VariantType::STRUCT) + { + error_E0532 = true; + } + + if (error_E0532) { std::string variant_type = TyTy::VariantDef::variant_type_string (variant->get_variant_type ()); @@ -508,7 +531,8 @@ TypeCheckPattern::visit (HIR::TuplePattern &pattern) { emit_pattern_size_error (pattern, par.get_fields ().size (), min_size_required); - // TODO attempt to continue to do typechecking even after wrong size + // TODO attempt to continue to do typechecking even after wrong + // size break; } @@ -680,10 +704,11 @@ TypeCheckPattern::visit (HIR::SlicePattern &pattern) if (cap_wi < pattern_min_cap) { - rust_error_at ( - pattern.get_locus (), ErrorCode::E0528, - "pattern requires at least %lu elements but array has %lu", - (unsigned long) pattern_min_cap, (unsigned long) cap_wi); + rust_error_at (pattern.get_locus (), ErrorCode::E0528, + "pattern requires at least %lu elements but " + "array has %lu", + (unsigned long) pattern_min_cap, + (unsigned long) cap_wi); break; } } -- 2.47.3