From 75ed46f65a9acb7cb4cf122c432d177d104be185 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20Poulhi=C3=A8s?= Date: Wed, 12 Jun 2024 21:58:26 +0200 Subject: [PATCH] rust: Desugar IfLet* into MatchExpr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the "regular" AST->HIR lowering for IfLet* with a desugaring into a MatchExpr. Desugar a simple if let: if let Some(y) = some_value { bar(); } into: match some_value { Some(y) => {bar();}, _ => () } Same applies for IfLetExprConseqElse (if let with an else block). Desugar: if let Some(y) = some_value { bar(); } else { baz(); } into: match some_value { Some(y) => {bar();}, _ => {baz();} } Fixes https://github.com/Rust-GCC/gccrs/issues/1177 gcc/rust/ChangeLog: * backend/rust-compile-block.h: Adjust after removal of HIR::IfLetExpr and HIR::IfLetExprConseqElse. * backend/rust-compile-expr.h: Likewise. * checks/errors/borrowck/rust-bir-builder-expr-stmt.cc (ExprStmtBuilder::visit): Likewise. * checks/errors/borrowck/rust-bir-builder-expr-stmt.h: Likewise. * checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h: Likewise. * checks/errors/borrowck/rust-bir-builder-struct.h: Likewise. * checks/errors/borrowck/rust-function-collector.h: Likewise. * checks/errors/privacy/rust-privacy-reporter.cc (PrivacyReporter::visit): Likewise. * checks/errors/privacy/rust-privacy-reporter.h: Likewise. * checks/errors/rust-const-checker.cc (ConstChecker::visit): Likewise. * checks/errors/rust-const-checker.h: Likewise. * checks/errors/rust-unsafe-checker.cc (UnsafeChecker::visit): Likewise. * checks/errors/rust-unsafe-checker.h: Likewise. * hir/rust-ast-lower-block.h (ASTLoweringIfLetBlock::translate): Change return type. * hir/rust-ast-lower.cc (ASTLoweringIfLetBlock::desugar_iflet): New. (ASTLoweringIfLetBlock::visit(AST::IfLetExpr &)): Adjust and use desugar_iflet. * hir/rust-ast-lower.h: Add comment. * hir/rust-hir-dump.cc (Dump::do_ifletexpr): Remove. (Dump::visit(IfLetExpr&)): Remove. (Dump::visit(IfLetExprConseqElse&)): Remove. * hir/rust-hir-dump.h (Dump::do_ifletexpr): Remove. (Dump::visit(IfLetExpr&)): Remove. (Dump::visit(IfLetExprConseqElse&)): Remove. * hir/tree/rust-hir-expr.h (class IfLetExpr): Remove. (class IfLetExprConseqElse): Remove. * hir/tree/rust-hir-full-decls.h (class IfLetExpr): Remove. (class IfLetExprConseqElse): Remove. * hir/tree/rust-hir-visitor.h: Adjust after removal of HIR::IfLetExpr and HIR::IfLetExprConseqElse. * hir/tree/rust-hir.cc (IfLetExpr::as_string): Remove. (IfLetExprConseqElse::as_string): Remove. (IfLetExpr::accept_vis): Remove. (IfLetExprConseqElse::accept_vis): Remove. * hir/tree/rust-hir.h: Adjust after removal of HIR::IfLetExpr and HIR::IfLetExprConseqElse. * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): Likewise. * typecheck/rust-hir-type-check-expr.h: Likewise. * checks/errors/rust-hir-pattern-analysis.cc (PatternChecker::visit (IfLetExpr &)): Remove. (PatternChecker::visit (IfLetExprConseqElse &)): Remove. * checks/errors/rust-hir-pattern-analysis.h (visit(IfLetExpr &)): Remove. (visit(IfLetExprConseqElse &)): Remove. gcc/testsuite/ChangeLog: * rust/compile/if_let_expr.rs: Adjust. * rust/compile/if_let_expr_simple.rs: New test. * rust/compile/iflet.rs: New test. * rust/execute/torture/iflet.rs: New test. * rust/compile/nr2/exclude: Add iflet.rs and if_let_expr_simple.rs Signed-off-by: Marc Poulhiès --- gcc/rust/backend/rust-compile-block.h | 4 - gcc/rust/backend/rust-compile-expr.h | 2 - .../borrowck/rust-bir-builder-expr-stmt.cc | 12 -- .../borrowck/rust-bir-builder-expr-stmt.h | 2 - .../borrowck/rust-bir-builder-lazyboolexpr.h | 8 - .../errors/borrowck/rust-bir-builder-struct.h | 2 - .../errors/borrowck/rust-function-collector.h | 2 - .../errors/privacy/rust-privacy-reporter.cc | 15 -- .../errors/privacy/rust-privacy-reporter.h | 2 - gcc/rust/checks/errors/rust-const-checker.cc | 16 -- gcc/rust/checks/errors/rust-const-checker.h | 2 - .../errors/rust-hir-pattern-analysis.cc | 16 -- .../checks/errors/rust-hir-pattern-analysis.h | 2 - gcc/rust/checks/errors/rust-unsafe-checker.cc | 16 -- gcc/rust/checks/errors/rust-unsafe-checker.h | 2 - gcc/rust/hir/rust-ast-lower-block.h | 11 +- gcc/rust/hir/rust-ast-lower.cc | 144 +++++++++++--- gcc/rust/hir/rust-ast-lower.h | 5 + gcc/rust/hir/rust-hir-dump.cc | 28 --- gcc/rust/hir/rust-hir-dump.h | 3 - gcc/rust/hir/tree/rust-hir-expr.h | 176 +----------------- gcc/rust/hir/tree/rust-hir-full-decls.h | 2 - gcc/rust/hir/tree/rust-hir-visitor.h | 6 - gcc/rust/hir/tree/rust-hir.cc | 59 ------ gcc/rust/hir/tree/rust-hir.h | 1 - .../typecheck/rust-hir-type-check-expr.cc | 61 ------ gcc/rust/typecheck/rust-hir-type-check-expr.h | 2 - gcc/testsuite/rust/compile/if_let_expr.rs | 5 +- .../rust/compile/if_let_expr_simple.rs | 12 ++ gcc/testsuite/rust/compile/iflet.rs | 32 ++++ gcc/testsuite/rust/compile/nr2/exclude | 3 + gcc/testsuite/rust/execute/torture/iflet.rs | 84 +++++++++ 32 files changed, 260 insertions(+), 477 deletions(-) create mode 100644 gcc/testsuite/rust/compile/if_let_expr_simple.rs create mode 100644 gcc/testsuite/rust/compile/iflet.rs create mode 100644 gcc/testsuite/rust/execute/torture/iflet.rs diff --git a/gcc/rust/backend/rust-compile-block.h b/gcc/rust/backend/rust-compile-block.h index 112f7b07e5e6..46a32cfaf867 100644 --- a/gcc/rust/backend/rust-compile-block.h +++ b/gcc/rust/backend/rust-compile-block.h @@ -96,8 +96,6 @@ class CompileConditionalBlocks : public HIRCompileBase, void visit (HIR::LoopExpr &) override {} void visit (HIR::WhileLoopExpr &) override {} void visit (HIR::WhileLetLoopExpr &) override {} - void visit (HIR::IfLetExpr &) override {} - void visit (HIR::IfLetExprConseqElse &) override {} void visit (HIR::MatchExpr &) override {} void visit (HIR::AwaitExpr &) override {} void visit (HIR::AsyncBlockExpr &) override {} @@ -180,8 +178,6 @@ class CompileExprWithBlock : public HIRCompileBase, void visit (HIR::LoopExpr &) override {} void visit (HIR::WhileLoopExpr &) override {} void visit (HIR::WhileLetLoopExpr &) override {} - void visit (HIR::IfLetExpr &) override {} - void visit (HIR::IfLetExprConseqElse &) override {} void visit (HIR::MatchExpr &) override {} void visit (HIR::AwaitExpr &) override {} void visit (HIR::AsyncBlockExpr &) override {} diff --git a/gcc/rust/backend/rust-compile-expr.h b/gcc/rust/backend/rust-compile-expr.h index 8f187029a109..871111bb007c 100644 --- a/gcc/rust/backend/rust-compile-expr.h +++ b/gcc/rust/backend/rust-compile-expr.h @@ -77,8 +77,6 @@ class CompileExpr : private HIRCompileBase, protected HIR::HIRExpressionVisitor // TODO // these need to be sugared in the HIR to if statements and a match void visit (HIR::WhileLetLoopExpr &) override {} - void visit (HIR::IfLetExpr &) override {} - void visit (HIR::IfLetExprConseqElse &) override {} // lets not worry about async yet.... void visit (HIR::AwaitExpr &) override {} diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc b/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc index c11cff0ae4df..3ae58843f1fb 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc @@ -611,18 +611,6 @@ ExprStmtBuilder::visit (HIR::IfExprConseqElse &expr) add_jump (else_end_bb, final_start_bb); } -void -ExprStmtBuilder::visit (HIR::IfLetExpr &expr) -{ - rust_sorry_at (expr.get_locus (), "if let expressions are not supported"); -} - -void -ExprStmtBuilder::visit (HIR::IfLetExprConseqElse &expr) -{ - rust_sorry_at (expr.get_locus (), "if let expressions are not supported"); -} - void ExprStmtBuilder::visit (HIR::MatchExpr &expr) { diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.h index d67d86fca78a..f538a1209a8f 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.h @@ -101,8 +101,6 @@ class ExprStmtBuilder final : public AbstractExprBuilder, void visit (HIR::IfExprConseqElse &expr) override; void visit (HIR::InlineAsm &expr) override; - void visit (HIR::IfLetExpr &expr) override; - void visit (HIR::IfLetExprConseqElse &expr) override; void visit (HIR::MatchExpr &expr) override; void visit (HIR::AwaitExpr &expr) override; void visit (HIR::AsyncBlockExpr &expr) override; diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h index 3a27c8e3337c..926ba692e2ca 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h @@ -193,14 +193,6 @@ class LazyBooleanExprBuilder : public AbstractExprBuilder { return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ()); } - void visit (HIR::IfLetExpr &expr) override - { - return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ()); - } - void visit (HIR::IfLetExprConseqElse &expr) override - { - return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ()); - } void visit (HIR::MatchExpr &expr) override { return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ()); diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h index 787b7017e1b6..351b4c8a3758 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h @@ -149,8 +149,6 @@ class StructBuilder : public AbstractBuilder, public HIR::HIRFullVisitor void visit (HIR::WhileLetLoopExpr &expr) override { rust_unreachable (); } void visit (HIR::IfExpr &expr) override { rust_unreachable (); } void visit (HIR::IfExprConseqElse &expr) override { rust_unreachable (); } - void visit (HIR::IfLetExpr &expr) override { rust_unreachable (); } - void visit (HIR::IfLetExprConseqElse &expr) override { rust_unreachable (); } void visit (HIR::MatchExpr &expr) override { rust_unreachable (); } void visit (HIR::AwaitExpr &expr) override { rust_unreachable (); } void visit (HIR::AsyncBlockExpr &expr) override { rust_unreachable (); } diff --git a/gcc/rust/checks/errors/borrowck/rust-function-collector.h b/gcc/rust/checks/errors/borrowck/rust-function-collector.h index 725d312f1113..1f7cf48e412b 100644 --- a/gcc/rust/checks/errors/borrowck/rust-function-collector.h +++ b/gcc/rust/checks/errors/borrowck/rust-function-collector.h @@ -119,8 +119,6 @@ class FunctionCollector : public HIR::HIRFullVisitor void visit (HIR::WhileLetLoopExpr &expr) override {} void visit (HIR::IfExpr &expr) override {} void visit (HIR::IfExprConseqElse &expr) override {} - void visit (HIR::IfLetExpr &expr) override {} - void visit (HIR::IfLetExprConseqElse &expr) override {} void visit (HIR::MatchExpr &expr) override {} void visit (HIR::AwaitExpr &expr) override {} void visit (HIR::AsyncBlockExpr &expr) override {} diff --git a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc index 43eb115a6325..9e4b0073db46 100644 --- a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc +++ b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc @@ -594,21 +594,6 @@ PrivacyReporter::visit (HIR::IfExprConseqElse &expr) expr.get_else_block ()->accept_vis (*this); } -void -PrivacyReporter::visit (HIR::IfLetExpr &) -{ - // TODO: We need to visit the if_let_expr - // TODO: We need to visit the block as well -} - -void -PrivacyReporter::visit (HIR::IfLetExprConseqElse &) -{ - // TODO: We need to visit the if_let_expr - // TODO: We need to visit the if_block as well - // TODO: We need to visit the else_block as well -} - void PrivacyReporter::visit (HIR::MatchExpr &expr) { diff --git a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h index c00ab37a78f8..f90f5a2fc8ba 100644 --- a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h +++ b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h @@ -121,8 +121,6 @@ types virtual void visit (HIR::WhileLetLoopExpr &expr); virtual void visit (HIR::IfExpr &expr); virtual void visit (HIR::IfExprConseqElse &expr); - virtual void visit (HIR::IfLetExpr &expr); - virtual void visit (HIR::IfLetExprConseqElse &expr); virtual void visit (HIR::MatchExpr &expr); virtual void visit (HIR::AwaitExpr &expr); virtual void visit (HIR::AsyncBlockExpr &expr); diff --git a/gcc/rust/checks/errors/rust-const-checker.cc b/gcc/rust/checks/errors/rust-const-checker.cc index d3c25b566b90..f858a2233495 100644 --- a/gcc/rust/checks/errors/rust-const-checker.cc +++ b/gcc/rust/checks/errors/rust-const-checker.cc @@ -511,22 +511,6 @@ ConstChecker::visit (IfExprConseqElse &expr) expr.get_else_block ()->accept_vis (*this); } -void -ConstChecker::visit (IfLetExpr &expr) -{ - expr.get_scrutinee_expr ()->accept_vis (*this); - expr.get_if_block ()->accept_vis (*this); -} - -void -ConstChecker::visit (IfLetExprConseqElse &expr) -{ - expr.get_scrutinee_expr ()->accept_vis (*this); - expr.get_if_block ()->accept_vis (*this); - - // TODO: Visit else expression -} - void ConstChecker::visit (MatchExpr &expr) { diff --git a/gcc/rust/checks/errors/rust-const-checker.h b/gcc/rust/checks/errors/rust-const-checker.h index 2bbf67b20d70..5363df9d5b1c 100644 --- a/gcc/rust/checks/errors/rust-const-checker.h +++ b/gcc/rust/checks/errors/rust-const-checker.h @@ -128,8 +128,6 @@ class ConstChecker : public HIRFullVisitor virtual void visit (WhileLetLoopExpr &expr) override; virtual void visit (IfExpr &expr) override; virtual void visit (IfExprConseqElse &expr) override; - virtual void visit (IfLetExpr &expr) override; - virtual void visit (IfLetExprConseqElse &expr) override; virtual void visit (MatchExpr &expr) override; virtual void visit (AwaitExpr &expr) override; virtual void visit (AsyncBlockExpr &expr) override; diff --git a/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc b/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc index f46f429e9306..8fb795b7b837 100644 --- a/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc +++ b/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc @@ -389,22 +389,6 @@ PatternChecker::visit (IfExprConseqElse &expr) expr.get_else_block ()->accept_vis (*this); } -void -PatternChecker::visit (IfLetExpr &expr) -{ - expr.get_scrutinee_expr ()->accept_vis (*this); - expr.get_if_block ()->accept_vis (*this); -} - -void -PatternChecker::visit (IfLetExprConseqElse &expr) -{ - expr.get_scrutinee_expr ()->accept_vis (*this); - expr.get_if_block ()->accept_vis (*this); - - expr.get_else_block ()->accept_vis (*this); -} - void PatternChecker::visit (MatchExpr &expr) { diff --git a/gcc/rust/checks/errors/rust-hir-pattern-analysis.h b/gcc/rust/checks/errors/rust-hir-pattern-analysis.h index 1af02baa24b1..9c43d4143d2a 100644 --- a/gcc/rust/checks/errors/rust-hir-pattern-analysis.h +++ b/gcc/rust/checks/errors/rust-hir-pattern-analysis.h @@ -102,8 +102,6 @@ class PatternChecker : public HIR::HIRFullVisitor virtual void visit (WhileLetLoopExpr &expr) override; virtual void visit (IfExpr &expr) override; virtual void visit (IfExprConseqElse &expr) override; - virtual void visit (IfLetExpr &expr) override; - virtual void visit (IfLetExprConseqElse &expr) override; virtual void visit (HIR::MatchExpr &expr) override; virtual void visit (AwaitExpr &expr) override; virtual void visit (AsyncBlockExpr &expr) override; diff --git a/gcc/rust/checks/errors/rust-unsafe-checker.cc b/gcc/rust/checks/errors/rust-unsafe-checker.cc index 3bf72428aadb..667e5257b86b 100644 --- a/gcc/rust/checks/errors/rust-unsafe-checker.cc +++ b/gcc/rust/checks/errors/rust-unsafe-checker.cc @@ -633,22 +633,6 @@ UnsafeChecker::visit (IfExprConseqElse &expr) expr.get_else_block ()->accept_vis (*this); } -void -UnsafeChecker::visit (IfLetExpr &expr) -{ - expr.get_scrutinee_expr ()->accept_vis (*this); - expr.get_if_block ()->accept_vis (*this); -} - -void -UnsafeChecker::visit (IfLetExprConseqElse &expr) -{ - expr.get_scrutinee_expr ()->accept_vis (*this); - expr.get_if_block ()->accept_vis (*this); - - // TODO: Visit else expression -} - void UnsafeChecker::visit (MatchExpr &expr) { diff --git a/gcc/rust/checks/errors/rust-unsafe-checker.h b/gcc/rust/checks/errors/rust-unsafe-checker.h index 3a1e715d2442..bd88dc395ea0 100644 --- a/gcc/rust/checks/errors/rust-unsafe-checker.h +++ b/gcc/rust/checks/errors/rust-unsafe-checker.h @@ -110,8 +110,6 @@ class UnsafeChecker : public HIRFullVisitor virtual void visit (WhileLetLoopExpr &expr) override; virtual void visit (IfExpr &expr) override; virtual void visit (IfExprConseqElse &expr) override; - virtual void visit (IfLetExpr &expr) override; - virtual void visit (IfLetExprConseqElse &expr) override; virtual void visit (MatchExpr &expr) override; virtual void visit (AwaitExpr &expr) override; virtual void visit (AsyncBlockExpr &expr) override; diff --git a/gcc/rust/hir/rust-ast-lower-block.h b/gcc/rust/hir/rust-ast-lower-block.h index f24173e55985..55541a5ad684 100644 --- a/gcc/rust/hir/rust-ast-lower-block.h +++ b/gcc/rust/hir/rust-ast-lower-block.h @@ -115,7 +115,7 @@ class ASTLoweringIfLetBlock : public ASTLoweringBase using Rust::HIR::ASTLoweringBase::visit; public: - static HIR::IfLetExpr *translate (AST::IfLetExpr &expr) + static HIR::MatchExpr *translate (AST::IfLetExpr &expr) { ASTLoweringIfLetBlock resolver; expr.accept_vis (resolver); @@ -135,7 +135,10 @@ class ASTLoweringIfLetBlock : public ASTLoweringBase private: ASTLoweringIfLetBlock () : ASTLoweringBase (), translated (nullptr) {} - HIR::IfLetExpr *translated; + void desugar_iflet (AST::IfLetExpr &, HIR::Expr **, HIR::Expr *, + std::vector &); + + HIR::MatchExpr *translated; }; class ASTLoweringExprWithBlock : public ASTLoweringBase @@ -149,9 +152,7 @@ class ASTLoweringExprWithBlock : public ASTLoweringBase ASTLoweringExprWithBlock resolver; expr.accept_vis (resolver); if (resolver.translated != nullptr) - { - resolver.mappings.insert_hir_expr (resolver.translated); - } + resolver.mappings.insert_hir_expr (resolver.translated); *terminated = resolver.terminated; return resolver.translated; diff --git a/gcc/rust/hir/rust-ast-lower.cc b/gcc/rust/hir/rust-ast-lower.cc index 940da204cc5b..c92c9432a68e 100644 --- a/gcc/rust/hir/rust-ast-lower.cc +++ b/gcc/rust/hir/rust-ast-lower.cc @@ -24,6 +24,8 @@ #include "rust-ast-lower-type.h" #include "rust-ast-lower-pattern.h" #include "rust-ast-lower-struct-field-expr.h" +#include "rust-expr.h" +#include "rust-hir-expr.h" namespace Rust { namespace HIR { @@ -198,62 +200,144 @@ ASTLoweringIfBlock::visit (AST::IfExprConseqElse &expr) std::unique_ptr (else_block), expr.get_locus ()); } +/** + * Lowers the common part "if let 'pattern' = 'expr' { 'if_block' }" of + * IfLetExpr[ConseqElse]: + * - 'expr' is lowered into *BRANCH_VALUE + * - 'pattern' + 'if_block' are lowered and resulting ARM pushed in MATCH_ARMS + * - 'KASE_ELSE_EXPR' is the lowered HIR to be used in the else part. + * + * Looks like: + * + * match (expr) { + * pattern => {if_block} + * _ => kase_else_expr + * } + * + */ void -ASTLoweringIfLetBlock::visit (AST::IfLetExpr &expr) +ASTLoweringIfLetBlock::desugar_iflet (AST::IfLetExpr &expr, + HIR::Expr **branch_value, + HIR::Expr *kase_else_expr, + std::vector &match_arms) { - std::vector> patterns; + HIR::Expr *kase_expr; + std::vector> match_arm_patterns; + + *branch_value = ASTLoweringExpr::translate (expr.get_value_expr ()); + kase_expr = ASTLoweringExpr::translate (expr.get_if_block ()); + + // (stable) if let only accepts a single pattern, but (unstable) if let chains + // need more than one pattern. + // We don't support if let chains, so only support a single pattern. + rust_assert (expr.get_patterns ().size () == 1); + for (auto &pattern : expr.get_patterns ()) { HIR::Pattern *ptrn = ASTLoweringPattern::translate (*pattern); - patterns.push_back (std::unique_ptr (ptrn)); + match_arm_patterns.push_back (std::unique_ptr (ptrn)); } - HIR::Expr *value_ptr = ASTLoweringExpr::translate (expr.get_value_expr ()); - bool ignored_terminated = false; - HIR::BlockExpr *block - = ASTLoweringBlock::translate (expr.get_if_block (), &ignored_terminated); + // The match arm corresponding to the if let pattern when it matches. + HIR::MatchArm arm (std::move (match_arm_patterns), expr.get_locus (), nullptr, + {}); auto crate_num = mappings.get_current_crate (); Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), mappings.get_next_hir_id (crate_num), UNKNOWN_LOCAL_DEFID); - translated = new HIR::IfLetExpr (mapping, std::move (patterns), - std::unique_ptr (value_ptr), - std::unique_ptr (block), - expr.get_locus ()); + HIR::MatchCase kase (std::move (mapping), std::move (arm), + std::unique_ptr (kase_expr)); + match_arms.push_back (std::move (kase)); + + // The default match arm when the if let pattern does not match + std::vector> match_arm_patterns_wildcard; + Analysis::NodeMapping mapping_default (crate_num, expr.get_node_id (), + mappings.get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + std::unique_ptr wc + = std::unique_ptr ( + new HIR::WildcardPattern (mapping_default, expr.get_locus ())); + + match_arm_patterns_wildcard.push_back (std::move (wc)); + + HIR::MatchArm arm_default (std::move (match_arm_patterns_wildcard), + expr.get_locus (), nullptr, {}); + + HIR::MatchCase kase_else (std::move (mapping_default), + std::move (arm_default), + std::unique_ptr (kase_else_expr)); + match_arms.push_back (std::move (kase_else)); } void -ASTLoweringIfLetBlock::visit (AST::IfLetExprConseqElse &expr) +ASTLoweringIfLetBlock::visit (AST::IfLetExpr &expr) { - std::vector> patterns; - for (auto &pattern : expr.get_patterns ()) - { - HIR::Pattern *ptrn = ASTLoweringPattern::translate (*pattern); - patterns.push_back (std::unique_ptr (ptrn)); - } - HIR::Expr *value_ptr = ASTLoweringExpr::translate (expr.get_value_expr ()); + // Desugar: + // if let Some(y) = some_value { + // bar(); + // } + // + // into: + // + // match some_value { + // Some(y) => {bar();}, + // _ => () + // } + + HIR::Expr *branch_value; - bool ignored_terminated = false; - HIR::BlockExpr *block - = ASTLoweringBlock::translate (expr.get_if_block (), &ignored_terminated); + std::vector match_arms; + auto crate_num = mappings.get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings.get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); - HIR::ExprWithBlock *else_block - = ASTLoweringExprWithBlock::translate (expr.get_else_block (), - &ignored_terminated); + HIR::TupleExpr *unit + = new HIR::TupleExpr (mapping, {}, {}, {}, expr.get_locus ()); + + desugar_iflet (expr, &branch_value, unit, match_arms); - rust_assert (else_block); + translated + = new HIR::MatchExpr (mapping, std::unique_ptr (branch_value), + std::move (match_arms), {}, {}, expr.get_locus ()); +} + +void +ASTLoweringIfLetBlock::visit (AST::IfLetExprConseqElse &expr) +{ + // desugar: + // if let Some(y) = some_value { + // bar(); + // } else { + // baz(); + // } + // + // into + // match some_value { + // Some(y) => {bar();}, + // _ => {baz();} + // } + // + + HIR::Expr *branch_value; + std::vector match_arms; + + HIR::Expr *kase_else_expr + = ASTLoweringExpr::translate (expr.get_else_block ()); + + desugar_iflet (expr, &branch_value, kase_else_expr, match_arms); auto crate_num = mappings.get_current_crate (); Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), mappings.get_next_hir_id (crate_num), UNKNOWN_LOCAL_DEFID); - translated = new HIR::IfLetExprConseqElse ( - mapping, std::move (patterns), std::unique_ptr (value_ptr), - std::unique_ptr (block), - std::unique_ptr (else_block), expr.get_locus ()); + translated + = new HIR::MatchExpr (mapping, std::unique_ptr (branch_value), + std::move (match_arms), {}, {}, expr.get_locus ()); } // rust-ast-lower-struct-field-expr.h diff --git a/gcc/rust/hir/rust-ast-lower.h b/gcc/rust/hir/rust-ast-lower.h index 23730e00221c..5ad3e63c824d 100644 --- a/gcc/rust/hir/rust-ast-lower.h +++ b/gcc/rust/hir/rust-ast-lower.h @@ -39,6 +39,11 @@ struct_field_name_exists (std::vector &fields, Visibility translate_visibility (const AST::Visibility &vis); +/** + * Main base class used for lowering AST to HIR. + * + * Every subclass should provide a translate() method that takes an AST node and + * lowers it to some HIR stored in the TRANSLATED member. */ class ASTLowering { public: diff --git a/gcc/rust/hir/rust-hir-dump.cc b/gcc/rust/hir/rust-hir-dump.cc index 6d750dc1c589..8ebdd3de6251 100644 --- a/gcc/rust/hir/rust-hir-dump.cc +++ b/gcc/rust/hir/rust-hir-dump.cc @@ -463,17 +463,6 @@ Dump::do_baseloopexpr (BaseLoopExpr &e) visit_field ("loop_block", e.get_loop_block ()); } -void -Dump::do_ifletexpr (IfLetExpr &e) -{ - do_expr (e); - - visit_collection ("match_arm_patterns", e.get_patterns ()); - - visit_field ("value", e.get_scrutinee_expr ()); - visit_field ("if_block", e.get_if_block ()); -} - void Dump::do_struct (Struct &e) { @@ -1441,23 +1430,6 @@ Dump::visit (IfExprConseqElse &e) end ("IfExprConseqElse"); } -void -Dump::visit (IfLetExpr &e) -{ - begin ("IfLetExpr"); - do_ifletexpr (e); - end ("IfLetExpr"); -} - -void -Dump::visit (IfLetExprConseqElse &e) -{ - begin ("IfLetExprConseqElse"); - do_ifletexpr (e); - visit_field ("else_block", e.get_else_block ()); - end ("IfLetExprConseqElse"); -} - void Dump::visit (MatchExpr &e) { diff --git a/gcc/rust/hir/rust-hir-dump.h b/gcc/rust/hir/rust-hir-dump.h index 2fe0261a363f..920b1031a71d 100644 --- a/gcc/rust/hir/rust-hir-dump.h +++ b/gcc/rust/hir/rust-hir-dump.h @@ -80,7 +80,6 @@ class Dump : public HIRFullVisitor void do_type (Type &); void do_expr (Expr &); void do_ifexpr (IfExpr &); - void do_ifletexpr (IfLetExpr &); void do_pathexpr (PathExpr &); void do_pathpattern (PathPattern &); void do_genericargs (GenericArgs &); @@ -162,8 +161,6 @@ class Dump : public HIRFullVisitor virtual void visit (WhileLetLoopExpr &) override; virtual void visit (IfExpr &) override; virtual void visit (IfExprConseqElse &) override; - virtual void visit (IfLetExpr &) override; - virtual void visit (IfLetExprConseqElse &) override; virtual void visit (MatchExpr &) override; virtual void visit (AwaitExpr &) override; diff --git a/gcc/rust/hir/tree/rust-hir-expr.h b/gcc/rust/hir/tree/rust-hir-expr.h index 56cb7d8b6e4a..99044905de37 100644 --- a/gcc/rust/hir/tree/rust-hir-expr.h +++ b/gcc/rust/hir/tree/rust-hir-expr.h @@ -32,7 +32,7 @@ namespace HIR { // TODO: inline? class LoopLabel /*: public Node*/ { - Lifetime label; // or type LIFETIME_OR_LABEL + Lifetime label; // of type LIFETIME_OR_LABEL location_t locus; @@ -3108,9 +3108,6 @@ class WhileLetLoopExpr : public BaseLoopExpr } }; -// forward decl for IfExpr -class IfLetExpr; - // Base if expression with no "else" or "if let" HIR node class IfExpr : public ExprWithBlock { @@ -3258,177 +3255,6 @@ class IfExprConseqElse : public IfExpr } }; -// Basic "if let" expression HIR node with no else -class IfLetExpr : public ExprWithBlock -{ - // MatchArmPatterns patterns; - std::vector > match_arm_patterns; // inlined - std::unique_ptr value; - std::unique_ptr if_block; - - location_t locus; - -public: - std::string as_string () const override; - - IfLetExpr (Analysis::NodeMapping mappings, - std::vector > match_arm_patterns, - std::unique_ptr value, std::unique_ptr if_block, - location_t locus) - : ExprWithBlock (std::move (mappings), AST::AttrVec ()), - match_arm_patterns (std::move (match_arm_patterns)), - value (std::move (value)), if_block (std::move (if_block)), locus (locus) - {} - // outer attributes not allowed on if let exprs either - - // copy constructor with clone - IfLetExpr (IfLetExpr const &other) - : ExprWithBlock (other), - /*match_arm_patterns(other.match_arm_patterns),*/ value ( - other.value->clone_expr ()), - if_block (other.if_block->clone_block_expr ()), locus (other.locus) - { - match_arm_patterns.reserve (other.match_arm_patterns.size ()); - for (const auto &e : other.match_arm_patterns) - match_arm_patterns.push_back (e->clone_pattern ()); - } - - // overload assignment operator to clone - IfLetExpr &operator= (IfLetExpr const &other) - { - ExprWithBlock::operator= (other); - // match_arm_patterns = other.match_arm_patterns; - value = other.value->clone_expr (); - if_block = other.if_block->clone_block_expr (); - locus = other.locus; - - match_arm_patterns.reserve (other.match_arm_patterns.size ()); - for (const auto &e : other.match_arm_patterns) - match_arm_patterns.push_back (e->clone_pattern ()); - - return *this; - } - - // move constructors - IfLetExpr (IfLetExpr &&other) = default; - IfLetExpr &operator= (IfLetExpr &&other) = default; - - // Unique pointer custom clone function - std::unique_ptr clone_if_let_expr () const - { - return std::unique_ptr (clone_if_let_expr_impl ()); - } - - location_t get_locus () const override final { return locus; } - - void accept_vis (HIRFullVisitor &vis) override; - void accept_vis (HIRExpressionVisitor &vis) override; - - std::unique_ptr &get_scrutinee_expr () { return value; } - - std::vector > &get_patterns () - { - return match_arm_patterns; - } - - std::unique_ptr &get_if_block () { return if_block; } - - ExprType get_expression_type () const final override - { - return ExprType::IfLet; - } - -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - IfLetExpr *clone_expr_impl () const override { return new IfLetExpr (*this); } - - /* Use covariance to implement clone function as returning this object rather - * than base */ - IfLetExpr *clone_expr_with_block_impl () const override - { - return new IfLetExpr (*this); - } - - // Base clone function but still concrete as concrete base class - virtual IfLetExpr *clone_if_let_expr_impl () const - { - return new IfLetExpr (*this); - } -}; - -/* HIR node representing "if let" expression with an "else" expression at the - * end */ -class IfLetExprConseqElse : public IfLetExpr -{ - std::unique_ptr else_block; - -public: - std::string as_string () const override; - - IfLetExprConseqElse ( - Analysis::NodeMapping mappings, - std::vector > match_arm_patterns, - std::unique_ptr value, std::unique_ptr if_block, - std::unique_ptr else_block, location_t locus) - : IfLetExpr (std::move (mappings), std::move (match_arm_patterns), - std::move (value), std::move (if_block), locus), - else_block (std::move (else_block)) - {} - // outer attributes not allowed - - // copy constructor with clone - IfLetExprConseqElse (IfLetExprConseqElse const &other) - : IfLetExpr (other), else_block (other.else_block->clone_expr_with_block ()) - {} - - // overload assignment operator to clone - IfLetExprConseqElse &operator= (IfLetExprConseqElse const &other) - { - IfLetExpr::operator= (other); - // match_arm_patterns = other.match_arm_patterns; - // value = other.value->clone_expr(); - // if_block = other.if_block->clone_block_expr(); - else_block = other.else_block->clone_expr_with_block (); - // outer_attrs = other.outer_attrs; - - return *this; - } - - // move constructors - IfLetExprConseqElse (IfLetExprConseqElse &&other) = default; - IfLetExprConseqElse &operator= (IfLetExprConseqElse &&other) = default; - - void accept_vis (HIRFullVisitor &vis) override; - void accept_vis (HIRExpressionVisitor &vis) override; - - void vis_else_block (HIRFullVisitor &vis) { else_block->accept_vis (vis); } - - std::unique_ptr &get_else_block () { return else_block; } - -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - IfLetExprConseqElse *clone_expr_impl () const override - { - return new IfLetExprConseqElse (*this); - } - - /* Use covariance to implement clone function as returning this object rather - * than base */ - IfLetExprConseqElse *clone_expr_with_block_impl () const override - { - return new IfLetExprConseqElse (*this); - } - - /* Use covariance to implement clone function as returning this object rather - * than base */ - IfLetExprConseqElse *clone_if_let_expr_impl () const override - { - return new IfLetExprConseqElse (*this); - } -}; - // Match arm expression struct MatchArm { diff --git a/gcc/rust/hir/tree/rust-hir-full-decls.h b/gcc/rust/hir/tree/rust-hir-full-decls.h index 7cc031870eba..0db8bd23404f 100644 --- a/gcc/rust/hir/tree/rust-hir-full-decls.h +++ b/gcc/rust/hir/tree/rust-hir-full-decls.h @@ -113,8 +113,6 @@ class WhileLoopExpr; class WhileLetLoopExpr; class IfExpr; class IfExprConseqElse; -class IfLetExpr; -class IfLetExprConseqElse; struct MatchArm; // class MatchCase; // class MatchCaseBlockExpr; diff --git a/gcc/rust/hir/tree/rust-hir-visitor.h b/gcc/rust/hir/tree/rust-hir-visitor.h index 840dc2e11226..d30901684b4c 100644 --- a/gcc/rust/hir/tree/rust-hir-visitor.h +++ b/gcc/rust/hir/tree/rust-hir-visitor.h @@ -81,8 +81,6 @@ class HIRFullVisitor virtual void visit (WhileLetLoopExpr &expr) = 0; virtual void visit (IfExpr &expr) = 0; virtual void visit (IfExprConseqElse &expr) = 0; - virtual void visit (IfLetExpr &expr) = 0; - virtual void visit (IfLetExprConseqElse &expr) = 0; virtual void visit (MatchExpr &expr) = 0; virtual void visit (AwaitExpr &expr) = 0; virtual void visit (AsyncBlockExpr &expr) = 0; @@ -219,8 +217,6 @@ class HIRFullVisitorBase : public HIRFullVisitor virtual void visit (WhileLetLoopExpr &) override {} virtual void visit (IfExpr &) override {} virtual void visit (IfExprConseqElse &) override {} - virtual void visit (IfLetExpr &) override {} - virtual void visit (IfLetExprConseqElse &) override {} virtual void visit (MatchExpr &) override {} virtual void visit (AwaitExpr &) override {} @@ -448,8 +444,6 @@ class HIRExpressionVisitor virtual void visit (WhileLetLoopExpr &expr) = 0; virtual void visit (IfExpr &expr) = 0; virtual void visit (IfExprConseqElse &expr) = 0; - virtual void visit (IfLetExpr &expr) = 0; - virtual void visit (IfLetExprConseqElse &expr) = 0; virtual void visit (InlineAsm &expr) = 0; virtual void visit (MatchExpr &expr) = 0; virtual void visit (AwaitExpr &expr) = 0; diff --git a/gcc/rust/hir/tree/rust-hir.cc b/gcc/rust/hir/tree/rust-hir.cc index d5ca95c1cc06..b00e147549e3 100644 --- a/gcc/rust/hir/tree/rust-hir.cc +++ b/gcc/rust/hir/tree/rust-hir.cc @@ -1571,41 +1571,6 @@ IfExprConseqElse::as_string () const return str; } -std::string -IfLetExpr::as_string () const -{ - std::string str ("IfLetExpr: "); - - str += "\n Condition match arm patterns: "; - if (match_arm_patterns.empty ()) - { - str += "none"; - } - else - { - for (const auto &pattern : match_arm_patterns) - { - str += "\n " + pattern->as_string (); - } - } - - str += "\n Scrutinee expr: " + value->as_string (); - - str += "\n If let block expr: " + if_block->as_string (); - - return str; -} - -std::string -IfLetExprConseqElse::as_string () const -{ - std::string str = IfLetExpr::as_string (); - - str += "\n Else expr: " + else_block->as_string (); - - return str; -} - std::string RangeFromToInclExpr::as_string () const { @@ -4149,18 +4114,6 @@ IfExprConseqElse::accept_vis (HIRFullVisitor &vis) vis.visit (*this); } -void -IfLetExpr::accept_vis (HIRFullVisitor &vis) -{ - vis.visit (*this); -} - -void -IfLetExprConseqElse::accept_vis (HIRFullVisitor &vis) -{ - vis.visit (*this); -} - void MatchExpr::accept_vis (HIRFullVisitor &vis) { @@ -4911,18 +4864,6 @@ RangeFromToInclExpr::accept_vis (HIRExpressionVisitor &vis) vis.visit (*this); } -void -IfLetExprConseqElse::accept_vis (HIRExpressionVisitor &vis) -{ - vis.visit (*this); -} - -void -IfLetExpr::accept_vis (HIRExpressionVisitor &vis) -{ - vis.visit (*this); -} - void IfExprConseqElse::accept_vis (HIRExpressionVisitor &vis) { diff --git a/gcc/rust/hir/tree/rust-hir.h b/gcc/rust/hir/tree/rust-hir.h index e61249987a2c..784e12e57ab1 100644 --- a/gcc/rust/hir/tree/rust-hir.h +++ b/gcc/rust/hir/tree/rust-hir.h @@ -300,7 +300,6 @@ class Expr : public Node, virtual public FullVisitable UnsafeBlock, BaseLoop, If, - IfLet, Match, Await, AsyncBlock, diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.cc b/gcc/rust/typecheck/rust-hir-type-check-expr.cc index 49f1bbb1a614..369e1fd270a7 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.cc @@ -503,67 +503,6 @@ TypeCheckExpr::visit (HIR::IfExprConseqElse &expr) } } -void -TypeCheckExpr::visit (HIR::IfLetExpr &expr) -{ - // this needs to perform a least upper bound coercion on the blocks and then - // unify the scruintee and arms - TyTy::BaseType *scrutinee_tyty - = TypeCheckExpr::Resolve (expr.get_scrutinee_expr ().get ()); - - for (auto &pattern : expr.get_patterns ()) - { - TyTy::BaseType *kase_arm_ty - = TypeCheckPattern::Resolve (pattern.get (), scrutinee_tyty); - - unify_site (expr.get_mappings ().get_hirid (), - TyTy::TyWithLocation (scrutinee_tyty), - TyTy::TyWithLocation (kase_arm_ty, pattern->get_locus ()), - expr.get_locus ()); - } - - TypeCheckExpr::Resolve (expr.get_if_block ().get ()); - - infered = TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ()); -} - -void -TypeCheckExpr::visit (HIR::IfLetExprConseqElse &expr) -{ - TyTy::BaseType *scrutinee_tyty - = TypeCheckExpr::Resolve (expr.get_scrutinee_expr ().get ()); - - for (auto &pattern : expr.get_patterns ()) - { - TyTy::BaseType *kase_arm_ty - = TypeCheckPattern::Resolve (pattern.get (), scrutinee_tyty); - - unify_site (expr.get_mappings ().get_hirid (), - TyTy::TyWithLocation (scrutinee_tyty), - TyTy::TyWithLocation (kase_arm_ty, pattern->get_locus ()), - expr.get_locus ()); - } - - auto if_blk_resolved = TypeCheckExpr::Resolve (expr.get_if_block ().get ()); - auto else_blk_resolved - = TypeCheckExpr::Resolve (expr.get_else_block ().get ()); - - if (if_blk_resolved->get_kind () == TyTy::NEVER) - infered = else_blk_resolved; - else if (else_blk_resolved->get_kind () == TyTy::NEVER) - infered = if_blk_resolved; - else - { - infered = unify_site ( - expr.get_mappings ().get_hirid (), - TyTy::TyWithLocation (if_blk_resolved, - expr.get_if_block ()->get_locus ()), - TyTy::TyWithLocation (else_blk_resolved, - expr.get_else_block ()->get_locus ()), - expr.get_locus ()); - } -} - void TypeCheckExpr::visit (HIR::UnsafeBlockExpr &expr) { diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h index 2f4a2c52f6db..e8137306b7c5 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.h +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h @@ -45,8 +45,6 @@ class TypeCheckExpr : private TypeCheckBase, private HIR::HIRExpressionVisitor void visit (HIR::NegationExpr &expr) override; void visit (HIR::IfExpr &expr) override; void visit (HIR::IfExprConseqElse &expr) override; - void visit (HIR::IfLetExpr &expr) override; - void visit (HIR::IfLetExprConseqElse &) override; void visit (HIR::BlockExpr &expr) override; void visit (HIR::UnsafeBlockExpr &expr) override; void visit (HIR::ArrayIndexExpr &expr) override; diff --git a/gcc/testsuite/rust/compile/if_let_expr.rs b/gcc/testsuite/rust/compile/if_let_expr.rs index 7bab19a1ef03..b0879e5fadbb 100644 --- a/gcc/testsuite/rust/compile/if_let_expr.rs +++ b/gcc/testsuite/rust/compile/if_let_expr.rs @@ -7,8 +7,9 @@ pub enum Option { } fn main() { - let x = Option::Some(3); // { dg-warning "unused name" } - let a = if let Option::Some(1) = x { + let x = Option::Some(3); + + let a = if let Option::Some(1) = x {// { dg-warning "unused name" } 1 } else if x == Option::Some(2) { 2 diff --git a/gcc/testsuite/rust/compile/if_let_expr_simple.rs b/gcc/testsuite/rust/compile/if_let_expr_simple.rs new file mode 100644 index 000000000000..d7fb0afa7fd3 --- /dev/null +++ b/gcc/testsuite/rust/compile/if_let_expr_simple.rs @@ -0,0 +1,12 @@ +enum MyOption { + Some(i32), + None, +} + +pub fn toto(i : MyOption) -> i32 { + if let MyOption::Some(v) = i { + v + } else { + 23i32 + } +} diff --git a/gcc/testsuite/rust/compile/iflet.rs b/gcc/testsuite/rust/compile/iflet.rs new file mode 100644 index 000000000000..6d46339610f5 --- /dev/null +++ b/gcc/testsuite/rust/compile/iflet.rs @@ -0,0 +1,32 @@ +pub fn simple_iflet() -> i32 { + let mut res = 0; + + enum E { + X(i32), + } + let v = E::X(4); + + if let E::X(n) = v { + res = 1; + } + + res +} + +pub fn simple_iflet_else() -> i32 { + let mut res = 0; + + enum E { + X(i32), + Y, + } + let v = E::X(4); + + if let E::Y = v { + res = 1; + } else { + res = 2; + } + + res +} diff --git a/gcc/testsuite/rust/compile/nr2/exclude b/gcc/testsuite/rust/compile/nr2/exclude index 47d651b22bdf..424ad6860945 100644 --- a/gcc/testsuite/rust/compile/nr2/exclude +++ b/gcc/testsuite/rust/compile/nr2/exclude @@ -223,4 +223,7 @@ issue-2203.rs issue-2499.rs issue-3032-1.rs issue-3032-2.rs +# https://github.com/Rust-GCC/gccrs/issues/3189 +if_let_expr_simple.rs +iflet.rs # please don't delete the trailing newline diff --git a/gcc/testsuite/rust/execute/torture/iflet.rs b/gcc/testsuite/rust/execute/torture/iflet.rs new file mode 100644 index 000000000000..da4e93ac3988 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/iflet.rs @@ -0,0 +1,84 @@ +enum Res { + OK, + BAD, +} + +enum LOption { + Some(i32), + None, +} + +// Expect a Some(_) +// +// Check we can match a Some. +fn test_can_destructure_Some(v: LOption) -> Res { + if let LOption::Some(v) = v { + return Res::OK; + } + return Res::BAD; +} + +// Expect Some(100). +// +// Check we can destructure and the inner value is correct. +fn test_inner_value_is_100(v: LOption) -> Res { + if let LOption::Some(v) = v { + return match v { + 100 => Res::OK, + _ => Res::BAD, + } + } + return Res::BAD; +} + +// Expect a None as actual parameter. +// +// Only when we FAIL to match a Some do we take the else and return OK. +fn test_if_else(v: LOption) -> Res { + if let LOption::Some(v) = v { + return Res::BAD; + } else { + return Res::OK; + } +} + +fn main() -> i32 { + + // Passing a None, so the function should return BAD + match test_can_destructure_Some(LOption::None) { + Res::OK => return 1, + Res::BAD => (), + } + + // Same, but with a Some, should return OK + match test_can_destructure_Some(LOption::Some(1)) { + Res::OK => (), + Res::BAD => return 1, + } + + // Check the destructuring is correct by looking for Some(100) + match test_inner_value_is_100(LOption::Some(100)) { + Res::OK => (), + Res::BAD => return 1, + } + + // ... passing Some(1) should return BAD + match test_inner_value_is_100(LOption::Some(1)) { + Res::OK => return 1, + Res::BAD => (), + } + + // ... and so does passing None + match test_inner_value_is_100(LOption::None) { + Res::OK => return 1, + Res::BAD => (), + } + + // Check if let... else ... + match test_if_else(LOption::None) { + Res::OK => (), + Res::BAD => return 1, + } + + 0 +}