Skip to content

Commit 96ec7ca

Browse files
committed
gccrs: Add typecheck for path patterns.
gcc/rust/ChangeLog: * hir/tree/rust-hir.cc (Item::item_kind_string): New function. * hir/tree/rust-hir.h: New function. * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): Modify to check all arms in match expressions even if some of them has errors. * typecheck/rust-hir-type-check-pattern.cc (TypeCheckPattern::visit): Add and fix check for path patterns. gcc/testsuite/ChangeLog: * rust/compile/issue-2324-2.rs: Fix error message. * rust/compile/match8.rs: New test. Signed-off-by: Raiki Tamura <[email protected]>
1 parent be1e78b commit 96ec7ca

File tree

6 files changed

+175
-28
lines changed

6 files changed

+175
-28
lines changed

gcc/rust/hir/tree/rust-hir.cc

+38
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,44 @@ Module::as_string () const
212212
return str + "\n";
213213
}
214214

215+
std::string
216+
Item::item_kind_string (Item::ItemKind kind)
217+
{
218+
switch (kind)
219+
{
220+
case Item::ItemKind::Static:
221+
return "static";
222+
case Item::ItemKind::Constant:
223+
return "constant";
224+
case Item::ItemKind::TypeAlias:
225+
return "type alias";
226+
case Item::ItemKind::Function:
227+
return "function";
228+
case Item::ItemKind::UseDeclaration:
229+
return "use declaration";
230+
case Item::ItemKind::ExternBlock:
231+
return "extern block";
232+
case Item::ItemKind::ExternCrate:
233+
return "extern crate";
234+
case Item::ItemKind::Struct:
235+
return "struct";
236+
case Item::ItemKind::Union:
237+
return "union";
238+
case Item::ItemKind::Enum:
239+
return "enum";
240+
case Item::ItemKind::EnumItem:
241+
return "enum item";
242+
case Item::ItemKind::Trait:
243+
return "trait";
244+
case Item::ItemKind::Impl:
245+
return "impl";
246+
case Item::ItemKind::Module:
247+
return "module";
248+
default:
249+
rust_unreachable ();
250+
}
251+
}
252+
215253
std::string
216254
StaticItem::as_string () const
217255
{

gcc/rust/hir/tree/rust-hir.h

+2
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,8 @@ class Item : public Stmt, public WithOuterAttrs
220220
Module,
221221
};
222222

223+
static std::string item_kind_string (ItemKind kind);
224+
223225
virtual ItemKind get_item_kind () const = 0;
224226

225227
// Unique pointer custom clone function

gcc/rust/typecheck/rust-hir-type-check-expr.cc

+11-2
Original file line numberDiff line numberDiff line change
@@ -1462,6 +1462,7 @@ TypeCheckExpr::visit (HIR::MatchExpr &expr)
14621462
TyTy::BaseType *scrutinee_tyty
14631463
= TypeCheckExpr::Resolve (expr.get_scrutinee_expr ().get ());
14641464

1465+
bool saw_error = false;
14651466
std::vector<TyTy::BaseType *> kase_block_tys;
14661467
for (auto &kase : expr.get_match_cases ())
14671468
{
@@ -1472,7 +1473,10 @@ TypeCheckExpr::visit (HIR::MatchExpr &expr)
14721473
TyTy::BaseType *kase_arm_ty
14731474
= TypeCheckPattern::Resolve (pattern.get (), scrutinee_tyty);
14741475
if (kase_arm_ty->get_kind () == TyTy ::TypeKind::ERROR)
1475-
return;
1476+
{
1477+
saw_error = true;
1478+
continue;
1479+
}
14761480

14771481
TyTy::BaseType *checked_kase = unify_site (
14781482
expr.get_mappings ().get_hirid (),
@@ -1481,14 +1485,19 @@ TypeCheckExpr::visit (HIR::MatchExpr &expr)
14811485
TyTy::TyWithLocation (kase_arm_ty, pattern->get_locus ()),
14821486
expr.get_locus ());
14831487
if (checked_kase->get_kind () == TyTy::TypeKind::ERROR)
1484-
return;
1488+
{
1489+
saw_error = true;
1490+
continue;
1491+
}
14851492
}
14861493

