Skip to content

Commit a8a3456

Browse files
bors[bot]philberty
andauthored
Merge #839
839: Add typechecking for match-expr r=philberty a=philberty This adds in the type checking pass for the match expression including static analysis for errors such as: - error[E0532]: expected tuple struct or tuple variant, found struct variant `Foo::D` - error[E0027]: pattern does not mention fields `x`, `y` - error[E0026]: variant `Foo::D` does not have a field named `b` - error[E0532]: expected tuple struct or tuple variant, found struct variant `Foo::D` Addresses #190 Co-authored-by: Philip Herron <[email protected]>
2 parents e8d91e9 + 45edfc2 commit a8a3456

13 files changed

+474
-12
lines changed

gcc/rust/Make-lang.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ GRS_OBJS = \
8989
rust/rust-hir-type-check-type.o \
9090
rust/rust-hir-type-check-struct.o \
9191
rust/rust-hir-address-taken.o \
92+
rust/rust-hir-type-check-pattern.o \
9293
rust/rust-substitution-mapper.o \
9394
rust/rust-lint-marklive.o \
9495
rust/rust-hir-type-check-path.o \

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

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3614,15 +3614,9 @@ struct MatchArm
36143614
{
36153615
private:
36163616
AST::AttrVec outer_attrs;
3617-
// MatchArmPatterns patterns;
3618-
std::vector<std::unique_ptr<Pattern> > match_arm_patterns; // inlined
3619-
3620-
// bool has_match_arm_guard;
3621-
// inlined from MatchArmGuard
3617+
std::vector<std::unique_ptr<Pattern> > match_arm_patterns;
36223618
std::unique_ptr<Expr> guard_expr;
36233619

3624-
// TODO: should this store location data?
3625-
36263620
public:
36273621
// Returns whether the MatchArm has a match arm guard expression
36283622
bool has_match_arm_guard () const { return guard_expr != nullptr; }
@@ -3679,6 +3673,11 @@ struct MatchArm
36793673
}
36803674

36813675
std::string as_string () const;
3676+
3677+
std::vector<std::unique_ptr<Pattern> > &get_patterns ()
3678+
{
3679+
return match_arm_patterns;
3680+
}
36823681
};
36833682

36843683
/* A "match case" - a correlated match arm and resulting expression. Not
@@ -3718,6 +3717,9 @@ struct MatchCase
37183717
std::string as_string () const;
37193718

37203719
Analysis::NodeMapping get_mappings () const { return mappings; }
3720+
3721+
MatchArm &get_arm () { return arm; }
3722+
std::unique_ptr<Expr> &get_expr () { return expr; }
37213723
};
37223724

37233725
#if 0
@@ -3868,6 +3870,15 @@ class MatchExpr : public ExprWithBlock
38683870

38693871
void accept_vis (HIRVisitor &vis) override;
38703872

3873+
std::unique_ptr<Expr> &get_scrutinee_expr ()
3874+
{
3875+
rust_assert (branch_value != nullptr);
3876+
return branch_value;
3877+
}
3878+
3879+
const std::vector<MatchCase> &get_match_cases () const { return match_arms; }
3880+
std::vector<MatchCase> &get_match_cases () { return match_arms; }
3881+
38713882
protected:
38723883
/* Use covariance to implement clone function as returning this object rather
38733884
* than base */

gcc/rust/resolve/rust-ast-resolve-pattern.cc

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ PatternDeclaration::visit (AST::TupleStructPattern &pattern)
4949
for (auto &inner_pattern : items_no_range.get_patterns ())
5050
{
5151
PatternDeclaration::go (inner_pattern.get (),
52-
pattern.get_node_id ());
52+
inner_pattern->get_pattern_node_id ());
5353
}
5454
}
5555
break;
@@ -85,10 +85,10 @@ PatternDeclaration::visit (AST::StructPattern &pattern)
8585
resolver->get_name_scope ().insert (
8686
CanonicalPath::new_seg (ident.get_node_id (),
8787
ident.get_identifier ()),
88-
ident.get_node_id (), pattern.get_locus ());
89-
resolver->insert_new_definition (
90-
ident.get_node_id (),
91-
Definition{ident.get_node_id (), pattern.get_node_id ()});
88+
ident.get_node_id (), ident.get_locus ());
89+
resolver->insert_new_definition (ident.get_node_id (),
90+
Definition{ident.get_node_id (),
91+
ident.get_node_id ()});
9292
resolver->mark_decl_mutability (ident.get_node_id (),
9393
ident.is_mut ());
9494
}

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

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "rust-hir-type-bounds.h"
3333
#include "rust-hir-dot-operator.h"
3434
#include "rust-hir-address-taken.h"
35+
#include "rust-hir-type-check-pattern.h"
3536

