From 7890a6dba8fcdb9454b2e58ea1363f270d2da2c5 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 29 May 2016 22:30:28 +0800 Subject: Parse/AST/HIR - Support Enum::Var(..) and Struct { .. } patters properly --- src/ast/pattern.cpp | 12 +++++++++++ src/ast/pattern.hpp | 10 +++++++--- src/dump_as_rust.cpp | 8 +++++--- src/expand/mod.cpp | 2 ++ src/hir/from_ast.cpp | 33 ++++++++++++++++++++++++++++-- src/hir/pattern.hpp | 11 ++++++++++ src/hir/visitor.cpp | 6 ++++++ src/hir_conv/bind.cpp | 30 ++++++++++++++++++++++++++++ src/hir_typeck/expr.cpp | 52 +++++++++++++++++++++++++++++++++++++++++++++++- src/parse/pattern.cpp | 13 +++++++++--- src/resolve/absolute.cpp | 4 +++- 11 files changed, 168 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/ast/pattern.cpp b/src/ast/pattern.cpp index ca5378e1..9e17abcf 100644 --- a/src/ast/pattern.cpp +++ b/src/ast/pattern.cpp @@ -70,6 +70,9 @@ namespace AST { (Tuple, os << "(" << ent.sub_patterns << ")"; ), + (WildcardStructTuple, + os << ent.path << " (..)"; + ), (StructTuple, os << ent.path << " (" << ent.sub_patterns << ")"; ), @@ -220,6 +223,9 @@ AST::Pattern AST::Pattern::clone() const (Tuple, rv.m_data = Data::make_Tuple({ H::clone_list(e.sub_patterns) }); ), + (WildcardStructTuple, + rv.m_data = Data::make_WildcardStructTuple({ ::AST::Path(e.path) }); + ), (StructTuple, rv.m_data = Data::make_StructTuple({ ::AST::Path(e.path), H::clone_list(e.sub_patterns) }); ), @@ -263,6 +269,9 @@ SERIALISE_TYPE(Pattern::, "Pattern", { (Tuple, s << e.sub_patterns; ), + (WildcardStructTuple, + s << e.path; + ), (StructTuple, s << e.path; s << e.sub_patterns; @@ -304,6 +313,9 @@ SERIALISE_TYPE(Pattern::, "Pattern", { _D(Tuple, s.item( ent.sub_patterns ); ) + _D(WildcardStructTuple, + s.item( ent.path ); + ) _D(StructTuple, s.item( ent.path ); s.item( ent.sub_patterns ); diff --git a/src/ast/pattern.hpp b/src/ast/pattern.hpp index 79d349c2..699ed466 100644 --- a/src/ast/pattern.hpp +++ b/src/ast/pattern.hpp @@ -40,8 +40,9 @@ public: (Ref, struct { bool mut; unique_ptr sub; } ), (Value, struct { Value start; Value end; } ), (Tuple, struct { ::std::vector sub_patterns; } ), + (WildcardStructTuple, struct { Path path; } ), (StructTuple, struct { Path path; ::std::vector sub_patterns; } ), - (Struct, struct { Path path; ::std::vector< ::std::pair< ::std::string, Pattern> > sub_patterns; } ), + (Struct, struct { Path path; ::std::vector< ::std::pair< ::std::string, Pattern> > sub_patterns; bool is_exhaustive; } ), (Slice, struct { ::std::vector leading; ::std::string extra_bind; ::std::vector trailing; } ) ); private: @@ -110,13 +111,16 @@ public: {} struct TagEnumVariant {}; + Pattern(TagEnumVariant, Path path): + m_data( Data::make_WildcardStructTuple( { ::std::move(path) } ) ) + {} Pattern(TagEnumVariant, Path path, ::std::vector sub_patterns): m_data( Data::make_StructTuple( { ::std::move(path), ::std::move(sub_patterns) } ) ) {} struct TagStruct {}; - Pattern(TagStruct, Path path, ::std::vector< ::std::pair< ::std::string,Pattern> > sub_patterns): - m_data( Data::make_Struct( { ::std::move(path), ::std::move(sub_patterns) } ) ) + Pattern(TagStruct, Path path, ::std::vector< ::std::pair< ::std::string,Pattern> > sub_patterns, bool is_exhaustive): + m_data( Data::make_Struct( { ::std::move(path), ::std::move(sub_patterns), is_exhaustive } ) ) {} struct TagSlice {}; diff --git a/src/dump_as_rust.cpp b/src/dump_as_rust.cpp index 4091842a..2d079223 100644 --- a/src/dump_as_rust.cpp +++ b/src/dump_as_rust.cpp @@ -808,15 +808,17 @@ void RustPrinter::print_pattern(const AST::Pattern& p, bool is_refutable) m_os << " ... " << v.end; } ), - (StructTuple, { - const auto& v = p.data().as_StructTuple(); + (WildcardStructTuple, + m_os << v.path << "(..)"; + ), + (StructTuple, m_os << v.path << "("; for(const auto& sp : v.sub_patterns) { print_pattern(sp, is_refutable); m_os << ","; } m_os << ")"; - }), + ), (Struct, { const auto& v = p.data().as_Struct(); m_os << v.path << "("; diff --git a/src/expand/mod.cpp b/src/expand/mod.cpp index c46c7d84..62425f86 100644 --- a/src/expand/mod.cpp +++ b/src/expand/mod.cpp @@ -161,6 +161,8 @@ void Expand_Pattern(bool is_early, ::AST::Crate& crate, LList sub_patterns; for(const auto& sp : e.sub_patterns) @@ -191,7 +218,8 @@ ::HIR::Pattern::Data::make_EnumStruct({ LowerHIR_GenericPath(pat.span(), e.path), nullptr, 0, - mv$(sub_patterns) + mv$(sub_patterns), + e.is_exhaustive }) }; ), @@ -201,7 +229,8 @@ ::HIR::Pattern::Data::make_Struct({ LowerHIR_GenericPath(pat.span(), e.path), nullptr, - mv$(sub_patterns) + mv$(sub_patterns), + e.is_exhaustive }) }; ) diff --git a/src/hir/pattern.hpp b/src/hir/pattern.hpp index fc763f54..c7b0fe7d 100644 --- a/src/hir/pattern.hpp +++ b/src/hir/pattern.hpp @@ -65,10 +65,15 @@ struct Pattern const Struct* binding; ::std::vector sub_patterns; } ), + (StructTupleWildcard, struct { + GenericPath path; + const Struct* binding; + }), (Struct, struct { GenericPath path; const Struct* binding; ::std::vector< ::std::pair< ::std::string, Pattern> > sub_patterns; + bool is_exhaustive; } ), // Refutable (Value, struct { Value val; } ), @@ -79,11 +84,17 @@ struct Pattern unsigned binding_idx; ::std::vector sub_patterns; } ), + (EnumTupleWildcard, struct { + GenericPath path; + const Enum* binding_ptr; + unsigned binding_idx; + } ), (EnumStruct, struct { GenericPath path; const Enum* binding_ptr; unsigned binding_idx; ::std::vector< ::std::pair< ::std::string, Pattern> > sub_patterns; + bool is_exhaustive; } ), (Slice, struct { ::std::vector sub_patterns; diff --git a/src/hir/visitor.cpp b/src/hir/visitor.cpp index 33ac6505..23acf4e4 100644 --- a/src/hir/visitor.cpp +++ b/src/hir/visitor.cpp @@ -300,6 +300,9 @@ void ::HIR::Visitor::visit_pattern(::HIR::Pattern& pat) for(auto& sp : e.sub_patterns) this->visit_pattern(sp); ), + (StructTupleWildcard, + this->visit_generic_path(e.path, ::HIR::Visitor::PathContext::TYPE); + ), (StructTuple, this->visit_generic_path(e.path, ::HIR::Visitor::PathContext::TYPE); for(auto& sp : e.sub_patterns) @@ -318,6 +321,9 @@ void ::HIR::Visitor::visit_pattern(::HIR::Pattern& pat) this->visit_pattern_val(e.start); this->visit_pattern_val(e.end); ), + (EnumTupleWildcard, + this->visit_generic_path(e.path, ::HIR::Visitor::PathContext::TYPE); + ), (EnumTuple, this->visit_generic_path(e.path, ::HIR::Visitor::PathContext::TYPE); for(auto& sp : e.sub_patterns) diff --git a/src/hir_conv/bind.cpp b/src/hir_conv/bind.cpp index 948a3d75..97f52cc9 100644 --- a/src/hir_conv/bind.cpp +++ b/src/hir_conv/bind.cpp @@ -122,6 +122,18 @@ namespace { ERROR(sp, E0000, "Struct tuple pattern on non-tuple struct " << e.path); } + fix_type_params(sp, str.m_params, e.path.m_params); + e.binding = &str; + ), + (StructTupleWildcard, + const auto& str = *reinterpret_cast< const ::HIR::Struct*>( get_type_pointer(sp, m_crate, e.path.m_path, Target::Struct) ); + TU_IFLET(::HIR::Struct::Data, str.m_data, Tuple, _, + // All good + ) + else { + ERROR(sp, E0000, "Struct tuple pattern on non-tuple struct " << e.path); + } + fix_type_params(sp, str.m_params, e.path.m_params); e.binding = &str; ), @@ -154,6 +166,24 @@ namespace { e.binding_ptr = &enm; e.binding_idx = idx; ), + (EnumTupleWildcard, + const auto& enm = *reinterpret_cast< const ::HIR::Enum*>( get_type_pointer(sp, m_crate, e.path.m_path, Target::EnumVariant) ); + const auto& des_name = e.path.m_path.m_components.back(); + unsigned int idx = ::std::find_if( enm.m_variants.begin(), enm.m_variants.end(), [&](const auto& x) { return x.first == des_name; }) - enm.m_variants.begin(); + if( idx == enm.m_variants.size() ) { + ERROR(sp, E0000, "Couldn't find enum variant " << e.path); + } + const auto& var = enm.m_variants[idx].second; + TU_IFLET(::HIR::Enum::Variant, var, Tuple, _, + // All good + ) + else { + ERROR(sp, E0000, "Enum tuple pattern on non-tuple variant " << e.path); + } + fix_type_params(sp, enm.m_params, e.path.m_params); + e.binding_ptr = &enm; + e.binding_idx = idx; + ), (EnumStruct, const auto& enm = *reinterpret_cast< const ::HIR::Enum*>( get_type_pointer(sp, m_crate, e.path.m_path, Target::EnumVariant) ); const auto& des_name = e.path.m_path.m_components.back(); diff --git a/src/hir_typeck/expr.cpp b/src/hir_typeck/expr.cpp index 18937155..e77c27a6 100644 --- a/src/hir_typeck/expr.cpp +++ b/src/hir_typeck/expr.cpp @@ -378,6 +378,28 @@ namespace { ) ) ), + (StructTupleWildcard, + this->add_ivars_params( e.path.m_params ); + if( type.m_data.is_Infer() ) { + type.m_data = ::HIR::TypeRef::Data::make_Path( {e.path.clone(), ::HIR::TypeRef::TypePathBinding(e.binding)} ); + } + assert(e.binding); + const auto& str = *e.binding; + // - assert check from earlier pass + assert( str.m_data.is_Tuple() ); + + TU_MATCH_DEF(::HIR::TypeRef::Data, (type.m_data), (te), + ( + // TODO: Type mismatch + ), + (Infer, throw ""; ), + (Path, + if( ! te.binding.is_Struct() || te.binding.as_Struct() != &str ) { + ERROR(sp, E0000, "Type mismatch in struct pattern - " << type << " is not " << e.path); + } + ) + ) + ), (Struct, this->add_ivars_params( e.path.m_params ); if( type.m_data.is_Infer() ) { @@ -453,13 +475,37 @@ namespace { this->add_binding(e.sub_patterns[i], var_ty); } else { - // SAFE: Can't have _ as monomorphise_type_needed checks for that + // SAFE: Can't have a _ (monomorphise_type_needed checks for that) this->add_binding(e.sub_patterns[i], const_cast< ::HIR::TypeRef&>(tup_var[i])); } } ) ) ), + (EnumTupleWildcard, + this->add_ivars_params( e.path.m_params ); + if( type.m_data.is_Infer() ) { + auto path = e.path.clone(); + path.m_path.m_components.pop_back(); + type.m_data = ::HIR::TypeRef::Data::make_Path( {mv$(path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)} ); + } + assert(e.binding_ptr); + const auto& enm = *e.binding_ptr; + const auto& var = enm.m_variants[e.binding_idx].second; + assert(var.is_Tuple()); + + TU_MATCH_DEF(::HIR::TypeRef::Data, (type.m_data), (te), + ( + // TODO: Type mismatch + ), + (Infer, throw ""; ), + (Path, + if( ! te.binding.is_Enum() || te.binding.as_Enum() != &enm ) { + ERROR(sp, E0000, "Type mismatch in enum pattern - " << type << " is not " << e.path); + } + ) + ) + ), (EnumStruct, this->add_ivars_params( e.path.m_params ); if( type.m_data.is_Infer() ) { @@ -619,6 +665,8 @@ namespace { ) ) ), + (StructTupleWildcard, + ), (Struct, if( ty.m_data.is_Infer() ) { //TODO: Does this lead to issues with generic parameters? @@ -651,6 +699,8 @@ namespace { ) ) ), + (EnumTupleWildcard, + ), (EnumStruct, if( ty.m_data.is_Infer() ) { TODO(sp, "EnumStruct - infer"); diff --git a/src/parse/pattern.cpp b/src/parse/pattern.cpp index e67647bd..5d13cba6 100644 --- a/src/parse/pattern.cpp +++ b/src/parse/pattern.cpp @@ -171,8 +171,8 @@ AST::Pattern Parse_PatternReal1(TokenStream& lex, bool is_refutable) { case TOK_UNDERSCORE: return AST::Pattern( ); - case TOK_DOUBLE_DOT: - return AST::Pattern( AST::Pattern::TagWildcard() ); + //case TOK_DOUBLE_DOT: + // return AST::Pattern( AST::Pattern::TagWildcard() ); case TOK_RWORD_BOX: return AST::Pattern( AST::Pattern::TagBox(), Parse_Pattern(lex, is_refutable) ); case TOK_DOUBLE_AMP: @@ -240,6 +240,11 @@ AST::Pattern Parse_PatternReal_Path(TokenStream& lex, AST::Path path, bool is_re switch( GET_TOK(tok, lex) ) { case TOK_PAREN_OPEN: + if( LOOK_AHEAD(lex) == TOK_DOUBLE_DOT ) { + GET_TOK(tok, lex); + GET_CHECK_TOK(tok, lex, TOK_PAREN_CLOSE); + return AST::Pattern( AST::Pattern::TagEnumVariant(), ::std::move(path) ); + } return AST::Pattern( AST::Pattern::TagEnumVariant(), ::std::move(path), Parse_PatternList(lex, is_refutable) ); case TOK_BRACE_OPEN: return Parse_PatternStruct(lex, ::std::move(path), is_refutable); @@ -331,6 +336,7 @@ AST::Pattern Parse_PatternStruct(TokenStream& lex, AST::Path path, bool is_refut TRACE_FUNCTION; Token tok; + bool is_exhaustive = true; ::std::vector< ::std::pair< ::std::string, AST::Pattern> > subpats; do { GET_TOK(tok, lex); @@ -338,6 +344,7 @@ AST::Pattern Parse_PatternStruct(TokenStream& lex, AST::Path path, bool is_refut if( tok.type() == TOK_BRACE_CLOSE ) break; if( tok.type() == TOK_DOUBLE_DOT ) { + is_exhaustive = false; GET_TOK(tok, lex); break; } @@ -391,6 +398,6 @@ AST::Pattern Parse_PatternStruct(TokenStream& lex, AST::Path path, bool is_refut } while( GET_TOK(tok, lex) == TOK_COMMA ); CHECK_TOK(tok, TOK_BRACE_CLOSE); - return AST::Pattern(AST::Pattern::TagStruct(), ::std::move(path), ::std::move(subpats)); + return AST::Pattern(AST::Pattern::TagStruct(), ::std::move(path), ::std::move(subpats), is_exhaustive); } diff --git a/src/resolve/absolute.cpp b/src/resolve/absolute.cpp index 5137aca6..05fa7523 100644 --- a/src/resolve/absolute.cpp +++ b/src/resolve/absolute.cpp @@ -1082,8 +1082,10 @@ void Resolve_Absolute_Pattern(Context& context, bool allow_refutable, ::AST::Pa for(auto& sp : e.sub_patterns) Resolve_Absolute_Pattern(context, allow_refutable, sp); ), + (WildcardStructTuple, + Resolve_Absolute_Path(context, pat.span(), Context::LookupMode::Pattern, e.path); + ), (StructTuple, - // TODO: This isn't a type lookup, it's a pattern lookup (allowing imported enum variants, e.g. `Some(_)` to work) Resolve_Absolute_Path(context, pat.span(), Context::LookupMode::Pattern, e.path); for(auto& sp : e.sub_patterns) Resolve_Absolute_Pattern(context, allow_refutable, sp); -- cgit v1.2.3