diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2022-05-13 15:45:24 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-05-13 15:45:24 +0000 |
commit | e4213b9568ae8cb8a4e31326e0e78c79db0a99cc (patch) | |
tree | 95fa5b04afbe6b66a3faece7399782c8305dab11 /gcc | |
parent | d4434b511a4e650e95c7a1de6810d8748c5d8a70 (diff) | |
parent | b1eb3e036c6fb5acc28c714375e6309fb5aa9ec8 (diff) | |
download | gcc-e4213b9568ae8cb8a4e31326e0e78c79db0a99cc.zip gcc-e4213b9568ae8cb8a4e31326e0e78c79db0a99cc.tar.gz gcc-e4213b9568ae8cb8a4e31326e0e78c79db0a99cc.tar.bz2 |
Merge #1248
1248: Support RangePatterns in matches r=dafaust a=dafaust
Add name resolution, lowering, type checking and compilation for `RangePattern`s in matches.
Co-authored-by: David Faust <david.faust@oracle.com>
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/rust/ast/rust-pattern.h | 28 | ||||
-rw-r--r-- | gcc/rust/backend/rust-compile-pattern.cc | 58 | ||||
-rw-r--r-- | gcc/rust/backend/rust-compile-pattern.h | 2 | ||||
-rw-r--r-- | gcc/rust/hir/rust-ast-lower-base.cc | 45 | ||||
-rw-r--r-- | gcc/rust/hir/rust-ast-lower-base.h | 3 | ||||
-rw-r--r-- | gcc/rust/hir/rust-ast-lower-pattern.cc | 18 | ||||
-rw-r--r-- | gcc/rust/hir/rust-ast-lower-pattern.h | 2 | ||||
-rw-r--r-- | gcc/rust/hir/tree/rust-hir-pattern.h | 44 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-ast-resolve-pattern.cc | 34 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-ast-resolve-pattern.h | 2 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-hir-type-check-pattern.cc | 77 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-hir-type-check-pattern.h | 7 | ||||
-rw-r--r-- | gcc/testsuite/rust/execute/torture/match_range1.rs | 34 | ||||
-rw-r--r-- | gcc/testsuite/rust/execute/torture/match_range2.rs | 40 |
14 files changed, 393 insertions, 1 deletions
diff --git a/gcc/rust/ast/rust-pattern.h b/gcc/rust/ast/rust-pattern.h index a3193f7..247af5d 100644 --- a/gcc/rust/ast/rust-pattern.h +++ b/gcc/rust/ast/rust-pattern.h @@ -195,6 +195,13 @@ protected: class RangePatternBound { public: + enum RangePatternBoundType + { + LITERAL, + PATH, + QUALPATH + }; + virtual ~RangePatternBound () {} // Unique pointer custom clone function @@ -208,6 +215,8 @@ public: virtual void accept_vis (ASTVisitor &vis) = 0; + virtual RangePatternBoundType get_bound_type () const = 0; + protected: // pure virtual as RangePatternBound is abstract virtual RangePatternBound *clone_range_pattern_bound_impl () const = 0; @@ -234,10 +243,19 @@ public: std::string as_string () const override; + Literal get_literal () const { return literal; } + + bool get_has_minus () const { return has_minus; } + Location get_locus () const { return locus; } void accept_vis (ASTVisitor &vis) override; + RangePatternBoundType get_bound_type () const override + { + return RangePatternBoundType::LITERAL; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -268,6 +286,11 @@ public: PathInExpression &get_path () { return path; } const PathInExpression &get_path () const { return path; } + RangePatternBoundType get_bound_type () const override + { + return RangePatternBoundType::PATH; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -300,6 +323,11 @@ public: QualifiedPathInExpression &get_qualified_path () { return path; } const QualifiedPathInExpression &get_qualified_path () const { return path; } + RangePatternBoundType get_bound_type () const override + { + return RangePatternBoundType::QUALPATH; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ diff --git a/gcc/rust/backend/rust-compile-pattern.cc b/gcc/rust/backend/rust-compile-pattern.cc index 9c1a35a..aefa4eb 100644 --- a/gcc/rust/backend/rust-compile-pattern.cc +++ b/gcc/rust/backend/rust-compile-pattern.cc @@ -105,6 +105,64 @@ CompilePatternCaseLabelExpr::visit (HIR::LiteralPattern &pattern) case_label_expr = build_case_label (lit, NULL_TREE, associated_case_label); } +static tree +compile_range_pattern_bound (HIR::RangePatternBound *bound, + Analysis::NodeMapping mappings, Location locus, + Context *ctx) +{ + tree result = NULL_TREE; + switch (bound->get_bound_type ()) + { + case HIR::RangePatternBound::RangePatternBoundType::LITERAL: { + HIR::RangePatternBoundLiteral &ref + = *static_cast<HIR::RangePatternBoundLiteral *> (bound); + + HIR::LiteralExpr *litexpr + = new HIR::LiteralExpr (mappings, ref.get_literal (), locus, + std::vector<AST::Attribute> ()); + + result = CompileExpr::Compile (litexpr, ctx); + } + break; + + case HIR::RangePatternBound::RangePatternBoundType::PATH: { + HIR::RangePatternBoundPath &ref + = *static_cast<HIR::RangePatternBoundPath *> (bound); + + result = ResolvePathRef::Compile (ref.get_path (), ctx); + + // If the path resolves to a const expression, fold it. + result = ConstCtx::fold (result); + } + break; + + case HIR::RangePatternBound::RangePatternBoundType::QUALPATH: { + HIR::RangePatternBoundQualPath &ref + = *static_cast<HIR::RangePatternBoundQualPath *> (bound); + + result = ResolvePathRef::Compile (ref.get_qualified_path (), ctx); + + // If the path resolves to a const expression, fold it. + result = ConstCtx::fold (result); + } + } + + return result; +} + +void +CompilePatternCaseLabelExpr::visit (HIR::RangePattern &pattern) +{ + tree upper = compile_range_pattern_bound (pattern.get_upper_bound ().get (), + pattern.get_pattern_mappings (), + pattern.get_locus (), ctx); + tree lower = compile_range_pattern_bound (pattern.get_lower_bound ().get (), + pattern.get_pattern_mappings (), + pattern.get_locus (), ctx); + + case_label_expr = build_case_label (lower, upper, associated_case_label); +} + // setup the bindings void diff --git a/gcc/rust/backend/rust-compile-pattern.h b/gcc/rust/backend/rust-compile-pattern.h index 1b6e80f..0eb5d61 100644 --- a/gcc/rust/backend/rust-compile-pattern.h +++ b/gcc/rust/backend/rust-compile-pattern.h @@ -37,13 +37,13 @@ public: void visit (HIR::StructPattern &pattern) override; void visit (HIR::TupleStructPattern &pattern) override; void visit (HIR::WildcardPattern &pattern) override; + void visit (HIR::RangePattern &pattern) override; // Empty visit for unused Pattern HIR nodes. void visit (HIR::GroupedPattern &) override {} void visit (HIR::IdentifierPattern &) override {} void visit (HIR::LiteralPattern &) override; void visit (HIR::QualifiedPathInExpression &) override {} - void visit (HIR::RangePattern &) override {} void visit (HIR::ReferencePattern &) override {} void visit (HIR::SlicePattern &) override {} void visit (HIR::TuplePattern &) override {} diff --git a/gcc/rust/hir/rust-ast-lower-base.cc b/gcc/rust/hir/rust-ast-lower-base.cc index e4b3e1e..7afe75c 100644 --- a/gcc/rust/hir/rust-ast-lower-base.cc +++ b/gcc/rust/hir/rust-ast-lower-base.cc @@ -950,6 +950,51 @@ ASTLoweringBase::lower_tuple_pattern_ranged ( std::move (upper_patterns))); } +std::unique_ptr<HIR::RangePatternBound> +ASTLoweringBase::lower_range_pattern_bound (AST::RangePatternBound *bound) +{ + std::unique_ptr<HIR::RangePatternBound> hir_bound = nullptr; + switch (bound->get_bound_type ()) + { + case AST::RangePatternBound::RangePatternBoundType::LITERAL: { + AST::RangePatternBoundLiteral &ref + = *static_cast<AST::RangePatternBoundLiteral *> (bound); + + HIR::Literal literal = lower_literal (ref.get_literal ()); + + hir_bound = std::unique_ptr<HIR::RangePatternBound> ( + new HIR::RangePatternBoundLiteral (literal, ref.get_locus (), + ref.get_has_minus ())); + } + break; + case AST::RangePatternBound::RangePatternBoundType::PATH: { + AST::RangePatternBoundPath &ref + = *static_cast<AST::RangePatternBoundPath *> (bound); + + HIR::PathInExpression *path + = ASTLowerPathInExpression::translate (&ref.get_path ()); + + hir_bound = std::unique_ptr<HIR::RangePatternBound> ( + new HIR::RangePatternBoundPath (*path)); + } + break; + case AST::RangePatternBound::RangePatternBoundType::QUALPATH: { + AST::RangePatternBoundQualPath &ref + = *static_cast<AST::RangePatternBoundQualPath *> (bound); + + HIR::QualifiedPathInExpression *qualpath + = ASTLowerQualPathInExpression::translate ( + &ref.get_qualified_path ()); + + hir_bound = std::unique_ptr<HIR::RangePatternBound> ( + new HIR::RangePatternBoundQualPath (*qualpath)); + } + break; + } + + return hir_bound; +} + HIR::Literal ASTLoweringBase::lower_literal (const AST::Literal &literal) { diff --git a/gcc/rust/hir/rust-ast-lower-base.h b/gcc/rust/hir/rust-ast-lower-base.h index 0041a8f..7e3eee1 100644 --- a/gcc/rust/hir/rust-ast-lower-base.h +++ b/gcc/rust/hir/rust-ast-lower-base.h @@ -282,6 +282,9 @@ protected: std::unique_ptr<TuplePatternItems> lower_tuple_pattern_ranged (AST::TuplePatternItemsRanged &pattern); + std::unique_ptr<HIR::RangePatternBound> + lower_range_pattern_bound (AST::RangePatternBound *bound); + HIR::Literal lower_literal (const AST::Literal &literal); }; diff --git a/gcc/rust/hir/rust-ast-lower-pattern.cc b/gcc/rust/hir/rust-ast-lower-pattern.cc index 957f8cd..1c08bf1 100644 --- a/gcc/rust/hir/rust-ast-lower-pattern.cc +++ b/gcc/rust/hir/rust-ast-lower-pattern.cc @@ -208,5 +208,23 @@ ASTLoweringPattern::visit (AST::LiteralPattern &pattern) = new HIR::LiteralPattern (mapping, std::move (l), pattern.get_locus ()); } +void +ASTLoweringPattern::visit (AST::RangePattern &pattern) +{ + auto upper_bound + = lower_range_pattern_bound (pattern.get_upper_bound ().get ()); + auto lower_bound + = lower_range_pattern_bound (pattern.get_lower_bound ().get ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, pattern.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated + = new HIR::RangePattern (mapping, std::move (lower_bound), + std::move (upper_bound), pattern.get_locus ()); +} + } // namespace HIR } // namespace Rust diff --git a/gcc/rust/hir/rust-ast-lower-pattern.h b/gcc/rust/hir/rust-ast-lower-pattern.h index 32e9dac..dfd3dc0 100644 --- a/gcc/rust/hir/rust-ast-lower-pattern.h +++ b/gcc/rust/hir/rust-ast-lower-pattern.h @@ -62,6 +62,8 @@ public: void visit (AST::LiteralPattern &pattern) override; + void visit (AST::RangePattern &pattern) override; + private: ASTLoweringPattern () : translated (nullptr) {} diff --git a/gcc/rust/hir/tree/rust-hir-pattern.h b/gcc/rust/hir/tree/rust-hir-pattern.h index 880fc3e..7129b5a 100644 --- a/gcc/rust/hir/tree/rust-hir-pattern.h +++ b/gcc/rust/hir/tree/rust-hir-pattern.h @@ -197,6 +197,13 @@ protected: class RangePatternBound { public: + enum RangePatternBoundType + { + LITERAL, + PATH, + QUALPATH + }; + virtual ~RangePatternBound () {} // Unique pointer custom clone function @@ -210,6 +217,8 @@ public: virtual void accept_vis (HIRFullVisitor &vis) = 0; + virtual RangePatternBoundType get_bound_type () const = 0; + protected: // pure virtual as RangePatternBound is abstract virtual RangePatternBound *clone_range_pattern_bound_impl () const = 0; @@ -238,8 +247,15 @@ public: Location get_locus () const { return locus; } + Literal get_literal () const { return literal; } + void accept_vis (HIRFullVisitor &vis) override; + RangePatternBoundType get_bound_type () const override + { + return RangePatternBoundType::LITERAL; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -264,8 +280,16 @@ public: Location get_locus () const { return path.get_locus (); } + PathInExpression &get_path () { return path; } + const PathInExpression &get_path () const { return path; } + void accept_vis (HIRFullVisitor &vis) override; + RangePatternBoundType get_bound_type () const override + { + return RangePatternBoundType::PATH; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -294,6 +318,14 @@ public: void accept_vis (HIRFullVisitor &vis) override; + QualifiedPathInExpression &get_qualified_path () { return path; } + const QualifiedPathInExpression &get_qualified_path () const { return path; } + + RangePatternBoundType get_bound_type () const override + { + return RangePatternBoundType::QUALPATH; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -368,6 +400,18 @@ public: return PatternType::RANGE; } + std::unique_ptr<RangePatternBound> &get_lower_bound () + { + rust_assert (lower != nullptr); + return lower; + } + + std::unique_ptr<RangePatternBound> &get_upper_bound () + { + rust_assert (upper != nullptr); + return upper; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ diff --git a/gcc/rust/resolve/rust-ast-resolve-pattern.cc b/gcc/rust/resolve/rust-ast-resolve-pattern.cc index bac5521..dc2cca4 100644 --- a/gcc/rust/resolve/rust-ast-resolve-pattern.cc +++ b/gcc/rust/resolve/rust-ast-resolve-pattern.cc @@ -131,5 +131,39 @@ PatternDeclaration::visit (AST::TuplePattern &pattern) } } +static void +resolve_range_pattern_bound (AST::RangePatternBound *bound, NodeId parent) +{ + switch (bound->get_bound_type ()) + { + case AST::RangePatternBound::RangePatternBoundType::LITERAL: + // Nothing to resolve for a literal. + break; + + case AST::RangePatternBound::RangePatternBoundType::PATH: { + AST::RangePatternBoundPath &ref + = *static_cast<AST::RangePatternBoundPath *> (bound); + + ResolvePath::go (&ref.get_path (), parent); + } + break; + + case AST::RangePatternBound::RangePatternBoundType::QUALPATH: { + AST::RangePatternBoundQualPath &ref + = *static_cast<AST::RangePatternBoundQualPath *> (bound); + + ResolvePath::go (&ref.get_qualified_path (), parent); + } + break; + } +} + +void +PatternDeclaration::visit (AST::RangePattern &pattern) +{ + resolve_range_pattern_bound (pattern.get_upper_bound ().get (), parent); + resolve_range_pattern_bound (pattern.get_lower_bound ().get (), parent); +} + } // namespace Resolver } // namespace Rust diff --git a/gcc/rust/resolve/rust-ast-resolve-pattern.h b/gcc/rust/resolve/rust-ast-resolve-pattern.h index 464e362..dfb05d3 100644 --- a/gcc/rust/resolve/rust-ast-resolve-pattern.h +++ b/gcc/rust/resolve/rust-ast-resolve-pattern.h @@ -103,6 +103,8 @@ public: void visit (AST::TuplePattern &pattern) override; + void visit (AST::RangePattern &pattern) override; + private: PatternDeclaration (NodeId parent) : ResolverBase (parent) {} }; diff --git a/gcc/rust/typecheck/rust-hir-type-check-pattern.cc b/gcc/rust/typecheck/rust-hir-type-check-pattern.cc index 52d0d47..bceafde 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-pattern.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-pattern.cc @@ -273,5 +273,82 @@ TypeCheckPattern::visit (HIR::LiteralPattern &pattern) pattern.get_literal (), pattern.get_locus ()); } +void +TypeCheckPattern::visit (HIR::RangePattern &pattern) +{ + // Resolve the upper and lower bounds, and ensure they are compatible types + TyTy::BaseType *upper = nullptr, *lower = nullptr; + + // TODO: It would be nice to factor this out into a helper since the logic for + // both bounds is exactly the same... + switch (pattern.get_upper_bound ()->get_bound_type ()) + { + case HIR::RangePatternBound::RangePatternBoundType::LITERAL: { + HIR::RangePatternBoundLiteral &ref + = *static_cast<HIR::RangePatternBoundLiteral *> ( + pattern.get_upper_bound ().get ()); + + HIR::Literal lit = ref.get_literal (); + + upper = resolve_literal (pattern.get_pattern_mappings (), lit, + pattern.get_locus ()); + } + break; + + case HIR::RangePatternBound::RangePatternBoundType::PATH: { + HIR::RangePatternBoundPath &ref + = *static_cast<HIR::RangePatternBoundPath *> ( + pattern.get_upper_bound ().get ()); + + upper = TypeCheckExpr::Resolve (&ref.get_path (), false); + } + break; + + case HIR::RangePatternBound::RangePatternBoundType::QUALPATH: { + HIR::RangePatternBoundQualPath &ref + = *static_cast<HIR::RangePatternBoundQualPath *> ( + pattern.get_upper_bound ().get ()); + + upper = TypeCheckExpr::Resolve (&ref.get_qualified_path (), false); + } + break; + } + + switch (pattern.get_lower_bound ()->get_bound_type ()) + { + case HIR::RangePatternBound::RangePatternBoundType::LITERAL: { + HIR::RangePatternBoundLiteral &ref + = *static_cast<HIR::RangePatternBoundLiteral *> ( + pattern.get_lower_bound ().get ()); + + HIR::Literal lit = ref.get_literal (); + + lower = resolve_literal (pattern.get_pattern_mappings (), lit, + pattern.get_locus ()); + } + break; + + case HIR::RangePatternBound::RangePatternBoundType::PATH: { + HIR::RangePatternBoundPath &ref + = *static_cast<HIR::RangePatternBoundPath *> ( + pattern.get_lower_bound ().get ()); + + lower = TypeCheckExpr::Resolve (&ref.get_path (), false); + } + break; + + case HIR::RangePatternBound::RangePatternBoundType::QUALPATH: { + HIR::RangePatternBoundQualPath &ref + = *static_cast<HIR::RangePatternBoundQualPath *> ( + pattern.get_lower_bound ().get ()); + + lower = TypeCheckExpr::Resolve (&ref.get_qualified_path (), false); + } + break; + } + + infered = upper->unify (lower); +} + } // namespace Resolver } // namespace Rust diff --git a/gcc/rust/typecheck/rust-hir-type-check-pattern.h b/gcc/rust/typecheck/rust-hir-type-check-pattern.h index b76c7ba..03c4977 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-pattern.h +++ b/gcc/rust/typecheck/rust-hir-type-check-pattern.h @@ -56,11 +56,18 @@ public: void visit (HIR::LiteralPattern &pattern) override; + void visit (HIR::RangePattern &pattern) override; + private: TypeCheckPattern (TyTy::BaseType *parent) : TypeCheckBase (), parent (parent), infered (nullptr) {} + static TyTy::BaseType * + typecheck_range_pattern_bound (HIR::RangePatternBound *bound, + Analysis::NodeMapping mappings, + Location locus); + TyTy::BaseType *parent; TyTy::BaseType *infered; }; diff --git a/gcc/testsuite/rust/execute/torture/match_range1.rs b/gcc/testsuite/rust/execute/torture/match_range1.rs new file mode 100644 index 0000000..8fe8f4c --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/match_range1.rs @@ -0,0 +1,34 @@ +// { dg-output "zero to END_RANGE\nzero to END_RANGE\nelse\n" } + +extern "C" { + fn printf(s: *const i8, ...); +} + +const END_RANGE: i32 = 15; + +fn foo (x: i32) { + match x { + 0..=END_RANGE => { + let a = "zero to END_RANGE\n\0"; + let b = a as *const str; + let c = b as *const i8; + printf (c); + } + + _ => { + let a = "else\n\0"; + let b = a as *const str; + let c = b as *const i8; + printf (c); + } + } +} + +fn main () -> i32 { + + foo (11); + foo (15); + foo (21); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/match_range2.rs b/gcc/testsuite/rust/execute/torture/match_range2.rs new file mode 100644 index 0000000..82980c2 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/match_range2.rs @@ -0,0 +1,40 @@ +// { dg-output "lowercase\nuppercase\nother\n" } + +extern "C" { + fn printf(s: *const i8, ...); +} + +const BIG_A: char = 'A'; +const BIG_Z: char = 'Z'; + +fn bar (x: char) { + match x { + + 'a'..='z' => { + let a = "lowercase\n\0"; + let b = a as *const str; + let c = b as *const i8; + printf (c); + } + BIG_A..=BIG_Z => { + let a = "uppercase\n\0"; + let b = a as *const str; + let c = b as *const i8; + printf (c); + } + _ => { + let a = "other\n\0"; + let b = a as *const str; + let c = b as *const i8; + printf (c); + } + } +} + +fn main () -> i32 { + bar ('b'); + bar ('X'); + bar ('!'); + + 0 +} |