3637
namespace Rust {
3738
namespace Resolver {
@@ -51,6 +52,9 @@ class TypeCheckExpr : public TypeCheckBase
5152

5253
if (resolver.infered == nullptr)
5354
{
55+
// FIXME
56+
// this is an internal error message for debugging and should be removed
57+
// at some point
5458
rust_error_at (expr->get_locus (), "failed to type resolve expression");
5559
return new TyTy::ErrorType (expr->get_mappings ().get_hirid ());
5660
}
@@ -540,6 +544,8 @@ class TypeCheckExpr : public TypeCheckBase
540544
Definition def;
541545
if (!resolver->lookup_definition (ref_node_id, &def))
542546
{
547+
// FIXME
548+
// this is an internal error
543549
rust_error_at (expr.get_locus (),
544550
"unknown reference for resolved name");
545551
return;
@@ -548,6 +554,8 @@ class TypeCheckExpr : public TypeCheckBase
548554
}
549555
else if (!resolver->lookup_resolved_type (ast_node_id, &ref_node_id))
550556
{
557+
// FIXME
558+
// this is an internal error
551559
rust_error_at (expr.get_locus (),
552560
"Failed to lookup type reference for node: %s",
553561
expr.as_string ().c_str ());
@@ -556,6 +564,8 @@ class TypeCheckExpr : public TypeCheckBase
556564

557565
if (ref_node_id == UNKNOWN_NODEID)
558566
{
567+
// FIXME
568+
// this is an internal error
559569
rust_error_at (expr.get_locus (), "unresolved node: %s",
560570
expr.as_string ().c_str ());
561571
return;
@@ -566,6 +576,8 @@ class TypeCheckExpr : public TypeCheckBase
566576
if (!mappings->lookup_node_to_hir (expr.get_mappings ().get_crate_num (),
567577
ref_node_id, &ref))
568578
{
579+
// FIXME
580+
// this is an internal error
569581
rust_error_at (expr.get_locus (), "123 reverse lookup failure");
570582
return;
571583
}
@@ -574,6 +586,8 @@ class TypeCheckExpr : public TypeCheckBase
574586
TyTy::BaseType *lookup;
575587
if (!context->lookup_type (ref, &lookup))
576588
{
589+
// FIXME
590+
// this is an internal error
577591
rust_error_at (mappings->lookup_location (ref),
578592
"Failed to resolve IdentifierExpr type: %s",
579593
expr.as_string ().c_str ());
@@ -1265,6 +1279,50 @@ class TypeCheckExpr : public TypeCheckBase
12651279
infered = expr_to_convert->cast (tyty_to_convert_to);
12661280
}
12671281

1282+
void visit (HIR::MatchExpr &expr) override
1283+
{
1284+
// this needs to perform a least upper bound coercion on the blocks and then
1285+
// unify the scruintee and arms
1286+
TyTy::BaseType *scrutinee_tyty
1287+
= TypeCheckExpr::Resolve (expr.get_scrutinee_expr ().get (), false);
1288+
1289+
std::vector<TyTy::BaseType *> kase_block_tys;
1290+
for (auto &kase : expr.get_match_cases ())
1291+
{
1292+
// lets check the arms
1293+
HIR::MatchArm &kase_arm = kase.get_arm ();
1294+
for (auto &pattern : kase_arm.get_patterns ())
1295+
{
1296+
TyTy::BaseType *kase_arm_ty
1297+
= TypeCheckPattern::Resolve (pattern.get ());
1298+
1299+
TyTy::BaseType *checked_kase = scrutinee_tyty->unify (kase_arm_ty);
1300+
if (checked_kase->get_kind () == TyTy::TypeKind::ERROR)
1301+
return;
1302+
}
1303+
1304+
// check the kase type
1305+
TyTy::BaseType *kase_block_ty
1306+
= TypeCheckExpr::Resolve (kase.get_expr ().get (), false);
1307+
kase_block_tys.push_back (kase_block_ty);
1308+
}
1309+
1310+
if (kase_block_tys.size () == 0)
1311+
{
1312+
infered = new TyTy::TupleType (expr.get_mappings ().get_hirid ());
1313+
return;
1314+
}
1315+
1316+
infered = kase_block_tys.at (0);
1317+
for (size_t i = 1; i < kase_block_tys.size (); i++)
1318+
{
1319+
TyTy::BaseType *kase_ty = kase_block_tys.at (i);
1320+
infered = infered->unify (kase_ty);
1321+
if (infered->get_kind () == TyTy::TypeKind::ERROR)
1322+
return;
1323+
}
1324+
}
1325+
12681326
protected:
12691327
bool
12701328
resolve_operator_overload (Analysis::RustLangItem::ItemType lang_item_type,

0 commit comments

Comments
 (0)