Skip to content

Commit 9e1e0c7

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 9e1e0c7

File tree

6 files changed

+171
-28
lines changed

6 files changed

+171
-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

+90-25
Original file line numberDiff line numberDiff line change
@@ -43,32 +43,97 @@ 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+
58+
if (maybe_item)
59+
{
60+
tl::optional<HirId> definition_id
61+
= mappings.lookup_node_to_hir (ref_node_id);
62+
rust_assert (definition_id.has_value ());
63+
HirId def_id = definition_id.value ();
64+
65+
tl::optional<HIR::Item *> hir_item = mappings.lookup_hir_item (def_id);
66+
// If the path refrerences an item, it must be constants or structs.
67+
if (hir_item.has_value ())
68+
{
69+
HIR::Item *item = hir_item.value ();
70+
71+
if (item->get_item_kind () != HIR::Item::ItemKind::Constant
72+
&& item->get_item_kind () != HIR::Item::ItemKind::Struct)
73+
{
74+
HIR::Item *item = hir_item.value ();
75+
std::string item_kind
76+
= HIR::Item::item_kind_string (item->get_item_kind ());
77+
78+
std::string path_buf;
79+
for (size_t i = 0; i < pattern.get_segments ().size (); i++)
80+
{
81+
HIR::PathExprSegment &seg = pattern.get_segments ().at (i);
82+
path_buf += seg.as_string ();
83+
if (i != pattern.get_segments ().size () - 1)
84+
path_buf += "::";
85+
}
86+
87+
rich_location rich_locus (
88+
line_table, pattern.get_final_segment ().get_locus ());
89+
rich_locus.add_fixit_replace (
90+
"not a unit struct, unit variant or constatnt");
91+
rust_error_at (rich_locus, ErrorCode::E0532,
92+
"expected unit struct, unit variant or constant, "
93+
"found %s %<%s%>",
94+
item_kind.c_str (), path_buf.c_str ());
95+
return;
96+
}
97+
}
98+
}
5399

54-
rust_assert (infered->get_kind () == TyTy::TypeKind::ADT);
55-
TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (infered);
100+
// If the path is of type ADT, it must be a unit struct or unit variants.
101+
if (pattern_ty->get_kind () == TyTy::TypeKind::ADT)
102+
{
103+
TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (pattern_ty);
104+
rust_assert (adt->get_variants ().size () > 0);
56105

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);
106+
TyTy::VariantDef *variant = adt->get_variants ().at (0);
107+
if (adt->is_enum ())
108+
{
109+
HirId variant_id = UNKNOWN_HIRID;
110+
bool ok = context->lookup_variant_definition (
111+
pattern.get_mappings ().get_hirid (), &variant_id);
112+
rust_assert (ok);
62113

63-
TyTy::VariantDef *variant = nullptr;
64-
ok = adt->lookup_variant_by_id (variant_id, &variant);
114+
ok = adt->lookup_variant_by_id (variant_id, &variant);
115+
rust_assert (ok);
116+
}
65117

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

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");
135+
infered = pattern_ty;
136+
}
72137
}
73138

74139
void
@@ -100,8 +165,8 @@ TypeCheckPattern::visit (HIR::TupleStructPattern &pattern)
100165
rust_assert (ok);
101166
}
102167

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
168+
// error[E0532]: expected tuple struct or tuple variant, found struct
169+
// variant `Foo::D`, E0532 by rustc 1.49.0 , E0164 by rustc 1.71.0
105170
if (variant->get_variant_type () != TyTy::VariantDef::VariantType::TUPLE)
106171
{
107172
std::string variant_type
@@ -203,8 +268,8 @@ TypeCheckPattern::visit (HIR::StructPattern &pattern)
203268
rust_assert (ok);
204269
}
205270

206-
// error[E0532]: expected tuple struct or tuple variant, found struct variant
207-
// `Foo::D`
271+
// error[E0532]: expected tuple struct or tuple variant, found struct
272+
// variant `Foo::D`
208273
if (variant->get_variant_type () != TyTy::VariantDef::VariantType::STRUCT)
209274
{
210275
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

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
enum E {
2+
A(),
3+
B,
4+
}
5+
6+
static static_e: E = E::A();
7+
8+
struct S;
9+
10+
type type_alias = S;
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::type_alias => {}
18+
// { dg-error "expected unit struct, unit variant or constant, found type alias .crate::type_alias." "" { target *-*-* } .-1 }
19+
crate::E => {}
20+
// { dg-error "expected unit struct, unit variant or constant, found enum .crate::E." "" { target *-*-* } .-1 }
21+
crate::static_e => {}
22+
// { dg-error "expected unit struct, unit variant or constant, found static .crate::static_e." "" { target *-*-* } .-1 }
23+
crate::f => {}
24+
// { dg-error "expected unit struct, unit variant or constant, found function .crate::f." "" { target *-*-* } .-1 }
25+
_ => {}
26+
}
27+
}
28+
29+
fn main() {}

0 commit comments

Comments
 (0)