diff --git a/src/ast/dump.cpp b/src/ast/dump.cpp index 595ebf147..f1467c494 100644 --- a/src/ast/dump.cpp +++ b/src/ast/dump.cpp @@ -261,12 +261,6 @@ class RustPrinter: m_os << "while "; AST::NodeVisitor::visit(n.m_cond); break; - case AST::ExprNode_Loop::WHILELET: - m_os << "while let "; - print_pattern(n.m_pattern, true); - m_os << " = "; - AST::NodeVisitor::visit(n.m_cond); - break; case AST::ExprNode_Loop::FOR: m_os << "while for "; print_pattern(n.m_pattern, true); @@ -287,6 +281,36 @@ class RustPrinter: AST::NodeVisitor::visit(n.m_code); } + void visit_iflet_conditions(std::vector& conds) { + for(size_t i = 0; i < conds.size(); i ++) { + if(i != 0) m_os << " && "; + if(conds[i].opt_pat) { + print_pattern(*conds[i].opt_pat, true); + m_os << " = "; + } + m_os << "("; + AST::NodeVisitor::visit(conds[i].value); + m_os << ")"; + } + } + void visit(AST::ExprNode_WhileLet& n) override { + bool expr_root = m_expr_root; + m_expr_root = false; + + m_os << "while let "; + visit_iflet_conditions(n.m_conditions); + if( expr_root ) + { + m_os << "\n"; + m_os << indent(); + } + else + { + m_os << " "; + } + + AST::NodeVisitor::visit(n.m_code); + } virtual void visit(AST::ExprNode_Match& n) override { bool expr_root = m_expr_root; m_expr_root = false; @@ -361,14 +385,7 @@ class RustPrinter: bool expr_root = m_expr_root; m_expr_root = false; m_os << "if let "; - for(const auto& pat : n.m_patterns) - { - if(&pat != &n.m_patterns.front()) - m_os << " | "; - print_pattern(pat, /*is_refutable=*/true); - } - m_os << " = "; - AST::NodeVisitor::visit(n.m_value); + visit_iflet_conditions(n.m_conditions); visit_if_common(expr_root, n.m_true, n.m_false); } diff --git a/src/ast/expr.cpp b/src/ast/expr.cpp index affacd534..71b0ad922 100644 --- a/src/ast/expr.cpp +++ b/src/ast/expr.cpp @@ -317,8 +317,35 @@ NODE(ExprNode_Loop, { os << " in/= " << *m_cond; os << " " << *m_code; },{ - return NEWNODE(ExprNode_Loop, m_label, m_type, m_pattern.clone(), OPT_CLONE(m_cond), m_code->clone()); + return NEWNODE(ExprNode_Loop, m_type, m_label, m_pattern.clone(), OPT_CLONE(m_cond), m_code->clone()); }) +NODE(ExprNode_WhileLet, { + if(m_label != "") { + os << "'" << m_label << ": "; + } + os << "while let "; + for(size_t i = 0; i < m_conditions.size(); i ++) { + if( i != 0 ) { + os << " && "; + } + if( m_conditions[i].opt_pat ) { + os << *m_conditions[i].opt_pat << " = "; + } + os << "(" << *m_conditions[i].value << ")"; + } + os << " { " << *m_code << " }"; + },{ + decltype(m_conditions) new_conds; + for(const auto& cond : m_conditions) { + AST::IfLet_Condition new_cond; + if( cond.opt_pat ) { + new_cond.opt_pat = std::make_unique( cond.opt_pat->clone() ); + } + new_cond.value = cond.value->clone(); + new_conds.push_back(std::move(new_cond)); + } + return NEWNODE(ExprNode_WhileLet, m_label, mv$(new_conds), m_code->clone()); + }) MatchGuard MatchGuard::clone() const { @@ -382,19 +409,28 @@ NODE(ExprNode_If, { }) NODE(ExprNode_IfLet, { os << "if let "; - for(const auto& pat : m_patterns) - { - if(&pat != &m_patterns.front()) - os << " | "; - os << pat; + for(size_t i = 0; i < m_conditions.size(); i ++) { + if( i != 0 ) { + os << " && "; + } + if( m_conditions[i].opt_pat ) { + os << *m_conditions[i].opt_pat << " = "; + } + os << "(" << *m_conditions[i].value << ")"; } - os << " = (" << *m_value << ") { " << *m_true << " }"; + os << " { " << *m_true << " }"; if(m_false) os << " else { " << *m_false << " }"; },{ - decltype(m_patterns) new_pats; - for(const auto& pat : m_patterns) - new_pats.push_back(pat.clone()); - return NEWNODE(ExprNode_IfLet, mv$(new_pats), m_value->clone(), m_true->clone(), OPT_CLONE(m_false)); + decltype(m_conditions) new_conds; + for(const auto& cond : m_conditions) { + AST::IfLet_Condition new_cond; + if( cond.opt_pat ) { + new_cond.opt_pat = std::make_unique( cond.opt_pat->clone() ); + } + new_cond.value = cond.value->clone(); + new_conds.push_back(std::move(new_cond)); + } + return NEWNODE(ExprNode_IfLet, mv$(new_conds), m_true->clone(), OPT_CLONE(m_false)); }) NODE(ExprNode_Integer, { @@ -707,6 +743,15 @@ NV(ExprNode_Loop, visit(node.m_code); UNINDENT(); }) +NV(ExprNode_WhileLet, +{ + INDENT(); + for(auto& c : node.m_conditions) { + visit(c.value); + } + visit(node.m_code); + UNINDENT(); +}) NV(ExprNode_Match, { INDENT(); @@ -733,7 +778,9 @@ NV(ExprNode_If, NV(ExprNode_IfLet, { INDENT(); - visit(node.m_value); + for(auto& c : node.m_conditions) { + visit(c.value); + } visit(node.m_true); visit(node.m_false); UNINDENT(); diff --git a/src/ast/expr.hpp b/src/ast/expr.hpp index ed13fbbc9..ceb9c7b4e 100644 --- a/src/ast/expr.hpp +++ b/src/ast/expr.hpp @@ -21,6 +21,7 @@ namespace AST { +class Pattern; class NodeVisitor; class ExprNode @@ -292,7 +293,6 @@ struct ExprNode_Loop: enum Type { LOOP, WHILE, - WHILELET, FOR, } m_type; Ident m_label; @@ -316,14 +316,41 @@ struct ExprNode_Loop: m_cond( ::std::move(cond) ), m_code( ::std::move(code) ) {} - ExprNode_Loop(Ident label, Type type, AST::Pattern pattern, ExprNodeP val, ExprNodeP code): - m_type(type), + ExprNode_Loop(Ident label, AST::Pattern pattern, ExprNodeP val, ExprNodeP code): + m_type(FOR), m_label( ::std::move(label) ), m_pattern( ::std::move(pattern) ), m_cond( ::std::move(val) ), m_code( ::std::move(code) ) {} NODE_METHODS(); +private: + ExprNode_Loop(Type type, Ident label, AST::Pattern pattern, ExprNodeP val, ExprNodeP code) + : m_type( type ) + , m_label( ::std::move(label) ) + , m_pattern( ::std::move(pattern) ) + , m_cond( ::std::move(val) ) + , m_code( ::std::move(code) ) + {} +}; +struct IfLet_Condition +{ + ::std::unique_ptr opt_pat; + ExprNodeP value; +}; +struct ExprNode_WhileLet: + public ExprNode +{ + Ident m_label; + std::vector m_conditions; + ExprNodeP m_code; + + ExprNode_WhileLet(Ident label, std::vector conditions, ExprNodeP code) + : m_label( ::std::move(label) ) + , m_conditions( ::std::move(conditions) ) + , m_code( ::std::move(code) ) + {} + NODE_METHODS(); }; TAGGED_UNION_EX(MatchGuard, (), None, ( @@ -387,16 +414,14 @@ struct ExprNode_If: struct ExprNode_IfLet: public ExprNode { - std::vector m_patterns; - ExprNodeP m_value; + std::vector m_conditions; ExprNodeP m_true; ExprNodeP m_false; - ExprNode_IfLet(std::vector patterns, ExprNodeP cond, ExprNodeP true_code, ExprNodeP false_code): - m_patterns( ::std::move(patterns) ), - m_value( ::std::move(cond) ), - m_true( ::std::move(true_code) ), - m_false( ::std::move(false_code) ) + ExprNode_IfLet(std::vector conditions, ExprNodeP true_code, ExprNodeP false_code) + : m_conditions( ::std::move(conditions) ) + , m_true( ::std::move(true_code) ) + , m_false( ::std::move(false_code) ) { } NODE_METHODS(); @@ -727,6 +752,7 @@ class NodeVisitor NT(ExprNode_CallMethod); NT(ExprNode_CallObject); NT(ExprNode_Loop); + NT(ExprNode_WhileLet); NT(ExprNode_Match); NT(ExprNode_If); NT(ExprNode_IfLet); @@ -776,6 +802,7 @@ class NodeVisitorDef: NT(ExprNode_CallMethod); NT(ExprNode_CallObject); NT(ExprNode_Loop); + NT(ExprNode_WhileLet); NT(ExprNode_Match); NT(ExprNode_If); NT(ExprNode_IfLet); diff --git a/src/expand/mod.cpp b/src/expand/mod.cpp index 43f78956f..05310f467 100644 --- a/src/expand/mod.cpp +++ b/src/expand/mod.cpp @@ -877,6 +877,7 @@ struct CExpandExpr: void visit(::AST::ExprNode_CallMethod& v) override { invalid(v); } void visit(::AST::ExprNode_CallObject& v) override { invalid(v); } void visit(::AST::ExprNode_Loop& v) override { invalid(v); } + void visit(::AST::ExprNode_WhileLet& v) override { invalid(v); } void visit(::AST::ExprNode_Match& v) override { invalid(v); } void visit(::AST::ExprNode_If& v) override { invalid(v); } void visit(::AST::ExprNode_IfLet& v) override { invalid(v); } @@ -950,7 +951,7 @@ struct CExpandExpr: void visit(::AST::ExprNode_Loop& node) override { this->visit_nodelete(node, node.m_cond); this->visit_nodelete(node, node.m_code); - Expand_Pattern(crate, modstack, this->cur_mod(), node.m_pattern, (node.m_type == ::AST::ExprNode_Loop::WHILELET)); + Expand_Pattern(crate, modstack, this->cur_mod(), node.m_pattern, false); if(node.m_type == ::AST::ExprNode_Loop::FOR) { auto core_crate = crate.m_ext_cratename_core; @@ -1009,6 +1010,67 @@ struct CExpandExpr: ) ); } } + + AST::ExprNodeP desugar_let_chain(const Span& sp, std::vector& conditions, AST::ExprNodeP true_block, std::function get_false_block) + { + // Iterate the conditions in reverse, because this is being built from the innermost block + for(size_t i = conditions.size(); i--; ) + { + auto& cond = conditions[i]; + auto node_nomatch = get_false_block(); + node_nomatch->set_span(sp); + if( cond.opt_pat ) { + ::std::vector< ::AST::ExprNode_Match_Arm> arms; + // - `pattern => body` + arms.push_back( ::AST::ExprNode_Match_Arm( + ::make_vec1( std::move(*cond.opt_pat) ), + AST::MatchGuard(), + std::move(true_block) + ) ); + // - `_ => break,` + arms.push_back( ::AST::ExprNode_Match_Arm( + ::make_vec1( ::AST::Pattern() ), + AST::MatchGuard(), + std::move(node_nomatch) + ) ); + true_block.reset(new ::AST::ExprNode_Match( std::move(cond.value), std::move(arms) )); + } + else { + true_block.reset(new ::AST::ExprNode_If( std::move(cond.value), std::move(true_block), std::move(node_nomatch) )); + } + true_block->set_span(sp); + } + return true_block; + } + + void visit(::AST::ExprNode_WhileLet& node) override { + for(auto& cond : node.m_conditions) { + if( cond.opt_pat ) { + Expand_Pattern(crate, modstack, this->cur_mod(), *cond.opt_pat, true); + } + this->visit_nodelete(node, cond.value); + } + this->visit_nodelete(node, node.m_code); + + // Desugar into: + /* + * loop { + * match val_a { + * pat_a => match val_b { + * pat_b => ..., + * _ => break, + * }, + * _ => break, + * } + * } + */ + auto node_body = desugar_let_chain(node.span(), node.m_conditions, + std::move(node.m_code), + [&](){ return AST::ExprNodeP { new AST::ExprNode_Flow(AST::ExprNode_Flow::BREAK, node.m_label, AST::ExprNodeP()) }; } + ); + replacement.reset(new ::AST::ExprNode_Loop(node.m_label, std::move(node_body) )); + replacement->set_span(node.span()); + } void visit(::AST::ExprNode_Match& node) override { this->visit_nodelete(node, node.m_val); for(auto& arm : node.m_arms) @@ -1050,11 +1112,49 @@ struct CExpandExpr: this->visit_nodelete(node, node.m_false); } void visit(::AST::ExprNode_IfLet& node) override { - for(auto& pat : node.m_patterns) - Expand_Pattern(crate, modstack, this->cur_mod(), pat, true); - this->visit_nodelete(node, node.m_value); + for(auto& cond : node.m_conditions) { + if( cond.opt_pat ) { + Expand_Pattern(crate, modstack, this->cur_mod(), *cond.opt_pat, true); + } + this->visit_nodelete(node, cond.value); + } this->visit_nodelete(node, node.m_true); this->visit_nodelete(node, node.m_false); + + // TODO: Desugar into: + /* + * '#iflet: { + * match val_a { + * pat_a => match val_b { + * pat_b => break '#iflet ({ true body }), + * _ => {}, + * }, + * _ => {}, + * } + * false body + * } + */ +#if 1 + Ident label({}, "#iflet"); + auto node_body = desugar_let_chain(node.span(), node.m_conditions, + AST::ExprNodeP { new AST::ExprNode_Flow(AST::ExprNode_Flow::BREAK, label, std::move(node.m_true)) }, + [&](){ return AST::ExprNodeP { new AST::ExprNode_Block() }; } + ); + // - Create the block + auto* replacement = new ::AST::ExprNode_Block(); + replacement->m_label = label; + replacement->m_nodes.push_back(std::move(node_body)); + if(node.m_false) { + replacement->m_nodes.push_back(std::move(node.m_false)); + } + else { + replacement->m_nodes.push_back(new AST::ExprNode_Tuple({})); + } + replacement->m_nodes.back()->set_span(node.span()); + replacement->m_yields_final_value = true; + replacement->set_span(node.span()); + this->replacement.reset(replacement); +#endif } void visit(::AST::ExprNode_Integer& node) override { } void visit(::AST::ExprNode_Float& node) override { } diff --git a/src/expand/proc_macro.cpp b/src/expand/proc_macro.cpp index 497183705..6ebb9b78b 100644 --- a/src/expand/proc_macro.cpp +++ b/src/expand/proc_macro.cpp @@ -985,6 +985,9 @@ namespace { void visit(::AST::ExprNode_Loop& node) { TODO(sp, "ExprNode_Loop"); } + void visit(::AST::ExprNode_WhileLet& node) { + TODO(sp, "ExprNode_Loop"); + } void visit(::AST::ExprNode_Match& node) { TODO(sp, "ExprNode_Match"); } diff --git a/src/hir/from_ast_expr.cpp b/src/hir/from_ast_expr.cpp index 60683327e..3d3bb4dd7 100644 --- a/src/hir/from_ast_expr.cpp +++ b/src/hir/from_ast_expr.cpp @@ -455,7 +455,63 @@ struct LowerHIR_ExprNode_Visitor: ::HIR::ExprNodeP(new ::HIR::ExprNode_Block( v.span(), false, mv$(code), {} )) ) ); break; } - case ::AST::ExprNode_Loop::WHILELET: { + case ::AST::ExprNode_Loop::FOR: + // NOTE: This should already be desugared (as a pass before resolve) + BUG(v.span(), "Encountered still-sugared for loop"); + break; + } + + // Iterate the constructed loop and determine if there are any `break` statements pointing to it + { + struct LoopVisitor: + public ::HIR::ExprVisitorDef + { + const RcString& top_label; + bool top_is_broken; + ::std::vector< const RcString*> name_stack; + + LoopVisitor(const RcString& top_label): + top_label(top_label), + top_is_broken(false), + name_stack() + {} + + void visit(::HIR::ExprNode_Loop& node) override { + bool push = !node.m_require_label; // Ignore any loops that require a targeted break + if( push ) { + this->name_stack.push_back( &node.m_label ); + } + ::HIR::ExprVisitorDef::visit(node); + if( push ) { + this->name_stack.pop_back( ); + } + } + void visit(::HIR::ExprNode_LoopControl& node) override { + ::HIR::ExprVisitorDef::visit(node); + + if( node.m_continue ) { + } + else { + for( auto it = this->name_stack.rbegin(); it != this->name_stack.rend(); ++ it ) + { + if( node.m_label == "" || node.m_label == **it ) + return ; + } + if( node.m_label == "" || node.m_label == this->top_label ) { + this->top_is_broken = true; + } + else { + // break is for a higher loop + } + } + } + }; + } + } + virtual void visit(::AST::ExprNode_WhileLet& v) override { + +#if 0 + { ::std::vector< ::HIR::ExprNode_Match::Arm> arms; // - Matches pattern - Run inner code @@ -476,14 +532,12 @@ struct LowerHIR_ExprNode_Visitor: ::HIR::ExprNodeP(new ::HIR::ExprNode_Match( v.span(), lower(v.m_cond), mv$(arms) - )) - ) ); - break; } - case ::AST::ExprNode_Loop::FOR: - // NOTE: This should already be desugared (as a pass before resolve) - BUG(v.span(), "Encountered still-sugared for loop"); - break; + )) + ) ); } +#else + TODO(v.span(), "while let (chained)"); +#endif // Iterate the constructed loop and determine if there are any `break` statements pointing to it { @@ -595,6 +649,7 @@ struct LowerHIR_ExprNode_Visitor: )); } virtual void visit(::AST::ExprNode_IfLet& v) override { +#if 0 ::std::vector< ::HIR::ExprNode_Match::Arm> arms; std::vector patterns; @@ -617,6 +672,9 @@ struct LowerHIR_ExprNode_Visitor: lower(v.m_value), mv$(arms) )); +#else +TODO(v.span(), "while let (chained)"); +#endif } virtual void visit(::AST::ExprNode_Integer& v) override { diff --git a/src/parse/expr.cpp b/src/parse/expr.cpp index 8861714be..0e8f4777f 100644 --- a/src/parse/expr.cpp +++ b/src/parse/expr.cpp @@ -31,6 +31,7 @@ ExprNodeP Parse_ExprBlockLine_Stmt(TokenStream& lex, bool& has_semicolon); //ExprNodeP Parse_Stmt(TokenStream& lex); // common.hpp ExprNodeP Parse_Stmt_Let(TokenStream& lex); ExprNodeP Parse_Expr0(TokenStream& lex); +ExprNodeP Parse_Expr3(TokenStream& lex); ExprNodeP Parse_IfStmt(TokenStream& lex); ExprNodeP Parse_WhileStmt(TokenStream& lex, Ident lifetime); ExprNodeP Parse_ForStmt(TokenStream& lex, Ident lifetime); @@ -403,6 +404,46 @@ ExprNodeP Parse_ExprBlockLine_Stmt(TokenStream& lex, bool& has_semicolon) return ret; } +// Note: This is called jsut after the initial `let` has been consumed +std::vector Parse_IfLetChain(TokenStream& lex) +{ + Token tok; + std::vector conditions; + auto pat = Parse_Pattern(lex, AllowOrPattern::Yes); + GET_CHECK_TOK(tok, lex, TOK_EQUAL); + ExprNodeP val; + { + SET_PARSE_FLAG(lex, disallow_struct_literal); + val = Parse_Expr3(lex); // This is just after `||` and `&&` + } + conditions.push_back(AST::IfLet_Condition { box$(pat), std::move(val) }); + + if( lex.getTokenIf(TOK_DOUBLE_AMP) ) { + do { + if( lex.getTokenIf(TOK_RWORD_LET) ) { + std::vector conditions; + auto pat = Parse_Pattern(lex, AllowOrPattern::Yes); + GET_CHECK_TOK(tok, lex, TOK_EQUAL); + ExprNodeP val; + { + SET_PARSE_FLAG(lex, disallow_struct_literal); + val = Parse_Expr3(lex); // This is just after `||` and `&&` + } + conditions.push_back(AST::IfLet_Condition { box$(pat), std::move(val) }); + } + else { + conditions.push_back(AST::IfLet_Condition { std::unique_ptr(), Parse_Expr3(lex) }); + } + } while( lex.getTokenIf(TOK_DOUBLE_AMP) ); + } + + if( lex.lookahead(0) == TOK_DOUBLE_PIPE ) { + TODO(lex.point_span(), "lazy boolean or in let chains not yet implemented (not yet valid rust, at 1.75)"); + } + + return conditions; +} + /// While loop (either as a statement, or as part of an expression) ExprNodeP Parse_WhileStmt(TokenStream& lex, Ident lifetime) { @@ -410,15 +451,8 @@ ExprNodeP Parse_WhileStmt(TokenStream& lex, Ident lifetime) if( GET_TOK(tok, lex) == TOK_RWORD_LET ) { // TODO: Pattern list (same as match)? - auto pat = Parse_Pattern(lex, AllowOrPattern::Yes); // Refutable pattern - GET_CHECK_TOK(tok, lex, TOK_EQUAL); - ExprNodeP val; - { - SET_PARSE_FLAG(lex, disallow_struct_literal); - val = Parse_Expr0(lex); - } - return NEWNODE( AST::ExprNode_Loop, lifetime, AST::ExprNode_Loop::WHILELET, - ::std::move(pat), ::std::move(val), Parse_ExprBlockNode(lex) ); + auto conditions = Parse_IfLetChain(lex); + return NEWNODE( AST::ExprNode_WhileLet, lifetime, ::std::move(conditions), Parse_ExprBlockNode(lex) ); } else { PUTBACK(tok, lex); @@ -443,8 +477,7 @@ ExprNodeP Parse_ForStmt(TokenStream& lex, Ident lifetime) SET_PARSE_FLAG(lex, disallow_struct_literal); val = Parse_Expr0(lex); } - return NEWNODE( AST::ExprNode_Loop, lifetime, AST::ExprNode_Loop::FOR, - ::std::move(pat), ::std::move(val), Parse_ExprBlockNode(lex) ); + return NEWNODE( AST::ExprNode_Loop, lifetime, ::std::move(pat), ::std::move(val), Parse_ExprBlockNode(lex) ); } /// Parse an 'if' statement // Note: TOK_RWORD_IF has already been eaten @@ -454,20 +487,12 @@ ExprNodeP Parse_IfStmt(TokenStream& lex) Token tok; ExprNodeP cond; - std::vector paterns; + std::vector conditions; { SET_PARSE_FLAG(lex, disallow_struct_literal); if( GET_TOK(tok, lex) == TOK_RWORD_LET ) { - // Allow leading pipes (same as match) - if(lex.lookahead(0) == TOK_PIPE) - GET_TOK(tok, lex); - // Refutable pattern - do { - paterns.push_back( Parse_Pattern(lex, AllowOrPattern::No) ); - } while(GET_TOK(tok, lex) == TOK_PIPE); - CHECK_TOK(tok, TOK_EQUAL); - cond = Parse_Expr0(lex); + conditions = Parse_IfLetChain(lex); } else { PUTBACK(tok, lex); @@ -497,8 +522,8 @@ ExprNodeP Parse_IfStmt(TokenStream& lex) PUTBACK(tok, lex); } - if( !paterns.empty() ) - return NEWNODE( AST::ExprNode_IfLet, ::std::move(paterns), ::std::move(cond), ::std::move(code), ::std::move(altcode) ); + if( !cond ) + return NEWNODE( AST::ExprNode_IfLet, ::std::move(conditions), ::std::move(code), ::std::move(altcode) ); else return NEWNODE( AST::ExprNode_If, ::std::move(cond), ::std::move(code), ::std::move(altcode) ); } diff --git a/src/resolve/absolute.cpp b/src/resolve/absolute.cpp index a5031db5f..43ebaea8a 100644 --- a/src/resolve/absolute.cpp +++ b/src/resolve/absolute.cpp @@ -2228,17 +2228,15 @@ void Resolve_Absolute_ExprNode(Context& context, ::AST::ExprNode& node) break; case ::AST::ExprNode_Loop::WHILE: break; - case ::AST::ExprNode_Loop::WHILELET: - this->context.start_patbind(); - Resolve_Absolute_Pattern(this->context, true, node.m_pattern); - this->context.end_patbind(); - break; case ::AST::ExprNode_Loop::FOR: BUG(node.span(), "`for` should be desugared"); } node.m_code->visit( *this ); this->context.pop_block(); } + void visit(AST::ExprNode_WhileLet& node) override { + BUG(node.span(), "`while let` should be desugared"); + } void visit(AST::ExprNode_LetBinding& node) override { DEBUG("ExprNode_LetBinding"); @@ -2256,6 +2254,8 @@ void Resolve_Absolute_ExprNode(Context& context, ::AST::ExprNode& node) } } void visit(AST::ExprNode_IfLet& node) override { + BUG(node.span(), "`if let` should be desugared"); +#if 0 DEBUG("ExprNode_IfLet"); node.m_value->visit( *this ); @@ -2275,6 +2275,7 @@ void Resolve_Absolute_ExprNode(Context& context, ::AST::ExprNode& node) if(node.m_false) node.m_false->visit(*this); +#endif } void visit(AST::ExprNode_StructLiteral& node) override { DEBUG("ExprNode_StructLiteral");