14871494
// check the kase type
14881495
TyTy::BaseType *kase_block_ty
14891496
= TypeCheckExpr::Resolve (kase.get_expr ().get ());
14901497
kase_block_tys.push_back (kase_block_ty);
14911498
}
1499+
if (saw_error)
1500+
return;
14921501

14931502
if (kase_block_tys.size () == 0)
14941503
{

gcc/rust/typecheck/rust-hir-type-check-pattern.cc

+93-25
Original file line numberDiff line numberDiff line change
@@ -43,32 +43,100 @@ TypeCheckPattern::Resolve (HIR::Pattern *pattern, TyTy::BaseType *parent)
4343
void
4444
TypeCheckPattern::visit (HIR::PathInExpression &pattern)
4545
{
46-
infered = TypeCheckExpr::Resolve (&pattern);
47-
48-
/*
49-
* We are compiling a PathInExpression, which can't be a Struct or Tuple
50-
* pattern. We should check that the declaration we are referencing IS NOT a
51-
* struct pattern or tuple with values.
52-
*/
46+
// Pattern must be enum variants, sturcts, constants, or associated constansts
47+
TyTy::BaseType *pattern_ty = TypeCheckExpr::Resolve (&pattern);
48+
49+
NodeId ref_node_id = UNKNOWN_NODEID;
50+
bool maybe_item = false;
51+
maybe_item
52+
|= resolver->lookup_resolved_name (pattern.get_mappings ().get_nodeid (),
53+
&ref_node_id);
54+
maybe_item
55+
|= resolver->lookup_resolved_type (pattern.get_mappings ().get_nodeid (),
56+
&ref_node_id);
57+
bool path_is_const_item = false;
58+
59+
if (maybe_item)
60+
{
61+
tl::optional<HirId> definition_id
62+
= mappings.lookup_node_to_hir (ref_node_id);
63+
rust_assert (definition_id.has_value ());
64+
HirId def_id = definition_id.value ();
65+
66+
tl::optional<HIR::Item *> hir_item = mappings.lookup_hir_item (def_id);
67+
// If the path refrerences an item, it must be constants or structs.
68+
if (hir_item.has_value ())
69+
{
70+
HIR::Item *item = hir_item.value ();
71+
if (item->get_item_kind () == HIR::Item::ItemKind::Constant)
72+
{
73+
path_is_const_item = true;
74+
}
75+
else if (item->get_item_kind () != HIR::Item::ItemKind::Struct)
76+
{
77+
HIR::Item *item = hir_item.value ();
78+
std::string item_kind
79+
= HIR::Item::item_kind_string (item->get_item_kind ());
80+
81+
std::string path_buf;
82+
for (size_t i = 0; i < pattern.get_segments ().size (); i++)
83+
{
84+
HIR::PathExprSegment &seg = pattern.get_segments ().at (i);
85+
path_buf += seg.as_string ();
86+
if (i != pattern.get_segments ().size () - 1)
87+
path_buf += "::";
88+
}
89+
90+
rich_location rich_locus (
91+
line_table, pattern.get_final_segment ().get_locus ());
92+
rich_locus.add_fixit_replace (
93+
"not a unit struct, unit variant or constatnt");
94+
rust_error_at (rich_locus, ErrorCode::E0532,
95+
"expected unit struct, unit variant or constant, "
96+
"found %s %<%s%>",
97+
item_kind.c_str (), path_buf.c_str ());
98+
return;
99+
}
100+
}
101+
}
53102

54-
rust_assert (infered->get_kind () == TyTy::TypeKind::ADT);
55-
TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (infered);
103+
// If the path is a constructor, it must be a unit struct or unit variants.
104+
if (!path_is_const_item && pattern_ty->get_kind () == TyTy::TypeKind::ADT)
105+
{
106+
TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (pattern_ty);
107+
rust_assert (adt->get_variants ().size () > 0);
56108

57-
HirId variant_id = UNKNOWN_HIRID;
58-
bool ok
59-
= context->lookup_variant_definition (pattern.get_mappings ().get_hirid (),
60-
&variant_id);
61-
rust_assert (ok);
109+
TyTy::VariantDef *variant = adt->get_variants ().at (0);
110+
if (adt->is_enum ())
111+
{
112+
HirId variant_id = UNKNOWN_HIRID;
113+
bool ok = context->lookup_variant_definition (
114+
pattern.get_mappings ().get_hirid (), &variant_id);
115+
rust_assert (ok);
62116

63-
TyTy::VariantDef *variant = nullptr;
64-
ok = adt->lookup_variant_by_id (variant_id, &variant);
117+
ok = adt->lookup_variant_by_id (variant_id, &variant);
118+
rust_assert (ok);
119+
}
65120

66-
TyTy::VariantDef::VariantType vty = variant->get_variant_type ();
121+
if (variant->get_variant_type () != TyTy::VariantDef::VariantType::NUM)
122+
{
123+
std::string variant_type = TyTy::VariantDef::variant_type_string (
124+
variant->get_variant_type ());
125+
126+
rich_location rich_locus (line_table,
127+
pattern.get_final_segment ().get_locus ());
128+
rich_locus.add_fixit_replace (
129+
"not a unit struct, unit variant or constatnt");
130+
rust_error_at (rich_locus, ErrorCode::E0532,
131+
"expected unit struct, unit variant or constant, "
132+
"found %s variant %<%s::%s%>",
133+
variant_type.c_str (), adt->get_name ().c_str (),
134+
variant->get_identifier ().c_str ());
135+
return;
136+
}
67137

68-
if (vty != TyTy::VariantDef::VariantType::NUM)
69-
rust_error_at (
70-
pattern.get_final_segment ().get_locus (), ErrorCode::E0532,
71-
"expected unit struct, unit variant or constant, found tuple variant");
138+
infered = pattern_ty;
139+
}
72140
}
73141

74142
void
@@ -100,8 +168,8 @@ TypeCheckPattern::visit (HIR::TupleStructPattern &pattern)
100168
rust_assert (ok);
101169
}
102170

103-
// error[E0532]: expected tuple struct or tuple variant, found struct variant
104-
// `Foo::D`, E0532 by rustc 1.49.0 , E0164 by rustc 1.71.0
171+
// error[E0532]: expected tuple struct or tuple variant, found struct
172+
// variant `Foo::D`, E0532 by rustc 1.49.0 , E0164 by rustc 1.71.0
105173
if (variant->get_variant_type () != TyTy::VariantDef::VariantType::TUPLE)
106174
{
107175
std::string variant_type
@@ -203,8 +271,8 @@ TypeCheckPattern::visit (HIR::StructPattern &pattern)
203271
rust_assert (ok);
204272
}
205273

206-
// error[E0532]: expected tuple struct or tuple variant, found struct variant
207-
// `Foo::D`
274+
// error[E0532]: expected tuple struct or tuple variant, found struct
275+
// variant `Foo::D`
208276
if (variant->get_variant_type () != TyTy::VariantDef::VariantType::STRUCT)
209277
{
210278
std::string variant_type

gcc/testsuite/rust/compile/issue-2324-2.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ enum State {
66
fn print_on_failure(state: &State) {
77
match *state {
88
State::Succeeded => (),
9-
State::Failed => (), // { dg-error "expected unit struct, unit variant or constant, found tuple variant" }
9+
State::Failed => (), // { dg-error "expected unit struct, unit variant or constant, found struct variant" }
1010
_ => ()
1111
}
1212
}

gcc/testsuite/rust/compile/match8.rs

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
enum E {
2+
A(),
3+
B,
4+
}
5+
6+
const CONST_E: E = E::A();
7+
8+
static static_e: E = E::A();
9+
10+
type type_alias = E;
11+
12+
fn f(e: E) {
13+
match e {
14+
E::A => {}
15+
// { dg-error "expected unit struct, unit variant or constant, found tuple variant .E::A." "" { target *-*-* } .-1 }
16+
E::B => {}
17+
crate::CONST_E => {}
18+
crate::type_alias => {}
19+
// { dg-error "expected unit struct, unit variant or constant, found type alias .crate::type_alias." "" { target *-*-* } .-1 }
20+
crate::E => {}
21+
// { dg-error "expected unit struct, unit variant or constant, found enum .crate::E." "" { target *-*-* } .-1 }
22+
crate::static_e => {}
23+
// { dg-error "expected unit struct, unit variant or constant, found static .crate::static_e." "" { target *-*-* } .-1 }
24+
crate::f => {}
25+
// { dg-error "expected unit struct, unit variant or constant, found function .crate::f." "" { target *-*-* } .-1 }
26+
_ => {}
27+
}
28+
}
29+
30+
fn main() {}

0 commit comments

Comments
 (0)