From c971a6fa8375598ecf9c99ee6b086e8cf957f568 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 29 Jul 2018 12:47:44 +0100 Subject: All - Initial work on supporting 1.29 as a target version --- Makefile | 1 + rust-nightly-date | 2 +- src/ast/ast.hpp | 5 +++ src/ast/attrs.hpp | 1 + src/ast/path.hpp | 4 ++ src/expand/assert.cpp | 89 +++++++++++++++++++++++++++++++++++++++++++ src/expand/file_line.cpp | 9 +++++ src/expand/lang_item.cpp | 15 +++++++- src/expand/mod.cpp | 19 ++++++++- src/hir/from_ast.cpp | 6 ++- src/include/main_bindings.hpp | 1 + src/macro_rules/eval.cpp | 4 +- src/macro_rules/parse.cpp | 14 +++---- src/main.cpp | 2 + src/parse/eTokenType.enum.h | 1 + src/parse/expr.cpp | 9 ++++- src/parse/lex.cpp | 8 +++- src/parse/pattern.cpp | 5 ++- src/parse/root.cpp | 73 ++++++++++++++++++++++++++++++----- src/parse/token.cpp | 11 +++--- src/parse/tokenstream.hpp | 2 + 21 files changed, 251 insertions(+), 30 deletions(-) create mode 100644 src/expand/assert.cpp diff --git a/Makefile b/Makefile index 256bb6c6..5b21f186 100644 --- a/Makefile +++ b/Makefile @@ -89,6 +89,7 @@ OBJ += expand/env.o OBJ += expand/test.o OBJ += expand/rustc_diagnostics.o OBJ += expand/proc_macro.o +OBJ += expand/assert.o OBJ += expand/test_harness.o OBJ += macro_rules/mod.o macro_rules/eval.o macro_rules/parse.o OBJ += resolve/use.o resolve/index.o resolve/absolute.o diff --git a/rust-nightly-date b/rust-nightly-date index 69416130..1242c4a4 100644 --- a/rust-nightly-date +++ b/rust-nightly-date @@ -1 +1 @@ -2017-07-14 +2018-07-09 diff --git a/src/ast/ast.hpp b/src/ast/ast.hpp index 0a43cc71..19f0c66b 100644 --- a/src/ast/ast.hpp +++ b/src/ast/ast.hpp @@ -8,6 +8,9 @@ #ifndef AST_HPP_INCLUDED #define AST_HPP_INCLUDED +#define TARGETVER_1_19 true +#define TARGETVER_1_29 true + #include #include #include @@ -44,6 +47,8 @@ enum eItemType { ITEM_TRAIT, ITEM_STRUCT, + ITEM_ENUM, + ITEM_UNION, ITEM_FN, ITEM_STATIC, }; diff --git a/src/ast/attrs.hpp b/src/ast/attrs.hpp index 1926e96a..860e75ee 100644 --- a/src/ast/attrs.hpp +++ b/src/ast/attrs.hpp @@ -77,6 +77,7 @@ class Attribute ::std::string m_name; AttributeData m_data; mutable bool m_is_used; + // TODO: Parse as a TT then expand? public: Attribute(Span sp, ::std::string name): m_span(::std::move(sp)), diff --git a/src/ast/path.hpp b/src/ast/path.hpp index c2d13d73..2693a070 100644 --- a/src/ast/path.hpp +++ b/src/ast/path.hpp @@ -271,6 +271,10 @@ public: return Path(*this) += x; } Path& operator+=(const Path& x); + Path& operator+=(PathNode pn) { + this->nodes().push_back( mv$(pn) ); + return *this; + } void append(PathNode node) { assert( !m_class.is_Invalid() ); diff --git a/src/expand/assert.cpp b/src/expand/assert.cpp new file mode 100644 index 00000000..1c057935 --- /dev/null +++ b/src/expand/assert.cpp @@ -0,0 +1,89 @@ +/* + * MRustC - Rust Compiler + * - By John Hodge (Mutabah/thePowersGang) + * + * expand/assert.cpp + * - assert! built-in macro (1.29) + */ +#include +#include // for Expand_BareExpr +#include +#include "../parse/ttstream.hpp" +#include "../parse/common.hpp" +#include "../parse/parseerror.hpp" + +class CExpander_assert: + public ExpandProcMacro +{ + ::std::unique_ptr expand(const Span& sp, const ::AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override + { + Token tok; + + auto lex = TTStream(sp, tt); + lex.parse_state().module = &mod; + if( ident != "" ) + ERROR(sp, E0000, "format_args! doesn't take an ident"); + + // assertion condition + auto n = Parse_Expr0(lex); + ASSERT_BUG(sp, n, "No expression returned"); + + ::std::vector toks; + + toks.push_back( Token(TOK_RWORD_IF) ); + + GET_TOK(tok, lex); + if( tok == TOK_COMMA ) + { + toks.push_back( Token(InterpolatedFragment(InterpolatedFragment::EXPR, n.release())) ); + toks.push_back( Token(TOK_BRACE_OPEN) ); + // User-provided message + toks.push_back( Token(TOK_IDENT, "panic") ); + toks.push_back( Token(TOK_EXCLAM) ); + toks.push_back( Token(TOK_PAREN_OPEN) ); + while(lex.lookahead(0) != TOK_EOF ) + { + toks.push_back( Token(InterpolatedFragment(InterpolatedFragment::EXPR, Parse_Expr0(lex).release())) ); + if( lex.lookahead(0) != TOK_COMMA ) + break; + GET_CHECK_TOK(tok, lex, TOK_COMMA); + toks.push_back( Token(TOK_COMMA) ); + } + GET_CHECK_TOK(tok, lex, TOK_EOF); + toks.push_back( Token(TOK_PAREN_CLOSE) ); + } + else if( tok == TOK_EOF ) + { + ::std::stringstream ss; + ss << "assertion failed: "; + n->print(ss); + + toks.push_back( Token(InterpolatedFragment(InterpolatedFragment::EXPR, n.release())) ); + + toks.push_back( Token(TOK_BRACE_OPEN) ); + // Auto-generated message + toks.push_back( Token(TOK_IDENT, "panic") ); + toks.push_back( Token(TOK_EXCLAM) ); + toks.push_back( Token(TOK_PAREN_OPEN) ); + toks.push_back( Token(TOK_STRING, ss.str()) ); + toks.push_back( Token(TOK_PAREN_CLOSE) ); + } + else + { + throw ParseError::Unexpected(lex, tok, {TOK_COMMA, TOK_EOF}); + } + + toks.push_back( Token(TOK_BRACE_CLOSE) ); + + return box$( TTStreamO(sp, TokenTree(Ident::Hygiene::new_scope(), mv$(toks))) ); + } +}; + +void Expand_init_assert() +{ + if( TARGETVER_1_29 ) + { + Register_Synext_Macro("assert", ::std::unique_ptr(new CExpander_assert)); + } +} + diff --git a/src/expand/file_line.cpp b/src/expand/file_line.cpp index 7a827ccf..2bf85ffd 100644 --- a/src/expand/file_line.cpp +++ b/src/expand/file_line.cpp @@ -46,6 +46,14 @@ class CExpanderColumn: return box$( TTStreamO(sp, TokenTree(Token((uint64_t)get_top_span(sp).start_ofs, CORETYPE_U32))) ); } }; +class CExpanderUnstableColumn: + public ExpandProcMacro +{ + ::std::unique_ptr expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override + { + return box$( TTStreamO(sp, TokenTree(Token((uint64_t)get_top_span(sp).start_ofs, CORETYPE_U32))) ); + } +}; class CExpanderModulePath: public ExpandProcMacro @@ -65,5 +73,6 @@ class CExpanderModulePath: STATIC_MACRO("file", CExpanderFile); STATIC_MACRO("line", CExpanderLine); STATIC_MACRO("column", CExpanderColumn); +STATIC_MACRO("__rust_unstable_column", CExpanderUnstableColumn); STATIC_MACRO("module_path", CExpanderModulePath); diff --git a/src/expand/lang_item.cpp b/src/expand/lang_item.cpp index 789ad88e..62527ac9 100644 --- a/src/expand/lang_item.cpp +++ b/src/expand/lang_item.cpp @@ -30,6 +30,7 @@ void handle_lang_item(const Span& sp, AST::Crate& crate, const AST::Path& path, else if( name == "copy" ) { DEBUG("Bind 'copy' to " << path); } + else if( TARGETVER_1_29 && name == "clone" ) {} // - Trait // ops traits else if( name == "drop" ) { DEBUG("Bind '"< Expand_Macro( +::std::unique_ptr Expand_Macro_Inner( const ::AST::Crate& crate, LList modstack, ::AST::Module& mod, Span mi_span, const ::std::string& name, const ::std::string& input_ident, TokenTree& input_tt ) @@ -144,6 +150,17 @@ void Expand_Attrs(::AST::AttributeList& attrs, AttrStage stage, ::AST::Crate& c // Error - Unknown macro name ERROR(mi_span, E0000, "Unknown macro '" << name << "'"); } +::std::unique_ptr Expand_Macro( + const ::AST::Crate& crate, LList modstack, ::AST::Module& mod, + Span mi_span, const ::std::string& name, const ::std::string& input_ident, TokenTree& input_tt + ) +{ + auto rv = Expand_Macro_Inner(crate, modstack, mod, mi_span, name, input_ident, input_tt); + assert(rv); + rv->parse_state().module = &mod; + rv->parse_state().crate = &crate; + return rv; +} ::std::unique_ptr Expand_Macro(const ::AST::Crate& crate, LList modstack, ::AST::Module& mod, ::AST::MacroInvocation& mi) { return Expand_Macro(crate, modstack, mod, mi.span(), mi.name(), mi.input_ident(), mi.input_tt()); diff --git a/src/hir/from_ast.cpp b/src/hir/from_ast.cpp index 7f25a42b..5dbf9c03 100644 --- a/src/hir/from_ast.cpp +++ b/src/hir/from_ast.cpp @@ -901,6 +901,9 @@ namespace { else if( repr_str == "simd" ) { is_simd = true; } + else if( repr_str == "transparent" ) { + // TODO: Mark so the C backend knows that it's supposed to be transparent + } else { TODO(a.span(), "Handle struct repr '" << repr_str << "'"); } @@ -1247,7 +1250,8 @@ namespace { else TU_IFLET(::HIR::TypeRef::Data, arg_self_ty.m_data, Path, e, // Box - Compare with `owned_box` lang item TU_IFLET(::HIR::Path::Data, e.path.m_data, Generic, pe, - if( pe.m_path == g_crate_ptr->get_lang_item_path(sp, "owned_box") ) + auto p = g_crate_ptr->get_lang_item_path_opt("owned_box"); + if( pe.m_path == p ) { if( pe.m_params.m_types.size() == 1 && pe.m_params.m_types[0] == self_type ) { diff --git a/src/include/main_bindings.hpp b/src/include/main_bindings.hpp index c9e573d4..8085eb4c 100644 --- a/src/include/main_bindings.hpp +++ b/src/include/main_bindings.hpp @@ -18,6 +18,7 @@ namespace AST { /// Parse a crate from the given file extern AST::Crate Parse_Crate(::std::string mainfile); +extern void Expand_Init(); extern void Expand(::AST::Crate& crate); extern void Expand_TestHarness(::AST::Crate& crate); extern void Expand_ProcMacro(::AST::Crate& crate); diff --git a/src/macro_rules/eval.cpp b/src/macro_rules/eval.cpp index a393ba46..cda51ebe 100644 --- a/src/macro_rules/eval.cpp +++ b/src/macro_rules/eval.cpp @@ -1189,7 +1189,8 @@ namespace } if(lex.consume_if(TOK_AT)) continue; - if( lex.consume_if(TOK_TRIPLE_DOT) ) + // ... or ..= + if( lex.consume_if(TOK_TRIPLE_DOT) || lex.consume_if(TOK_DOUBLE_DOT_EQUAL) ) { switch(lex.next()) { @@ -1491,6 +1492,7 @@ namespace case TOK_DOUBLE_AMP: case TOK_DOUBLE_PIPE: case TOK_DOUBLE_DOT: + case TOK_DOUBLE_DOT_EQUAL: case TOK_TRIPLE_DOT: lex.consume(); break; diff --git a/src/macro_rules/parse.cpp b/src/macro_rules/parse.cpp index b3b1014e..00cf7cf7 100644 --- a/src/macro_rules/parse.cpp +++ b/src/macro_rules/parse.cpp @@ -49,8 +49,7 @@ public: switch( GET_TOK(tok, lex) ) { // TODO: Allow any reserved word - case TOK_RWORD_TYPE: - case TOK_RWORD_PUB: + case TOK_RWORD_PUB ... TOK_RWORD_UNSIZED: case TOK_IDENT: { ::std::string name = tok.type() == TOK_IDENT ? mv$(tok.str()) : FMT(tok); GET_CHECK_TOK(tok, lex, TOK_COLON); @@ -200,10 +199,13 @@ public: default: throw ParseError::Unexpected(lex, tok); } - + } + else if( tok.type() == TOK_RWORD_CRATE ) + { + ret.push_back( MacroExpansionEnt( (1<<30) | 0 ) ); } //else if( tok.type() == TOK_IDENT || tok_is_rword(tok.type()) ) - else if( tok.type() == TOK_IDENT || tok.type() == TOK_RWORD_TYPE || tok.type() == TOK_RWORD_PUB ) + else if( tok.type() == TOK_IDENT || tok.type() >= TOK_RWORD_PUB ) { // Look up the named parameter in the list of param names for this arm auto name = tok.type() == TOK_IDENT ? tok.str() : FMT(tok); @@ -222,10 +224,6 @@ public: } ret.push_back( MacroExpansionEnt(idx) ); } - else if( tok.type() == TOK_RWORD_CRATE ) - { - ret.push_back( MacroExpansionEnt( (1<<30) | 0 ) ); - } else { throw ParseError::Unexpected(lex, tok); diff --git a/src/main.cpp b/src/main.cpp index 8f2740fc..85afcb33 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -221,6 +221,8 @@ int main(int argc, char *argv[]) Cfg_SetFlag("test"); } + Expand_Init(); + try { // Parse the crate into AST diff --git a/src/parse/eTokenType.enum.h b/src/parse/eTokenType.enum.h index 5104142b..4408c45a 100644 --- a/src/parse/eTokenType.enum.h +++ b/src/parse/eTokenType.enum.h @@ -58,6 +58,7 @@ _(TOK_SLASH) _(TOK_DOT) _(TOK_DOUBLE_DOT) +_(TOK_DOUBLE_DOT_EQUAL) _(TOK_TRIPLE_DOT) _(TOK_EQUAL) diff --git a/src/parse/expr.cpp b/src/parse/expr.cpp index 5194e1d8..e5d7981d 100644 --- a/src/parse/expr.cpp +++ b/src/parse/expr.cpp @@ -706,7 +706,7 @@ ExprNodeP Parse_Expr1_1(TokenStream& lex) ExprNodeP left, right; // Inclusive range to a value - if( GET_TOK(tok, lex) == TOK_TRIPLE_DOT ) { + if( GET_TOK(tok, lex) == TOK_TRIPLE_DOT || (TARGETVER_1_29 && tok.type() == TOK_DOUBLE_DOT_EQUAL) ) { right = next(lex); return NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::RANGE_INC, nullptr, mv$(right) ); } @@ -746,6 +746,13 @@ LEFTASSOC(Parse_Expr1_2, Parse_Expr1_5, case TOK_TRIPLE_DOT: rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::RANGE_INC, mv$(rv), next(lex) ); break; + case TOK_DOUBLE_DOT_EQUAL: + if( TARGETVER_1_29 ) + { + rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::RANGE_INC, mv$(rv), next(lex) ); + break; + } + // Fall through ) // 1: Bool OR LEFTASSOC(Parse_Expr1_5, Parse_Expr2, diff --git a/src/parse/lex.cpp b/src/parse/lex.cpp index 8376eeee..0b145379 100644 --- a/src/parse/lex.cpp +++ b/src/parse/lex.cpp @@ -83,8 +83,10 @@ static const struct { TOKENT("-=", TOK_DASH_EQUAL), TOKENT("->", TOK_THINARROW), TOKENT(".", TOK_DOT), + // NOTE: These have special handling when following numbers TOKENT("..", TOK_DOUBLE_DOT), TOKENT("...",TOK_TRIPLE_DOT), + TOKENT("..=",TOK_DOUBLE_DOT_EQUAL), TOKENT("/" , TOK_SLASH), TOKENT("/*", BLOCKCOMMENT), TOKENT("//", LINECOMMENT), @@ -402,9 +404,13 @@ Token Lexer::getTokenInt() // Double/Triple Dot if( ch == '.' ) { - if( this->getc() == '.') { + ch = this->getc(); + if( ch == '.') { this->m_next_tokens.push_back(TOK_TRIPLE_DOT); } + else if( ch == '=') { + this->m_next_tokens.push_back(TOK_DOUBLE_DOT_EQUAL); + } else { this->ungetc(); this->m_next_tokens.push_back(TOK_DOUBLE_DOT); diff --git a/src/parse/pattern.cpp b/src/parse/pattern.cpp index f6d61728..239bac80 100644 --- a/src/parse/pattern.cpp +++ b/src/parse/pattern.cpp @@ -113,6 +113,7 @@ AST::Pattern Parse_Pattern(TokenStream& lex, bool is_refutable) break; // Known value `IDENT ...` case TOK_TRIPLE_DOT: + case TOK_DOUBLE_DOT_EQUAL: break; // Known binding `ident @` case TOK_AT: @@ -156,7 +157,9 @@ AST::Pattern Parse_PatternReal(TokenStream& lex, bool is_refutable) } auto ps = lex.start_span(); AST::Pattern ret = Parse_PatternReal1(lex, is_refutable); - if( GET_TOK(tok, lex) == TOK_TRIPLE_DOT ) + if( (GET_TOK(tok, lex) == TOK_TRIPLE_DOT) + || (TARGETVER_1_29 && tok.type() == TOK_DOUBLE_DOT_EQUAL) + ) { if( !ret.data().is_Value() ) throw ParseError::Generic(lex, "Using '...' with a non-value on left"); diff --git a/src/parse/root.cpp b/src/parse/root.cpp index 68ad570b..ef1fb439 100644 --- a/src/parse/root.cpp +++ b/src/parse/root.cpp @@ -18,6 +18,7 @@ #include // check_cfg - for `mod nonexistant;` #include // Used by directory path #include "lex.hpp" // New file lexer +#include #include template @@ -649,9 +650,7 @@ AST::Trait Parse_TraitDef(TokenStream& lex, const AST::AttributeList& meta_items // TODO: Just add these as `where Self: ` (would that break typecheck?) do { if( GET_TOK(tok, lex) == TOK_LIFETIME ) { - // TODO: Need a better way of indiciating 'static than just an invalid path - ASSERT_BUG(lex.point_span(), tok.str() == "static", "TODO: Support lifetimes other than 'static in trait bounds"); - supertraits.push_back( make_spanned( Span(tok.get_pos()), Type_TraitPath{ {}, AST::Path() } ) ); + params.add_bound(::AST::GenericBound::make_TypeLifetime({ TypeRef(lex.point_span(), "Self"), ::AST::LifetimeRef(lex.get_ident(tok)) })); } else if( tok.type() == TOK_BRACE_OPEN ) { break; @@ -988,14 +987,26 @@ AST::Attribute Parse_MetaItem(TokenStream& lex) { TRACE_FUNCTION; Token tok; - GET_TOK(tok, lex); - if( tok.type() == TOK_INTERPOLATED_META ) { + if( lex.lookahead(0) == TOK_INTERPOLATED_META ) { + GET_TOK(tok, lex); return mv$(tok.frag_meta()); } auto ps = lex.start_span(); - CHECK_TOK(tok, TOK_IDENT); + GET_TOK(tok, lex); + + switch(tok.type()) + { + case TOK_IDENT: + break; + case TOK_INTEGER: + if( TARGETVER_1_29 ) + return AST::Attribute(lex.end_span(ps), "", tok.to_str()); + default: + throw ParseError::Unexpected(lex, tok, {TOK_IDENT, TOK_INTEGER}); + } + ::std::string name = mv$(tok.str()); switch(GET_TOK(tok, lex)) { @@ -1006,6 +1017,10 @@ AST::Attribute Parse_MetaItem(TokenStream& lex) return AST::Attribute(lex.end_span(ps), name, tok.str()); case TOK_INTERPOLATED_EXPR: { auto n = tok.take_frag_node(); + void Expand_BareExpr(const AST::Crate& , const AST::Module&, ::std::unique_ptr& n); + assert( lex.parse_state().crate ); + assert( lex.parse_state().module ); + Expand_BareExpr(*lex.parse_state().crate, *lex.parse_state().module, n); if( auto* v = dynamic_cast<::AST::ExprNode_String*>(&*n) ) { return AST::Attribute(lex.end_span(ps), name, mv$(v->m_value)); @@ -1013,9 +1028,15 @@ AST::Attribute Parse_MetaItem(TokenStream& lex) else { // - Force an error. - CHECK_TOK(tok, TOK_STRING); + throw ParseError::Unexpected(lex, Token(InterpolatedFragment(InterpolatedFragment::EXPR, n.release())), TOK_STRING); } break; } + case TOK_INTEGER: + if( TARGETVER_1_29 ) + return AST::Attribute(lex.end_span(ps), name, tok.to_str()); + case TOK_IDENT: + if( TARGETVER_1_29 ) + return AST::Attribute(lex.end_span(ps), name, tok.to_str()); default: // - Force an error. CHECK_TOK(tok, TOK_STRING); @@ -1311,8 +1332,19 @@ void Parse_Use_Set(TokenStream& lex, const ProtoSpan& ps, const AST::Path& base_ break ; } else { - CHECK_TOK(tok, TOK_IDENT); - path = base_path + AST::PathNode(tok.str(), {}); + path = ::AST::Path(base_path); + + while(1) + { + CHECK_TOK(tok, TOK_IDENT); + path += AST::PathNode(tok.str(), {}); + if( !TARGETVER_1_29 ) + break; + if( lex.lookahead(0) != TOK_DOUBLE_COLON ) + break; + GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON); + GET_TOK(tok, lex); + } name = mv$(tok.str()); } @@ -1706,6 +1738,19 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv) } return ::AST::Named< ::AST::Item> { "", mv$(impl), false }; } + // `unsafe auto trait` + case TOK_IDENT: + if( TARGETVER_1_29 && tok.str() == "auto" ) { + GET_CHECK_TOK(tok, lex, TOK_RWORD_TRAIT); + GET_CHECK_TOK(tok, lex, TOK_IDENT); + item_name = mv$(tok.str()); + auto tr = Parse_TraitDef(lex, meta_items); + tr.set_is_unsafe(); + tr.set_is_marker(); + item_data = ::AST::Item( ::std::move(tr) ); + break; + } + //goto default; default: throw ParseError::Unexpected(lex, tok, {TOK_RWORD_FN, TOK_RWORD_TRAIT, TOK_RWORD_IMPL}); } @@ -1742,6 +1787,15 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv) item_name = mv$(tok.str()); item_data = ::AST::Item( Parse_Union(lex, meta_items) ); } + // `auto trait` + else if( TARGETVER_1_29 && tok.str() == "auto" ) { + GET_CHECK_TOK(tok, lex, TOK_RWORD_TRAIT); + GET_CHECK_TOK(tok, lex, TOK_IDENT); + item_name = mv$(tok.str()); + auto tr = Parse_TraitDef(lex, meta_items); + tr.set_is_marker(); + item_data = ::AST::Item( ::std::move(tr) ); + } else { throw ParseError::Unexpected(lex, tok); } @@ -1959,6 +2013,7 @@ AST::Crate Parse_Crate(::std::string mainfile) crate.root_module().m_file_info.path = mainpath; crate.root_module().m_file_info.controls_dir = true; + lex.parse_state().crate = &crate; Parse_ModRoot(lex, crate.root_module(), crate.m_attrs); return crate; diff --git a/src/parse/token.cpp b/src/parse/token.cpp index 115df135..f1471453 100644 --- a/src/parse/token.cpp +++ b/src/parse/token.cpp @@ -359,8 +359,9 @@ struct EscapedString { case TOK_SLASH: return "/"; case TOK_DOT: return "."; - case TOK_DOUBLE_DOT: return "..."; - case TOK_TRIPLE_DOT: return ".."; + case TOK_DOUBLE_DOT: return ".."; + case TOK_DOUBLE_DOT_EQUAL: return "..="; + case TOK_TRIPLE_DOT: return "..."; case TOK_EQUAL: return "="; case TOK_PLUS_EQUAL: return "+="; @@ -484,13 +485,13 @@ struct EscapedString { os << ":" << *reinterpret_cast(tok.m_data.as_Fragment()); break; case TOK_INTERPOLATED_EXPR: - os << ":" << *reinterpret_cast(tok.m_data.as_Fragment()); + os << ":" << *reinterpret_cast(tok.m_data.as_Fragment()); break; case TOK_INTERPOLATED_STMT: - os << ":" << *reinterpret_cast(tok.m_data.as_Fragment()); + os << ":" << *reinterpret_cast(tok.m_data.as_Fragment()); break; case TOK_INTERPOLATED_BLOCK: - os << ":" << *reinterpret_cast(tok.m_data.as_Fragment()); + os << ":" << *reinterpret_cast(tok.m_data.as_Fragment()); break; case TOK_INTERPOLATED_META: os << ":" << *reinterpret_cast(tok.m_data.as_Fragment()); diff --git a/src/parse/tokenstream.hpp b/src/parse/tokenstream.hpp index a9d325c2..25b6a3c1 100644 --- a/src/parse/tokenstream.hpp +++ b/src/parse/tokenstream.hpp @@ -16,6 +16,7 @@ namespace AST { class Module; + class Crate; class AttributeList; } @@ -27,6 +28,7 @@ struct ParseState // A debugging hook that disables expansion of macros bool no_expand_macros = false; + const ::AST::Crate* crate = nullptr; ::AST::Module* module = nullptr; ::AST::AttributeList* parent_attrs = nullptr; -- cgit v1.2.3 From a88d64cbbaeaeb2725259f318f7758ae7a7a91b0 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Wed, 1 Aug 2018 18:21:01 +0800 Subject: HIR - Conversion and typecheck fixes for 1.29 --- src/ast/ast.hpp | 3 +- src/hir/dump.cpp | 33 ++++++++++++++++ src/hir/from_ast.cpp | 15 +++++++ src/hir/hir.hpp | 2 + src/hir/visitor.cpp | 11 ++++-- src/hir/visitor.hpp | 3 +- src/hir_conv/constant_evaluation.cpp | 76 ++++++++++++++++++++++++++++-------- src/hir_typeck/expr_cs.cpp | 8 ++-- src/hir_typeck/helpers.cpp | 20 +++++++++- src/hir_typeck/outer.cpp | 35 +++++++++++++---- src/hir_typeck/static.cpp | 14 +++++++ src/include/target_version.hpp | 11 ++++++ 12 files changed, 196 insertions(+), 35 deletions(-) create mode 100644 src/include/target_version.hpp diff --git a/src/ast/ast.hpp b/src/ast/ast.hpp index 19f0c66b..f78d559f 100644 --- a/src/ast/ast.hpp +++ b/src/ast/ast.hpp @@ -8,8 +8,7 @@ #ifndef AST_HPP_INCLUDED #define AST_HPP_INCLUDED -#define TARGETVER_1_19 true -#define TARGETVER_1_29 true +#include #include #include diff --git a/src/hir/dump.cpp b/src/hir/dump.cpp index 874a80a7..e607925e 100644 --- a/src/hir/dump.cpp +++ b/src/hir/dump.cpp @@ -89,13 +89,46 @@ namespace { void visit_trait(::HIR::ItemPath p, ::HIR::Trait& item) override { m_os << indent() << "trait " << p.get_name() << item.m_params.fmt_args() << "\n"; + if( ! item.m_parent_traits.empty() ) + { + m_os << indent() << " " << ": "; + bool is_first = true; + for(auto& bound : item.m_parent_traits) + { + if( !is_first ) + m_os << indent() << " " << "+ "; + m_os << bound << "\n"; + is_first = false; + } + } if( ! item.m_params.m_bounds.empty() ) { m_os << indent() << " " << item.m_params.fmt_bounds() << "\n"; } m_os << indent() << "{\n"; inc_indent(); + + for(auto& i : item.m_types) + { + m_os << indent() << "type " << i.first; + if( ! i.second.m_trait_bounds.empty() ) + { + m_os << ": "; + bool is_first = true; + for(auto& bound : i.second.m_trait_bounds) + { + if( !is_first ) + m_os << " + "; + m_os << bound; + is_first = false; + } + } + //this->visit_type(i.second.m_default); + m_os << ";\n"; + } + ::HIR::Visitor::visit_trait(p, item); + dec_indent(); m_os << indent() << "}\n"; } diff --git a/src/hir/from_ast.cpp b/src/hir/from_ast.cpp index 5dbf9c03..9c8f34f6 100644 --- a/src/hir/from_ast.cpp +++ b/src/hir/from_ast.cpp @@ -1258,6 +1258,21 @@ namespace { receiver = ::HIR::Function::Receiver::Box; } } + // TODO: for other types, support arbitary structs/paths. + // - The path must include Self as a (the only?) type param. + if( receiver == ::HIR::Function::Receiver::Free ) + { + if( pe.m_params.m_types.size() == 0 ) { + ERROR(sp, E0000, "Unsupported receiver type - " << arg_self_ty); + } + if( pe.m_params.m_types.size() != 1 ) { + TODO(sp, "Receiver types with more than one param - " << arg_self_ty); + } + if( pe.m_params.m_types[0] != self_type ) { + ERROR(sp, E0000, "Unsupported receiver type - " << arg_self_ty); + } + receiver = ::HIR::Function::Receiver::Custom; + } ) ) else { diff --git a/src/hir/hir.hpp b/src/hir/hir.hpp index 20b9ad58..daa27d10 100644 --- a/src/hir/hir.hpp +++ b/src/hir/hir.hpp @@ -8,6 +8,7 @@ * Contains the expanded and desugared AST */ #pragma once +#include #include #include @@ -122,6 +123,7 @@ public: //PointerMut, //PointerConst, Box, + Custom, }; typedef ::std::vector< ::std::pair< ::HIR::Pattern, ::HIR::TypeRef> > args_t; diff --git a/src/hir/visitor.cpp b/src/hir/visitor.cpp index 2e03990a..87b790ae 100644 --- a/src/hir/visitor.cpp +++ b/src/hir/visitor.cpp @@ -168,10 +168,9 @@ void ::HIR::Visitor::visit_trait(::HIR::ItemPath p, ::HIR::Trait& item) this->visit_trait_path(par); } for(auto& i : item.m_types) { + auto item_path = ::HIR::ItemPath(trait_ip, i.first.c_str()); DEBUG("type " << i.first); - for(auto& bound : i.second.m_trait_bounds) - this->visit_trait_path(bound); - this->visit_type(i.second.m_default); + this->visit_associatedtype(item_path, i.second); } for(auto& i : item.m_values) { auto item_path = ::HIR::ItemPath(trait_ip, i.first.c_str()); @@ -234,6 +233,12 @@ void ::HIR::Visitor::visit_union(::HIR::ItemPath p, ::HIR::Union& item) for(auto& var : item.m_variants) this->visit_type(var.second.ent); } +void ::HIR::Visitor::visit_associatedtype(ItemPath p, ::HIR::AssociatedType& item) +{ + for(auto& bound : item.m_trait_bounds) + this->visit_trait_path(bound); + this->visit_type(item.m_default); +} void ::HIR::Visitor::visit_function(::HIR::ItemPath p, ::HIR::Function& item) { this->visit_params(item.m_params); diff --git a/src/hir/visitor.hpp b/src/hir/visitor.hpp index dbf759a4..d432b29d 100644 --- a/src/hir/visitor.hpp +++ b/src/hir/visitor.hpp @@ -33,8 +33,9 @@ public: virtual void visit_type_alias(ItemPath p, ::HIR::TypeAlias& item); virtual void visit_trait(ItemPath p, ::HIR::Trait& item); virtual void visit_struct(ItemPath p, ::HIR::Struct& item); - virtual void visit_union(ItemPath p, ::HIR::Union& item); virtual void visit_enum(ItemPath p, ::HIR::Enum& item); + virtual void visit_union(ItemPath p, ::HIR::Union& item); + virtual void visit_associatedtype(ItemPath p, ::HIR::AssociatedType& item); // - Value Items virtual void visit_function(ItemPath p, ::HIR::Function& item); virtual void visit_static(ItemPath p, ::HIR::Static& item); diff --git a/src/hir_conv/constant_evaluation.cpp b/src/hir_conv/constant_evaluation.cpp index 5a41e954..a2847e04 100644 --- a/src/hir_conv/constant_evaluation.cpp +++ b/src/hir_conv/constant_evaluation.cpp @@ -48,7 +48,7 @@ namespace { } }; - ::HIR::Literal evaluate_constant(const Span& sp, const ::HIR::Crate& crate, NewvalState newval_state, const ::HIR::ExprPtr& expr, ::HIR::TypeRef exp, ::std::vector< ::HIR::Literal> args={}); + ::HIR::Literal evaluate_constant(const Span& sp, const ::HIR::Crate& crate, NewvalState newval_state, const ::HIR::ExprPtr& expr, t_cb_generic monomorph_cb, ::HIR::TypeRef exp, ::std::vector< ::HIR::Literal> args={}); ::HIR::Literal clone_literal(const ::HIR::Literal& v) { @@ -245,7 +245,26 @@ namespace { } } - ::HIR::Literal evaluate_constant_hir(const Span& sp, const ::HIR::Crate& crate, NewvalState newval_state, const ::HIR::ExprNode& expr, ::HIR::TypeRef exp_type, ::std::vector< ::HIR::Literal> args) + ::HIR::Literal evaluate_constant_intrinsic(const Span& sp, const ::HIR::Crate& crate, NewvalState newval_state, const ::std::string& name, const ::HIR::PathParams& params, ::std::vector< ::HIR::Literal> args) + { + TRACE_FUNCTION_F("\"" << name << "\"" << params << " " << args); + if( name == "size_of" ) { + ASSERT_BUG(sp, params.m_types.size() == 1, "size_of intrinsic takes one type param (consteval)"); + const auto& ty = params.m_types[0]; + + size_t size; + if( !Target_GetSizeOf(sp, StaticTraitResolve { crate }, ty, size) ) + { + TODO(sp, "Handle error from Target_GetSizeOf(" << ty << ") in evaluate_constant_intrinsic"); + } + return ::HIR::Literal::make_Integer(size); + } + else { + TODO(sp, "name=" << name << params << " args=" << args); + } + } + + ::HIR::Literal evaluate_constant_hir(const Span& sp, const ::HIR::Crate& crate, NewvalState newval_state, const ::HIR::ExprNode& expr, t_cb_generic monomorph_cb, ::HIR::TypeRef exp_type, ::std::vector< ::HIR::Literal> args) { // TODO: Force this function/tree through the entire pipeline so we can MIR it? // - Requires a HUGE change to the way the compiler operates. @@ -260,6 +279,7 @@ namespace { ::HIR::TypeRef m_exp_type; ::HIR::TypeRef m_rv_type; ::HIR::Literal m_rv; + t_cb_generic m_monomorph_cb; Visitor(const ::HIR::Crate& crate, NewvalState newval_state, ::HIR::TypeRef exp_ty): m_crate(crate), @@ -613,7 +633,7 @@ namespace { } void visit(::HIR::ExprNode_CallPath& node) override { - + const auto& sp = node.span(); TRACE_FUNCTION_FR("_CallPath - " << node.m_path, m_rv); auto& fcn = get_function(node.span(), m_crate, node.m_path); @@ -651,10 +671,27 @@ namespace { exp_ret_type = fcn.m_return.clone(); - // Call by invoking evaluate_constant on the function + if( fcn.m_abi == "rust-intrinsic" ) + { + auto pp = monomorphise_path_params_with(node.span(), node.m_path.m_data.as_Generic().m_params, m_monomorph_cb, true); + m_rv = evaluate_constant_intrinsic(node.span(), m_crate, m_newval_state, fcn.m_linkage.name, pp, mv$(args)); + } + else { - TRACE_FUNCTION_F("Call const fn " << node.m_path << " args={ " << args << " }"); - m_rv = evaluate_constant(node.span(), m_crate, m_newval_state, fcn.m_code, mv$(exp_ret_type), mv$(args)); + // Call by invoking evaluate_constant on the function + t_cb_generic cb; + ::HIR::PathParams pp; + if( const auto* g = node.m_path.m_data.opt_Generic() ) + { + pp = monomorphise_path_params_with(node.span(), g->m_params, m_monomorph_cb, true); + cb = monomorphise_type_get_cb(sp, nullptr, nullptr, &pp); + } + else + { + cb = monomorphise_type_get_cb(sp, nullptr, nullptr, nullptr); + } + TRACE_FUNCTION_F("Call const fn " << node.m_path << " args={ " << args << " } - pp=" << pp); + m_rv = evaluate_constant(node.span(), m_crate, m_newval_state, fcn.m_code, cb, mv$(exp_ret_type), mv$(args)); } } void visit(::HIR::ExprNode_CallValue& node) override { @@ -1009,6 +1046,7 @@ namespace { }; Visitor v { crate, newval_state, mv$(exp_type) }; + v.m_monomorph_cb = monomorph_cb; for(auto& arg : args) v.m_values.push_back( mv$(arg) ); const_cast<::HIR::ExprNode&>(expr).visit(v); @@ -1021,7 +1059,7 @@ namespace { return mv$(v.m_rv); } - ::HIR::Literal evaluate_constant_mir(const Span& sp, const ::HIR::Crate& crate, NewvalState newval_state, const ::MIR::Function& fcn, ::HIR::TypeRef exp, ::std::vector< ::HIR::Literal> args) + ::HIR::Literal evaluate_constant_mir(const Span& sp, const ::HIR::Crate& crate, NewvalState newval_state, const ::MIR::Function& fcn, t_cb_generic monomorph_cb, ::HIR::TypeRef exp, ::std::vector< ::HIR::Literal> args) { // TODO: Full-blown miri TRACE_FUNCTION_F("exp=" << exp << ", args=" << args); @@ -1452,7 +1490,8 @@ namespace { // Call by invoking evaluate_constant on the function { TRACE_FUNCTION_F("Call const fn " << fcnp << " args={ " << call_args << " }"); - dst = evaluate_constant(sp, crate, newval_state, fcn.m_code, fcn.m_return.clone(), mv$(call_args)); + // TODO: Correct monomorph_cb + dst = evaluate_constant(sp, crate, newval_state, fcn.m_code, monomorph_cb, fcn.m_return.clone(), mv$(call_args)); } cur_block = e.ret_block; @@ -1461,13 +1500,13 @@ namespace { } } - ::HIR::Literal evaluate_constant(const Span& sp, const ::HIR::Crate& crate, NewvalState newval_state, const ::HIR::ExprPtr& expr, ::HIR::TypeRef exp, ::std::vector< ::HIR::Literal> args) + ::HIR::Literal evaluate_constant(const Span& sp, const ::HIR::Crate& crate, NewvalState newval_state, const ::HIR::ExprPtr& expr, t_cb_generic monomorph_cb, ::HIR::TypeRef exp, ::std::vector< ::HIR::Literal> args) { if( expr.m_mir ) { - return evaluate_constant_mir(sp, crate, mv$(newval_state), *expr.m_mir, mv$(exp), mv$(args)); + return evaluate_constant_mir(sp, crate, mv$(newval_state), *expr.m_mir, monomorph_cb, mv$(exp), mv$(args)); } else if( expr ) { - return evaluate_constant_hir(sp, crate, mv$(newval_state), *expr, mv$(exp), mv$(args)); + return evaluate_constant_hir(sp, crate, mv$(newval_state), *expr, monomorph_cb, mv$(exp), mv$(args)); } else { BUG(sp, "Attempting to evaluate constant expression with no associated code"); @@ -1585,13 +1624,14 @@ namespace { ::HIR::Visitor::visit_type(ty); TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Array, e, + TRACE_FUNCTION_FR(ty, ty); if( e.size_val == ~0u ) { assert(e.size); assert(*e.size); const auto& expr_ptr = *e.size; auto nvs = NewvalState { m_new_values, *m_mod_path, FMT("ty_" << &ty << "$") }; - auto val = evaluate_constant(expr_ptr->span(), m_crate, nvs, expr_ptr, ::HIR::CoreType::Usize); + auto val = evaluate_constant(expr_ptr->span(), m_crate, nvs, expr_ptr, monomorphise_type_get_cb(expr_ptr->span(), nullptr, nullptr, nullptr), ::HIR::CoreType::Usize); if( !val.is_Integer() ) ERROR(expr_ptr->span(), E0000, "Array size isn't an integer"); e.size_val = static_cast(val.as_Integer()); @@ -1615,14 +1655,16 @@ namespace { // return ; auto nvs = NewvalState { m_new_values, *m_mod_path, FMT(p.get_name() << "$") }; - item.m_value_res = evaluate_constant(item.m_value->span(), m_crate, nvs, item.m_value, item.m_type.clone(), {}); + const auto& sp = item.m_value->span(); + item.m_value_res = evaluate_constant(sp, m_crate, nvs, item.m_value, monomorphise_type_get_cb(sp, nullptr, nullptr, nullptr), item.m_type.clone(), {}); - check_lit_type(item.m_value->span(), item.m_type, item.m_value_res); + check_lit_type(sp, item.m_type, item.m_value_res); DEBUG("constant: " << item.m_type << " = " << item.m_value_res); } } void visit_enum(::HIR::ItemPath p, ::HIR::Enum& item) override { + static Span sp; if( auto* e = item.m_data.opt_Value() ) { uint64_t i = 0; @@ -1630,7 +1672,9 @@ namespace { { if( var.expr ) { - auto val = evaluate_constant(var.expr->span(), m_crate, NewvalState { m_new_values, *m_mod_path, FMT(p.get_name() << "$" << var.name << "$") }, var.expr, {}); + auto nvs = NewvalState { m_new_values, *m_mod_path, FMT(p.get_name() << "$" << var.name << "$") }; + const auto& sp = var.expr->span(); + auto val = evaluate_constant(sp, m_crate, nvs, var.expr, monomorphise_type_get_cb(sp, nullptr, nullptr, nullptr), {}, {}); DEBUG("enum variant: " << p << "::" << var.name << " = " << val); i = val.as_Integer(); } @@ -1664,7 +1708,7 @@ namespace { void visit(::HIR::ExprNode_ArraySized& node) override { assert( node.m_size ); NewvalState nvs { m_exp.m_new_values, *m_exp.m_mod_path, FMT("array_" << &node << "$") }; - auto val = evaluate_constant_hir(node.span(), m_exp.m_crate, mv$(nvs), *node.m_size, ::HIR::CoreType::Usize, {}); + auto val = evaluate_constant_hir(node.span(), m_exp.m_crate, mv$(nvs), *node.m_size, monomorphise_type_get_cb(node.span(), nullptr, nullptr, nullptr), ::HIR::CoreType::Usize, {}); if( !val.is_Integer() ) ERROR(node.span(), E0000, "Array size isn't an integer"); node.m_size_val = static_cast(val.as_Integer()); diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 4f698c15..07f86d44 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -890,10 +890,10 @@ namespace { { case ::HIR::ExprNode_BinOp::Op::CmpEqu: item_name = "eq"; break; case ::HIR::ExprNode_BinOp::Op::CmpNEqu: item_name = "eq"; break; - case ::HIR::ExprNode_BinOp::Op::CmpLt: item_name = "ord"; break; - case ::HIR::ExprNode_BinOp::Op::CmpLtE: item_name = "ord"; break; - case ::HIR::ExprNode_BinOp::Op::CmpGt: item_name = "ord"; break; - case ::HIR::ExprNode_BinOp::Op::CmpGtE: item_name = "ord"; break; + case ::HIR::ExprNode_BinOp::Op::CmpLt: item_name = TARGETVER_1_29 ? "partial_ord" : "ord"; break; + case ::HIR::ExprNode_BinOp::Op::CmpLtE: item_name = TARGETVER_1_29 ? "partial_ord" : "ord"; break; + case ::HIR::ExprNode_BinOp::Op::CmpGt: item_name = TARGETVER_1_29 ? "partial_ord" : "ord"; break; + case ::HIR::ExprNode_BinOp::Op::CmpGtE: item_name = TARGETVER_1_29 ? "partial_ord" : "ord"; break; default: break; } assert(item_name); diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index 22291123..8f1f0685 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -1050,8 +1050,10 @@ bool TraitResolution::iterate_bounds( ::std::function cb) const { ::HIR::GenericPath trait_path; + DEBUG("Checking ATY bounds on " << pe.trait << " :: " << pe.item); if( !this->trait_contains_type(sp, pe.trait, this->m_crate.get_trait_by_path(sp, pe.trait.m_path), pe.item, trait_path) ) BUG(sp, "Cannot find associated type " << pe.item << " anywhere in trait " << pe.trait); + DEBUG("trait_path=" << trait_path); const auto& trait_ref = m_crate.get_trait_by_path(sp, trait_path.m_path); const auto& aty_def = trait_ref.m_types.find(pe.item)->second; @@ -1361,12 +1363,19 @@ bool TraitResolution::find_trait_impls(const Span& sp, ASSERT_BUG(sp, e.path.m_data.is_UfcsKnown(), "Opaque bound type wasn't UfcsKnown - " << type); const auto& pe = e.path.m_data.as_UfcsKnown(); + // TODO: Should Self here be `type` or `*pe.type` + // - Depends... if implicit it should be `type` (as it relates to the associated type), but if explicit it's referring to the trait auto monomorph_cb = monomorphise_type_get_cb(sp, &*pe.type, &pe.trait.m_params, nullptr, nullptr); auto rv = this->iterate_aty_bounds(sp, pe, [&](const auto& bound) { + DEBUG("Bound on ATY: " << bound); const auto& b_params = bound.m_path.m_params; ::HIR::PathParams params_mono_o; const auto& b_params_mono = (monomorphise_pathparams_needed(b_params) ? params_mono_o = monomorphise_path_params_with(sp, b_params, monomorph_cb, false) : b_params); + // TODO: Monormophise and EAT associated types + ::std::map< ::std::string, ::HIR::TypeRef> b_atys; + for(const auto& aty : bound.m_type_bounds) + b_atys.insert(::std::make_pair( aty.first, monomorphise_type_with(sp, aty.second, monomorph_cb) )); if( bound.m_path.m_path == trait ) { @@ -1375,13 +1384,15 @@ bool TraitResolution::find_trait_impls(const Span& sp, { if( &b_params_mono == ¶ms_mono_o ) { - if( callback( ImplRef(type.clone(), mv$(params_mono_o), {}), cmp ) ) + // TODO: assoc bounds + if( callback( ImplRef(type.clone(), mv$(params_mono_o), mv$(b_atys)), cmp ) ) return true; params_mono_o = monomorphise_path_params_with(sp, b_params, monomorph_cb, false); } else { - if( callback( ImplRef(&type, &bound.m_path.m_params, &null_assoc), cmp ) ) + //if( callback( ImplRef(&type, &bound.m_path.m_params, &null_assoc), cmp ) ) + if( callback( ImplRef(&type, &bound.m_path.m_params, &b_atys), cmp ) ) return true; } } @@ -2219,12 +2230,14 @@ bool TraitResolution::find_trait_impls_bound(const Span& sp, const ::HIR::Simple // TODO: A bound can imply something via its associated types. How deep can this go? // E.g. `T: IntoIterator` implies `::IntoIter : Iterator` return this->iterate_bounds([&](const auto& b)->bool { + DEBUG(b); if( b.is_TraitBound() ) { const auto& e = b.as_TraitBound(); const auto& b_params = e.trait.m_path.m_params; auto cmp = e.type .compare_with_placeholders(sp, type, m_ivars.callback_resolve_infer()); + DEBUG("cmp = " << cmp); if( cmp == ::HIR::Compare::Unequal ) return false; @@ -3643,6 +3656,9 @@ const ::HIR::TypeRef* TraitResolution::check_method_receiver(const Span& sp, ::H return &this->m_ivars.get_type(*ty.m_data.as_Borrow().inner); } break; + case ::HIR::Function::Receiver::Custom: + // TODO: Handle custom-receiver functions + return nullptr; case ::HIR::Function::Receiver::Box: if(const auto* ity = this->type_is_owned_box(sp, ty)) { diff --git a/src/hir_typeck/outer.cpp b/src/hir_typeck/outer.cpp index dddb7731..b38511d1 100644 --- a/src/hir_typeck/outer.cpp +++ b/src/hir_typeck/outer.cpp @@ -201,13 +201,16 @@ namespace { { while( param_vals.m_types.size() < param_def.m_types.size() ) { unsigned int i = param_vals.m_types.size(); - if( param_def.m_types[i].m_default.m_data.is_Infer() ) { + const auto& ty_def = param_def.m_types[i]; + if( ty_def.m_default.m_data.is_Infer() ) { ERROR(sp, E0000, "Unspecified parameter with no default"); } // Replace and expand - param_vals.m_types.push_back( param_def.m_types[i].m_default.clone() ); + param_vals.m_types.push_back( ty_def.m_default.clone() ); auto& ty = param_vals.m_types.back(); + // TODO: Monomorphise? + // Replace `Self` here with the real Self update_self_type(sp, ty); } @@ -220,7 +223,7 @@ namespace { if( param_vals.m_types[i] == ::HIR::TypeRef() ) { //if( param_def.m_types[i].m_default == ::HIR::TypeRef() ) // ERROR(sp, E0000, "Unspecified parameter with no default"); - // TODO: Monomorph? + // TODO: Monomorphise? param_vals.m_types[i] = param_def.m_types[i].m_default.clone(); update_self_type(sp, param_vals.m_types[i]); } @@ -429,6 +432,16 @@ namespace { } return trait_path_g; } + ::HIR::GenericPath get_current_trait_gp() const + { + assert(m_current_trait_path); + assert(m_current_trait); + auto trait_path = ::HIR::GenericPath( m_current_trait_path->get_simple_path() ); + for(unsigned int i = 0; i < m_current_trait->m_params.m_types.size(); i ++ ) { + trait_path.m_params.m_types.push_back( ::HIR::TypeRef(m_current_trait->m_params.m_types[i].m_name, i) ); + } + return trait_path; + } void visit_path_UfcsUnknown(const Span& sp, ::HIR::Path& p, ::HIR::Visitor::PathContext pc) { TRACE_FUNCTION_FR("UfcsUnknown - p=" << p, p); @@ -449,10 +462,7 @@ namespace { // If processing a trait, and the type is 'Self', search for the type/method on the trait // - TODO: This could be encoded by a `Self: Trait` bound in the generics, but that may have knock-on issues? if( te.name == "Self" && m_current_trait ) { - auto trait_path = ::HIR::GenericPath( m_current_trait_path->get_simple_path() ); - for(unsigned int i = 0; i < m_current_trait->m_params.m_types.size(); i ++ ) { - trait_path.m_params.m_types.push_back( ::HIR::TypeRef(m_current_trait->m_params.m_types[i].m_name, i) ); - } + auto trait_path = this->get_current_trait_gp(); if( this->locate_in_trait_and_set(sp, pc, trait_path, *m_current_trait, p.m_data) ) { // Success! return ; @@ -616,6 +626,17 @@ namespace { auto _ = m_resolve.set_item_generics(item.m_params); ::HIR::Visitor::visit_enum(p, item); } + void visit_associatedtype(::HIR::ItemPath p, ::HIR::AssociatedType& item) + { + // Push `Self = ::Type` for processing defaults in the bounds. + auto path_aty = ::HIR::Path( ::HIR::TypeRef("Self", 0xFFFF), this->get_current_trait_gp(), p.get_name() ); + auto ty_aty = ::HIR::TypeRef::new_path( mv$(path_aty), ::HIR::TypeRef::TypePathBinding::make_Opaque({}) ); + m_self_types.push_back(&ty_aty); + + ::HIR::Visitor::visit_associatedtype(p, item); + + m_self_types.pop_back(); + } void visit_type_impl(::HIR::TypeImpl& impl) override { diff --git a/src/hir_typeck/static.cpp b/src/hir_typeck/static.cpp index 8000f5af..cfa94dbb 100644 --- a/src/hir_typeck/static.cpp +++ b/src/hir_typeck/static.cpp @@ -118,6 +118,16 @@ bool StaticTraitResolve::find_impl( } } + if(const auto* e = type.m_data.opt_Generic() ) + { + if( (e->binding >> 8) == 2 ) + { + // TODO: If the type is a magic placeholder, assume it impls the specified trait. + // TODO: Restructure so this knows that the placehlder impls the impl-provided bounds. + return found_cb( ImplRef(&type, trait_params, &null_assoc), false ); + } + } + // --- MAGIC IMPLS --- // TODO: There should be quite a few more here, but laziness TU_IFLET(::HIR::TypeRef::Data, type.m_data, Function, e, @@ -556,6 +566,7 @@ bool StaticTraitResolve::find_impl__check_crate_raw( if( placeholders.size() == 0 ) placeholders.resize(impl_params.size()); placeholders[i] = ::HIR::TypeRef("impl_?", 2*256 + i); + DEBUG("Placeholder " << placeholders[i] << " for " << impl_params_def.m_types[i].m_name); } } // Callback that matches placeholders to concrete types @@ -571,6 +582,9 @@ bool StaticTraitResolve::find_impl__check_crate_raw( ph = ty.clone(); return ::HIR::Compare::Equal; } + else if( ph == ty ) { + return ::HIR::Compare::Equal; + } else { TODO(sp, "[find_impl__check_crate_raw:cb_match] Compare placeholder " << i << " " << ph << " == " << ty); } diff --git a/src/include/target_version.hpp b/src/include/target_version.hpp new file mode 100644 index 00000000..dddf69e4 --- /dev/null +++ b/src/include/target_version.hpp @@ -0,0 +1,11 @@ +/* + * MRustC - Rust Compiler + * - By John Hodge (Mutabah/thePowersGang) + * + * include/target_version.hpp + * - mrustc target lanuage version definitions + */ +#pragma once + +#define TARGETVER_1_19 true +#define TARGETVER_1_29 true -- cgit v1.2.3 From c3d14bb51bea1f2a6e917fb8359335772c52f6f4 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Wed, 1 Aug 2018 20:12:17 +0800 Subject: Expand - Hacky Try trait usage --- src/expand/mod.cpp | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/expand/mod.cpp b/src/expand/mod.cpp index 872105a6..a0cc3f7b 100644 --- a/src/expand/mod.cpp +++ b/src/expand/mod.cpp @@ -803,12 +803,19 @@ struct CExpandExpr: auto path_Err = ::AST::Path(core_crate, {::AST::PathNode("result"), ::AST::PathNode("Result"), ::AST::PathNode("Err")}); auto path_From = ::AST::Path(core_crate, {::AST::PathNode("convert"), ::AST::PathNode("From")}); path_From.nodes().back().args().m_types.push_back( ::TypeRef(node.span()) ); + // TODO: Lang item (needs lang items enumerated earlier) + //auto it = crate.m_lang_items.find("try"); + //ASSERT_BUG(node.span(), it != crate.m_lang_items.end(), "Can't find the `try` lang item"); + //auto path_Try = it->second; + auto path_Try = ::AST::Path(core_crate, {::AST::PathNode("ops"), ::AST::PathNode("Try")}); + auto path_Try_into_result = ::AST::Path(::AST::Path::TagUfcs(), ::TypeRef(node.span()), path_Try, { ::AST::PathNode("into_result") }); + auto path_Try_from_error = ::AST::Path(::AST::Path::TagUfcs(), ::TypeRef(node.span()), path_Try, { ::AST::PathNode("from_error") }); // Desugars into // ``` - // match `m_value` { + // match `Try::into_result(m_value)` { // Ok(v) => v, - // Err(e) => return Err(From::from(e)), + // Err(e) => return Try::from_error(From::from(e)), // } // ``` @@ -819,7 +826,7 @@ struct CExpandExpr: nullptr, ::AST::ExprNodeP( new ::AST::ExprNode_NamedValue( ::AST::Path(::AST::Path::TagLocal(), "v") ) ) )); - // `Err(e) => return Err(From::from(e)),` + // `Err(e) => return Try::from_error(From::from(e)),` arms.push_back(::AST::ExprNode_Match_Arm( ::make_vec1( ::AST::Pattern(::AST::Pattern::TagNamedTuple(), node.span(), path_Err, ::make_vec1( ::AST::Pattern(::AST::Pattern::TagBind(), node.span(), "e") )) ), nullptr, @@ -827,7 +834,7 @@ struct CExpandExpr: ::AST::ExprNode_Flow::RETURN, "", ::AST::ExprNodeP(new ::AST::ExprNode_CallPath( - ::AST::Path(path_Err), + ::AST::Path(path_Try_from_error), ::make_vec1( ::AST::ExprNodeP(new ::AST::ExprNode_CallPath( ::AST::Path(::AST::Path::TagUfcs(), ::TypeRef(node.span()), mv$(path_From), { ::AST::PathNode("from") }), @@ -838,7 +845,13 @@ struct CExpandExpr: )) )); - replacement.reset(new ::AST::ExprNode_Match( mv$(node.m_value), mv$(arms) )); + replacement.reset(new ::AST::ExprNode_Match( + ::AST::ExprNodeP(new AST::ExprNode_CallPath( + mv$(path_Try_into_result), + ::make_vec1( mv$(node.m_value) ) + )), + mv$(arms) + )); } } }; -- cgit v1.2.3 From b2423dbde77141cced2a53c3a4f2e323ed8e4efa Mon Sep 17 00:00:00 2001 From: John Hodge Date: Thu, 2 Aug 2018 21:26:58 +0800 Subject: HIR Typecheck - Magic Clone impls --- src/hir_typeck/expr_cs.cpp | 4 +- src/hir_typeck/helpers.cpp | 218 ++++++++++++++++++++++++++++++++++----------- src/hir_typeck/helpers.hpp | 3 +- src/hir_typeck/static.cpp | 97 ++++++++++++++++++++ src/hir_typeck/static.hpp | 5 ++ 5 files changed, 270 insertions(+), 57 deletions(-) diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 07f86d44..65bca2c0 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -2155,8 +2155,8 @@ namespace { } ), (Borrow, - // Check class (must be equal) and type - if( s_e.type != e.type ) { + // Check class (destination must be weaker) and type + if( !(s_e.type >= e.type) ) { ERROR(sp, E0000, "Invalid cast from " << src_ty << " to " << tgt_ty); } const auto& src_inner = this->context.get_type(*s_e.inner); diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index 8f1f0685..a3991981 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -1089,7 +1089,8 @@ bool TraitResolution::iterate_aty_bounds(const Span& sp, const ::HIR::Path::Data bool TraitResolution::find_trait_impls(const Span& sp, const ::HIR::SimplePath& trait, const ::HIR::PathParams& params, const ::HIR::TypeRef& ty, - t_cb_trait_impl_r callback + t_cb_trait_impl_r callback, + bool magic_trait_impls /*=true*/ ) const { static ::HIR::PathParams null_params; @@ -1110,6 +1111,7 @@ bool TraitResolution::find_trait_impls(const Span& sp, const auto& lang_Sized = this->m_crate.get_lang_item_path(sp, "sized"); const auto& lang_Copy = this->m_crate.get_lang_item_path(sp, "copy"); + //const auto& lang_Clone = this->m_crate.get_lang_item_path(sp, "clone"); const auto& lang_Unsize = this->m_crate.get_lang_item_path(sp, "unsize"); const auto& lang_CoerceUnsized = this->m_crate.get_lang_item_path(sp, "coerce_unsized"); const auto& trait_fn = this->m_crate.get_lang_item_path(sp, "fn"); @@ -1118,23 +1120,37 @@ bool TraitResolution::find_trait_impls(const Span& sp, const auto& trait_index = this->m_crate.get_lang_item_path(sp, "index"); const auto& trait_indexmut = this->m_crate.get_lang_item_path(sp, "index_mut"); - if( trait == lang_Sized ) { - auto cmp = type_is_sized(sp, type); - if( cmp != ::HIR::Compare::Unequal ) { - return callback( ImplRef(&type, &null_params, &null_assoc), cmp ); - } - else { - return false; + if( magic_trait_impls ) + { + if( trait == lang_Sized ) { + auto cmp = type_is_sized(sp, type); + if( cmp != ::HIR::Compare::Unequal ) { + return callback( ImplRef(&type, &null_params, &null_assoc), cmp ); + } + else { + return false; + } } - } - if( trait == lang_Copy ) { - auto cmp = this->type_is_copy(sp, type); - if( cmp != ::HIR::Compare::Unequal ) { - return callback( ImplRef(&type, &null_params, &null_assoc), cmp ); + if( trait == lang_Copy ) { + auto cmp = this->type_is_copy(sp, type); + if( cmp != ::HIR::Compare::Unequal ) { + return callback( ImplRef(&type, &null_params, &null_assoc), cmp ); + } + else { + return false; + } } - else { - return false; + + if( TARGETVER_1_29 && trait == this->m_crate.get_lang_item_path(sp, "clone") ) + { + auto cmp = this->type_is_clone(sp, type); + if( cmp != ::HIR::Compare::Unequal ) { + return callback( ImplRef(&type, &null_params, &null_assoc), cmp ); + } + else { + return false; + } } } @@ -1416,53 +1432,56 @@ bool TraitResolution::find_trait_impls(const Span& sp, } ) - // Magic Unsize impls to trait objects - if( trait == lang_Unsize ) + if( magic_trait_impls ) { - ASSERT_BUG(sp, params.m_types.size() == 1, "Unsize trait requires a single type param"); - const auto& dst_ty = this->m_ivars.get_type(params.m_types[0]); + // Magic Unsize impls to trait objects + if( trait == lang_Unsize ) + { + ASSERT_BUG(sp, params.m_types.size() == 1, "Unsize trait requires a single type param"); + const auto& dst_ty = this->m_ivars.get_type(params.m_types[0]); - if( find_trait_impls_bound(sp, trait, params, type, callback) ) - return true; + if( find_trait_impls_bound(sp, trait, params, type, callback) ) + return true; - bool rv = false; - auto cb = [&](auto new_dst) { - ::HIR::PathParams real_params { mv$(new_dst) }; - rv = callback( ImplRef(type.clone(), mv$(real_params), {}), ::HIR::Compare::Fuzzy ); - }; - //if( dst_ty.m_data.is_Infer() || type.m_data.is_Infer() ) - //{ - // rv = callback( ImplRef(type.clone(), params.clone(), {}), ::HIR::Compare::Fuzzy ); - // return rv; - //} - auto cmp = this->can_unsize(sp, dst_ty, type, cb); - if( cmp == ::HIR::Compare::Equal ) - { - assert(!rv); - rv = callback( ImplRef(type.clone(), params.clone(), {}), ::HIR::Compare::Equal ); + bool rv = false; + auto cb = [&](auto new_dst) { + ::HIR::PathParams real_params { mv$(new_dst) }; + rv = callback( ImplRef(type.clone(), mv$(real_params), {}), ::HIR::Compare::Fuzzy ); + }; + //if( dst_ty.m_data.is_Infer() || type.m_data.is_Infer() ) + //{ + // rv = callback( ImplRef(type.clone(), params.clone(), {}), ::HIR::Compare::Fuzzy ); + // return rv; + //} + auto cmp = this->can_unsize(sp, dst_ty, type, cb); + if( cmp == ::HIR::Compare::Equal ) + { + assert(!rv); + rv = callback( ImplRef(type.clone(), params.clone(), {}), ::HIR::Compare::Equal ); + } + return rv; } - return rv; - } - // Magical CoerceUnsized impls for various types - if( trait == lang_CoerceUnsized ) { - const auto& dst_ty = params.m_types.at(0); - // - `*mut T => *const T` - TU_IFLET( ::HIR::TypeRef::Data, type.m_data, Pointer, e, - TU_IFLET( ::HIR::TypeRef::Data, dst_ty.m_data, Pointer, de, - if( de.type < e.type ) { - auto cmp = e.inner->compare_with_placeholders(sp, *de.inner, this->m_ivars.callback_resolve_infer()); - if( cmp != ::HIR::Compare::Unequal ) - { - ::HIR::PathParams pp; - pp.m_types.push_back( dst_ty.clone() ); - if( callback( ImplRef(type.clone(), mv$(pp), {}), cmp ) ) { - return true; + // Magical CoerceUnsized impls for various types + if( trait == lang_CoerceUnsized ) { + const auto& dst_ty = params.m_types.at(0); + // - `*mut T => *const T` + TU_IFLET( ::HIR::TypeRef::Data, type.m_data, Pointer, e, + TU_IFLET( ::HIR::TypeRef::Data, dst_ty.m_data, Pointer, de, + if( de.type < e.type ) { + auto cmp = e.inner->compare_with_placeholders(sp, *de.inner, this->m_ivars.callback_resolve_infer()); + if( cmp != ::HIR::Compare::Unequal ) + { + ::HIR::PathParams pp; + pp.m_types.push_back( dst_ty.clone() ); + if( callback( ImplRef(type.clone(), mv$(pp), {}), cmp ) ) { + return true; + } } } - } + ) ) - ) + } } // 1. Search generic params @@ -3169,6 +3188,97 @@ bool TraitResolution::trait_contains_type(const Span& sp, const ::HIR::GenericPa ) ) } +::HIR::Compare TraitResolution::type_is_clone(const Span& sp, const ::HIR::TypeRef& ty) const +{ + TRACE_FUNCTION_F(ty); + const auto& type = this->m_ivars.get_type(ty); + const auto& lang_Clone = this->m_crate.get_lang_item_path(sp, "clone"); + TU_MATCH_DEF(::HIR::TypeRef::Data, (type.m_data), (e), + ( + // NOTE: Don't use find_trait_impls, because that calls this + bool is_fuzzy = false; + bool has_eq = find_trait_impls(sp, lang_Clone, ::HIR::PathParams{}, ty, [&](auto , auto c)->bool{ + switch(c) + { + case ::HIR::Compare::Equal: return true; + case ::HIR::Compare::Fuzzy: + is_fuzzy = true; + return false; + case ::HIR::Compare::Unequal: + return false; + } + throw ""; + }, false); + if( has_eq ) { + return ::HIR::Compare::Equal; + } + else if( is_fuzzy ) { + return ::HIR::Compare::Fuzzy; + } + else { + return ::HIR::Compare::Unequal; + } + ), + (Infer, + switch(e.ty_class) + { + case ::HIR::InferClass::Integer: + case ::HIR::InferClass::Float: + return ::HIR::Compare::Equal; + default: + DEBUG("Fuzzy Clone impl for ivar?"); + return ::HIR::Compare::Fuzzy; + } + ), + (Generic, + // TODO: Store this result - or even pre-calculate it. + return this->iterate_bounds([&](const auto& b)->bool { + TU_IFLET(::HIR::GenericBound, b, TraitBound, be, + if(be.type == ty) + { + if(be.trait.m_path == lang_Clone) + return true; + ::HIR::PathParams pp; + bool rv = this->find_named_trait_in_trait(sp, + lang_Clone,pp, *be.trait.m_trait_ptr, be.trait.m_path.m_path, be.trait.m_path.m_params, type, + [&](const auto& , const auto&, const auto&)->bool { return true; } + ); + if(rv) + return true; + } + ) + return false; + }) ? ::HIR::Compare::Equal : ::HIR::Compare::Unequal ; + ), + (Primitive, + if( e == ::HIR::CoreType::Str ) + return ::HIR::Compare::Unequal; + return ::HIR::Compare::Equal; + ), + (Borrow, + return e.type == ::HIR::BorrowType::Shared ? ::HIR::Compare::Equal : ::HIR::Compare::Unequal ; + ), + (Pointer, + return ::HIR::Compare::Equal; + ), + (Tuple, + auto rv = ::HIR::Compare::Equal; + for(const auto& sty : e) + rv &= type_is_clone(sp, sty); + return rv; + ), + (Slice, + return ::HIR::Compare::Unequal; + ), + (Function, + return ::HIR::Compare::Equal; + ), + (Array, + // TODO: Clone here? + return type_is_copy(sp, *e.inner); + ) + ) +} // Checks if a type can unsize to another // - Returns Compare::Equal if the unsize is possible and fully known // - Returns Compare::Fuzzy if the unsize is possible, but still unknown. diff --git a/src/hir_typeck/helpers.hpp b/src/hir_typeck/helpers.hpp index 58688d6e..e7a917f4 100644 --- a/src/hir_typeck/helpers.hpp +++ b/src/hir_typeck/helpers.hpp @@ -207,7 +207,7 @@ public: typedef ::std::function t_cb_trait_impl_r; /// Searches for a trait impl that matches the provided trait name and type - bool find_trait_impls(const Span& sp, const ::HIR::SimplePath& trait, const ::HIR::PathParams& params, const ::HIR::TypeRef& type, t_cb_trait_impl_r callback) const; + bool find_trait_impls(const Span& sp, const ::HIR::SimplePath& trait, const ::HIR::PathParams& params, const ::HIR::TypeRef& type, t_cb_trait_impl_r callback, bool magic_trait_impls=true) const; /// Locate a named trait in the provied trait (either itself or as a parent trait) bool find_named_trait_in_trait(const Span& sp, @@ -283,6 +283,7 @@ public: ::HIR::Compare type_is_sized(const Span& sp, const ::HIR::TypeRef& ty) const; ::HIR::Compare type_is_copy(const Span& sp, const ::HIR::TypeRef& ty) const; + ::HIR::Compare type_is_clone(const Span& sp, const ::HIR::TypeRef& ty) const; // If `new_type_callback` is populated, it will be called with the actual/possible dst_type // If `infer_callback` is populated, it will be called when either side is an ivar diff --git a/src/hir_typeck/static.cpp b/src/hir_typeck/static.cpp index cfa94dbb..016d86a0 100644 --- a/src/hir_typeck/static.cpp +++ b/src/hir_typeck/static.cpp @@ -104,6 +104,11 @@ bool StaticTraitResolve::find_impl( return found_cb( ImplRef(&type, &null_params, &null_assoc), false ); } } + else if( TARGETVER_1_29 && trait_path == m_lang_Clone ) { + if( this->type_is_clone(sp, type) ) { + return found_cb( ImplRef(&type, &null_params, &null_assoc), false ); + } + } else if( trait_path == m_lang_Sized ) { if( this->type_is_sized(sp, type) ) { return found_cb( ImplRef(&type, &null_params, &null_assoc), false ); @@ -1393,6 +1398,10 @@ bool StaticTraitResolve::type_is_copy(const Span& sp, const ::HIR::TypeRef& ty) return true; ), (Closure, + if( TARGETVER_1_29 ) + { + // TODO: Auto-gerated impls + } return false; ), (Infer, @@ -1444,6 +1453,94 @@ bool StaticTraitResolve::type_is_copy(const Span& sp, const ::HIR::TypeRef& ty) ) throw ""; } +bool StaticTraitResolve::type_is_clone(const Span& sp, const ::HIR::TypeRef& ty) const +{ + if( !TARGETVER_1_29 ) BUG(sp, "Calling type_is_clone when not in 1.29 mode"); + + TU_MATCH(::HIR::TypeRef::Data, (ty.m_data), (e), + (Generic, + { + auto it = m_clone_cache.find(ty); + if( it != m_clone_cache.end() ) + { + return it->second; + } + } + bool rv = this->iterate_bounds([&](const auto& b)->bool { + auto pp = ::HIR::PathParams(); + return this->find_impl__check_bound(sp, m_lang_Clone, &pp, ty, [&](auto , bool ){ return true; }, b); + }); + m_clone_cache.insert(::std::make_pair( ty.clone(), rv )); + return rv; + ), + (Path, + { + auto it = m_clone_cache.find(ty); + if( it != m_clone_cache.end() ) + return it->second; + } + auto pp = ::HIR::PathParams(); + bool rv = this->find_impl(sp, m_lang_Clone, &pp, ty, [&](auto , bool){ return true; }, true); + m_clone_cache.insert(::std::make_pair( ty.clone(), rv )); + return rv; + ), + (Diverge, + // The ! type is kinda Copy/Clone ... + return true; + ), + (Closure, + // TODO: Auto-gerated impls + return false; + ), + (Infer, + // Shouldn't be hit + return false; + ), + (Borrow, + // Only shared &-ptrs are copy/clone + return (e.type == ::HIR::BorrowType::Shared); + ), + (Pointer, + // All raw pointers are Copy/Clone + return true; + ), + (Function, + // All function pointers are Copy/Clone + return true; + ), + (Primitive, + // All primitives (except the unsized `str`) are Copy/Clone + return e != ::HIR::CoreType::Str; + ), + (Array, + return e.size_val == 0 || type_is_clone(sp, *e.inner); + ), + (Slice, + // [T] isn't Sized, so isn't Copy ether + return false; + ), + (TraitObject, + // (Trait) isn't Sized, so isn't Copy ether + return false; + ), + (ErasedType, + for(const auto& trait : e.m_traits) + { + if( find_named_trait_in_trait(sp, m_lang_Clone, {}, *trait.m_trait_ptr, trait.m_path.m_path, trait.m_path.m_params, ty, [](const auto&, auto ){ }) ) { + return true; + } + } + return false; + ), + (Tuple, + for(const auto& ty : e) + if( !type_is_clone(sp, ty) ) + return false; + return true; + ) + ) + throw ""; +} bool StaticTraitResolve::type_is_sized(const Span& sp, const ::HIR::TypeRef& ty) const { diff --git a/src/hir_typeck/static.hpp b/src/hir_typeck/static.hpp index 8c9cb9a6..ae429a3f 100644 --- a/src/hir_typeck/static.hpp +++ b/src/hir_typeck/static.hpp @@ -23,6 +23,7 @@ public: ::std::map< ::HIR::TypeRef, ::HIR::TypeRef> m_type_equalities; ::HIR::SimplePath m_lang_Copy; + ::HIR::SimplePath m_lang_Clone; // 1.29 ::HIR::SimplePath m_lang_Drop; ::HIR::SimplePath m_lang_Sized; ::HIR::SimplePath m_lang_Unsize; @@ -34,6 +35,7 @@ public: private: mutable ::std::map< ::HIR::TypeRef, bool > m_copy_cache; + mutable ::std::map< ::HIR::TypeRef, bool > m_clone_cache; public: StaticTraitResolve(const ::HIR::Crate& crate): @@ -42,6 +44,8 @@ public: m_item_generics(nullptr) { m_lang_Copy = m_crate.get_lang_item_path_opt("copy"); + if( TARGETVER_1_29 ) + m_lang_Clone = m_crate.get_lang_item_path_opt("clone"); m_lang_Drop = m_crate.get_lang_item_path_opt("drop"); m_lang_Sized = m_crate.get_lang_item_path_opt("sized"); m_lang_Unsize = m_crate.get_lang_item_path_opt("unsize"); @@ -178,6 +182,7 @@ public: // Common bounds // ------------- bool type_is_copy(const Span& sp, const ::HIR::TypeRef& ty) const; + bool type_is_clone(const Span& sp, const ::HIR::TypeRef& ty) const; // 1.29 bool type_is_sized(const Span& sp, const ::HIR::TypeRef& ty) const; bool can_unsize(const Span& sp, const ::HIR::TypeRef& dst, const ::HIR::TypeRef& src) const; -- cgit v1.2.3 From de045aa86e72c353c9caa1899b8ff5cc6e67ab8e Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 3 Aug 2018 22:44:16 +0800 Subject: HIR Typecheck - Support semi-arbitary method receivers --- src/hir_typeck/helpers.cpp | 115 ++++++++++++++++++++++++++------------------- src/hir_typeck/helpers.hpp | 4 +- 2 files changed, 69 insertions(+), 50 deletions(-) diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index a3991981..0e839219 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -2971,14 +2971,14 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, } namespace { - bool trait_contains_method_inner(const ::HIR::Trait& trait_ptr, const ::std::string& name, ::HIR::Function::Receiver& receiver) + bool trait_contains_method_inner(const ::HIR::Trait& trait_ptr, const ::std::string& name, const ::HIR::Function*& out_fcn_ptr) { auto it = trait_ptr.m_values.find(name); if( it != trait_ptr.m_values.end() ) { if( it->second.is_Function() ) { const auto& v = it->second.as_Function(); - receiver = v.m_receiver; + out_fcn_ptr = &v; return true; } } @@ -2986,27 +2986,30 @@ namespace { } } -bool TraitResolution::trait_contains_method(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const ::HIR::TypeRef& self, const ::std::string& name, ::HIR::Function::Receiver& out_receiver, ::HIR::GenericPath& out_path) const +const ::HIR::Function* TraitResolution::trait_contains_method(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const ::HIR::TypeRef& self, const ::std::string& name, ::HIR::GenericPath& out_path) const { TRACE_FUNCTION_FR("trait_path=" << trait_path << ",name=" << name, out_path); + const ::HIR::Function* rv = nullptr; - if( trait_contains_method_inner(trait_ptr, name, out_receiver) ) + if( trait_contains_method_inner(trait_ptr, name, rv) ) { + assert(rv); out_path = trait_path.clone(); - return true; + return rv; } auto monomorph_cb = monomorphise_type_get_cb(sp, &self, &trait_path.m_params, nullptr); for(const auto& st : trait_ptr.m_all_parent_traits) { - if( trait_contains_method_inner(*st.m_trait_ptr, name, out_receiver) ) + if( trait_contains_method_inner(*st.m_trait_ptr, name, rv) ) { + assert(rv); out_path.m_path = st.m_path.m_path; out_path.m_params = monomorphise_path_params_with(sp, st.m_path.m_params, monomorph_cb, false); - return true; + return rv; } } - return false; + return nullptr; } bool TraitResolution::trait_contains_type(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const ::std::string& name, ::HIR::GenericPath& out_path) const { @@ -3717,9 +3720,9 @@ unsigned int TraitResolution::autoderef_find_method(const Span& sp, // Checks that a given real receiver type matches a desired receiver type (with the correct access) // Returns the pointer to the `Self` type, or nullptr if there's a mismatch -const ::HIR::TypeRef* TraitResolution::check_method_receiver(const Span& sp, ::HIR::Function::Receiver receiver, const ::HIR::TypeRef& ty, TraitResolution::MethodAccess access) const +const ::HIR::TypeRef* TraitResolution::check_method_receiver(const Span& sp, const ::HIR::Function& fcn, const ::HIR::TypeRef& ty, TraitResolution::MethodAccess access) const { - switch(receiver) + switch(fcn.m_receiver) { case ::HIR::Function::Receiver::Free: // Free functions are never usable @@ -3768,6 +3771,21 @@ const ::HIR::TypeRef* TraitResolution::check_method_receiver(const Span& sp, ::H break; case ::HIR::Function::Receiver::Custom: // TODO: Handle custom-receiver functions + // - match_test_generics, if it succeeds return the matched Self + { + const ::HIR::TypeRef* detected_self_ty = nullptr; + auto cb_getself = [&](auto idx, const auto& /*name*/, const auto& ty)->::HIR::Compare{ + if( idx == 0xFFFF ) + { + detected_self_ty = &ty; + } + return ::HIR::Compare::Equal; + }; + if( fcn.m_args.front().second .match_test_generics(sp, ty, this->m_ivars.callback_resolve_infer(), cb_getself) ) { + assert(detected_self_ty); + return detected_self_ty; + } + } return nullptr; case ::HIR::Function::Receiver::Box: if(const auto* ity = this->type_is_owned_box(sp, ty)) @@ -3808,16 +3826,18 @@ bool TraitResolution::find_method(const Span& sp, assert(e.trait.m_trait_ptr); // 1. Find the named method in the trait. ::HIR::GenericPath final_trait_path; - ::HIR::Function::Receiver receiver; - if( !this->trait_contains_method(sp, e.trait.m_path, *e.trait.m_trait_ptr, e.type, method_name, receiver, final_trait_path) ) { + const ::HIR::Function* fcn_ptr; + if( !(fcn_ptr = this->trait_contains_method(sp, e.trait.m_path, *e.trait.m_trait_ptr, e.type, method_name, final_trait_path)) ) { DEBUG("- Method '" << method_name << "' missing"); continue ; } DEBUG("- Found trait " << final_trait_path << " (bound)"); // 2. Compare the receiver of the above to this type and the bound. - if(const auto* self_ty = check_method_receiver(sp, receiver, ty, access)) + if(const auto* self_ty = check_method_receiver(sp, *fcn_ptr, ty, access)) { + if( self_ty->m_data.is_Infer() ) + return false; // TODO: Do a fuzzy match here? auto cmp = self_ty->compare_with_placeholders(sp, e.type, cb_infer); if( cmp == ::HIR::Compare::Equal ) @@ -3886,12 +3906,11 @@ bool TraitResolution::find_method(const Span& sp, const auto& trait = this->m_crate.get_trait_by_path(sp, e.m_trait.m_path.m_path); ::HIR::GenericPath final_trait_path; - ::HIR::Function::Receiver receiver; - if( this->trait_contains_method(sp, e.m_trait.m_path, trait, ::HIR::TypeRef("Self", 0xFFFF), method_name, receiver, final_trait_path) ) + if( const auto* fcn_ptr = this->trait_contains_method(sp, e.m_trait.m_path, trait, ::HIR::TypeRef("Self", 0xFFFF), method_name, final_trait_path) ) { DEBUG("- Found trait " << final_trait_path); // - If the receiver is valid, then it's correct (no need to check the type again) - if(const auto* self_ty_p = check_method_receiver(sp, receiver, ty, access)) + if(const auto* self_ty_p = check_method_receiver(sp, *fcn_ptr, ty, access)) { possibilities.push_back(::std::make_pair(borrow_type, ::HIR::Path(self_ty_p->clone(), mv$(final_trait_path), method_name, {}) )); rv = true; @@ -3909,12 +3928,11 @@ bool TraitResolution::find_method(const Span& sp, const auto& trait = this->m_crate.get_trait_by_path(sp, trait_path.m_path.m_path); ::HIR::GenericPath final_trait_path; - ::HIR::Function::Receiver receiver; - if( this->trait_contains_method(sp, trait_path.m_path, trait, ::HIR::TypeRef("Self", 0xFFFF), method_name, receiver, final_trait_path) ) + if( const auto* fcn_ptr = this->trait_contains_method(sp, trait_path.m_path, trait, ::HIR::TypeRef("Self", 0xFFFF), method_name, final_trait_path) ) { DEBUG("- Found trait " << final_trait_path); - if(const auto* self_ty_p = check_method_receiver(sp, receiver, ty, access)) + if(const auto* self_ty_p = check_method_receiver(sp, *fcn_ptr, ty, access)) { possibilities.push_back(::std::make_pair(borrow_type, ::HIR::Path(self_ty_p->clone(), mv$(final_trait_path), method_name, {}) )); rv = true; @@ -3961,21 +3979,22 @@ bool TraitResolution::find_method(const Span& sp, { ASSERT_BUG(sp, bound.m_trait_ptr, "Pointer to trait " << bound.m_path << " not set in " << e.trait.m_path); ::HIR::GenericPath final_trait_path; - ::HIR::Function::Receiver receiver; - if( !this->trait_contains_method(sp, bound.m_path, *bound.m_trait_ptr, ::HIR::TypeRef("Self", 0xFFFF), method_name, receiver, final_trait_path) ) - continue ; - DEBUG("- Found trait " << final_trait_path); - if(const auto* self_ty_p = check_method_receiver(sp, receiver, ty, access)) + if( const auto* fcn_ptr = this->trait_contains_method(sp, bound.m_path, *bound.m_trait_ptr, ::HIR::TypeRef("Self", 0xFFFF), method_name, final_trait_path) ) { - if( monomorphise_pathparams_needed(final_trait_path.m_params) ) { - final_trait_path.m_params = monomorphise_path_params_with(sp, final_trait_path.m_params, monomorph_cb, false); - DEBUG("- Monomorph to " << final_trait_path); - } + DEBUG("- Found trait " << final_trait_path); - // Found the method, return the UFCS path for it - possibilities.push_back(::std::make_pair( borrow_type, ::HIR::Path(self_ty_p->clone(), mv$(final_trait_path), method_name, {}) )); - rv = true; + if(const auto* self_ty_p = check_method_receiver(sp, *fcn_ptr, ty, access)) + { + if( monomorphise_pathparams_needed(final_trait_path.m_params) ) { + final_trait_path.m_params = monomorphise_path_params_with(sp, final_trait_path.m_params, monomorph_cb, false); + DEBUG("- Monomorph to " << final_trait_path); + } + + // Found the method, return the UFCS path for it + possibilities.push_back(::std::make_pair( borrow_type, ::HIR::Path(self_ty_p->clone(), mv$(final_trait_path), method_name, {}) )); + rv = true; + } } } @@ -3999,21 +4018,21 @@ bool TraitResolution::find_method(const Span& sp, // Found such a bound, now to test if it is useful ::HIR::GenericPath final_trait_path; - ::HIR::Function::Receiver receiver; - if( !this->trait_contains_method(sp, be.trait.m_path, *be.trait.m_trait_ptr, ::HIR::TypeRef("Self", 0xFFFF), method_name, receiver, final_trait_path) ) - continue ; - DEBUG("- Found trait " << final_trait_path); - - if(const auto* self_ty_p = check_method_receiver(sp, receiver, ty, access)) + if( const auto* fcn_ptr = this->trait_contains_method(sp, be.trait.m_path, *be.trait.m_trait_ptr, ::HIR::TypeRef("Self", 0xFFFF), method_name, final_trait_path) ) { - if( monomorphise_pathparams_needed(final_trait_path.m_params) ) { - final_trait_path.m_params = monomorphise_path_params_with(sp, final_trait_path.m_params, monomorph_cb, false); - DEBUG("- Monomorph to " << final_trait_path); - } + DEBUG("- Found trait " << final_trait_path); - // Found the method, return the UFCS path for it - possibilities.push_back(::std::make_pair( borrow_type, ::HIR::Path(self_ty_p->clone(), mv$(final_trait_path), method_name, {}) )); - rv = true; + if(const auto* self_ty_p = check_method_receiver(sp, *fcn_ptr, ty, access)) + { + if( monomorphise_pathparams_needed(final_trait_path.m_params) ) { + final_trait_path.m_params = monomorphise_path_params_with(sp, final_trait_path.m_params, monomorph_cb, false); + DEBUG("- Monomorph to " << final_trait_path); + } + + // Found the method, return the UFCS path for it + possibilities.push_back(::std::make_pair( borrow_type, ::HIR::Path(self_ty_p->clone(), mv$(final_trait_path), method_name, {}) )); + rv = true; + } } } } @@ -4033,7 +4052,7 @@ bool TraitResolution::find_method(const Span& sp, if( it == impl.m_methods.end() ) return false ; const ::HIR::Function& fcn = it->second.data; - if( const auto* self_ty_p = this->check_method_receiver(sp, fcn.m_receiver, ty, access) ) + if( const auto* self_ty_p = this->check_method_receiver(sp, fcn, ty, access) ) { DEBUG("Found `impl" << impl.m_params.fmt_args() << " " << impl.m_type << "` fn " << method_name/* << " - " << top_ty*/); if( *self_ty_p == *cur_check_ty ) @@ -4069,12 +4088,12 @@ bool TraitResolution::find_method(const Span& sp, break; ::HIR::GenericPath final_trait_path; - ::HIR::Function::Receiver receiver; - if( !this->trait_contains_method(sp, *trait_ref.first, *trait_ref.second, ::HIR::TypeRef("Self", 0xFFFF), method_name, receiver, final_trait_path) ) + const ::HIR::Function* fcn_ptr; + if( !(fcn_ptr = this->trait_contains_method(sp, *trait_ref.first, *trait_ref.second, ::HIR::TypeRef("Self", 0xFFFF), method_name, final_trait_path)) ) continue ; DEBUG("- Found trait " << final_trait_path); - if( const auto* self_ty_p = check_method_receiver(sp, receiver, ty, access) ) + if( const auto* self_ty_p = check_method_receiver(sp, *fcn_ptr, ty, access) ) { const auto& self_ty = *self_ty_p; DEBUG("Search for impl of " << *trait_ref.first << " for " << self_ty); diff --git a/src/hir_typeck/helpers.hpp b/src/hir_typeck/helpers.hpp index e7a917f4..7868b93f 100644 --- a/src/hir_typeck/helpers.hpp +++ b/src/hir_typeck/helpers.hpp @@ -262,7 +262,7 @@ public: Move, }; private: - const ::HIR::TypeRef* check_method_receiver(const Span& sp, ::HIR::Function::Receiver receiver, const ::HIR::TypeRef& ty, TraitResolution::MethodAccess access) const; + const ::HIR::TypeRef* check_method_receiver(const Span& sp, const ::HIR::Function& fcn, const ::HIR::TypeRef& ty, TraitResolution::MethodAccess access) const; public: enum class AllowedReceivers { All, @@ -278,7 +278,7 @@ public: ) const; /// Locates a named method in a trait, and returns the path of the trait that contains it (with fixed parameters) - bool trait_contains_method(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const ::HIR::TypeRef& self, const ::std::string& name, ::HIR::Function::Receiver& out_receiver, ::HIR::GenericPath& out_path) const; + const ::HIR::Function* trait_contains_method(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const ::HIR::TypeRef& self, const ::std::string& name, ::HIR::GenericPath& out_path) const; bool trait_contains_type(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const ::std::string& name, ::HIR::GenericPath& out_path) const; ::HIR::Compare type_is_sized(const Span& sp, const ::HIR::TypeRef& ty) const; -- cgit v1.2.3 From 5ad533aca561e3daaaf5c7e492ccc5b6a3c99d1b Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 3 Aug 2018 23:25:55 +0800 Subject: HIR Typecheck - Handle UfcsUnknown in fuzzy matching --- src/hir_expand/ufcs_everything.cpp | 8 ++++---- src/hir_typeck/expr_check.cpp | 8 ++++---- src/hir_typeck/helpers.cpp | 4 ++++ 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/hir_expand/ufcs_everything.cpp b/src/hir_expand/ufcs_everything.cpp index 629dd284..97947f4a 100644 --- a/src/hir_expand/ufcs_everything.cpp +++ b/src/hir_expand/ufcs_everything.cpp @@ -353,10 +353,10 @@ namespace { { case ::HIR::ExprNode_BinOp::Op::CmpEqu: { langitem = "eq"; method = "eq"; } if(0) case ::HIR::ExprNode_BinOp::Op::CmpNEqu:{ langitem = "eq"; method = "ne"; } if(0) - case ::HIR::ExprNode_BinOp::Op::CmpLt: { langitem = "ord"; method = "lt"; } if(0) - case ::HIR::ExprNode_BinOp::Op::CmpLtE: { langitem = "ord"; method = "le"; } if(0) - case ::HIR::ExprNode_BinOp::Op::CmpGt: { langitem = "ord"; method = "gt"; } if(0) - case ::HIR::ExprNode_BinOp::Op::CmpGtE: { langitem = "ord"; method = "ge"; } + case ::HIR::ExprNode_BinOp::Op::CmpLt: { langitem = TARGETVER_1_29 ? "partial_ord" : "ord"; method = "lt"; } if(0) + case ::HIR::ExprNode_BinOp::Op::CmpLtE: { langitem = TARGETVER_1_29 ? "partial_ord" : "ord"; method = "le"; } if(0) + case ::HIR::ExprNode_BinOp::Op::CmpGt: { langitem = TARGETVER_1_29 ? "partial_ord" : "ord"; method = "gt"; } if(0) + case ::HIR::ExprNode_BinOp::Op::CmpGtE: { langitem = TARGETVER_1_29 ? "partial_ord" : "ord"; method = "ge"; } { // 1. Check if the types are valid for primitive comparison if( ty_l == ty_r ) { diff --git a/src/hir_typeck/expr_check.cpp b/src/hir_typeck/expr_check.cpp index 985fe15f..8a199557 100644 --- a/src/hir_typeck/expr_check.cpp +++ b/src/hir_typeck/expr_check.cpp @@ -208,10 +208,10 @@ namespace { { case ::HIR::ExprNode_BinOp::Op::CmpEqu: item_name = "eq"; break; case ::HIR::ExprNode_BinOp::Op::CmpNEqu: item_name = "eq"; break; - case ::HIR::ExprNode_BinOp::Op::CmpLt: item_name = "ord"; break; - case ::HIR::ExprNode_BinOp::Op::CmpLtE: item_name = "ord"; break; - case ::HIR::ExprNode_BinOp::Op::CmpGt: item_name = "ord"; break; - case ::HIR::ExprNode_BinOp::Op::CmpGtE: item_name = "ord"; break; + case ::HIR::ExprNode_BinOp::Op::CmpLt: item_name = TARGETVER_1_29 ? "partial_ord" : "ord"; break; + case ::HIR::ExprNode_BinOp::Op::CmpLtE: item_name = TARGETVER_1_29 ? "partial_ord" : "ord"; break; + case ::HIR::ExprNode_BinOp::Op::CmpGt: item_name = TARGETVER_1_29 ? "partial_ord" : "ord"; break; + case ::HIR::ExprNode_BinOp::Op::CmpGtE: item_name = TARGETVER_1_29 ? "partial_ord" : "ord"; break; default: break; } assert(item_name); diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index 0e839219..1383300f 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -2812,6 +2812,10 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, if( ty.m_data.is_Infer() && !ty.m_data.as_Infer().is_lit() ) { return ::HIR::Compare::Fuzzy; } + // If the RHS is an unbound UfcsKnown, also fuzzy + if( ty.m_data.is_Path() && ty.m_data.as_Path().binding.is_Unbound() ) { + return ::HIR::Compare::Fuzzy; + } return ::HIR::Compare::Unequal; } }; -- cgit v1.2.3 From cd56b774f425b0c842556c3ddeeba708b0fe309f Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 4 Aug 2018 15:35:46 +0800 Subject: Trans - Add auto-generated Clone impls (only for Copy types currently) --- Makefile | 2 +- src/hir_typeck/static.cpp | 7 ++- src/main.cpp | 5 ++ src/mir/from_hir.cpp | 8 +++ src/mir/mir_ptr.hpp | 9 ++- src/trans/auto_impls.cpp | 130 ++++++++++++++++++++++++++++++++++++++++++++ src/trans/enumerate.cpp | 11 +++- src/trans/main_bindings.hpp | 2 + src/trans/trans_list.hpp | 6 ++ 9 files changed, 170 insertions(+), 10 deletions(-) create mode 100644 src/trans/auto_impls.cpp diff --git a/Makefile b/Makefile index 5b21f186..f2067a9c 100644 --- a/Makefile +++ b/Makefile @@ -115,7 +115,7 @@ OBJ += mir/check.o mir/cleanup.o mir/optimise.o OBJ += mir/check_full.o OBJ += hir/serialise.o hir/deserialise.o hir/serialise_lowlevel.o OBJ += trans/trans_list.o trans/mangling.o -OBJ += trans/enumerate.o trans/monomorphise.o trans/codegen.o +OBJ += trans/enumerate.o trans/auto_impls.o trans/monomorphise.o trans/codegen.o OBJ += trans/codegen_c.o trans/codegen_c_structured.o trans/codegen_mmir.o OBJ += trans/target.o trans/allocator.o diff --git a/src/hir_typeck/static.cpp b/src/hir_typeck/static.cpp index 016d86a0..84c73bfb 100644 --- a/src/hir_typeck/static.cpp +++ b/src/hir_typeck/static.cpp @@ -105,8 +105,11 @@ bool StaticTraitResolve::find_impl( } } else if( TARGETVER_1_29 && trait_path == m_lang_Clone ) { - if( this->type_is_clone(sp, type) ) { - return found_cb( ImplRef(&type, &null_params, &null_assoc), false ); + if( type.m_data.is_Tuple() || type.m_data.is_Array() || type.m_data.is_Function() ) + { + if( this->type_is_clone(sp, type) ) { + return found_cb( ImplRef(&type, &null_params, &null_assoc), false ); + } } } else if( trait_path == m_lang_Sized ) { diff --git a/src/main.cpp b/src/main.cpp index 85afcb33..7104acb7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -657,6 +657,11 @@ int main(int argc, char *argv[]) } throw ::std::runtime_error("Invalid crate_type value"); }); + // - Generate automatic impls (mainly Clone for 1.29) + CompilePhaseV("Trans Auto Impls", [&]() { + // TODO: Drop glue generation? + Trans_AutoImpls(*hir_crate, items); + }); // - Generate monomorphised versions of all functions CompilePhaseV("Trans Monomorph", [&]() { Trans_Monomorphise_List(*hir_crate, items); }); // - Do post-monomorph inlining diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index dc3b78a7..84d60082 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -1805,6 +1805,14 @@ namespace { mv$(values) })); } + if( fcn.m_abi == "platform-intrinsic" ) + { + m_builder.end_block(::MIR::Terminator::make_Call({ + next_block, panic_block, + res.clone(), ::MIR::CallTarget::make_Intrinsic({ "platform:"+gpath.m_path.m_components.back(), gpath.m_params.clone() }), + mv$(values) + })); + } // rustc has drop_in_place as a lang item, mrustc uses an intrinsic if( gpath.m_path == m_builder.crate().get_lang_item_path_opt("drop_in_place") ) diff --git a/src/mir/mir_ptr.hpp b/src/mir/mir_ptr.hpp index 9133dd44..27dd6b22 100644 --- a/src/mir/mir_ptr.hpp +++ b/src/mir/mir_ptr.hpp @@ -7,7 +7,6 @@ */ #pragma once - namespace MIR { class Function; @@ -32,10 +31,10 @@ public: void reset(); - ::MIR::Function* operator->() { return ptr; } - ::MIR::Function& operator*() { return *ptr; } - const ::MIR::Function* operator->() const { return ptr; } - const ::MIR::Function& operator*() const { return *ptr; } + ::MIR::Function* operator->() { if(!ptr) throw ""; return ptr; } + const ::MIR::Function* operator->() const { if(!ptr) throw ""; return ptr; } + ::MIR::Function& operator*() { if(!ptr) throw ""; return *ptr; } + const ::MIR::Function& operator*() const { if(!ptr) throw ""; return *ptr; } operator bool() const { return ptr != nullptr; } }; diff --git a/src/trans/auto_impls.cpp b/src/trans/auto_impls.cpp new file mode 100644 index 00000000..334d9eae --- /dev/null +++ b/src/trans/auto_impls.cpp @@ -0,0 +1,130 @@ +/* + * MRustC - Rust Compiler + * - By John Hodge (Mutabah/thePowersGang) + * + * trans/auto_impls.cpp + * - Automatic trait/method impls + * + * Handles implementing Clone (when in 1.29 mode) + */ +#include "main_bindings.hpp" +#include "trans_list.hpp" +#include +#include +#include // monomorph +#include // StaticTraitResolve +#include +#include // find_if + +namespace { + struct State + { + ::HIR::Crate& crate; + StaticTraitResolve resolve; + const TransList& trans_list; + ::std::deque<::HIR::TypeRef> todo_list; + ::std::set<::HIR::TypeRef> done_list; + + ::HIR::SimplePath lang_Clone; + + State(::HIR::Crate& crate, const TransList& trans_list): + crate(crate), + resolve( crate ), + trans_list(trans_list) + { + lang_Clone = crate.get_lang_item_path(Span(), "clone"); + } + + void enqueue_type(const ::HIR::TypeRef& ty) { + if( this->trans_list.auto_clone_impls.count(ty) == 0 && this->done_list.count(ty) == 0 ) { + this->done_list.insert( ty.clone() ); + this->todo_list.push_back( ty.clone() ); + } + } + }; +} + +void Trans_AutoImpl_Clone(State& state, ::HIR::TypeRef ty) +{ + Span sp; + TRACE_FUNCTION_F(ty); + + // Create MIR + ::MIR::Function mir_fcn; + if( state.resolve.type_is_copy(sp, ty) ) + { + ::MIR::BasicBlock bb; + bb.statements.push_back(::MIR::Statement::make_Assign({ + ::MIR::LValue::make_Return({}), + ::MIR::RValue::make_Use( ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Argument({ 0 })) }) ) + })); + bb.terminator = ::MIR::Terminator::make_Return({}); + mir_fcn.blocks.push_back(::std::move( bb )); + } + else + { + TODO(Span(), "auto Clone for " << ty << " - Not Copy"); + } + + // Function + ::HIR::Function fcn { + /*m_save_code=*/false, + ::HIR::Linkage {}, + ::HIR::Function::Receiver::BorrowShared, + /*m_abi=*/ABI_RUST, + /*m_unsafe =*/false, + /*m_const=*/false, + ::HIR::GenericParams {}, + /*m_args=*/::make_vec1(::std::make_pair( + ::HIR::Pattern( ::HIR::PatternBinding(false, ::HIR::PatternBinding::Type::Move, "self", 0), ::HIR::Pattern::Data::make_Any({}) ), + ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, ty.clone()) + )), + /*m_variadic=*/false, + /*m_return=*/ty.clone(), + ::HIR::ExprPtr {} + }; + fcn.m_code.m_mir = ::MIR::FunctionPointer( new ::MIR::Function(mv$(mir_fcn)) ); + + // Impl + ::HIR::TraitImpl impl; + impl.m_type = mv$(ty); + impl.m_methods.insert(::std::make_pair( ::std::string("clone"), ::HIR::TraitImpl::ImplEnt< ::HIR::Function> { false, ::std::move(fcn) } )); + + // Add impl to the crate + state.crate.m_trait_impls.insert(::std::make_pair( state.lang_Clone, ::std::move(impl) )); +} + +void Trans_AutoImpls(::HIR::Crate& crate, TransList& trans_list) +{ + State state { crate, trans_list }; + + // Generate for all + for(const auto& ty : trans_list.auto_clone_impls) + { + state.done_list.insert( ty.clone() ); + Trans_AutoImpl_Clone(state, ty.clone()); + } + + while( !state.todo_list.empty() ) + { + auto ty = ::std::move(state.todo_list.front()); + state.todo_list.pop_back(); + + Trans_AutoImpl_Clone(state, mv$(ty)); + } + + const auto impl_range = crate.m_trait_impls.equal_range( state.lang_Clone ); + for(const auto& ty : state.done_list) + { + // TODO: Find a way of turning a set into a vector so items can be erased. + + auto p = ::HIR::Path(ty.clone(), ::HIR::GenericPath(state.lang_Clone), "clone"); + //DEBUG("add_function(" << p << ")"); + auto e = trans_list.add_function(::std::move(p)); + + auto it = ::std::find_if( impl_range.first, impl_range.second, [&](const auto& i){ return i.second.m_type == ty; }); + assert( it->second.m_methods.size() == 1 ); + e->ptr = &it->second.m_methods.begin()->second.data; + } +} + diff --git a/src/trans/enumerate.cpp b/src/trans/enumerate.cpp index 4e04ddf9..e16f9dcf 100644 --- a/src/trans/enumerate.cpp +++ b/src/trans/enumerate.cpp @@ -1209,7 +1209,7 @@ namespace { DEBUG("[get_ent_fullpath] Found " << impl_ref); //ASSERT_BUG(sp, !is_fuzz, "Fuzzy match not allowed here"); if( ! impl_ref.m_data.is_TraitImpl() ) { - DEBUG("Trans impl search found an invalid impl type"); + DEBUG("Trans impl search found an invalid impl type - " << impl_ref.m_data.tag_str()); is_dynamic = true; // TODO: This can only really happen if it's a trait object magic impl, which should become a vtable lookup. return true; @@ -1380,6 +1380,14 @@ void Trans_Enumerate_FillFrom_Path(EnumState& state, const ::HIR::Path& path, co { // Must have been a dynamic dispatch request, just leave as-is } + // <* as Clone>::clone + else if( TARGETVER_1_29 && path_mono.m_data.is_UfcsKnown() && path_mono.m_data.as_UfcsKnown().trait == state.crate.get_lang_item_path_opt("clone") ) + { + const auto& pe = path_mono.m_data.as_UfcsKnown(); + ASSERT_BUG(sp, pe.item == "clone", ""); + // Add this type to a list of types that will have the impl auto-generated + state.rv.auto_clone_impls.insert( pe.type->clone() ); + } else { BUG(sp, "AutoGenerate returned for unknown path type - " << path_mono); @@ -1692,4 +1700,3 @@ void Trans_Enumerate_FillFrom(EnumState& state, const ::HIR::Static& item, Trans out_stat.ptr = &item; out_stat.pp = mv$(pp); } - diff --git a/src/trans/main_bindings.hpp b/src/trans/main_bindings.hpp index b938e8bf..096efe86 100644 --- a/src/trans/main_bindings.hpp +++ b/src/trans/main_bindings.hpp @@ -38,6 +38,8 @@ extern TransList Trans_Enumerate_Public(::HIR::Crate& crate); /// Re-run enumeration on monomorphised functions, removing now-unused items extern void Trans_Enumerate_Cleanup(const ::HIR::Crate& crate, TransList& list); +extern void Trans_AutoImpls(::HIR::Crate& crate, TransList& trans_list); + extern void Trans_Monomorphise_List(const ::HIR::Crate& crate, TransList& list); extern void Trans_Codegen(const ::std::string& outfile, const TransOptions& opt, const ::HIR::Crate& crate, const TransList& list, bool is_executable); diff --git a/src/trans/trans_list.hpp b/src/trans/trans_list.hpp index 48274f87..51e8af4b 100644 --- a/src/trans/trans_list.hpp +++ b/src/trans/trans_list.hpp @@ -52,6 +52,10 @@ struct TransList_Function Trans_Params pp; // If `pp.has_types` is true, the below is valid CachedFunction monomorphised; + + TransList_Function(): + ptr(nullptr) + {} }; struct TransList_Static { @@ -75,6 +79,8 @@ public: ::std::set< ::HIR::TypeRef> m_typeids; /// Required struct/enum constructor impls ::std::set< ::HIR::GenericPath> m_constructors; + // Automatic Clone impls + ::std::set< ::HIR::TypeRef> auto_clone_impls; // .second is `true` if this is a from a reference to the type ::std::vector< ::std::pair<::HIR::TypeRef, bool> > m_types; -- cgit v1.2.3 From 2d3ca13d000f392cca8bf17cf8969c96e80aa786 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 4 Aug 2018 15:36:30 +0800 Subject: Minicargo - Always print called processes --- tools/minicargo/build.cpp | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/tools/minicargo/build.cpp b/tools/minicargo/build.cpp index ea93a793..2f8fafe4 100644 --- a/tools/minicargo/build.cpp +++ b/tools/minicargo/build.cpp @@ -940,10 +940,18 @@ bool Builder::spawn_process(const char* exe_name, const StringList& args, const ::std::stringstream cmdline; cmdline << exe_name; for (const auto& arg : args.get_vec()) + // TODO: Escaping cmdline << " " << arg; auto cmdline_str = cmdline.str(); - DEBUG("Calling " << cmdline_str); - + if(true) + { + ::std::cout << "> " << cmdline_str << ::std::end;; + } + else + { + DEBUG("Calling " << cmdline_str); + } + #if 0 // TODO: Determine required minimal environment, to avoid importing the entire caller environment ::std::stringstream environ_str; @@ -1005,12 +1013,22 @@ bool Builder::spawn_process(const char* exe_name, const StringList& args, const // Generate `argv` auto argv = args.get_vec(); argv.insert(argv.begin(), exe_name); - //DEBUG("Calling " << argv); - Debug_Print([&](auto& os){ - os << "Calling"; + + if(true) + { + ::std::cout << ">"; for(const auto& p : argv) - os << " " << p; - }); + ::std::cout << " " << p; + ::std::cout << ::std::endl; + } + else + { + Debug_Print([&](auto& os){ + os << "Calling"; + for(const auto& p : argv) + os << " " << p; + }); + } DEBUG("Environment " << env); argv.push_back(nullptr); -- cgit v1.2.3 From 9fe41ffb9bde218ad97c5430d6cc92051634357d Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 4 Aug 2018 18:22:58 +0800 Subject: Codegen C - Fix a few bugs and add new/now-used intrinsics --- src/trans/codegen_c.cpp | 109 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 102 insertions(+), 7 deletions(-) diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 2ab4ff35..3947de9b 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -303,6 +303,18 @@ namespace { << "\treturn ((v&0xFFFFFFFF) == 0 ? __builtin_ctz(v>>32) + 32 : __builtin_ctz(v));\n" << "}\n" ; + // Atomic hackery + for(int sz = 8; sz <= 64; sz *= 2) + { + m_of + << "static inline uint"<>4]|(__mrustc_revmap[v&15]<<4); }\n" + << "static inline uint16_t __mrustc_bitrev16(uint16_t v) { if(v==0) return 0; uint16_t rv = ((uint16_t)__mrustc_bitrev8(v>>8))|((uint16_t)__mrustc_bitrev8(v)<<8); }\n" + << "static inline uint32_t __mrustc_bitrev32(uint32_t v) { if(v==0) return 0; uint32_t rv = ((uint32_t)__mrustc_bitrev16(v>>16))|((uint32_t)__mrustc_bitrev16(v)<<16); }\n" + << "static inline uint64_t __mrustc_bitrev64(uint64_t v) { if(v==0) return 0; uint64_t rv = ((uint64_t)__mrustc_bitrev32(v>>32))|((uint64_t)__mrustc_bitrev32(v)<<32); }\n" + // TODO: 128 ; + if( m_options.emulated_i128 ) + { + m_of << "static inline uint128_t __mrustc_bitrev128(uint128_t v) { uint128_t rv = { __mrustc_bitrev64(v>>64)), __mrustc_bitrev64(v) }; return rv; }\n"; + } + else + { + m_of << "static inline uint128_t __mrustc_bitrev128(uint128_t v) { if(v==0) return 0; uint128_t rv = ((uint128_t)__mrustc_bitrev64(v>>64))|((uint128_t)__mrustc_bitrev64(v)<<64); }\n"; + } + for(int sz = 8; sz <= 64; sz *= 2) + { + m_of + << "static inline uint"< b ? a : b); }\n" + << "static inline uint"< (int"<type_is_bad_zst(ty_dst) ) { @@ -4071,7 +4108,7 @@ namespace { } else if( e.args.at(0).is_Constant() ) { - m_of << "{ "; emit_ctype(ty_src, FMT_CB(s, s << "v";)); m_of << " = "; emit_param(e.args.at(0)); m_of << ";"; + m_of << "{ "; emit_ctype(ty_src, FMT_CB(s, s << "v";)); m_of << " = "; emit_param(e.args.at(0)); m_of << "; "; m_of << "memcpy( &"; emit_lvalue(e.ret_val); m_of << ", &v, sizeof("; emit_ctype(ty_dst); m_of << ")); "; m_of << "}"; } @@ -4103,7 +4140,7 @@ namespace { } else { - m_of << "memcpy( &"; emit_lvalue(e.ret_val); m_of << ", &"; emit_param(e.args.at(0)); m_of << ", sizeof("; emit_ctype(params.m_types.at(0)); m_of << "))"; + m_of << "memcpy( &"; emit_lvalue(e.ret_val); m_of << ", &"; emit_param(e.args.at(0)); m_of << ", sizeof("; emit_ctype(ty_src); m_of << "))"; } } else if( name == "copy_nonoverlapping" || name == "copy" ) { @@ -4236,6 +4273,22 @@ namespace { m_of << "("; emit_param(e.args.at(0)); m_of << ")"; } } + else if( name == "bitreverse" ) { + const auto& ty = params.m_types.at(0); + MIR_ASSERT(mir_res, ty.m_data.is_Primitive(), "Invalid type passed to bitreverse. Must be a primitive, got " << ty); + emit_lvalue(e.ret_val); m_of << " = "; + switch(get_prim_size(ty)) + { + case 8: m_of << "__mrustc_bitrev8"; break; + case 16: m_of << "__mrustc_bitrev16"; break; + case 32: m_of << "__mrustc_bitrev32"; break; + case 64: m_of << "__mrustc_bitrev64"; break; + case 128: m_of << "__mrustc_bitrev128"; break; + default: + MIR_TODO(mir_res, "bswap<" << ty << ">"); + } + m_of << "("; emit_param(e.args.at(0)); m_of << ")"; + } // > Obtain the discriminane of a &T as u64 else if( name == "discriminant_value" ) { const auto& ty = params.m_types.at(0); @@ -4442,7 +4495,8 @@ namespace { } } // Unchecked Arithmatic - else if( name == "unchecked_div" ) { + // - exact_div is UB to call on a non-multiple + else if( name == "unchecked_div" || name == "exact_div") { emit_lvalue(e.ret_val); m_of << " = "; if( type_is_emulated_i128(params.m_types.at(0)) ) { @@ -4515,7 +4569,7 @@ namespace { // Bit Twiddling // - CounT Leading Zeroes // - CounT Trailing Zeroes - else if( name == "ctlz" || name == "ctlz_nonzero" || name == "cttz" ) { + else if( name == "ctlz" || name == "ctlz_nonzero" || name == "cttz" || name == "cttz_nonzero" ) { auto emit_arg0 = [&](){ emit_param(e.args.at(0)); }; const auto& ty = params.m_types.at(0); emit_lvalue(e.ret_val); m_of << " = ("; @@ -4647,6 +4701,11 @@ namespace { else if( name == "volatile_store" ) { m_of << "*(volatile "; emit_ctype(params.m_types.at(0)); m_of << "*)"; emit_param(e.args.at(0)); m_of << " = "; emit_param(e.args.at(1)); } + else if( name == "nontemporal_store" ) { + // TODO: Actually do a non-temporal store + // GCC: _mm_stream_* (depending on input type, which must be `repr(simd)`) + m_of << "*(volatile "; emit_ctype(params.m_types.at(0)); m_of << "*)"; emit_param(e.args.at(0)); m_of << " = "; emit_param(e.args.at(1)); + } // --- Atomics! // > Single-ordering atomics else if( name == "atomic_xadd" || name.compare(0, 7+4+1, "atomic_xadd_") == 0 ) { @@ -4661,6 +4720,13 @@ namespace { auto ordering = get_atomic_ordering(name, 7+3+1); emit_atomic_arith(AtomicOp::And, ordering); } + else if( name == "atomic_nand" || name.compare(0, 7+4+1, "atomic_nand_") == 0 ) { + auto ordering = get_atomic_ordering(name, 7+4+1); + const auto& ty = params.m_types.at(0); + emit_lvalue(e.ret_val); m_of << " = __mrustc_atomicloop" << get_prim_size(ty) << "("; + emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", " << get_atomic_ty_gcc(ordering) << ", __mrustc_op_and_not" << get_prim_size(ty); + m_of << ")"; + } else if( name == "atomic_or" || name.compare(0, 7+2+1, "atomic_or_") == 0 ) { auto ordering = get_atomic_ordering(name, 7+2+1); emit_atomic_arith(AtomicOp::Or, ordering); @@ -4669,6 +4735,24 @@ namespace { auto ordering = get_atomic_ordering(name, 7+3+1); emit_atomic_arith(AtomicOp::Xor, ordering); } + else if( name == "atomic_max" || name.compare(0, 7+3+1, "atomic_max_") == 0 + || name == "atomic_min" || name.compare(0, 7+3+1, "atomic_min_") == 0 ) { + auto ordering = get_atomic_ordering(name, 7+3+1); + const auto& ty = params.m_types.at(0); + const char* op = (name[7+1] == 'a' ? "imax" : "imin"); // m'a'x vs m'i'n + emit_lvalue(e.ret_val); m_of << " = __mrustc_atomicloop" << get_prim_size(ty) << "("; + emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", " << get_atomic_ty_gcc(ordering) << ", __mrustc_op_" << op << get_prim_size(ty); + m_of << ")"; + } + else if( name == "atomic_umax" || name.compare(0, 7+4+1, "atomic_umax_") == 0 + || name == "atomic_umin" || name.compare(0, 7+4+1, "atomic_umin_") == 0 ) { + auto ordering = get_atomic_ordering(name, 7+4+1); + const auto& ty = params.m_types.at(0); + const char* op = (name[7+2] == 'a' ? "umax" : "umin"); // m'a'x vs m'i'n + emit_lvalue(e.ret_val); m_of << " = __mrustc_atomicloop" << get_prim_size(ty) << "("; + emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", " << get_atomic_ty_gcc(ordering) << ", __mrustc_op_" << op << get_prim_size(ty); + m_of << ")"; + } else if( name == "atomic_load" || name.compare(0, 7+4+1, "atomic_load_") == 0 ) { auto ordering = get_atomic_ordering(name, 7+4+1); emit_lvalue(e.ret_val); m_of << " = "; @@ -4779,6 +4863,11 @@ namespace { else if( name == "atomic_singlethreadfence" || name.compare(0, 7+18, "atomic_singlethreadfence_") == 0 ) { // TODO: Does this matter? } + // -- Platform Intrinsics -- + else if( name.compare(0, 9, "platform:") == 0 ) { + // TODO: Platform intrinsics + m_of << "abort() /* TODO: Platform intrinsic \"" << name << "\" */"; + } else { MIR_BUG(mir_res, "Unknown intrinsic '" << name << "'"); } @@ -5339,10 +5428,16 @@ namespace { // TODO: This should have been eliminated? ("MIR Cleanup" should have removed all inline Const references) ::HIR::TypeRef ty; const auto& lit = get_literal_for_const(c.p, ty); - if(lit.is_Integer() || lit.is_Float() || lit.is_String()) + if(lit.is_Integer() || lit.is_Float()) { emit_literal(ty, lit, {}); } + else if( lit.is_String()) + { + m_of << "make_sliceptr("; + this->print_escaped_string( lit.as_String() ); + m_of << ", " << ::std::dec << lit.as_String().size() << ")"; + } else { // NOTE: GCC hack - statement expressions -- cgit v1.2.3 From e42b7877ac1f7c173d42600b220b1f50a143b9b4 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Wed, 3 Oct 2018 20:50:30 +0800 Subject: Fiddling for rustc 1.29 update --- Makefile | 10 ++++------ rust-version | 2 +- rust_src.patch | 26 -------------------------- rustc-1.19.0-src.patch | 26 ++++++++++++++++++++++++++ rustc-1.29.0-src.patch | 25 +++++++++++++++++++++++++ src/expand/lang_item.cpp | 27 +++++++++++++++++++++++++++ src/expand/mod.cpp | 2 ++ src/hir/hir.hpp | 1 + src/hir_conv/constant_evaluation.cpp | 22 +++++++++++++++++++++- src/parse/types.cpp | 36 ++++++++++++++++++++++++++++++++++++ 10 files changed, 143 insertions(+), 34 deletions(-) delete mode 100644 rust_src.patch create mode 100644 rustc-1.19.0-src.patch create mode 100644 rustc-1.29.0-src.patch diff --git a/Makefile b/Makefile index f2067a9c..371cb640 100644 --- a/Makefile +++ b/Makefile @@ -17,8 +17,6 @@ EXESUF ?= CXX ?= g++ V ?= @ -TARGET_CC ?= clang - TAIL_COUNT ?= 10 # - Disable implicit rules @@ -177,13 +175,13 @@ rustc-nightly-src.tar.gz: $(RUSTC_SRC_DES) curl -sS https://static.rust-lang.org/dist/$${DL_RUST_DATE}/rustc-nightly-src.tar.gz -o rustc-nightly-src.tar.gz # TODO: Handle non-nightly download -$(RUSTC_SRC_DL): rust-nightly-date rustc-nightly-src.tar.gz rust_src.patch +$(RUSTC_SRC_DL): rust-nightly-date rustc-nightly-src.tar.gz rustc-nightly-src.patch @export DL_RUST_DATE=$$(cat rust-nightly-date); \ export DISK_RUST_DATE=$$([ -f $(RUSTC_SRC_DL) ] && cat $(RUSTC_SRC_DL)); \ if [ "$$DL_RUST_DATE" != "$$DISK_RUST_DATE" ]; then \ rm -rf rustc-nightly-src; \ tar -xf rustc-nightly-src.tar.gz; \ - cd $(RUSTSRC) && patch -p0 < ../rust_src.patch; \ + cd $(RUSTSRC) && patch -p0 < ../rustc-nightly-src.patch; \ fi cat rust-nightly-date > $(RUSTC_SRC_DL) else @@ -192,9 +190,9 @@ $(RUSTC_SRC_TARBALL): $(RUSTC_SRC_DES) @echo [CURL] $@ @rm -f $@ @curl -sS https://static.rust-lang.org/dist/$@ -o $@ -$(RUSTC_SRC_DL): $(RUSTC_SRC_TARBALL) rust_src.patch +$(RUSTC_SRC_DL): $(RUSTC_SRC_TARBALL) rustc-$(shell cat $(RUSTC_SRC_DES))-src.patch tar -xf $(RUSTC_SRC_TARBALL) - cd $(RUSTCSRC) && patch -p0 < ../rust_src.patch; + cd $(RUSTCSRC) && patch -p0 < ../rustc-$(shell cat $(RUSTC_SRC_DES))-src.patch; cat $(RUSTC_SRC_DES) > $(RUSTC_SRC_DL) endif diff --git a/rust-version b/rust-version index 815d5ca0..5e57fb89 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1.19.0 +1.29.0 diff --git a/rust_src.patch b/rust_src.patch deleted file mode 100644 index 1cc13242..00000000 --- a/rust_src.patch +++ /dev/null @@ -1,26 +0,0 @@ ---- src/libcore/intrinsics.rs -+++ src/libcore/intrinsics.rs -@@ -678,5 +678,9 @@ - pub fn min_align_of_val(_: &T) -> usize; - -+ /// Obtain the length of a slice pointer -+ #[cfg(rust_compiler="mrustc")] -+ pub fn mrustc_slice_len(pointer: *const [T]) -> usize; -+ - /// Gets a static string slice containing the name of a type. - pub fn type_name() -> &'static str; - ---- src/libcore/slice/mod.rs -+++ src/libcore/slice/mod.rs -@@ -413,6 +413,8 @@ - #[inline] - fn len(&self) -> usize { -- unsafe { -- mem::transmute::<&[T], Repr>(self).len -- } -+ #[cfg(not(rust_compiler="mrustc"))] -+ let rv = unsafe { mem::transmute::<&[T], Repr>(self).len }; -+ #[cfg(rust_compiler="mrustc")] -+ let rv = unsafe { ::intrinsics::mrustc_slice_len(self) }; -+ rv - } diff --git a/rustc-1.19.0-src.patch b/rustc-1.19.0-src.patch new file mode 100644 index 00000000..1cc13242 --- /dev/null +++ b/rustc-1.19.0-src.patch @@ -0,0 +1,26 @@ +--- src/libcore/intrinsics.rs ++++ src/libcore/intrinsics.rs +@@ -678,5 +678,9 @@ + pub fn min_align_of_val(_: &T) -> usize; + ++ /// Obtain the length of a slice pointer ++ #[cfg(rust_compiler="mrustc")] ++ pub fn mrustc_slice_len(pointer: *const [T]) -> usize; ++ + /// Gets a static string slice containing the name of a type. + pub fn type_name() -> &'static str; + +--- src/libcore/slice/mod.rs ++++ src/libcore/slice/mod.rs +@@ -413,6 +413,8 @@ + #[inline] + fn len(&self) -> usize { +- unsafe { +- mem::transmute::<&[T], Repr>(self).len +- } ++ #[cfg(not(rust_compiler="mrustc"))] ++ let rv = unsafe { mem::transmute::<&[T], Repr>(self).len }; ++ #[cfg(rust_compiler="mrustc")] ++ let rv = unsafe { ::intrinsics::mrustc_slice_len(self) }; ++ rv + } diff --git a/rustc-1.29.0-src.patch b/rustc-1.29.0-src.patch new file mode 100644 index 00000000..df6ef8f5 --- /dev/null +++ b/rustc-1.29.0-src.patch @@ -0,0 +1,25 @@ +--- src/libcore/intrinsics.rs ++++ src/libcore/intrinsics.rs +@@ -678,5 +678,9 @@ + pub fn min_align_of_val(_: &T) -> usize; + ++ /// Obtain the length of a slice pointer ++ #[cfg(rust_compiler="mrustc")] ++ pub fn mrustc_slice_len(pointer: *const [T]) -> usize; ++ + /// Gets a static string slice containing the name of a type. + pub fn type_name() -> &'static str; + +--- src/libcore/slice/mod.rs ++++ src/libcore/slice/mod.rs +@@ -413,5 +413,7 @@ + pub const fn len(&self) -> usize { +- unsafe { +- Repr { rust: self }.raw.len +- } ++ #[cfg(not(rust_compiler="mrustc"))] ++ let rv = unsafe { Repr { rust: self }.raw.len }; ++ #[cfg(rust_compiler="mrustc")] ++ let rv = unsafe { ::intrinsics::mrustc_slice_len(self) }; ++ rv + } diff --git a/src/expand/lang_item.cpp b/src/expand/lang_item.cpp index 62527ac9..0bdd37e5 100644 --- a/src/expand/lang_item.cpp +++ b/src/expand/lang_item.cpp @@ -88,6 +88,7 @@ void handle_lang_item(const Span& sp, AST::Crate& crate, const AST::Path& path, else if( name == "unsafe_cell" ) { } else if( TARGETVER_1_29 && name == "alloc_layout") { } else if( TARGETVER_1_29 && name == "panic_info" ) {} // Struct + else if( TARGETVER_1_29 && name == "manually_drop" ) {} // Struct // Generators else if( TARGETVER_1_29 && name == "generator" ) {} // - Trait @@ -114,6 +115,32 @@ void handle_lang_item(const Span& sp, AST::Crate& crate, const AST::Path& path, else if( name == "start" ) { } else if( name == "eh_personality" ) { } + // libcompiler_builtins + // - i128/u128 helpers (not used by mrustc) + else if( name == "i128_add" ) { } + else if( name == "i128_addo" ) { } + else if( name == "u128_add" ) { } + else if( name == "u128_addo" ) { } + else if( name == "i128_sub" ) { } + else if( name == "i128_subo" ) { } + else if( name == "u128_sub" ) { } + else if( name == "u128_subo" ) { } + else if( name == "i128_mul" ) { } + else if( name == "i128_mulo" ) { } + else if( name == "u128_mul" ) { } + else if( name == "u128_mulo" ) { } + else if( name == "i128_div" ) { } + else if( name == "i128_rem" ) { } + else if( name == "u128_div" ) { } + else if( name == "u128_rem" ) { } + else if( name == "i128_shl" ) { } + else if( name == "i128_shlo" ) { } + else if( name == "u128_shl" ) { } + else if( name == "u128_shlo" ) { } + else if( name == "i128_shr" ) { } + else if( name == "i128_shro" ) { } + else if( name == "u128_shr" ) { } + else if( name == "u128_shro" ) { } else { ERROR(sp, E0000, "Unknown language item '" << name << "'"); diff --git a/src/expand/mod.cpp b/src/expand/mod.cpp index a0cc3f7b..66a7308a 100644 --- a/src/expand/mod.cpp +++ b/src/expand/mod.cpp @@ -772,6 +772,7 @@ struct CExpandExpr: case ::AST::ExprNode_BinOp::RANGE_INC: { // NOTE: Not language items auto core_crate = (crate.m_load_std == ::AST::Crate::LOAD_NONE ? "" : "core"); + auto path_None = ::AST::Path(core_crate, { ::AST::PathNode("option"), ::AST::PathNode("Option"), ::AST::PathNode("None") }); auto path_RangeInclusive_NonEmpty = ::AST::Path(core_crate, { ::AST::PathNode("ops"), ::AST::PathNode("RangeInclusive") }); auto path_RangeToInclusive = ::AST::Path(core_crate, { ::AST::PathNode("ops"), ::AST::PathNode("RangeToInclusive") }); @@ -780,6 +781,7 @@ struct CExpandExpr: ::AST::ExprNode_StructLiteral::t_values values; values.push_back({ {}, "start", mv$(node.m_left) }); values.push_back({ {}, "end" , mv$(node.m_right) }); + values.push_back({ {}, "is_empty", ::AST::ExprNodeP(new ::AST::ExprNode_NamedValue(mv$(path_None))) }); replacement.reset( new ::AST::ExprNode_StructLiteral(mv$(path_RangeInclusive_NonEmpty), nullptr, mv$(values)) ); } else diff --git a/src/hir/hir.hpp b/src/hir/hir.hpp index daa27d10..d693c61d 100644 --- a/src/hir/hir.hpp +++ b/src/hir/hir.hpp @@ -50,6 +50,7 @@ struct VisEnt /// NOTE: Intentionally minimal, just covers the values (not the types) TAGGED_UNION(Literal, Invalid, (Invalid, struct {}), + (Defer, struct {}), // List = Array, Tuple, struct literal (List, ::std::vector), // TODO: Have a variant for repetition lists // Variant = Enum variant diff --git a/src/hir_conv/constant_evaluation.cpp b/src/hir_conv/constant_evaluation.cpp index a2847e04..34830f79 100644 --- a/src/hir_conv/constant_evaluation.cpp +++ b/src/hir_conv/constant_evaluation.cpp @@ -15,6 +15,8 @@ #include #include +#define CHECK_DEFER(var) do { if( var.is_Defer() ) { m_rv = ::HIR::Literal::make_Defer({}); return ; } } while(0) + namespace { typedef ::std::vector< ::std::pair< ::std::string, ::HIR::Static> > t_new_values; @@ -332,10 +334,12 @@ namespace { TRACE_FUNCTION_F("_BinOp"); node.m_left->visit(*this); + CHECK_DEFER(m_rv); auto left = mv$(m_rv); auto ret_type = mv$(m_rv_type); node.m_right->visit(*this); + CHECK_DEFER(m_rv); auto right = mv$(m_rv); if( left.tag() != right.tag() ) { @@ -601,6 +605,7 @@ namespace { ::std::vector< ::HIR::Literal> vals; for(const auto& vn : node.m_args ) { vn->visit(*this); + CHECK_DEFER(m_rv); assert( !m_rv.is_Invalid() ); vals.push_back( mv$(m_rv) ); } @@ -824,7 +829,13 @@ namespace { auto ep = get_ent_fullpath(node.span(), m_crate, node.m_path, EntNS::Value); TU_MATCH_DEF( EntPtr, (ep), (e), ( - BUG(node.span(), "Path value with unsupported value type - " << ep.tag_str()); + BUG(node.span(), "_PathValue(" << node.m_path << ") with unsupported value type - " << ep.tag_str()); + ), + (NotFound, + // If the value can't be found, and it's an associated constant, return a literal indicating + // that the value can't yet be evaluated. + DEBUG(node.span() << " - _PathValue(" << node.m_path << ") not found"); + m_rv = ::HIR::Literal::make_Defer({}); ), (Static, // TODO: Should be a more complex path to support associated paths @@ -915,6 +926,7 @@ namespace { } val_set.second->visit(*this); + CHECK_DEFER(m_rv); vals[idx] = mv$(m_rv); } for( unsigned int i = 0; i < vals.size(); i ++ ) { @@ -962,6 +974,7 @@ namespace { m_exp_type = mv$(exp_tys[i]); node.m_vals[i]->visit(*this); + CHECK_DEFER(m_rv); assert( !m_rv.is_Invalid() ); vals.push_back( mv$(m_rv) ); @@ -994,6 +1007,7 @@ namespace { { m_exp_type = exp_inner_ty.clone(); vn->visit(*this); + CHECK_DEFER(m_rv); assert( !m_rv.is_Invalid() ); vals.push_back( mv$(m_rv) ); } @@ -1029,6 +1043,7 @@ namespace { { m_exp_type = mv$(exp_inner_ty); node.m_val->visit(*this); + CHECK_DEFER(m_rv); assert( !m_rv.is_Invalid() ); for(unsigned int i = 0; i < count-1; i ++) { @@ -1285,6 +1300,11 @@ namespace { (BinOp, auto inval_l = read_param(e.val_l); auto inval_r = read_param(e.val_r); + if( inval_l.is_Invalid() || inval_r.is_Invalid() ) + { + val = ::HIR::Literal::make_Invalid({}); + break ; + } ASSERT_BUG(sp, inval_l.tag() == inval_r.tag(), "Mismatched literal types in binop - " << inval_l << " and " << inval_r); TU_MATCH_DEF( ::HIR::Literal, (inval_l, inval_r), (l, r), ( diff --git a/src/parse/types.cpp b/src/parse/types.cpp index a07e66f8..db66a77e 100644 --- a/src/parse/types.cpp +++ b/src/parse/types.cpp @@ -15,6 +15,7 @@ TypeRef Parse_Type_Int(TokenStream& lex, bool allow_trait_list); TypeRef Parse_Type_Fn(TokenStream& lex, AST::HigherRankedBounds hrbs = {}); TypeRef Parse_Type_Path(TokenStream& lex, AST::HigherRankedBounds hrbs, bool allow_trait_list); +TypeRef Parse_Type_TraitObject(TokenStream& lex, ::AST::HigherRankedBounds hrbs = {}); TypeRef Parse_Type_ErasedType(TokenStream& lex, bool allow_trait_list); // === CODE === @@ -84,6 +85,10 @@ TypeRef Parse_Type_Int(TokenStream& lex, bool allow_trait_list) // TODO: path macros return TypeRef(TypeRef::TagMacro(), Parse_MacroInvocation(ps, mv$(tok.str()), lex)); } + if( TARGETVER_1_29 && tok.str() == "dyn" ) + { + return Parse_Type_TraitObject(lex, {}); + } // or a primitive //if( auto ct = coretype_fromstring(tok.str()) ) //{ @@ -311,6 +316,37 @@ TypeRef Parse_Type_Path(TokenStream& lex, ::AST::HigherRankedBounds hrbs, bool a } } } +TypeRef Parse_Type_TraitObject(TokenStream& lex, ::AST::HigherRankedBounds hrbs) +{ + Token tok; + auto ps = lex.start_span(); + + ::std::vector traits; + ::std::vector lifetimes; + + traits.push_back(Type_TraitPath { mv$(hrbs), Parse_Path(lex, PATH_GENERIC_TYPE) }); + + while( lex.lookahead(0) == TOK_PLUS ) + { + GET_CHECK_TOK(tok, lex, TOK_PLUS); + if( LOOK_AHEAD(lex) == TOK_LIFETIME ) { + GET_TOK(tok, lex); + lifetimes.push_back(AST::LifetimeRef( /*lex.point_span(),*/ lex.get_ident(mv$(tok)) )); + } + else + { + if( lex.lookahead(0) == TOK_RWORD_FOR ) + { + hrbs = Parse_HRB(lex); + } + traits.push_back({ mv$(hrbs), Parse_Path(lex, PATH_GENERIC_TYPE) }); + } + } + + if( lifetimes.empty()) + lifetimes.push_back(AST::LifetimeRef()); + return TypeRef(lex.end_span(ps), mv$(traits), mv$(lifetimes)); +} TypeRef Parse_Type_ErasedType(TokenStream& lex, bool allow_trait_list) { Token tok; -- cgit v1.2.3 From 01b1a1382080aa1d9fc648d305a4a49a44781214 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Thu, 4 Oct 2018 07:53:02 +0800 Subject: Const Eval - Intrinsic support (size_of), slightly better error reporting --- src/hir_conv/constant_evaluation.cpp | 62 +++++++++++++++++++++++------------- 1 file changed, 40 insertions(+), 22 deletions(-) diff --git a/src/hir_conv/constant_evaluation.cpp b/src/hir_conv/constant_evaluation.cpp index e1fde1bf..a4210e05 100644 --- a/src/hir_conv/constant_evaluation.cpp +++ b/src/hir_conv/constant_evaluation.cpp @@ -64,7 +64,7 @@ namespace { ::HIR::Literal evaluate_constant(const ::HIR::ItemPath& ip, const ::HIR::ExprPtr& expr, ::HIR::TypeRef exp); - ::HIR::Literal evaluate_constant_mir(const ::MIR::Function& fcn, MonomorphState ms, ::HIR::TypeRef exp, ::std::vector< ::HIR::Literal> args); + ::HIR::Literal evaluate_constant_mir(const ::HIR::ItemPath& ip, const ::MIR::Function& fcn, MonomorphState ms, ::HIR::TypeRef exp, ::std::vector< ::HIR::Literal> args); }; ::HIR::Literal clone_literal(const ::HIR::Literal& v) @@ -270,12 +270,12 @@ namespace { } } - ::HIR::Literal Evaluator::evaluate_constant_mir(const ::MIR::Function& fcn, MonomorphState ms, ::HIR::TypeRef exp, ::std::vector< ::HIR::Literal> args) + ::HIR::Literal Evaluator::evaluate_constant_mir(const ::HIR::ItemPath& ip, const ::MIR::Function& fcn, MonomorphState ms, ::HIR::TypeRef exp, ::std::vector< ::HIR::Literal> args) { // TODO: Full-blown miri TRACE_FUNCTION_F("exp=" << exp << ", args=" << args); - ::MIR::TypeResolve state { this->root_span, this->resolve, FMT_CB(,), exp, {}, fcn }; + ::MIR::TypeResolve state { this->root_span, this->resolve, FMT_CB(ss, ss< locals( fcn.locals.size() ); @@ -401,6 +401,7 @@ namespace { (Const, auto p = ms.monomorph(state.sp, e2.p); MonomorphState const_ms; + // TODO: If there's any mention of Self in this path, then return Literal::Defer auto ent = get_ent_fullpath(state.sp, this->resolve.m_crate, p, EntNS::Value, const_ms); MIR_ASSERT(state, ent.is_Constant(), "MIR Constant::Const(" << p << ") didn't point to a Constant - " << ent.tag_str()); const auto& c = *ent.as_Constant(); @@ -777,29 +778,46 @@ namespace { return retval; ), (Call, - if( !e.fcn.is_Path() ) - MIR_BUG(state, "Unexpected terminator - " << block.terminator); - const auto& fcnp_raw = e.fcn.as_Path(); - auto fcnp = ms.monomorph(state.sp, fcnp_raw); - auto& dst = local_state.get_lval(e.ret_val); - MonomorphState fcn_ms; - auto& fcn = get_function(this->root_span, this->resolve.m_crate, fcnp, fcn_ms); + if( const auto* te = e.fcn.opt_Intrinsic() ) + { + if( te->name == "size_of" ) { + auto ty = ms.monomorph(state.sp, te->params.m_types.at(0)); + size_t size_val; + Target_GetSizeOf(state.sp, this->resolve, ty, size_val); + dst = ::HIR::Literal::make_Integer( size_val ); + } + else { + MIR_TODO(state, "Call intrinsic \"" << te->name << "\" - " << block.terminator); + } + } + else if( const auto* te = e.fcn.opt_Path() ) + { + const auto& fcnp_raw = *te; + auto fcnp = ms.monomorph(state.sp, fcnp_raw); + + MonomorphState fcn_ms; + auto& fcn = get_function(this->root_span, this->resolve.m_crate, fcnp, fcn_ms); - ::std::vector< ::HIR::Literal> call_args; - call_args.reserve( e.args.size() ); - for(const auto& a : e.args) - call_args.push_back( read_param(a) ); - // TODO: Set m_const during parse and check here + ::std::vector< ::HIR::Literal> call_args; + call_args.reserve( e.args.size() ); + for(const auto& a : e.args) + call_args.push_back( read_param(a) ); + // TODO: Set m_const during parse and check here - // Call by invoking evaluate_constant on the function + // Call by invoking evaluate_constant on the function + { + TRACE_FUNCTION_F("Call const fn " << fcnp << " args={ " << call_args << " }"); + auto fcn_ip = ::HIR::ItemPath(fcnp); + const auto* mir = this->resolve.m_crate.get_or_gen_mir( fcn_ip, fcn ); + MIR_ASSERT(state, mir, "No MIR for function " << fcnp); + dst = evaluate_constant_mir(fcn_ip, *mir, mv$(fcn_ms), fcn.m_return.clone(), mv$(call_args)); + } + } + else { - TRACE_FUNCTION_F("Call const fn " << fcnp << " args={ " << call_args << " }"); - const auto* mir = this->resolve.m_crate.get_or_gen_mir( ::HIR::ItemPath(fcnp.clone()), fcn ); - MIR_ASSERT(state, mir, "No MIR for function " << fcnp); - dst = evaluate_constant_mir(*mir, mv$(fcn_ms), fcn.m_return.clone(), mv$(call_args)); + MIR_BUG(state, "Unexpected terminator - " << block.terminator); } - cur_block = e.ret_block; ) ) @@ -812,7 +830,7 @@ namespace { const auto* mir = this->resolve.m_crate.get_or_gen_mir(ip, expr, exp); if( mir ) { - return evaluate_constant_mir(*mir, {}, mv$(exp), {}); + return evaluate_constant_mir(ip, *mir, {}, mv$(exp), {}); } else { BUG(this->root_span, "Attempting to evaluate constant expression with no associated code"); -- cgit v1.2.3 From 26d664141d451aff8eac5ee967008df04e614ff2 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 6 Oct 2018 07:29:46 +0800 Subject: Const Evaluate - Very rough defer --- src/hir/item_path.hpp | 5 +++++ src/hir_conv/constant_evaluation.cpp | 26 ++++++++++++++++++++++++-- src/hir_typeck/common.cpp | 4 ++++ src/hir_typeck/common.hpp | 1 + 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/hir/item_path.hpp b/src/hir/item_path.hpp index d19435eb..d93df9e8 100644 --- a/src/hir/item_path.hpp +++ b/src/hir/item_path.hpp @@ -87,6 +87,11 @@ public: return name ? name : ""; } + const ItemPath& get_top_ip() const { + if( this->parent ) + return this->parent->get_top_ip(); + return *this; + } ItemPath operator+(const ::std::string& name) const { return ItemPath(*this, name.c_str()); } diff --git a/src/hir_conv/constant_evaluation.cpp b/src/hir_conv/constant_evaluation.cpp index a4210e05..acb613be 100644 --- a/src/hir_conv/constant_evaluation.cpp +++ b/src/hir_conv/constant_evaluation.cpp @@ -73,6 +73,9 @@ namespace { (Invalid, return ::HIR::Literal(); ), + (Defer, + return ::HIR::Literal::make_Defer({}); + ), (List, ::std::vector< ::HIR::Literal> vals; for(const auto& val : e) { @@ -400,8 +403,13 @@ namespace { ), (Const, auto p = ms.monomorph(state.sp, e2.p); + // If there's any mention of generics in this path, then return Literal::Defer + if( visit_path_tys_with(e2.p, [&](const auto& ty)->bool { return ty.m_data.is_Generic(); }) ) + { + DEBUG("Return Literal::Defer for constant " << e2.p << " which references a generic parameter"); + return ::HIR::Literal::make_Defer({}); + } MonomorphState const_ms; - // TODO: If there's any mention of Self in this path, then return Literal::Defer auto ent = get_ent_fullpath(state.sp, this->resolve.m_crate, p, EntNS::Value, const_ms); MIR_ASSERT(state, ent.is_Constant(), "MIR Constant::Const(" << p << ") didn't point to a Constant - " << ent.tag_str()); const auto& c = *ent.as_Constant(); @@ -588,6 +596,8 @@ namespace { (BinOp, auto inval_l = read_param(e.val_l); auto inval_r = read_param(e.val_r); + if( inval_l.is_Defer() || inval_r.is_Defer() ) + return ::HIR::Literal::make_Defer({}); MIR_ASSERT(state, inval_l.tag() == inval_r.tag(), "Mismatched literal types in binop - " << inval_l << " and " << inval_r); TU_MATCH_DEF( ::HIR::Literal, (inval_l, inval_r), (l, r), ( @@ -654,6 +664,8 @@ namespace { ), (UniOp, auto inval = local_state.read_lval(e.val); + if( inval.is_Defer() ) + return ::HIR::Literal::make_Defer({}); TU_IFLET( ::HIR::Literal, inval, Integer, i, switch( e.op ) { @@ -830,7 +842,15 @@ namespace { const auto* mir = this->resolve.m_crate.get_or_gen_mir(ip, expr, exp); if( mir ) { - return evaluate_constant_mir(ip, *mir, {}, mv$(exp), {}); + ::HIR::TypeRef ty_self { "Self", GENERIC_Self }; + // Might want to have a fully-populated MonomorphState for expanding inside impl blocks + // HACK: Generate a roughly-correct one + MonomorphState ms; + const auto& top_ip = ip.get_top_ip(); + if( top_ip.trait && !top_ip.ty ) { + ms.self_ty = &ty_self; + } + return evaluate_constant_mir(ip, *mir, mv$(ms), mv$(exp), {}); } else { BUG(this->root_span, "Attempting to evaluate constant expression with no associated code"); @@ -839,6 +859,8 @@ namespace { void check_lit_type(const Span& sp, const ::HIR::TypeRef& type, ::HIR::Literal& lit) { + if( lit.is_Defer() ) + return ; // TODO: Mask down limited size integers TU_MATCHA( (type.m_data), (te), (Infer, diff --git a/src/hir_typeck/common.cpp b/src/hir_typeck/common.cpp index e78ed21b..4b0328e7 100644 --- a/src/hir_typeck/common.cpp +++ b/src/hir_typeck/common.cpp @@ -113,6 +113,10 @@ bool visit_ty_with(const ::HIR::TypeRef& ty, t_cb_visit_ty callback) ) return false; } +bool visit_path_tys_with(const ::HIR::Path& path, t_cb_visit_ty callback) +{ + return visit_ty_with__path(path, callback); +} bool monomorphise_pathparams_needed(const ::HIR::PathParams& tpl) { diff --git a/src/hir_typeck/common.hpp b/src/hir_typeck/common.hpp index 09a5d9b2..14d9162f 100644 --- a/src/hir_typeck/common.hpp +++ b/src/hir_typeck/common.hpp @@ -33,6 +33,7 @@ typedef ::std::function t_cb_visit_ty; /// Calls the provided callback on every type seen when recursing the type. /// If the callback returns `true`, no further types are visited and the function returns `true`. extern bool visit_ty_with(const ::HIR::TypeRef& ty, t_cb_visit_ty callback); +extern bool visit_path_tys_with(const ::HIR::Path& ty, t_cb_visit_ty callback); typedef ::std::function t_cb_clone_ty; /// Clones a type, calling the provided callback on every type (optionally providing a replacement) -- cgit v1.2.3 From 54f252c5c165e3f520d627d5c644502b1ff15c41 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 6 Oct 2018 08:39:10 +0800 Subject: Misc - Fix travis build (at least up to current state) --- Makefile | 6 +++++- minicargo.mk | 2 +- script-overrides/stable-1.29.0-linux/build_compiler_builtins.txt | 1 + script-overrides/stable-1.29.0-linux/build_libc.txt | 2 ++ script-overrides/stable-1.29.0-linux/build_rustc_asan.txt | 0 script-overrides/stable-1.29.0-linux/build_rustc_lsan.txt | 0 script-overrides/stable-1.29.0-linux/build_rustc_msan.txt | 0 script-overrides/stable-1.29.0-linux/build_rustc_tsan.txt | 0 script-overrides/stable-1.29.0-linux/build_std.txt | 5 +++++ script-overrides/stable-1.29.0-linux/build_unwind.txt | 1 + 10 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 script-overrides/stable-1.29.0-linux/build_compiler_builtins.txt create mode 100644 script-overrides/stable-1.29.0-linux/build_libc.txt create mode 100644 script-overrides/stable-1.29.0-linux/build_rustc_asan.txt create mode 100644 script-overrides/stable-1.29.0-linux/build_rustc_lsan.txt create mode 100644 script-overrides/stable-1.29.0-linux/build_rustc_msan.txt create mode 100644 script-overrides/stable-1.29.0-linux/build_rustc_tsan.txt create mode 100644 script-overrides/stable-1.29.0-linux/build_std.txt create mode 100644 script-overrides/stable-1.29.0-linux/build_unwind.txt diff --git a/Makefile b/Makefile index 89cd8429..7d6d7876 100644 --- a/Makefile +++ b/Makefile @@ -165,6 +165,10 @@ fn_getdeps = \ .PHONY: RUSTCSRC RUSTCSRC: $(RUSTC_SRC_DL) +# +# rustc (with std/cargo) source download +# +# NIGHTLY: ifeq ($(RUSTC_SRC_TY),nightly) rustc-nightly-src.tar.gz: $(RUSTC_SRC_DES) @export DL_RUST_DATE=$$(cat rust-nightly-date); \ @@ -173,7 +177,6 @@ rustc-nightly-src.tar.gz: $(RUSTC_SRC_DES) rm -f rustc-nightly-src.tar.gz; \ curl -sS https://static.rust-lang.org/dist/$${DL_RUST_DATE}/rustc-nightly-src.tar.gz -o rustc-nightly-src.tar.gz -# TODO: Handle non-nightly download $(RUSTC_SRC_DL): rust-nightly-date rustc-nightly-src.tar.gz rustc-nightly-src.patch @export DL_RUST_DATE=$$(cat rust-nightly-date); \ export DISK_RUST_DATE=$$([ -f $(RUSTC_SRC_DL) ] && cat $(RUSTC_SRC_DL)); \ @@ -184,6 +187,7 @@ $(RUSTC_SRC_DL): rust-nightly-date rustc-nightly-src.tar.gz rustc-nightly-src.pa fi cat rust-nightly-date > $(RUSTC_SRC_DL) else +# NAMED (Stable or beta) RUSTC_SRC_TARBALL := rustc-$(shell cat $(RUSTC_SRC_DES))-src.tar.gz $(RUSTC_SRC_TARBALL): $(RUSTC_SRC_DES) @echo [CURL] $@ diff --git a/minicargo.mk b/minicargo.mk index 6c9962a6..ef83d554 100644 --- a/minicargo.mk +++ b/minicargo.mk @@ -5,7 +5,7 @@ OUTDIR_SUF ?= MMIR ?= RUSTC_CHANNEL ?= stable -RUSTC_VERSION ?= 1.19.0 +RUSTC_VERSION ?= $(cat rust-version) ifeq ($(OS),Windows_NT) else ifeq ($(shell uname -s || echo not),Darwin) OVERRIDE_SUFFIX ?= -macos diff --git a/script-overrides/stable-1.29.0-linux/build_compiler_builtins.txt b/script-overrides/stable-1.29.0-linux/build_compiler_builtins.txt new file mode 100644 index 00000000..06ae3dbf --- /dev/null +++ b/script-overrides/stable-1.29.0-linux/build_compiler_builtins.txt @@ -0,0 +1 @@ +# NOTE: mrustc doesn't need this built fully \ No newline at end of file diff --git a/script-overrides/stable-1.29.0-linux/build_libc.txt b/script-overrides/stable-1.29.0-linux/build_libc.txt new file mode 100644 index 00000000..aa2eb983 --- /dev/null +++ b/script-overrides/stable-1.29.0-linux/build_libc.txt @@ -0,0 +1,2 @@ +cargo:rustc-cfg=stdbuild +cargo:rerun-if-changed=build.rs \ No newline at end of file diff --git a/script-overrides/stable-1.29.0-linux/build_rustc_asan.txt b/script-overrides/stable-1.29.0-linux/build_rustc_asan.txt new file mode 100644 index 00000000..e69de29b diff --git a/script-overrides/stable-1.29.0-linux/build_rustc_lsan.txt b/script-overrides/stable-1.29.0-linux/build_rustc_lsan.txt new file mode 100644 index 00000000..e69de29b diff --git a/script-overrides/stable-1.29.0-linux/build_rustc_msan.txt b/script-overrides/stable-1.29.0-linux/build_rustc_msan.txt new file mode 100644 index 00000000..e69de29b diff --git a/script-overrides/stable-1.29.0-linux/build_rustc_tsan.txt b/script-overrides/stable-1.29.0-linux/build_rustc_tsan.txt new file mode 100644 index 00000000..e69de29b diff --git a/script-overrides/stable-1.29.0-linux/build_std.txt b/script-overrides/stable-1.29.0-linux/build_std.txt new file mode 100644 index 00000000..062afd95 --- /dev/null +++ b/script-overrides/stable-1.29.0-linux/build_std.txt @@ -0,0 +1,5 @@ +# TODO: THis is the windows set +cargo:rustc-link-lib=advapi32 +cargo:rustc-link-lib=ws2_32 +cargo:rustc-link-lib=userenv +cargo:rustc-link-lib=shell32 \ No newline at end of file diff --git a/script-overrides/stable-1.29.0-linux/build_unwind.txt b/script-overrides/stable-1.29.0-linux/build_unwind.txt new file mode 100644 index 00000000..aba1574a --- /dev/null +++ b/script-overrides/stable-1.29.0-linux/build_unwind.txt @@ -0,0 +1 @@ +# On both windows (MSVC) and linux (glibc), nothing is needed \ No newline at end of file -- cgit v1.2.3 From 74dab6a2bc0a3f1cdeca32aedfec7c46c06d70e1 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 7 Oct 2018 10:49:23 +0800 Subject: Typecheck - Fix a couple of small holes --- src/hir_typeck/expr_cs.cpp | 66 ++++++++++++++++++++++++++++++++++++++++++++++ src/hir_typeck/helpers.cpp | 10 ++++--- 2 files changed, 72 insertions(+), 4 deletions(-) diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 825df467..e7748115 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -2667,6 +2667,69 @@ namespace { { ERROR(sp, E0000, "No applicable methods for {" << ty << "}." << node.m_method); } + if( possible_methods.size() > 1 ) + { + // TODO: What do do when there's multiple possibilities? + // - Should use available information to strike them down + // > Try and equate the return type and the arguments, if any fail then move on to the next possibility? + // > ONLY if those arguments/return are generic + // + // Possible causes of multiple entries + // - Multiple distinct traits with the same method + // > If `self` is concretely known, this is an error (and shouldn't happen in well-formed code). + // - Multiple inherent methods on a type + // > These would have to have different type parmeters + // - Multiple trait bounds (same trait, different type params) + // > Guess at the type params, then discard if there's a conflict? + // > De-duplicate same traits? + // + // + // So: To be able to prune the list, we need to check the type parameters for the trait/type/impl + + // De-duplcate traits in this list. + // - If the self type and the trait name are the same, replace with an entry using placeholder + // ivars (node.m_trait_param_ivars) + for(auto it_1 = possible_methods.begin(); it_1 != possible_methods.end(); ++ it_1) + { + if( !it_1->second.m_data.is_UfcsKnown() ) + continue; + bool was_found = false; + auto& e1 = it_1->second.m_data.as_UfcsKnown(); + for(auto it_2 = it_1 + 1; it_2 != possible_methods.end(); ++ it_2) + { + if( !it_2->second.m_data.is_UfcsKnown() ) + continue; + if( it_2->second == it_1->second ) { + it_2 = possible_methods.erase(it_2) - 1; + continue ; + } + const auto& e2 = it_2->second.m_data.as_UfcsKnown(); + + if( *e1.type != *e2.type ) + continue; + if( e1.trait.m_path != e2.trait.m_path ) + continue; + + DEBUG("Duplicate trait in possible_methods - " << it_1->second << " and " << it_2->second); + if( !was_found ) + { + was_found = true; + const auto& ivars = node.m_trait_param_ivars; + unsigned int n_params = e1.trait.m_params.m_types.size(); + assert(n_params <= ivars.size()); + ::HIR::PathParams trait_params; + trait_params.m_types.reserve( n_params ); + for(unsigned int i = 0; i < n_params; i++) { + trait_params.m_types.push_back( ::HIR::TypeRef::new_infer(ivars[i], ::HIR::InferClass::None) ); + //ASSERT_BUG(sp, m_ivars.get_type( trait_params.m_types.back() ).m_data.as_Infer().index == ivars[i], "A method selection ivar was bound"); + } + e1.trait.m_params = mv$(trait_params); + + it_2 = possible_methods.erase(it_2) - 1; + } + } + } + } auto& ad_borrow = possible_methods.front().first; auto& fcn_path = possible_methods.front().second; DEBUG("- deref_count = " << deref_count << ", fcn_path = " << fcn_path); @@ -2704,6 +2767,7 @@ namespace { ) if( this->m_is_fallback && fcn_path.m_data.is_UfcsInherent() ) { + //possible_methods.erase(possible_methods.begin()); while( !possible_methods.empty() && possible_methods.front().second.m_data.is_UfcsInherent() ) { possible_methods.erase(possible_methods.begin()); @@ -5248,6 +5312,7 @@ namespace { } // if solid or fuzzy, leave as-is output_type = mv$( out_ty_o ); + DEBUG("[check_associated] cmp = " << cmp << " (2)"); } if( cmp == ::HIR::Compare::Equal ) { // NOTE: Sometimes equal can be returned when it's not 100% equal (TODO) @@ -5327,6 +5392,7 @@ namespace { } context.equate_types(sp, v.left_ty, output_type); } + // TODO: Any equating of type params? return true; } else if( count == 0 ) { diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index 1383300f..6860de41 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -1414,16 +1414,18 @@ bool TraitResolution::find_trait_impls(const Span& sp, } } + bool rv = false; bool ret = this->find_named_trait_in_trait(sp, trait, params, *bound.m_trait_ptr, bound.m_path.m_path, b_params_mono, type, [&](const auto& i_ty, const auto& i_params, const auto& i_assoc) { auto cmp = this->compare_pp(sp, i_params, params); DEBUG("cmp=" << cmp << ", impl " << trait << i_params << " for " << i_ty << " -- desired " << trait << params); - return cmp != ::HIR::Compare::Unequal && callback( ImplRef(i_ty.clone(), i_params.clone(), {}), cmp ); + rv |= (cmp != ::HIR::Compare::Unequal && callback( ImplRef(i_ty.clone(), i_params.clone(), {}), cmp )); + return true; // NOTE: actually ignored? }); if( ret ) { // NOTE: Callback called in closure's return statement - return true; + return rv; } return false; }); @@ -3666,6 +3668,7 @@ unsigned int TraitResolution::autoderef_find_method(const Span& sp, } if( !possibilities.empty() ) { + DEBUG("FOUND " << possibilities.size() << " options: " << possibilities); return deref_count; } @@ -3813,7 +3816,7 @@ bool TraitResolution::find_method(const Span& sp, ) const { bool rv = false; - TRACE_FUNCTION_F("ty=" << ty << ", name=" << method_name << ", access=" << access); + TRACE_FUNCTION_FR("ty=" << ty << ", name=" << method_name << ", access=" << access, possibilities); auto cb_infer = m_ivars.callback_resolve_infer(); // 1. Search generic bounds for a match @@ -3858,7 +3861,6 @@ bool TraitResolution::find_method(const Span& sp, {} }) ) )); rv = true; - break; } else if( cmp == ::HIR::Compare::Fuzzy ) { -- cgit v1.2.3 From f31020b3f3aeb299e68af9c4790bb591dcfc2aca Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 13 Oct 2018 08:34:50 +0800 Subject: Span - Fix lack of separator in warnings --- src/span.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/span.cpp b/src/span.cpp index eacdc7aa..4e309287 100644 --- a/src/span.cpp +++ b/src/span.cpp @@ -75,10 +75,10 @@ void Span::error(ErrorType tag, ::std::function msg) cons #endif } void Span::warning(WarningType tag, ::std::function msg) const { - print_span_message(*this, [&](auto& os){os << "warning" << tag;}, msg); + print_span_message(*this, [&](auto& os){os << "warn:" << tag;}, msg); } void Span::note(::std::function msg) const { - print_span_message(*this, [](auto& os){os << "note";}, msg); + print_span_message(*this, [](auto& os){os << "note:";}, msg); } ::std::ostream& operator<<(::std::ostream& os, const Span& sp) -- cgit v1.2.3 From 76757341622b747074be74cc75aa5f4f51665f15 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 3 Nov 2018 22:08:03 +0800 Subject: HIR Typecheck - Fixing holes from 1.29 compiler_builtins --- src/hir/hir.cpp | 2 +- src/hir/type.cpp | 60 +++++----- src/hir_typeck/expr_check.cpp | 4 +- src/hir_typeck/expr_cs.cpp | 7 +- src/hir_typeck/helpers.cpp | 260 ++++++++++++++++++++++++------------------ src/hir_typeck/helpers.hpp | 1 + src/hir_typeck/impl_ref.cpp | 19 +-- src/include/tagged_union.hpp | 5 +- src/trans/codegen_c.cpp | 6 + 9 files changed, 205 insertions(+), 159 deletions(-) diff --git a/src/hir/hir.cpp b/src/hir/hir.cpp index 9f9bc1c3..fb0cdbd3 100644 --- a/src/hir/hir.cpp +++ b/src/hir/hir.cpp @@ -344,7 +344,7 @@ bool ::HIR::TraitImpl::matches_type(const ::HIR::TypeRef& type, ::HIR::t_cb_reso { // NOTE: Don't return any impls when the type is an unbouned ivar. Wouldn't be able to pick anything anyway // TODO: For `Unbound`, it could be valid, if the target is a generic. - if( is_unbounded_infer(type) || TU_TEST1(type.m_data, Path, .binding.is_Unbound()) ) { + if( /*is_unbounded_infer(type) ||*/ TU_TEST1(type.m_data, Path, .binding.is_Unbound()) ) { return false; } return matches_type_int(m_params, m_type, type, ty_res, true); diff --git a/src/hir/type.cpp b/src/hir/type.cpp index 6f826111..434d471b 100644 --- a/src/hir/type.cpp +++ b/src/hir/type.cpp @@ -58,8 +58,8 @@ namespace HIR { void ::HIR::TypeRef::fmt(::std::ostream& os) const { - TU_MATCH(::HIR::TypeRef::Data, (m_data), (e), - (Infer, + TU_MATCH_HDR( (m_data), { ) + TU_ARM(m_data, Infer, e) { os << "_"; if( e.index != ~0u || e.ty_class != ::HIR::InferClass::None ) { os << "/*"; @@ -73,14 +73,14 @@ void ::HIR::TypeRef::fmt(::std::ostream& os) const } os << "*/"; } - ), - (Diverge, + } + TU_ARM(m_data, Diverge, e) { os << "!"; - ), - (Primitive, + } + TU_ARM(m_data, Primitive, e) { os << e; - ), - (Path, + } + TU_ARM(m_data, Path, e) { os << e.path; TU_MATCH(::HIR::TypeRef::TypePathBinding, (e.binding), (be), (Unbound, os << "/*?*/";), @@ -89,8 +89,8 @@ void ::HIR::TypeRef::fmt(::std::ostream& os) const (Union, os << "/*U*/";), (Enum, os << "/*E*/";) ) - ), - (Generic, + } + TU_ARM(m_data, Generic, e) { os << e.name << "/*"; if( e.binding == 0xFFFF ) os << ""; @@ -103,8 +103,8 @@ void ::HIR::TypeRef::fmt(::std::ostream& os) const else os << e.binding; os << "*/"; - ), - (TraitObject, + } + TU_ARM(m_data, TraitObject, e) { os << "dyn ("; if( e.m_trait.m_path != ::HIR::GenericPath() ) { @@ -115,8 +115,8 @@ void ::HIR::TypeRef::fmt(::std::ostream& os) const if( e.m_lifetime != LifetimeRef::new_static() ) os << "+" << e.m_lifetime; os << ")"; - ), - (ErasedType, + } + TU_ARM(m_data, ErasedType, e) { os << "impl "; for(const auto& tr : e.m_traits) { if( &tr != &e.m_traits[0] ) @@ -126,25 +126,25 @@ void ::HIR::TypeRef::fmt(::std::ostream& os) const if( e.m_lifetime != LifetimeRef::new_static() ) os << "+ '" << e.m_lifetime; os << "/*" << e.m_origin << "#" << e.m_index << "*/"; - ), - (Array, + } + TU_ARM(m_data, Array, e) { os << "[" << *e.inner << "; "; if( e.size_val != ~0u ) os << e.size_val; else os << "/*sz*/"; os << "]"; - ), - (Slice, + } + TU_ARM(m_data, Slice, e) { os << "[" << *e.inner << "]"; - ), - (Tuple, + } + TU_ARM(m_data, Tuple, e) { os << "("; for(const auto& t : e) os << t << ", "; os << ")"; - ), - (Borrow, + } + TU_ARM(m_data, Borrow, e) { switch(e.type) { case ::HIR::BorrowType::Shared: os << "&"; break; @@ -152,8 +152,8 @@ void ::HIR::TypeRef::fmt(::std::ostream& os) const case ::HIR::BorrowType::Owned: os << "&move "; break; } os << *e.inner; - ), - (Pointer, + } + TU_ARM(m_data, Pointer, e) { switch(e.type) { case ::HIR::BorrowType::Shared: os << "*const "; break; @@ -161,8 +161,8 @@ void ::HIR::TypeRef::fmt(::std::ostream& os) const case ::HIR::BorrowType::Owned: os << "*move "; break; } os << *e.inner; - ), - (Function, + } + TU_ARM(m_data, Function, e) { if( e.is_unsafe ) { os << "unsafe "; } @@ -173,8 +173,8 @@ void ::HIR::TypeRef::fmt(::std::ostream& os) const for(const auto& t : e.m_arg_types) os << t << ", "; os << ") -> " << *e.m_rettype; - ), - (Closure, + } + TU_ARM(m_data, Closure, e) { os << "closure["< " << *e.m_rettype; */ - ) - ) + } + } } bool ::HIR::TypeRef::operator==(const ::HIR::TypeRef& x) const diff --git a/src/hir_typeck/expr_check.cpp b/src/hir_typeck/expr_check.cpp index 8a199557..6d2feaba 100644 --- a/src/hir_typeck/expr_check.cpp +++ b/src/hir_typeck/expr_check.cpp @@ -177,8 +177,8 @@ namespace { case ::HIR::ExprNode_Assign::Op::And: lang_item = "bitand_assign"; break; case ::HIR::ExprNode_Assign::Op::Or : lang_item = "bitor_assign" ; break; case ::HIR::ExprNode_Assign::Op::Xor: lang_item = "bitxor_assign"; break; - case ::HIR::ExprNode_Assign::Op::Shr: lang_item = "shl_assign"; break; - case ::HIR::ExprNode_Assign::Op::Shl: lang_item = "shr_assign"; break; + case ::HIR::ExprNode_Assign::Op::Shr: lang_item = "shr_assign"; break; + case ::HIR::ExprNode_Assign::Op::Shl: lang_item = "shl_assign"; break; } assert(lang_item); const auto& trait_path = this->get_lang_item_path(node.span(), lang_item); diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index e7748115..a236c818 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -846,8 +846,8 @@ namespace { case ::HIR::ExprNode_Assign::Op::And: lang_item = "bitand_assign"; break; case ::HIR::ExprNode_Assign::Op::Or : lang_item = "bitor_assign" ; break; case ::HIR::ExprNode_Assign::Op::Xor: lang_item = "bitxor_assign"; break; - case ::HIR::ExprNode_Assign::Op::Shr: lang_item = "shl_assign"; break; - case ::HIR::ExprNode_Assign::Op::Shl: lang_item = "shr_assign"; break; + case ::HIR::ExprNode_Assign::Op::Shr: lang_item = "shr_assign"; break; + case ::HIR::ExprNode_Assign::Op::Shl: lang_item = "shl_assign"; break; } assert(lang_item); const auto& trait_path = this->context.m_crate.get_lang_item_path(node.span(), lang_item); @@ -5294,7 +5294,6 @@ namespace { auto out_ty_o = impl.get_type(v.name.c_str()); if( out_ty_o == ::HIR::TypeRef() ) { - //BUG(sp, "Getting associated type '" << v.name << "' which isn't in " << v.trait << " (" << ty << ")"); out_ty_o = ::HIR::TypeRef(::HIR::Path( v.impl_ty.clone(), ::HIR::GenericPath(v.trait, v.params.clone()), v.name, ::HIR::PathParams() )); } out_ty_o = context.m_resolve.expand_associated_types(sp, mv$(out_ty_o)); @@ -5450,6 +5449,8 @@ namespace { if( TU_TEST1(impl_ty.m_data, Infer, .is_lit() == false) ) { DEBUG("Unbounded ivar, waiting - TODO: Add possibility " << impl_ty << " == " << possible_impl_ty); + context.possible_equate_type_coerce_to(impl_ty.m_data.as_Infer().index, possible_impl_ty); + context.possible_equate_type_coerce_from(impl_ty.m_data.as_Infer().index, possible_impl_ty); return false; } // Only one possible impl diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index 6860de41..4d3ea82d 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -914,8 +914,8 @@ bool HMTypeInferrence::types_equal(const ::HIR::TypeRef& rl, const ::HIR::TypeRe return pathparams_equal(le.m_trait.m_path.m_params, re.m_trait.m_path.m_params); ), (ErasedType, + ASSERT_BUG(Span(), le.m_origin != ::HIR::SimplePath(), "Erased type with unset origin"); return H::compare_path(*this, le.m_origin, re.m_origin); - //TODO(Span(), "ErasedType"); ), (Tuple, return type_list_equal(*this, le, re); @@ -932,12 +932,17 @@ void TraitResolution::prep_indexes() static Span sp_AAA; const Span& sp = sp_AAA; + // TODO: Create a list of all known type rules in this scope (recursively) + // - What if there's recursive bounds (e.g. on ATYs) + auto add_equality = [&](::HIR::TypeRef long_ty, ::HIR::TypeRef short_ty){ DEBUG("[prep_indexes] ADD " << long_ty << " => " << short_ty); // TODO: Sort the two types by "complexity" (most of the time long >= short) this->m_type_equalities.insert(::std::make_pair( mv$(long_ty), mv$(short_ty) )); }; + // Obtain type equality bounds. + // TODO: Also flatten the bounds list into known trait bounds? this->iterate_bounds([&](const auto& b)->bool { if(const auto* bep = b.opt_TraitBound()) { @@ -1047,6 +1052,31 @@ bool TraitResolution::iterate_bounds( ::std::function cb) const +{ + // Iterate all bounds, finding trait + return this->iterate_bounds([&](const auto& gb) { + if( const auto* be = gb.opt_TraitBound() ) + { + // TODO: Type filter (to avoid the cost of checking parent bounds) + if( cb(be->type, be->trait) ) + return true; + + assert(be->trait.m_trait_ptr); + const auto& trait_ref = *be->trait.m_trait_ptr; + auto monomorph_cb = monomorphise_type_get_cb(sp, &be->type, &be->trait.m_path.m_params, nullptr, nullptr); + for(const auto& parent_tp : trait_ref.m_all_parent_traits) + { + ::HIR::TraitPath tp_mono_o; + const auto& tp_mono = (monomorphise_traitpath_needed(parent_tp) ? tp_mono_o = monomorphise_traitpath_with(sp, parent_tp, monomorph_cb, false) : parent_tp); + // TODO: Monomorphise the bound + if( cb(be->type, tp_mono) ) + return true; + } + } + return false; + }); +} bool TraitResolution::iterate_aty_bounds(const Span& sp, const ::HIR::Path::Data::Data_UfcsKnown& pe, ::std::function cb) const { ::HIR::GenericPath trait_path; @@ -2241,136 +2271,127 @@ bool TraitResolution::find_trait_impls_bound(const Span& sp, const ::HIR::Simple ) ) -#if 0 - if( m_ivars.get_type(type).m_data.is_Infer() ) - return false; - if( TU_TEST1(m_ivars.get_type(type).m_data, Path, .binding.is_Unbound()) ) - return false; -#endif + // NOTE: Even if the type is completely unknown (infer or unbound UFCS), search the bound list. // TODO: A bound can imply something via its associated types. How deep can this go? // E.g. `T: IntoIterator` implies `::IntoIter : Iterator` - return this->iterate_bounds([&](const auto& b)->bool { - DEBUG(b); - if( b.is_TraitBound() ) - { - const auto& e = b.as_TraitBound(); - const auto& b_params = e.trait.m_path.m_params; + // > Would maybe want a list of all explicit and implied bounds instead. + return this->iterate_bounds_traits(sp, [&](const auto& bound_ty, const ::HIR::TraitPath& bound_trait)->bool { + const auto& b_params = bound_trait.m_path.m_params; - auto cmp = e.type .compare_with_placeholders(sp, type, m_ivars.callback_resolve_infer()); - DEBUG("cmp = " << cmp); - if( cmp == ::HIR::Compare::Unequal ) - return false; + auto cmp = bound_ty .compare_with_placeholders(sp, type, m_ivars.callback_resolve_infer()); + DEBUG("cmp = " << cmp); + if( cmp == ::HIR::Compare::Unequal ) + return false; - if( e.trait.m_path.m_path == trait ) { - // Check against `params` - DEBUG("[find_trait_impls_bound] Checking params " << params << " vs " << b_params); - auto ord = cmp; - ord &= this->compare_pp(sp, b_params, params); - if( ord == ::HIR::Compare::Unequal ) - return false; - if( ord == ::HIR::Compare::Fuzzy ) { - DEBUG("Fuzzy match"); - } - DEBUG("[find_trait_impls_bound] Match " << b); - // Hand off to the closure, and return true if it does - // TODO: The type bounds are only the types that are specified. - if( callback( ImplRef(&e.type, &e.trait.m_path.m_params, &e.trait.m_type_bounds), ord) ) { - return true; - } + if( bound_trait.m_path.m_path == trait ) { + // Check against `params` + DEBUG("[find_trait_impls_bound] Checking params " << params << " vs " << b_params); + auto ord = cmp; + ord &= this->compare_pp(sp, b_params, params); + if( ord == ::HIR::Compare::Unequal ) + return false; + if( ord == ::HIR::Compare::Fuzzy ) { + DEBUG("Fuzzy match"); + } + DEBUG("[find_trait_impls_bound] Match " << bound_ty << " : " << bound_trait); + // Hand off to the closure, and return true if it does + // TODO: The type bounds are only the types that are specified. + auto b = bound_trait.clone(); + if( callback( ImplRef(bound_ty.clone(), mv$(b.m_path.m_params), mv$(b.m_type_bounds)), ord) ) { + return true; } + } - // TODO: Allow fuzzy equality? - if( cmp == ::HIR::Compare::Equal ) - { - // HACK: The wrapping closure takes associated types from this bound and applies them to the returned set - // - XXX: This is actually wrong (false-positive) in many cases. FIXME - bool rv = this->find_named_trait_in_trait(sp, - trait,params, - *e.trait.m_trait_ptr, e.trait.m_path.m_path,e.trait.m_path.m_params, - type, - [&](const auto& ty, const auto& params, const auto& assoc) { - // TODO: Avoid duplicating this map every time - ::std::map< ::std::string,::HIR::TypeRef> assoc2; - for(const auto& i : assoc) { + // TODO: Allow fuzzy equality? + if( cmp == ::HIR::Compare::Equal ) + { + // HACK: The wrapping closure takes associated types from this bound and applies them to the returned set + // - XXX: This is actually wrong (false-positive) in many cases. FIXME + bool rv = this->find_named_trait_in_trait(sp, + trait,params, + *bound_trait.m_trait_ptr, bound_trait.m_path.m_path,bound_trait.m_path.m_params, + type, + [&](const auto& ty, const auto& params, const auto& assoc) { + // TODO: Avoid duplicating this map every time + ::std::map< ::std::string,::HIR::TypeRef> assoc2; + for(const auto& i : assoc) { + assoc2.insert( ::std::make_pair(i.first, i.second.clone()) ); + } + for(const auto& i : bound_trait.m_type_bounds) { + // TODO: Only include from above when needed + //if( des_trait_ref.m_types.count(i.first) ) { assoc2.insert( ::std::make_pair(i.first, i.second.clone()) ); - } - for(const auto& i : e.trait.m_type_bounds) { - // TODO: Only include from above when needed - //if( des_trait_ref.m_types.count(i.first) ) { - assoc2.insert( ::std::make_pair(i.first, i.second.clone()) ); - //} - } - return callback( ImplRef(ty.clone(), params.clone(), mv$(assoc2)), ::HIR::Compare::Equal ); - }); - if( rv ) { - return true; - } + //} + } + return callback( ImplRef(ty.clone(), params.clone(), mv$(assoc2)), ::HIR::Compare::Equal ); + }); + if( rv ) { + return true; } + } - // If the input type is an associated type controlled by this trait bound, check for added bounds. - // TODO: This just checks a single layer, but it's feasable that there could be multiple layers - if( assoc_info && e.trait.m_path.m_path == assoc_info->trait.m_path && e.type == *assoc_info->type ) - { - // Check the trait params - auto ord = this->compare_pp(sp, b_params, assoc_info->trait.m_params); - if( ord == ::HIR::Compare::Fuzzy ) { - //TODO(sp, "Handle fuzzy matches searching for associated type bounds"); - } - else if( ord == ::HIR::Compare::Unequal ) { - return false; - } - auto outer_ord = ord; + // If the input type is an associated type controlled by this trait bound, check for added bounds. + // TODO: This just checks a single layer, but it's feasable that there could be multiple layers + if( assoc_info && bound_trait.m_path.m_path == assoc_info->trait.m_path && bound_ty == *assoc_info->type ) + { + // Check the trait params + auto ord = this->compare_pp(sp, b_params, assoc_info->trait.m_params); + if( ord == ::HIR::Compare::Fuzzy ) { + //TODO(sp, "Handle fuzzy matches searching for associated type bounds"); + } + else if( ord == ::HIR::Compare::Unequal ) { + return false; + } + auto outer_ord = ord; - const auto& trait_ref = *e.trait.m_trait_ptr; - const auto& at = trait_ref.m_types.at(assoc_info->item); - for(const auto& bound : at.m_trait_bounds) { - if( bound.m_path.m_path == trait ) - { - auto monomorph_cb = [&](const auto& gt)->const ::HIR::TypeRef& { - const auto& ge = gt.m_data.as_Generic(); - if( ge.binding == 0xFFFF ) { - return *assoc_info->type; - } - else { - if( ge.binding >= assoc_info->trait.m_params.m_types.size() ) - BUG(sp, "find_trait_impls_bound - Generic #" << ge.binding << " " << ge.name << " out of range"); - return assoc_info->trait.m_params.m_types[ge.binding]; - } - }; - - DEBUG("- Found an associated type bound for this trait via another bound"); - ::HIR::Compare ord = outer_ord; - if( monomorphise_pathparams_needed(bound.m_path.m_params) ) { - // TODO: Use a compare+callback method instead - auto b_params_mono = monomorphise_path_params_with(sp, bound.m_path.m_params, monomorph_cb, false); - ord &= this->compare_pp(sp, b_params_mono, params); + const auto& trait_ref = *bound_trait.m_trait_ptr; + const auto& at = trait_ref.m_types.at(assoc_info->item); + for(const auto& bound : at.m_trait_bounds) { + if( bound.m_path.m_path == trait ) + { + auto monomorph_cb = [&](const auto& gt)->const ::HIR::TypeRef& { + const auto& ge = gt.m_data.as_Generic(); + if( ge.binding == 0xFFFF ) { + return *assoc_info->type; } else { - ord &= this->compare_pp(sp, bound.m_path.m_params, params); - } - if( ord == ::HIR::Compare::Unequal ) - return false; - if( ord == ::HIR::Compare::Fuzzy ) { - DEBUG("Fuzzy match"); + if( ge.binding >= assoc_info->trait.m_params.m_types.size() ) + BUG(sp, "find_trait_impls_bound - Generic #" << ge.binding << " " << ge.name << " out of range"); + return assoc_info->trait.m_params.m_types[ge.binding]; } + }; - auto tp_mono = monomorphise_traitpath_with(sp, bound, monomorph_cb, false); - // - Expand associated types - for(auto& ty : tp_mono.m_type_bounds) { - ty.second = this->expand_associated_types(sp, mv$(ty.second)); - } - DEBUG("- tp_mono = " << tp_mono); - // TODO: Instead of using `type` here, build the real type - if( callback( ImplRef(type.clone(), mv$(tp_mono.m_path.m_params), mv$(tp_mono.m_type_bounds)), ord ) ) { - return true; - } + DEBUG("- Found an associated type bound for this trait via another bound"); + ::HIR::Compare ord = outer_ord; + if( monomorphise_pathparams_needed(bound.m_path.m_params) ) { + // TODO: Use a compare+callback method instead + auto b_params_mono = monomorphise_path_params_with(sp, bound.m_path.m_params, monomorph_cb, false); + ord &= this->compare_pp(sp, b_params_mono, params); + } + else { + ord &= this->compare_pp(sp, bound.m_path.m_params, params); + } + if( ord == ::HIR::Compare::Unequal ) + return false; + if( ord == ::HIR::Compare::Fuzzy ) { + DEBUG("Fuzzy match"); + } + + auto tp_mono = monomorphise_traitpath_with(sp, bound, monomorph_cb, false); + // - Expand associated types + for(auto& ty : tp_mono.m_type_bounds) { + ty.second = this->expand_associated_types(sp, mv$(ty.second)); + } + DEBUG("- tp_mono = " << tp_mono); + // TODO: Instead of using `type` here, build the real type + if( callback( ImplRef(type.clone(), mv$(tp_mono.m_path.m_params), mv$(tp_mono.m_type_bounds)), ord ) ) { + return true; } } } - - return false; } + return false; }); } @@ -3843,7 +3864,8 @@ bool TraitResolution::find_method(const Span& sp, // 2. Compare the receiver of the above to this type and the bound. if(const auto* self_ty = check_method_receiver(sp, *fcn_ptr, ty, access)) { - if( self_ty->m_data.is_Infer() ) + // If the type is an unbounded ivar, don't check. + if( TU_TEST1(self_ty->m_data, Infer, .is_lit() == false) ) return false; // TODO: Do a fuzzy match here? auto cmp = self_ty->compare_with_placeholders(sp, e.type, cb_infer); @@ -3864,7 +3886,17 @@ bool TraitResolution::find_method(const Span& sp, } else if( cmp == ::HIR::Compare::Fuzzy ) { - TODO(sp, "Fuzzy match checking bounded method - " << *self_ty << " != " << e.type); + DEBUG("Fuzzy match checking bounded method - " << *self_ty << " != " << e.type); + + // Found the method, return the UFCS path for it + possibilities.push_back(::std::make_pair( borrow_type, + ::HIR::Path( ::HIR::Path::Data::make_UfcsKnown({ + box$( self_ty->clone() ), + mv$(final_trait_path), + method_name, + {} + }) ) )); + rv = true; } else { diff --git a/src/hir_typeck/helpers.hpp b/src/hir_typeck/helpers.hpp index 7868b93f..cb95c94f 100644 --- a/src/hir_typeck/helpers.hpp +++ b/src/hir_typeck/helpers.hpp @@ -201,6 +201,7 @@ public: /// Iterate over in-scope bounds (function then top) bool iterate_bounds( ::std::function cb) const; + bool iterate_bounds_traits(const Span& sp, ::std::function cb) const; bool iterate_aty_bounds(const Span& sp, const ::HIR::Path::Data::Data_UfcsKnown& pe, ::std::function cb) const; typedef ::std::function&)> t_cb_trait_impl; diff --git a/src/hir_typeck/impl_ref.cpp b/src/hir_typeck/impl_ref.cpp index e8966b38..d2dc9fe6 100644 --- a/src/hir_typeck/impl_ref.cpp +++ b/src/hir_typeck/impl_ref.cpp @@ -219,8 +219,8 @@ bool ImplRef::type_is_specialisable(const char* name) const ::std::ostream& operator<<(::std::ostream& os, const ImplRef& x) { - TU_MATCH(ImplRef::Data, (x.m_data), (e), - (TraitImpl, + TU_MATCH_HDR( (x.m_data), { ) + TU_ARM(x.m_data, TraitImpl, e) { if( e.impl == nullptr ) { os << "none"; } @@ -258,13 +258,16 @@ bool ImplRef::type_is_specialisable(const char* name) const } os << "}"; } - ), - (BoundedPtr, + } + TU_ARM(x.m_data, BoundedPtr, e) { + assert(e.type); + assert(e.trait_args); + assert(e.assoc); os << "bound (ptr) " << *e.type << " : ?" << *e.trait_args << " + {" << *e.assoc << "}"; - ), - (Bounded, + } + TU_ARM(x.m_data, Bounded, e) { os << "bound " << e.type << " : ?" << e.trait_args << " + {"<::type, VARS, brace) +#define TU_MATCH_HDR_(CLASS, VARS, brace) switch( (TU_FIRST VARS).tag() ) brace case CLASS::TAGDEAD: assert(!"ERROR: destructed tagged union used"); + // Evil hack: two for loops, the inner stops the outer after it's done. -#define TU_ARM(VAR, TAG, NAME) case ::std::remove_reference::type::TAG_##TAG: for(bool tu_lc = true; tu_lc; tu_lc=false) for(auto& NAME = VAR.as_##TAG(); (void)NAME, tu_lc; tu_lc=false) +#define TU_ARM(VAR, TAG, NAME) break; case ::std::remove_reference::type::TAG_##TAG: for(bool tu_lc = true; tu_lc; tu_lc=false) for(auto& NAME = VAR.as_##TAG(); (void)NAME, tu_lc; tu_lc=false) //#define TU_TEST(VAL, ...) (VAL.is_##TAG() && VAL.as_##TAG() TEST) #define TU_TEST1(VAL, TAG1, TEST) (VAL.is_##TAG1() && VAL.as_##TAG1() TEST) diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 86bbdddc..1bbafcd2 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -1776,6 +1776,9 @@ namespace { }; TU_MATCHA( (lit), (e), (Invalid, m_of << "/* INVALID */"; ), + (Defer, + MIR_BUG(*m_mir_res, "Defer literal encountered"); + ), (List, m_of << "{"; if( ty.m_data.is_Array() ) @@ -5285,6 +5288,9 @@ namespace { (Invalid, m_of << "/* INVALID */"; ), + (Defer, + MIR_BUG(*m_mir_res, "Defer literal encountered"); + ), (List, if( ty.m_data.is_Array() ) { -- cgit v1.2.3 From e4f9ba0abf4646687e38d0eed15ebd19b514910b Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 8 Dec 2018 17:14:04 +0800 Subject: Expand - Tweaks to select between 1.19 and 1.29 --- src/expand/lang_item.cpp | 2 +- src/expand/mod.cpp | 3 ++- src/include/target_version.hpp | 12 ++++++++++-- src/main.cpp | 2 ++ 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/expand/lang_item.cpp b/src/expand/lang_item.cpp index 0bdd37e5..f59d81c3 100644 --- a/src/expand/lang_item.cpp +++ b/src/expand/lang_item.cpp @@ -68,7 +68,7 @@ void handle_lang_item(const Span& sp, AST::Crate& crate, const AST::Path& path, else if( name == "fn_once" ) { DEBUG("Bind '"< g_debug_disable_map; +TargetVersion gTargetVersion = TargetVersion::Rustc1_19; + void init_debug_list() { g_debug_disable_map.insert( "Parse" ); -- cgit v1.2.3 From a74368d639cec8794a2bfd6d8cc08e8812ec0aa1 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 9 Dec 2018 00:29:11 +0800 Subject: HIR - Don't yield impls for a unbounded ivar Self --- src/hir/hir.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hir/hir.cpp b/src/hir/hir.cpp index fb0cdbd3..a0b2b21d 100644 --- a/src/hir/hir.cpp +++ b/src/hir/hir.cpp @@ -344,7 +344,8 @@ bool ::HIR::TraitImpl::matches_type(const ::HIR::TypeRef& type, ::HIR::t_cb_reso { // NOTE: Don't return any impls when the type is an unbouned ivar. Wouldn't be able to pick anything anyway // TODO: For `Unbound`, it could be valid, if the target is a generic. - if( /*is_unbounded_infer(type) ||*/ TU_TEST1(type.m_data, Path, .binding.is_Unbound()) ) { + // - Pure infer could also be useful (for knowing if there's any other potential impls) + if( is_unbounded_infer(type) || TU_TEST1(type.m_data, Path, .binding.is_Unbound()) ) { return false; } return matches_type_int(m_params, m_type, type, ty_res, true); -- cgit v1.2.3 From 3056e863b8b80732746bfde6cce7f8264055cd4e Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 9 Dec 2018 00:34:24 +0800 Subject: Trans Auto Impls - Don't run if 1.19 mode --- src/trans/auto_impls.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/trans/auto_impls.cpp b/src/trans/auto_impls.cpp index 334d9eae..ffd0d30a 100644 --- a/src/trans/auto_impls.cpp +++ b/src/trans/auto_impls.cpp @@ -96,6 +96,9 @@ void Trans_AutoImpl_Clone(State& state, ::HIR::TypeRef ty) void Trans_AutoImpls(::HIR::Crate& crate, TransList& trans_list) { + if( TARGETVER_1_19 ) + return ; + State state { crate, trans_list }; // Generate for all -- cgit v1.2.3 From 412ab776b3e9bc6635d71cae1276a7d90600cf40 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 9 Dec 2018 00:37:24 +0800 Subject: Makefile - Allow overriding rustc version --- Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 7d6d7876..e7c4dc1f 100644 --- a/Makefile +++ b/Makefile @@ -136,13 +136,14 @@ RUSTC_SRC_DES := rust-nightly-date RUSTCSRC := rustc-nightly-src/ else ifeq ($(RUSTC_SRC_TY),stable) RUSTC_SRC_DES := rust-version -RUSTCSRC := rustc-$(shell cat $(RUSTC_SRC_DES))-src/ +RUSTC_VERSION ?= $(shell cat $(RUSTC_SRC_DES)) +RUSTCSRC := rustc-$(RUSTC_VERSION)-src/ else $(error Unknown rustc channel) endif RUSTC_SRC_DL := $(RUSTCSRC)/dl-version -MAKE_MINICARGO = $(MAKE) -f minicargo.mk RUSTC_VERSION=$(shell cat $(RUSTC_SRC_DES)) RUSTC_CHANNEL=$(RUSTC_SRC_TY) +MAKE_MINICARGO = $(MAKE) -f minicargo.mk RUSTC_VERSION=$(RUSTC_VERSION) RUSTC_CHANNEL=$(RUSTC_SRC_TY) output/libstd.hir: $(BIN) -- cgit v1.2.3 From 2637ce90570d305eca74d2324793e730fb8a3452 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 9 Dec 2018 00:38:10 +0800 Subject: main - Set default target version to 1.29, allow environment to change that --- src/main.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 5db6d811..6eb726ac 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -34,7 +34,7 @@ bool g_debug_enabled = true; ::std::string g_cur_phase; ::std::set< ::std::string> g_debug_disable_map; -TargetVersion gTargetVersion = TargetVersion::Rustc1_19; +TargetVersion gTargetVersion = TargetVersion::Rustc1_29; void init_debug_list() { @@ -1085,6 +1085,19 @@ ProgramParams::ProgramParams(int argc, char *argv[]) exit(1); } + + if( const auto* a = getenv("MRUSTC_TARGET_VER") ) + { + if( strcmp(a, "1.19") == 0 ) { + gTargetVersion = TargetVersion::Rustc1_19; + } + else if( strcmp(a, "1.29") == 0 ) { + gTargetVersion = TargetVersion::Rustc1_29; + } + else { + } + } + if( const auto* a = getenv("MRUSTC_DUMP") ) { while( a[0] ) -- cgit v1.2.3 From 2a2b29e747d5cf06f930c1b6c671628f1d9e5cb6 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 9 Dec 2018 08:23:12 +0800 Subject: HIR Types - Comment out an overly-verbose log message --- src/hir/type.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hir/type.cpp b/src/hir/type.cpp index 434d471b..2c24e3e1 100644 --- a/src/hir/type.cpp +++ b/src/hir/type.cpp @@ -889,7 +889,7 @@ bool ::HIR::TypeRef::match_test_generics(const Span& sp, const ::HIR::TypeRef& x } ::HIR::Compare HIR::TypeRef::compare_with_placeholders(const Span& sp, const ::HIR::TypeRef& x, t_cb_resolve_type resolve_placeholder) const { - TRACE_FUNCTION_F(*this << " ?= " << x); + //TRACE_FUNCTION_F(*this << " ?= " << x); const auto& left = (m_data.is_Infer() || m_data.is_Generic() ? resolve_placeholder(*this) : *this); //const auto& left = *this; const auto& right = (x.m_data.is_Infer() ? resolve_placeholder(x) : (x.m_data.is_Generic() ? resolve_placeholder(x) : x)); -- cgit v1.2.3 From 880d23e75d2408a1b8ce9bc545241c17a48e8f3c Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 9 Dec 2018 08:35:10 +0800 Subject: HIR Typecheck - Enumeration of potential type values and elimination using known bounds Potential types from trait bounds are enumerated and, if there's no possible coercions/unsizing, are searched for a single type that meets all known conditions (i.e. trait bounds on the ivar, and method existence) --- src/hir_typeck/expr_cs.cpp | 300 ++++++++++++++++++++++++++++++++++----------- src/hir_typeck/helpers.cpp | 8 +- 2 files changed, 231 insertions(+), 77 deletions(-) diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index a236c818..23deda62 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -75,11 +75,16 @@ struct Context { bool force_no_to = false; bool force_no_from = false; + // Target types for coercion/unsizing (these types are known to exist in the function) ::std::vector<::HIR::TypeRef> types_coerce_to; ::std::vector<::HIR::TypeRef> types_unsize_to; + // Source types for coercion/unsizing (these types are known to exist in the function) ::std::vector<::HIR::TypeRef> types_coerce_from; ::std::vector<::HIR::TypeRef> types_unsize_from; + // Possible default types (from generic defaults) //::std::vector<::HIR::TypeRef> types_default; + // Possible types from trait impls (may introduce new types) + ::std::vector<::HIR::TypeRef> bounded; void reset() { //auto tmp = mv$(this->types_default); @@ -87,7 +92,19 @@ struct Context //this->types_default = mv$(tmp); } bool has_rules() const { - return !types_unsize_to.empty() || !types_coerce_to.empty() || !types_unsize_from.empty() || !types_coerce_from.empty() /* || !types_default.empty()*/; + if( !types_coerce_to.empty() ) + return true; + if( !types_unsize_to.empty() ) + return true; + if( !types_coerce_from.empty() ) + return true; + if( !types_unsize_from.empty() ) + return true; + //if( !types_default.empty() ) + // return true; + if( !bounded.empty() ) + return true; + return false; } }; @@ -104,6 +121,8 @@ struct Context /// Callback-based revisits (e.g. for slice patterns handling slices/arrays) ::std::vector< ::std::unique_ptr > adv_revisits; + // Keep track of if an ivar is used in a context where it has to be Sized + // - If it is, then we can discount any unsized possibilities ::std::vector m_ivars_sized; ::std::vector< IVarPossible> possible_ivar_vals; @@ -190,6 +209,8 @@ struct Context } /// Default type //void possible_equate_type_def(unsigned int ivar_index, const ::HIR::TypeRef& t); + /// Add a possible type for an ivar (which is used if only one possibility meets available bounds) + void possible_equate_type_bound(unsigned int ivar_index, const ::HIR::TypeRef& t); void possible_equate_type(unsigned int ivar_index, const ::HIR::TypeRef& t, bool is_to, bool is_borrow); void possible_equate_type_disable(unsigned int ivar_index, bool is_to); @@ -2665,6 +2686,7 @@ namespace { DEBUG("possible_methods = " << possible_methods); if( possible_methods.empty() ) { + //ERROR(sp, E0000, "Could not find method `" << method_name << "` on type `" << top_ty << "`"); ERROR(sp, E0000, "No applicable methods for {" << ty << "}." << node.m_method); } if( possible_methods.size() > 1 ) @@ -4231,6 +4253,25 @@ void Context::possible_equate_type(unsigned int ivar_index, const ::HIR::TypeRef ); list.push_back( t.clone() ); } +void Context::possible_equate_type_bound(unsigned int ivar_index, const ::HIR::TypeRef& t) { + DEBUG(ivar_index << " bounded as " << t << " " << this->m_ivars.get_type(t)); + { + ::HIR::TypeRef ty_l; + ty_l.m_data.as_Infer().index = ivar_index; + const auto& real_ty = m_ivars.get_type(ty_l); + if( real_ty != ty_l ) + { + DEBUG("IVar " << ivar_index << " is actually " << real_ty); + return ; + } + } + + if( ivar_index >= possible_ivar_vals.size() ) { + possible_ivar_vals.resize( ivar_index + 1 ); + } + auto& ent = possible_ivar_vals[ivar_index]; + ent.bounded.push_back( t.clone() ); +} void Context::possible_equate_type_disable(unsigned int ivar_index, bool is_to) { DEBUG(ivar_index << " ?= ?? (" << (is_to ? "to" : "from") << ")"); { @@ -5221,8 +5262,6 @@ namespace { const auto& sp = v.span; TRACE_FUNCTION_F(v); - ::HIR::TypeRef possible_impl_ty; - ::HIR::PathParams possible_params; ::HIR::TypeRef output_type; struct H { @@ -5286,7 +5325,12 @@ namespace { // Locate applicable trait impl unsigned int count = 0; DEBUG("Searching for impl " << v.trait << v.params << " for " << context.m_ivars.fmt_type(v.impl_ty)); - ImplRef best_impl; + struct Possibility { + ::HIR::TypeRef impl_ty; + ::HIR::PathParams params; + ImplRef impl_ref; + }; + ::std::vector possible_impls; bool found = context.m_resolve.find_trait_impls(sp, v.trait, v.params, v.impl_ty, [&](auto impl, auto cmp) { DEBUG("[check_associated] Found cmp=" << cmp << " " << impl); @@ -5328,47 +5372,58 @@ namespace { count += 1; DEBUG("[check_associated] - (possible) " << impl); - if( possible_impl_ty == ::HIR::TypeRef() ) { + if( possible_impls.empty() ) { DEBUG("[check_associated] First - " << impl); - possible_impl_ty = impl.get_impl_type(); - possible_params = impl.get_trait_params(); - best_impl = mv$(impl); + possible_impls.push_back({ impl.get_impl_type(), impl.get_trait_params(), mv$(impl) }); } - // TODO: If there is an existing impl, determine if this is part of the same specialisation tree + // If there is an existing impl, determine if this is part of the same specialisation tree // - If more specific, replace. If less, ignore. - #if 1 // NOTE: `overlaps_with` (should be) reflective - else if( impl.overlaps_with(context.m_crate, best_impl) ) + else { - DEBUG("[check_associated] - Overlaps with existing - " << best_impl); - // if not more specific than the existing best, ignore. - if( ! impl.more_specific_than(best_impl) ) - { - DEBUG("[check_associated] - Less specific than existing"); - // NOTE: This picks the _least_ specific impl - possible_impl_ty = impl.get_impl_type(); - possible_params = impl.get_trait_params(); - best_impl = mv$(impl); - count -= 1; - } - // If the existing best is not more specific than the new one, use the new one - else if( ! best_impl.more_specific_than(impl) ) + bool was_used = false; + for(auto& possible_impl : possible_impls) { - DEBUG("[check_associated] - More specific than existing - " << impl); - count -= 1; + const auto& best_impl = possible_impl.impl_ref; + if( impl.overlaps_with(context.m_crate, best_impl) ) + { + DEBUG("[check_associated] - Overlaps with existing - " << best_impl); + // if not more specific than the existing best, ignore. + if( ! impl.more_specific_than(best_impl) ) + { + DEBUG("[check_associated] - Less specific than existing"); + // NOTE: This picks the _least_ specific impl + possible_impl.impl_ty = impl.get_impl_type(); + possible_impl.params = impl.get_trait_params(); + possible_impl.impl_ref = mv$(impl); + count -= 1; + } + // If the existing best is not more specific than the new one, use the new one + else if( ! best_impl.more_specific_than(impl) ) + { + DEBUG("[check_associated] - More specific than existing - " << best_impl); + count -= 1; + } + else + { + // Supposedly, `more_specific_than` should be reflexive... + DEBUG("[check_associated] > Neither is more specific. Error?"); + } + was_used = true; + break; + } + else + { + // Disjoint impls. + DEBUG("[check_associated] Disjoint with " << best_impl); + } } - else + if( !was_used ) { - // Supposedly, `more_specific_than` should be reflexive... - DEBUG("[check_associated] > Neither is more specific. Error?"); + DEBUG("[check_associated] Add new possible impl " << impl); + possible_impls.push_back({ impl.get_impl_type(), impl.get_trait_params(), mv$(impl) }); } } - else - { - // Disjoint impls. - DEBUG("[check_associated] Disjoint impl -" << impl); - } - #endif return false; } @@ -5430,6 +5485,9 @@ namespace { } } else if( count == 1 ) { + auto& possible_impl_ty = possible_impls.at(0).impl_ty; + auto& possible_params = possible_impls.at(0).params; + auto& best_impl = possible_impls.at(0).impl_ref; DEBUG("Only one impl " << v.trait << context.m_ivars.fmt(possible_params) << " for " << context.m_ivars.fmt_type(possible_impl_ty) << " - out=" << output_type); // - If there are any magic params in the impl, don't use it yet. @@ -5449,8 +5507,7 @@ namespace { if( TU_TEST1(impl_ty.m_data, Infer, .is_lit() == false) ) { DEBUG("Unbounded ivar, waiting - TODO: Add possibility " << impl_ty << " == " << possible_impl_ty); - context.possible_equate_type_coerce_to(impl_ty.m_data.as_Infer().index, possible_impl_ty); - context.possible_equate_type_coerce_from(impl_ty.m_data.as_Infer().index, possible_impl_ty); + //context.possible_equate_type_bound(impl_ty.m_data.as_Infer().index, possible_impl_ty); return false; } // Only one possible impl @@ -5506,32 +5563,75 @@ namespace { else { // Multiple possible impls, don't know yet DEBUG("Multiple impls"); + for(const auto& pi : possible_impls) + { + DEBUG(pi.params << " for " << pi.impl_ty); + for(size_t i = 0; i < pi.params.m_types.size(); i++) + { + const auto& t = context.get_type(v.params.m_types[i]); + if( const auto* e = t.m_data.opt_Infer() ) { + context.possible_equate_type_bound(e->index, pi.params.m_types[i]); + } + } + } return false; } } - bool check_ivar_poss(Context& context, unsigned int i, Context::IVarPossible& ivar_ent, bool honour_disable=true) + bool check_ivar_poss__fails_bounds(const Span& sp, Context& context, const ::HIR::TypeRef& ty_l, const ::HIR::TypeRef& new_ty) { - static Span _span; - const auto& sp = _span; + for(const auto& bound : context.link_assoc) + { + // TODO: Monomorphise this type replacing mentions of the current ivar with the replacement? + if( bound.impl_ty != ty_l ) + continue ; + + // Search for any trait impl that could match this, + bool has = context.m_resolve.find_trait_impls(sp, bound.trait, bound.params, new_ty, [&](const auto , auto){return true;}); + if( !has ) { + // If none was found, remove from the possibility list + DEBUG("Remove possibility " << new_ty << " because it failed a bound"); + return true; + } + } - if( ! ivar_ent.has_rules() ) { - // No rules, don't do anything (and don't print) - DEBUG(i << ": No rules"); - return false; + // Handle methods + for(const auto* node_ptr_dyn : context.to_visit) + { + if( const auto* node_ptr = dynamic_cast(node_ptr_dyn) ) + { + const auto& node = *node_ptr; + const auto& ty_tpl = context.get_type(node.m_value->m_res_type); + + bool used_ty = false; + auto t = clone_ty_with(sp, ty_tpl, [&](const auto& ty, auto& out_ty){ if( ty == ty_l ) { out_ty = new_ty.clone(); used_ty = true; return true; } else { return false; }}); + if(!used_ty) + continue; + + DEBUG("Check <" << t << ">::" << node.m_method); + ::std::vector<::std::pair> possible_methods; + unsigned int deref_count = context.m_resolve.autoderef_find_method(node.span(), node.m_traits, node.m_trait_param_ivars, t, node.m_method, possible_methods); + DEBUG("> deref_count = " << deref_count << ", " << possible_methods); + if( possible_methods.empty() ) + { + // No method found, which would be an error + return true; + } + } + else + { + } } - ::HIR::TypeRef ty_l_ivar; - ty_l_ivar.m_data.as_Infer().index = i; - const auto& ty_l = context.m_ivars.get_type(ty_l_ivar); - bool allow_unsized = !(i < context.m_ivars_sized.size() ? context.m_ivars_sized.at(i) : false); + return false; + } - if( ty_l != ty_l_ivar ) { - DEBUG("- IVar " << i << " had possibilities, but was known to be " << ty_l); - // Completely clear by reinitialising - ivar_ent = Context::IVarPossible(); - return false; - } + bool check_ivar_poss__coercions(Context& context, unsigned int i, Context::IVarPossible& ivar_ent, const ::HIR::TypeRef& ty_l, bool honour_disable=true) + { + static Span _span; + const auto& sp = _span; + + bool allow_unsized = !(i < context.m_ivars_sized.size() ? context.m_ivars_sized.at(i) : false); enum class DedupKeep { Both, @@ -5831,9 +5931,6 @@ namespace { } else { - TRACE_FUNCTION_F(i); - - // TODO: Dedup based on context? // - The dedup should probably be aware of the way the types are used (for coercions). H::dedup_type_list(context, ivar_ent.types_coerce_to); @@ -5992,22 +6089,7 @@ namespace { const auto& new_ty = context.get_type(*it); if( !new_ty.m_data.is_Infer() ) { - for(const auto& bound : context.link_assoc) - { - if( bound.impl_ty != ty_l ) - continue ; - - // TODO: Monomorphise this type replacing mentions of the current ivar with the replacement? - - // Search for any trait impl that could match this, - bool has = context.m_resolve.find_trait_impls(sp, bound.trait, bound.params, new_ty, [&](const auto , auto){return true;}); - if( !has ) { - // If none was found, remove from the possibility list - remove = true; - DEBUG("Remove possibility " << new_ty << " because it failed a bound"); - break ; - } - } + remove = check_ivar_poss__fails_bounds(sp, context, ty_l, new_ty); if( !remove && !allow_unsized ) { @@ -6142,6 +6224,77 @@ namespace { return false; } + + /// Check IVar possibilities, from both coercion/unsizing (which have well-encoded rules) and from trait impls + bool check_ivar_poss(Context& context, unsigned int i, Context::IVarPossible& ivar_ent, bool honour_disable=true) + { + static Span _span; + const auto& sp = _span; + + if( ! ivar_ent.has_rules() ) { + // No rules, don't do anything (and don't print) + DEBUG(i << ": No rules"); + return false; + } + + if( honour_disable && (ivar_ent.force_no_to || ivar_ent.force_no_from) ) + { + DEBUG(i << ": forced unknown"); + return false; + } + + ::HIR::TypeRef ty_l_ivar; + ty_l_ivar.m_data.as_Infer().index = i; + const auto& ty_l = context.m_ivars.get_type(ty_l_ivar); + + if( ty_l != ty_l_ivar ) { + DEBUG("- IVar " << i << " had possibilities, but was known to be " << ty_l); + // Completely clear by reinitialising + ivar_ent = Context::IVarPossible(); + return false; + } + + TRACE_FUNCTION_F(i); + + + if( check_ivar_poss__coercions(context, i, ivar_ent, ty_l, honour_disable) ) + { + return true; + } + + if( !ivar_ent.bounded.empty() ) + { + // TODO: Search know possibilties and check if they satisfy the bounds for this ivar + unsigned int n_good = 0; + const ::HIR::TypeRef* only_good; + for(const auto& new_ty : ivar_ent.bounded) + { + DEBUG("- Test " << new_ty << " against current rules"); + if( check_ivar_poss__fails_bounds(sp, context, ty_l, new_ty) ) + { + } + else + { + n_good ++; + only_good = &new_ty; + DEBUG("> " << new_ty << " feasible"); + } + } + if(n_good == 1 + && ivar_ent.types_coerce_from.size() == 0 && ivar_ent.types_coerce_to.size() == 0 + && ivar_ent.types_unsize_from.size() == 0 && ivar_ent.types_unsize_to.size() == 0 + ) + { + DEBUG("Only " << *only_good << " fits current bound sets"); + // Since it's the only possibility, choose it? + context.equate_types(sp, ty_l, *only_good); + return true; + } + DEBUG(n_good << " valid options"); + } + + return false; + } } @@ -6300,6 +6453,7 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR: { // Check the possible equations DEBUG("--- IVar possibilities"); + // TODO: De-duplicate this with the block ~80 lines below // NOTE: Ordering is a hack for libgit2 for(unsigned int i = context.possible_ivar_vals.size(); i --; ) { diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index 4d3ea82d..06995914 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -2280,9 +2280,9 @@ bool TraitResolution::find_trait_impls_bound(const Span& sp, const ::HIR::Simple const auto& b_params = bound_trait.m_path.m_params; auto cmp = bound_ty .compare_with_placeholders(sp, type, m_ivars.callback_resolve_infer()); - DEBUG("cmp = " << cmp); if( cmp == ::HIR::Compare::Unequal ) return false; + DEBUG("[find_trait_impls_bound] " << bound_trait << " for " << bound_ty << " cmp = " << cmp); if( bound_trait.m_path.m_path == trait ) { // Check against `params` @@ -3707,9 +3707,9 @@ unsigned int TraitResolution::autoderef_find_method(const Span& sp, } } while(current_ty); - // Dereference failed! This is a hard error (hitting _ is checked above and returns ~0) - //this->m_ivars.dump(); - ERROR(sp, E0000, "Could not find method `" << method_name << "` on type `" << top_ty << "`"); + // No method found, return an empty list and return 0 + assert( possibilities.empty() ); + return 0; } ::std::ostream& operator<<(::std::ostream& os, const TraitResolution::AutoderefBorrow& x) -- cgit v1.2.3 From c071e39c9d5b5d28863471e32607acf932cf3c10 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 9 Dec 2018 09:06:06 +0800 Subject: HIR Typecheck - Hack when method resolution finds both a bound and an available trait --- src/hir_typeck/expr_cs.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 23deda62..13eabe9c 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -2745,7 +2745,14 @@ namespace { trait_params.m_types.push_back( ::HIR::TypeRef::new_infer(ivars[i], ::HIR::InferClass::None) ); //ASSERT_BUG(sp, m_ivars.get_type( trait_params.m_types.back() ).m_data.as_Infer().index == ivars[i], "A method selection ivar was bound"); } - e1.trait.m_params = mv$(trait_params); + // If one of these was already using the placeholder ivars, then maintain the other one? + if( e2.trait.m_params == trait_params ) + { + } + else + { + e1.trait.m_params = mv$(trait_params); + } it_2 = possible_methods.erase(it_2) - 1; } -- cgit v1.2.3 From ae0027ac83893674397008a5153c6418f61ed28b Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 9 Dec 2018 12:20:50 +0800 Subject: minicargo.mk - Fix bad shell command --- minicargo.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/minicargo.mk b/minicargo.mk index ef83d554..70b4c058 100644 --- a/minicargo.mk +++ b/minicargo.mk @@ -5,7 +5,7 @@ OUTDIR_SUF ?= MMIR ?= RUSTC_CHANNEL ?= stable -RUSTC_VERSION ?= $(cat rust-version) +RUSTC_VERSION ?= $(shell cat rust-version) ifeq ($(OS),Windows_NT) else ifeq ($(shell uname -s || echo not),Darwin) OVERRIDE_SUFFIX ?= -macos -- cgit v1.2.3 From 998de6c1b99b44f6049f744c713657587f91e1ac Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 19 Oct 2018 07:40:53 +0800 Subject: Codegen C - Fix incorrect use of ZST in enum constructor shim (fixes #86) --- src/trans/codegen_c.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 1bbafcd2..a1b3d065 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -1575,7 +1575,7 @@ namespace { { if( this->type_is_bad_zst(repr->fields[var_idx].ty) ) { - m_of << " .DATA = { /* ZST Variant */ }"; + //m_of << " .DATA = { /* ZST Variant */ }"; } else { -- cgit v1.2.3 From 6e16b6d9df92e7ec3222984502f580e46dae09f6 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 9 Dec 2018 21:42:34 +0800 Subject: HIR Typecheck - Fix incorrect equality/success markings --- src/hir_typeck/helpers.cpp | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index 06995914..27728dbe 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -188,17 +188,17 @@ bool HMTypeInferrence::apply_defaults() break; case ::HIR::InferClass::Diverge: rv = true; - DEBUG("- " << *v.type << " -> !"); + DEBUG("- IVar " << e.index << " = !"); *v.type = ::HIR::TypeRef(::HIR::TypeRef::Data::make_Diverge({})); break; case ::HIR::InferClass::Integer: rv = true; - DEBUG("- " << *v.type << " -> i32"); + DEBUG("- IVar " << e.index << " = i32"); *v.type = ::HIR::TypeRef( ::HIR::CoreType::I32 ); break; case ::HIR::InferClass::Float: rv = true; - DEBUG("- " << *v.type << " -> f64"); + DEBUG("- IVar " << e.index << " = f64"); *v.type = ::HIR::TypeRef( ::HIR::CoreType::F64 ); break; } @@ -2253,9 +2253,9 @@ bool TraitResolution::find_named_trait_in_trait(const Span& sp, //auto cmp = this->compare_pp(sp, pt_mono.m_path.m_params, des_params); //if( cmp != ::HIR::Compare::Unequal ) //{ - callback( target_type, pt_mono.m_path.m_params, pt_mono.m_type_bounds ); + if( callback( target_type, pt_mono.m_path.m_params, pt_mono.m_type_bounds ) ) + return true; //} - return true; } } @@ -2312,7 +2312,7 @@ bool TraitResolution::find_trait_impls_bound(const Span& sp, const ::HIR::Simple trait,params, *bound_trait.m_trait_ptr, bound_trait.m_path.m_path,bound_trait.m_path.m_params, type, - [&](const auto& ty, const auto& params, const auto& assoc) { + [&](const auto& ty, const auto& b_params, const auto& assoc) { // TODO: Avoid duplicating this map every time ::std::map< ::std::string,::HIR::TypeRef> assoc2; for(const auto& i : assoc) { @@ -2324,7 +2324,15 @@ bool TraitResolution::find_trait_impls_bound(const Span& sp, const ::HIR::Simple assoc2.insert( ::std::make_pair(i.first, i.second.clone()) ); //} } - return callback( ImplRef(ty.clone(), params.clone(), mv$(assoc2)), ::HIR::Compare::Equal ); + // TODO: Check param equality + auto ord = ::HIR::Compare::Equal; + ord &= this->compare_pp(sp, b_params, params); + if( ord == ::HIR::Compare::Unequal ) + return false; + if( ord == ::HIR::Compare::Fuzzy ) { + DEBUG("Fuzzy match"); + } + return callback( ImplRef(ty.clone(), b_params.clone(), mv$(assoc2)), ord ); }); if( rv ) { return true; -- cgit v1.2.3 From 937b161b40dd6dfdaa0a55c1399b3af2d23227d7 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 9 Dec 2018 21:42:59 +0800 Subject: HIR Typecheck Expr - Handle duplicate bounded options for types --- src/hir_typeck/expr_cs.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 13eabe9c..23ac0afd 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -4277,6 +4277,9 @@ void Context::possible_equate_type_bound(unsigned int ivar_index, const ::HIR::T possible_ivar_vals.resize( ivar_index + 1 ); } auto& ent = possible_ivar_vals[ivar_index]; + for(const auto& e : ent.bounded) + if( e == t ) + return ; ent.bounded.push_back( t.clone() ); } void Context::possible_equate_type_disable(unsigned int ivar_index, bool is_to) { @@ -5392,6 +5395,7 @@ namespace { for(auto& possible_impl : possible_impls) { const auto& best_impl = possible_impl.impl_ref; + // TODO: Handle duplicates (from overlapping bounds) if( impl.overlaps_with(context.m_crate, best_impl) ) { DEBUG("[check_associated] - Overlaps with existing - " << best_impl); -- cgit v1.2.3 From f4c39e95caf3c9a8ccd302dbd9eca92b32564c27 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 16 Dec 2018 16:53:46 +0800 Subject: Typecheck Expressions - Extended possibility checking, fallback default (HACK) --- src/hir_typeck/common.cpp | 21 ++++++----- src/hir_typeck/common.hpp | 1 + src/hir_typeck/expr_cs.cpp | 94 ++++++++++++++++++++++++++++++++++++++-------- src/hir_typeck/helpers.cpp | 22 +++++++++-- 4 files changed, 110 insertions(+), 28 deletions(-) diff --git a/src/hir_typeck/common.cpp b/src/hir_typeck/common.cpp index 4b0328e7..1bb21f99 100644 --- a/src/hir_typeck/common.cpp +++ b/src/hir_typeck/common.cpp @@ -144,7 +144,7 @@ bool monomorphise_type_needed(const ::HIR::TypeRef& tpl) } -::HIR::PathParams clone_ty_with__path_params(const Span& sp, const ::HIR::PathParams& tpl, t_cb_clone_ty callback) { +::HIR::PathParams clone_path_params_with(const Span& sp, const ::HIR::PathParams& tpl, t_cb_clone_ty callback) { ::HIR::PathParams rv; rv.m_types.reserve( tpl.m_types.size() ); for( const auto& ty : tpl.m_types) @@ -152,7 +152,7 @@ bool monomorphise_type_needed(const ::HIR::TypeRef& tpl) return rv; } ::HIR::GenericPath clone_ty_with__generic_path(const Span& sp, const ::HIR::GenericPath& tpl, t_cb_clone_ty callback) { - return ::HIR::GenericPath( tpl.m_path, clone_ty_with__path_params(sp, tpl.m_params, callback) ); + return ::HIR::GenericPath( tpl.m_path, clone_path_params_with(sp, tpl.m_params, callback) ); } ::HIR::TraitPath clone_ty_with__trait_path(const Span& sp, const ::HIR::TraitPath& tpl, t_cb_clone_ty callback) { ::HIR::TraitPath rv { @@ -181,22 +181,22 @@ bool monomorphise_type_needed(const ::HIR::TypeRef& tpl) box$( clone_ty_with(sp, *e2.type, callback) ), clone_ty_with__generic_path(sp, e2.trait, callback), e2.item, - clone_ty_with__path_params(sp, e2.params, callback) + clone_path_params_with(sp, e2.params, callback) }); ), (UfcsUnknown, return ::HIR::Path::Data::make_UfcsUnknown({ box$( clone_ty_with(sp, *e2.type, callback) ), e2.item, - clone_ty_with__path_params(sp, e2.params, callback) + clone_path_params_with(sp, e2.params, callback) }); ), (UfcsInherent, return ::HIR::Path::Data::make_UfcsInherent({ box$( clone_ty_with(sp, *e2.type, callback) ), e2.item, - clone_ty_with__path_params(sp, e2.params, callback), - clone_ty_with__path_params(sp, e2.impl_params, callback) + clone_path_params_with(sp, e2.params, callback), + clone_path_params_with(sp, e2.impl_params, callback) }); ) ) @@ -207,7 +207,7 @@ bool monomorphise_type_needed(const ::HIR::TypeRef& tpl) ::HIR::TypeRef rv; if( callback(tpl, rv) ) { - DEBUG(tpl << " => " << rv); + //DEBUG(tpl << " => " << rv); return rv; } @@ -226,8 +226,9 @@ bool monomorphise_type_needed(const ::HIR::TypeRef& tpl) clone_ty_with__path(sp, e.path, callback), e.binding.clone() } ); - // If the input binding was Opaque, clear it back to Unbound - if( e.binding.is_Opaque() ) { + // If the input binding was Opaque, AND the type changed, clear it back to Unbound + if( e.binding.is_Opaque() /*&& rv != tpl*/ ) { + // NOTE: The replacement can be Self=Self, which should trigger a binding clear. rv.m_data.as_Path().binding = ::HIR::TypeRef::TypePathBinding(); } ), @@ -323,7 +324,7 @@ namespace { ::HIR::PathParams monomorphise_path_params_with(const Span& sp, const ::HIR::PathParams& tpl, t_cb_generic callback, bool allow_infer) { - return clone_ty_with__path_params(sp, tpl, monomorphise_type_with__closure(sp, tpl, callback, allow_infer)); + return clone_path_params_with(sp, tpl, monomorphise_type_with__closure(sp, tpl, callback, allow_infer)); } ::HIR::GenericPath monomorphise_genericpath_with(const Span& sp, const ::HIR::GenericPath& tpl, t_cb_generic callback, bool allow_infer) { diff --git a/src/hir_typeck/common.hpp b/src/hir_typeck/common.hpp index 14d9162f..c0e495a6 100644 --- a/src/hir_typeck/common.hpp +++ b/src/hir_typeck/common.hpp @@ -38,6 +38,7 @@ extern bool visit_path_tys_with(const ::HIR::Path& ty, t_cb_visit_ty callback); typedef ::std::function t_cb_clone_ty; /// Clones a type, calling the provided callback on every type (optionally providing a replacement) extern ::HIR::TypeRef clone_ty_with(const Span& sp, const ::HIR::TypeRef& tpl, t_cb_clone_ty callback); +extern ::HIR::PathParams clone_path_params_with(const Span& sp, const ::HIR::PathParams& tpl, t_cb_clone_ty callback); // Helper for passing a group of params around struct MonomorphState diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 23ac0afd..a7c5ddee 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -2712,6 +2712,13 @@ namespace { // - If the self type and the trait name are the same, replace with an entry using placeholder // ivars (node.m_trait_param_ivars) for(auto it_1 = possible_methods.begin(); it_1 != possible_methods.end(); ++ it_1) + { + if( it_1->first != possible_methods.front().first ) + { + it_1 = possible_methods.erase(it_1) - 1; + } + } + for(auto it_1 = possible_methods.begin(); it_1 != possible_methods.end(); ++ it_1) { if( !it_1->second.m_data.is_UfcsKnown() ) continue; @@ -2727,10 +2734,17 @@ namespace { } const auto& e2 = it_2->second.m_data.as_UfcsKnown(); + // TODO: If the trait is the same, but the type differs, pick the first? + if( e1.trait == e2.trait ) { + DEBUG("Duplicate trait, different type - " << e1.trait << " for " << *e1.type << " or " << *e2.type << ", picking the first"); + it_2 = possible_methods.erase(it_2) - 1; + continue ; + } if( *e1.type != *e2.type ) continue; if( e1.trait.m_path != e2.trait.m_path ) continue; + assert( !(e1.trait.m_params == e2.trait.m_params) ); DEBUG("Duplicate trait in possible_methods - " << it_1->second << " and " << it_2->second); if( !was_found ) @@ -2745,11 +2759,8 @@ namespace { trait_params.m_types.push_back( ::HIR::TypeRef::new_infer(ivars[i], ::HIR::InferClass::None) ); //ASSERT_BUG(sp, m_ivars.get_type( trait_params.m_types.back() ).m_data.as_Infer().index == ivars[i], "A method selection ivar was bound"); } - // If one of these was already using the placeholder ivars, then maintain the other one? - if( e2.trait.m_params == trait_params ) - { - } - else + // If one of these was already using the placeholder ivars, then maintain the one with the palceholders + if( e1.trait.m_params != trait_params ) { e1.trait.m_params = mv$(trait_params); } @@ -2759,6 +2770,12 @@ namespace { } } } + assert( !possible_methods.empty() ); + if( possible_methods.size() != 1 && possible_methods.front().second.m_data.is_UfcsKnown() ) + { + DEBUG("- Multiple options, deferring"); + return; + } auto& ad_borrow = possible_methods.front().first; auto& fcn_path = possible_methods.front().second; DEBUG("- deref_count = " << deref_count << ", fcn_path = " << fcn_path); @@ -4261,7 +4278,6 @@ void Context::possible_equate_type(unsigned int ivar_index, const ::HIR::TypeRef list.push_back( t.clone() ); } void Context::possible_equate_type_bound(unsigned int ivar_index, const ::HIR::TypeRef& t) { - DEBUG(ivar_index << " bounded as " << t << " " << this->m_ivars.get_type(t)); { ::HIR::TypeRef ty_l; ty_l.m_data.as_Infer().index = ivar_index; @@ -4278,9 +4294,21 @@ void Context::possible_equate_type_bound(unsigned int ivar_index, const ::HIR::T } auto& ent = possible_ivar_vals[ivar_index]; for(const auto& e : ent.bounded) + { if( e == t ) + { + if( t.m_data.is_Infer() ) + DEBUG(ivar_index << " duplicate bounded " << t << " " << this->m_ivars.get_type(t)); + else + DEBUG(ivar_index << " duplicate bounded " << t); return ; + } + } ent.bounded.push_back( t.clone() ); + if( t.m_data.is_Infer() ) + DEBUG(ivar_index << " bounded as " << t << " " << this->m_ivars.get_type(t)); + else + DEBUG(ivar_index << " bounded as " << t); } void Context::possible_equate_type_disable(unsigned int ivar_index, bool is_to) { DEBUG(ivar_index << " ?= ?? (" << (is_to ? "to" : "from") << ")"); @@ -5593,17 +5621,49 @@ namespace { { for(const auto& bound : context.link_assoc) { - // TODO: Monomorphise this type replacing mentions of the current ivar with the replacement? - if( bound.impl_ty != ty_l ) - continue ; + bool used_ty = false; + auto cb = [&](const ::HIR::TypeRef& ty, ::HIR::TypeRef& out_ty){ if( ty == ty_l ) { out_ty = new_ty.clone(); used_ty = true; return true; } else { return false; }}; + auto t = clone_ty_with(sp, bound.impl_ty, cb); + auto p = clone_path_params_with(sp, bound.params, cb); + if(!used_ty) + continue; + // - Run EAT on t and p + t = context.m_resolve.expand_associated_types( sp, mv$(t) ); + // TODO: EAT on `p` + DEBUG("Check " << t << " : " << bound.trait << p); + DEBUG("- From " << bound.impl_ty << " : " << bound.trait << bound.params); // Search for any trait impl that could match this, - bool has = context.m_resolve.find_trait_impls(sp, bound.trait, bound.params, new_ty, [&](const auto , auto){return true;}); - if( !has ) { + bool bound_failed = true; + context.m_resolve.find_trait_impls(sp, bound.trait, p, t, [&](const auto impl, auto cmp){ + // If this bound specifies an associated type, then check that that type could match + if( bound.name != "" ) + { + auto aty = impl.get_type(bound.name.c_str()); + if( aty == ::HIR::TypeRef() ) { + // A possible match was found, so don't delete just yet + bound_failed = false; + // - Return false to keep searching + return false; + } + else if( aty.compare_with_placeholders(sp, bound.left_ty, context.m_ivars.callback_resolve_infer()) == HIR::Compare::Unequal ) { + bound_failed = true; + // - Bail instantly + return true; + } + else { + } + } + bound_failed = false; + return true; + }); + if( bound_failed ) { // If none was found, remove from the possibility list DEBUG("Remove possibility " << new_ty << " because it failed a bound"); return true; } + + // TODO: Check for the resultant associated type } // Handle methods @@ -6276,8 +6336,9 @@ namespace { if( !ivar_ent.bounded.empty() ) { // TODO: Search know possibilties and check if they satisfy the bounds for this ivar + DEBUG("Options: " << ivar_ent.bounded); unsigned int n_good = 0; - const ::HIR::TypeRef* only_good; + const ::HIR::TypeRef* only_good = nullptr; for(const auto& new_ty : ivar_ent.bounded) { DEBUG("- Test " << new_ty << " against current rules"); @@ -6287,11 +6348,14 @@ namespace { else { n_good ++; - only_good = &new_ty; + if( !only_good ) + only_good = &new_ty; DEBUG("> " << new_ty << " feasible"); } } - if(n_good == 1 + // Picks the first if in fallback mode (which is signalled by `honour_disable` being false) + // - This handles the case where there's multiple valid options (needed for libcompiler_builtins) + if( (honour_disable ? n_good == 1 : n_good > 0) && ivar_ent.types_coerce_from.size() == 0 && ivar_ent.types_coerce_to.size() == 0 && ivar_ent.types_unsize_from.size() == 0 && ivar_ent.types_unsize_to.size() == 0 ) @@ -6635,7 +6699,7 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR: const auto& sp = node->span(); if( const auto* np = dynamic_cast<::HIR::ExprNode_CallMethod*>(node) ) { - WARNING(sp, W0000, "Spare Rule - {" << context.m_ivars.fmt_type(np->m_value->m_res_type) << "}." << np->m_method); + WARNING(sp, W0000, "Spare Rule - {" << context.m_ivars.fmt_type(np->m_value->m_res_type) << "}." << np->m_method << " -> " << context.m_ivars.fmt_type(np->m_res_type)); } else { diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index 27728dbe..b353e6a7 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -2247,7 +2247,7 @@ bool TraitResolution::find_named_trait_in_trait(const Span& sp, { auto pt_mono = monomorphise_traitpath_with(sp, pt, monomorph_cb, false); - DEBUG(pt << " => " << pt_mono); + //DEBUG(pt << " => " << pt_mono); if( pt.m_path.m_path == des ) { // NOTE: Doesn't quite work... //auto cmp = this->compare_pp(sp, pt_mono.m_path.m_params, des_params); @@ -3890,6 +3890,7 @@ bool TraitResolution::find_method(const Span& sp, method_name, {} }) ) )); + DEBUG("++ " << possibilities.back()); rv = true; } else if( cmp == ::HIR::Compare::Fuzzy ) @@ -3904,6 +3905,7 @@ bool TraitResolution::find_method(const Span& sp, method_name, {} }) ) )); + DEBUG("++ " << possibilities.back()); rv = true; } else @@ -3959,6 +3961,7 @@ bool TraitResolution::find_method(const Span& sp, if(const auto* self_ty_p = check_method_receiver(sp, *fcn_ptr, ty, access)) { possibilities.push_back(::std::make_pair(borrow_type, ::HIR::Path(self_ty_p->clone(), mv$(final_trait_path), method_name, {}) )); + DEBUG("++ " << possibilities.back()); rv = true; } } @@ -3981,6 +3984,7 @@ bool TraitResolution::find_method(const Span& sp, if(const auto* self_ty_p = check_method_receiver(sp, *fcn_ptr, ty, access)) { possibilities.push_back(::std::make_pair(borrow_type, ::HIR::Path(self_ty_p->clone(), mv$(final_trait_path), method_name, {}) )); + DEBUG("++ " << possibilities.back()); rv = true; } } @@ -4039,6 +4043,7 @@ bool TraitResolution::find_method(const Span& sp, // Found the method, return the UFCS path for it possibilities.push_back(::std::make_pair( borrow_type, ::HIR::Path(self_ty_p->clone(), mv$(final_trait_path), method_name, {}) )); + DEBUG("++ " << possibilities.back()); rv = true; } } @@ -4077,6 +4082,7 @@ bool TraitResolution::find_method(const Span& sp, // Found the method, return the UFCS path for it possibilities.push_back(::std::make_pair( borrow_type, ::HIR::Path(self_ty_p->clone(), mv$(final_trait_path), method_name, {}) )); + DEBUG("++ " << possibilities.back()); rv = true; } } @@ -4104,6 +4110,7 @@ bool TraitResolution::find_method(const Span& sp, if( *self_ty_p == *cur_check_ty ) { possibilities.push_back(::std::make_pair( borrow_type, ::HIR::Path(self_ty_p->clone(), method_name, {}) )); + DEBUG("++ " << possibilities.back()); return true; } } @@ -4156,10 +4163,19 @@ bool TraitResolution::find_method(const Span& sp, // TODO: Re-monomorphise the trait path! - //if( find_trait_impls(sp, *trait_ref.first, trait_params, self_ty, [](auto , auto ) { return true; }) ) { - if( find_trait_impls_crate(sp, *trait_ref.first, &trait_params, self_ty, [](auto , auto ) { return true; }) ) { + bool magic_found = false; + bool crate_impl_found = false; + // NOTE: THis just detects the presence of a trait impl, not the specifics + find_trait_impls_crate(sp, *trait_ref.first, &trait_params, self_ty, [&](auto impl, auto cmp) { + DEBUG("[find_method] " << impl << ", cmp = " << cmp); + magic_found = true; + crate_impl_found = true; + return true; + }); + if( crate_impl_found ) { DEBUG("Found trait impl " << *trait_ref.first << trait_params << " for " << self_ty << " ("< Date: Sat, 22 Dec 2018 12:40:44 +0800 Subject: MIR Cleanup - Better error reporting for bugs around unevaluated Literal::Defer --- src/hir/hir.cpp | 5 +++++ src/hir_typeck/expr_check.cpp | 1 + src/mir/cleanup.cpp | 26 ++++++++++++++++++++++---- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/hir/hir.cpp b/src/hir/hir.cpp index a0b2b21d..475928a1 100644 --- a/src/hir/hir.cpp +++ b/src/hir/hir.cpp @@ -23,6 +23,9 @@ namespace HIR { (Invalid, os << "!"; ), + (Defer, + os << "?"; + ), (List, os << "["; for(const auto& val : e) @@ -58,6 +61,8 @@ namespace HIR { TU_MATCH(::HIR::Literal, (l,r), (le,re), (Invalid, ), + (Defer, + ), (List, if( le.size() != re.size() ) return false; diff --git a/src/hir_typeck/expr_check.cpp b/src/hir_typeck/expr_check.cpp index 6d2feaba..2d63d045 100644 --- a/src/hir_typeck/expr_check.cpp +++ b/src/hir_typeck/expr_check.cpp @@ -1166,6 +1166,7 @@ namespace { ExprVisitor_Validate ev(m_resolve, tmp, item.m_type); ev.visit_root(item.m_value); } + m_resolve.expand_associated_types(Span(), item.m_type); } void visit_enum(::HIR::ItemPath p, ::HIR::Enum& item) override { //auto _ = this->m_ms.set_item_generics(item.m_params); diff --git a/src/mir/cleanup.cpp b/src/mir/cleanup.cpp index 37d256df..03e8f99e 100644 --- a/src/mir/cleanup.cpp +++ b/src/mir/cleanup.cpp @@ -91,8 +91,11 @@ namespace { } } -const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::Path& path, ::HIR::TypeRef& out_ty) +const ::HIR::Literal* MIR_Cleanup_GetConstant(const MIR::TypeResolve& state, const ::HIR::Path& path, ::HIR::TypeRef& out_ty) { + const Span& sp = state.sp; + const auto& resolve = state.m_resolve; + TRACE_FUNCTION_F(path); TU_MATCHA( (path.m_data), (pe), (Generic, const auto& constant = resolve.m_crate.get_constant_by_path(sp, pe.m_path); @@ -155,6 +158,7 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR // Obtain `out_ty` by monomorphising the type in the trait. auto monomorph_cb = monomorphise_type_get_cb(sp, &*pe.type, &pe.trait.m_params, nullptr); out_ty = monomorphise_type_with(sp, trait_cdef.m_type, monomorph_cb); + resolve.expand_associated_types(sp, out_ty); if( best_impl ) { ASSERT_BUG(sp, best_impl->m_constants.find(pe.item) != best_impl->m_constants.end(), "Item '" << pe.item << "' missing in impl for " << path); @@ -164,7 +168,17 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR else { // No impl found at all, use the default in the trait - return &trait_cdef.m_value_res; + if( trait_cdef.m_value_res.is_Defer() ) + { + // - Monomorphise and insert the item's MIR? + // OR: Should a previous stage have already done this? (E.g. after typecheck) + MIR_TODO(state, "Evaluate deferred trait constant - " << path); + } + else + { + DEBUG("- Default " << trait_cdef.m_value_res); + return &trait_cdef.m_value_res; + } } } ), @@ -315,7 +329,7 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR } else { - MIR_BUG(state, "Unexpected type - " << ty); + MIR_BUG(state, "Unexpected type for literal from " << path << " - " << ty << " (lit = " << lit << ")"); } ), (Primitive, @@ -328,6 +342,7 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR case ::HIR::CoreType::U32: case ::HIR::CoreType::U16: case ::HIR::CoreType::U8: + MIR_ASSERT(state, lit.is_Integer(), "Literal for " << path << ": " << ty << " not an integer, instead " << lit); return ::MIR::Constant::make_Uint({ lit.as_Integer(), te }); case ::HIR::CoreType::Isize: case ::HIR::CoreType::I128: @@ -335,11 +350,14 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR case ::HIR::CoreType::I32: case ::HIR::CoreType::I16: case ::HIR::CoreType::I8: + MIR_ASSERT(state, lit.is_Integer(), "Literal for " << path << ": " << ty << " not an integer, instead " << lit); return ::MIR::Constant::make_Int({ static_cast(lit.as_Integer()), te }); case ::HIR::CoreType::F64: case ::HIR::CoreType::F32: + MIR_ASSERT(state, lit.is_Float(), "Literal for " << path << ": " << ty << " not a float, instead " << lit); return ::MIR::Constant::make_Float({ lit.as_Float(), te }); case ::HIR::CoreType::Bool: + MIR_ASSERT(state, lit.is_Integer(), "Literal for " << path << ": " << ty << " not an integer, instead " << lit); return ::MIR::Constant::make_Bool({ !!lit.as_Integer() }); case ::HIR::CoreType::Str: MIR_BUG(state, "Const of type `str` - " << path); @@ -1070,7 +1088,7 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, TU_IFLET( ::MIR::Constant, e, Const, ce, // 1. Find the constant ::HIR::TypeRef ty; - const auto* lit_ptr = MIR_Cleanup_GetConstant(sp, resolve, ce.p, ty); + const auto* lit_ptr = MIR_Cleanup_GetConstant(state, ce.p, ty); if( lit_ptr ) { DEBUG("Replace constant " << ce.p << " with " << *lit_ptr); -- cgit v1.2.3 From b141095b38ac0ea5a7ed58aa405afd1c318aa442 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 22 Dec 2018 14:19:37 +0800 Subject: Codegen C - Fix incorrect memory orderings --- src/trans/codegen_c.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index a1b3d065..8bbbd033 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -313,9 +313,10 @@ namespace { { m_of << "static inline uint"< Date: Sat, 22 Dec 2018 15:53:25 +0800 Subject: MIR Cleanup - Misc commenting on handling of Defer literals --- src/hir_typeck/static.cpp | 24 +++++++++++++----------- src/main.cpp | 1 + src/mir/cleanup.cpp | 15 +++++++-------- src/trans/trans_list.hpp | 7 +++++++ 4 files changed, 28 insertions(+), 19 deletions(-) diff --git a/src/hir_typeck/static.cpp b/src/hir_typeck/static.cpp index 84c73bfb..64b04611 100644 --- a/src/hir_typeck/static.cpp +++ b/src/hir_typeck/static.cpp @@ -2006,8 +2006,8 @@ StaticTraitResolve::ValuePtr StaticTraitResolve::get_value(const Span& sp, const { TRACE_FUNCTION_F(p << ", signature_only=" << signature_only); out_params = MonomorphState {}; - TU_MATCHA( (p.m_data), (pe), - (Generic, + TU_MATCH_HDR( (p.m_data), {) + TU_ARM(p.m_data, Generic, pe) { if( pe.m_path.m_components.size() > 1 ) { const auto& ti = m_crate.get_typeitem_by_path(sp, pe.m_path, /*ignore_crate_name=*/false, /*ignore_last_node=*/true); @@ -2051,8 +2051,8 @@ StaticTraitResolve::ValuePtr StaticTraitResolve::get_value(const Span& sp, const ) ) throw ""; - ), - (UfcsKnown, + } + TU_ARM(p.m_data, UfcsKnown, pe) { out_params.self_ty = &*pe.type; out_params.pp_impl = &pe.trait.m_params; out_params.pp_method = &pe.params; @@ -2074,8 +2074,10 @@ StaticTraitResolve::ValuePtr StaticTraitResolve::get_value(const Span& sp, const return false; const auto& ti = *impl.m_data.as_TraitImpl().impl; auto it = ti.m_constants.find(pe.item); - if(it == ti.m_constants.end()) + if(it == ti.m_constants.end()) { + // An impl was found, but it did't have the value return false; + } if( impl.more_specific_than(best_impl) ) { @@ -2108,8 +2110,8 @@ StaticTraitResolve::ValuePtr StaticTraitResolve::get_value(const Span& sp, const return &c.data; } throw ""; - ), - (UfcsInherent, + } + TU_ARM(p.m_data, UfcsInherent, pe) { out_params.self_ty = &*pe.type; //out_params.pp_impl = &out_params.pp_impl_data; out_params.pp_impl = &pe.impl_params; @@ -2140,10 +2142,10 @@ StaticTraitResolve::ValuePtr StaticTraitResolve::get_value(const Span& sp, const return false; }); return rv; - ), - (UfcsUnknown, + } + TU_ARM(p.m_data, UfcsUnknown, pe) { BUG(sp, "UfcsUnknown - " << p); - ) - ) + } + } throw ""; } diff --git a/src/main.cpp b/src/main.cpp index 6eb726ac..a34cb76d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -80,6 +80,7 @@ void init_debug_list() g_debug_disable_map.insert( "HIR Serialise" ); g_debug_disable_map.insert( "Trans Enumerate" ); + g_debug_disable_map.insert( "Trans Auto Impls" ); g_debug_disable_map.insert( "Trans Monomorph" ); g_debug_disable_map.insert( "MIR Optimise Inline" ); g_debug_disable_map.insert( "Trans Codegen" ); diff --git a/src/mir/cleanup.cpp b/src/mir/cleanup.cpp index 03e8f99e..1a15ea22 100644 --- a/src/mir/cleanup.cpp +++ b/src/mir/cleanup.cpp @@ -170,9 +170,10 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const MIR::TypeResolve& state, con // No impl found at all, use the default in the trait if( trait_cdef.m_value_res.is_Defer() ) { - // - Monomorphise and insert the item's MIR? - // OR: Should a previous stage have already done this? (E.g. after typecheck) - MIR_TODO(state, "Evaluate deferred trait constant - " << path); + DEBUG(state << "Found deferred trait constant - " << path); + // Return null to force the replacement to not happen (yet) + // - Expansion and resolution of this constant happens after/in "Trans Monomorph" + return nullptr; } else { @@ -184,7 +185,7 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const MIR::TypeResolve& state, con ), (UfcsInherent, const ::HIR::TypeImpl* best_impl = nullptr; - // TODO: Associated constants (inherent) + // Associated constants (inherent) resolve.m_crate.find_type_impls(*pe.type, [&](const auto& ty)->const auto& { return ty; }, [&](const auto& impl) { auto it = impl.m_constants.find(pe.item); @@ -366,7 +367,6 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const MIR::TypeResolve& state, con ), (Pointer, if( lit.is_BorrowPath() || lit.is_BorrowData() ) { - // TODO: MIR_TODO(state, "BorrowOf into pointer - " << lit << " into " << ty); } else { @@ -715,7 +715,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator& bool source_is_dst = false; if( MIR_Cleanup_Unsize_GetMetadata(state, mutator, dst_ty_inner, src_ty_inner, ptr_value, meta_value, meta_type, source_is_dst) ) { - // TODO: There is a case where the source is already a fat pointer. In that case the pointer of the new DST must be the source DST pointer + // There is a case where the source is already a fat pointer. In that case the pointer of the new DST must be the source DST pointer if( source_is_dst ) { auto ty_unit_ptr = ::HIR::TypeRef::new_pointer(::HIR::BorrowType::Shared, ::HIR::TypeRef::new_unit()); @@ -845,7 +845,6 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator& if( dte.type == ste.type ) { - // TODO: Use unsize code above return MIR_Cleanup_Unsize(state, mutator, dst_ty, *ste.inner, mv$(value)); } else @@ -1084,7 +1083,7 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, auto& se = stmt.as_Assign(); TU_IFLET( ::MIR::RValue, se.src, Constant, e, - // TODO: Replace `Const` with actual values + // Replace `Const` with actual values TU_IFLET( ::MIR::Constant, e, Const, ce, // 1. Find the constant ::HIR::TypeRef ty; diff --git a/src/trans/trans_list.hpp b/src/trans/trans_list.hpp index 51e8af4b..703180fd 100644 --- a/src/trans/trans_list.hpp +++ b/src/trans/trans_list.hpp @@ -62,6 +62,11 @@ struct TransList_Static const ::HIR::Static* ptr; Trans_Params pp; }; +struct TransList_Const +{ + const ::HIR::Constant* ptr; + Trans_Params pp; +}; class TransList { @@ -74,6 +79,8 @@ public: ::std::map< ::HIR::Path, ::std::unique_ptr > m_functions; ::std::map< ::HIR::Path, ::std::unique_ptr > m_statics; + /// Constants that are still Defer + ::std::map< ::HIR::Path, ::std::unique_ptr > m_constants; ::std::map< ::HIR::Path, Trans_Params> m_vtables; /// Required type_id values ::std::set< ::HIR::TypeRef> m_typeids; -- cgit v1.2.3 From 883cf34da3e273cd3878026d855b9579055c09c0 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 22 Dec 2018 18:31:15 +0800 Subject: Constant Evaluation - Evaluate missing associated constants with trait impl versions --- src/hir/expr_ptr.cpp | 7 +++ src/hir/expr_ptr.hpp | 1 + src/hir_conv/bind.cpp | 3 + src/hir_conv/constant_evaluation.cpp | 115 ++++++++++++++++++++++++++++------- src/trans/enumerate.cpp | 3 + src/trans/trans_list.hpp | 1 + 6 files changed, 107 insertions(+), 23 deletions(-) diff --git a/src/hir/expr_ptr.cpp b/src/hir/expr_ptr.cpp index fcef34bd..7b3a6811 100644 --- a/src/hir/expr_ptr.cpp +++ b/src/hir/expr_ptr.cpp @@ -45,6 +45,13 @@ } +const Span& HIR::ExprPtr::span() const +{ + static Span static_sp; + if( *this ) + return (*this)->span(); + return static_sp; +} const ::MIR::Function* HIR::ExprPtr::get_mir_opt() const { if(!this->m_mir) diff --git a/src/hir/expr_ptr.hpp b/src/hir/expr_ptr.hpp index b510e737..58fa3762 100644 --- a/src/hir/expr_ptr.hpp +++ b/src/hir/expr_ptr.hpp @@ -105,6 +105,7 @@ public: ::HIR::ExprNode* get() const { return node.get(); } void reset(::HIR::ExprNode* p) { node.reset(p); } + const Span& span() const; ::HIR::ExprNode& operator*() { return *node; } const ::HIR::ExprNode& operator*() const { return *node; } ::HIR::ExprNode* operator->() { return &*node; } diff --git a/src/hir_conv/bind.cpp b/src/hir_conv/bind.cpp index 227ccd9f..37a6e494 100644 --- a/src/hir_conv/bind.cpp +++ b/src/hir_conv/bind.cpp @@ -140,6 +140,9 @@ namespace { TU_MATCH(::HIR::Literal, (lit), (e), (Invalid, ), + (Defer, + // Shouldn't happen here, but ... + ), (List, for(auto& val : e) { visit_literal(sp, val); diff --git a/src/hir_conv/constant_evaluation.cpp b/src/hir_conv/constant_evaluation.cpp index acb613be..78148ba4 100644 --- a/src/hir_conv/constant_evaluation.cpp +++ b/src/hir_conv/constant_evaluation.cpp @@ -16,6 +16,8 @@ #include #include +#include // For handling monomorph of MIR in provided associated constants + #define CHECK_DEFER(var) do { if( var.is_Defer() ) { m_rv = ::HIR::Literal::make_Defer({}); return ; } } while(0) namespace { @@ -382,29 +384,24 @@ namespace { LocalState local_state( state, retval, args, locals ); auto const_to_lit = [&](const ::MIR::Constant& c)->::HIR::Literal { - TU_MATCH(::MIR::Constant, (c), (e2), - (Int, + TU_MATCH_HDR( (c), {) + TU_ARM(c, Int, e2) { return ::HIR::Literal(static_cast(e2.v)); - ), - (Uint, + } + TU_ARM(c, Uint, e2) return ::HIR::Literal(e2.v); - ), - (Float, + TU_ARM(c, Float, e2) return ::HIR::Literal(e2.v); - ), - (Bool, + TU_ARM(c, Bool, e2) return ::HIR::Literal(static_cast(e2.v)); - ), - (Bytes, + TU_ARM(c, Bytes, e2) return ::HIR::Literal::make_String({e2.begin(), e2.end()}); - ), - (StaticString, + TU_ARM(c, StaticString, e2) return ::HIR::Literal(e2); - ), - (Const, + TU_ARM(c, Const, e2) { auto p = ms.monomorph(state.sp, e2.p); // If there's any mention of generics in this path, then return Literal::Defer - if( visit_path_tys_with(e2.p, [&](const auto& ty)->bool { return ty.m_data.is_Generic(); }) ) + if( visit_path_tys_with(p, [&](const auto& ty)->bool { return ty.m_data.is_Generic(); }) ) { DEBUG("Return Literal::Defer for constant " << e2.p << " which references a generic parameter"); return ::HIR::Literal::make_Defer({}); @@ -418,7 +415,7 @@ namespace { auto& item = const_cast<::HIR::Constant&>(c); // Challenge: Adding items to the module might invalidate an iterator. ::HIR::ItemPath mod_ip { item.m_value.m_state->m_mod_path }; - auto eval = Evaluator { item.m_value->span(), resolve.m_crate, NewvalState { item.m_value.m_state->m_module, mod_ip, FMT(&c << "$") } }; + auto eval = Evaluator { item.m_value.span(), resolve.m_crate, NewvalState { item.m_value.m_state->m_module, mod_ip, FMT(&c << "$") } }; DEBUG("- Evaluate " << p); DEBUG("- " << ::HIR::ItemPath(p)); item.m_value_res = eval.evaluate_constant(::HIR::ItemPath(p), item.m_value, item.m_type.clone()); @@ -426,11 +423,10 @@ namespace { //check_lit_type(item.m_value->span(), item.m_type, item.m_value_res); } return clone_literal( c.m_value_res ); - ), - (ItemAddr, + } + TU_ARM(c, ItemAddr, e2) return ::HIR::Literal::make_BorrowPath( ms.monomorph(state.sp, e2) ); - ) - ) + } throw ""; }; auto read_param = [&](const ::MIR::Param& p) -> ::HIR::Literal @@ -961,6 +957,79 @@ namespace { m_mod_path = saved_mp; } + void visit_trait_impl(const ::HIR::SimplePath& trait_path, ::HIR::TraitImpl& impl) override + { + static Span sp; + TRACE_FUNCTION_F("impl" << impl.m_params.fmt_args() << " " << trait_path << impl.m_trait_args << " for " << impl.m_type); + const auto& trait = m_crate.get_trait_by_path(sp, trait_path); + + StaticTraitResolve resolve( m_crate ); + // - TODO: Defer this call until first missing item? + resolve.set_impl_generics(impl.m_params); + + auto mp = ::HIR::ItemPath(impl.m_src_module); + m_mod_path = ∓ + m_mod = &m_crate.get_mod_by_path(sp, impl.m_src_module); + + for(const auto& vi : trait.m_values) + { + // Search for any constants that are in the trait itself, but NOT in this impl + // - For each of these, find the lowest parent specialisation with the constant set + // - Ensure that the MIR has been generated for the constant (TODO: This only needs to be done for + // specialisations, not trait-provided) + // - Monomorphise the MIR for this impl, and let expansion happen as usual + if( vi.second.is_Constant() ) + { + if( impl.m_constants.count(vi.first) > 0 ) + continue; + DEBUG("- Constant " << vi.first << " missing, looking for a source"); + // This trait impl doesn't have this constant, need to find the provided version that applies + + MonomorphState ms; + ms.self_ty = &impl.m_type; + ms.pp_impl = &impl.m_trait_args; + + resolve.find_impl(sp, trait_path, impl.m_trait_args, impl.m_type, [&](ImplRef found_impl, bool is_fuzzed)->bool { + ASSERT_BUG(sp, found_impl.m_data.is_TraitImpl(), ""); + // If this found impl is the current one, keep searching + if( found_impl.m_data.as_TraitImpl().impl == &impl ) + return false; + TODO(sp, "Found a possible parent specialisation of " << trait_path << impl.m_trait_args << " for " << impl.m_type << " - " << found_impl); + return false; + }); + const auto& template_const = vi.second.as_Constant(); + if( template_const.m_value_res.is_Defer() ) { + auto eval = Evaluator { sp, m_crate, NewvalState { *m_mod, *m_mod_path, FMT("impl" << &impl << "$" << vi.first << "$") } }; + ::HIR::ExprPtr ep; + Trans_Params tp(sp); + tp.self_type = ms.self_ty->clone(); + tp.pp_impl = ms.pp_impl->clone(); + ep.m_mir = Trans_Monomorphise(resolve, mv$(tp), template_const.m_value.m_mir); + ep.m_state = ::HIR::ExprStatePtr( ::HIR::ExprState(*m_mod, m_mod_path->get_simple_path()) ); + ep.m_state->stage = ::HIR::ExprState::Stage::Mir; + impl.m_constants.insert(::std::make_pair( + vi.first, + ::HIR::TraitImpl::ImplEnt<::HIR::Constant> { + /*is_specialisable=*/false, + ::HIR::Constant { + template_const.m_params.clone(), + /*m_type=*/ms.monomorph(sp, template_const.m_type), + /*m_value=*/mv$(ep), + ::HIR::Literal() + } + } + )); + } + else { + TODO(sp, "Assign associated type " << vi.first << " in impl" << impl.m_params.fmt_args() << " " << trait_path << impl.m_trait_args << " for " << impl.m_type); + } + } + } + ::HIR::Visitor::visit_trait_impl(trait_path, impl); + m_mod = nullptr; + m_mod_path = nullptr; + } + void visit_type(::HIR::TypeRef& ty) override { ::HIR::Visitor::visit_type(ty); @@ -988,12 +1057,12 @@ namespace { ::HIR::Visitor::visit_constant(p, item); // NOTE: Consteval needed here for MIR match generation to work - if( item.m_value ) + if( item.m_value || item.m_value.m_mir ) { - auto eval = Evaluator { item.m_value->span(), m_crate, NewvalState { *m_mod, *m_mod_path, FMT(p.get_name() << "$") } }; + auto eval = Evaluator { item.m_value.span(), m_crate, NewvalState { *m_mod, *m_mod_path, FMT(p.get_name() << "$") } }; item.m_value_res = eval.evaluate_constant(p, item.m_value, item.m_type.clone()); - check_lit_type(item.m_value->span(), item.m_type, item.m_value_res); + check_lit_type(item.m_value.span(), item.m_type, item.m_value_res); DEBUG("constant: " << item.m_type << " = " << item.m_value_res); } diff --git a/src/trans/enumerate.cpp b/src/trans/enumerate.cpp index e16f9dcf..ce3eb53a 100644 --- a/src/trans/enumerate.cpp +++ b/src/trans/enumerate.cpp @@ -1599,6 +1599,9 @@ void Trans_Enumerate_FillFrom_Literal(EnumState& state, const ::HIR::Literal& li TU_MATCHA( (lit), (e), (Invalid, ), + (Defer, + // TODO: Bug? + ), (List, for(const auto& v : e) Trans_Enumerate_FillFrom_Literal(state, v, pp); diff --git a/src/trans/trans_list.hpp b/src/trans/trans_list.hpp index 703180fd..b58a241d 100644 --- a/src/trans/trans_list.hpp +++ b/src/trans/trans_list.hpp @@ -18,6 +18,7 @@ class Function; class Static; } +// TODO: This is very similar to "hir_typeck/common.hpp" MonomorphState struct Trans_Params { Span sp; -- cgit v1.2.3 From 52cd5e2947f634df8bfa7da89ee33eee82134ff7 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 22 Dec 2018 20:38:08 +0800 Subject: tagged_union - Fix TU_ARM not using parens around the value --- src/include/tagged_union.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/tagged_union.hpp b/src/include/tagged_union.hpp index 93dc6980..12e39fc8 100644 --- a/src/include/tagged_union.hpp +++ b/src/include/tagged_union.hpp @@ -120,7 +120,7 @@ #define TU_MATCH_HDR_(CLASS, VARS, brace) switch( (TU_FIRST VARS).tag() ) brace case CLASS::TAGDEAD: assert(!"ERROR: destructed tagged union used"); // Evil hack: two for loops, the inner stops the outer after it's done. -#define TU_ARM(VAR, TAG, NAME) break; case ::std::remove_reference::type::TAG_##TAG: for(bool tu_lc = true; tu_lc; tu_lc=false) for(auto& NAME = VAR.as_##TAG(); (void)NAME, tu_lc; tu_lc=false) +#define TU_ARM(VAR, TAG, NAME) break; case ::std::remove_reference::type::TAG_##TAG: for(bool tu_lc = true; tu_lc; tu_lc=false) for(auto& NAME = (VAR).as_##TAG(); (void)NAME, tu_lc; tu_lc=false) //#define TU_TEST(VAL, ...) (VAL.is_##TAG() && VAL.as_##TAG() TEST) #define TU_TEST1(VAL, TAG1, TEST) (VAL.is_##TAG1() && VAL.as_##TAG1() TEST) -- cgit v1.2.3 From 48c0451b76c6f91ee467d8cac0e0c7fd475c8b46 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 22 Dec 2018 20:38:38 +0800 Subject: Resolve Use - Support glob from external module --- src/resolve/use.cpp | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/src/resolve/use.cpp b/src/resolve/use.cpp index 23f7e70c..db942641 100644 --- a/src/resolve/use.cpp +++ b/src/resolve/use.cpp @@ -428,28 +428,36 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path //out_path = imp_data.path; } - TU_MATCH_DEF(::AST::PathBinding, (*binding), (e), - ( - BUG(sp2, "Wildcard import expanded to an invalid item class - " << binding->tag_str()); - ), - (Crate, + TU_MATCH_HDR( (*binding), {) + TU_ARM(*binding, Crate, e) { assert(e.crate_); const ::HIR::Module& hmod = e.crate_->m_hir->m_root_module; auto rv = Resolve_Use_GetBinding__ext(sp2, crate, AST::Path("", { AST::PathNode(des_item_name,{}) }), hmod, 0, allow); if( ! rv.is_Unbound() ) { return mv$(rv); } - ), - (Module, + } + TU_ARM(*binding, Module, e) { auto allow_inner = (allow == Lookup::Any ? Lookup::AnyOpt : allow); - assert(e.module_); - // TODO: Prevent infinite recursion? - auto rv = Resolve_Use_GetBinding_Mod(span, crate, *e.module_, des_item_name, {}, allow_inner); - if( ! rv.is_Unbound() ) { - return mv$(rv); + if( e.module_ ) { + // TODO: Prevent infinite recursion? + auto rv = Resolve_Use_GetBinding_Mod(span, crate, *e.module_, des_item_name, {}, allow_inner); + if( ! rv.is_Unbound() ) { + return mv$(rv); + } } - ), - (Enum, + else if( e.hir ) { + const ::HIR::Module& hmod = *e.hir; + auto rv = Resolve_Use_GetBinding__ext(sp2, crate, AST::Path("", { AST::PathNode(des_item_name,{}) }), hmod, 0, allow); + if( ! rv.is_Unbound() ) { + return mv$(rv); + } + } + else { + BUG(span, "NULL module for binding on glob of " << imp_data.path); + } + } + TU_ARM(*binding, Enum, e) { assert(e.enum_ || e.hir); if( e.enum_ ) { const auto& enm = *e.enum_; @@ -470,8 +478,11 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path return ::AST::PathBinding::make_EnumVar({ nullptr, static_cast(idx), &enm }); } } - ) - ) + } break; + default: + BUG(sp2, "Wildcard import expanded to an invalid item class - " << binding->tag_str()); + break; + } } } -- cgit v1.2.3 From e842fbbc375907b13b69d0f53de6dc3149804c13 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 22 Dec 2018 21:07:47 +0800 Subject: Lang items for 1.29 (allocator traits removed, need to do magic) --- src/expand/lang_item.cpp | 5 ++++- src/hir/from_ast.cpp | 39 +++++++++++++++++++++------------------ 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/expand/lang_item.cpp b/src/expand/lang_item.cpp index f59d81c3..55bde52f 100644 --- a/src/expand/lang_item.cpp +++ b/src/expand/lang_item.cpp @@ -215,7 +215,10 @@ public: // collections else if( name == "str" ) {} else if( name == "slice" ) {} - else if( TARGETVER_1_29 && name == "slice_u8" ) {} + else if( TARGETVER_1_29 && name == "slice_u8" ) {} // libcore now, `impl [u8]` + else if( TARGETVER_1_29 && name == "slice_alloc" ) {} // liballoc's impls on [T] + else if( TARGETVER_1_29 && name == "slice_u8_alloc" ) {} // liballoc's impls on [u8] + else if( TARGETVER_1_29 && name == "str_alloc" ) {} // liballoc's impls on str // std - interestingly else if( name == "f32" ) {} else if( name == "f64" ) {} diff --git a/src/hir/from_ast.cpp b/src/hir/from_ast.cpp index 40c872fa..1079e981 100644 --- a/src/hir/from_ast.cpp +++ b/src/hir/from_ast.cpp @@ -1932,25 +1932,28 @@ public: } }; // Check for existing defintions of lang items before adding magic ones - if( rv.m_lang_items.count("boxed_trait") == 0 ) + if( TARGETVER_1_19 ) { - rv.m_lang_items.insert(::std::make_pair( ::std::string("boxed_trait"), H::resolve_path(rv, false, {"ops", "Boxed"}) )); - } - if( rv.m_lang_items.count("placer_trait") == 0 ) - { - rv.m_lang_items.insert(::std::make_pair( ::std::string("placer_trait"), H::resolve_path(rv, false, {"ops", "Placer"}) )); - } - if( rv.m_lang_items.count("place_trait") == 0 ) - { - rv.m_lang_items.insert(::std::make_pair( ::std::string("place_trait"), H::resolve_path(rv, false, {"ops", "Place"}) )); - } - if( rv.m_lang_items.count("box_place_trait") == 0 ) - { - rv.m_lang_items.insert(::std::make_pair( ::std::string("box_place_trait"), H::resolve_path(rv, false, {"ops", "BoxPlace"}) )); - } - if( rv.m_lang_items.count("in_place_trait") == 0 ) - { - rv.m_lang_items.insert(::std::make_pair( ::std::string("in_place_trait"), H::resolve_path(rv, false, {"ops", "InPlace"}) )); + if( rv.m_lang_items.count("boxed_trait") == 0 ) + { + rv.m_lang_items.insert(::std::make_pair( ::std::string("boxed_trait"), H::resolve_path(rv, false, {"ops", "Boxed"}) )); + } + if( rv.m_lang_items.count("placer_trait") == 0 ) + { + rv.m_lang_items.insert(::std::make_pair( ::std::string("placer_trait"), H::resolve_path(rv, false, {"ops", "Placer"}) )); + } + if( rv.m_lang_items.count("place_trait") == 0 ) + { + rv.m_lang_items.insert(::std::make_pair( ::std::string("place_trait"), H::resolve_path(rv, false, {"ops", "Place"}) )); + } + if( rv.m_lang_items.count("box_place_trait") == 0 ) + { + rv.m_lang_items.insert(::std::make_pair( ::std::string("box_place_trait"), H::resolve_path(rv, false, {"ops", "BoxPlace"}) )); + } + if( rv.m_lang_items.count("in_place_trait") == 0 ) + { + rv.m_lang_items.insert(::std::make_pair( ::std::string("in_place_trait"), H::resolve_path(rv, false, {"ops", "InPlace"}) )); + } } } -- cgit v1.2.3 From 2744a49ad3f3a8ff138ee0fd9b90244f3b5d7853 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Wed, 26 Dec 2018 23:36:18 +0800 Subject: Typecheck Expressions - Handle changes to the `box` operator for 1.29 (still needs work later down the line) `box` no longer has operator traits, and is (I believe) back to being 100% compiler magic. --- src/hir_typeck/expr_cs.cpp | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index a7c5ddee..7f58be4e 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -2354,7 +2354,29 @@ namespace { ) this->m_completed = true; } - void visit(::HIR::ExprNode_Emplace& node) override { + void visit_emplace_129(::HIR::ExprNode_Emplace& node) { + const auto& sp = node.span(); + const auto& exp_ty = this->context.get_type(node.m_res_type); + const auto& data_ty = this->context.get_type(node.m_value->m_res_type); + const auto& placer_ty = this->context.get_type(node.m_place->m_res_type); + const auto& lang_Boxed = this->context.m_lang_Box; + TRACE_FUNCTION_F("exp_ty=" << exp_ty << ", data_ty=" << data_ty << ", placer_ty" << placer_ty); + ASSERT_BUG(sp, node.m_type == ::HIR::ExprNode_Emplace::Type::Boxer, "1.29 mode with non-box _Emplace node"); + ASSERT_BUG(sp, placer_ty == ::HIR::TypeRef::new_unit(), "1.29 mode with box in syntax - placer type is " << placer_ty); + + ASSERT_BUG(sp, !lang_Boxed.m_components.empty(), "`owbed_box` not present when `box` operator used"); + + // NOTE: `owned_box` shouldn't point to anything but a struct + const auto& str = this->context.m_crate.get_struct_by_path(sp, lang_Boxed); + // TODO: Store this type to avoid having to construct it every pass + auto boxed_ty = ::HIR::TypeRef::new_path( ::HIR::GenericPath(lang_Boxed, {data_ty.clone()}), &str ); + + // TODO: is there anyting special about this node that might need revisits? + + context.equate_types(sp, exp_ty, boxed_ty); + this->m_completed = true; + } + void visit_emplace_119(::HIR::ExprNode_Emplace& node) { const auto& sp = node.span(); const auto& exp_ty = this->context.get_type(node.m_res_type); const auto& data_ty = this->context.get_type(node.m_value->m_res_type); @@ -2449,6 +2471,16 @@ namespace { this->m_completed = true; } + void visit(::HIR::ExprNode_Emplace& node) override { + switch(gTargetVersion) + { + case TargetVersion::Rustc1_19: + return visit_emplace_119(node); + case TargetVersion::Rustc1_29: + return visit_emplace_129(node); + } + throw "BUG: Unhandled target version"; + } void visit(::HIR::ExprNode_TupleVariant& node) override { no_revisit(node); -- cgit v1.2.3 From 4630e1bc870361b666e6f38a2049a2552ca9d8b7 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Thu, 27 Dec 2018 15:54:20 +0800 Subject: Typecheck Expressions - Minimal support for match ergonomics (typecheck only) --- src/hir/pattern.hpp | 1 + src/hir_typeck/expr_cs.cpp | 600 ++++++++++++++++++++++++++++++++++++++++----- src/hir_typeck/helpers.cpp | 4 + 3 files changed, 548 insertions(+), 57 deletions(-) diff --git a/src/hir/pattern.hpp b/src/hir/pattern.hpp index df14de79..d190db5a 100644 --- a/src/hir/pattern.hpp +++ b/src/hir/pattern.hpp @@ -136,6 +136,7 @@ struct Pattern PatternBinding m_binding; Data m_data; + unsigned m_implicit_deref_count; Pattern() {} Pattern(PatternBinding pb, Data d): diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 7f58be4e..8df54be5 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -16,6 +16,17 @@ namespace { inline HIR::ExprNodeP mk_exprnodep(HIR::ExprNode* en, ::HIR::TypeRef ty){ en->m_res_type = mv$(ty); return HIR::ExprNodeP(en); } + + inline ::HIR::SimplePath get_parent_path(const ::HIR::SimplePath& sp) { + auto rv = sp; + rv.m_components.pop_back(); + return rv; + } + inline ::HIR::GenericPath get_parent_path(const ::HIR::GenericPath& gp) { + auto rv = gp.clone(); + rv.m_path.m_components.pop_back(); + return rv; + } } #define NEWNODE(TY, SP, CLASS, ...) mk_exprnodep(new HIR::ExprNode##CLASS(SP ,## __VA_ARGS__), TY) @@ -216,7 +227,8 @@ struct Context void possible_equate_type_disable(unsigned int ivar_index, bool is_to); // - Add a pattern binding (forcing the type to match) - void add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::TypeRef& type); + void handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::TypeRef& type); + void handle_pattern_direct_inner(const Span& sp, ::HIR::Pattern& pat, const ::HIR::TypeRef& type); void add_binding_inner(const Span& sp, const ::HIR::PatternBinding& pb, ::HIR::TypeRef type); void add_var(const Span& sp, unsigned int index, const ::std::string& name, ::HIR::TypeRef type); @@ -751,7 +763,7 @@ namespace { TRACE_FUNCTION_F(&node << " let " << node.m_pattern << ": " << node.m_type); this->context.add_ivars( node.m_type ); - this->context.add_binding(node.span(), node.m_pattern, node.m_type); + this->context.handle_pattern(node.span(), node.m_pattern, node.m_type); if( node.m_value ) { @@ -791,7 +803,7 @@ namespace { TRACE_FUNCTION_F("ARM " << arm.m_patterns); for(auto& pat : arm.m_patterns) { - this->context.add_binding(node.span(), pat, val_type); + this->context.handle_pattern(node.span(), pat, val_type); } if( arm.m_cond ) @@ -1088,8 +1100,7 @@ namespace { } else { - auto s_path = gp.m_path; - s_path.m_components.pop_back(); + auto s_path = get_parent_path(gp.m_path); const auto& enm = this->context.m_crate.get_enum_by_path(sp, s_path); fix_param_count(sp, this->context, ::HIR::TypeRef(), false, gp, enm.m_params, gp.m_params); @@ -1648,8 +1659,7 @@ namespace { } break; case ::HIR::ExprNode_PathValue::ENUM_VAR_CONSTR: { const auto& var_name = e.m_path.m_components.back(); - auto enum_path = e.m_path; - enum_path.m_components.pop_back(); + auto enum_path = get_parent_path(e.m_path); const auto& enm = this->context.m_crate.get_enum_by_path(sp, enum_path); fix_param_count(sp, this->context, ::HIR::TypeRef(), false, e, enm.m_params, e.m_params); size_t idx = enm.find_variant(var_name); @@ -1875,7 +1885,7 @@ namespace { TRACE_FUNCTION_F(&node << " |...| ..."); for(auto& arg : node.m_args) { this->context.add_ivars( arg.second ); - this->context.add_binding( node.span(), arg.first, arg.second ); + this->context.handle_pattern( node.span(), arg.first, arg.second ); } this->context.add_ivars( node.m_return ); this->context.add_ivars( node.m_code->m_res_type ); @@ -3635,7 +3645,492 @@ void Context::add_binding_inner(const Span& sp, const ::HIR::PatternBinding& pb, } // NOTE: Mutates the pattern to add ivars to contained paths -void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::TypeRef& type) +void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::TypeRef& type) +{ + TRACE_FUNCTION_F("pat = " << pat << ", type = " << type); + + // TODO: 1.29 includes "match ergonomics" which allows automatic insertion of borrow/deref when matching + // - Handling this will make pattern matching slightly harder (all patterns needing revisist) + // - BUT: New bindings will still be added as usualin this pass. + // - Any use of `&` (or `ref`?) in the pattern disables match ergonomics for the entire pattern. + // - Does `box` also do this disable? + // + // + // - Add a counter to each pattern indicting how many implicit borrows/derefs are applied. + // - When this function is called, check if the pattern is eligable for pattern auto-ref/deref + // - Detect if the pattern uses & or ref. If it does, then invoke the existing code + // - Otherwise, register a revisit for the pattern + + + struct H2 { + static bool has_ref_or_borrow(const Span& sp, const ::HIR::Pattern& pat) { + if( pat.m_binding.is_valid() && pat.m_binding.m_type != ::HIR::PatternBinding::Type::Move ) { + return true; + } + if( pat.m_data.is_Ref() ) { + return true; + } + bool rv = false; + TU_MATCHA( (pat.m_data), (e), + (Any, + ), + (Value, + ), + (Range, + ), + (Box, + rv |= H2::has_ref_or_borrow(sp, *e.sub); + ), + (Ref, + rv |= H2::has_ref_or_borrow(sp, *e.sub); + ), + (Tuple, + for(const auto& subpat : e.sub_patterns) + rv |= H2::has_ref_or_borrow(sp, subpat); + ), + (SplitTuple, + for(auto& subpat : e.leading) { + rv |= H2::has_ref_or_borrow(sp, subpat); + } + for(auto& subpat : e.trailing) { + rv |= H2::has_ref_or_borrow(sp, subpat); + } + ), + (Slice, + for(auto& sub : e.sub_patterns) + rv |= H2::has_ref_or_borrow(sp, sub); + ), + (SplitSlice, + for(auto& sub : e.leading) + rv |= H2::has_ref_or_borrow(sp, sub); + for(auto& sub : e.trailing) + rv |= H2::has_ref_or_borrow(sp, sub); + ), + + // - Enums/Structs + (StructValue, + ), + (StructTuple, + for(const auto& subpat : e.sub_patterns) + rv |= H2::has_ref_or_borrow(sp, subpat); + ), + (Struct, + for( auto& field_pat : e.sub_patterns ) + rv |= H2::has_ref_or_borrow(sp, field_pat.second); + ), + (EnumValue, + ), + (EnumTuple, + for(const auto& subpat : e.sub_patterns) + rv |= H2::has_ref_or_borrow(sp, subpat); + ), + (EnumStruct, + for( auto& field_pat : e.sub_patterns ) + rv |= H2::has_ref_or_borrow(sp, field_pat.second); + ) + ) + return rv; + } + }; + + // 1. Determine if this pattern can apply auto-ref/deref + if( pat.m_data.is_Any() ) { + // `_` pattern, no destructure/match, so no auto-ref/deref + // - TODO: Does this do auto-borrow too? + if( pat.m_binding.is_valid() ) { + this->add_binding_inner(sp, pat.m_binding, type.clone()); + } + return ; + } + + // NOTE: Even if the top-level is a binding, and even if the top-level type is fully known, match ergonomics + // still applies. + if( TARGETVER_1_29 && ! H2::has_ref_or_borrow(sp, pat) ) { + // There's not a `&` or `ref` in the pattern, and we're targeting 1.29 + // - Run the match ergonomics handler + // TODO: Default binding mode can be overridden back to "move" with `mut` + + struct MatchErgonomicsRevisit: + public Revisitor + { + Span sp; + ::HIR::TypeRef m_outer_ty; + ::HIR::Pattern& m_pattern; + ::HIR::PatternBinding::Type m_outer_mode; + + MatchErgonomicsRevisit(Span sp, ::HIR::TypeRef outer, ::HIR::Pattern& pat, ::HIR::PatternBinding::Type binding_mode=::HIR::PatternBinding::Type::Move): + sp(mv$(sp)), m_outer_ty(mv$(outer)), + m_pattern(pat), + m_outer_mode(binding_mode) + {} + + void fmt(::std::ostream& os) const override { + os << "MatchErgonomicsRevisit { " << m_pattern << " : " << m_outer_ty << " }"; + } + bool revisit(Context& context) override { + TRACE_FUNCTION_F("Match ergonomics - " << m_pattern << " : " << m_outer_ty); + return this->revisit_inner(context, m_pattern, m_outer_ty, m_outer_mode); + } + // TODO: Recurse into inner patterns, creating new revisitors? + // - OR, could just recurse on it. + // + // Recusring incurs costs on every iteration, but is less expensive the first time around + // New revisitors are cheaper when inferrence takes multiple iterations, but takes longer first time. + bool revisit_inner(Context& context, ::HIR::Pattern& pattern, const ::HIR::TypeRef& type, ::HIR::PatternBinding::Type binding_mode) const { + if( !revisit_inner_real(context, pattern, type, binding_mode) ) + { + DEBUG("Add revisit for " << pattern << " : " << type << "(mode = " << (int)binding_mode << ")"); + context.add_revisit_adv( box$(( MatchErgonomicsRevisit { sp, type.clone(), pattern, binding_mode } )) ); + } + return true; + } + bool revisit_inner_real(Context& context, ::HIR::Pattern& pattern, const ::HIR::TypeRef& type, ::HIR::PatternBinding::Type binding_mode) const { + TRACE_FUNCTION_F(pattern << " : " << type); + + // Binding applies to the raw input type (not after dereferencing) + if( pattern.m_binding.is_valid() ) + { + // - Binding present, use the current binding mode + switch(binding_mode) + { + case ::HIR::PatternBinding::Type::Move: + context.equate_types(sp, context.get_var(sp, pattern.m_binding.m_slot), type); + break; + default: + TODO(sp, "Assign variable type using mode " << (int)binding_mode << " and " << type); + } + } + + // If the type is a borrow, then count derefs required for the borrow + // - If the first non-borrow inner is an ivar, return false + unsigned n_deref = 0; + ::HIR::BorrowType bt = ::HIR::BorrowType::Owned; + const auto* ty_p = &context.get_type(type); + while( ty_p->m_data.is_Borrow() ) { + bt = ::std::max(bt, ty_p->m_data.as_Borrow().type); + ty_p = &context.get_type( *ty_p->m_data.as_Borrow().inner ); + n_deref ++; + } + DEBUG("- " << n_deref << " derefs of class " << bt << " to get " << *ty_p); + if( ty_p->m_data.is_Infer() ) { + // Still pure infer, can't do anything + // - What if it's an literal? + + // TODO: Visit all inner bindings and disable coercion fallbacks on them. + MatchErgonomicsRevisit::disable_possibilities_on_bindings(sp, context, pattern); + return false; + } + const auto& ty = *ty_p; + + // Here we have a known type and binding mode for this pattern + // - Time to handle this pattern then recurse into sub-patterns + + // Store the deref count in the pattern. + pattern.m_implicit_deref_count = n_deref; + // Determine the new binding mode from the borrow type + switch(bt) + { + case ::HIR::BorrowType::Owned: + // No change + break; + case ::HIR::BorrowType::Unique: + switch(binding_mode) + { + case ::HIR::PatternBinding::Type::Move: + case ::HIR::PatternBinding::Type::MutRef: + binding_mode = ::HIR::PatternBinding::Type::MutRef; + break; + case ::HIR::PatternBinding::Type::Ref: + // No change + break; + } + break; + case ::HIR::BorrowType::Shared: + binding_mode = ::HIR::PatternBinding::Type::Ref; + break; + } + + bool rv = false; + TU_MATCH_HDR( (pattern.m_data), { ) + TU_ARM(pattern.m_data, Any, pe) { + // no-op + rv = true; + } + TU_ARM(pattern.m_data, Value, pe) { + // no-op? + rv = true; + } + TU_ARM(pattern.m_data, Range, pe) { + // no-op? + rv = true; + } + TU_ARM(pattern.m_data, Box, pe) { + // TODO: inner pattern + TODO(sp, "Match ergonomics - box pattern"); + } + TU_ARM(pattern.m_data, Ref, pe) { + BUG(sp, "Match ergonomics - & pattern"); + } + TU_ARM(pattern.m_data, Tuple, e) { + if( !ty.m_data.is_Tuple() ) { + ERROR(sp, E0000, "Matching a non-tuple with a tuple pattern - " << ty); + } + const auto& te = ty.m_data.as_Tuple(); + if( e.sub_patterns.size() != te.size() ) { + ERROR(sp, E0000, "Tuple pattern with an incorrect number of fields, expected " << e.sub_patterns.size() << "-tuple, got " << ty); + } + + rv = true; + for(unsigned int i = 0; i < e.sub_patterns.size(); i ++ ) + rv &= this->revisit_inner(context, e.sub_patterns[i], te[i], binding_mode); + } + TU_ARM(pattern.m_data, SplitTuple, pe) { + TODO(sp, "Match ergonomics - split-tuple pattern"); + } + TU_ARM(pattern.m_data, Slice, e) { + const ::HIR::TypeRef* slice_inner; + TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Slice, te, + slice_inner = &*te.inner; + ) + else TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Array, te, + slice_inner = &*te.inner; + ) + else { + ERROR(sp, E0000, "Matching a non-array/slice with a slice pattern - " << ty); + } + rv = true; + for(auto& sub : e.sub_patterns) + rv |= this->revisit_inner(context, sub, *slice_inner, binding_mode); + } + TU_ARM(pattern.m_data, SplitSlice, pe) { + TODO(sp, "Match ergonomics - split-slice pattern"); + } + TU_ARM(pattern.m_data, StructValue, e) { + context.add_ivars_params( e.path.m_params ); + context.equate_types( sp, ty, ::HIR::TypeRef::new_path(e.path.clone(), ::HIR::TypeRef::TypePathBinding(e.binding)) ); + rv = true; + } + TU_ARM(pattern.m_data, StructTuple, e) { + context.add_ivars_params( e.path.m_params ); + context.equate_types( sp, ty, ::HIR::TypeRef::new_path(e.path.clone(), ::HIR::TypeRef::TypePathBinding(e.binding)) ); + TODO(sp, "Match ergonomics - tuple struct pattern"); + } + TU_ARM(pattern.m_data, Struct, e) { + context.add_ivars_params( e.path.m_params ); + context.equate_types( sp, ty, ::HIR::TypeRef::new_path(e.path.clone(), ::HIR::TypeRef::TypePathBinding(e.binding)) ); + assert(e.binding); + const auto& str = *e.binding; + + // - assert check from earlier pass + ASSERT_BUG(sp, str.m_data.is_Named(), "Struct pattern on non-Named struct"); + const auto& sd = str.m_data.as_Named(); + const auto& params = e.path.m_params; + + rv = true; + for( auto& field_pat : e.sub_patterns ) + { + unsigned int f_idx = ::std::find_if( sd.begin(), sd.end(), [&](const auto& x){ return x.first == field_pat.first; } ) - sd.begin(); + if( f_idx == sd.size() ) { + ERROR(sp, E0000, "Struct " << e.path << " doesn't have a field " << field_pat.first); + } + const ::HIR::TypeRef& field_type = sd[f_idx].second.ent; + if( monomorphise_type_needed(field_type) ) { + auto field_type_mono = monomorphise_type(sp, str.m_params, params, field_type); + rv &= this->revisit_inner(context, field_pat.second, field_type_mono, binding_mode); + } + else { + rv &= this->revisit_inner(context, field_pat.second, field_type, binding_mode); + } + } + } + TU_ARM(pattern.m_data, EnumValue, e) { + context.add_ivars_params( e.path.m_params ); + context.equate_types( sp, ty, ::HIR::TypeRef::new_path(get_parent_path(e.path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)) ); + rv = true; + } + TU_ARM(pattern.m_data, EnumTuple, e) { + context.add_ivars_params( e.path.m_params ); + context.equate_types( sp, ty, ::HIR::TypeRef::new_path(get_parent_path(e.path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)) ); + assert(e.binding_ptr); + const auto& enm = *e.binding_ptr; + const auto& str = *enm.m_data.as_Data()[e.binding_idx].type.m_data.as_Path().binding.as_Struct(); + const auto& tup_var = str.m_data.as_Tuple(); + + const auto& params = e.path.m_params; + + if( e.sub_patterns.size() != tup_var.size() ) { + ERROR(sp, E0000, "Enum pattern with an incorrect number of fields - " << e.path << " - expected " << tup_var.size() << ", got " << e.sub_patterns.size() ); + } + + rv = true; // &= below ensures that all must be complete to return complete + for( unsigned int i = 0; i < e.sub_patterns.size(); i ++ ) + { + if( monomorphise_type_needed(tup_var[i].ent) ) { + auto var_ty = monomorphise_type(sp, enm.m_params, params, tup_var[i].ent); + rv &= this->revisit_inner(context, e.sub_patterns[i], var_ty, binding_mode); + } + else { + rv &= this->revisit_inner(context, e.sub_patterns[i], tup_var[i].ent, binding_mode); + } + } + } + TU_ARM(pattern.m_data, EnumStruct, e) { + context.add_ivars_params( e.path.m_params ); + context.equate_types( sp, ty, ::HIR::TypeRef::new_path(get_parent_path(e.path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)) ); + assert(e.binding_ptr); + TODO(sp, "Match ergonomics - enum struct pattern"); + } + } + return rv; + } + + static void disable_possibilities_on_bindings(const Span& sp, Context& context, const ::HIR::Pattern& pat) + { + if( pat.m_binding.is_valid() ) { + const auto& pb = pat.m_binding; + context.equate_types_from_shadow(sp, context.get_var(sp, pb.m_slot)); + } + TU_MATCHA( (pat.m_data), (e), + (Any, + ), + (Value, + ), + (Range, + ), + (Box, + disable_possibilities_on_bindings(sp, context, *e.sub); + ), + (Ref, + disable_possibilities_on_bindings(sp, context, *e.sub); + ), + (Tuple, + for(auto& subpat : e.sub_patterns) + disable_possibilities_on_bindings(sp, context, subpat); + ), + (SplitTuple, + for(auto& subpat : e.leading) { + disable_possibilities_on_bindings(sp, context, subpat); + } + for(auto& subpat : e.trailing) { + disable_possibilities_on_bindings(sp, context, subpat); + } + ), + (Slice, + for(auto& sub : e.sub_patterns) + disable_possibilities_on_bindings(sp, context, sub); + ), + (SplitSlice, + for(auto& sub : e.leading) + disable_possibilities_on_bindings(sp, context, sub); + for(auto& sub : e.trailing) + disable_possibilities_on_bindings(sp, context, sub); + ), + + // - Enums/Structs + (StructValue, + ), + (StructTuple, + for(auto& subpat : e.sub_patterns) + disable_possibilities_on_bindings(sp, context, subpat); + ), + (Struct, + for(auto& field_pat : e.sub_patterns) + disable_possibilities_on_bindings(sp, context, field_pat.second); + ), + (EnumValue, + ), + (EnumTuple, + for(auto& subpat : e.sub_patterns) + disable_possibilities_on_bindings(sp, context, subpat); + ), + (EnumStruct, + for(auto& field_pat : e.sub_patterns) + disable_possibilities_on_bindings(sp, context, field_pat.second); + ) + ) + } + static void create_bindings(const Span& sp, Context& context, ::HIR::Pattern& pat) + { + if( pat.m_binding.is_valid() ) { + const auto& pb = pat.m_binding; + context.add_var( sp, pb.m_slot, pb.m_name, context.m_ivars.new_ivar_tr() ); + // TODO: Ensure that there's no more bindings below this? + // - I'll leave the option open, MIR generation should handle cases where there's multiple borrows + // or moves. + } + TU_MATCHA( (pat.m_data), (e), + (Any, + ), + (Value, + ), + (Range, + ), + (Box, + create_bindings(sp, context, *e.sub); + ), + (Ref, + create_bindings(sp, context, *e.sub); + ), + (Tuple, + for(auto& subpat : e.sub_patterns) + create_bindings(sp, context, subpat); + ), + (SplitTuple, + for(auto& subpat : e.leading) { + create_bindings(sp, context, subpat); + } + for(auto& subpat : e.trailing) { + create_bindings(sp, context, subpat); + } + ), + (Slice, + for(auto& sub : e.sub_patterns) + create_bindings(sp, context, sub); + ), + (SplitSlice, + for(auto& sub : e.leading) + create_bindings(sp, context, sub); + for(auto& sub : e.trailing) + create_bindings(sp, context, sub); + ), + + // - Enums/Structs + (StructValue, + ), + (StructTuple, + for(auto& subpat : e.sub_patterns) + create_bindings(sp, context, subpat); + ), + (Struct, + for(auto& field_pat : e.sub_patterns) + create_bindings(sp, context, field_pat.second); + ), + (EnumValue, + ), + (EnumTuple, + for(auto& subpat : e.sub_patterns) + create_bindings(sp, context, subpat); + ), + (EnumStruct, + for(auto& field_pat : e.sub_patterns) + create_bindings(sp, context, field_pat.second); + ) + ) + } + }; + // - Create variables, assigning new ivars for all of them. + MatchErgonomicsRevisit::create_bindings(sp, *this, pat); + // - Add a revisit for the outer pattern (saving the current target type as well as the pattern) + DEBUG("Handle match ergonomics - " << pat << " with " << type); + this->add_revisit_adv( box$(( MatchErgonomicsRevisit { sp, type.clone(), pat } )) ); + return ; + } + + // --- + this->handle_pattern_direct_inner(sp, pat, type); +} + +void Context::handle_pattern_direct_inner(const Span& sp, ::HIR::Pattern& pat, const ::HIR::TypeRef& type) { TRACE_FUNCTION_F("pat = " << pat << ", type = " << type); @@ -3645,7 +4140,6 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type // TODO: Bindings aren't allowed within another binding } - struct H { static void handle_value(Context& context, const Span& sp, const ::HIR::TypeRef& type, const ::HIR::Pattern::Value& val) { TU_MATCH(::HIR::Pattern::Value, (val), (v), @@ -3702,13 +4196,13 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type if( te.path.m_data.is_Generic() && te.path.m_data.as_Generic().m_path == m_lang_Box ) { // Box const auto& inner = te.path.m_data.as_Generic().m_params.m_types.at(0); - this->add_binding(sp, *e.sub, inner); + this->handle_pattern_direct_inner(sp, *e.sub, inner); break ; } ) auto inner = this->m_ivars.new_ivar_tr(); - this->add_binding(sp, *e.sub, inner); + this->handle_pattern_direct_inner(sp, *e.sub, inner); ::HIR::GenericPath path { m_lang_Box, ::HIR::PathParams(mv$(inner)) }; this->equate_types( sp, type, ::HIR::TypeRef::new_path(mv$(path), ::HIR::TypeRef::TypePathBinding(&m_crate.get_struct_by_path(sp, m_lang_Box))) ); ), @@ -3718,11 +4212,11 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type if( te.type != e.type ) { ERROR(sp, E0000, "Pattern-type mismatch, &-ptr mutability mismatch"); } - this->add_binding(sp, *e.sub, *te.inner); + this->handle_pattern_direct_inner(sp, *e.sub, *te.inner); ) else { auto inner = this->m_ivars.new_ivar_tr(); - this->add_binding(sp, *e.sub, inner); + this->handle_pattern_direct_inner(sp, *e.sub, inner); this->equate_types(sp, type, ::HIR::TypeRef::new_borrow( e.type, mv$(inner) )); } ), @@ -3735,14 +4229,14 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type } for(unsigned int i = 0; i < e.sub_patterns.size(); i ++ ) - this->add_binding(sp, e.sub_patterns[i], te[i] ); + this->handle_pattern_direct_inner(sp, e.sub_patterns[i], te[i] ); ) else { ::std::vector< ::HIR::TypeRef> sub_types; for(unsigned int i = 0; i < e.sub_patterns.size(); i ++ ) { sub_types.push_back( this->m_ivars.new_ivar_tr() ); - this->add_binding(sp, e.sub_patterns[i], sub_types[i] ); + this->handle_pattern_direct_inner(sp, e.sub_patterns[i], sub_types[i] ); } this->equate_types(sp, ty, ::HIR::TypeRef( mv$(sub_types) )); } @@ -3755,11 +4249,11 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type unsigned int tup_idx = 0; for(auto& subpat : e.leading) { - this->add_binding(sp, subpat, te[tup_idx++]); + this->handle_pattern_direct_inner(sp, subpat, te[tup_idx++]); } tup_idx = te.size() - e.trailing.size(); for(auto& subpat : e.trailing) { - this->add_binding(sp, subpat, te[tup_idx++]); + this->handle_pattern_direct_inner(sp, subpat, te[tup_idx++]); } // TODO: Should this replace the pattern with a non-split? @@ -3775,12 +4269,12 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type leading_tys.reserve(e.leading.size()); for(auto& subpat : e.leading) { leading_tys.push_back( this->m_ivars.new_ivar_tr() ); - this->add_binding(sp, subpat, leading_tys.back()); + this->handle_pattern_direct_inner(sp, subpat, leading_tys.back()); } ::std::vector<::HIR::TypeRef> trailing_tys; for(auto& subpat : e.trailing) { trailing_tys.push_back( this->m_ivars.new_ivar_tr() ); - this->add_binding(sp, subpat, trailing_tys.back()); + this->handle_pattern_direct_inner(sp, subpat, trailing_tys.back()); } struct SplitTuplePatRevisit: @@ -3831,16 +4325,16 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type const auto& ty = this->get_type(type); TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Slice, te, for(auto& sub : e.sub_patterns) - this->add_binding(sp, sub, *te.inner ); + this->handle_pattern_direct_inner(sp, sub, *te.inner ); ) else TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Array, te, for(auto& sub : e.sub_patterns) - this->add_binding(sp, sub, *te.inner ); + this->handle_pattern_direct_inner(sp, sub, *te.inner ); ) else TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Infer, te, auto inner = this->m_ivars.new_ivar_tr(); for(auto& sub : e.sub_patterns) - this->add_binding(sp, sub, inner); + this->handle_pattern_direct_inner(sp, sub, inner); struct SlicePatRevisit: public Revisitor @@ -3968,9 +4462,9 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type } for(auto& sub : e.leading) - this->add_binding( sp, sub, inner ); + this->handle_pattern_direct_inner( sp, sub, inner ); for(auto& sub : e.trailing) - this->add_binding( sp, sub, inner ); + this->handle_pattern_direct_inner( sp, sub, inner ); ), // - Enums/Structs @@ -3997,10 +4491,10 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type const auto& field_type = sd[i].ent; if( monomorphise_type_needed(field_type) ) { auto var_ty = monomorphise_type(sp, str.m_params, params, field_type); - this->add_binding(sp, sub_pat, var_ty); + this->handle_pattern_direct_inner(sp, sub_pat, var_ty); } else { - this->add_binding(sp, sub_pat, field_type); + this->handle_pattern_direct_inner(sp, sub_pat, field_type); } } ), @@ -4028,20 +4522,16 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type const ::HIR::TypeRef& field_type = sd[f_idx].second.ent; if( monomorphise_type_needed(field_type) ) { auto field_type_mono = monomorphise_type(sp, str.m_params, params, field_type); - this->add_binding(sp, field_pat.second, field_type_mono); + this->handle_pattern_direct_inner(sp, field_pat.second, field_type_mono); } else { - this->add_binding(sp, field_pat.second, field_type); + this->handle_pattern_direct_inner(sp, field_pat.second, field_type); } } ), (EnumValue, this->add_ivars_params( e.path.m_params ); - { - auto path = e.path.clone(); - path.m_path.m_components.pop_back(); - this->equate_types( sp, type, ::HIR::TypeRef::new_path(mv$(path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)) ); - } + this->equate_types( sp, type, ::HIR::TypeRef::new_path(get_parent_path(e.path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)) ); assert(e.binding_ptr); const auto& enm = *e.binding_ptr; @@ -4053,12 +4543,7 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type ), (EnumTuple, this->add_ivars_params( e.path.m_params ); - { - auto path = e.path.clone(); - path.m_path.m_components.pop_back(); - - this->equate_types( sp, type, ::HIR::TypeRef::new_path(mv$(path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)) ); - } + this->equate_types( sp, type, ::HIR::TypeRef::new_path(get_parent_path(e.path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)) ); assert(e.binding_ptr); const auto& enm = *e.binding_ptr; const auto& str = *enm.m_data.as_Data()[e.binding_idx].type.m_data.as_Path().binding.as_Struct(); @@ -4074,21 +4559,16 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type { if( monomorphise_type_needed(tup_var[i].ent) ) { auto var_ty = monomorphise_type(sp, enm.m_params, params, tup_var[i].ent); - this->add_binding(sp, e.sub_patterns[i], var_ty); + this->handle_pattern_direct_inner(sp, e.sub_patterns[i], var_ty); } else { - this->add_binding(sp, e.sub_patterns[i], tup_var[i].ent); + this->handle_pattern_direct_inner(sp, e.sub_patterns[i], tup_var[i].ent); } } ), (EnumStruct, this->add_ivars_params( e.path.m_params ); - { - auto path = e.path.clone(); - path.m_path.m_components.pop_back(); - - this->equate_types( sp, type, ::HIR::TypeRef::new_path(mv$(path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)) ); - } + this->equate_types( sp, type, ::HIR::TypeRef::new_path(get_parent_path(e.path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)) ); if( e.sub_patterns.empty() ) return ; @@ -4108,10 +4588,10 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type const ::HIR::TypeRef& field_type = tup_var[f_idx].second.ent; if( monomorphise_type_needed(field_type) ) { auto field_type_mono = monomorphise_type(sp, enm.m_params, params, field_type); - this->add_binding(sp, field_pat.second, field_type_mono); + this->handle_pattern_direct_inner(sp, field_pat.second, field_type_mono); } else { - this->add_binding(sp, field_pat.second, field_type); + this->handle_pattern_direct_inner(sp, field_pat.second, field_type); } } ) @@ -4369,6 +4849,7 @@ void Context::add_var(const Span& sp, unsigned int index, const ::std::string& n m_bindings.resize(index+1); if( m_bindings[index].name == "" ) { m_bindings[index] = Binding { name, mv$(type) }; + this->require_sized(sp, m_bindings[index].ty); } else { ASSERT_BUG(sp, m_bindings[index].name == name, ""); @@ -6414,7 +6895,7 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR: Context context { ms.m_crate, ms.m_impl_generics, ms.m_item_generics }; for( auto& arg : args ) { - context.add_binding( Span(), arg.first, arg.second ); + context.handle_pattern( Span(), arg.first, arg.second ); } // - Build up ruleset from node tree @@ -6543,14 +7024,19 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR: ++ it; } } - for( auto it = context.adv_revisits.begin(); it != context.adv_revisits.end(); ) { - auto& ent = **it; - if( ent.revisit(context) ) { - it = context.adv_revisits.erase(it); + ::std::vector adv_revisit_remove_list; + size_t len = context.adv_revisits.size(); + for(size_t i = 0; i < len; i ++) + { + auto& ent = *context.adv_revisits[i]; + adv_revisit_remove_list.push_back( ent.revisit(context) ); } - else { - ++ it; + for(size_t i = len; i --;) + { + if( adv_revisit_remove_list[i] ) { + context.adv_revisits.erase( context.adv_revisits.begin() + i ); + } } } diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index b353e6a7..f3604917 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -1062,6 +1062,9 @@ bool TraitResolution::iterate_bounds_traits(const Span& sp, ::std::functiontype, be->trait) ) return true; + // TODO: Remove, or fix places where `find_named_trait_in_trait` is used along with this function + // - Using both leads to duplicate detections, which can confuse callers +#if 0 assert(be->trait.m_trait_ptr); const auto& trait_ref = *be->trait.m_trait_ptr; auto monomorph_cb = monomorphise_type_get_cb(sp, &be->type, &be->trait.m_path.m_params, nullptr, nullptr); @@ -1073,6 +1076,7 @@ bool TraitResolution::iterate_bounds_traits(const Span& sp, ::std::functiontype, tp_mono) ) return true; } +#endif } return false; }); -- cgit v1.2.3 From 0132d377f8a8e41bf6c92d8461855d7a8febcf10 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Thu, 27 Dec 2018 16:58:27 +0800 Subject: Lower MIR - Rough handling of 1.29 `box` operator --- src/mir/from_hir.cpp | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index 6a96ab64..78ba9024 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -18,6 +18,7 @@ #include "operations.hpp" #include #include +#include // Target_GetSizeAndAlignOf - for `box` namespace { @@ -1556,6 +1557,17 @@ namespace { } void visit(::HIR::ExprNode_Emplace& node) override + { + switch(gTargetVersion) + { + case TargetVersion::Rustc1_19: + return visit_emplace_119(node); + case TargetVersion::Rustc1_29: + return visit_emplace_129(node); + } + throw "BUG: Unhandled target version"; + } + void visit_emplace_119(::HIR::ExprNode_Emplace& node) { if( node.m_type == ::HIR::ExprNode_Emplace::Type::Noop ) { return node.m_value->visit(*this); @@ -1689,6 +1701,94 @@ namespace { m_builder.mark_value_assigned(node.span(), res); m_builder.set_result( node.span(), mv$(res) ); } + void visit_emplace_129(::HIR::ExprNode_Emplace& node) + { + assert( node.m_type == ::HIR::ExprNode_Emplace::Type::Boxer ); + const auto& data_ty = node.m_value->m_res_type; + + node.m_value->visit(*this); + auto val = m_builder.get_result(node.span()); + + const auto& lang_exchange_malloc = m_builder.crate().get_lang_item_path(node.span(), "exchange_malloc"); + const auto& lang_owned_box = m_builder.crate().get_lang_item_path(node.span(), "owned_box"); + + ::HIR::PathParams trait_params_data; + trait_params_data.m_types.push_back( data_ty.clone() ); + + // 1. Determine the size/alignment of the type + ::MIR::Param size_param, align_param; + size_t item_size, item_align; + if( Target_GetSizeAndAlignOf(node.span(), m_builder.resolve(), data_ty, item_size, item_align) ) { + size_param = ::MIR::Constant::make_Int({ static_cast(item_size), ::HIR::CoreType::Usize }); + align_param = ::MIR::Constant::make_Int({ static_cast(item_align), ::HIR::CoreType::Usize }); + } + else { + // Insert calls to "size_of" and "align_of" intrinsics + auto size_slot = m_builder.new_temporary( ::HIR::CoreType::Usize ); + auto size__panic = m_builder.new_bb_unlinked(); + auto size__ok = m_builder.new_bb_unlinked(); + m_builder.end_block(::MIR::Terminator::make_Call({ + size__ok, size__panic, + size_slot.clone(), ::MIR::CallTarget::make_Intrinsic({ "size_of", trait_params_data.clone() }), + {} + })); + m_builder.set_cur_block(size__panic); m_builder.end_block( ::MIR::Terminator::make_Diverge({}) ); // HACK + m_builder.set_cur_block(size__ok); + auto align_slot = m_builder.new_temporary( ::HIR::CoreType::Usize ); + auto align__panic = m_builder.new_bb_unlinked(); + auto align__ok = m_builder.new_bb_unlinked(); + m_builder.end_block(::MIR::Terminator::make_Call({ + align__ok, align__panic, + align_slot.clone(), ::MIR::CallTarget::make_Intrinsic({ "align_of", trait_params_data.clone() }), + {} + })); + m_builder.set_cur_block(align__panic); m_builder.end_block( ::MIR::Terminator::make_Diverge({}) ); // HACK + m_builder.set_cur_block(align__ok); + + size_param = ::std::move(size_slot); + align_param = ::std::move(align_slot); + } + + // 2. Call the allocator function and get a pointer + // - NOTE: "exchange_malloc" returns a `*mut u8`, need to cast that to the target type + auto place_raw_type = ::HIR::TypeRef::new_pointer(::HIR::BorrowType::Unique, ::HIR::CoreType::U8); + auto place_raw = m_builder.new_temporary( place_raw_type ); + + auto place__panic = m_builder.new_bb_unlinked(); + auto place__ok = m_builder.new_bb_unlinked(); + m_builder.end_block(::MIR::Terminator::make_Call({ + place__ok, place__panic, + place_raw.clone(), ::HIR::Path(lang_exchange_malloc), + make_vec2<::MIR::Param>( ::std::move(size_param), ::std::move(align_param) ) + })); + m_builder.set_cur_block(place__panic); m_builder.end_block( ::MIR::Terminator::make_Diverge({}) ); // HACK + m_builder.set_cur_block(place__ok); + + auto place_type = ::HIR::TypeRef::new_pointer(::HIR::BorrowType::Unique, data_ty.clone()); + auto place = m_builder.new_temporary( place_type ); + m_builder.push_stmt_assign(node.span(), place.clone(), ::MIR::RValue::make_Cast({ mv$(place_raw), place_type.clone() })); + // 3. Do a non-dropping write into the target location (i.e. just a MIR assignment) + // TODO: This should indicate that the destination shouldn't be dropped, but since drops don't happen on + // reassign currently, that's not yet an issue. + m_builder.push_stmt_assign(node.span(), ::MIR::LValue::make_Deref({box$(place.clone())}), mv$(val)); + // 4. Convert the pointer into an `owned_box` + auto res_type = ::HIR::TypeRef::new_path(::HIR::GenericPath(lang_owned_box, mv$(trait_params_data)), &m_builder.crate().get_struct_by_path(node.span(), lang_owned_box)); + auto res = m_builder.new_temporary(res_type); + auto cast__panic = m_builder.new_bb_unlinked(); + auto cast__ok = m_builder.new_bb_unlinked(); + ::HIR::PathParams transmute_params; + transmute_params.m_types.push_back( res_type.clone() ); + transmute_params.m_types.push_back( place_type.clone() ); + m_builder.end_block(::MIR::Terminator::make_Call({ + cast__ok, cast__panic, + res.clone(), ::MIR::CallTarget::make_Intrinsic({ "transmute", mv$(transmute_params) }), + {} + })); + m_builder.set_cur_block(cast__panic); m_builder.end_block( ::MIR::Terminator::make_Diverge({}) ); // HACK + m_builder.set_cur_block(cast__ok); + + m_builder.set_result(node.span(), mv$(res)); + } void visit(::HIR::ExprNode_TupleVariant& node) override { -- cgit v1.2.3 From a0bdedaaed4393236877c45bb56692fe05732a56 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Thu, 27 Dec 2018 18:35:54 +0800 Subject: Lower MIR - Match ergonomics (and a little bit of cleanup/fixes). - liballoc building, up to libstd --- src/hir/pattern.cpp | 3 + src/hir/pattern.hpp | 2 +- src/hir_typeck/expr_cs.cpp | 4 ++ src/mir/from_hir.cpp | 2 +- src/mir/from_hir_match.cpp | 136 ++++++++++++++++++++++++++------------------- src/mir/mir_builder.cpp | 2 + 6 files changed, 90 insertions(+), 59 deletions(-) diff --git a/src/hir/pattern.cpp b/src/hir/pattern.cpp index da6446d7..a86dbfa7 100644 --- a/src/hir/pattern.cpp +++ b/src/hir/pattern.cpp @@ -46,6 +46,9 @@ namespace HIR { if( x.m_binding.is_valid() ) { os << x.m_binding; } + if( x.m_implicit_deref_count > 0 ) { + os << "&*" << x.m_implicit_deref_count; + } TU_MATCH(Pattern::Data, (x.m_data), (e), (Any, os << "_"; diff --git a/src/hir/pattern.hpp b/src/hir/pattern.hpp index d190db5a..b17ebcb4 100644 --- a/src/hir/pattern.hpp +++ b/src/hir/pattern.hpp @@ -136,7 +136,7 @@ struct Pattern PatternBinding m_binding; Data m_data; - unsigned m_implicit_deref_count; + unsigned m_implicit_deref_count = 0; Pattern() {} Pattern(PatternBinding pb, Data d): diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 8df54be5..739d0f8b 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -3858,6 +3858,10 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T } TU_ARM(pattern.m_data, Value, pe) { // no-op? + if( pe.val.is_String() ) { + ASSERT_BUG(sp, pattern.m_implicit_deref_count >= 1, ""); + pattern.m_implicit_deref_count -= 1; + } rv = true; } TU_ARM(pattern.m_data, Range, pe) { diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index 78ba9024..c3281bd6 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -1782,7 +1782,7 @@ namespace { m_builder.end_block(::MIR::Terminator::make_Call({ cast__ok, cast__panic, res.clone(), ::MIR::CallTarget::make_Intrinsic({ "transmute", mv$(transmute_params) }), - {} + make_vec1( ::MIR::Param( mv$(place) ) ) })); m_builder.set_cur_block(cast__panic); m_builder.end_block( ::MIR::Terminator::make_Diverge({}) ); // HACK m_builder.set_cur_block(cast__ok); diff --git a/src/mir/from_hir_match.cpp b/src/mir/from_hir_match.cpp index b8fabdc0..8014ea8e 100644 --- a/src/mir/from_hir_match.cpp +++ b/src/mir/from_hir_match.cpp @@ -886,9 +886,10 @@ void PatternRulesetBuilder::append_from_lit(const Span& sp, const ::HIR::Literal ) ) } -void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pat, const ::HIR::TypeRef& ty) +void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pat, const ::HIR::TypeRef& top_ty) { - TRACE_FUNCTION_F("pat="<m_data.is_Borrow() ) + BUG(sp, "Deref step " << i << "/" << pat.m_implicit_deref_count << " hit a non-borrow " << *ty_p << " from " << top_ty); + ty_p = &*ty_p->m_data.as_Borrow().inner; + m_field_path.push_back( FIELD_DEREF ); + } + const auto& ty = *ty_p; + // TODO: Outer handling for Value::Named patterns // - Convert them into either a pattern, or just a variant of this function that operates on ::HIR::Literal // > It does need a way of handling unknown-value constants (e.g. ::CONST) @@ -931,6 +942,10 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa if( pve.binding ) { this->append_from_lit(sp, pve.binding->m_value_res, ty); + for(size_t i = 0; i < pat.m_implicit_deref_count; i ++) + { + m_field_path.pop_back(); + } return ; } else @@ -940,20 +955,23 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa ) ) - TU_MATCHA( (ty.m_data), (e), - (Infer, BUG(sp, "Ivar for in match type"); ), - (Diverge, + TU_MATCH_HDR( (ty.m_data), {) + TU_ARM(ty.m_data, Infer, e) { + BUG(sp, "Ivar for in match type"); + } + TU_ARM(ty.m_data, Diverge, e) { // Since ! can never exist, mark this arm as impossible. // TODO: Marking as impossible (and not emitting) leads to exhuaustiveness failure. //this->m_is_impossible = true; - ), - (Primitive, - TU_MATCH_DEF(::HIR::Pattern::Data, (pat.m_data), (pe), - ( BUG(sp, "Matching primitive with invalid pattern - " << pat); ), - (Any, + } + TU_ARM(ty.m_data, Primitive, e) { + TU_MATCH_HDR( (pat.m_data), {) + default: + BUG(sp, "Matching primitive with invalid pattern - " << pat); + TU_ARM(pat.m_data, Any, pe) { this->push_rule( PatternRule::make_Any({}) ); - ), - (Range, + } + TU_ARM(pat.m_data, Range, pe) { switch(e) { case ::HIR::CoreType::F32: @@ -994,8 +1012,8 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa BUG(sp, "Hit match over `str` - must be `&str`"); break; } - ), - (Value, + } + TU_ARM(pat.m_data, Value, pe) { switch(e) { case ::HIR::CoreType::F32: @@ -1035,16 +1053,16 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa BUG(sp, "Hit match over `str` - must be `&str`"); break; } - ) - ) - ), - (Tuple, + } + } + } + TU_ARM(ty.m_data, Tuple, e) { m_field_path.push_back(0); TU_MATCH_DEF(::HIR::Pattern::Data, (pat.m_data), (pe), ( BUG(sp, "Matching tuple with invalid pattern - " << pat); ), (Any, for(const auto& sty : e) { - this->append_from(sp, pat, sty); + this->append_from(sp, empty_pattern, sty); m_field_path.back() ++; } ), @@ -1070,8 +1088,8 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa ) ) m_field_path.pop_back(); - ), - (Path, + } + TU_ARM(ty.m_data, Path, e) { // This is either a struct destructure or an enum TU_MATCHA( (e.binding), (pbe), (Unbound, @@ -1132,12 +1150,12 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa TU_MATCH_DEF( ::HIR::Pattern::Data, (pat.m_data), (pe), ( BUG(sp, "Match not allowed, " << ty << " with " << pat); ), (Any, - // - Recurse into type and use the same pattern again + // - Recurse into type using an empty pattern for(const auto& fld : sd) { ::HIR::TypeRef tmp; const auto& sty_mono = (monomorphise_type_needed(fld.ent) ? tmp = monomorph(fld.ent) : fld.ent); - this->append_from(sp, pat, sty_mono); + this->append_from(sp, empty_pattern, sty_mono); m_field_path.back() ++; } ), @@ -1166,7 +1184,7 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa { ::HIR::TypeRef tmp; const auto& sty_mono = (monomorphise_type_needed(fld.second.ent) ? tmp = monomorph(fld.second.ent) : fld.second.ent); - this->append_from(sp, pat, sty_mono); + this->append_from(sp, empty_pattern, sty_mono); m_field_path.back() ++; } m_field_path.pop_back(); @@ -1182,8 +1200,7 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa auto it = ::std::find_if( pe.sub_patterns.begin(), pe.sub_patterns.end(), [&](const auto& x){ return x.first == fld.first; } ); if( it == pe.sub_patterns.end() ) { - ::HIR::Pattern any_pat {}; - this->append_from(sp, any_pat, sty_mono); + this->append_from(sp, empty_pattern, sty_mono); } else { @@ -1289,8 +1306,8 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa ) ) ) - ), - (Generic, + } + TU_ARM(ty.m_data, Generic, e) { // Generics don't destructure, so the only valid pattern is `_` TU_MATCH_DEF( ::HIR::Pattern::Data, (pat.m_data), (pe), ( BUG(sp, "Match not allowed, " << ty << " with " << pat); ), @@ -1298,29 +1315,29 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa this->push_rule( PatternRule::make_Any({}) ); ) ) - ), - (TraitObject, + } + TU_ARM(ty.m_data, TraitObject, e) { if( pat.m_data.is_Any() ) { } else { ERROR(sp, E0000, "Attempting to match over a trait object"); } - ), - (ErasedType, + } + TU_ARM(ty.m_data, ErasedType, e) { if( pat.m_data.is_Any() ) { } else { ERROR(sp, E0000, "Attempting to match over an erased type"); } - ), - (Array, + } + TU_ARM(ty.m_data, Array, e) { // Sequential match just like tuples. m_field_path.push_back(0); TU_MATCH_DEF(::HIR::Pattern::Data, (pat.m_data), (pe), ( BUG(sp, "Matching array with invalid pattern - " << pat); ), (Any, for(unsigned int i = 0; i < e.size_val; i ++) { - this->append_from(sp, pat, *e.inner); + this->append_from(sp, empty_pattern, *e.inner); m_field_path.back() ++; } ), @@ -1336,8 +1353,8 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa ) ) m_field_path.pop_back(); - ), - (Slice, + } + TU_ARM(ty.m_data, Slice, e) { TU_MATCH_DEF(::HIR::Pattern::Data, (pat.m_data), (pe), ( BUG(sp, "Matching over [T] with invalid pattern - " << pat); @@ -1393,18 +1410,19 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa }) ); ) ) - ), - (Borrow, + } + TU_ARM(ty.m_data, Borrow, e) { m_field_path.push_back( FIELD_DEREF ); - TU_MATCH_DEF( ::HIR::Pattern::Data, (pat.m_data), (pe), - ( BUG(sp, "Matching borrow invalid pattern - " << pat); ), - (Any, - this->append_from( sp, pat, *e.inner ); - ), - (Ref, + TU_MATCH_HDR( (pat.m_data), {) + default: + BUG(sp, "Matching borrow invalid pattern - " << ty << " with " << pat); + TU_ARM(pat.m_data, Any, pe) { + this->append_from( sp, empty_pattern, *e.inner ); + } + TU_ARM(pat.m_data, Ref, pe) { this->append_from( sp, *pe.sub, *e.inner ); - ), - (Value, + } + TU_ARM(pat.m_data, Value, pe) { // TODO: Check type? if( pe.val.is_String() ) { const auto& s = pe.val.as_String(); @@ -1423,32 +1441,36 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa else { BUG(sp, "Matching borrow invalid pattern - " << pat); } - ) - ) + } + } m_field_path.pop_back(); - ), - (Pointer, + } + TU_ARM(ty.m_data, Pointer, e) { if( pat.m_data.is_Any() ) { } else { ERROR(sp, E0000, "Attempting to match over a pointer"); } - ), - (Function, + } + TU_ARM(ty.m_data, Function, e) { if( pat.m_data.is_Any() ) { } else { ERROR(sp, E0000, "Attempting to match over a functon pointer"); } - ), - (Closure, + } + TU_ARM(ty.m_data, Closure, e) { if( pat.m_data.is_Any() ) { } else { ERROR(sp, E0000, "Attempting to match over a closure"); } - ) - ) + } + } + for(size_t i = 0; i < pat.m_implicit_deref_count; i ++) + { + m_field_path.pop_back(); + } } namespace { diff --git a/src/mir/mir_builder.cpp b/src/mir/mir_builder.cpp index 3e14ce66..a3650919 100644 --- a/src/mir/mir_builder.cpp +++ b/src/mir/mir_builder.cpp @@ -397,6 +397,7 @@ void MirBuilder::push_stmt(const Span& sp, ::MIR::Statement stmt) void MirBuilder::mark_value_assigned(const Span& sp, const ::MIR::LValue& dst) { VarState* state_p = nullptr; + // TODO: Tracking of complex asignment states (e.g. assignment of a field) TU_MATCH_DEF(::MIR::LValue, (dst), (e), ( ), @@ -420,6 +421,7 @@ void MirBuilder::mark_value_assigned(const Span& sp, const ::MIR::LValue& dst) drop_value_from_state(sp, *state_p, dst.clone()); *state_p = VarState::make_Valid({}); } + // TODO: What about assigning into non-tracked locations? Should still cause a drop } void MirBuilder::raise_temporaries(const Span& sp, const ::MIR::LValue& val, const ScopeHandle& scope, bool to_above/*=false*/) -- cgit v1.2.3 From 38575976d5835cb8cc9e7ae335969873d01e7d65 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 28 Dec 2018 08:37:09 +0800 Subject: macro_rules - Support for the :vis fragment --- src/ast/ast.hpp | 2 ++ src/macro_rules/eval.cpp | 26 ++++++++++++++++++++++++++ src/macro_rules/macro_rules.hpp | 1 + src/macro_rules/mod.cpp | 12 ++++++++++++ src/macro_rules/parse.cpp | 15 +++++++++++++++ src/macro_rules/pattern_checks.hpp | 1 + src/parse/common.hpp | 1 + src/parse/eTokenType.enum.h | 1 + src/parse/expr.cpp | 1 + src/parse/interpolated_fragment.cpp | 11 +++++++++++ src/parse/interpolated_fragment.hpp | 3 +++ src/parse/parseerror.cpp | 22 +++++++++++----------- src/parse/root.cpp | 7 ++++++- src/parse/token.cpp | 27 +++++++++++++++++++++++++-- src/parse/token.hpp | 3 +++ src/parse/types.cpp | 10 +++++++++- 16 files changed, 128 insertions(+), 15 deletions(-) diff --git a/src/ast/ast.hpp b/src/ast/ast.hpp index f78d559f..49e2bdc6 100644 --- a/src/ast/ast.hpp +++ b/src/ast/ast.hpp @@ -42,6 +42,8 @@ class Item; using ::std::unique_ptr; using ::std::move; +typedef bool Visibility; + enum eItemType { ITEM_TRAIT, diff --git a/src/macro_rules/eval.cpp b/src/macro_rules/eval.cpp index cda51ebe..558f26b3 100644 --- a/src/macro_rules/eval.cpp +++ b/src/macro_rules/eval.cpp @@ -655,6 +655,8 @@ bool Macro_TryPatternCap(TokenStream& lex, MacroPatEnt::Type type) return LOOK_AHEAD(lex) == TOK_IDENT || LOOK_AHEAD(lex) == TOK_INTERPOLATED_META; case MacroPatEnt::PAT_ITEM: return is_token_item( LOOK_AHEAD(lex) ) || LOOK_AHEAD(lex) == TOK_IDENT; + case MacroPatEnt::PAT_VIS: + return is_token_vis( LOOK_AHEAD(lex) ); } BUG(lex.point_span(), "Fell through"); } @@ -723,6 +725,8 @@ InterpolatedFragment Macro_HandlePatternCap(TokenStream& lex, MacroPatEnt::Type CHECK_TOK(tok, TOK_IDENT); // TODO: TOK_INTERPOLATED_IDENT return InterpolatedFragment( TokenTree(lex.getHygiene(), tok) ); + case MacroPatEnt::PAT_VIS: + return InterpolatedFragment( Parse_Publicity(lex, /*allow_restricted=*/true) ); } throw ""; } @@ -1817,6 +1821,26 @@ namespace } return true; } + bool consume_vis(TokenStreamRO& lex) + { + TRACE_FUNCTION; + if( lex.consume_if(TOK_INTERPOLATED_VIS) ) + { + return true; + } + else if( lex.consume_if(TOK_RWORD_PUB) ) + { + if( lex.next() == TOK_PAREN_OPEN ) + { + return consume_tt(lex); + } + return true; + } + else + { + return true; + } + } bool consume_from_frag(TokenStreamRO& lex, MacroPatEnt::Type type) { @@ -1891,6 +1915,8 @@ namespace break; case MacroPatEnt::PAT_ITEM: return consume_item(lex); + case MacroPatEnt::PAT_VIS: + return consume_vis(lex); } return true; } diff --git a/src/macro_rules/macro_rules.hpp b/src/macro_rules/macro_rules.hpp index c04e3548..9ec6a6bb 100644 --- a/src/macro_rules/macro_rules.hpp +++ b/src/macro_rules/macro_rules.hpp @@ -60,6 +60,7 @@ struct MacroPatEnt PAT_BLOCK, PAT_META, PAT_ITEM, // :item + PAT_VIS, } type; MacroPatEnt(): diff --git a/src/macro_rules/mod.cpp b/src/macro_rules/mod.cpp index 6410d334..fcea5b25 100644 --- a/src/macro_rules/mod.cpp +++ b/src/macro_rules/mod.cpp @@ -156,6 +156,16 @@ bool is_token_item(eTokenType tt) { return false; } } +bool is_token_vis(eTokenType tt) { + switch(tt) + { + case TOK_RWORD_PUB: + case TOK_INTERPOLATED_VIS: + return true; + default: + return true; // TODO: Is this true? it can capture just nothing + } +} MacroRulesPtr::~MacroRulesPtr() { @@ -188,6 +198,7 @@ MacroRulesPtr::~MacroRulesPtr() case MacroPatEnt::PAT_BLOCK: os << "block"; break; case MacroPatEnt::PAT_META: os << "meta"; break; case MacroPatEnt::PAT_ITEM: os << "item"; break; + case MacroPatEnt::PAT_VIS: os << "vis"; break; } break; } @@ -209,6 +220,7 @@ MacroRulesPtr::~MacroRulesPtr() case MacroPatEnt::PAT_BLOCK: os << "PAT_BLOCK"; break; case MacroPatEnt::PAT_META: os << "PAT_META"; break; case MacroPatEnt::PAT_ITEM: os << "PAT_ITEM"; break; + case MacroPatEnt::PAT_VIS: os << "PAT_VIS"; break; } return os; } diff --git a/src/macro_rules/parse.cpp b/src/macro_rules/parse.cpp index 00cf7cf7..e6d9d7ae 100644 --- a/src/macro_rules/parse.cpp +++ b/src/macro_rules/parse.cpp @@ -82,6 +82,8 @@ public: ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_BLOCK) ); else if( type == "item" ) ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_ITEM) ); + else if( /*TARGETVER_1_29 && */ type == "vis" ) // TODO: Should this be selective? + ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_VIS) ); else ERROR(lex.point_span(), E0000, "Unknown fragment type '" << type << "'"); break; } @@ -428,6 +430,19 @@ bool patterns_are_same(const Span& sp, const MacroPatEnt& left, const MacroPatEn default: ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left); } + // Matches visibility specifiers + case MacroPatEnt::PAT_VIS: + switch(left.type) + { + case MacroPatEnt::PAT_TOKEN: + if( is_token_vis(left.tok.type()) ) + ERROR(sp, E0000, "Incompatible macro fragments"); + return false; + case MacroPatEnt::PAT_VIS: + return true; + default: + ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left); + } } throw ""; } diff --git a/src/macro_rules/pattern_checks.hpp b/src/macro_rules/pattern_checks.hpp index 4ebbe915..6ce15050 100644 --- a/src/macro_rules/pattern_checks.hpp +++ b/src/macro_rules/pattern_checks.hpp @@ -13,3 +13,4 @@ extern bool is_token_type(eTokenType tt); extern bool is_token_expr(eTokenType tt); extern bool is_token_stmt(eTokenType tt); extern bool is_token_item(eTokenType tt); +extern bool is_token_vis(eTokenType tt); diff --git a/src/parse/common.hpp b/src/parse/common.hpp index 49499c86..c742fe4f 100644 --- a/src/parse/common.hpp +++ b/src/parse/common.hpp @@ -40,6 +40,7 @@ extern ::std::vector Parse_PathNodes(TokenStream& lex, eParsePath extern AST::PathParams Parse_Path_GenericList(TokenStream& lex); +extern AST::Visibility Parse_Publicity(TokenStream& lex, bool allow_restricted=true); extern AST::HigherRankedBounds Parse_HRB(TokenStream& lex); extern AST::AttributeList Parse_ItemAttrs(TokenStream& lex); extern void Parse_ParentAttrs(TokenStream& lex, AST::AttributeList& out); diff --git a/src/parse/eTokenType.enum.h b/src/parse/eTokenType.enum.h index 4408c45a..93590264 100644 --- a/src/parse/eTokenType.enum.h +++ b/src/parse/eTokenType.enum.h @@ -21,6 +21,7 @@ _(TOK_INTERPOLATED_STMT) _(TOK_INTERPOLATED_BLOCK) _(TOK_INTERPOLATED_META) _(TOK_INTERPOLATED_ITEM) +_(TOK_INTERPOLATED_VIS) // Value tokens _(TOK_IDENT) diff --git a/src/parse/expr.cpp b/src/parse/expr.cpp index e5d7981d..03c77043 100644 --- a/src/parse/expr.cpp +++ b/src/parse/expr.cpp @@ -124,6 +124,7 @@ ExprNodeP Parse_ExprBlockLine_WithItems(TokenStream& lex, ::std::shared_ptr*>(m_ptr); break; + case InterpolatedFragment::VIS: + delete reinterpret_cast(m_ptr); + break; } } } @@ -82,6 +85,11 @@ InterpolatedFragment::InterpolatedFragment(TypeRef v): m_ptr( new TypeRef(mv$(v)) ) { } +InterpolatedFragment::InterpolatedFragment(AST::Visibility v): + m_type( InterpolatedFragment::VIS ), + m_ptr( new AST::Visibility(mv$(v)) ) +{ +} ::std::ostream& operator<<(::std::ostream& os, InterpolatedFragment const& x) { @@ -117,6 +125,9 @@ InterpolatedFragment::InterpolatedFragment(TypeRef v): const auto& named_item = *reinterpret_cast*>(x.m_ptr); os << "item[" << named_item.data.tag_str() << "(" << named_item.name << ")]"; } break; + case InterpolatedFragment::VIS: + os << "vis[" << *reinterpret_cast(x.m_ptr) << "]"; + break; } return os; } diff --git a/src/parse/interpolated_fragment.hpp b/src/parse/interpolated_fragment.hpp index 36539fb0..1e69fe26 100644 --- a/src/parse/interpolated_fragment.hpp +++ b/src/parse/interpolated_fragment.hpp @@ -12,6 +12,7 @@ class TypeRef; class TokenTree; namespace AST { + typedef bool Visibility; class Pattern; class Path; class ExprNode; @@ -37,6 +38,7 @@ public: META, ITEM, + VIS, } m_type; // Owned type-pruned pointer @@ -53,6 +55,7 @@ public: InterpolatedFragment(::AST::Named ); ~InterpolatedFragment(); InterpolatedFragment(Type , ::AST::ExprNode*); + InterpolatedFragment(AST::Visibility); // :vis TokenTree& as_tt() { assert(m_type == TT); return *reinterpret_cast(m_ptr); } const TokenTree& as_tt() const { assert(m_type == TT); return *reinterpret_cast(m_ptr); } diff --git a/src/parse/parseerror.cpp b/src/parse/parseerror.cpp index 1bb30985..f2a5343b 100644 --- a/src/parse/parseerror.cpp +++ b/src/parse/parseerror.cpp @@ -61,7 +61,7 @@ ParseError::Unexpected::Unexpected(const TokenStream& lex, const Token& tok)//: Span pos = tok.get_pos(); if(pos.filename == "") pos = lex.point_span(); - ::std::cout << pos << ": Unexpected(" << tok << ")" << ::std::endl; + ERROR(pos, E0000, "Unexpected token " << tok); } ParseError::Unexpected::Unexpected(const TokenStream& lex, const Token& tok, Token exp)//: // m_tok( mv$(tok) ) @@ -69,22 +69,22 @@ ParseError::Unexpected::Unexpected(const TokenStream& lex, const Token& tok, Tok Span pos = tok.get_pos(); if(pos.filename == "") pos = lex.point_span(); - ::std::cout << pos << ": Unexpected(" << tok << ", " << exp << ")" << ::std::endl; + ERROR(pos, E0000, "Unexpected token " << tok << ", expected " << exp); } ParseError::Unexpected::Unexpected(const TokenStream& lex, const Token& tok, ::std::vector exp) { Span pos = tok.get_pos(); if(pos.filename == "") pos = lex.point_span(); - ::std::cout << pos << ": Unexpected " << tok << ", expected "; - bool f = true; - for(auto v: exp) { - if(!f) - ::std::cout << " or "; - f = false; - ::std::cout << Token::typestr(v); - } - ::std::cout << ::std::endl; + ERROR(pos, E0000, "Unexpected token " << tok << ", expected one of " << FMT_CB(os, { + bool f = true; + for(auto v: exp) { + if(!f) + os << " or "; + f = false; + os << Token::typestr(v); + } + })); } ParseError::Unexpected::~Unexpected() throw() { diff --git a/src/parse/root.cpp b/src/parse/root.cpp index ef1fb439..61218326 100644 --- a/src/parse/root.cpp +++ b/src/parse/root.cpp @@ -49,9 +49,14 @@ void Parse_ModRoot(TokenStream& lex, AST::Module& mod, AST::AttributeList& mod_a bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv); //::AST::Path Parse_Publicity(TokenStream& lex) -bool Parse_Publicity(TokenStream& lex, bool allow_restricted=true) +::AST::Visibility Parse_Publicity(TokenStream& lex, bool allow_restricted/*=true*/) { Token tok; + if( LOOK_AHEAD(lex) == TOK_INTERPOLATED_VIS ) + { + GET_TOK(tok, lex); + return tok.take_frag_vis(); + } if( LOOK_AHEAD(lex) == TOK_RWORD_PUB ) { GET_TOK(tok, lex); diff --git a/src/parse/token.cpp b/src/parse/token.cpp index f1471453..f9c168e8 100644 --- a/src/parse/token.cpp +++ b/src/parse/token.cpp @@ -35,6 +35,9 @@ Token::~Token() case TOK_INTERPOLATED_META: delete reinterpret_cast(m_data.as_Fragment()); break; + case TOK_INTERPOLATED_VIS: + delete reinterpret_cast(m_data.as_Fragment()); + break; default: break; } @@ -68,7 +71,12 @@ Token::Token(const InterpolatedFragment& frag) { switch(frag.m_type) { - case InterpolatedFragment::TT: throw ""; + case InterpolatedFragment::TT: + throw ""; + case InterpolatedFragment::VIS: + m_type = TOK_INTERPOLATED_VIS; + m_data = new AST::Visibility( *reinterpret_cast(frag.m_ptr) ); + break; case InterpolatedFragment::TYPE: m_type = TOK_INTERPOLATED_TYPE; m_data = new TypeRef( reinterpret_cast(frag.m_ptr)->clone() ); @@ -106,7 +114,12 @@ Token::Token(TagTakeIP, InterpolatedFragment frag) { switch(frag.m_type) { - case InterpolatedFragment::TT: throw ""; + case InterpolatedFragment::TT: + throw ""; + case InterpolatedFragment::VIS: + m_type = TOK_INTERPOLATED_VIS; + m_data = new AST::Visibility( mv$(*reinterpret_cast(frag.m_ptr)) ); + break; case InterpolatedFragment::TYPE: m_type = TOK_INTERPOLATED_TYPE; m_data = new TypeRef( mv$(*reinterpret_cast(frag.m_ptr)) ); @@ -228,6 +241,15 @@ Token Token::clone() const delete ptr; return mv$(rv); } +::AST::Visibility Token::take_frag_vis() +{ + assert( m_type == TOK_INTERPOLATED_VIS ); + auto ptr = reinterpret_cast(m_data.as_Fragment()); + m_data.as_Fragment() = nullptr; + auto rv = mv$( *ptr ); + delete ptr; + return mv$(rv); +} const char* Token::typestr(enum eTokenType type) { @@ -309,6 +331,7 @@ struct EscapedString { case TOK_INTERPOLATED_META: return "/*:meta*/"; case TOK_INTERPOLATED_ITEM: return "/*:item*/"; case TOK_INTERPOLATED_IDENT: return "/*:ident*/"; + case TOK_INTERPOLATED_VIS: return "/*:vis*/"; // Value tokens case TOK_IDENT: return m_data.as_String(); case TOK_LIFETIME: return "'" + m_data.as_String(); diff --git a/src/parse/token.hpp b/src/parse/token.hpp index 3605679b..d5e7a6db 100644 --- a/src/parse/token.hpp +++ b/src/parse/token.hpp @@ -44,6 +44,7 @@ extern ::std::ostream& operator<<(::std::ostream& os, const Position& p); class TypeRef; class TokenTree; namespace AST { + typedef bool Visibility; class Pattern; class Path; class ExprNode; @@ -120,12 +121,14 @@ public: uint64_t intval() const { return m_data.as_Integer().m_intval; } double floatval() const { return m_data.as_Float().m_floatval; } + // TODO: Replace these with a way of getting a InterpolatedFragment& TypeRef& frag_type() { assert(m_type == TOK_INTERPOLATED_TYPE); return *reinterpret_cast( m_data.as_Fragment() ); } AST::Path& frag_path() { assert(m_type == TOK_INTERPOLATED_PATH); return *reinterpret_cast( m_data.as_Fragment() ); } AST::Pattern& frag_pattern() { assert(m_type == TOK_INTERPOLATED_PATTERN); return *reinterpret_cast( m_data.as_Fragment() ); } AST::Attribute& frag_meta() { assert(m_type == TOK_INTERPOLATED_META); return *reinterpret_cast( m_data.as_Fragment() ); } ::std::unique_ptr take_frag_node(); ::AST::Named take_frag_item(); + ::AST::Visibility take_frag_vis(); bool operator==(const Token& r) const { if(type() != r.type()) diff --git a/src/parse/types.cpp b/src/parse/types.cpp index db66a77e..bbcff489 100644 --- a/src/parse/types.cpp +++ b/src/parse/types.cpp @@ -87,7 +87,15 @@ TypeRef Parse_Type_Int(TokenStream& lex, bool allow_trait_list) } if( TARGETVER_1_29 && tok.str() == "dyn" ) { - return Parse_Type_TraitObject(lex, {}); + if( lex.lookahead(0) == TOK_PAREN_OPEN ) { + GET_TOK(tok, lex); + auto rv = Parse_Type_TraitObject(lex, {}); + GET_CHECK_TOK(tok, lex, TOK_PAREN_CLOSE); + return rv; + } + else { + return Parse_Type_TraitObject(lex, {}); + } } // or a primitive //if( auto ct = coretype_fromstring(tok.str()) ) -- cgit v1.2.3 From 4b25ba4af9b3a3c62fd73d2c71e4761b021caec2 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 28 Dec 2018 09:49:32 +0800 Subject: Misc expand tweaks --- src/ast/expr.cpp | 3 ++- src/expand/crate_tags.cpp | 8 +++++++ src/expand/format_args.cpp | 58 ++++++++++++++++++++++++++++++++++------------ src/expand/lang_item.cpp | 4 ++++ src/expand/stringify.cpp | 1 + 5 files changed, 58 insertions(+), 16 deletions(-) diff --git a/src/ast/expr.cpp b/src/ast/expr.cpp index 1525ed12..5111bad6 100644 --- a/src/ast/expr.cpp +++ b/src/ast/expr.cpp @@ -358,7 +358,8 @@ NODE(ExprNode_Tuple, { }) NODE(ExprNode_NamedValue, { - os << m_path; + m_path.print_pretty(os, false); + //os << m_path; },{ return NEWNODE(ExprNode_NamedValue, AST::Path(m_path)); }) diff --git a/src/expand/crate_tags.cpp b/src/expand/crate_tags.cpp index 0e7d8447..1a2abf83 100644 --- a/src/expand/crate_tags.cpp +++ b/src/expand/crate_tags.cpp @@ -62,6 +62,14 @@ public: // TODO: Check for an existing allocator crate crate.m_lang_items.insert(::std::make_pair( "mrustc-allocator", AST::Path("",{}) )); } + + void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item&i) const override { + if( ! i.is_Function() ) { + ERROR(sp, E0000, "#[allocator] can only be put on functions and the crate - found on " << i.tag_str()); + } + // TODO: Ensure that this is an extern { fn } + // TODO: Does this need to do anything? + } }; class Decorator_PanicRuntime: public ExpandDecorator diff --git a/src/expand/format_args.cpp b/src/expand/format_args.cpp index 915af2af..fe2bdfb4 100644 --- a/src/expand/format_args.cpp +++ b/src/expand/format_args.cpp @@ -431,27 +431,18 @@ namespace { toks.push_back( mv$(t3) ); toks.push_back( mv$(t4) ); } -} -class CFormatArgsExpander: - public ExpandProcMacro -{ - ::std::unique_ptr expand(const Span& sp, const ::AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override + ::std::unique_ptr expand_format_args(const Span& sp, const ::AST::Crate& crate, TTStream& lex, bool add_newline) { Token tok; - auto lex = TTStream(sp, tt); - lex.parse_state().module = &mod; - if( ident != "" ) - ERROR(sp, E0000, "format_args! doesn't take an ident"); - - auto n = Parse_ExprVal(lex); - ASSERT_BUG(sp, n, "No expression returned"); - Expand_BareExpr(crate, mod, n); + auto format_string_node = Parse_ExprVal(lex); + ASSERT_BUG(sp, format_string_node, "No expression returned"); + Expand_BareExpr(crate, lex.parse_state().get_current_mod(), format_string_node); - auto* format_string_np = dynamic_cast(&*n); + auto* format_string_np = dynamic_cast(&*format_string_node); if( !format_string_np ) { - ERROR(sp, E0000, "format_args! requires a string literal - got " << *n); + ERROR(sp, E0000, "format_args! requires a string literal - got " << *format_string_node); } const auto& format_string_sp = format_string_np->span(); const auto& format_string = format_string_np->m_value; @@ -497,6 +488,10 @@ class CFormatArgsExpander: ::std::vector< FmtFrag> fragments; ::std::string tail; ::std::tie( fragments, tail ) = parse_format_string(format_string_sp, format_string, named_args_index, free_args.size()); + if( add_newline ) + { + tail += "\n"; + } bool is_simple = true; for(unsigned int i = 0; i < fragments.size(); i ++) @@ -719,7 +714,40 @@ class CFormatArgsExpander: return box$( TTStreamO(sp, TokenTree(Ident::Hygiene::new_scope(), mv$(toks))) ); } +} + +class CFormatArgsExpander: + public ExpandProcMacro +{ + ::std::unique_ptr expand(const Span& sp, const ::AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override + { + Token tok; + + auto lex = TTStream(sp, tt); + lex.parse_state().module = &mod; + if( ident != "" ) + ERROR(sp, E0000, "format_args! doesn't take an ident"); + + return expand_format_args(sp, crate, lex, /*add_newline=*/false); + } +}; + +class CFormatArgsNlExpander: + public ExpandProcMacro +{ + ::std::unique_ptr expand(const Span& sp, const ::AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override + { + Token tok; + + auto lex = TTStream(sp, tt); + lex.parse_state().module = &mod; + if( ident != "" ) + ERROR(sp, E0000, "format_args_nl! doesn't take an ident"); + + return expand_format_args(sp, crate, lex, /*add_newline=*/true); + } }; STATIC_MACRO("format_args", CFormatArgsExpander); +STATIC_MACRO("format_args_nl", CFormatArgsNlExpander); diff --git a/src/expand/lang_item.cpp b/src/expand/lang_item.cpp index 55bde52f..8dd481f3 100644 --- a/src/expand/lang_item.cpp +++ b/src/expand/lang_item.cpp @@ -78,6 +78,8 @@ void handle_lang_item(const Span& sp, AST::Crate& crate, const AST::Path& path, else if( name == "debug_trait" ) { /* TODO: Poke derive() with this */ } + else if( TARGETVER_1_29 && name == "termination" ) { } // 1.29 - trait used for non-() main + // Structs else if( name == "non_zero" ) { } else if( name == "phantom_data" ) { } @@ -222,6 +224,8 @@ public: // std - interestingly else if( name == "f32" ) {} else if( name == "f64" ) {} + else if( TARGETVER_1_29 && name == "f32_runtime" ) {} + else if( TARGETVER_1_29 && name == "f64_runtime" ) {} else { ERROR(sp, E0000, "Unknown lang item '" << name << "' on impl"); } diff --git a/src/expand/stringify.cpp b/src/expand/stringify.cpp index 06c65c02..b85c23c6 100644 --- a/src/expand/stringify.cpp +++ b/src/expand/stringify.cpp @@ -22,6 +22,7 @@ class CExpander: { if(!rv.empty()) rv += " "; + DEBUG(" += " << tok); rv += tok.to_str(); } -- cgit v1.2.3 From 83f59c8887adcaa3486cb64c5a78a4660223e234 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 28 Dec 2018 16:58:28 +0800 Subject: main - Fix supurrious warning when enabling debug for multiple phases --- src/main.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index a34cb76d..1af432b2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -98,7 +98,6 @@ void init_debug_list() { s = ::std::string { debug_string, end }; debug_string = end + 1; - g_debug_disable_map.erase( s ); } else { -- cgit v1.2.3 From e16796df604ba1017a19917ea94840ee8c4b0336 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 28 Dec 2018 16:58:52 +0800 Subject: Resolve - Clean up AST path bindings, one binding per namespace - This is prep work for supporting `use` of macros --- src/ast/ast.cpp | 2 +- src/ast/ast.hpp | 1 - src/ast/path.cpp | 140 ++++++++++----- src/ast/path.hpp | 122 ++++++++----- src/hir/from_ast.cpp | 71 ++++---- src/hir/from_ast_expr.cpp | 54 +++--- src/include/tagged_union.hpp | 6 +- src/resolve/absolute.cpp | 110 ++++++------ src/resolve/index.cpp | 197 +++++++++------------ src/resolve/use.cpp | 412 ++++++++++++++++++++++--------------------- 10 files changed, 600 insertions(+), 515 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index e4fe49da..b439553a 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -257,7 +257,7 @@ MacroInvocation MacroInvocation::clone() const UseStmt UseStmt::clone() const { - return UseStmt(sp, path); + return UseStmt(sp, AST::Path(path)); } void ExternBlock::add_item(Named named_item) diff --git a/src/ast/ast.hpp b/src/ast/ast.hpp index 49e2bdc6..2d802f53 100644 --- a/src/ast/ast.hpp +++ b/src/ast/ast.hpp @@ -466,7 +466,6 @@ struct UseStmt { Span sp; ::AST::Path path; - ::AST::PathBinding alt_binding; UseStmt(Span sp, Path p): sp(sp), diff --git a/src/ast/path.cpp b/src/ast/path.cpp index 6fdf1e40..0c8c4c69 100644 --- a/src/ast/path.cpp +++ b/src/ast/path.cpp @@ -17,8 +17,8 @@ namespace AST { // --- AST::PathBinding -::std::ostream& operator<<(::std::ostream& os, const PathBinding& x) { - TU_MATCH(PathBinding, (x), (i), +::std::ostream& operator<<(::std::ostream& os, const PathBinding_Type& x) { + TU_MATCHA( (x), (i), (Unbound, os << "_"; ), (Crate , os << "Crate"; ), (Module, os << "Module"; ), @@ -26,39 +26,80 @@ namespace AST { (Struct, os << "Struct"; ), (Enum, os << "Enum"; ), (Union, os << "Union"; ), + (EnumVar, os << "EnumVar(" << i.idx << ")"; ), + (TypeAlias, os << "TypeAlias";), + (TypeParameter, os << "TyParam(" << i.level << " # " << i.idx << ")"; ) + ) + return os; +} +PathBinding_Type PathBinding_Type::clone() const +{ + TU_MATCHA( (*this), (e), + (Unbound , return PathBinding_Type::make_Unbound({}); ), + (Module , return PathBinding_Type::make_Module(e); ), + (Crate , return PathBinding_Type(e); ), + (Trait , return PathBinding_Type(e); ), + (Struct , return PathBinding_Type(e); ), + (Enum , return PathBinding_Type(e); ), + (Union , return PathBinding_Type(e); ), + (TypeAlias, return PathBinding_Type::make_TypeAlias(e); ), + (EnumVar , return PathBinding_Type::make_EnumVar(e); ), + + (TypeParameter, return PathBinding_Type::make_TypeParameter(e); ) + ) + throw "BUG: Fell off the end of PathBinding_Type::clone"; +} +::std::ostream& operator<<(::std::ostream& os, const PathBinding_Value& x) { + TU_MATCHA( (x), (i), + (Unbound, os << "_"; ), + (Struct, os << "Struct"; ), (Static, os << "Static"; ), (Function, os << "Function";), (EnumVar, os << "EnumVar(" << i.idx << ")"; ), - (TypeAlias, os << "TypeAlias";), - (StructMethod, os << "StructMethod"; ), - (TraitMethod, os << "TraitMethod"; ), - - (TypeParameter, os << "TyParam(" << i.level << " # " << i.idx << ")"; ), (Variable, os << "Var(" << i.slot << ")"; ) ) return os; } -PathBinding PathBinding::clone() const +PathBinding_Value PathBinding_Value::clone() const { - TU_MATCH(::AST::PathBinding, (*this), (e), - (Unbound , return PathBinding::make_Unbound({}); ), - (Module , return PathBinding::make_Module(e); ), - (Crate , return PathBinding(e); ), - (Trait , return PathBinding(e); ), - (Struct , return PathBinding(e); ), - (Enum , return PathBinding(e); ), - (Union , return PathBinding(e); ), - (Static , return PathBinding(e); ), - (Function, return PathBinding(e); ), - (TypeAlias, return PathBinding::make_TypeAlias(e); ), - (EnumVar , return PathBinding::make_EnumVar(e); ), - (StructMethod, return PathBinding::make_StructMethod(e); ), - (TraitMethod, return PathBinding::make_TraitMethod(e); ), - - (TypeParameter, return PathBinding::make_TypeParameter(e); ), - (Variable, return PathBinding::make_Variable(e); ) + TU_MATCHA( (*this), (e), + (Unbound , return PathBinding_Value::make_Unbound({}); ), + (Struct , return PathBinding_Value(e); ), + (Static , return PathBinding_Value(e); ), + (Function, return PathBinding_Value(e); ), + (EnumVar , return PathBinding_Value::make_EnumVar(e); ), + (Variable, return PathBinding_Value::make_Variable(e); ) ) - throw "BUG: Fell off the end of PathBinding::clone"; + throw "BUG: Fell off the end of PathBinding_Value::clone"; +} +::std::ostream& operator<<(::std::ostream& os, const PathBinding_Macro& x) { + TU_MATCHA( (x), (i), + (Unbound, os << "_"; ), + (ProcMacroDerive, + os << "ProcMacroDerive(? " << i.mac_name << ")"; + ), + (ProcMacroAttribute, + os << "ProcMacroAttribute(? " << i.mac_name << ")"; + ), + (ProcMacro, + os << "ProcMacro(? " << i.mac_name << ")"; + ), + (MacroRules, + os << "MacroRules(? ?)"; + ) + ) + return os; +} +PathBinding_Macro PathBinding_Macro::clone() const +{ + TU_MATCHA( (*this), (e), + (Unbound , return PathBinding_Macro::make_Unbound({}); ), + (ProcMacroDerive, return PathBinding_Macro(e); ), + (ProcMacroAttribute, return PathBinding_Macro(e); ), + (ProcMacro, return PathBinding_Macro(e); ), + (MacroRules, return PathBinding_Macro(e); ) + ) + throw "BUG: Fell off the end of PathBinding_Macro::clone"; } ::std::ostream& operator<<(::std::ostream& os, const PathParams& x) @@ -159,8 +200,10 @@ AST::Path::Path(TagUfcs, TypeRef type, Path trait, ::std::vector } AST::Path::Path(const Path& x): m_class() - //m_binding(x.m_binding) + //,m_bindings(x.m_bindings) { + memcpy(&m_bindings, &x.m_bindings, sizeof(Bindings)); + TU_MATCH(Class, (x.m_class), (ent), (Invalid, m_class = Class::make_Invalid({});), (Local, @@ -185,15 +228,13 @@ AST::Path::Path(const Path& x): m_class = Class::make_UFCS({ box$(ent.type->clone()), nullptr, ent.nodes }); ) ) - - memcpy(&m_binding, &x.m_binding, sizeof(PathBinding)); } void Path::bind_variable(unsigned int slot) { - m_binding = PathBinding::make_Variable({slot}); + m_bindings.value = PathBinding_Value::make_Variable({slot}); } -void Path::bind_enum_var(const Enum& ent, const ::std::string& name, const ::std::vector& /*args*/) +void Path::bind_enum_var(const Enum& ent, const ::std::string& name) { auto it = ::std::find_if(ent.variants().begin(), ent.variants().end(), [&](const auto& x) { return x.m_name == name; }); if( it == ent.variants().end() ) @@ -203,10 +244,8 @@ void Path::bind_enum_var(const Enum& ent, const ::std::string& name, const ::std unsigned int idx = it - ent.variants().begin(); DEBUG("Bound to enum variant '" << name << "' (#" << idx << ")"); - ::AST::PathBinding::Data_EnumVar tmp = {}; - tmp.enum_ = &ent; - tmp.idx = idx; - m_binding = PathBinding::make_EnumVar( mv$(tmp) ); + m_bindings.type = PathBinding_Type::make_EnumVar({ &ent, idx }); + m_bindings.value = PathBinding_Value::make_EnumVar({ &ent, idx }); } Path& Path::operator+=(const Path& other) @@ -214,7 +253,7 @@ Path& Path::operator+=(const Path& other) for(auto& node : other.nodes()) append(node); // If the path is modified, clear the binding - m_binding = PathBinding(); + m_bindings = Bindings(); return *this; } @@ -268,13 +307,13 @@ void Path::print_pretty(::std::ostream& os, bool is_type_context, bool is_debug) ), (Local, // Only print comment if there's no binding - if( m_binding.is_Unbound() ) + if( m_bindings.value.is_Unbound() ) { if( is_debug ) os << "/*var*/"; } else - assert( m_binding.is_Variable() ); + assert( m_bindings.value.is_Variable() ); os << ent.name; ), (Relative, @@ -334,8 +373,29 @@ void Path::print_pretty(::std::ostream& os, bool is_type_context, bool is_debug) } ) ) - if( is_debug ) - os << "/*" << m_binding << "*/"; + if( is_debug ) { + os << "/*"; + bool printed = false; + if( !m_bindings.value.is_Unbound() ) { + if(printed) os << ","; + os << "v:" << m_bindings.value; + printed = true; + } + if( !m_bindings.type.is_Unbound() ) { + if(printed) os << ","; + os << "t:" << m_bindings.type; + printed = true; + } + if( !m_bindings.macro.is_Unbound() ) { + if(printed) os << ","; + os << "m:" << m_bindings.macro; + printed = true; + } + if( !printed ) { + os << "?"; + } + os << "*/"; + } } ::std::ostream& operator<<(::std::ostream& os, const Path& path) diff --git a/src/ast/path.hpp b/src/ast/path.hpp index 2693a070..b1453f04 100644 --- a/src/ast/path.hpp +++ b/src/ast/path.hpp @@ -45,7 +45,36 @@ class Static; class Function; class ExternCrate; -TAGGED_UNION_EX(PathBinding, (), Unbound, ( +TAGGED_UNION_EX(PathBinding_Value, (), Unbound, ( + (Unbound, struct { + }), + (Struct, struct { + const Struct* struct_; + const ::HIR::Struct* hir; + }), + (Static, struct { + const Static* static_; + const ::HIR::Static* hir; // if nullptr and static_ == nullptr, points to a `const` + }), + (Function, struct { + const Function* func_; + }), + (EnumVar, struct { + const Enum* enum_; + unsigned int idx; + const ::HIR::Enum* hir; + }), + (Variable, struct { + unsigned int slot; + }) + ), + (), (), + ( + public: + PathBinding_Value clone() const; + ) + ); +TAGGED_UNION_EX(PathBinding_Type, (), Unbound, ( (Unbound, struct { }), (Crate, struct { @@ -71,13 +100,7 @@ TAGGED_UNION_EX(PathBinding, (), Unbound, ( const Trait* trait_; const ::HIR::Trait* hir; }), - (Static, struct { - const Static* static_; - const ::HIR::Static* hir; // if nullptr and static_ == nullptr, points to a `const` - }), - (Function, struct { - const Function* func_; - }), + (EnumVar, struct { const Enum* enum_; unsigned int idx; @@ -86,31 +109,48 @@ TAGGED_UNION_EX(PathBinding, (), Unbound, ( (TypeAlias, struct { const TypeAlias* alias_; }), - (StructMethod, struct { - const Struct* struct_; - ::std::string name; - }), - (TraitMethod, struct { - const Trait* trait_; - ::std::string name; - }), (TypeParameter, struct { unsigned int level; unsigned int idx; + }) + ), + (), (), + ( + public: + PathBinding_Type clone() const; + ) + ); +TAGGED_UNION_EX(PathBinding_Macro, (), Unbound, ( + (Unbound, struct { }), - (Variable, struct { - unsigned int slot; + (ProcMacroDerive, struct { + const ExternCrate* crate_; + ::std::string mac_name; + }), + (ProcMacroAttribute, struct { + const ExternCrate* crate_; + ::std::string mac_name; + }), + (ProcMacro, struct { + const ExternCrate* crate_; + ::std::string mac_name; + }), + (MacroRules, struct { + const ExternCrate* crate_; // Can be NULL + //const MacroRules* mac; }) ), (), (), ( public: - PathBinding clone() const; + PathBinding_Macro clone() const; ) ); -extern ::std::ostream& operator<<(::std::ostream& os, const PathBinding& x); +extern ::std::ostream& operator<<(::std::ostream& os, const PathBinding_Value& x); +extern ::std::ostream& operator<<(::std::ostream& os, const PathBinding_Type& x); +extern ::std::ostream& operator<<(::std::ostream& os, const PathBinding_Macro& x); struct PathParams { @@ -191,23 +231,30 @@ public: public: Class m_class; -private: - PathBinding m_binding; -public: + struct Bindings { + PathBinding_Value value; + PathBinding_Type type; + PathBinding_Macro macro; + + Bindings clone() const { + return Bindings { + value.clone(), type.clone(), macro.clone() + }; + } + bool has_binding() const { + return !value.is_Unbound() || !type.is_Unbound() || !macro.is_Unbound(); + } + } m_bindings; + virtual ~Path(); // INVALID Path(): m_class() {} Path(Path&&) = default; - Path& operator=(AST::Path&& x) { - m_class = mv$(x.m_class); - m_binding = mv$(x.m_binding); - //DEBUG("Path, " << x); - return *this; - } + Path& operator=(AST::Path&& x) = default; - Path(const Path& x); + /*explicit*/ Path(const Path& x); Path& operator=(const AST::Path&) = delete; // ABSOLUTE @@ -281,7 +328,7 @@ public: //if( m_class.is_Invalid() ) // m_class = Class::make_Relative({}); nodes().push_back( mv$(node) ); - m_binding = PathBinding(); + m_bindings = Bindings(); } bool is_trivial() const { @@ -318,8 +365,6 @@ public: bool is_concrete() const; - bool is_bound() const { return !m_binding.is_Unbound(); } - const PathBinding& binding() const { return m_binding; } void bind_variable(unsigned int slot); ::std::vector& nodes() { @@ -353,14 +398,9 @@ private: void check_param_counts(const GenericParams& params, bool expect_params, PathNode& node); public: - void bind_enum_var(const Enum& ent, const ::std::string& name, const ::std::vector& args={}); - void bind_function(const Function& ent, const ::std::vector& args={}) { - (void)args; - m_binding = PathBinding::make_Function({&ent}); - } - - void bind(::AST::PathBinding pb) { - m_binding = mv$(pb); + void bind_enum_var(const Enum& ent, const ::std::string& name); + void bind_function(const Function& ent) { + m_bindings.value = PathBinding_Value::make_Function({&ent}); } }; diff --git a/src/hir/from_ast.cpp b/src/hir/from_ast.cpp index 1079e981..f62d097a 100644 --- a/src/hir/from_ast.cpp +++ b/src/hir/from_ast.cpp @@ -214,11 +214,10 @@ const ::AST::Crate* g_ast_crate_ptr; (StructTuple, unsigned int leading_count = e.tup_pat.start.size(); unsigned int trailing_count = e.tup_pat.end .size(); - TU_MATCH_DEF(::AST::PathBinding, (e.path.binding()), (pb), - ( + TU_MATCH_HDRA( (e.path.m_bindings.value), {) + default: BUG(pat.span(), "Encountered StructTuple pattern not pointing to a enum variant or a struct - " << e.path); - ), - (EnumVar, + TU_ARMA(EnumVar, pb) { assert( pb.enum_ || pb.hir ); unsigned int field_count; if( pb.enum_ ) { @@ -268,8 +267,8 @@ const ::AST::Crate* g_ast_crate_ptr; mv$(sub_patterns) }) }; - ), - (Struct, + } + TU_ARMA(Struct, pb) { assert( pb.struct_ || pb.hir ); unsigned int field_count; if( pb.struct_ ) { @@ -317,8 +316,8 @@ const ::AST::Crate* g_ast_crate_ptr; mv$(sub_patterns) }) }; - ) - ) + } + } ), (Struct, ::std::vector< ::std::pair< ::std::string, ::HIR::Pattern> > sub_patterns; @@ -326,11 +325,10 @@ const ::AST::Crate* g_ast_crate_ptr; sub_patterns.push_back( ::std::make_pair(sp.first, LowerHIR_Pattern(sp.second)) ); - TU_MATCH_DEF(::AST::PathBinding, (e.path.binding()), (pb), - ( + TU_MATCH_HDRA( (e.path.m_bindings.type), {) + default: BUG(pat.span(), "Encountered Struct pattern not pointing to a enum variant or a struct - " << e.path); - ), - (EnumVar, + TU_ARMA(EnumVar, pb) { return ::HIR::Pattern { mv$(binding), ::HIR::Pattern::Data::make_EnumStruct({ @@ -340,8 +338,8 @@ const ::AST::Crate* g_ast_crate_ptr; e.is_exhaustive }) }; - ), - (TypeAlias, + } + TU_ARMA(TypeAlias, pb) { return ::HIR::Pattern { mv$(binding), ::HIR::Pattern::Data::make_Struct({ @@ -351,8 +349,8 @@ const ::AST::Crate* g_ast_crate_ptr; e.is_exhaustive }) }; - ), - (Struct, + } + TU_ARMA(Struct, pb) { return ::HIR::Pattern { mv$(binding), ::HIR::Pattern::Data::make_Struct({ @@ -362,8 +360,8 @@ const ::AST::Crate* g_ast_crate_ptr; e.is_exhaustive }) }; - ) - ) + } + } ), (Value, @@ -750,9 +748,9 @@ const ::AST::Crate* g_ast_crate_ptr; TU_IFLET(::AST::Path::Class, e.path.m_class, Local, l, unsigned int slot; // NOTE: TypeParameter is unused - TU_IFLET(::AST::PathBinding, e.path.binding(), Variable, p, - slot = p.slot; - ) + if( const auto* p = e.path.m_bindings.value.opt_Variable() ) { + slot = p->slot; + } else { BUG(ty.span(), "Unbound local encountered in " << e.path); } @@ -768,7 +766,7 @@ const ::AST::Crate* g_ast_crate_ptr; for(const auto& t : e.traits) { DEBUG("t = " << t.path); - const auto& tb = t.path.binding().as_Trait(); + const auto& tb = t.path.m_bindings.type.as_Trait(); assert( tb.trait_ || tb.hir ); if( (tb.trait_ ? tb.trait_->is_marker() : tb.hir->m_is_marker) ) { @@ -1361,7 +1359,7 @@ void _add_mod_val_item(::HIR::Module& mod, ::std::string name, bool is_pub, ::H // Populate trait list for(const auto& item : ast_mod.m_type_items) { - if( item.second.path.binding().is_Trait() ) { + if( item.second.path.m_bindings.type.is_Trait() ) { auto sp = LowerHIR_SimplePath(Span(), item.second.path); if( ::std::find(mod.m_traits.begin(), mod.m_traits.end(), sp) == mod.m_traits.end() ) mod.m_traits.push_back( mv$(sp) ); @@ -1500,16 +1498,14 @@ void _add_mod_val_item(::HIR::Module& mod, ::std::string name, bool is_pub, ::H if( ie.second.is_import ) { auto hir_path = LowerHIR_SimplePath( sp, ie.second.path ); ::HIR::TypeItem ti; - TU_MATCH_DEF( ::AST::PathBinding, (ie.second.path.binding()), (pb), - ( + if( const auto* pb = ie.second.path.m_bindings.type.opt_EnumVar() ) { + DEBUG("Import NS " << ie.first << " = " << hir_path << " (Enum Variant)"); + ti = ::HIR::TypeItem::make_Import({ mv$(hir_path), true, pb->idx }); + } + else { DEBUG("Import NS " << ie.first << " = " << hir_path); ti = ::HIR::TypeItem::make_Import({ mv$(hir_path), false, 0 }); - ), - (EnumVar, - DEBUG("Import NS " << ie.first << " = " << hir_path << " (Enum Variant)"); - ti = ::HIR::TypeItem::make_Import({ mv$(hir_path), true, pb.idx }); - ) - ) + } _add_mod_ns_item(mod, ie.first, ie.second.is_pub, mv$(ti)); } } @@ -1520,16 +1516,15 @@ void _add_mod_val_item(::HIR::Module& mod, ::std::string name, bool is_pub, ::H auto hir_path = LowerHIR_SimplePath( sp, ie.second.path ); ::HIR::ValueItem vi; - TU_MATCH_DEF( ::AST::PathBinding, (ie.second.path.binding()), (pb), - ( + TU_MATCH_HDRA( (ie.second.path.m_bindings.value), {) + default: DEBUG("Import VAL " << ie.first << " = " << hir_path); vi = ::HIR::ValueItem::make_Import({ mv$(hir_path), false, 0 }); - ), - (EnumVar, + TU_ARMA(EnumVar, pb) { DEBUG("Import VAL " << ie.first << " = " << hir_path << " (Enum Variant)"); vi = ::HIR::ValueItem::make_Import({ mv$(hir_path), true, pb.idx }); - ) - ) + } + } _add_mod_val_item(mod, ie.first, ie.second.is_pub, mv$(vi)); } } @@ -1566,7 +1561,7 @@ void LowerHIR_Module_Impls(const ::AST::Module& ast_mod, ::HIR::Crate& hir_crat if( impl.def().trait().ent.is_valid() ) { - const auto& pb = impl.def().trait().ent.binding(); + const auto& pb = impl.def().trait().ent.m_bindings.type; ASSERT_BUG(Span(), pb.is_Trait(), "Binding for trait path in impl isn't a Trait - " << impl.def().trait().ent); ASSERT_BUG(Span(), pb.as_Trait().trait_ || pb.as_Trait().hir, "Trait pointer for trait path in impl isn't set"); bool is_marker = (pb.as_Trait().trait_ ? pb.as_Trait().trait_->is_marker() : pb.as_Trait().hir->m_is_marker); diff --git a/src/hir/from_ast_expr.cpp b/src/hir/from_ast_expr.cpp index 6daf49c3..cc642482 100644 --- a/src/hir/from_ast_expr.cpp +++ b/src/hir/from_ast_expr.cpp @@ -211,22 +211,22 @@ struct LowerHIR_ExprNode_Visitor: TU_IFLET(::AST::Path::Class, v.m_path.m_class, Local, e, m_rv.reset( new ::HIR::ExprNode_CallValue( v.span(), - ::HIR::ExprNodeP(new ::HIR::ExprNode_Variable( v.span(), e.name, v.m_path.binding().as_Variable().slot )), + ::HIR::ExprNodeP(new ::HIR::ExprNode_Variable( v.span(), e.name, v.m_path.m_bindings.value.as_Variable().slot )), mv$(args) ) ); ) else { - TU_MATCH_DEF(::AST::PathBinding, (v.m_path.binding()), (e), + TU_MATCH_DEF(::AST::PathBinding_Value, (v.m_path.m_bindings.value), (e), ( m_rv.reset( new ::HIR::ExprNode_CallPath( v.span(), LowerHIR_Path(v.span(), v.m_path), mv$( args ) ) ); ), - (TypeAlias, - TODO(v.span(), "CallPath -> TupleVariant TypeAlias"); - ), + //(TypeAlias, + // TODO(v.span(), "CallPath -> TupleVariant TypeAlias"); + // ), (EnumVar, m_rv.reset( new ::HIR::ExprNode_TupleVariant( v.span(), LowerHIR_GenericPath(v.span(), v.m_path), false, @@ -508,7 +508,7 @@ struct LowerHIR_ExprNode_Visitor: ) ); } virtual void visit(::AST::ExprNode_StructLiteral& v) override { - if( v.m_path.binding().is_Union() ) + if( v.m_path.m_bindings.type.is_Union() ) { if( v.m_values.size() != 1 ) ERROR(v.span(), E0000, "Union constructors can only specify a single field"); @@ -528,7 +528,7 @@ struct LowerHIR_ExprNode_Visitor: values.push_back( ::std::make_pair(val.name, LowerHIR_ExprNode_Inner(*val.value)) ); m_rv.reset( new ::HIR::ExprNode_StructLiteral( v.span(), LowerHIR_GenericPath(v.span(), v.m_path), - ! v.m_path.binding().is_EnumVar(), + ! v.m_path.m_bindings.type.is_EnumVar(), LowerHIR_ExprNode_Inner_Opt(v.m_base_value.get()), mv$(values) ) ); @@ -559,22 +559,14 @@ struct LowerHIR_ExprNode_Visitor: } virtual void visit(::AST::ExprNode_NamedValue& v) override { TU_IFLET(::AST::Path::Class, v.m_path.m_class, Local, e, - if( !v.m_path.binding().is_Variable() ) { - BUG(v.span(), "Named value was a local, but wasn't bound - " << v.m_path); - } - auto slot = v.m_path.binding().as_Variable().slot; + ASSERT_BUG(v.span(), v.m_path.m_bindings.value.is_Variable(), "Named value was a local, but wasn't bound - " << v.m_path); + auto slot = v.m_path.m_bindings.value.as_Variable().slot; m_rv.reset( new ::HIR::ExprNode_Variable( v.span(), e.name, slot ) ); ) - else { - TU_MATCH_DEF(::AST::PathBinding, (v.m_path.binding()), (e), - ( - auto p = LowerHIR_Path(v.span(), v.m_path); - if( p.m_data.is_Generic() ) { - BUG(v.span(), "Unknown binding for PathValue but path is generic - " << v.m_path); - } - m_rv.reset( new ::HIR::ExprNode_PathValue( v.span(), mv$(p), ::HIR::ExprNode_PathValue::UNKNOWN ) ); - ), - (Struct, + else + { + TU_MATCH_HDRA( (v.m_path.m_bindings.value), {) + TU_ARMA(Struct, e) { ASSERT_BUG(v.span(), e.struct_ || e.hir, "PathValue bound to a struct but pointer not set - " << v.m_path); // Check the form and emit a PathValue if not a unit bool is_tuple_constructor = false; @@ -604,8 +596,8 @@ struct LowerHIR_ExprNode_Visitor: else { m_rv.reset( new ::HIR::ExprNode_UnitVariant( v.span(), LowerHIR_GenericPath(v.span(), v.m_path), true ) ); } - ), - (EnumVar, + } + TU_ARMA(EnumVar, e) { ASSERT_BUG(v.span(), e.enum_ || e.hir, "PathValue bound to an enum but pointer not set - " << v.m_path); const auto& var_name = v.m_path.nodes().back().name(); bool is_tuple_constructor = false; @@ -646,11 +638,11 @@ struct LowerHIR_ExprNode_Visitor: else { m_rv.reset( new ::HIR::ExprNode_UnitVariant( v.span(), LowerHIR_GenericPath(v.span(), v.m_path), false ) ); } - ), - (Function, + } + TU_ARMA(Function, e) { m_rv.reset( new ::HIR::ExprNode_PathValue( v.span(), LowerHIR_Path(v.span(), v.m_path), ::HIR::ExprNode_PathValue::FUNCTION ) ); - ), - (Static, + } + TU_ARMA(Static, e) { if( e.static_ ) { if( e.static_->s_class() != ::AST::Static::CONST ) { @@ -669,8 +661,12 @@ struct LowerHIR_ExprNode_Visitor: { m_rv.reset( new ::HIR::ExprNode_PathValue( v.span(), LowerHIR_Path(v.span(), v.m_path), ::HIR::ExprNode_PathValue::CONSTANT ) ); } - ) - ) + } + break; default: + auto p = LowerHIR_Path(v.span(), v.m_path); + ASSERT_BUG(v.span(), !p.m_data.is_Generic(), "Unknown binding for PathValue but path is generic - " << v.m_path); + m_rv.reset( new ::HIR::ExprNode_PathValue( v.span(), mv$(p), ::HIR::ExprNode_PathValue::UNKNOWN ) ); + } } } diff --git a/src/include/tagged_union.hpp b/src/include/tagged_union.hpp index 12e39fc8..d249de13 100644 --- a/src/include/tagged_union.hpp +++ b/src/include/tagged_union.hpp @@ -118,10 +118,14 @@ #define TU_MATCH_HDR(VARS, brace) TU_MATCH_HDR_(::std::remove_reference::type, VARS, brace) #define TU_MATCH_HDR_(CLASS, VARS, brace) switch( (TU_FIRST VARS).tag() ) brace case CLASS::TAGDEAD: assert(!"ERROR: destructed tagged union used"); - // Evil hack: two for loops, the inner stops the outer after it's done. #define TU_ARM(VAR, TAG, NAME) break; case ::std::remove_reference::type::TAG_##TAG: for(bool tu_lc = true; tu_lc; tu_lc=false) for(auto& NAME = (VAR).as_##TAG(); (void)NAME, tu_lc; tu_lc=false) +#define TU_MATCH_HDRA(VARS, brace) TU_MATCH_HDRA_(::std::remove_reference::type, VARS, brace) +#define TU_MATCH_HDRA_(CLASS, VARS, brace) const auto& tu_match_hdr2_v = (TU_FIRST VARS); switch( tu_match_hdr2_v.tag() ) brace case CLASS::TAGDEAD: assert(!"ERROR: destructed tagged union used"); +// Evil hack: two for loops, the inner stops the outer after it's done. +#define TU_ARMA(TAG, NAME) break; case ::std::remove_reference::type::TAG_##TAG: for(bool tu_lc = true; tu_lc; tu_lc=false) for(auto& NAME = tu_match_hdr2_v.as_##TAG(); (void)NAME, tu_lc; tu_lc=false) + //#define TU_TEST(VAL, ...) (VAL.is_##TAG() && VAL.as_##TAG() TEST) #define TU_TEST1(VAL, TAG1, TEST) (VAL.is_##TAG1() && VAL.as_##TAG1() TEST) #define TU_TEST2(VAL, TAG1, FLD1,TAG2, TEST) (VAL.is_##TAG1() && VAL.as_##TAG1() FLD1.is_##TAG2() && VAL.as_##TAG1() FLD1.as_##TAG2() TEST) diff --git a/src/resolve/absolute.cpp b/src/resolve/absolute.cpp index 19da5820..d0db3c13 100644 --- a/src/resolve/absolute.cpp +++ b/src/resolve/absolute.cpp @@ -313,6 +313,7 @@ namespace { auto v = mod.m_namespace_items.find(name); if( v != mod.m_namespace_items.end() ) { + DEBUG("- NS: Namespace " << v->second.path); path = ::AST::Path( v->second.path ); return true; } @@ -320,6 +321,7 @@ namespace { auto v = mod.m_type_items.find(name); if( v != mod.m_type_items.end() ) { + DEBUG("- NS: Type " << v->second.path); path = ::AST::Path( v->second.path ); return true; } @@ -327,15 +329,10 @@ namespace break; case LookupMode::Type: - //if( name == "IntoIterator" ) { - // DEBUG("lookup_in_mod(mod="<second.path); path = ::AST::Path( v->second.path ); return true; } @@ -345,14 +342,15 @@ namespace { auto v = mod.m_value_items.find(name); if( v != mod.m_value_items.end() ) { - const auto& b = v->second.path.binding(); + const auto& b = v->second.path.m_bindings.value; switch( b.tag() ) { - case ::AST::PathBinding::TAG_EnumVar: - case ::AST::PathBinding::TAG_Static: + case ::AST::PathBinding_Value::TAG_EnumVar: + case ::AST::PathBinding_Value::TAG_Static: + DEBUG("- PV: Value " << v->second.path); path = ::AST::Path( v->second.path ); return true; - case ::AST::PathBinding::TAG_Struct: + case ::AST::PathBinding_Value::TAG_Struct: // TODO: Restrict this to unit-like structs if( b.as_Struct().struct_ && !b.as_Struct().struct_->m_data.is_Unit() ) ; @@ -360,6 +358,7 @@ namespace ; else { + DEBUG("- PV: Value " << v->second.path); path = ::AST::Path( v->second.path ); return true; } @@ -375,6 +374,7 @@ namespace { auto v = mod.m_value_items.find(name); if( v != mod.m_value_items.end() ) { + DEBUG("- C/V: Value " << v->second.path); path = ::AST::Path( v->second.path ); return true; } @@ -592,7 +592,7 @@ void Resolve_Absolute_Path_BindUFCS(Context& context, const Span& sp, Context::L { // Trait is specified, definitely a trait item // - Must resolve here - const auto& pb = ufcs.trait->binding(); + const auto& pb = ufcs.trait->m_bindings.type; if( ! pb.is_Trait() ) { ERROR(sp, E0000, "UFCS trait was not a trait - " << *ufcs.trait); } @@ -662,7 +662,7 @@ namespace { { np.nodes().push_back( mv$(nodes[i]) ); } - np.bind( path.binding().clone() ); + np.m_bindings = path.m_bindings.clone(); return np; } AST::Path split_into_ufcs_ty(const Span& sp, AST::Path path, unsigned int i /*item_name_idx*/) @@ -716,7 +716,6 @@ namespace { const auto& varname = p.m_components.back(); auto var_idx = e.find_variant(varname); ASSERT_BUG(sp, var_idx != SIZE_MAX, "Extern crate import path points to non-present variant - " << p); - auto pb = ::AST::PathBinding::make_EnumVar({nullptr, static_cast(var_idx), &e}); // Construct output path (with same set of parameters) AST::Path rv( p.m_crate_name, {} ); @@ -724,7 +723,12 @@ namespace { for(const auto& c : p.m_components) rv.nodes().push_back( AST::PathNode(c) ); rv.nodes().back().args() = mv$( path.nodes().back().args() ); - rv.bind( mv$(pb) ); + if( e.m_data.is_Data() && e.m_data.as_Data()[var_idx].is_struct ) { + rv.m_bindings.type = ::AST::PathBinding_Type::make_EnumVar({nullptr, static_cast(var_idx), &e}); + } + else { + rv.m_bindings.value = ::AST::PathBinding_Value::make_EnumVar({nullptr, static_cast(var_idx), &e}); + } path = mv$(rv); return ; @@ -735,7 +739,7 @@ namespace { ) } - ::AST::PathBinding pb; + ::AST::Path::Bindings pb; const auto& name = p.m_components.back(); if( is_value ) @@ -749,19 +753,19 @@ namespace { BUG(sp, "HIR Import item pointed to an import"); ), (Constant, - pb = ::AST::PathBinding::make_Static({nullptr, nullptr}); + pb.value = ::AST::PathBinding_Value::make_Static({nullptr, nullptr}); ), (Static, - pb = ::AST::PathBinding::make_Static({nullptr, &e}); + pb.value = ::AST::PathBinding_Value::make_Static({nullptr, &e}); ), (StructConstant, - pb = ::AST::PathBinding::make_Struct({nullptr, &ext_crate.m_hir->get_typeitem_by_path(sp, e.ty, true).as_Struct()}); + pb.value = ::AST::PathBinding_Value::make_Struct({nullptr, &ext_crate.m_hir->get_typeitem_by_path(sp, e.ty, true).as_Struct()}); ), (Function, - pb = ::AST::PathBinding::make_Function({nullptr/*, &e*/}); + pb.value = ::AST::PathBinding_Value::make_Function({nullptr/*, &e*/}); ), (StructConstructor, - pb = ::AST::PathBinding::make_Struct({nullptr, &ext_crate.m_hir->get_typeitem_by_path(sp, e.ty, true).as_Struct()}); + pb.value = ::AST::PathBinding_Value::make_Struct({nullptr, &ext_crate.m_hir->get_typeitem_by_path(sp, e.ty, true).as_Struct()}); ) ) } @@ -776,22 +780,22 @@ namespace { BUG(sp, "HIR Import item pointed to an import"); ), (Module, - pb = ::AST::PathBinding::make_Module({nullptr, &e}); + pb.type = ::AST::PathBinding_Type::make_Module({nullptr, &e}); ), (Trait, - pb = ::AST::PathBinding::make_Trait({nullptr, &e}); + pb.type = ::AST::PathBinding_Type::make_Trait({nullptr, &e}); ), (TypeAlias, - pb = ::AST::PathBinding::make_TypeAlias({nullptr/*, &e*/}); + pb.type = ::AST::PathBinding_Type::make_TypeAlias({nullptr/*, &e*/}); ), (Struct, - pb = ::AST::PathBinding::make_Struct({nullptr, &e}); + pb.type = ::AST::PathBinding_Type::make_Struct({nullptr, &e}); ), (Union, - pb = ::AST::PathBinding::make_Union({nullptr, &e}); + pb.type = ::AST::PathBinding_Type::make_Union({nullptr, &e}); ), (Enum, - pb = ::AST::PathBinding::make_Enum({nullptr, &e}); + pb.type = ::AST::PathBinding_Type::make_Enum({nullptr, &e}); ) ) } @@ -802,7 +806,7 @@ namespace { for(const auto& c : p.m_components) rv.nodes().push_back( AST::PathNode(c) ); rv.nodes().back().args() = mv$( path.nodes().back().args() ); - rv.bind( mv$(pb) ); + rv.m_bindings = mv$(pb); path = mv$(rv); } @@ -816,7 +820,7 @@ namespace { switch(mode) { case Context::LookupMode::Namespace: - path.bind( ::AST::PathBinding::make_Module({nullptr, &crate.m_hir->m_root_module}) ); + path.m_bindings.type = ::AST::PathBinding_Type::make_Module({nullptr, &crate.m_hir->m_root_module}); return ; default: TODO(sp, "Looking up a non-namespace, but pointed to crate root"); @@ -862,7 +866,7 @@ namespace { trait_path.nodes().back().args().m_types.push_back( ::TypeRef(sp) ); } } - trait_path.bind( ::AST::PathBinding::make_Trait({nullptr, &e}) ); + trait_path.m_bindings.type = ::AST::PathBinding_Type::make_Trait({nullptr, &e}); ::AST::Path new_path; const auto& next_node = path_abs.nodes[i+1]; @@ -922,7 +926,12 @@ namespace { ERROR(sp, E0000, "Type parameters were not expected here (enum params go on the variant)"); } - path.bind( ::AST::PathBinding::make_EnumVar({nullptr, static_cast(idx), &e}) ); + if( e.m_data.is_Data() && e.m_data.as_Data()[idx].is_struct ) { + path.m_bindings.type = ::AST::PathBinding_Type::make_EnumVar({nullptr, static_cast(idx), &e}); + } + else { + path.m_bindings.value = ::AST::PathBinding_Value::make_EnumVar({nullptr, static_cast(idx), &e}); + } path = split_into_crate(sp, mv$(path), start, crate.m_name); return; } @@ -949,22 +958,22 @@ namespace { return ; ), (Trait, - path.bind( ::AST::PathBinding::make_Trait({nullptr, &e}) ); + path.m_bindings.type = ::AST::PathBinding_Type::make_Trait({nullptr, &e}); ), (Module, - path.bind( ::AST::PathBinding::make_Module({nullptr, &e}) ); + path.m_bindings.type = ::AST::PathBinding_Type::make_Module({nullptr, &e}); ), (TypeAlias, - path.bind( ::AST::PathBinding::make_TypeAlias({nullptr/*, &e*/}) ); + path.m_bindings.type = ::AST::PathBinding_Type::make_TypeAlias({nullptr/*, &e*/}); ), (Enum, - path.bind( ::AST::PathBinding::make_Enum({nullptr, &e}) ); + path.m_bindings.type = ::AST::PathBinding_Type::make_Enum({nullptr, &e}); ), (Struct, - path.bind( ::AST::PathBinding::make_Struct({nullptr, &e}) ); + path.m_bindings.type = ::AST::PathBinding_Type::make_Struct({nullptr, &e}); ), (Union, - path.bind( ::AST::PathBinding::make_Union({nullptr, &e}) ); + path.m_bindings.type = ::AST::PathBinding_Type::make_Union({nullptr, &e}); ) ) // Update path (trim down to `start` and set crate name) @@ -984,7 +993,7 @@ namespace { ), (StructConstant, auto ty_path = e.ty; - path.bind( ::AST::PathBinding::make_Struct({nullptr, &crate.m_hir->get_struct_by_path(sp, ty_path)}) ); + path.m_bindings.value = ::AST::PathBinding_Value::make_Struct({nullptr, &crate.m_hir->get_struct_by_path(sp, ty_path)}); path = split_into_crate(sp, mv$(path), start, crate.m_name); return ; ), @@ -994,7 +1003,7 @@ namespace { ), (Constant, // Bind and update path - path.bind( ::AST::PathBinding::make_Static({nullptr, nullptr}) ); + path.m_bindings.value = ::AST::PathBinding_Value::make_Static({nullptr, nullptr}); path = split_into_crate(sp, mv$(path), start, crate.m_name); return ; ) @@ -1016,22 +1025,22 @@ namespace { return ; ), (Function, - path.bind( ::AST::PathBinding::make_Function({nullptr/*, &e*/}) ); + path.m_bindings.value = ::AST::PathBinding_Value::make_Function({nullptr/*, &e*/}); ), (StructConstructor, auto ty_path = e.ty; - path.bind( ::AST::PathBinding::make_Struct({nullptr, &crate.m_hir->get_struct_by_path(sp, ty_path)}) ); + path.m_bindings.value = ::AST::PathBinding_Value::make_Struct({nullptr, &crate.m_hir->get_struct_by_path(sp, ty_path)}); ), (StructConstant, auto ty_path = e.ty; - path.bind( ::AST::PathBinding::make_Struct({nullptr, &crate.m_hir->get_struct_by_path(sp, ty_path)}) ); + path.m_bindings.value = ::AST::PathBinding_Value::make_Struct({nullptr, &crate.m_hir->get_struct_by_path(sp, ty_path)}); ), (Static, - path.bind( ::AST::PathBinding::make_Static({nullptr, &e}) ); + path.m_bindings.value = ::AST::PathBinding_Value::make_Static({nullptr, &e}); ), (Constant, // Bind - path.bind( ::AST::PathBinding::make_Static({nullptr, nullptr}) ); + path.m_bindings.value = ::AST::PathBinding_Value::make_Static({nullptr, nullptr}); ) ) path = split_into_crate(sp, mv$(path), start, crate.m_name); @@ -1088,7 +1097,7 @@ void Resolve_Absolute_Path_BindAbsolute(Context& context, const Span& sp, Contex const auto& name_ref = it->second; DEBUG("#" << i << " \"" << n.name() << "\" = " << name_ref.path << (name_ref.is_import ? " (import)" : "") ); - TU_MATCH_DEF(::AST::PathBinding, (name_ref.path.binding()), (e), + TU_MATCH_DEF(::AST::PathBinding_Type, (name_ref.path.m_bindings.type), (e), ( ERROR(sp, E0000, "Encountered non-namespace item '" << n.name() << "' ("< Instead use the type name. if( ! p.m_class.is_Local() && coretype_fromstring(e.nodes[0].name()) != CORETYPE_INVAL ) { - TU_IFLET( ::AST::PathBinding, p.binding(), Module, pe, + if( const auto* pep = p.m_bindings.type.opt_Module() ) { + const auto& pe = *pep; bool found = false; const auto& name = e.nodes[1].name(); if( !pe.module_ ) { @@ -1340,7 +1350,7 @@ void Resolve_Absolute_Path(/*const*/ Context& context, const Span& sp, Context:: } DEBUG("Primitive module hack yeilded " << p); - ) + } } if( e.nodes.size() > 1 ) @@ -1447,7 +1457,7 @@ void Resolve_Absolute_Path(/*const*/ Context& context, const Span& sp, Context:: BUG(sp, "Path wasn't absolutised correctly"); ), (Local, - if( path.binding().is_Unbound() ) + if( !path.m_bindings.has_binding() ) { TODO(sp, "Bind unbound local path - " << path); } @@ -1565,7 +1575,7 @@ void Resolve_Absolute_Type(Context& context, TypeRef& type) assert( ufcs.nodes.size() == 1); ) - TU_IFLET(::AST::PathBinding, e.path.binding(), Trait, be, + TU_IFLET(::AST::PathBinding_Type, e.path.m_bindings.type, Trait, be, auto ty = ::TypeRef( type.span(), ::make_vec1(Type_TraitPath { {}, mv$(e.path)}), {} ); type = mv$(ty); return ; @@ -2157,7 +2167,7 @@ void Resolve_Absolute_Mod( Context item_context, ::AST::Module& mod ) item_context.pop(def.params()); - const_cast< ::AST::Trait*>(def.trait().ent.binding().as_Trait().trait_)->set_is_marker(); + const_cast< ::AST::Trait*>(def.trait().ent.m_bindings.type.as_Trait().trait_)->set_is_marker(); } else { diff --git a/src/resolve/index.cpp b/src/resolve/index.cpp index 659bded4..148bf069 100644 --- a/src/resolve/index.cpp +++ b/src/resolve/index.cpp @@ -125,46 +125,47 @@ void Resolve_Index_Module_Base(const AST::Crate& crate, AST::Module& mod) ), // - Types/modules only (Module, - p.bind( ::AST::PathBinding::make_Module({&e}) ); + p.m_bindings.type = ::AST::PathBinding_Type::make_Module({&e}); _add_item(i.data.span, mod, IndexName::Namespace, i.name, i.is_pub, mv$(p)); ), (Crate, ASSERT_BUG(i.data.span, crate.m_extern_crates.count(e.name) > 0, "Referenced crate '" << e.name << "' isn't loaded for `extern crate`"); - p.bind( ::AST::PathBinding::make_Crate({ &crate.m_extern_crates.at(e.name) }) ); + p.m_bindings.type = ::AST::PathBinding_Type::make_Crate({ &crate.m_extern_crates.at(e.name) }); _add_item(i.data.span, mod, IndexName::Namespace, i.name, i.is_pub, mv$(p)); ), (Enum, - p.bind( ::AST::PathBinding::make_Enum({&e}) ); + p.m_bindings.type = ::AST::PathBinding_Type::make_Enum({&e}); _add_item_type(i.data.span, mod, i.name, i.is_pub, mv$(p)); ), (Union, - p.bind( ::AST::PathBinding::make_Union({&e}) ); + p.m_bindings.type = ::AST::PathBinding_Type::make_Union({&e}); _add_item_type(i.data.span, mod, i.name, i.is_pub, mv$(p)); ), (Trait, - p.bind( ::AST::PathBinding::make_Trait({&e}) ); + p.m_bindings.type = ::AST::PathBinding_Type::make_Trait({&e}); _add_item_type(i.data.span, mod, i.name, i.is_pub, mv$(p)); ), (Type, - p.bind( ::AST::PathBinding::make_TypeAlias({&e}) ); + p.m_bindings.type = ::AST::PathBinding_Type::make_TypeAlias({&e}); _add_item_type(i.data.span, mod, i.name, i.is_pub, mv$(p)); ), // - Mixed (Struct, - p.bind( ::AST::PathBinding::make_Struct({&e}) ); + p.m_bindings.type = ::AST::PathBinding_Type::make_Struct({&e}); // - If the struct is a tuple-like struct (or unit-like), it presents in the value namespace if( ! e.m_data.is_Struct() ) { + p.m_bindings.value = ::AST::PathBinding_Value::make_Struct({&e}); _add_item_value(i.data.span, mod, i.name, i.is_pub, p); } _add_item_type(i.data.span, mod, i.name, i.is_pub, mv$(p)); ), // - Values only (Function, - p.bind( ::AST::PathBinding::make_Function({&e}) ); + p.m_bindings.value = ::AST::PathBinding_Value::make_Function({&e}); _add_item_value(i.data.span, mod, i.name, i.is_pub, mv$(p)); ), (Static, - p.bind( ::AST::PathBinding::make_Static({&e}) ); + p.m_bindings.value = ::AST::PathBinding_Value::make_Static({&e}); _add_item_value(i.data.span, mod, i.name, i.is_pub, mv$(p)); ) ) @@ -182,73 +183,48 @@ void Resolve_Index_Module_Base(const AST::Crate& crate, AST::Module& mod) // TODO: Ensure that the path is canonical? const auto& sp = i_data.sp; - struct H { - static void handle_pb(const Span& sp, AST::Module& mod, const AST::Named& i, const AST::PathBinding& pb, bool allow_collide) - { - const auto& i_data = i.data.as_Use(); - TU_MATCH(::AST::PathBinding, (pb), (e), - (Unbound, - ), - (Variable, - BUG(sp, "Import was bound to variable"); - ), - (TypeParameter, - BUG(sp, "Import was bound to type parameter"); - ), - (TraitMethod, - BUG(sp, "Import was bound to trait method"); - ), - (StructMethod, - BUG(sp, "Import was bound to struct method"); - ), - - (Crate , _add_item(sp, mod, IndexName::Namespace, i.name, i.is_pub, i_data.path, !allow_collide); ), - (Module, _add_item(sp, mod, IndexName::Namespace, i.name, i.is_pub, i_data.path, !allow_collide); ), - (Enum, _add_item_type(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); ), - (Union, _add_item_type(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); ), - (Trait, _add_item_type(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); ), - (TypeAlias,_add_item_type(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); ), - - (Struct, - _add_item_type(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); - // - If the struct is a tuple-like struct, it presents in the value namespace - assert(e.struct_ || e.hir); - if( !(e.struct_ ? e.struct_->m_data.is_Struct() : e.hir->m_data.is_Named()) ) - { - _add_item_value(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); - } - ), - (Static , _add_item_value(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); ), - (Function, _add_item_value(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); ), - (EnumVar , - bool is_struct = false; - if( e.enum_ ) { - ASSERT_BUG(sp, e.idx < e.enum_->variants().size(), "Variant out of range for " << i_data.path); - is_struct = e.enum_->variants().at(e.idx).m_data.is_Struct(); - } - else { - //ASSERT_BUG(sp, e.idx < e.hir->m_variants.size(), "Variant out of range for " << i_data.path); - is_struct = TU_TEST1(e.hir->m_data, Data, .at(e.idx).is_struct); - } - if( is_struct ) - _add_item_type(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); - else - _add_item_value(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); - ) - ) + ASSERT_BUG(sp, i_data.path.m_bindings.has_binding(), "`use " << i_data.path << "` left unbound in module " << mod.path()); + + bool allow_collide = false; + // - Types + {TU_MATCH_HDRA( (i_data.path.m_bindings.type), {) + TU_ARMA(Unbound, _e) { + DEBUG(i.name << " - Not a type/module"); } - }; - if( i_data.path.binding().is_Unbound() ) { - BUG(sp, "`use " << i_data.path << "` left unbound in module " << mod.path()); - } - else { - H::handle_pb(sp, mod, i, i_data.path.binding(), false); - } - if( i_data.alt_binding.is_Unbound() ) { - // Doesn't matter - } - else { - H::handle_pb(sp, mod, i, i_data.alt_binding, true); + TU_ARMA(TypeParameter, e) + BUG(sp, "Import was bound to type parameter"); + TU_ARMA(Crate , e) + _add_item(sp, mod, IndexName::Namespace, i.name, i.is_pub, i_data.path, !allow_collide); + TU_ARMA(Module, e) + _add_item(sp, mod, IndexName::Namespace, i.name, i.is_pub, i_data.path, !allow_collide); + TU_ARMA(Enum, e) + _add_item_type(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); + TU_ARMA(Union, e) + _add_item_type(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); + TU_ARMA(Trait, e) + _add_item_type(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); + TU_ARMA(TypeAlias, e) + _add_item_type(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); + TU_ARMA(Struct, e) + _add_item_type(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); + TU_ARMA(EnumVar, e) + _add_item_type(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); + }} + // - Values + TU_MATCH_HDRA( (i_data.path.m_bindings.value), {) + TU_ARMA(Unbound, _e) { + DEBUG(i.name << " - Not a value"); + } + TU_ARMA(Variable, e) + BUG(sp, "Import was bound to a variable"); + TU_ARMA(Struct, e) + _add_item_value(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); + TU_ARMA(EnumVar, e) + _add_item_value(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); + TU_ARMA(Static , e) + _add_item_value(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); + TU_ARMA(Function, e) + _add_item_value(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); } } else @@ -298,22 +274,22 @@ void Resolve_Index_Module_Wildcard__glob_in_hir_mod(const Span& sp, const AST::C //throw ""; ), (Module, - p.bind( ::AST::PathBinding::make_Module({nullptr, &e}) ); + p.m_bindings.type = ::AST::PathBinding_Type::make_Module({nullptr, &e}); ), (Trait, - p.bind( ::AST::PathBinding::make_Trait({nullptr, &e}) ); + p.m_bindings.type = ::AST::PathBinding_Type::make_Trait({nullptr, &e}); ), (Struct, - p.bind( ::AST::PathBinding::make_Struct({nullptr, &e}) ); + p.m_bindings.type = ::AST::PathBinding_Type::make_Struct({nullptr, &e}); ), (Union, - p.bind( ::AST::PathBinding::make_Union({nullptr, &e}) ); + p.m_bindings.type = ::AST::PathBinding_Type::make_Union({nullptr, &e}); ), (Enum, - p.bind( ::AST::PathBinding::make_Enum({nullptr}) ); + p.m_bindings.type = ::AST::PathBinding_Type::make_Enum({nullptr}); ), (TypeAlias, - p.bind( ::AST::PathBinding::make_TypeAlias({nullptr}) ); + p.m_bindings.type = ::AST::PathBinding_Type::make_TypeAlias({nullptr}); ) ) _add_item_type( sp, dst_mod, it.first, is_pub, mv$(p), false ); @@ -333,8 +309,8 @@ void Resolve_Index_Module_Wildcard__glob_in_hir_mod(const Span& sp, const AST::C for(unsigned int i = 0; i < spath.m_components.size()-1; i ++) { const auto& it = hmod->m_mod_items.at( spath.m_components[i] ); if(it->ent.is_Enum()) { - ASSERT_BUG(sp, i + 1 == spath.m_components.size() - 1, ""); - p.bind( ::AST::PathBinding::make_EnumVar({nullptr, 0}) ); + ASSERT_BUG(sp, i + 1 == spath.m_components.size() - 1, "Found enum not at penultimate component of HIR import path"); + p.m_bindings.value = ::AST::PathBinding_Value::make_EnumVar({nullptr, 0}); // TODO: What's the index? vep = nullptr; hmod = nullptr; break ; @@ -355,20 +331,20 @@ void Resolve_Index_Module_Wildcard__glob_in_hir_mod(const Span& sp, const AST::C throw ""; ), (Constant, - p.bind( ::AST::PathBinding::make_Static({nullptr}) ); + p.m_bindings.value = ::AST::PathBinding_Value::make_Static({nullptr}); ), (Static, - p.bind( ::AST::PathBinding::make_Static({nullptr}) ); + p.m_bindings.value = ::AST::PathBinding_Value::make_Static({nullptr}); ), // TODO: What if these refer to an enum variant? (StructConstant, - p.bind( ::AST::PathBinding::make_Struct({ nullptr, &crate.m_extern_crates.at(e.ty.m_crate_name).m_hir->get_typeitem_by_path(sp, e.ty, true).as_Struct() }) ); + p.m_bindings.value = ::AST::PathBinding_Value::make_Struct({ nullptr, &crate.m_extern_crates.at(e.ty.m_crate_name).m_hir->get_typeitem_by_path(sp, e.ty, true).as_Struct() }); ), (StructConstructor, - p.bind( ::AST::PathBinding::make_Struct({ nullptr, &crate.m_extern_crates.at(e.ty.m_crate_name).m_hir->get_typeitem_by_path(sp, e.ty, true).as_Struct() }) ); + p.m_bindings.value = ::AST::PathBinding_Value::make_Struct({ nullptr, &crate.m_extern_crates.at(e.ty.m_crate_name).m_hir->get_typeitem_by_path(sp, e.ty, true).as_Struct() }); ), (Function, - p.bind( ::AST::PathBinding::make_Function({nullptr}) ); + p.m_bindings.value = ::AST::PathBinding_Value::make_Function({nullptr}); ) ) } @@ -418,14 +394,14 @@ void Resolve_Index_Module_Wildcard__submod(AST::Crate& crate, AST::Module& dst_m void Resolve_Index_Module_Wildcard__use_stmt(AST::Crate& crate, AST::Module& dst_mod, const AST::UseStmt& i_data, bool is_pub) { const auto& sp = i_data.sp; - const auto& b = i_data.path.binding(); + const auto& b = i_data.path.m_bindings.type; - TU_IFLET(::AST::PathBinding, b, Crate, e, + TU_IFLET(::AST::PathBinding_Type, b, Crate, e, DEBUG("Glob crate " << i_data.path); const auto& hmod = e.crate_->m_hir->m_root_module; Resolve_Index_Module_Wildcard__glob_in_hir_mod(sp, crate, dst_mod, hmod, i_data.path, is_pub); ) - else TU_IFLET(::AST::PathBinding, b, Module, e, + else TU_IFLET(::AST::PathBinding_Type, b, Module, e, DEBUG("Glob mod " << i_data.path); if( !e.module_ ) { @@ -438,7 +414,7 @@ void Resolve_Index_Module_Wildcard__use_stmt(AST::Crate& crate, AST::Module& dst Resolve_Index_Module_Wildcard__submod(crate, dst_mod, *e.module_, is_pub); } ) - else TU_IFLET(::AST::PathBinding, b, Enum, e, + else TU_IFLET(::AST::PathBinding_Type, b, Enum, e, ASSERT_BUG(sp, e.enum_ || e.hir, "Glob import but enum pointer not set - " << i_data.path); if( e.enum_ ) { @@ -446,11 +422,12 @@ void Resolve_Index_Module_Wildcard__use_stmt(AST::Crate& crate, AST::Module& dst unsigned int idx = 0; for( const auto& ev : e.enum_->variants() ) { ::AST::Path p = i_data.path + ev.m_name; - p.bind( ::AST::PathBinding::make_EnumVar({e.enum_, idx}) ); if( ev.m_data.is_Struct() ) { + p.m_bindings.type = ::AST::PathBinding_Type::make_EnumVar({e.enum_, idx}); _add_item_type ( sp, dst_mod, ev.m_name, is_pub, mv$(p), false ); } else { + p.m_bindings.value = ::AST::PathBinding_Value::make_EnumVar({e.enum_, idx}); _add_item_value( sp, dst_mod, ev.m_name, is_pub, mv$(p), false ); } @@ -467,7 +444,7 @@ void Resolve_Index_Module_Wildcard__use_stmt(AST::Crate& crate, AST::Module& dst for(const auto& ev : de->variants) { ::AST::Path p = i_data.path + ev.name; - p.bind( ::AST::PathBinding::make_EnumVar({nullptr, idx, e.hir}) ); + p.m_bindings.value = ::AST::PathBinding_Value::make_EnumVar({nullptr, idx, e.hir}); _add_item_value( sp, dst_mod, ev.name, is_pub, mv$(p), false ); @@ -480,12 +457,13 @@ void Resolve_Index_Module_Wildcard__use_stmt(AST::Crate& crate, AST::Module& dst for(const auto& ev : *de) { ::AST::Path p = i_data.path + ev.name; - p.bind( ::AST::PathBinding::make_EnumVar({nullptr, idx, e.hir}) ); if( ev.is_struct ) { + p.m_bindings.type = ::AST::PathBinding_Type::make_EnumVar({nullptr, idx, e.hir}); _add_item_type ( sp, dst_mod, ev.name, is_pub, mv$(p), false ); } else { + p.m_bindings.value = ::AST::PathBinding_Value::make_EnumVar({nullptr, idx, e.hir}); _add_item_value( sp, dst_mod, ev.name, is_pub, mv$(p), false ); } @@ -598,9 +576,9 @@ void Resolve_Index_Module_Normalise_Path_ext(const ::AST::Crate& crate, const Sp { TU_IFLET( ::HIR::TypeItem, it_m->second->ent, Import, e, // Replace the path with this path (maintaining binding) - auto binding = path.binding().clone(); + auto bindings = path.m_bindings.clone(); path = hir_to_ast(e.path); - path.bind( mv$(binding) ); + path.m_bindings = mv$(bindings); ) return ; } @@ -611,9 +589,9 @@ void Resolve_Index_Module_Normalise_Path_ext(const ::AST::Crate& crate, const Sp { TU_IFLET( ::HIR::ValueItem, it_v->second->ent, Import, e, // Replace the path with this path (maintaining binding) - auto binding = path.binding().clone(); + auto bindings = path.m_bindings.clone(); path = hir_to_ast(e.path); - path.bind( mv$(binding) ); + path.m_bindings = mv$(bindings); ) return ; } @@ -648,27 +626,26 @@ bool Resolve_Index_Module_Normalise_Path(const ::AST::Crate& crate, const Span& auto new_path = ie.path; for(unsigned int j = i+1; j < info.nodes.size(); j ++) new_path.nodes().push_back( mv$(info.nodes[j]) ); - new_path.bind( path.binding().clone() ); + new_path.m_bindings = path.m_bindings.clone(); path = mv$(new_path); return Resolve_Index_Module_Normalise_Path(crate, sp, path, loc); } else { - TU_MATCH_DEF(::AST::PathBinding, (ie.path.binding()), (e), - ( + TU_MATCH_HDR( (ie.path.m_bindings.type), {) + default: BUG(sp, "Path " << path << " pointed to non-module " << ie.path); - ), - (Module, + TU_ARM( ie.path.m_bindings.type, Module, e) { mod = e.module_; - ), - (Crate, + } + TU_ARM( ie.path.m_bindings.type, Crate, e) { Resolve_Index_Module_Normalise_Path_ext(crate, sp, path, loc, *e.crate_, i+1); return false; - ), - (Enum, + } + TU_ARM( ie.path.m_bindings.type, Enum, e) { // NOTE: Just assuming that if an Enum is hit, it's sane return false; - ) - ) + } + } } } diff --git a/src/resolve/use.cpp b/src/resolve/use.cpp index db942641..a0d1aa53 100644 --- a/src/resolve/use.cpp +++ b/src/resolve/use.cpp @@ -22,8 +22,8 @@ enum class Lookup ::AST::Path Resolve_Use_AbsolutisePath(const ::AST::Path& base_path, ::AST::Path path); void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path path, ::std::span< const ::AST::Module* > parent_modules={}); -::AST::PathBinding Resolve_Use_GetBinding(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path, ::std::span< const ::AST::Module* > parent_modules, Lookup allow=Lookup::Any); -::AST::PathBinding Resolve_Use_GetBinding__ext(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path, const ::HIR::Module& hmodr, unsigned int start, Lookup allow); +::AST::Path::Bindings Resolve_Use_GetBinding(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path, ::std::span< const ::AST::Module* > parent_modules); +::AST::Path::Bindings Resolve_Use_GetBinding__ext(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path, const ::HIR::Module& hmodr, unsigned int start); void Resolve_Use(::AST::Crate& crate) @@ -117,14 +117,22 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path if( !use_stmt_data.path.m_class.is_Absolute() ) BUG(span, "Use path is not absolute after absolutisation"); + // NOTE: Use statements can refer to _three_ different items + // - types/modules ("type namespace") + // - values ("value namespace") + // - macros ("macro namespace") // TODO: Have Resolve_Use_GetBinding return the actual path - use_stmt_data.path.bind( Resolve_Use_GetBinding(span, crate, use_stmt_data.path, parent_modules) ); + use_stmt_data.path.m_bindings = Resolve_Use_GetBinding(span, crate, use_stmt_data.path, parent_modules); + if( !use_stmt_data.path.m_bindings.has_binding() ) + { + ERROR(span, E0000, "Unable to resolve `use` target " << use_stmt_data.path); + } DEBUG("'" << use_stmt.name << "' = " << use_stmt_data.path); // - If doing a glob, ensure the item type is valid if( use_stmt.name == "" ) { - TU_MATCH_DEF(::AST::PathBinding, (use_stmt_data.path.binding()), (e), + TU_MATCH_DEF(::AST::PathBinding_Type, (use_stmt_data.path.m_bindings.type), (e), ( ERROR(span, E0000, "Wildcard import of invalid item type - " << use_stmt_data.path); ), @@ -138,35 +146,6 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path } else { - // TODO: Handle case where a use can resolve to two different items (one value, one type/namespace) - // - Easiest way is with an extra binding slot - Lookup allow = Lookup::Any; - switch( use_stmt_data.path.binding().tag() ) - { - case ::AST::PathBinding::TAG_Crate: - case ::AST::PathBinding::TAG_Module: - case ::AST::PathBinding::TAG_Trait: - case ::AST::PathBinding::TAG_TypeAlias: - case ::AST::PathBinding::TAG_Enum: - allow = Lookup::Value; - break; - case ::AST::PathBinding::TAG_Struct: - case ::AST::PathBinding::TAG_Union: - allow = Lookup::Value; - break; - case ::AST::PathBinding::TAG_EnumVar: - allow = Lookup::Value; - break; - case ::AST::PathBinding::TAG_Static: - case ::AST::PathBinding::TAG_Function: - allow = Lookup::Type; - break; - // DEAD, Unbound, ... - default: break; - } - ASSERT_BUG(span, allow != Lookup::Any, "Invalid path binding type in use statement - " << use_stmt_data.path); - use_stmt_data.alt_binding = Resolve_Use_GetBinding(span, crate, use_stmt_data.path, parent_modules, allow); - DEBUG("- Alt Binding: " << use_stmt_data.alt_binding); } } @@ -264,25 +243,24 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path } } -::AST::PathBinding Resolve_Use_GetBinding_Mod( +::AST::Path::Bindings Resolve_Use_GetBinding_Mod( const Span& span, const ::AST::Crate& crate, const ::AST::Module& mod, const ::std::string& des_item_name, - ::std::span< const ::AST::Module* > parent_modules, - Lookup allow + ::std::span< const ::AST::Module* > parent_modules ) { + ::AST::Path::Bindings rv; // If the desired item is an anon module (starts with #) then parse and index if( des_item_name.size() > 0 && des_item_name[0] == '#' ) { unsigned int idx = 0; if( ::std::sscanf(des_item_name.c_str(), "#%u", &idx) != 1 ) { BUG(span, "Invalid anon path segment '" << des_item_name << "'"); } - if( idx >= mod.anon_mods().size() ) { - BUG(span, "Invalid anon path segment '" << des_item_name << "'"); - } + ASSERT_BUG(span, idx < mod.anon_mods().size(), "Invalid anon path segment '" << des_item_name << "'"); assert( mod.anon_mods()[idx] ); - return ::AST::PathBinding::make_Module({&*mod.anon_mods()[idx], nullptr}); + rv.type = ::AST::PathBinding_Type::make_Module({&*mod.anon_mods()[idx], nullptr}); + return rv; } // Seach for the name defined in the module. @@ -292,8 +270,6 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path continue ; if( item.name == des_item_name ) { - //if( allow != Lookup::Any ) - // DEBUG(mod.path() << " " << des_item_name << " " << item.data.tag_str()); TU_MATCH(::AST::Item, (item.data), (e), (None, // IMPOSSIBLE - Handled above @@ -314,46 +290,38 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path BUG(span, "Hit Extern in use resolution"); ), (Crate, - if( allow != Lookup::Value ) - ASSERT_BUG(span, crate.m_extern_crates.count(e.name), "Crate '" << e.name << "' not loaded"); - return ::AST::PathBinding::make_Crate({ &crate.m_extern_crates.at(e.name) }); + ASSERT_BUG(span, crate.m_extern_crates.count(e.name), "Crate '" << e.name << "' not loaded"); + rv.type = ::AST::PathBinding_Type::make_Crate({ &crate.m_extern_crates.at(e.name) }); ), (Type, - if( allow != Lookup::Value ) - return ::AST::PathBinding::make_TypeAlias({&e}); + rv.type = ::AST::PathBinding_Type::make_TypeAlias({&e}); ), (Trait, - if( allow != Lookup::Value ) - return ::AST::PathBinding::make_Trait({&e}); + rv.type = ::AST::PathBinding_Type::make_Trait({&e}); ), (Function, - if( allow != Lookup::Type ) - return ::AST::PathBinding::make_Function({&e}); + rv.value = ::AST::PathBinding_Value::make_Function({&e}); ), (Static, - if( allow != Lookup::Type ) - return ::AST::PathBinding::make_Static({&e}); + rv.value = ::AST::PathBinding_Value::make_Static({&e}); ), (Struct, - if( allow != Lookup::Value ) - return ::AST::PathBinding::make_Struct({&e}); - if( e.m_data.is_Tuple() && allow != Lookup::Type ) - return ::AST::PathBinding::make_Struct({&e}); + if( !e.m_data.is_Struct() ) + rv.value = ::AST::PathBinding_Value::make_Struct({&e}); + rv.type = ::AST::PathBinding_Type::make_Struct({&e}); ), (Enum, - if( allow != Lookup::Value ) - return ::AST::PathBinding::make_Enum({&e}); + rv.type = ::AST::PathBinding_Type::make_Enum({&e}); ), (Union, - if( allow != Lookup::Value ) - return ::AST::PathBinding::make_Union({&e}); + rv.type = ::AST::PathBinding_Type::make_Union({&e}); ), (Module, - if( allow != Lookup::Value ) - return ::AST::PathBinding::make_Module({&e}); + rv.type = ::AST::PathBinding_Type::make_Module({&e}); ) ) + return rv; } } @@ -366,58 +334,33 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path const Span& sp2 = imp_data.sp; if( imp.name == des_item_name ) { DEBUG("- Named import " << imp.name << " = " << imp_data); - if( imp_data.path.binding().is_Unbound() ) { + if( !imp_data.path.m_bindings.has_binding() ) { DEBUG(" > Needs resolve"); // TODO: Handle possibility of recursion //out_path = imp_data.path; - return Resolve_Use_GetBinding(sp2, crate, Resolve_Use_AbsolutisePath(sp2, mod.path(), imp_data.path), parent_modules, allow); + return Resolve_Use_GetBinding(sp2, crate, Resolve_Use_AbsolutisePath(sp2, mod.path(), imp_data.path), parent_modules); } else { - if( allow != Lookup::Any && allow != Lookup::AnyOpt ) - { - switch( imp_data.path.binding().tag() ) - { - case ::AST::PathBinding::TAG_Crate: - case ::AST::PathBinding::TAG_Module: - case ::AST::PathBinding::TAG_Trait: - case ::AST::PathBinding::TAG_TypeAlias: - case ::AST::PathBinding::TAG_Enum: - if( allow != Lookup::Type ) - continue; - break; - case ::AST::PathBinding::TAG_Struct: - break; - case ::AST::PathBinding::TAG_EnumVar: - break; - case ::AST::PathBinding::TAG_Static: - case ::AST::PathBinding::TAG_Function: - if( allow != Lookup::Value ) - continue; - break; - default: - break; - } - } //out_path = imp_data.path; - return imp_data.path.binding().clone(); + return imp_data.path.m_bindings.clone(); } } if( imp.is_pub && imp.name == "" ) { DEBUG("- Search glob of " << imp_data.path); // INEFFICIENT! Resolves and throws away the result (because we can't/shouldn't mutate here) - ::AST::PathBinding binding_; - const auto* binding = &imp_data.path.binding(); - if( binding->is_Unbound() ) { + ::AST::Path::Bindings bindings_; + const auto* bindings = &imp_data.path.m_bindings; + if( bindings->type.is_Unbound() ) { DEBUG("Temp resolving wildcard " << imp_data); // Handle possibility of recursion static ::std::vector resolve_stack_ptrs; if( ::std::find(resolve_stack_ptrs.begin(), resolve_stack_ptrs.end(), &imp_data) == resolve_stack_ptrs.end() ) { resolve_stack_ptrs.push_back( &imp_data ); - binding_ = Resolve_Use_GetBinding(sp2, crate, Resolve_Use_AbsolutisePath(sp2, mod.path(), imp_data.path), parent_modules); + bindings_ = Resolve_Use_GetBinding(sp2, crate, Resolve_Use_AbsolutisePath(sp2, mod.path(), imp_data.path), parent_modules); // *waves hand* I'm not evil. - const_cast< ::AST::PathBinding&>( imp_data.path.binding() ) = binding_.clone(); - binding = &binding_; + const_cast< ::AST::Path::Bindings&>( imp_data.path.m_bindings ) = bindings_.clone(); + bindings = &bindings_; resolve_stack_ptrs.pop_back(); } else { @@ -428,28 +371,27 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path //out_path = imp_data.path; } - TU_MATCH_HDR( (*binding), {) - TU_ARM(*binding, Crate, e) { + TU_MATCH_HDRA( (bindings->type), {) + TU_ARMA(Crate, e) { assert(e.crate_); const ::HIR::Module& hmod = e.crate_->m_hir->m_root_module; - auto rv = Resolve_Use_GetBinding__ext(sp2, crate, AST::Path("", { AST::PathNode(des_item_name,{}) }), hmod, 0, allow); - if( ! rv.is_Unbound() ) { + auto rv = Resolve_Use_GetBinding__ext(sp2, crate, AST::Path("", { AST::PathNode(des_item_name,{}) }), hmod, 0); + if( rv.has_binding() ) { return mv$(rv); } } - TU_ARM(*binding, Module, e) { - auto allow_inner = (allow == Lookup::Any ? Lookup::AnyOpt : allow); + TU_ARMA(Module, e) { if( e.module_ ) { // TODO: Prevent infinite recursion? - auto rv = Resolve_Use_GetBinding_Mod(span, crate, *e.module_, des_item_name, {}, allow_inner); - if( ! rv.is_Unbound() ) { + auto rv = Resolve_Use_GetBinding_Mod(span, crate, *e.module_, des_item_name, {}); + if( rv.has_binding() ) { return mv$(rv); } } else if( e.hir ) { const ::HIR::Module& hmod = *e.hir; - auto rv = Resolve_Use_GetBinding__ext(sp2, crate, AST::Path("", { AST::PathNode(des_item_name,{}) }), hmod, 0, allow); - if( ! rv.is_Unbound() ) { + auto rv = Resolve_Use_GetBinding__ext(sp2, crate, AST::Path("", { AST::PathNode(des_item_name,{}) }), hmod, 0); + if( rv.has_binding() ) { return mv$(rv); } } @@ -457,7 +399,7 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path BUG(span, "NULL module for binding on glob of " << imp_data.path); } } - TU_ARM(*binding, Enum, e) { + TU_ARMA(Enum, e) { assert(e.enum_ || e.hir); if( e.enum_ ) { const auto& enm = *e.enum_; @@ -465,7 +407,12 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path for(const auto& var : enm.variants()) { if( var.m_name == des_item_name ) { - return ::AST::PathBinding::make_EnumVar({ &enm, i }); + ::AST::Path::Bindings rv; + if( var.m_data.is_Struct() ) + rv.type = ::AST::PathBinding_Type::make_EnumVar({ &enm, i }); + else + rv.value = ::AST::PathBinding_Value::make_EnumVar({ &enm, i }); + return rv; } i ++; } @@ -475,12 +422,19 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path auto idx = enm.find_variant(des_item_name); if( idx != SIZE_MAX ) { - return ::AST::PathBinding::make_EnumVar({ nullptr, static_cast(idx), &enm }); + ::AST::Path::Bindings rv; + if( enm.m_data.is_Data() && enm.m_data.as_Data()[idx].is_struct ) { + rv.type = ::AST::PathBinding_Type::make_EnumVar({ nullptr, static_cast(idx), &enm }); + } + else { + rv.value = ::AST::PathBinding_Value::make_EnumVar({ nullptr, static_cast(idx), &enm }); + } + return rv; } } } break; default: - BUG(sp2, "Wildcard import expanded to an invalid item class - " << binding->tag_str()); + BUG(sp2, "Wildcard import expanded to an invalid item class - " << bindings->type.tag_str()); break; } } @@ -488,13 +442,12 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path if( mod.path().nodes().size() > 0 && mod.path().nodes().back().name()[0] == '#' ) { assert( parent_modules.size() > 0 ); - return Resolve_Use_GetBinding_Mod(span, crate, *parent_modules.back(), des_item_name, parent_modules.subspan(0, parent_modules.size()-1), allow); + return Resolve_Use_GetBinding_Mod(span, crate, *parent_modules.back(), des_item_name, parent_modules.subspan(0, parent_modules.size()-1)); } else { - if( allow == Lookup::Any ) - ERROR(span, E0000, "Could not find node '" << des_item_name << "' in module " << mod.path()); - else - return ::AST::PathBinding::make_Unbound({}); + //if( allow == Lookup::Any ) + // ERROR(span, E0000, "Could not find node '" << des_item_name << "' in module " << mod.path()); + return ::AST::Path::Bindings(); } } @@ -543,8 +496,9 @@ namespace { } } -::AST::PathBinding Resolve_Use_GetBinding__ext(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path, const ::HIR::Module& hmodr, unsigned int start, Lookup allow) +::AST::Path::Bindings Resolve_Use_GetBinding__ext(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path, const ::HIR::Module& hmodr, unsigned int start) { + ::AST::Path::Bindings rv; TRACE_FUNCTION_F(path); const auto& nodes = path.nodes(); const ::HIR::Module* hmod = &hmodr; @@ -577,7 +531,13 @@ namespace { if( idx == SIZE_MAX ) { ERROR(span, E0000, "Unable to find variant " << path); } - return ::AST::PathBinding::make_EnumVar({ nullptr, static_cast(idx), &enm }); + if( enm.m_data.is_Data() && enm.m_data.as_Data()[idx].is_struct ) { + rv.type = ::AST::PathBinding_Type::make_EnumVar({ nullptr, static_cast(idx), &enm }); + } + else { + rv.value = ::AST::PathBinding_Value::make_EnumVar({ nullptr, static_cast(idx), &enm }); + } + return rv; } else { hmod = reinterpret_cast(ptr); @@ -597,16 +557,23 @@ namespace { if(idx == SIZE_MAX) { ERROR(span, E0000, "Unable to find variant " << path); } - return ::AST::PathBinding::make_EnumVar({ nullptr, static_cast(idx), &e }); + if( e.m_data.is_Data() && e.m_data.as_Data()[idx].is_struct ) { + rv.type = ::AST::PathBinding_Type::make_EnumVar({ nullptr, static_cast(idx), &e }); + } + else { + rv.value = ::AST::PathBinding_Value::make_EnumVar({ nullptr, static_cast(idx), &e }); + } + return rv; ) ) } - if( allow != Lookup::Value ) + // - namespace/type items { auto it = hmod->m_mod_items.find(nodes.back().name()); - if( it != hmod->m_mod_items.end() ) { + if( it != hmod->m_mod_items.end() ) + { const auto* item_ptr = &it->second->ent; - DEBUG("E : " << nodes.back().name() << " = " << item_ptr->tag_str()); + DEBUG("E : Mod " << nodes.back().name() << " = " << item_ptr->tag_str()); if( item_ptr->is_Import() ) { const auto& e = item_ptr->as_Import(); const auto& ec = crate.m_extern_crates.at( e.path.m_crate_name ); @@ -616,94 +583,117 @@ namespace { p.m_components.pop_back(); const auto& enm = ec.m_hir->get_typeitem_by_path(span, p, true).as_Enum(); assert(e.idx < enm.num_variants()); - return ::AST::PathBinding::make_EnumVar({ nullptr, e.idx, &enm }); + rv.type = ::AST::PathBinding_Type::make_EnumVar({ nullptr, e.idx, &enm }); + } + else if( e.path.m_components.empty() ) + { + rv.type = ::AST::PathBinding_Type::make_Module({nullptr, &ec.m_hir->m_root_module}); + } + else + { + item_ptr = &ec.m_hir->get_typeitem_by_path(span, e.path, true); // ignore_crate_name=true } - if( e.path.m_components.empty() ) - return ::AST::PathBinding::make_Module({nullptr, &ec.m_hir->m_root_module}); - item_ptr = &ec.m_hir->get_typeitem_by_path(span, e.path, true); // ignore_crate_name=true } - TU_MATCHA( (*item_ptr), (e), - (Import, - BUG(span, "Recursive import in " << path << " - " << it->second->ent.as_Import().path << " -> " << e.path); - ), - (Module, - return ::AST::PathBinding::make_Module({nullptr, &e}); - ), - (TypeAlias, - return ::AST::PathBinding::make_TypeAlias({nullptr}); - ), - (Enum, - return ::AST::PathBinding::make_Enum({nullptr, &e}); - ), - (Struct, - return ::AST::PathBinding::make_Struct({nullptr, &e}); - ), - (Union, - return ::AST::PathBinding::make_Union({nullptr, &e}); - ), - (Trait, - return ::AST::PathBinding::make_Trait({nullptr, &e}); + if( rv.type.is_Unbound() ) + { + TU_MATCHA( (*item_ptr), (e), + (Import, + BUG(span, "Recursive import in " << path << " - " << it->second->ent.as_Import().path << " -> " << e.path); + ), + (Module, + rv.type = ::AST::PathBinding_Type::make_Module({nullptr, &e}); + ), + (TypeAlias, + rv.type = ::AST::PathBinding_Type::make_TypeAlias({nullptr}); + ), + (Enum, + rv.type = ::AST::PathBinding_Type::make_Enum({nullptr, &e}); + ), + (Struct, + rv.type = ::AST::PathBinding_Type::make_Struct({nullptr, &e}); + ), + (Union, + rv.type = ::AST::PathBinding_Type::make_Union({nullptr, &e}); + ), + (Trait, + rv.type = ::AST::PathBinding_Type::make_Trait({nullptr, &e}); + ) ) - ) + } + } + else + { + DEBUG("Types = " << FMT_CB(ss, for(const auto& e : hmod->m_mod_items){ ss << e.first << ":" << e.second->ent.tag_str() << ","; })); } - DEBUG("Types = " << FMT_CB(ss, for(const auto& e : hmod->m_mod_items){ ss << e.first << ":" << e.second->ent.tag_str() << ","; })); } - if( allow != Lookup::Type ) + // - Values { auto it2 = hmod->m_value_items.find(nodes.back().name()); if( it2 != hmod->m_value_items.end() ) { const auto* item_ptr = &it2->second->ent; - DEBUG("E : " << nodes.back().name() << " = " << item_ptr->tag_str()); + DEBUG("E : Value " << nodes.back().name() << " = " << item_ptr->tag_str()); if( item_ptr->is_Import() ) { const auto& e = item_ptr->as_Import(); // This doesn't need to recurse - it can just do a single layer (as no Import should refer to another) const auto& ec = crate.m_extern_crates.at( e.path.m_crate_name ); - if( e.is_variant ) { + if( e.is_variant ) + { auto p = e.path; p.m_components.pop_back(); const auto& enm = ec.m_hir->get_typeitem_by_path(span, p, true).as_Enum(); assert(e.idx < enm.num_variants()); - return ::AST::PathBinding::make_EnumVar({ nullptr, e.idx, &enm }); + rv.value = ::AST::PathBinding_Value::make_EnumVar({ nullptr, e.idx, &enm }); + } + else + { + item_ptr = &ec.m_hir->get_valitem_by_path(span, e.path, true); // ignore_crate_name=true } - item_ptr = &ec.m_hir->get_valitem_by_path(span, e.path, true); // ignore_crate_name=true } - TU_MATCHA( (*item_ptr), (e), - (Import, - BUG(span, "Recursive import in " << path << " - " << it2->second->ent.as_Import().path << " -> " << e.path); - ), - (Constant, - return ::AST::PathBinding::make_Static({ nullptr }); - ), - (Static, - return ::AST::PathBinding::make_Static({ nullptr }); - ), - // TODO: What happens if these two refer to an enum constructor? - (StructConstant, - ASSERT_BUG(span, crate.m_extern_crates.count(e.ty.m_crate_name), "Crate '" << e.ty.m_crate_name << "' not loaded for " << e.ty); - return ::AST::PathBinding::make_Struct({ nullptr, &crate.m_extern_crates.at(e.ty.m_crate_name).m_hir->get_typeitem_by_path(span, e.ty, true).as_Struct() }); - ), - (StructConstructor, - ASSERT_BUG(span, crate.m_extern_crates.count(e.ty.m_crate_name), "Crate '" << e.ty.m_crate_name << "' not loaded for " << e.ty); - return ::AST::PathBinding::make_Struct({ nullptr, &crate.m_extern_crates.at(e.ty.m_crate_name).m_hir->get_typeitem_by_path(span, e.ty, true).as_Struct() }); - ), - (Function, - return ::AST::PathBinding::make_Function({ nullptr }); + if( rv.value.is_Unbound() ) + { + TU_MATCHA( (*item_ptr), (e), + (Import, + BUG(span, "Recursive import in " << path << " - " << it2->second->ent.as_Import().path << " -> " << e.path); + ), + (Constant, + rv.value = ::AST::PathBinding_Value::make_Static({ nullptr }); + ), + (Static, + rv.value = ::AST::PathBinding_Value::make_Static({ nullptr }); + ), + // TODO: What happens if these two refer to an enum constructor? + (StructConstant, + ASSERT_BUG(span, crate.m_extern_crates.count(e.ty.m_crate_name), "Crate '" << e.ty.m_crate_name << "' not loaded for " << e.ty); + rv.value = ::AST::PathBinding_Value::make_Struct({ nullptr, &crate.m_extern_crates.at(e.ty.m_crate_name).m_hir->get_typeitem_by_path(span, e.ty, true).as_Struct() }); + ), + (StructConstructor, + ASSERT_BUG(span, crate.m_extern_crates.count(e.ty.m_crate_name), "Crate '" << e.ty.m_crate_name << "' not loaded for " << e.ty); + rv.value = ::AST::PathBinding_Value::make_Struct({ nullptr, &crate.m_extern_crates.at(e.ty.m_crate_name).m_hir->get_typeitem_by_path(span, e.ty, true).as_Struct() }); + ), + (Function, + rv.value = ::AST::PathBinding_Value::make_Function({ nullptr }); + ) ) - ) + } + } + else + { + DEBUG("Values = " << FMT_CB(ss, for(const auto& e : hmod->m_value_items){ ss << e.first << ":" << e.second->ent.tag_str() << ","; })); } - - DEBUG("Values = " << FMT_CB(ss, for(const auto& e : hmod->m_value_items){ ss << e.first << ":" << e.second->ent.tag_str() << ","; })); } - DEBUG("E : None"); - return ::AST::PathBinding::make_Unbound({}); + if( rv.type.is_Unbound() && rv.value.is_Unbound() ) + { + DEBUG("E : None"); + } + return rv; } -::AST::PathBinding Resolve_Use_GetBinding__ext(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path, const AST::ExternCrate& ec, unsigned int start, Lookup allow) +::AST::Path::Bindings Resolve_Use_GetBinding__ext(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path, const AST::ExternCrate& ec, unsigned int start) { - return Resolve_Use_GetBinding__ext(span, crate, path, ec.m_hir->m_root_module, start, allow); + return Resolve_Use_GetBinding__ext(span, crate, path, ec.m_hir->m_root_module, start); } -::AST::PathBinding Resolve_Use_GetBinding(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path, ::std::span< const ::AST::Module* > parent_modules, Lookup allow) +::AST::Path::Bindings Resolve_Use_GetBinding(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path, ::std::span< const ::AST::Module* > parent_modules) { TRACE_FUNCTION_F(path); //::AST::Path rv; @@ -713,14 +703,17 @@ namespace { const auto& path_abs = path.m_class.as_Absolute(); ASSERT_BUG(span, crate.m_extern_crates.count(path_abs.crate), "Crate '" << path_abs.crate << "' not loaded"); - return Resolve_Use_GetBinding__ext(span, crate, path, crate.m_extern_crates.at( path_abs.crate ), 0, allow); + return Resolve_Use_GetBinding__ext(span, crate, path, crate.m_extern_crates.at( path_abs.crate ), 0); } + ::AST::Path::Bindings rv; + const AST::Module* mod = &crate.m_root_module; const auto& nodes = path.nodes(); if( nodes.size() == 0 ) { // An import of the root. - return ::AST::PathBinding::make_Module({ mod, nullptr }); + rv.type = ::AST::PathBinding_Type::make_Module({ mod, nullptr }); + return rv; } for( unsigned int i = 0; i < nodes.size()-1; i ++ ) { @@ -729,19 +722,18 @@ namespace { //rv = Resolve_Use_CanoniseAndBind_Mod(span, crate, *mod, mv$(rv), nodes[i].name(), parent_modules, Lookup::Type); //const auto& b = rv.binding(); assert(mod); - auto b = Resolve_Use_GetBinding_Mod(span, crate, *mod, nodes.at(i).name(), parent_modules, Lookup::Type); - TU_MATCH_DEF(::AST::PathBinding, (b), (e), - ( - ERROR(span, E0000, "Unexpected item type " << b.tag_str() << " in import of " << path); - ), - (Unbound, - ERROR(span, E0000, "Cannot find component " << i << " of " << path); - ), - (Crate, + auto b = Resolve_Use_GetBinding_Mod(span, crate, *mod, nodes.at(i).name(), parent_modules); + TU_MATCH_HDRA( (b.type), {) + default: + ERROR(span, E0000, "Unexpected item type " << b.type.tag_str() << " in import of " << path); + TU_ARMA(Unbound, e) { + ERROR(span, E0000, "Cannot find component " << i << " of " << path << " (" << b.type << ")"); + } + TU_ARMA(Crate, e) { // TODO: Mangle the original path (or return a new path somehow) - return Resolve_Use_GetBinding__ext(span, crate, path, *e.crate_, i+1, allow); - ), - (Enum, + return Resolve_Use_GetBinding__ext(span, crate, path, *e.crate_, i+1); + } + TU_ARMA(Enum, e) { const auto& enum_ = *e.enum_; i += 1; if( i != nodes.size() - 1 ) { @@ -750,10 +742,12 @@ namespace { const auto& node2 = nodes[i]; int variant_index = -1; + bool is_value; for( unsigned int j = 0; j < enum_.variants().size(); j ++ ) { if( enum_.variants()[j].m_name == node2.name() ) { variant_index = j; + is_value = !enum_.variants()[i].m_data.is_Struct(); break ; } } @@ -761,22 +755,32 @@ namespace { ERROR(span, E0000, "Unknown enum variant '" << node2.name() << "'"); } - return ::AST::PathBinding::make_EnumVar({&enum_, static_cast(variant_index)}); - ), - (Module, + if( is_value ) { + rv.value = ::AST::PathBinding_Value::make_EnumVar({&enum_, static_cast(variant_index)}); + } + else { + rv.type = ::AST::PathBinding_Type::make_EnumVar({&enum_, static_cast(variant_index)}); + } + return rv; + } + TU_ARMA(Module, e) { ASSERT_BUG(span, e.module_ || e.hir, "nullptr module pointer in node " << i << " of " << path); if( !e.module_ ) { assert(e.hir); // TODO: Mangle the original path (or return a new path somehow) - return Resolve_Use_GetBinding__ext(span, crate, path, *e.hir, i+1, allow); + return Resolve_Use_GetBinding__ext(span, crate, path, *e.hir, i+1); } mod = e.module_; - ) - ) + } + } } assert(mod); - return Resolve_Use_GetBinding_Mod(span, crate, *mod, nodes.back().name(), parent_modules, allow); + return Resolve_Use_GetBinding_Mod(span, crate, *mod, nodes.back().name(), parent_modules); } +//::AST::PathBinding_Macro Resolve_Use_GetBinding_Macro(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path, ::std::span< const ::AST::Module* > parent_modules) +//{ +// throw ""; +//} -- cgit v1.2.3 From b6fb5429b0983d5571c5ec01abbd502526ed9086 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 28 Dec 2018 19:58:29 +0800 Subject: Resovle - Macro imports (partial), bugfixes --- src/ast/path.hpp | 3 ++- src/resolve/index.cpp | 19 ++++++++++++++++--- src/resolve/use.cpp | 28 +++++++++++++++++++++++++--- 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/src/ast/path.hpp b/src/ast/path.hpp index b1453f04..89804b61 100644 --- a/src/ast/path.hpp +++ b/src/ast/path.hpp @@ -20,6 +20,7 @@ #include "../include/ident.hpp" class TypeRef; +class MacroRules; namespace HIR { class Module; @@ -138,7 +139,7 @@ TAGGED_UNION_EX(PathBinding_Macro, (), Unbound, ( }), (MacroRules, struct { const ExternCrate* crate_; // Can be NULL - //const MacroRules* mac; + const MacroRules* mac; }) ), (), (), diff --git a/src/resolve/index.cpp b/src/resolve/index.cpp index 148bf069..bbcd7e58 100644 --- a/src/resolve/index.cpp +++ b/src/resolve/index.cpp @@ -59,6 +59,7 @@ namespace { void _add_item(const Span& sp, AST::Module& mod, IndexName location, const ::std::string& name, bool is_pub, ::AST::Path ir, bool error_on_collision=true) { + ASSERT_BUG(sp, ir.m_bindings.has_binding(), ""); auto& list = get_mod_index(mod, location); bool was_import = (ir != mod.path() + name); @@ -262,16 +263,28 @@ void Resolve_Index_Module_Wildcard__glob_in_hir_mod(const Span& sp, const AST::C for(const auto& it : hmod.m_mod_items) { const auto& ve = *it.second; if( ve.is_public ) { + const auto* vep = &ve.ent; AST::Path p; - if( ve.ent.is_Import() ) { - p = hir_to_ast( ve.ent.as_Import().path ); + if( vep->is_Import() ) { + const auto& spath = vep->as_Import().path; + p = hir_to_ast( spath ); + + ASSERT_BUG(sp, crate.m_extern_crates.count(spath.m_crate_name) == 1, "Crate " << spath.m_crate_name << " is not loaded"); + const auto* hmod = &crate.m_extern_crates.at(spath.m_crate_name).m_hir->m_root_module; + for(unsigned int i = 0; i < spath.m_components.size()-1; i ++) { + const auto& it = hmod->m_mod_items.at( spath.m_components[i] ); + ASSERT_BUG(sp, it->ent.is_Module(), ""); + hmod = &it->ent.as_Module(); + } + vep = &hmod->m_mod_items.at( spath.m_components.back() )->ent; } else { p = path + it.first; } - TU_MATCHA( (ve.ent), (e), + TU_MATCHA( (*vep), (e), (Import, //throw ""; + TODO(sp, "Get binding for HIR import? " << e.path); ), (Module, p.m_bindings.type = ::AST::PathBinding_Type::make_Module({nullptr, &e}); diff --git a/src/resolve/use.cpp b/src/resolve/use.cpp index a0d1aa53..203256a4 100644 --- a/src/resolve/use.cpp +++ b/src/resolve/use.cpp @@ -307,6 +307,7 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path rv.value = ::AST::PathBinding_Value::make_Static({&e}); ), (Struct, + // TODO: What happens with name collisions? if( !e.m_data.is_Struct() ) rv.value = ::AST::PathBinding_Value::make_Struct({&e}); rv.type = ::AST::PathBinding_Type::make_Struct({&e}); @@ -321,9 +322,19 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path rv.type = ::AST::PathBinding_Type::make_Module({&e}); ) ) - return rv; } } + // TODO: macros + for(const auto& mac : mod.macros()) + { + if( mac.name == des_item_name ) { + TODO(span, "Import of macro - " << des_item_name); + } + } + if( rv.has_binding() ) + { + return rv; + } // Imports for( const auto& imp : mod.items() ) @@ -690,7 +701,17 @@ namespace { } ::AST::Path::Bindings Resolve_Use_GetBinding__ext(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path, const AST::ExternCrate& ec, unsigned int start) { - return Resolve_Use_GetBinding__ext(span, crate, path, ec.m_hir->m_root_module, start); + auto rv = Resolve_Use_GetBinding__ext(span, crate, path, ec.m_hir->m_root_module, start); + if( start + 1 == path.nodes().size() ) + { + const auto& name = path.nodes().back().name(); + auto it = ec.m_hir->m_exported_macros.find( name ); + if( it != ec.m_hir->m_exported_macros.end() ) + { + rv.macro = ::AST::PathBinding_Macro::make_MacroRules({ &ec, &*it->second }); + } + } + return rv; } ::AST::Path::Bindings Resolve_Use_GetBinding(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path, ::std::span< const ::AST::Module* > parent_modules) @@ -747,7 +768,7 @@ namespace { { if( enum_.variants()[j].m_name == node2.name() ) { variant_index = j; - is_value = !enum_.variants()[i].m_data.is_Struct(); + is_value = !enum_.variants()[j].m_data.is_Struct(); break ; } } @@ -755,6 +776,7 @@ namespace { ERROR(span, E0000, "Unknown enum variant '" << node2.name() << "'"); } + DEBUG("AST Enum variant - " << variant_index << ", is_value=" << is_value << " " << enum_.variants()[variant_index].m_data.tag_str()); if( is_value ) { rv.value = ::AST::PathBinding_Value::make_EnumVar({&enum_, static_cast(variant_index)}); } -- cgit v1.2.3 From ea32668e6ca82962d720ad9d7751a8e4339b09aa Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 28 Dec 2018 19:58:42 +0800 Subject: Trans Target - cfg for atomic comare-and-set (tied to atomic ptr) --- src/trans/target.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/trans/target.cpp b/src/trans/target.cpp index f91b679a..121a9134 100644 --- a/src/trans/target.cpp +++ b/src/trans/target.cpp @@ -509,6 +509,7 @@ void Target_SetCfg(const ::std::string& target_name) if(s == "32") return g_target.m_arch.m_atomics.u32; if(s == "64") return g_target.m_arch.m_atomics.u64; if(s == "ptr") return g_target.m_arch.m_atomics.ptr; // Has an atomic pointer-sized value + if(s == "cas") return g_target.m_arch.m_atomics.ptr; // TODO: Atomic compare-and-set option return false; }); Cfg_SetValueCb("target_feature", [](const ::std::string& s) { -- cgit v1.2.3 From 4e69aee8c5f942ee25ea6583a156a7aa4bc41d5c Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 28 Dec 2018 21:34:40 +0800 Subject: Lower HIR - Rough (roughshod) handling of `repr(align(N))` --- src/hir/from_ast.cpp | 58 +++++++++++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/src/hir/from_ast.cpp b/src/hir/from_ast.cpp index f62d097a..f5d841a7 100644 --- a/src/hir/from_ast.cpp +++ b/src/hir/from_ast.cpp @@ -879,56 +879,54 @@ namespace { ) ) - auto struct_repr = ::HIR::Struct::Repr::Rust; + auto rv = ::HIR::Struct { + LowerHIR_GenericParams(ent.params(), nullptr), + ::HIR::Struct::Repr::Rust, + mv$(data) + }; + if( const auto* attr_repr = attrs.get("repr") ) { - ASSERT_BUG(Span(), attr_repr->has_sub_items(), "#[repr] attribute malformed, " << *attr_repr); - bool is_c = false; - bool is_simd = false; - bool is_packed = false; - ASSERT_BUG(Span(), attr_repr->items().size() > 0, "#[repr] attribute malformed, " << *attr_repr); + ASSERT_BUG(attr_repr->span(), attr_repr->has_sub_items(), "#[repr] attribute malformed, " << *attr_repr); + ASSERT_BUG(attr_repr->span(), attr_repr->items().size() > 0, "#[repr] attribute malformed, " << *attr_repr); for( const auto& a : attr_repr->items() ) { - ASSERT_BUG(Span(), a.has_noarg(), "#[repr] attribute malformed, " << *attr_repr); const auto& repr_str = a.name(); if( repr_str == "C" ) { - is_c = true; + ASSERT_BUG(a.span(), a.has_noarg(), "#[repr] attribute malformed, " << *attr_repr); + ASSERT_BUG(a.span(), rv.m_repr == ::HIR::Struct::Repr::Rust, "Conflicting #[repr] attributes"); + rv.m_repr = ::HIR::Struct::Repr::C; } else if( repr_str == "packed" ) { - is_packed = true; + ASSERT_BUG(a.span(), a.has_noarg(), "#[repr] attribute malformed, " << *attr_repr); + ASSERT_BUG(a.span(), rv.m_repr == ::HIR::Struct::Repr::Rust, "Conflicting #[repr] attributes"); + rv.m_repr = ::HIR::Struct::Repr::Packed; } else if( repr_str == "simd" ) { - is_simd = true; + ASSERT_BUG(a.span(), a.has_noarg(), "#[repr] attribute malformed, " << *attr_repr); + ASSERT_BUG(a.span(), rv.m_repr == ::HIR::Struct::Repr::Rust, "Conflicting #[repr] attributes"); + rv.m_repr = ::HIR::Struct::Repr::Simd; } else if( repr_str == "transparent" ) { + ASSERT_BUG(a.span(), a.has_noarg(), "#[repr] attribute malformed, " << *attr_repr); + ASSERT_BUG(a.span(), rv.m_repr == ::HIR::Struct::Repr::Rust, "Conflicting #[repr] attributes"); // TODO: Mark so the C backend knows that it's supposed to be transparent + //rv.m_repr = ::HIR::Struct::Repr::Transparent; + } + else if( repr_str == "align" ) { + //ASSERT_BUG(a.span(), a.has_string(), "#[repr(aligned)] attribute malformed, " << *attr_repr); + ASSERT_BUG(a.span(), rv.m_repr == ::HIR::Struct::Repr::Rust, "Conflicting #[repr] attributes"); + // TODO: Alignment repr + //rv.m_repr = ::HIR::Struct::Repr::Aligned; + //rv.m_align_size = ::std::stol(a.string()); } else { TODO(a.span(), "Handle struct repr '" << repr_str << "'"); } } - - if( is_packed ) { - // TODO: What if `simd` is present? - // NOTE: repr(packed,C) is treated as the same as repr(packed) in mrustc - struct_repr = ::HIR::Struct::Repr::Packed; - } - else if( is_c ) { - // TODO: What if `simd` is present? - struct_repr = ::HIR::Struct::Repr::C; - } - else if( is_simd ) { - struct_repr = ::HIR::Struct::Repr::Simd; - } - else { - } } - return ::HIR::Struct { - LowerHIR_GenericParams(ent.params(), nullptr), - struct_repr, - mv$(data) - }; + return rv; } ::HIR::Enum LowerHIR_Enum(::HIR::ItemPath path, const ::AST::Enum& ent, const ::AST::AttributeList& attrs, ::std::function push_struct) -- cgit v1.2.3 From 174646946ada8348c4d1d153ce422eeae2937fd5 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 28 Dec 2018 21:50:55 +0800 Subject: Typecheck Expressions - More match ergonomics --- src/hir_typeck/expr_cs.cpp | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 739d0f8b..99de3912 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -3917,7 +3917,24 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T TU_ARM(pattern.m_data, StructTuple, e) { context.add_ivars_params( e.path.m_params ); context.equate_types( sp, ty, ::HIR::TypeRef::new_path(e.path.clone(), ::HIR::TypeRef::TypePathBinding(e.binding)) ); - TODO(sp, "Match ergonomics - tuple struct pattern"); + + assert(e.binding); + const auto& str = *e.binding; + + // - assert check from earlier pass + ASSERT_BUG(sp, str.m_data.is_Tuple(), "Struct-tuple pattern on non-Tuple struct"); + const auto& sd = str.m_data.as_Tuple(); + const auto& params = e.path.m_params; + + rv = true; + for( unsigned int i = 0; i < e.sub_patterns.size(); i ++ ) + { + /*const*/ auto& sub_pat = e.sub_patterns[i]; + const auto& field_type = sd[i].ent; + ::HIR::TypeRef tmp; + const auto& var_ty = (monomorphise_type_needed(field_type) ? (tmp = monomorphise_type(sp, str.m_params, params, field_type)) : field_type); + rv &= this->revisit_inner(context, sub_pat, var_ty, binding_mode); + } } TU_ARM(pattern.m_data, Struct, e) { context.add_ivars_params( e.path.m_params ); @@ -3982,7 +3999,28 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T context.add_ivars_params( e.path.m_params ); context.equate_types( sp, ty, ::HIR::TypeRef::new_path(get_parent_path(e.path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)) ); assert(e.binding_ptr); - TODO(sp, "Match ergonomics - enum struct pattern"); + + const auto& enm = *e.binding_ptr; + const auto& str = *enm.m_data.as_Data()[e.binding_idx].type.m_data.as_Path().binding.as_Struct(); + const auto& tup_var = str.m_data.as_Named(); + const auto& params = e.path.m_params; + + rv = true; // &= below ensures that all must be complete to return complete + for( auto& field_pat : e.sub_patterns ) + { + unsigned int f_idx = ::std::find_if( tup_var.begin(), tup_var.end(), [&](const auto& x){ return x.first == field_pat.first; } ) - tup_var.begin(); + if( f_idx == tup_var.size() ) { + ERROR(sp, E0000, "Enum variant " << e.path << " doesn't have a field " << field_pat.first); + } + const ::HIR::TypeRef& field_type = tup_var[f_idx].second.ent; + if( monomorphise_type_needed(field_type) ) { + auto field_type_mono = monomorphise_type(sp, enm.m_params, params, field_type); + rv &= this->revisit_inner(context, field_pat.second, field_type_mono, binding_mode); + } + else { + rv &= this->revisit_inner(context, field_pat.second, field_type, binding_mode); + } + } } } return rv; -- cgit v1.2.3 From 5238ab2025b099f861bd2d071ed3521e7ee4e842 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 29 Dec 2018 11:15:08 +0800 Subject: Typecheck Expressions - Fix incorrect anotation on blocks traversed for coercions --- src/hir_typeck/expr_check.cpp | 1 + src/hir_typeck/expr_cs.cpp | 31 ++++++++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/hir_typeck/expr_check.cpp b/src/hir_typeck/expr_check.cpp index 2d63d045..cd57c471 100644 --- a/src/hir_typeck/expr_check.cpp +++ b/src/hir_typeck/expr_check.cpp @@ -1050,6 +1050,7 @@ namespace { } void check_types_equal(const Span& sp, const ::HIR::TypeRef& l, const ::HIR::TypeRef& r) const { + //DEBUG(sp << " - " << l << " == " << r); if( /*l.m_data.is_Diverge() ||*/ r.m_data.is_Diverge() ) { // Diverge, matches everything. // TODO: Is this always true? diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 99de3912..3c3f6e71 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -3112,6 +3112,14 @@ namespace { ::HIR::ExprVisitorDef::visit_pattern(sp, pat); } + void visit(::HIR::ExprNode_Block& node) override { + ::HIR::ExprVisitorDef::visit(node); + if( node.m_value_node ) + { + check_types_equal(node.span(), node.m_res_type, node.m_value_node->m_res_type); + } + } + void visit(::HIR::ExprNode_Let& node) override { this->check_type_resolved_top(node.span(), node.m_type); ::HIR::ExprVisitorDef::visit(node); @@ -3320,6 +3328,21 @@ namespace { ) ) } + + void check_types_equal(const Span& sp, const ::HIR::TypeRef& l, const ::HIR::TypeRef& r) const + { + DEBUG(sp << " - " << l << " == " << r); + if( /*l.m_data.is_Diverge() ||*/ r.m_data.is_Diverge() ) { + // Diverge, matches everything. + // TODO: Is this always true? + } + else if( l != r ) { + ERROR(sp, E0000, "Type mismatch - " << l << " != " << r); + } + else { + // All good + } + } }; } @@ -5746,6 +5769,7 @@ namespace { // If the coercion is of a block, do the reborrow on the last node of the block // - Cleans up the dumped MIR and prevents needing a reborrow elsewhere. + // - TODO: Alter the block's result types ::HIR::ExprNodeP* npp = node_ptr_ptr; while( auto* p = dynamic_cast< ::HIR::ExprNode_Block*>(&**npp) ) { @@ -5755,7 +5779,7 @@ namespace { ASSERT_BUG( p->span(), context.m_ivars.types_equal(p->m_res_type, src), "Block and result mismatch - " << context.m_ivars.fmt_type(p->m_res_type) << " != " << context.m_ivars.fmt_type(src) ); - p->m_res_type = new_type.clone(); + p->m_res_type = dst.clone(); npp = &p->m_value_node; } ::HIR::ExprNodeP& node_ptr = *npp; @@ -5784,7 +5808,7 @@ namespace { context.equate_types(sp, *dep->inner, *se.inner); return CoerceResult::Custom; case CoerceResult::Unsize: - DEBUG("- NEWNODE _Unsize " << &*node_ptr << " -> " << dst); + DEBUG("- NEWNODE _Unsize " << &node_ptr << " " << &*node_ptr << " -> " << dst); auto span = node_ptr->span(); node_ptr = NEWNODE( dst.clone(), span, _Unsize, mv$(node_ptr), dst.clone() ); return CoerceResult::Custom; @@ -6973,7 +6997,7 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR: context.add_ivars(root_ptr->m_res_type); root_ptr->visit(visitor); - DEBUG("Return type = " << new_res_ty); + DEBUG("Return type = " << new_res_ty << ", root_ptr = " << typeid(*root_ptr).name() << " " << root_ptr->m_res_type); context.equate_types_coerce(sp, new_res_ty, root_ptr); } @@ -7267,6 +7291,7 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR: } BUG(root_ptr->span(), "Spare rules left after typecheck stabilised"); } + DEBUG("root_ptr = " << typeid(*root_ptr).name() << " " << root_ptr->m_res_type); // - Recreate the pointer expr.reset( root_ptr.release() ); -- cgit v1.2.3 From 024c97cfe2639d10e3c24343750aac1e37797d54 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 29 Dec 2018 11:15:43 +0800 Subject: HIR Dump - Tweak output for better readability --- src/hir/dump.cpp | 38 +++++++++++++------------------------- 1 file changed, 13 insertions(+), 25 deletions(-) diff --git a/src/hir/dump.cpp b/src/hir/dump.cpp index e607925e..6d786a90 100644 --- a/src/hir/dump.cpp +++ b/src/hir/dump.cpp @@ -331,33 +331,21 @@ namespace { void visit(::HIR::ExprNode_Block& node) override { - if( node.m_nodes.size() == 0 ) { - m_os << "{"; - if( node.m_value_node ) - { - m_os << " "; - this->visit_node_ptr(node.m_value_node); - } - m_os << " }"; + m_os << "{\n"; + inc_indent(); + for(auto& sn : node.m_nodes) { + m_os << indent(); + this->visit_node_ptr(sn); + m_os << ";\n"; } - else { - m_os << "{\n"; - inc_indent(); - for(auto& sn : node.m_nodes) { - m_os << "\n"; - m_os << indent(); - this->visit_node_ptr(sn); - m_os << ";\n"; - } - if( node.m_value_node ) - { - m_os << indent(); - this->visit_node_ptr(node.m_value_node); - m_os << "\n"; - } - dec_indent(); - m_os << indent() << "}"; + if( node.m_value_node ) + { + m_os << indent(); + this->visit_node_ptr(node.m_value_node); + m_os << "\n"; } + dec_indent(); + m_os << indent() << "}"; } void visit(::HIR::ExprNode_Asm& node) override -- cgit v1.2.3 From 0a47863a680677817631f507ea6f6565b537487e Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 29 Dec 2018 11:44:53 +0800 Subject: Misc MIR generation fixes --- src/hir_typeck/expr_cs.cpp | 2 +- src/mir/from_hir.cpp | 4 ++-- src/mir/from_hir_match.cpp | 2 +- src/mir/mir_builder.cpp | 6 +++++- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 3c3f6e71..e8e0f65c 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -3881,7 +3881,7 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T } TU_ARM(pattern.m_data, Value, pe) { // no-op? - if( pe.val.is_String() ) { + if( pe.val.is_String() || pe.val.is_ByteString() ) { ASSERT_BUG(sp, pattern.m_implicit_deref_count >= 1, ""); pattern.m_implicit_deref_count -= 1; } diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index c3281bd6..38d00a5a 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -1218,7 +1218,7 @@ namespace { } void visit(::HIR::ExprNode_Cast& node) override { - TRACE_FUNCTION_F("_Cast"); + TRACE_FUNCTION_F("_Cast " << node.m_res_type); this->visit_node_ptr(node.m_value); const auto& ty_out = node.m_res_type; @@ -2009,7 +2009,7 @@ namespace { } void visit(::HIR::ExprNode_Field& node) override { - TRACE_FUNCTION_F("_Field"); + TRACE_FUNCTION_F("_Field \"" << node.m_field << "\""); this->visit_node_ptr(node.m_value); auto val = m_builder.get_result_in_lvalue(node.m_value->span(), node.m_value->m_res_type); diff --git a/src/mir/from_hir_match.cpp b/src/mir/from_hir_match.cpp index 8014ea8e..264c74c5 100644 --- a/src/mir/from_hir_match.cpp +++ b/src/mir/from_hir_match.cpp @@ -1119,7 +1119,7 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa (Any, // _ on a box, recurse into the box type. m_field_path.push_back(FIELD_DEREF); - this->append_from(sp, pat, inner_ty); + this->append_from(sp, empty_pattern, inner_ty); m_field_path.pop_back(); ), (Box, diff --git a/src/mir/mir_builder.cpp b/src/mir/mir_builder.cpp index a3650919..ac1b7650 100644 --- a/src/mir/mir_builder.cpp +++ b/src/mir/mir_builder.cpp @@ -290,7 +290,11 @@ void MirBuilder::push_stmt_assign(const Span& sp, ::MIR::LValue dst, ::MIR::RVal } ), (Cast, - this->moved_lvalue(sp, e.val); + // TODO: Does this actually move? + if( e.type.m_data.is_Borrow() ) + { + this->moved_lvalue(sp, e.val); + } ), (BinOp, switch(e.op) -- cgit v1.2.3 From 24086285e2b5035dd23a4e5088baeb27f7774fe9 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 29 Dec 2018 13:32:51 +0800 Subject: Lower MIR - Handing of irrefutable enum matches, some other tweaks --- src/hir_typeck/static.cpp | 81 ++++++++++++++++++++++++++++++++++++++++++++- src/hir_typeck/static.hpp | 1 + src/mir/cleanup.cpp | 9 +++-- src/mir/from_hir.cpp | 83 ++++++++++++++++++++++++++++------------------- src/trans/codegen_c.cpp | 1 + 5 files changed, 139 insertions(+), 36 deletions(-) diff --git a/src/hir_typeck/static.cpp b/src/hir_typeck/static.cpp index 64b04611..d40ee811 100644 --- a/src/hir_typeck/static.cpp +++ b/src/hir_typeck/static.cpp @@ -1600,7 +1600,7 @@ bool StaticTraitResolve::type_is_sized(const Span& sp, const ::HIR::TypeRef& ty) return true; ), (Diverge, - // The ! type is kinda Copy ... + // The ! type is kinda Sized ... return true; ), (Closure, @@ -1645,6 +1645,85 @@ bool StaticTraitResolve::type_is_sized(const Span& sp, const ::HIR::TypeRef& ty) ) throw ""; } +bool StaticTraitResolve::type_is_impossible(const Span& sp, const ::HIR::TypeRef& ty) const +{ + TU_MATCH_HDRA( (ty.m_data), {) + break; + default: + return false; + TU_ARMA(Diverge, _e) + return true; + TU_ARMA(Path, e) { + TU_MATCHA( (e.binding), (pbe), + (Unbound, + // BUG? + return false; + ), + (Opaque, + // TODO: This can only be with UfcsKnown, so check if the trait specifies ?Sized + return false; + ), + (Struct, + const auto& params = e.path.m_data.as_Generic().m_params; + // TODO: Check all fields, if one flags this, then it's impossible. + const auto& str = *pbe; + TU_MATCH_HDRA( (str.m_data), {) + TU_ARMA(Unit, e) + return false; + TU_ARMA(Tuple, e) { + for(const auto& fld : e) + { + const auto& tpl = fld.ent; + ::HIR::TypeRef tmp; + const auto& ty = (monomorphise_type_needed(tpl) ? tmp = monomorphise_type_with(sp, tpl, monomorphise_type_get_cb(sp, nullptr, ¶ms, nullptr)) : tpl); + if( type_is_impossible(sp, ty) ) + return true; + } + return false; + } + TU_ARMA(Named, e) + for(const auto& fld : e) + { + TODO(sp, "type_is_impossible for struct " << ty << " - " << fld.second.ent); + } + } + ), + (Enum, + // TODO: Check all variants. + TODO(sp, "type_is_impossible for enum " << ty); + ), + (Union, + // TODO: Check all variants? Or just one? + TODO(sp, "type_is_impossible for union " << ty); + ) + ) + return true; + } + TU_ARMA(Borrow, e) + return type_is_impossible(sp, *e.inner); + TU_ARMA(Pointer, e) { + return false; + //return type_is_impossible(sp, *e.inner); + } + TU_ARMA(Function, e) { + // TODO: Check all arguments? + return true; + } + TU_ARMA(Array, e) { + return type_is_impossible(sp, *e.inner); + } + TU_ARMA(Slice, e) { + return type_is_impossible(sp, *e.inner); + } + TU_ARMA(Tuple, e) { + for(const auto& ty : e) + if( type_is_impossible(sp, ty) ) + return true; + return false; + } + } + throw ""; +} bool StaticTraitResolve::can_unsize(const Span& sp, const ::HIR::TypeRef& dst_ty, const ::HIR::TypeRef& src_ty) const { diff --git a/src/hir_typeck/static.hpp b/src/hir_typeck/static.hpp index ae429a3f..f764f8f7 100644 --- a/src/hir_typeck/static.hpp +++ b/src/hir_typeck/static.hpp @@ -184,6 +184,7 @@ public: bool type_is_copy(const Span& sp, const ::HIR::TypeRef& ty) const; bool type_is_clone(const Span& sp, const ::HIR::TypeRef& ty) const; // 1.29 bool type_is_sized(const Span& sp, const ::HIR::TypeRef& ty) const; + bool type_is_impossible(const Span& sp, const ::HIR::TypeRef& ty) const; bool can_unsize(const Span& sp, const ::HIR::TypeRef& dst, const ::HIR::TypeRef& src) const; /// Returns `true` if the passed type either implements Drop, or contains a type that implements Drop diff --git a/src/mir/cleanup.cpp b/src/mir/cleanup.cpp index 1a15ea22..f3e987d6 100644 --- a/src/mir/cleanup.cpp +++ b/src/mir/cleanup.cpp @@ -214,8 +214,8 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const MIR::TypeResolve& state, con TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te), ( if( path == ::HIR::GenericPath() ) - MIR_TODO(state, "Literal of type " << ty << " - " << path << " - " << lit); - DEBUG("Unknown type " << ty << " - Return BorrowOf"); + MIR_TODO(state, "Literal of type " << ty << " - " << lit); + DEBUG("Unknown type " << ty << ", but a path was provided - Return ItemAddr " << path); return ::MIR::Constant( mv$(path) ); ), (Tuple, @@ -454,6 +454,11 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const MIR::TypeResolve& state, con else { MIR_TODO(state, "Const with type " << ty); } + ), + (Function, + //MIR_TODO(state, "Const function pointer " << lit << " w/ type " << ty); + MIR_ASSERT(state, lit.is_BorrowPath(), ""); + return ::MIR::Constant::make_ItemAddr( lit.as_BorrowPath().clone() ); ) ) } diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index 38d00a5a..2c45f5bb 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -207,22 +207,22 @@ namespace { allow_refutable = 2; } - TU_MATCHA( (pat.m_data), (e), - (Any, - ), - (Box, + TU_MATCH_HDRA( (pat.m_data), {) + TU_ARMA(Any, e) { + } + TU_ARMA(Box, e) { destructure_from_ex(sp, *e.sub, ::MIR::LValue::make_Deref({ box$( mv$(lval) ) }), allow_refutable); - ), - (Ref, + } + TU_ARMA(Ref, e) { destructure_from_ex(sp, *e.sub, ::MIR::LValue::make_Deref({ box$( mv$(lval) ) }), allow_refutable); - ), - (Tuple, + } + TU_ARMA(Tuple, e) { for(unsigned int i = 0; i < e.sub_patterns.size(); i ++ ) { destructure_from_ex(sp, e.sub_patterns[i], ::MIR::LValue::make_Field({ box$( lval.clone() ), i}), allow_refutable); } - ), - (SplitTuple, + } + TU_ARMA(SplitTuple, e) { assert(e.total_size >= e.leading.size() + e.trailing.size()); for(unsigned int i = 0; i < e.leading.size(); i ++ ) { @@ -234,17 +234,17 @@ namespace { { destructure_from_ex(sp, e.trailing[i], ::MIR::LValue::make_Field({ box$( lval.clone() ), ofs+i}), allow_refutable); } - ), - (StructValue, + } + TU_ARMA(StructValue, e) { // Nothing. - ), - (StructTuple, + } + TU_ARMA(StructTuple, e) { for(unsigned int i = 0; i < e.sub_patterns.size(); i ++ ) { destructure_from_ex(sp, e.sub_patterns[i], ::MIR::LValue::make_Field({ box$( lval.clone() ), i}), allow_refutable); } - ), - (Struct, + } + TU_ARMA(Struct, e) { const auto& str = *e.binding; const auto& fields = str.m_data.as_Named(); for(const auto& fld_pat : e.sub_patterns) @@ -252,31 +252,48 @@ namespace { unsigned idx = ::std::find_if( fields.begin(), fields.end(), [&](const auto&x){ return x.first == fld_pat.first; } ) - fields.begin(); destructure_from_ex(sp, fld_pat.second, ::MIR::LValue::make_Field({ box$( lval.clone() ), idx}), allow_refutable); } - ), + } // Refutable - (Value, + TU_ARMA(Value, e) { ASSERT_BUG(sp, allow_refutable, "Refutable pattern not expected - " << pat); - ), - (Range, + } + TU_ARMA(Range, e) { ASSERT_BUG(sp, allow_refutable, "Refutable pattern not expected - " << pat); - ), - (EnumValue, + } + TU_ARMA(EnumValue, e) { const auto& enm = *e.binding_ptr; if( enm.num_variants() > 1 ) { ASSERT_BUG(sp, allow_refutable, "Refutable pattern not expected - " << pat); } - ), - (EnumTuple, + } + TU_ARMA(EnumTuple, e) { const auto& enm = *e.binding_ptr; - ASSERT_BUG(sp, enm.num_variants() == 1 || allow_refutable, "Refutable pattern not expected - " << pat); + const auto& variants = enm.m_data.as_Data(); + // TODO: Check that this is the only non-impossible arm + if( !allow_refutable ) + { + for(size_t i = 0; i < variants.size(); i ++) + { + const auto& var_ty = variants[i].type; + if( i == e.binding_idx ) { + continue; + } + ::HIR::TypeRef tmp; + const auto& ty = (monomorphise_type_needed(var_ty) ? tmp = monomorphise_type_with(sp, var_ty, monomorphise_type_get_cb(sp, nullptr, &e.path.m_params, nullptr)) : var_ty); + if( m_builder.resolve().type_is_impossible(sp, ty) ) { + continue; + } + ERROR(sp, E0000, "Variant " << variants[i].name << " not handled"); + } + } auto lval_var = ::MIR::LValue::make_Downcast({ box$(mv$(lval)), e.binding_idx }); for(unsigned int i = 0; i < e.sub_patterns.size(); i ++ ) { destructure_from_ex(sp, e.sub_patterns[i], ::MIR::LValue::make_Field({ box$( lval_var.clone() ), i}), allow_refutable); } - ), - (EnumStruct, + } + TU_ARMA(EnumStruct, e) { const auto& enm = *e.binding_ptr; ASSERT_BUG(sp, enm.num_variants() == 1 || allow_refutable, "Refutable pattern not expected - " << pat); ASSERT_BUG(sp, enm.m_data.is_Data(), "Expected struct variant - " << pat); @@ -289,8 +306,8 @@ namespace { unsigned idx = ::std::find_if( fields.begin(), fields.end(), [&](const auto&x){ return x.first == fld_pat.first; } ) - fields.begin(); destructure_from_ex(sp, fld_pat.second, ::MIR::LValue::make_Field({ box$( lval_var.clone() ), idx}), allow_refutable); } - ), - (Slice, + } + TU_ARMA(Slice, e) { // These are only refutable if T is [T] bool ty_is_array = false; m_builder.with_val_type(sp, lval, [&ty_is_array](const auto& ty){ @@ -316,8 +333,8 @@ namespace { destructure_from_ex(sp, subpat, ::MIR::LValue::make_Field({ box$(lval.clone()), i }), allow_refutable ); } } - ), - (SplitSlice, + } + TU_ARMA(SplitSlice, e) { // These are only refutable if T is [T] bool ty_is_array = false; unsigned int array_size = 0; @@ -412,8 +429,8 @@ namespace { } } } - ) - ) + } + } // TU_MATCH_HDRA } // -- ExprVisitor diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 8bbbd033..0f2cd636 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -2730,6 +2730,7 @@ namespace { // Emit a call to box_free for the type ::HIR::GenericPath box_free { m_crate.get_lang_item_path(sp, "box_free"), { ity->clone() } }; // TODO: This is specific to the official liballoc's owned_box + // TODO: Shared logic with Box drop glue above. m_of << indent << Trans_Mangle(box_free) << "("; emit_lvalue(e.slot); m_of << "._0._0._0);\n"; } else -- cgit v1.2.3 From e8401bfcea28bef9151aea9a8bd9b1c2789b5f79 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 29 Dec 2018 14:55:15 +0800 Subject: Codegen C - Handle 1.29 box_free calling convention (hack) --- src/trans/codegen_c.cpp | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 0f2cd636..c6f072fd 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -856,6 +856,26 @@ namespace { } } + void emit_box_drop(unsigned indent_level, const ::HIR::TypeRef& inner_type, const ::MIR::LValue& slot, bool run_destructor) + { + auto indent = RepeatLitStr { "\t", static_cast(indent_level) }; + // Emit a call to box_free for the type + if( run_destructor ) + { + auto inner_ptr = ::HIR::TypeRef::new_pointer( ::HIR::BorrowType::Unique, inner_type.clone() ); + m_of << indent; emit_ctype(inner_ptr, FMT_CB(ss, ss << "i"; )); m_of << " = "; emit_lvalue(slot); m_of << "._0._0._0;\n"; + emit_destructor_call( ::MIR::LValue::make_Local(~0u), inner_type, true, indent_level ); + } + // TODO: This is specific to the official liballoc's owned_box + ::HIR::GenericPath box_free { m_crate.get_lang_item_path(sp, "box_free"), { inner_type.clone() } }; + if( TARGETVER_1_29 ) { + // In 1.29, `box_free` takes Unique, so pass the Unique within the Box + m_of << indent << Trans_Mangle(box_free) << "("; emit_lvalue(slot); m_of << "._0);\n"; + } + else { + m_of << indent << Trans_Mangle(box_free) << "("; emit_lvalue(slot); m_of << "._0._0._0);\n"; + } + } void emit_box_drop_glue(::HIR::GenericPath p, const ::HIR::Struct& item) { auto struct_ty = ::HIR::TypeRef( p.clone(), &item ); @@ -875,13 +895,7 @@ namespace { m_mir_res = &mir_res; m_of << "static void " << Trans_Mangle(drop_glue_path) << "(struct s_" << Trans_Mangle(p) << "* rv) {\n"; - // Obtain inner pointer - // TODO: This is very specific to the structure of the official liballoc's Box. - m_of << "\t"; emit_ctype(args[0].second, FMT_CB(ss, ss << "arg0"; )); m_of << " = rv->_0._0._0;\n"; - // Call destructor of inner data - emit_destructor_call( ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Argument({0})) }), *ity, true, 1); - // Emit a call to box_free for the type - m_of << "\t" << Trans_Mangle(box_free) << "(arg0);\n"; + emit_box_drop(1, *ity, ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Return({})) }), /*run_destructor=*/true); m_of << "}\n"; m_mir_res = nullptr; @@ -1068,6 +1082,7 @@ namespace { ::MIR::Function empty_fcn; ::MIR::TypeResolve top_mir_res { sp, m_resolve, FMT_CB(ss, ss << "struct " << p;), ::HIR::TypeRef(), {}, empty_fcn }; m_mir_res = &top_mir_res; + // TODO: repr(transparent) and repr(align(foo)) bool is_packed = item.m_repr == ::HIR::Struct::Repr::Packed; TRACE_FUNCTION_F(p); @@ -2727,11 +2742,7 @@ namespace { // Shallow drops are only valid on owned_box if( const auto* ity = m_resolve.is_type_owned_box(ty) ) { - // Emit a call to box_free for the type - ::HIR::GenericPath box_free { m_crate.get_lang_item_path(sp, "box_free"), { ity->clone() } }; - // TODO: This is specific to the official liballoc's owned_box - // TODO: Shared logic with Box drop glue above. - m_of << indent << Trans_Mangle(box_free) << "("; emit_lvalue(e.slot); m_of << "._0._0._0);\n"; + emit_box_drop(1, *ity, e.slot, /*run_destructor=*/false); } else { -- cgit v1.2.3 From 28a48cfe2fde578219de5e15268348897c73b0d7 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 29 Dec 2018 15:00:52 +0800 Subject: HIR - Add new struct reprs (mostly stubbed) - Also cleared out some dead code in target.cpp --- src/hir/deserialise.cpp | 3 +- src/hir/from_ast.cpp | 23 ++++---- src/hir/hir.cpp | 15 ++++++ src/hir/hir.hpp | 4 ++ src/hir/serialise.cpp | 1 + src/trans/target.cpp | 136 ++---------------------------------------------- src/trans/target.hpp | 13 ----- 7 files changed, 37 insertions(+), 158 deletions(-) diff --git a/src/hir/deserialise.cpp b/src/hir/deserialise.cpp index afce2fe4..9ce063b4 100644 --- a/src/hir/deserialise.cpp +++ b/src/hir/deserialise.cpp @@ -995,11 +995,12 @@ default: throw ""; } + auto align = static_cast(m_in.read_u64c()); auto markings = deserialise_markings(); auto str_markings = deserialise_str_markings(); return ::HIR::Struct { - mv$(params), repr, mv$(data), mv$(markings), mv$(str_markings) + mv$(params), repr, mv$(data), align, mv$(markings), mv$(str_markings) }; } ::HIR::Trait HirDeserialiser::deserialise_trait() diff --git a/src/hir/from_ast.cpp b/src/hir/from_ast.cpp index f5d841a7..23e722f4 100644 --- a/src/hir/from_ast.cpp +++ b/src/hir/from_ast.cpp @@ -894,31 +894,32 @@ namespace { const auto& repr_str = a.name(); if( repr_str == "C" ) { ASSERT_BUG(a.span(), a.has_noarg(), "#[repr] attribute malformed, " << *attr_repr); - ASSERT_BUG(a.span(), rv.m_repr == ::HIR::Struct::Repr::Rust, "Conflicting #[repr] attributes"); - rv.m_repr = ::HIR::Struct::Repr::C; + if( rv.m_repr != ::HIR::Struct::Repr::Packed ) + { + ASSERT_BUG(a.span(), rv.m_repr == ::HIR::Struct::Repr::Rust, "Conflicting #[repr] attributes - " << rv.m_repr << ", " << repr_str); + rv.m_repr = ::HIR::Struct::Repr::C; + } } else if( repr_str == "packed" ) { ASSERT_BUG(a.span(), a.has_noarg(), "#[repr] attribute malformed, " << *attr_repr); - ASSERT_BUG(a.span(), rv.m_repr == ::HIR::Struct::Repr::Rust, "Conflicting #[repr] attributes"); + ASSERT_BUG(a.span(), rv.m_repr == ::HIR::Struct::Repr::Rust || rv.m_repr == ::HIR::Struct::Repr::C, "Conflicting #[repr] attributes - " << rv.m_repr << ", " << repr_str); rv.m_repr = ::HIR::Struct::Repr::Packed; } else if( repr_str == "simd" ) { ASSERT_BUG(a.span(), a.has_noarg(), "#[repr] attribute malformed, " << *attr_repr); - ASSERT_BUG(a.span(), rv.m_repr == ::HIR::Struct::Repr::Rust, "Conflicting #[repr] attributes"); + ASSERT_BUG(a.span(), rv.m_repr == ::HIR::Struct::Repr::Rust, "Conflicting #[repr] attributes - " << rv.m_repr << ", " << repr_str); rv.m_repr = ::HIR::Struct::Repr::Simd; } else if( repr_str == "transparent" ) { ASSERT_BUG(a.span(), a.has_noarg(), "#[repr] attribute malformed, " << *attr_repr); - ASSERT_BUG(a.span(), rv.m_repr == ::HIR::Struct::Repr::Rust, "Conflicting #[repr] attributes"); - // TODO: Mark so the C backend knows that it's supposed to be transparent - //rv.m_repr = ::HIR::Struct::Repr::Transparent; + ASSERT_BUG(a.span(), rv.m_repr == ::HIR::Struct::Repr::Rust, "Conflicting #[repr] attributes - " << rv.m_repr << ", " << repr_str); + rv.m_repr = ::HIR::Struct::Repr::Transparent; } else if( repr_str == "align" ) { //ASSERT_BUG(a.span(), a.has_string(), "#[repr(aligned)] attribute malformed, " << *attr_repr); - ASSERT_BUG(a.span(), rv.m_repr == ::HIR::Struct::Repr::Rust, "Conflicting #[repr] attributes"); - // TODO: Alignment repr - //rv.m_repr = ::HIR::Struct::Repr::Aligned; - //rv.m_align_size = ::std::stol(a.string()); + ASSERT_BUG(a.span(), rv.m_repr == ::HIR::Struct::Repr::Rust, "Conflicting #[repr] attributes - " << rv.m_repr << ", " << repr_str); + rv.m_repr = ::HIR::Struct::Repr::Aligned; + //rv.m_forced_alignment = ::std::stol(a.string()); } else { TODO(a.span(), "Handle struct repr '" << repr_str << "'"); diff --git a/src/hir/hir.cpp b/src/hir/hir.cpp index 475928a1..bd396df9 100644 --- a/src/hir/hir.cpp +++ b/src/hir/hir.cpp @@ -93,6 +93,21 @@ namespace HIR { ) return true; } + + ::std::ostream& operator<<(::std::ostream& os, const Struct::Repr& x) { + os << "repr("; + switch(x) + { + case Struct::Repr::Rust: os << "Rust"; break; + case Struct::Repr::C: os << "C"; break; + case Struct::Repr::Packed: os << "packed"; break; + case Struct::Repr::Simd: os << "simd"; break; + case Struct::Repr::Aligned: os << "align(?)"; break; + case Struct::Repr::Transparent: os << "transparent"; break; + } + os << ")"; + return os; + } } size_t HIR::Enum::find_variant(const ::std::string& name) const diff --git a/src/hir/hir.hpp b/src/hir/hir.hpp index 33200e96..fc4a19e8 100644 --- a/src/hir/hir.hpp +++ b/src/hir/hir.hpp @@ -267,6 +267,8 @@ public: C, Packed, Simd, + Aligned, // Alignment stored elsewhere + Transparent, }; TAGGED_UNION(Data, Unit, (Unit, struct {}), @@ -277,10 +279,12 @@ public: GenericParams m_params; Repr m_repr; Data m_data; + unsigned m_forced_alignment = 0; TraitMarkings m_markings; StructMarkings m_struct_markings; }; +extern ::std::ostream& operator<<(::std::ostream& os, const Struct::Repr& x); class Union { public: diff --git a/src/hir/serialise.cpp b/src/hir/serialise.cpp index 50da4453..c3a27998 100644 --- a/src/hir/serialise.cpp +++ b/src/hir/serialise.cpp @@ -975,6 +975,7 @@ ) ) + m_out.write_u64c(item.m_forced_alignment); serialise(item.m_markings); serialise(item.m_struct_markings); } diff --git a/src/trans/target.cpp b/src/trans/target.cpp index 121a9134..dccc566d 100644 --- a/src/trans/target.cpp +++ b/src/trans/target.cpp @@ -517,139 +517,6 @@ void Target_SetCfg(const ::std::string& target_name) }); } -namespace { - // Returns NULL when the repr can't be determined - ::std::unique_ptr make_struct_repr(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty) - { - TRACE_FUNCTION_F(ty); - ::std::vector ents; - bool packed = false; - bool allow_sort = false; - if( const auto* te = ty.m_data.opt_Path() ) - { - const auto& str = *te->binding.as_Struct(); - auto monomorph_cb = monomorphise_type_get_cb(sp, nullptr, &te->path.m_data.as_Generic().m_params, nullptr); - auto monomorph = [&](const auto& tpl) { - auto rv = monomorphise_type_with(sp, tpl, monomorph_cb); - resolve.expand_associated_types(sp, rv); - return rv; - }; - TU_MATCHA( (str.m_data), (se), - (Unit, - ), - (Tuple, - unsigned int idx = 0; - for(const auto& e : se) - { - auto ty = monomorph(e.ent); - size_t size, align; - if( !Target_GetSizeAndAlignOf(sp, resolve, ty, size,align) ) - return nullptr; - if( size == SIZE_MAX ) - BUG(sp, "Unsized type in tuple struct"); - ents.push_back(StructRepr::Ent { idx++, size, align, mv$(ty) }); - } - ), - (Named, - unsigned int idx = 0; - for(const auto& e : se) - { - auto ty = monomorph(e.second.ent); - size_t size, align; - if( !Target_GetSizeAndAlignOf(sp, resolve, ty, size,align) ) - return nullptr; - if( size == SIZE_MAX ) - BUG(sp, "Unsized type in struct"); - ents.push_back(StructRepr::Ent { idx++, size, align, mv$(ty) }); - } - ) - ) - switch(str.m_repr) - { - case ::HIR::Struct::Repr::Packed: - packed = true; - TODO(sp, "make_struct_repr - repr(packed)"); // needs codegen to know to pack the structure - break; - case ::HIR::Struct::Repr::Simd: - case ::HIR::Struct::Repr::C: - // No sorting, no packing - break; - case ::HIR::Struct::Repr::Rust: - allow_sort = true; - break; - } - } - else if( const auto* te = ty.m_data.opt_Tuple() ) - { - unsigned int idx = 0; - for(const auto& t : *te) - { - size_t size, align; - if( !Target_GetSizeAndAlignOf(sp, resolve, t, size,align) ) - return nullptr; - if( size == SIZE_MAX ) - BUG(sp, "Unsized type in tuple"); - ents.push_back(StructRepr::Ent { idx++, size, align, t.clone() }); - } - } - else - { - BUG(sp, "Unexpected type in creating struct repr"); - } - - - if( allow_sort ) - { - // TODO: Sort by alignment then size (largest first) - // - Requires codegen to use this information - } - - StructRepr rv; - size_t cur_ofs = 0; - size_t max_align = 1; - for(auto& e : ents) - { - // Increase offset to fit alignment - if( !packed ) - { - while( cur_ofs % e.align != 0 ) - { - rv.ents.push_back({ ~0u, 1, 1, ::HIR::TypeRef( ::HIR::CoreType::U8 ) }); - cur_ofs ++; - } - } - max_align = ::std::max(max_align, e.align); - - rv.ents.push_back(mv$(e)); - cur_ofs += e.size; - } - if( !packed ) - { - while( cur_ofs % max_align != 0 ) - { - rv.ents.push_back({ ~0u, 1, 1, ::HIR::TypeRef( ::HIR::CoreType::U8 ) }); - cur_ofs ++; - } - } - return box$(rv); - } -} -const StructRepr* Target_GetStructRepr(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty) -{ - // TODO: Thread safety - // Map of generic paths to struct representations. - static ::std::map<::HIR::TypeRef, ::std::unique_ptr> s_cache; - - auto it = s_cache.find(ty); - if( it != s_cache.end() ) - { - return it->second.get(); - } - - auto ires = s_cache.insert(::std::make_pair( ty.clone(), make_struct_repr(sp, resolve, ty) )); - return ires.first->second.get(); -} - bool Target_GetSizeAndAlignOf(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty, size_t& out_size, size_t& out_align) { TRACE_FUNCTION_FR(ty, "size=" << out_size << ", align=" << out_align); @@ -904,6 +771,9 @@ namespace { case ::HIR::Struct::Repr::Simd: // No sorting, no packing break; + case ::HIR::Struct::Repr::Aligned: + // TODO: Update the minimum alignment + case ::HIR::Struct::Repr::Transparent: case ::HIR::Struct::Repr::Rust: allow_sort = true; break; diff --git a/src/trans/target.hpp b/src/trans/target.hpp index b1ed9456..107d19e1 100644 --- a/src/trans/target.hpp +++ b/src/trans/target.hpp @@ -48,18 +48,6 @@ struct TargetSpec TargetArch m_arch; }; -struct StructRepr -{ - struct Ent { - unsigned int field_idx; - size_t size; - size_t align; - ::HIR::TypeRef ty; - }; - // List of types, including padding (indicated by a UINT_MAX field idx) - // Ordered as they would be emitted - ::std::vector ents; -}; struct TypeRepr { size_t align = 0; @@ -107,7 +95,6 @@ extern void Target_ExportCurSpec(const ::std::string& filename); extern bool Target_GetSizeOf(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty, size_t& out_size); extern bool Target_GetAlignOf(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty, size_t& out_align); extern bool Target_GetSizeAndAlignOf(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty, size_t& out_size, size_t& out_align); -extern const StructRepr* Target_GetStructRepr(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& struct_ty); extern const TypeRepr* Target_GetTypeRepr(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty); -- cgit v1.2.3 From 33e23617276a6fd91cba8f3e223cb9bdc8b023bd Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 29 Dec 2018 15:19:01 +0800 Subject: HIR Serialise - Make error reporting for bad deserialisation more consistent --- src/hir/deserialise.cpp | 73 ++++++++++++++++++++++++------------------------- 1 file changed, 35 insertions(+), 38 deletions(-) diff --git a/src/hir/deserialise.cpp b/src/hir/deserialise.cpp index 9ce063b4..30f88843 100644 --- a/src/hir/deserialise.cpp +++ b/src/hir/deserialise.cpp @@ -270,7 +270,7 @@ case ::MacroPatEnt::PAT_ITEM: break; default: - throw ""; + BUG(Span(), "Bad tag for MacroPatEnt - #" << static_cast(rv.type) << " " << rv.type); } return rv; } @@ -282,7 +282,7 @@ return rv; } ::MacroExpansionEnt deserialise_macroexpansionent() { - switch(m_in.read_tag()) + switch(auto tag = m_in.read_tag()) { case 0: return ::MacroExpansionEnt( deserialise_token() ); @@ -305,7 +305,7 @@ }); } default: - throw ""; + BUG(Span(), "Bad tag for MacroExpansionEnt - " << tag); } } @@ -331,7 +331,7 @@ return ::Token::Data::make_Float({ dty, m_in.read_double() }); } default: - throw ::std::runtime_error(FMT("Invalid Token data tag - " << tag)); + BUG(Span(), "Bad tag for Token::Data - " << static_cast(tag)); } } @@ -362,7 +362,7 @@ case ::MIR::Param::TAG_LValue: return deserialise_mir_lvalue(); case ::MIR::Param::TAG_Constant: return deserialise_mir_constant(); default: - throw ::std::runtime_error(FMT("Invalid MIR LValue tag - " << tag)); + BUG(Span(), "Bad tag for MIR::Param - " << tag); } } ::MIR::LValue deserialise_mir_lvalue() { @@ -395,14 +395,14 @@ } ) #undef _ default: - throw ::std::runtime_error(FMT("Invalid MIR LValue tag - " << tag)); + BUG(Span(), "Bad tag for MIR::LValue - " << tag); } } ::MIR::RValue deserialise_mir_rvalue() { TRACE_FUNCTION; - switch( m_in.read_tag() ) + switch(auto tag = m_in.read_tag()) { #define _(x, ...) case ::MIR::RValue::TAG_##x: return ::MIR::RValue::make_##x( __VA_ARGS__ ); _(Use, deserialise_mir_lvalue() ) @@ -456,14 +456,14 @@ }) #undef _ default: - throw ""; + BUG(Span(), "Bad tag for MIR::RValue - " << tag); } } ::MIR::Constant deserialise_mir_constant() { TRACE_FUNCTION; - switch( m_in.read_tag() ) + switch(auto tag = m_in.read_tag()) { #define _(x, ...) case ::MIR::Constant::TAG_##x: DEBUG("- " #x); return ::MIR::Constant::make_##x( __VA_ARGS__ ); _(Int, { @@ -492,13 +492,13 @@ _(ItemAddr, deserialise_path() ) #undef _ default: - throw ""; + BUG(Span(), "Bad tag for MIR::Const - " << tag); } } ::HIR::TypeItem deserialise_typeitem() { - switch( m_in.read_tag() ) + switch(auto tag = m_in.read_tag()) { case 0: { auto spath = deserialise_simplepath(); @@ -518,12 +518,12 @@ case 6: return ::HIR::TypeItem( deserialise_union() ); default: - throw ""; + BUG(Span(), "Bad tag for HIR::TypeItem - " << tag); } } ::HIR::ValueItem deserialise_valueitem() { - switch( m_in.read_tag() ) + switch(auto tag = m_in.read_tag()) { case 0: { auto spath = deserialise_simplepath(); @@ -541,7 +541,7 @@ case 5: return ::HIR::ValueItem::make_StructConstructor({ deserialise_simplepath() }); default: - throw ""; + BUG(Span(), "Bad tag for HIR::ValueItem - " << tag); } } @@ -655,7 +655,7 @@ ::HIR::TraitValueItem deserialise_traitvalueitem() { - switch( m_in.read_tag() ) + switch(auto tag = m_in.read_tag()) { #define _(x, ...) case ::HIR::TraitValueItem::TAG_##x: DEBUG("- " #x); return ::HIR::TraitValueItem::make_##x( __VA_ARGS__ ); break; _(Constant, deserialise_constant() ) @@ -663,8 +663,7 @@ _(Function, deserialise_function() ) #undef _ default: - DEBUG("Invalid TraitValueItem tag"); - throw ""; + BUG(Span(), "Bad tag for HIR::TraitValueItem - " << tag); } } ::HIR::AssociatedType deserialise_associatedtype() @@ -798,7 +797,7 @@ }) #undef _ default: - throw ::std::runtime_error(FMT("Bad TypeRef tag - " << tag)); + BUG(Span(), "Bad tag for HIR::TypeRef - " << tag); } return rv; } @@ -843,7 +842,7 @@ ::HIR::Path HirDeserialiser::deserialise_path() { TRACE_FUNCTION; - switch( m_in.read_tag() ) + switch(auto tag = m_in.read_tag()) { case 0: DEBUG("Generic"); @@ -865,7 +864,7 @@ deserialise_pathparams() } ); default: - throw ""; + BUG(Span(), "Bad tag for HIR::Path - " << tag); } } @@ -891,7 +890,7 @@ } ::HIR::GenericBound HirDeserialiser::deserialise_genericbound() { - switch( m_in.read_tag() ) + switch(auto tag = m_in.read_tag()) { case 0: return ::HIR::GenericBound::make_Lifetime({}); @@ -908,8 +907,7 @@ deserialise_type() }); default: - DEBUG("Bad GenericBound tag"); - throw ""; + BUG(Span(), "Bad tag for HIR::GenericBound - " << tag); } } @@ -918,7 +916,7 @@ TRACE_FUNCTION; struct H { static ::HIR::Enum::Class deserialise_enumclass(HirDeserialiser& des) { - switch( des.m_in.read_tag() ) + switch( auto tag = des.m_in.read_tag() ) { case ::HIR::Enum::Class::TAG_Data: return ::HIR::Enum::Class::make_Data( des.deserialise_vec<::HIR::Enum::DataVariant>() ); @@ -928,7 +926,7 @@ des.deserialise_vec<::HIR::Enum::ValueVariant>() }); default: - throw ""; + BUG(Span(), "Bad tag for HIR::Enum::Class - " << tag); } } }; @@ -978,7 +976,7 @@ DEBUG("params = " << params.fmt_args() << params.fmt_bounds()); ::HIR::Struct::Data data; - switch( m_in.read_tag() ) + switch( auto tag = m_in.read_tag() ) { case ::HIR::Struct::Data::TAG_Unit: DEBUG("Unit"); @@ -993,7 +991,7 @@ data = ::HIR::Struct::Data( deserialise_vec< ::std::pair< ::std::string, ::HIR::VisEnt< ::HIR::TypeRef> > >() ); break; default: - throw ""; + BUG(Span(), "Bad tag for HIR::Struct::Data - " << tag); } auto align = static_cast(m_in.read_u64c()); auto markings = deserialise_markings(); @@ -1023,7 +1021,7 @@ ::HIR::Literal HirDeserialiser::deserialise_literal() { - switch( m_in.read_tag() ) + switch( auto tag = m_in.read_tag() ) { #define _(x, ...) case ::HIR::Literal::TAG_##x: return ::HIR::Literal::make_##x(__VA_ARGS__); _(Invalid, {}) @@ -1039,7 +1037,7 @@ _(String, m_in.read_string() ) #undef _ default: - throw ""; + BUG(Span(), "Unknown literal when deserialising - " << tag); } } @@ -1069,7 +1067,7 @@ { TRACE_FUNCTION; - switch( m_in.read_tag() ) + switch( auto tag = m_in.read_tag() ) { case 0: return ::MIR::Statement::make_Assign({ @@ -1102,8 +1100,7 @@ deserialise_vec() }); default: - ::std::cerr << "Bad tag for a MIR Statement" << ::std::endl; - throw ""; + BUG(Span(), "Bad tag for MIR::Statement - " << tag); } } ::MIR::Terminator HirDeserialiser::deserialise_mir_terminator() @@ -1115,7 +1112,7 @@ } ::MIR::Terminator HirDeserialiser::deserialise_mir_terminator_() { - switch( m_in.read_tag() ) + switch( auto tag = m_in.read_tag() ) { #define _(x, ...) case ::MIR::Terminator::TAG_##x: return ::MIR::Terminator::make_##x( __VA_ARGS__ ); _(Incomplete, {}) @@ -1147,13 +1144,13 @@ }) #undef _ default: - throw ""; + BUG(Span(), "Bad tag for MIR::Terminator - " << tag); } } ::MIR::SwitchValues HirDeserialiser::deserialise_mir_switchvalues() { TRACE_FUNCTION; - switch(m_in.read_tag()) + switch(auto tag = m_in.read_tag()) { #define _(x, ...) case ::MIR::SwitchValues::TAG_##x: return ::MIR::SwitchValues::make_##x( __VA_ARGS__ ); _(Unsigned, deserialise_vec_c([&](){ return m_in.read_u64c(); })) @@ -1161,13 +1158,13 @@ _(String , deserialise_vec<::std::string>()) #undef _ default: - throw ""; + BUG(Span(), "Bad tag for MIR::SwitchValues - " << tag); } } ::MIR::CallTarget HirDeserialiser::deserialise_mir_calltarget() { - switch( m_in.read_tag() ) + switch(auto tag = m_in.read_tag()) { #define _(x, ...) case ::MIR::CallTarget::TAG_##x: return ::MIR::CallTarget::make_##x( __VA_ARGS__ ); _(Value, deserialise_mir_lvalue() ) @@ -1178,7 +1175,7 @@ }) #undef _ default: - throw ""; + BUG(Span(), "Bad tag for MIR::CallTarget - " << tag); } } -- cgit v1.2.3 From be45bb67e1cbcb3c68cdf6f5c9353ce98c67ee2e Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 29 Dec 2018 15:24:12 +0800 Subject: HIR Deserialise - Handle :vis macro fragment --- src/hir/deserialise.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hir/deserialise.cpp b/src/hir/deserialise.cpp index 30f88843..70ff1a34 100644 --- a/src/hir/deserialise.cpp +++ b/src/hir/deserialise.cpp @@ -268,6 +268,7 @@ case ::MacroPatEnt::PAT_BLOCK: case ::MacroPatEnt::PAT_META: case ::MacroPatEnt::PAT_ITEM: + case ::MacroPatEnt::PAT_VIS: break; default: BUG(Span(), "Bad tag for MacroPatEnt - #" << static_cast(rv.type) << " " << rv.type); -- cgit v1.2.3 From cdedfd8738aa488f7b87fd65ac8ab160c0947b18 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 29 Dec 2018 16:55:27 +0800 Subject: Resolve/HIR - Rough handling of `pub use macro_path;` --- src/ast/ast.hpp | 8 +++++++- src/expand/derive.cpp | 6 +++--- src/expand/macro_rules.cpp | 4 ++-- src/expand/mod.cpp | 2 +- src/hir/from_ast.cpp | 19 +++++++++++++++++++ src/resolve/index.cpp | 20 ++++++++++++++++++-- 6 files changed, 50 insertions(+), 9 deletions(-) diff --git a/src/ast/ast.hpp b/src/ast/ast.hpp index 2d802f53..b80b5fb7 100644 --- a/src/ast/ast.hpp +++ b/src/ast/ast.hpp @@ -537,7 +537,13 @@ public: // List of macros imported from other modules (via #[macro_use], includes proc macros) // - First value is an absolute path to the macro (including crate name) - ::std::vector<::std::pair< ::std::vector<::std::string>, const MacroRules* >> m_macro_imports; + struct MacroImport { + bool is_pub; + ::std::string name; // Can be different, if `use foo as bar` is used + ::std::vector<::std::string> path; // includes the crate name + const MacroRules* macro_ptr; + }; + ::std::vector m_macro_imports; public: Module() {} diff --git a/src/expand/derive.cpp b/src/expand/derive.cpp index 5e97c888..a03992da 100644 --- a/src/expand/derive.cpp +++ b/src/expand/derive.cpp @@ -2236,15 +2236,15 @@ static void derive_item(const Span& sp, const AST::Crate& crate, AST::Module& mo bool found = false; for(const auto& mac_path : mod.m_macro_imports) { - if( mac_path.first.back() == mac_name ) + if( mac_path.name == mac_name ) { - if( mac_path.second ) { + if( mac_path.macro_ptr ) { // macro_rules! based derive? TODO(sp, "Custom derive using macro_rules?"); } else { // proc_macro - Invoke the handler. - auto lex = ProcMacro_Invoke(sp, crate, mac_path.first, path.nodes().back().name(), item); + auto lex = ProcMacro_Invoke(sp, crate, mac_path.path, path.nodes().back().name(), item); if( lex ) { Parse_ModRoot_Items(*lex, mod); diff --git a/src/expand/macro_rules.cpp b/src/expand/macro_rules.cpp index 89f394e1..3bacfcf7 100644 --- a/src/expand/macro_rules.cpp +++ b/src/expand/macro_rules.cpp @@ -61,8 +61,8 @@ class CMacroUseHandler: }); for(const auto& p : ec.m_hir->m_proc_macros) { - mod.m_macro_imports.push_back(::std::make_pair( p.path.m_components, nullptr )); - mod.m_macro_imports.back().first.insert( mod.m_macro_imports.back().first.begin(), p.path.m_crate_name ); + mod.m_macro_imports.push_back({ false, p.path.m_components.back(), p.path.m_components, nullptr }); + mod.m_macro_imports.back().path.insert( mod.m_macro_imports.back().path.begin(), p.path.m_crate_name ); } } ) diff --git a/src/expand/mod.cpp b/src/expand/mod.cpp index 34c47455..4dfd1224 100644 --- a/src/expand/mod.cpp +++ b/src/expand/mod.cpp @@ -1044,7 +1044,7 @@ void Expand_Mod(::AST::Crate& crate, LList modstack, ::AST:: } } for( const auto& mi: mod.m_macro_imports ) - DEBUG("- Imports '" << mi.first << "'"); + DEBUG("- Imports '" << mi.path << "'"); } // Insert prelude if: Enabled for this module, present for the crate, and this module is not an anon diff --git a/src/hir/from_ast.cpp b/src/hir/from_ast.cpp index 23e722f4..49e5a4b6 100644 --- a/src/hir/from_ast.cpp +++ b/src/hir/from_ast.cpp @@ -1803,6 +1803,25 @@ public: } } } + for( const auto& mac : crate.m_root_module.m_macro_imports ) + { + if( mac.is_pub ) + { + // TODO: Why does this to such a move? + auto v = ::std::make_pair( mac.name, MacroRulesPtr(new MacroRules( mv$(*const_cast(mac.macro_ptr)) )) ); + + auto it = macros.find(mac.name); + if( it == macros.end() ) + { + auto res = macros.insert( mv$(v) ); + DEBUG("- Import " << mac.name << "! (from \"" << res.first->second->m_source_crate << "\")"); + } + else { + DEBUG("- Replace " << mac.name << "! (from \"" << it->second->m_source_crate << "\") with one from \"" << v.second->m_source_crate << "\""); + it->second = mv$( v.second ); + } + } + } } // - Proc Macros if( crate.m_crate_type == ::AST::Crate::Type::ProcMacro ) diff --git a/src/resolve/index.cpp b/src/resolve/index.cpp index bbcd7e58..48f2d0da 100644 --- a/src/resolve/index.cpp +++ b/src/resolve/index.cpp @@ -212,7 +212,7 @@ void Resolve_Index_Module_Base(const AST::Crate& crate, AST::Module& mod) _add_item_type(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); }} // - Values - TU_MATCH_HDRA( (i_data.path.m_bindings.value), {) + {TU_MATCH_HDRA( (i_data.path.m_bindings.value), {) TU_ARMA(Unbound, _e) { DEBUG(i.name << " - Not a value"); } @@ -226,7 +226,23 @@ void Resolve_Index_Module_Base(const AST::Crate& crate, AST::Module& mod) _add_item_value(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); TU_ARMA(Function, e) _add_item_value(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); - } + }} + // - Macros + {TU_MATCH_HDRA( (i_data.path.m_bindings.macro), {) + TU_ARMA(Unbound, _e) { + DEBUG(i.name << " - Not a macro"); + } + TU_ARMA(MacroRules, e) { + ::std::vector<::std::string> path; + path.push_back( i_data.path.m_class.as_Absolute().crate ); + for(const auto& node : i_data.path.m_class.as_Absolute().nodes ) + path.push_back( node.name() ); + mod.m_macro_imports.push_back({ + i.is_pub, i.name, mv$(path), e.mac + }); + } + // TODO: Other imports (e.g. derives, which have different naming structures) + }} } else { -- cgit v1.2.3 From 7c5411ea0aedeabb879efe5654ed0e28039a4b78 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 29 Dec 2018 18:28:51 +0800 Subject: Typecheck Expressions - Fallback mode when inferrence stalls with match ergonomics --- src/hir_typeck/expr_cs.cpp | 122 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 101 insertions(+), 21 deletions(-) diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index e8e0f65c..04cb6f17 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -37,7 +37,7 @@ struct Context { public: virtual void fmt(::std::ostream& os) const = 0; - virtual bool revisit(Context& context) = 0; + virtual bool revisit(Context& context, bool is_fallback) = 0; }; struct Binding @@ -3790,24 +3790,26 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T void fmt(::std::ostream& os) const override { os << "MatchErgonomicsRevisit { " << m_pattern << " : " << m_outer_ty << " }"; } - bool revisit(Context& context) override { - TRACE_FUNCTION_F("Match ergonomics - " << m_pattern << " : " << m_outer_ty); - return this->revisit_inner(context, m_pattern, m_outer_ty, m_outer_mode); + bool revisit(Context& context, bool is_fallback_mode) override { + TRACE_FUNCTION_F("Match ergonomics - " << m_pattern << " : " << m_outer_ty << (is_fallback_mode ? " (fallback)": "")); + return this->revisit_inner_real(context, m_pattern, m_outer_ty, m_outer_mode, is_fallback_mode); } // TODO: Recurse into inner patterns, creating new revisitors? // - OR, could just recurse on it. // // Recusring incurs costs on every iteration, but is less expensive the first time around // New revisitors are cheaper when inferrence takes multiple iterations, but takes longer first time. - bool revisit_inner(Context& context, ::HIR::Pattern& pattern, const ::HIR::TypeRef& type, ::HIR::PatternBinding::Type binding_mode) const { - if( !revisit_inner_real(context, pattern, type, binding_mode) ) + bool revisit_inner(Context& context, ::HIR::Pattern& pattern, const ::HIR::TypeRef& type, ::HIR::PatternBinding::Type binding_mode) const + { + if( !revisit_inner_real(context, pattern, type, binding_mode, false) ) { DEBUG("Add revisit for " << pattern << " : " << type << "(mode = " << (int)binding_mode << ")"); context.add_revisit_adv( box$(( MatchErgonomicsRevisit { sp, type.clone(), pattern, binding_mode } )) ); } return true; } - bool revisit_inner_real(Context& context, ::HIR::Pattern& pattern, const ::HIR::TypeRef& type, ::HIR::PatternBinding::Type binding_mode) const { + bool revisit_inner_real(Context& context, ::HIR::Pattern& pattern, const ::HIR::TypeRef& type, ::HIR::PatternBinding::Type binding_mode, bool is_fallback) const + { TRACE_FUNCTION_F(pattern << " : " << type); // Binding applies to the raw input type (not after dereferencing) @@ -3837,7 +3839,72 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T DEBUG("- " << n_deref << " derefs of class " << bt << " to get " << *ty_p); if( ty_p->m_data.is_Infer() ) { // Still pure infer, can't do anything - // - What if it's an literal? + // - What if it's a literal? + + if( n_deref == 0 && is_fallback ) + { + ::HIR::TypeRef possible_type; + // TODO: Get a potential type from the pattern, and set as a possibility. + // - Note, this is only if no derefs were applied + TU_MATCH_HDR( (pattern.m_data), { ) + TU_ARM(pattern.m_data, Any, pe) { + // No type information. + } + TU_ARM(pattern.m_data, Value, pe) { + // TODO: Get type info + } + TU_ARM(pattern.m_data, Range, pe) { + // TODO: Get type info (same as Value) + } + TU_ARM(pattern.m_data, Box, pe) { + // TODO: Get type info (Box<_>) + } + TU_ARM(pattern.m_data, Ref, pe) { + BUG(sp, "Match ergonomics - & pattern"); + } + TU_ARM(pattern.m_data, Tuple, e) { + // TODO: Get type info `(T, U, ...)` + } + TU_ARM(pattern.m_data, SplitTuple, pe) { + // Can't get type information, tuple size is unkown + } + TU_ARM(pattern.m_data, Slice, e) { + // Can be either a [T] or [T; n]. Can't provide a hint + } + TU_ARM(pattern.m_data, SplitSlice, pe) { + // Can be either a [T] or [T; n]. Can't provide a hint + } + TU_ARM(pattern.m_data, StructValue, e) { + context.add_ivars_params( e.path.m_params ); + possible_type = ::HIR::TypeRef::new_path(e.path.clone(), ::HIR::TypeRef::TypePathBinding(e.binding)); + } + TU_ARM(pattern.m_data, StructTuple, e) { + context.add_ivars_params( e.path.m_params ); + possible_type = ::HIR::TypeRef::new_path(e.path.clone(), ::HIR::TypeRef::TypePathBinding(e.binding)); + } + TU_ARM(pattern.m_data, Struct, e) { + context.add_ivars_params( e.path.m_params ); + possible_type = ::HIR::TypeRef::new_path(e.path.clone(), ::HIR::TypeRef::TypePathBinding(e.binding)); + } + TU_ARM(pattern.m_data, EnumValue, e) { + context.add_ivars_params( e.path.m_params ); + possible_type = ::HIR::TypeRef::new_path(get_parent_path(e.path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)); + } + TU_ARM(pattern.m_data, EnumTuple, e) { + context.add_ivars_params( e.path.m_params ); + possible_type = ::HIR::TypeRef::new_path(get_parent_path(e.path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)); + } + TU_ARM(pattern.m_data, EnumStruct, e) { + context.add_ivars_params( e.path.m_params ); + possible_type = ::HIR::TypeRef::new_path(get_parent_path(e.path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)); + } + } + if( possible_type != ::HIR::TypeRef() ) + { + DEBUG("Possible equate " << possible_type); + context.equate_types( sp, *ty_p, possible_type ); + } + } // TODO: Visit all inner bindings and disable coercion fallbacks on them. MatchErgonomicsRevisit::disable_possibilities_on_bindings(sp, context, pattern); @@ -4360,7 +4427,7 @@ void Context::handle_pattern_direct_inner(const Span& sp, ::HIR::Pattern& pat, c void fmt(::std::ostream& os) const override { os << "SplitTuplePatRevisit { " << m_outer_ty << " = (" << m_leading_tys << ", ..., " << m_trailing_tys << ") }"; } - bool revisit(Context& context) override { + bool revisit(Context& context, bool is_fallback) override { const auto& ty = context.get_type(m_outer_ty); TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Infer, te, return false; @@ -4414,7 +4481,7 @@ void Context::handle_pattern_direct_inner(const Span& sp, ::HIR::Pattern& pat, c {} void fmt(::std::ostream& os) const override { os << "SlicePatRevisit { " << inner << ", " << type << ", " << size; } - bool revisit(Context& context) override { + bool revisit(Context& context, bool is_fallback) override { const auto& ty = context.get_type(type); TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Slice, te, context.equate_types(sp, *te.inner, inner); @@ -4489,7 +4556,7 @@ void Context::handle_pattern_direct_inner(const Span& sp, ::HIR::Pattern& pat, c {} void fmt(::std::ostream& os) const override { os << "SplitSlice inner=" << inner << ", outer=" << type << ", binding="<type); if( ty.m_data.is_Infer() ) return false; @@ -6881,12 +6948,6 @@ namespace { static Span _span; const auto& sp = _span; - if( ! ivar_ent.has_rules() ) { - // No rules, don't do anything (and don't print) - DEBUG(i << ": No rules"); - return false; - } - if( honour_disable && (ivar_ent.force_no_to || ivar_ent.force_no_from) ) { DEBUG(i << ": forced unknown"); @@ -6898,9 +6959,18 @@ namespace { const auto& ty_l = context.m_ivars.get_type(ty_l_ivar); if( ty_l != ty_l_ivar ) { - DEBUG("- IVar " << i << " had possibilities, but was known to be " << ty_l); - // Completely clear by reinitialising - ivar_ent = Context::IVarPossible(); + if( ivar_ent.has_rules() ) + { + DEBUG("- IVar " << i << " had possibilities, but was known to be " << ty_l); + // Completely clear by reinitialising + ivar_ent = Context::IVarPossible(); + } + return false; + } + + if( ! ivar_ent.has_rules() ) { + // No rules, don't do anything (and don't print) + DEBUG(i << ": No rules"); return false; } @@ -7096,7 +7166,7 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR: for(size_t i = 0; i < len; i ++) { auto& ent = *context.adv_revisits[i]; - adv_revisit_remove_list.push_back( ent.revisit(context) ); + adv_revisit_remove_list.push_back( ent.revisit(context, /*is_fallback=*/false) ); } for(size_t i = len; i --;) { @@ -7234,6 +7304,16 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR: } } // `if peek_changed` (ivar possibilities #2) + if( !context.m_ivars.peek_changed() ) + { + size_t len = context.adv_revisits.size(); + for(size_t i = 0; i < len; i ++) + { + auto& ent = *context.adv_revisits[i]; + ent.revisit(context, /*is_fallback=*/true); + } + } + // Finally. If nothing changed, apply ivar defaults if( !context.m_ivars.peek_changed() ) { -- cgit v1.2.3 From 3c81276f5f8e6ba385dbe01d7aee9405a2bac350 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 29 Dec 2018 19:32:45 +0800 Subject: Typecheck/Trans - Handle magic clone impls for 1.29 --- src/hir_typeck/helpers.cpp | 196 +++++++++++++++++++++++++-------------------- src/hir_typeck/helpers.hpp | 2 + src/trans/enumerate.cpp | 6 +- 3 files changed, 116 insertions(+), 88 deletions(-) diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index f3604917..3ff39c63 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -1120,6 +1120,107 @@ bool TraitResolution::iterate_aty_bounds(const Span& sp, const ::HIR::Path::Data return false; } +bool TraitResolution::find_trait_impls_magic(const Span& sp, + const ::HIR::SimplePath& trait, const ::HIR::PathParams& params, + const ::HIR::TypeRef& ty, + t_cb_trait_impl_r callback + ) const +{ + static ::HIR::PathParams null_params; + static ::std::map< ::std::string, ::HIR::TypeRef> null_assoc; + + const auto& lang_Sized = this->m_crate.get_lang_item_path(sp, "sized"); + const auto& lang_Copy = this->m_crate.get_lang_item_path(sp, "copy"); + //const auto& lang_Clone = this->m_crate.get_lang_item_path(sp, "clone"); + const auto& lang_Unsize = this->m_crate.get_lang_item_path(sp, "unsize"); + const auto& lang_CoerceUnsized = this->m_crate.get_lang_item_path(sp, "coerce_unsized"); + + const auto& type = this->m_ivars.get_type(ty); + TRACE_FUNCTION_F("trait = " << trait << params << ", type = " << type); + + if( trait == lang_Sized ) { + auto cmp = type_is_sized(sp, type); + if( cmp != ::HIR::Compare::Unequal ) { + return callback( ImplRef(&type, &null_params, &null_assoc), cmp ); + } + else { + return false; + } + } + + if( trait == lang_Copy ) { + auto cmp = this->type_is_copy(sp, type); + if( cmp != ::HIR::Compare::Unequal ) { + return callback( ImplRef(&type, &null_params, &null_assoc), cmp ); + } + else { + return false; + } + } + + if( TARGETVER_1_29 && trait == this->m_crate.get_lang_item_path(sp, "clone") ) + { + auto cmp = this->type_is_clone(sp, type); + if( cmp != ::HIR::Compare::Unequal ) { + return callback( ImplRef(&type, &null_params, &null_assoc), cmp ); + } + else { + return false; + } + } + + // Magic Unsize impls to trait objects + if( trait == lang_Unsize ) + { + ASSERT_BUG(sp, params.m_types.size() == 1, "Unsize trait requires a single type param"); + const auto& dst_ty = this->m_ivars.get_type(params.m_types[0]); + + if( find_trait_impls_bound(sp, trait, params, type, callback) ) + return true; + + bool rv = false; + auto cb = [&](auto new_dst) { + ::HIR::PathParams real_params { mv$(new_dst) }; + rv = callback( ImplRef(type.clone(), mv$(real_params), {}), ::HIR::Compare::Fuzzy ); + }; + //if( dst_ty.m_data.is_Infer() || type.m_data.is_Infer() ) + //{ + // rv = callback( ImplRef(type.clone(), params.clone(), {}), ::HIR::Compare::Fuzzy ); + // return rv; + //} + auto cmp = this->can_unsize(sp, dst_ty, type, cb); + if( cmp == ::HIR::Compare::Equal ) + { + assert(!rv); + rv = callback( ImplRef(type.clone(), params.clone(), {}), ::HIR::Compare::Equal ); + } + return rv; + } + + // Magical CoerceUnsized impls for various types + if( trait == lang_CoerceUnsized ) { + const auto& dst_ty = params.m_types.at(0); + // - `*mut T => *const T` + TU_IFLET( ::HIR::TypeRef::Data, type.m_data, Pointer, e, + TU_IFLET( ::HIR::TypeRef::Data, dst_ty.m_data, Pointer, de, + if( de.type < e.type ) { + auto cmp = e.inner->compare_with_placeholders(sp, *de.inner, this->m_ivars.callback_resolve_infer()); + if( cmp != ::HIR::Compare::Unequal ) + { + ::HIR::PathParams pp; + pp.m_types.push_back( dst_ty.clone() ); + if( callback( ImplRef(type.clone(), mv$(pp), {}), cmp ) ) { + return true; + } + } + } + ) + ) + } + + return false; +} + bool TraitResolution::find_trait_impls(const Span& sp, const ::HIR::SimplePath& trait, const ::HIR::PathParams& params, const ::HIR::TypeRef& ty, @@ -1143,11 +1244,6 @@ bool TraitResolution::find_trait_impls(const Span& sp, } #endif - const auto& lang_Sized = this->m_crate.get_lang_item_path(sp, "sized"); - const auto& lang_Copy = this->m_crate.get_lang_item_path(sp, "copy"); - //const auto& lang_Clone = this->m_crate.get_lang_item_path(sp, "clone"); - const auto& lang_Unsize = this->m_crate.get_lang_item_path(sp, "unsize"); - const auto& lang_CoerceUnsized = this->m_crate.get_lang_item_path(sp, "coerce_unsized"); const auto& trait_fn = this->m_crate.get_lang_item_path(sp, "fn"); const auto& trait_fn_mut = this->m_crate.get_lang_item_path(sp, "fn_mut"); const auto& trait_fn_once = this->m_crate.get_lang_item_path(sp, "fn_once"); @@ -1156,35 +1252,8 @@ bool TraitResolution::find_trait_impls(const Span& sp, if( magic_trait_impls ) { - if( trait == lang_Sized ) { - auto cmp = type_is_sized(sp, type); - if( cmp != ::HIR::Compare::Unequal ) { - return callback( ImplRef(&type, &null_params, &null_assoc), cmp ); - } - else { - return false; - } - } - - if( trait == lang_Copy ) { - auto cmp = this->type_is_copy(sp, type); - if( cmp != ::HIR::Compare::Unequal ) { - return callback( ImplRef(&type, &null_params, &null_assoc), cmp ); - } - else { - return false; - } - } - - if( TARGETVER_1_29 && trait == this->m_crate.get_lang_item_path(sp, "clone") ) - { - auto cmp = this->type_is_clone(sp, type); - if( cmp != ::HIR::Compare::Unequal ) { - return callback( ImplRef(&type, &null_params, &null_assoc), cmp ); - } - else { - return false; - } + if( find_trait_impls_magic(sp, trait, params, ty, callback) ) { + return true; } } @@ -1468,58 +1537,6 @@ bool TraitResolution::find_trait_impls(const Span& sp, } ) - if( magic_trait_impls ) - { - // Magic Unsize impls to trait objects - if( trait == lang_Unsize ) - { - ASSERT_BUG(sp, params.m_types.size() == 1, "Unsize trait requires a single type param"); - const auto& dst_ty = this->m_ivars.get_type(params.m_types[0]); - - if( find_trait_impls_bound(sp, trait, params, type, callback) ) - return true; - - bool rv = false; - auto cb = [&](auto new_dst) { - ::HIR::PathParams real_params { mv$(new_dst) }; - rv = callback( ImplRef(type.clone(), mv$(real_params), {}), ::HIR::Compare::Fuzzy ); - }; - //if( dst_ty.m_data.is_Infer() || type.m_data.is_Infer() ) - //{ - // rv = callback( ImplRef(type.clone(), params.clone(), {}), ::HIR::Compare::Fuzzy ); - // return rv; - //} - auto cmp = this->can_unsize(sp, dst_ty, type, cb); - if( cmp == ::HIR::Compare::Equal ) - { - assert(!rv); - rv = callback( ImplRef(type.clone(), params.clone(), {}), ::HIR::Compare::Equal ); - } - return rv; - } - - // Magical CoerceUnsized impls for various types - if( trait == lang_CoerceUnsized ) { - const auto& dst_ty = params.m_types.at(0); - // - `*mut T => *const T` - TU_IFLET( ::HIR::TypeRef::Data, type.m_data, Pointer, e, - TU_IFLET( ::HIR::TypeRef::Data, dst_ty.m_data, Pointer, de, - if( de.type < e.type ) { - auto cmp = e.inner->compare_with_placeholders(sp, *de.inner, this->m_ivars.callback_resolve_infer()); - if( cmp != ::HIR::Compare::Unequal ) - { - ::HIR::PathParams pp; - pp.m_types.push_back( dst_ty.clone() ); - if( callback( ImplRef(type.clone(), mv$(pp), {}), cmp ) ) { - return true; - } - } - } - ) - ) - } - } - // 1. Search generic params if( find_trait_impls_bound(sp, trait, params, type, callback) ) return true; @@ -4169,7 +4186,12 @@ bool TraitResolution::find_method(const Span& sp, bool magic_found = false; bool crate_impl_found = false; - // NOTE: THis just detects the presence of a trait impl, not the specifics + + crate_impl_found = find_trait_impls_magic(sp, *trait_ref.first, trait_params, self_ty, [&](auto impl, auto cmp) { + return true; + }); + + // NOTE: This just detects the presence of a trait impl, not the specifics find_trait_impls_crate(sp, *trait_ref.first, &trait_params, self_ty, [&](auto impl, auto cmp) { DEBUG("[find_method] " << impl << ", cmp = " << cmp); magic_found = true; diff --git a/src/hir_typeck/helpers.hpp b/src/hir_typeck/helpers.hpp index cb95c94f..fcd17cfb 100644 --- a/src/hir_typeck/helpers.hpp +++ b/src/hir_typeck/helpers.hpp @@ -225,6 +225,8 @@ public: } /// Search for a trait implementation in the crate (allows nullptr to ignore params) bool find_trait_impls_crate(const Span& sp, const ::HIR::SimplePath& trait, const ::HIR::PathParams* params, const ::HIR::TypeRef& type, t_cb_trait_impl_r callback) const; + /// Check for magic (automatically determined) trait implementations + bool find_trait_impls_magic(const Span& sp, const ::HIR::SimplePath& trait, const ::HIR::PathParams& params, const ::HIR::TypeRef& type, t_cb_trait_impl_r callback) const; private: ::HIR::Compare check_auto_trait_impl_destructure(const Span& sp, const ::HIR::SimplePath& trait, const ::HIR::PathParams* params_ptr, const ::HIR::TypeRef& type) const; diff --git a/src/trans/enumerate.cpp b/src/trans/enumerate.cpp index ce3eb53a..a94e302c 100644 --- a/src/trans/enumerate.cpp +++ b/src/trans/enumerate.cpp @@ -1376,7 +1376,11 @@ void Trans_Enumerate_FillFrom_Path(EnumState& state, const ::HIR::Path& path, co // Must have been a dynamic dispatch request, just leave as-is } // - ::call* - else if( path_mono.m_data.is_UfcsKnown() && path_mono.m_data.as_UfcsKnown().type->m_data.is_Function() ) + else if( path_mono.m_data.is_UfcsKnown() && path_mono.m_data.as_UfcsKnown().type->m_data.is_Function() && ( + path_mono.m_data.as_UfcsKnown().trait.m_path == state.crate.get_lang_item_path_opt("fn") + || path_mono.m_data.as_UfcsKnown().trait.m_path == state.crate.get_lang_item_path_opt("fn_mut") + || path_mono.m_data.as_UfcsKnown().trait.m_path == state.crate.get_lang_item_path_opt("fn_once") + ) ) { // Must have been a dynamic dispatch request, just leave as-is } -- cgit v1.2.3 From 4ed6aa06c15bf4d96f855c2508c0bed545b5b06b Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 29 Dec 2018 20:01:46 +0800 Subject: Trans Enumerate - Handle 1.29 having generics on `lang_start` --- src/trans/enumerate.cpp | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/trans/enumerate.cpp b/src/trans/enumerate.cpp index a94e302c..06ca92a3 100644 --- a/src/trans/enumerate.cpp +++ b/src/trans/enumerate.cpp @@ -63,21 +63,25 @@ TransList Trans_Enumerate_Main(const ::HIR::Crate& crate) auto c_start_path = crate.get_lang_item_path_opt("mrustc-start"); if( c_start_path == ::HIR::SimplePath() ) { + // user entrypoint + auto main_path = crate.get_lang_item_path(Span(), "mrustc-main"); + const auto& main_fcn = crate.get_function_by_path(sp, main_path); + + state.enum_fcn( main_path, main_fcn, {} ); + // "start" language item // - Takes main, and argc/argv as arguments { auto start_path = crate.get_lang_item_path(sp, "start"); const auto& fcn = crate.get_function_by_path(sp, start_path); - state.enum_fcn( start_path, fcn, {} ); - } - - // user entrypoint - { - auto main_path = crate.get_lang_item_path(Span(), "mrustc-main"); - const auto& fcn = crate.get_function_by_path(sp, main_path); - - state.enum_fcn( main_path, fcn, {} ); + Trans_Params lang_start_pp; + if( TARGETVER_1_29 ) + { + // With 1.29, this now takes main's return type as a type parameter + lang_start_pp.pp_method.m_types.push_back( main_fcn.m_return.clone() ); + } + state.enum_fcn( start_path, fcn, mv$(lang_start_pp) ); } } else -- cgit v1.2.3 From 73261b9520fb7c3003b435fbc5f28613b4aff390 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 29 Dec 2018 20:02:05 +0800 Subject: Misc - Fix script overrides for std (was using windows), remove absent test helper --- Makefile | 5 ++++- script-overrides/stable-1.29.0-linux/build_std.txt | 10 +++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index e7c4dc1f..29a8e39e 100644 --- a/Makefile +++ b/Makefile @@ -153,7 +153,10 @@ output/libtest.hir output/libpanic_unwind.hir output/libproc_macro.hir: output/l output/rustc output/cargo: output/libtest.hir $(MAKE_MINICARGO) $@ -TEST_DEPS := output/libstd.hir output/libtest.hir output/libpanic_unwind.hir output/librust_test_helpers.a +TEST_DEPS := output/libstd.hir output/libtest.hir output/libpanic_unwind.hir +ifeq ($(RUSTC_VERSION),1.19.0) +TEST_DEPS += output/librust_test_helpers.a +endif fcn_extcrate = $(patsubst %,output/lib%.hir,$(1)) diff --git a/script-overrides/stable-1.29.0-linux/build_std.txt b/script-overrides/stable-1.29.0-linux/build_std.txt index 062afd95..e88dd227 100644 --- a/script-overrides/stable-1.29.0-linux/build_std.txt +++ b/script-overrides/stable-1.29.0-linux/build_std.txt @@ -1,5 +1,5 @@ -# TODO: THis is the windows set -cargo:rustc-link-lib=advapi32 -cargo:rustc-link-lib=ws2_32 -cargo:rustc-link-lib=userenv -cargo:rustc-link-lib=shell32 \ No newline at end of file +# TODO: Build libbacktrace +cargo:rustc-link-lib=dl +cargo:rustc-link-lib=rt +cargo:rustc-link-lib=pthread + -- cgit v1.2.3 From aa3e514294a257fb5821533dfbfd02467cf0c9d0 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 30 Dec 2018 07:24:24 +0800 Subject: expand assert - Fix logic error --- src/expand/assert.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/expand/assert.cpp b/src/expand/assert.cpp index 1c057935..5bb23bde 100644 --- a/src/expand/assert.cpp +++ b/src/expand/assert.cpp @@ -31,6 +31,7 @@ class CExpander_assert: ::std::vector toks; toks.push_back( Token(TOK_RWORD_IF) ); + toks.push_back( Token(TOK_EXCLAM) ); GET_TOK(tok, lex); if( tok == TOK_COMMA ) -- cgit v1.2.3 From e0353e87cda89f33c665e05963d6fd7893972063 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 30 Dec 2018 07:34:53 +0800 Subject: Typecheck - Don't drop ManuallyDrop --- src/hir_typeck/static.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/hir_typeck/static.cpp b/src/hir_typeck/static.cpp index d40ee811..c9e2bae9 100644 --- a/src/hir_typeck/static.cpp +++ b/src/hir_typeck/static.cpp @@ -1928,6 +1928,12 @@ bool StaticTraitResolve::type_needs_drop_glue(const Span& sp, const ::HIR::TypeR if( e.binding.is_Opaque() ) return true; + // In 1.29, "manually_drop" is a struct with special behaviour (instead of being a union) + if( TARGETVER_1_29 && e.path.m_data.as_Generic().m_path == m_crate.get_lang_item_path_opt("manually_drop") ) + { + return false; + } + auto pp = ::HIR::PathParams(); bool has_direct_drop = this->find_impl(sp, m_lang_Drop, &pp, ty, [&](auto , bool){ return true; }, true); if( has_direct_drop ) -- cgit v1.2.3 From 6fb11a5af19b91557dba1ca853599596622f56df Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 30 Dec 2018 07:36:38 +0800 Subject: Codegen C - Add hacky compiler-provided glue --- src/main.cpp | 2 ++ src/trans/allocator.cpp | 19 +++-------- src/trans/allocator.hpp | 10 ++---- src/trans/codegen_c.cpp | 85 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 94 insertions(+), 22 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 1af432b2..782e043f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -638,6 +638,8 @@ int main(int argc, char *argv[]) crate_type = ::AST::Crate::Type::Executable; } + // TODO: For 1.29 executables/dylibs, add oom/panic shims + // Enumerate items to be passed to codegen TransList items = CompilePhase("Trans Enumerate", [&]() { switch( crate_type ) diff --git a/src/trans/allocator.cpp b/src/trans/allocator.cpp index 5f61093d..9f5559ae 100644 --- a/src/trans/allocator.cpp +++ b/src/trans/allocator.cpp @@ -12,25 +12,14 @@ #define DEF_METHOD(name, ret) { #name, AllocatorDataTy::ret, sizeof(ALLOCATOR_METHODS_ARGS_##name)/sizeof(AllocatorDataTy), ALLOCATOR_METHODS_ARGS_##name } DEF_METHOD_ARGS(alloc, AllocatorDataTy::Layout) -DEF_METHOD_ARGS(oom, AllocatorDataTy::AllocError) DEF_METHOD_ARGS(dealloc, AllocatorDataTy::Ptr, AllocatorDataTy::Layout) -DEF_METHOD_ARGS(usable_size, AllocatorDataTy::LayoutRef) -DEF_METHOD_ARGS(realloc, AllocatorDataTy::Ptr, AllocatorDataTy::Layout, AllocatorDataTy::Layout) +DEF_METHOD_ARGS(realloc, AllocatorDataTy::Ptr, AllocatorDataTy::Layout, AllocatorDataTy::Usize) DEF_METHOD_ARGS(alloc_zeroed, AllocatorDataTy::Layout) -DEF_METHOD_ARGS(alloc_excess, AllocatorDataTy::Layout) -DEF_METHOD_ARGS(realloc_excess, AllocatorDataTy::Ptr, AllocatorDataTy::Layout, AllocatorDataTy::Layout) -DEF_METHOD_ARGS(grow_in_place, AllocatorDataTy::Ptr, AllocatorDataTy::Layout, AllocatorDataTy::Layout) -DEF_METHOD_ARGS(shrink_in_place, AllocatorDataTy::Ptr, AllocatorDataTy::Layout, AllocatorDataTy::Layout) -const AllocatorMethod ALLOCATOR_METHODS[10] = { +const AllocatorMethod ALLOCATOR_METHODS[4] = { DEF_METHOD(alloc, ResultPtr), - DEF_METHOD(oom, Never), DEF_METHOD(dealloc, Unit), - DEF_METHOD(usable_size, UsizePair), DEF_METHOD(realloc, ResultPtr), - DEF_METHOD(alloc_zeroed, ResultPtr), - DEF_METHOD(alloc_excess, ResultExcess), - DEF_METHOD(realloc_excess, ResultExcess), - DEF_METHOD(grow_in_place, ResultUnit), - DEF_METHOD(shrink_in_place, ResultUnit) + DEF_METHOD(alloc_zeroed, ResultPtr) }; +const size_t NUM_ALLOCATOR_METHODS = sizeof(ALLOCATOR_METHODS)/sizeof(ALLOCATOR_METHODS[0]); diff --git a/src/trans/allocator.hpp b/src/trans/allocator.hpp index 8a4e5186..c124ef57 100644 --- a/src/trans/allocator.hpp +++ b/src/trans/allocator.hpp @@ -9,17 +9,12 @@ enum class AllocatorDataTy { // - Return - Never, // ! Unit, // () ResultPtr, // (..., *mut i8) + *mut u8 - ResultExcess, // (..., *mut i8, *mut i8) + *mut u8 - UsizePair, // (..., *mut usize, *mut usize) + () - ResultUnit, // i8 // - Args Layout, // usize, usize - LayoutRef, // *const Layout [actually *const i8] - AllocError, // *const i8 Ptr, // *mut u8 + Usize, // usize }; struct AllocatorMethod { const char* name; @@ -33,5 +28,6 @@ enum class AllocatorKind { DefaultExe, }; -extern const AllocatorMethod ALLOCATOR_METHODS[10]; +extern const AllocatorMethod ALLOCATOR_METHODS[]; +extern const size_t NUM_ALLOCATOR_METHODS; diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index c6f072fd..710300ce 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -639,6 +639,84 @@ namespace { << "__thread void* mrustc_panic_value;\n" ; } + + // Allocator shims + if( TARGETVER_1_29 ) + { + const char* alloc_prefix = "__rdl_"; + for(size_t i = 0; i < NUM_ALLOCATOR_METHODS; i++) + { + struct H { + static void ty_args(::std::vector& out, AllocatorDataTy t) { + switch(t) + { + case AllocatorDataTy::Unit: + case AllocatorDataTy::ResultPtr: // (..., *mut i8) + *mut u8 + throw ""; + // - Args + case AllocatorDataTy::Layout: // usize, usize + out.push_back("uintptr_t"); + out.push_back("uintptr_t"); + break; + case AllocatorDataTy::Ptr: // *mut u8 + out.push_back("int8_t*"); + break; + case AllocatorDataTy::Usize: + out.push_back("uintptr_t"); + break; + } + } + static const char* ty_ret(AllocatorDataTy t) { + switch(t) + { + case AllocatorDataTy::Unit: + return "void"; + case AllocatorDataTy::ResultPtr: // (..., *mut i8) + *mut u8 + return "int8_t*"; + // - Args + case AllocatorDataTy::Layout: // usize, usize + case AllocatorDataTy::Ptr: // *mut u8 + case AllocatorDataTy::Usize: + throw ""; + } + throw ""; + } + static void emit_proto(::std::ostream& os, const AllocatorMethod& method, const char* name_prefix, const ::std::vector& args) { + os << H::ty_ret(method.ret) << " " << name_prefix << method.name << "("; + for(size_t j = 0; j < args.size(); j ++) + { + if( j != 0 ) + os << ", "; + os << args[j] << " a" << j; + } + os << ")"; + } + }; + const auto& method = ALLOCATOR_METHODS[i]; + ::std::vector args; + for(size_t j = 0; j < method.n_args; j ++) + H::ty_args(args, method.args[j]); + H::emit_proto(m_of, method, "__rust_", args); m_of << " {\n"; + m_of << "\textern "; H::emit_proto(m_of, method, alloc_prefix, args); m_of << ";\n"; + m_of << "\t" << alloc_prefix << method.name << "("; + for(size_t j = 0; j < args.size(); j ++) + { + if( j != 0 ) + m_of << ", "; + m_of << "a" << j; + } + m_of << ");\n"; + m_of << "}\n"; + } + + // TODO: Bind `panic_impl` lang item to the item tagged with `panic_implementation` + // TODO: Bind `oom` lang item to the item tagged with `alloc_error_handler` + // - Can do this in enumerate/auto_impls instead, for better iteraction with enum + // XXX: HACK HACK HACK - This only works with libcore/libstd's current layout + m_of << "uint32_t panic_impl(uintptr_t payload) { extern uint32_t __rust_start_panic(uintptr_t payload); return __rust_start_panic(payload); }\n"; + m_of << "struct s__ZN4core5alloc6Layout_A { uintptr_t a, b; };\n"; + m_of << "void oom_impl(struct s__ZN4core5alloc6Layout_A l) { extern void _ZN3std5alloc8rust_oom(struct s__ZN4core5alloc6Layout_A l); _ZN3std5alloc8rust_oom(l); }\n"; + } } m_of.flush(); @@ -2189,6 +2267,13 @@ namespace { m_of << "}\n"; return; } + else if( item.m_linkage.name.rfind("llvm.", 0) == 0 ) + { + emit_function_header(p, item, params); + m_of << " { abort(); }\n"; + m_mir_res = nullptr; + return ; + } else { m_of << "extern "; -- cgit v1.2.3 From 8a1ed074f96357b32f8079aa30c5700bf4f51bd1 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 30 Dec 2018 08:06:11 +0800 Subject: Test harness - Fix harness for 1.29 --- src/expand/test_harness.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/expand/test_harness.cpp b/src/expand/test_harness.cpp index 204ca75e..f720cac7 100644 --- a/src/expand/test_harness.cpp +++ b/src/expand/test_harness.cpp @@ -81,6 +81,11 @@ void Expand_TestHarness(::AST::Crate& crate) } desc_vals.push_back({ {}, "should_panic", mv$(should_panic_val) }); } + if( TARGETVER_1_29 ) + { + // TODO: Get this from attributes + desc_vals.push_back({ {}, "allow_fail", NEWNODE(_Bool, false) }); + } auto desc_expr = NEWNODE(_StructLiteral, ::AST::Path("test", { ::AST::PathNode("TestDesc")}), nullptr, mv$(desc_vals)); ::AST::ExprNode_StructLiteral::t_values descandfn_vals; -- cgit v1.2.3 From c39ca5729eb2782e4286f3e582009e43482ebdc7 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 30 Dec 2018 09:45:13 +0800 Subject: Codegen C - Fix integer printing quirks --- src/trans/codegen_c.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 710300ce..2c40c991 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -1965,10 +1965,10 @@ namespace { break; case ::HIR::CoreType::U64: case ::HIR::CoreType::Usize: - m_of << ::std::hex << "0x" << e << ::std::dec; + m_of << ::std::hex << "0x" << e << "ull" << ::std::dec; break; case ::HIR::CoreType::U128: - m_of << ::std::hex << "0x" << e << ::std::dec; + m_of << ::std::hex << "0x" << e << "ull" << ::std::dec; break; case ::HIR::CoreType::I8: m_of << static_cast( static_cast(e) ); @@ -1982,7 +1982,7 @@ namespace { case ::HIR::CoreType::I64: case ::HIR::CoreType::I128: case ::HIR::CoreType::Isize: - m_of << static_cast(e); + m_of << static_cast(e) << "ll"; break; case ::HIR::CoreType::Char: assert(0 <= e && e <= 0x10FFFF); @@ -5629,6 +5629,16 @@ namespace { { switch(c.t) { + // TODO: These should already have been truncated/reinterpreted, but just in case. + case ::HIR::CoreType::I8: + m_of << static_cast( static_cast(c.v) ); // cast to int, because `int8_t` is printed as a `char` + break; + case ::HIR::CoreType::I16: + m_of << static_cast(c.v); + break; + case ::HIR::CoreType::I32: + m_of << static_cast(c.v); + break; case ::HIR::CoreType::I64: case ::HIR::CoreType::Isize: m_of << c.v; -- cgit v1.2.3 From c2af54e57545b55be1a5c32cfe4ffbc4b6e114a4 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 30 Dec 2018 10:35:38 +0800 Subject: MIR Optimise - constant evaluation: addition --- src/mir/optimise.cpp | 128 +++++++++++++++++++++++++++------------------------ 1 file changed, 69 insertions(+), 59 deletions(-) diff --git a/src/mir/optimise.cpp b/src/mir/optimise.cpp index 80bca08d..67a5d4a4 100644 --- a/src/mir/optimise.cpp +++ b/src/mir/optimise.cpp @@ -2219,75 +2219,85 @@ bool MIR_Optimise_ConstPropagte(::MIR::TypeResolve& state, ::MIR::Function& fcn) const auto& val_l = se.val_l.as_Constant(); const auto& val_r = se.val_r.as_Constant(); - ::MIR::Constant new_value; - bool replace = false; - switch(se.op) + if( val_l.is_Const() || val_r.is_Const() ) { - case ::MIR::eBinOp::EQ: - if( val_l.is_Const() || val_r.is_Const() ) - ; - else + } + else + { + struct H { + static int64_t truncate_s(::HIR::CoreType ct, int64_t v) { + return v; + } + static uint64_t truncate_u(::HIR::CoreType ct, uint64_t v) { + switch(ct) + { + case ::HIR::CoreType::U8: return v & 0xFF; + case ::HIR::CoreType::U16: return v & 0xFFFF; + case ::HIR::CoreType::U32: return v & 0xFFFFFFFF; + case ::HIR::CoreType::U64: return v; + case ::HIR::CoreType::U128: return v; + case ::HIR::CoreType::Usize: return v; + case ::HIR::CoreType::Char: + //MIR_BUG(state, "Invalid use of operator on char"); + break; + default: + // Invalid type for Uint literal + break; + } + return v; + } + }; + ::MIR::Constant new_value; + switch(se.op) { - replace = true; + case ::MIR::eBinOp::EQ: new_value = ::MIR::Constant::make_Bool({val_l == val_r}); - } - break; - case ::MIR::eBinOp::NE: - if( val_l.is_Const() || val_r.is_Const() ) - ; - else - { - replace = true; + break; + case ::MIR::eBinOp::NE: new_value = ::MIR::Constant::make_Bool({val_l != val_r}); - } - break; - case ::MIR::eBinOp::LT: - if( val_l.is_Const() || val_r.is_Const() ) - ; - else - { - replace = true; + break; + case ::MIR::eBinOp::LT: new_value = ::MIR::Constant::make_Bool({val_l < val_r}); - } - break; - case ::MIR::eBinOp::LE: - if( val_l.is_Const() || val_r.is_Const() ) - ; - else - { - replace = true; + break; + case ::MIR::eBinOp::LE: new_value = ::MIR::Constant::make_Bool({val_l <= val_r}); - } - break; - case ::MIR::eBinOp::GT: - if( val_l.is_Const() || val_r.is_Const() ) - ; - else - { - replace = true; + break; + case ::MIR::eBinOp::GT: new_value = ::MIR::Constant::make_Bool({val_l > val_r}); - } - break; - case ::MIR::eBinOp::GE: - if( val_l.is_Const() || val_r.is_Const() ) - ; - else - { - replace = true; + break; + case ::MIR::eBinOp::GE: new_value = ::MIR::Constant::make_Bool({val_l >= val_r}); + break; + + case ::MIR::eBinOp::ADD: + MIR_ASSERT(state, val_l.tag() == val_r.tag(), "Mismatched types for eBinOp::ADD - " << val_l << " + " << val_r); + //{TU_MATCH_HDRA( (val_l, val_r), {) + {TU_MATCH_HDRA( (val_l), {) + default: + break; + // TU_ARMav(Int, (le, re)) { + TU_ARMA(Int, le) { const auto& re = val_r.as_Int(); + MIR_ASSERT(state, le.t == re.t, "Mismatched types for eBinOp::ADD - " << val_l << " + " << val_r); + new_value = ::MIR::Constant::make_Int({ H::truncate_s(le.t, le.v + re.v) }); + } + TU_ARMA(Uint, le) { const auto& re = val_r.as_Uint(); + MIR_ASSERT(state, le.t == re.t, "Mismatched types for eBinOp::ADD - " << val_l << " + " << val_r); + new_value = ::MIR::Constant::make_Uint({ H::truncate_u(le.t, le.v + re.v) }); + } + }} + break; + // TODO: Other binary operations + // Could emit a TODO? + default: + break; } - break; - // TODO: Other binary operations - // Could emit a TODO? - default: - break; - } - if( replace ) - { - DEBUG(state << " " << e->src << " = " << new_value); - e->src = mv$(new_value); - changed = true; + if( new_value != ::MIR::Constant() ) + { + DEBUG(state << " " << e->src << " = " << new_value); + e->src = mv$(new_value); + changed = true; + } } } ), -- cgit v1.2.3 From bd64912c9847479800ba24c1e1fea7191197c591 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 30 Dec 2018 13:18:07 +0800 Subject: minicargo - Cleanup and planning for better `cfg()` handing --- tools/minicargo/Makefile | 2 +- tools/minicargo/cfg.cpp | 262 +++++++++++++++++++++++++++++++++++++++++++ tools/minicargo/cfg.hpp | 9 ++ tools/minicargo/manifest.cpp | 175 +---------------------------- 4 files changed, 278 insertions(+), 170 deletions(-) create mode 100644 tools/minicargo/cfg.cpp create mode 100644 tools/minicargo/cfg.hpp diff --git a/tools/minicargo/Makefile b/tools/minicargo/Makefile index 363ef4b9..862f6b3c 100644 --- a/tools/minicargo/Makefile +++ b/tools/minicargo/Makefile @@ -13,7 +13,7 @@ V ?= @ OBJDIR := .obj/ BIN := ../bin/minicargo$(EXESUF) -OBJS := main.o build.o manifest.o repository.o +OBJS := main.o build.o manifest.o repository.o cfg.o LINKFLAGS := -g -lpthread CXXFLAGS := -Wall -std=c++14 -g -O2 diff --git a/tools/minicargo/cfg.cpp b/tools/minicargo/cfg.cpp new file mode 100644 index 00000000..e8c732d8 --- /dev/null +++ b/tools/minicargo/cfg.cpp @@ -0,0 +1,262 @@ +/* + * mrustc "minicargo" (minimal cargo clone) + * - By John Hodge (Mutabah) + * + * cfg.cpp + * - Handling of target configuration (in manifest nodes) + */ +#include // cerr +#include "debug.h" +#include +#include +#include +#include +#include "cfg.hpp" + +// TODO: Extract this from the target at runtime (by invoking the compiler on the passed target) +#ifdef _WIN32 +//# define TARGET_NAME "i586-windows-msvc" +# define CFG_UNIX false +# define CFG_WINDOWS true +#elif defined(__NetBSD__) +//# define TARGET_NAME "x86_64-unknown-netbsd" +# define CFG_UNIX true +# define CFG_WINDOWS false +#else +//# define TARGET_NAME "x86_64-unknown-linux-gnu" +# define CFG_UNIX true +# define CFG_WINDOWS false +#endif + +class CfgParseLexer +{ +public: + class Tok + { + friend class CfgParseLexer; + public: + enum Type { + EndOfStream, + Operator, + Ident, + String, + }; + private: + Type m_ty; + const char* s; + const char* e; + ::std::string m_val; + Tok(): + m_ty(EndOfStream), s(nullptr),e(nullptr) + { + } + Tok(const char* s): + m_ty(Operator), s(s), e(s+1), m_val() + { + } + Tok(const char* s, const char* e): + m_ty(Ident), s(s), e(e), m_val() + { + } + Tok(const char* s, const char* e, ::std::string val): + m_ty(String), s(s), e(e), m_val(::std::move(val)) + { + } + public: + bool operator==(char c) const { + return (m_ty == Operator && *s == c); + } + bool operator!=(char c) const { return !(*this == c); } + bool operator==(const char* v) const { + return strlen(v) == static_cast(e - s) && memcmp(s, v, e-s) == 0; + } + bool operator!=(const char* v) const { return !(*this == v); } + + const Type ty() const { return m_ty; } + const ::std::string& str() const { + return m_val; + } + ::std::string to_string() const { + return ::std::string(s, e); + } + }; +private: + const char* m_pos; + Tok m_cur; + +public: + CfgParseLexer(const char* s): + m_pos(s), + m_cur(nullptr,nullptr) + { + consume(); + } + const Tok& cur() const { + return m_cur; + } + + Tok consume() { + auto rv = m_cur; + m_cur = get_next(); + //::std::cout << "consume: " << rv.to_string() << " => " << m_cur.to_string() << ::std::endl; + return rv; + } + bool consume_if(char c) { + if( cur() == c ) { + consume(); + return true; + } + else { + return false; + } + } + bool consume_if(const char* s) { + if( cur() == s ) { + consume(); + return true; + } + else { + return false; + } + } +private: + Tok get_next(); +}; + +struct CfgChecker +{ + const char* target_env; + const char* target_os; + const char* target_arch; + + bool check_cfg(CfgParseLexer& p) const; +}; + +CfgChecker gCfgChecker { + (CFG_WINDOWS ? "msvc" : "gnu"), + (CFG_WINDOWS ? "windows" : "linux"), + "x86" + }; + +CfgParseLexer::Tok CfgParseLexer::get_next() +{ + while(*m_pos == ' ') + m_pos ++; + if(*m_pos == 0) + return Tok(); + switch(*m_pos) + { + case '(': case ')': + case ',': case '=': + return Tok(m_pos++); + case '"': { + ::std::string str; + auto s = m_pos; + m_pos ++; + while( *m_pos != '"' ) + { + if( *m_pos == '\\' ) + { + TODO("Escape sequences in cfg parser"); + } + str += *m_pos; + m_pos ++; + } + m_pos ++; + return Tok(s, m_pos, str); } + default: + if( isalnum(*m_pos) || *m_pos == '_' ) + { + auto s = m_pos; + while(isalnum(*m_pos) || *m_pos == '_') + m_pos ++; + return Tok(s, m_pos); + } + else + { + throw ::std::runtime_error(format("Unexpected character in cfg() - ", *m_pos)); + } + } +} + +bool Cfg_Check(const char* cfg_string) +{ + CfgParseLexer p { cfg_string + 4 }; + + if( gCfgChecker.target_os == nullptr ) + { + // TODO: If the checker isn't initialised, invoke the compiler and ask it to dump the current target + // - It's pre-initialised above currently + } + + bool success = gCfgChecker.check_cfg(p); + if( !p.consume_if(")") ) + throw ::std::runtime_error(format("Expected ')' after cfg condition - got", p.cur().to_string())); + return success; +} + +bool CfgChecker::check_cfg(CfgParseLexer& p) const +{ + auto name = p.consume(); + if( name.ty() != CfgParseLexer::Tok::Ident ) + throw ::std::runtime_error("Expected an identifier"); + // Combinators + if( p.consume_if('(') ) { + bool rv; + if( false ) { + } + else if( name == "not" ) { + rv = !check_cfg(p); + } + else if( name == "all" ) { + rv = true; + do + { + rv &= check_cfg(p); + } while(p.consume_if(',')); + } + else { + TODO("Unknown fragment in cfg - " << name.to_string()); + } + if( !p.consume_if(')') ) + throw ::std::runtime_error("Expected ')' after combinator content"); + return rv; + } + // Values + else if( p.consume_if('=') ) { + auto t = p.consume(); + if( t.ty() != CfgParseLexer::Tok::String ) + throw ::std::runtime_error("Expected a string after `=`"); + const auto& val = t.str(); + + if( false ) { + } + else if( name == "target_env" ) + return val == this->target_env; + else if( name == "target_os" ) + return val == this->target_os; + else if( name == "target_arch" ) + return val == this->target_arch; + else { + TODO("Unknown fragment in cfg - " << name.to_string()); + } + } + // Flags + else { + if( false ) { + } + else if( name == "unix" ) { + return CFG_UNIX; + } + else if( name == "windows" ) { + return CFG_WINDOWS; + } + else if( name == "stage0" ) { + return false; + } + else { + TODO("Unknown fragment in cfg - " << name.to_string()); + } + } + throw ::std::runtime_error("Hit end of check_cfg"); +} diff --git a/tools/minicargo/cfg.hpp b/tools/minicargo/cfg.hpp new file mode 100644 index 00000000..907c8079 --- /dev/null +++ b/tools/minicargo/cfg.hpp @@ -0,0 +1,9 @@ +/* + * mrustc "minicargo" (minimal cargo clone) + * - By John Hodge (Mutabah) + * + * cfg.cpp + * - Handling of target configuration (in manifest nodes) + */ +#pragma once +extern bool Cfg_Check(const char* cfg_string); diff --git a/tools/minicargo/manifest.cpp b/tools/minicargo/manifest.cpp index bbaa24f6..79db0e35 100644 --- a/tools/minicargo/manifest.cpp +++ b/tools/minicargo/manifest.cpp @@ -13,20 +13,15 @@ #include #include // toupper #include "repository.h" +#include "cfg.hpp" // TODO: Extract this from the target at runtime (by invoking the compiler on the passed target) #ifdef _WIN32 # define TARGET_NAME "i586-windows-msvc" -# define CFG_UNIX false -# define CFG_WINDOWS true #elif defined(__NetBSD__) # define TARGET_NAME "x86_64-unknown-netbsd" -# define CFG_UNIX true -# define CFG_WINDOWS false #else # define TARGET_NAME "x86_64-unknown-linux-gnu" -# define CFG_UNIX true -# define CFG_WINDOWS false #endif static ::std::vector<::std::shared_ptr> g_loaded_manifests; @@ -241,169 +236,7 @@ PackageManifest PackageManifest::load_from_toml(const ::std::string& path) // - It can be a target spec, or a cfg(foo) same as rustc bool success; if( cfg.substr(0, 4) == "cfg(" ) { - class Parser - { - public: - class Tok - { - friend class Parser; - const char* s; - const char* e; - Tok(const char* s, const char* e): - s(s), e(e) - { - } - public: - bool operator==(const char* v) const { - return (strlen(v) == e - s) && memcmp(s, v, e-s) == 0; - } - bool operator!=(const char* v) const { - return (strlen(v) != e - s) || memcmp(s, v, e-s) != 0; - } - ::std::string to_string() const { - return ::std::string(s, e); - } - }; - private: - const char* m_pos; - Tok m_cur; - - public: - Parser(const char* s): - m_pos(s), - m_cur(nullptr,nullptr) - { - consume(); - } - const Tok& cur() const { - return m_cur; - } - - Tok consume() { - auto rv = m_cur; - m_cur = get_next(); - //::std::cout << "consume: " << rv.to_string() << " => " << m_cur.to_string() << ::std::endl; - return rv; - } - bool consume_if(const char* s) { - if( cur() == s ) { - consume(); - return true; - } - else { - return false; - } - } - private: - Tok get_next() { - while(*m_pos == ' ') - m_pos ++; - if(*m_pos == 0) - return Tok { m_pos, m_pos }; - switch(*m_pos) - { - case '(': case ')': - case ',': case '=': - return Tok { m_pos++, m_pos }; - case '"': { - auto s = m_pos; - m_pos ++; - while( *m_pos != '"' ) - { - if( *m_pos == '\\' ) - { - TODO("Escape sequences in cfg parser"); - } - m_pos ++; - } - m_pos ++; - return Tok { s, m_pos }; } - default: - if( isalnum(*m_pos) || *m_pos == '_' ) - { - auto s = m_pos; - while(isalnum(*m_pos) || *m_pos == '_') - m_pos ++; - return Tok { s, m_pos }; - } - else - { - throw ::std::runtime_error(format("Unexpected character in cfg() - ", *m_pos)); - } - } - } - }; - - struct H { - static bool check_cfg(Parser& p) - { - if( p.consume_if("not") ) { - if( !p.consume_if("(") ) - throw ::std::runtime_error("Expected '(' after `not`"); - auto rv = !check_cfg(p); - if( !p.consume_if(")") ) - throw ::std::runtime_error("Expected ')' after `not` content"); - return rv; - } - else if( p.consume_if("all") ) { - if( !p.consume_if("(") ) - throw ::std::runtime_error("Expected '(' after `all`"); - bool rv = true; - do - { - rv &= check_cfg(p); - } while(p.consume_if(",")); - if( !p.consume_if(")") ) - throw ::std::runtime_error("Expected ')' after `all` content"); - return rv; - } - // Strings - else if( p.consume_if("target_os") ) { - if( !p.consume_if("=") ) - throw ::std::runtime_error("Expected '=' after target_os"); - auto t = p.consume(); - if( t == "\"emscripten\"" ) { - return false; - } - else if( t == "\"macos\"" ) { - return false; - } - else { - TODO("Handle target_os string - " << t.to_string()); - } - } - else if( p.consume_if("target_arch") ) { - if( !p.consume_if("=") ) - throw ::std::runtime_error("Expected '=' after target"); - auto t = p.consume(); - if( t == "\"wasm32\"" ) { - return false; - } - else{ - TODO("Handle target_arch string - " << t.to_string()); - } - } - // Flags - else if( p.consume_if("unix") ) { - return CFG_UNIX; - } - else if( p.consume_if("windows") ) { - return CFG_WINDOWS; - } - else if( p.consume_if("stage0") ) { - return false; - } - else { - TODO("Unknown fragment in cfg - " << p.cur().to_string()); - throw ::std::runtime_error(""); - } - } - }; - - Parser p { cfg.data() + 4 }; - success = H::check_cfg(p); - if( !p.consume_if(")") ) - throw ::std::runtime_error(format("Expected ')' after cfg condition - got", p.cur().to_string())); + success = Cfg_Check(cfg.c_str()); } else { // It's a target name @@ -428,6 +261,10 @@ PackageManifest PackageManifest::load_from_toml(const ::std::string& path) it->fill_from_kv(was_added, key_val, 4); } + else if( real_section == "dev-dependencies" ) + { + // TODO: Developemnt (test/bench) deps + } else { TODO("Unknown manifest section for target - " << real_section); -- cgit v1.2.3 From 2e9e8169126fbf9d14bed00bcb3185607f728767 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 30 Dec 2018 13:18:42 +0800 Subject: Common TOML - Allow EOF right after a line --- tools/common/toml.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/common/toml.cpp b/tools/common/toml.cpp index 489f32b6..7e24b610 100644 --- a/tools/common/toml.cpp +++ b/tools/common/toml.cpp @@ -263,8 +263,7 @@ TomlKeyValue TomlFile::get_next_value() } if( m_current_composite.empty() ) { - // TODO: Allow EOF? - if(t.m_type != Token::Type::Newline) + if(t.m_type != Token::Type::Newline && t.m_type != Token::Type::Eof) throw ::std::runtime_error(::format("Unexpected token in TOML file after entry - ", t)); } else -- cgit v1.2.3 From 823ad74acb87dced844acade9b7799e9793c59a4 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 30 Dec 2018 14:14:08 +0800 Subject: Typecheck Outer - Rough handling of `impl Trait` in argument position --- src/hir_typeck/outer.cpp | 68 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 51 insertions(+), 17 deletions(-) diff --git a/src/hir_typeck/outer.cpp b/src/hir_typeck/outer.cpp index b38511d1..63e92d8b 100644 --- a/src/hir_typeck/outer.cpp +++ b/src/hir_typeck/outer.cpp @@ -291,24 +291,52 @@ namespace { TU_IFLET(::HIR::TypeRef::Data, ty.m_data, ErasedType, e, if( e.m_origin == ::HIR::SimplePath() ) { - // If not, ensure taht we're checking a function return type, and error if not - if( ! m_fcn_path ) + // If not, figure out what to do with it + + // If the function path is set, we're processing the return type of a function + // - Add this to the list of erased types associated with the function + if( m_fcn_path ) + { + assert(m_fcn_ptr); + DEBUG(*m_fcn_path << " " << m_fcn_erased_count); + + ::HIR::PathParams params; + for(unsigned int i = 0; i < m_fcn_ptr->m_params.m_types.size(); i ++) + params.m_types.push_back(::HIR::TypeRef(m_fcn_ptr->m_params.m_types[i].m_name, 256+i)); + // Populate with function path + e.m_origin = m_fcn_path->get_full_path(); + TU_MATCHA( (e.m_origin.m_data), (e2), + (Generic, e2.m_params = mv$(params); ), + (UfcsInherent, e2.params = mv$(params); ), + (UfcsKnown, e2.params = mv$(params); ), + (UfcsUnknown, throw ""; ) + ) + e.m_index = m_fcn_erased_count++; + } + // If the function _pointer_ is set (but not the path), then we're in the function arguments + // - Add a un-namable generic parameter (TODO: Prevent this from being explicitly set when called) + else if( m_fcn_ptr ) + { + size_t idx = m_fcn_ptr->m_params.m_types.size(); + auto new_ty = ::HIR::TypeRef( FMT("impl$" << idx), 256 + idx ); + m_fcn_ptr->m_params.m_types.push_back({ FMT("impl$" << idx), ::HIR::TypeRef(), true }); + for( const auto& trait : e.m_traits ) + { + m_fcn_ptr->m_params.m_bounds.push_back(::HIR::GenericBound::make_TraitBound({ + new_ty.clone(), + trait.clone() + })); + } + if( e.m_lifetime != ::HIR::LifetimeRef() ) + { + TODO(sp, "Add bound " << new_ty << " : " << e.m_lifetime); + } + ty = ::std::move(new_ty); + } + else + { ERROR(sp, E0000, "Use of an erased type outside of a function return - " << ty); - assert(m_fcn_ptr); - DEBUG(*m_fcn_path << " " << m_fcn_erased_count); - - ::HIR::PathParams params; - for(unsigned int i = 0; i < m_fcn_ptr->m_params.m_types.size(); i ++) - params.m_types.push_back(::HIR::TypeRef(m_fcn_ptr->m_params.m_types[i].m_name, 256+i)); - // Populate with function path - e.m_origin = m_fcn_path->get_full_path(); - TU_MATCHA( (e.m_origin.m_data), (e2), - (Generic, e2.m_params = mv$(params); ), - (UfcsInherent, e2.params = mv$(params); ), - (UfcsKnown, e2.params = mv$(params); ), - (UfcsUnknown, throw ""; ) - ) - e.m_index = m_fcn_erased_count++; + } } ) } @@ -682,6 +710,12 @@ namespace { m_fcn_erased_count = 0; visit_type(item.m_return); m_fcn_path = nullptr; + // TODO: Visit arguments + for(auto& arg : item.m_args) + { + visit_type(arg.second); + } + m_fcn_ptr = nullptr; ::HIR::Visitor::visit_function(p, item); } -- cgit v1.2.3 From 852050a97d8304d30d1ea51b7acacf1ece387973 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 30 Dec 2018 14:51:21 +0800 Subject: Auto Impls - Automatic delegating impl of Clone for tuples --- src/trans/auto_impls.cpp | 60 +++++++++++++++++++++++++++++++++++++++++++++++- src/trans/enumerate.cpp | 1 + 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/src/trans/auto_impls.cpp b/src/trans/auto_impls.cpp index ffd0d30a..418a338b 100644 --- a/src/trans/auto_impls.cpp +++ b/src/trans/auto_impls.cpp @@ -63,7 +63,65 @@ void Trans_AutoImpl_Clone(State& state, ::HIR::TypeRef ty) } else { - TODO(Span(), "auto Clone for " << ty << " - Not Copy"); + const auto& lang_Clone = state.resolve.m_crate.get_lang_item_path(sp, "clone"); + TU_MATCH_HDRA( (ty.m_data), {) + default: + TODO(sp, "auto Clone for " << ty << " - Not Copy"); + TU_ARMA(Tuple, te) { + assert(te.size() > 0); + + ::std::vector< ::MIR::Param> values; + // For each field of the tuple, create a clone (either using Copy if posible, or calling Clone::clone) + for(const auto& subty : te) + { + auto fld_lvalue = ::MIR::LValue::make_Field({ box$(::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Argument({ 0 })) })), values.size() }); + if( state.resolve.type_is_copy(sp, subty) ) + { + values.push_back( ::std::move(fld_lvalue) ); + } + else + { + // Allocate to locals (one for the `&T`, the other for the cloned `T`) + auto borrow_lv = ::MIR::LValue::make_Local( mir_fcn.locals.size() ); + mir_fcn.locals.push_back(::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, subty.clone())); + auto res_lv = ::MIR::LValue::make_Local( mir_fcn.locals.size() ); + mir_fcn.locals.push_back(subty.clone()); + + // Call `::clone`, passing a borrow of the field + ::MIR::BasicBlock bb; + bb.statements.push_back(::MIR::Statement::make_Assign({ + borrow_lv.clone(), + ::MIR::RValue::make_Borrow({ 0, ::HIR::BorrowType::Shared, mv$(fld_lvalue) }) + })); + bb.terminator = ::MIR::Terminator::make_Call({ + mir_fcn.blocks.size() + 2, // return block (after the panic block below) + mir_fcn.blocks.size() + 1, // panic block (next block) + res_lv.clone(), + ::MIR::CallTarget( ::HIR::Path(subty.clone(), lang_Clone, "clone") ), + ::make_vec1<::MIR::Param>( ::std::move(borrow_lv) ) + }); + mir_fcn.blocks.push_back(::std::move( bb )); + + // Stub panic handling (TODO: Make this iterate `values` and drop all of them) + ::MIR::BasicBlock panic_bb; + bb.terminator = ::MIR::Terminator::make_Diverge({}); + mir_fcn.blocks.push_back(::std::move( panic_bb )); + + // Save the output of the `clone` call + values.push_back( ::std::move(res_lv) ); + } + } + + // Construct the result tuple + ::MIR::BasicBlock bb; + bb.statements.push_back(::MIR::Statement::make_Assign({ + ::MIR::LValue::make_Return({}), + ::MIR::RValue::make_Tuple({ mv$(values) }) + })); + bb.terminator = ::MIR::Terminator::make_Return({}); + mir_fcn.blocks.push_back(::std::move( bb )); + } + } } // Function diff --git a/src/trans/enumerate.cpp b/src/trans/enumerate.cpp index 06ca92a3..bb6d6e6f 100644 --- a/src/trans/enumerate.cpp +++ b/src/trans/enumerate.cpp @@ -1393,6 +1393,7 @@ void Trans_Enumerate_FillFrom_Path(EnumState& state, const ::HIR::Path& path, co { const auto& pe = path_mono.m_data.as_UfcsKnown(); ASSERT_BUG(sp, pe.item == "clone", ""); + // TODO: If this is !Copy, then we need to ensure that the inner type's clone impls are also available // Add this type to a list of types that will have the impl auto-generated state.rv.auto_clone_impls.insert( pe.type->clone() ); } -- cgit v1.2.3 From 44d040f6d4325f713b9fefeadb1ee533a0fd5294 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 30 Dec 2018 15:08:38 +0800 Subject: Parse/Macro - Handle `crate` as a visibility specifier --- src/macro_rules/eval.cpp | 4 ++-- src/macro_rules/mod.cpp | 1 + src/parse/root.cpp | 7 ++++++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/macro_rules/eval.cpp b/src/macro_rules/eval.cpp index 558f26b3..23ffab77 100644 --- a/src/macro_rules/eval.cpp +++ b/src/macro_rules/eval.cpp @@ -1824,7 +1824,7 @@ namespace bool consume_vis(TokenStreamRO& lex) { TRACE_FUNCTION; - if( lex.consume_if(TOK_INTERPOLATED_VIS) ) + if( lex.consume_if(TOK_INTERPOLATED_VIS) || lex.consume_if(TOK_RWORD_CRATE) ) { return true; } @@ -2065,7 +2065,7 @@ unsigned int Macro_InvokeRules_MatchPattern(const Span& sp, const MacroRules& ru DEBUG(i << " ExpectTok(" << *e << ") == " << tok); if( tok != *e ) { - ERROR(sp, E0000, "Expected token in match arm"); + ERROR(sp, E0000, "Expected token " << *e << " in match arm, got " << tok); break; } } diff --git a/src/macro_rules/mod.cpp b/src/macro_rules/mod.cpp index fcea5b25..3297a139 100644 --- a/src/macro_rules/mod.cpp +++ b/src/macro_rules/mod.cpp @@ -160,6 +160,7 @@ bool is_token_vis(eTokenType tt) { switch(tt) { case TOK_RWORD_PUB: + case TOK_RWORD_CRATE: case TOK_INTERPOLATED_VIS: return true; default: diff --git a/src/parse/root.cpp b/src/parse/root.cpp index 61218326..5fc90f0c 100644 --- a/src/parse/root.cpp +++ b/src/parse/root.cpp @@ -48,7 +48,6 @@ AST::Attribute Parse_MetaItem(TokenStream& lex); void Parse_ModRoot(TokenStream& lex, AST::Module& mod, AST::AttributeList& mod_attrs); bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv); -//::AST::Path Parse_Publicity(TokenStream& lex) ::AST::Visibility Parse_Publicity(TokenStream& lex, bool allow_restricted/*=true*/) { Token tok; @@ -57,6 +56,12 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv) GET_TOK(tok, lex); return tok.take_frag_vis(); } + if( LOOK_AHEAD(lex) == TOK_RWORD_CRATE ) + { + // TODO: Return a path that indicates the entire current crate + GET_TOK(tok, lex); + return true; + } if( LOOK_AHEAD(lex) == TOK_RWORD_PUB ) { GET_TOK(tok, lex); -- cgit v1.2.3 From 48ea151b6fed48d96af12cbcc9137db49fcd5996 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 30 Dec 2018 15:58:13 +0800 Subject: Expand - Handle #[cfg]-d enum variants --- src/expand/mod.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/expand/mod.cpp b/src/expand/mod.cpp index 4dfd1224..f63f7ab5 100644 --- a/src/expand/mod.cpp +++ b/src/expand/mod.cpp @@ -1188,6 +1188,15 @@ void Expand_Mod(::AST::Crate& crate, LList modstack, ::AST:: ) Expand_Attrs(var.m_attrs, AttrStage::Post, [&](const auto& sp, const auto& d, const auto& a){ d.handle(sp, a, crate, var); }); } + // Handle cfg on variants (kinda hacky) + for(auto it = e.variants().begin(); it != e.variants().end(); ) { + if( it->m_name == "" ) { + it = e.variants().erase(it); + } + else { + ++ it; + } + } ), (Union, Expand_GenericParams(crate, modstack, mod, e.m_params); -- cgit v1.2.3 From 529c542631de917f45e25485be2dd778e34ba1ea Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 30 Dec 2018 15:59:13 +0800 Subject: Parse - Handle `crate::` paths --- src/parse/paths.cpp | 2 ++ src/parse/root.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/parse/paths.cpp b/src/parse/paths.cpp index d103840e..26311d83 100644 --- a/src/parse/paths.cpp +++ b/src/parse/paths.cpp @@ -39,6 +39,8 @@ AST::Path Parse_Path(TokenStream& lex, eParsePathGenericMode generic_mode) return AST::Path(AST::Path::TagSuper(), count, Parse_PathNodes(lex, generic_mode)); } + case TOK_RWORD_CRATE: + GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON); case TOK_DOUBLE_COLON: return Parse_Path(lex, true, generic_mode); diff --git a/src/parse/root.cpp b/src/parse/root.cpp index 5fc90f0c..5eae2488 100644 --- a/src/parse/root.cpp +++ b/src/parse/root.cpp @@ -1396,6 +1396,8 @@ void Parse_Use(TokenStream& lex, ::std::function Date: Sun, 30 Dec 2018 17:45:45 +0800 Subject: Parse root - Support finding `foo/bar.rs` from `foo.rs` --- src/parse/root.cpp | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/parse/root.cpp b/src/parse/root.cpp index 5eae2488..9ab84c78 100644 --- a/src/parse/root.cpp +++ b/src/parse/root.cpp @@ -1887,16 +1887,33 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv) if( sub_path == "-" ) { ERROR(lex.point_span(), E0000, "Cannot load module from file when reading stdin"); } - else if( path_attr.size() == 0 && ! mod_fileinfo.controls_dir ) - { - ERROR(lex.point_span(), E0000, "Can't load from files outside of mod.rs or crate root"); - } else if( !H::check_item_cfg(meta_items) ) { // Ignore - emit Item::None item_name = mv$(name); item_data = ::AST::Item( ); break ; } + else if( path_attr.size() == 0 && ! mod_fileinfo.controls_dir ) + { + // TODO: Also search for curmod/submod.rs + //::std::string newpath_file = (mod_path.nodes().size() > 1 ? dirname(mod_fileinfo.path) + mod_path.nodes()[mod_path.nodes().size()-2].name() + "/" + name + ".rs" : ""); + ::std::string newpath_file = (mod_path.nodes().size() >= 1 ? dirname(mod_fileinfo.path) + mod_path.nodes()[mod_path.nodes().size()-1].name() + "/" + name + ".rs" : ""); + DEBUG("newpath_file = '" << newpath_file << "' " << mod_fileinfo.path << " " << mod_path); + ::std::ifstream ifs_file(newpath_file); + if( ifs_file.is_open() ) + { + submod.m_file_info.path = newpath_file; + submod.m_file_info.controls_dir = false; + DEBUG("- path = " << submod.m_file_info.path); + Lexer sub_lex(submod.m_file_info.path); + Parse_ModRoot(sub_lex, submod, meta_items); + GET_CHECK_TOK(tok, sub_lex, TOK_EOF); + } + else + { + ERROR(lex.point_span(), E0000, "Can't load from files outside of mod.rs or crate root"); + } + } else { ::std::string newpath_dir = sub_path + "/"; @@ -1917,7 +1934,9 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv) else if( ifs_file.is_open() ) { submod.m_file_info.path = newpath_file; + submod.m_file_info.controls_dir = false; } + // TODO: If this is not a controlling file, look in `modname/` for the new module else { // Can't find file -- cgit v1.2.3 From 2f0ddfaf240c0269087d307b6df6bc00817e6806 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Tue, 1 Jan 2019 11:32:39 +0800 Subject: Parse - Module Loading - Hopefully fix libcore without breaking other crates --- src/ast/ast.hpp | 4 ++ src/parse/root.cpp | 128 ++++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 117 insertions(+), 15 deletions(-) diff --git a/src/ast/ast.hpp b/src/ast/ast.hpp index b80b5fb7..493b397c 100644 --- a/src/ast/ast.hpp +++ b/src/ast/ast.hpp @@ -517,7 +517,11 @@ public: struct FileInfo { bool controls_dir = false; + bool force_no_load = false; + // Path to this module ::std::string path = "!"; + // Directory controlled by this module + ::std::string dir = ""; }; FileInfo m_file_info; diff --git a/src/parse/root.cpp b/src/parse/root.cpp index 9ab84c78..d457d197 100644 --- a/src/parse/root.cpp +++ b/src/parse/root.cpp @@ -1513,6 +1513,102 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv) return true; } +#if 0 +namespace { + ::AST::Module::FileInfo get_submod_file( + Span sp, const ::AST::Module::FileInfo& parent_fileinfo, const ::std::string& new_mod_name, const ::std::string& path_attr, + bool is_extern_file, bool is_cfg_disabled + ) + { + ::AST::Module::FileInfo rv; + TRACE_FUNCTION_F(new_mod_name << ", " << path_attr << ", " << is_extern_file); + ::std::string sub_path; + bool sub_file_controls_dir = true; + + // 1. Determine the base path for the module + if( parent_fileinfo.path == "-" ) { + if( path_attr.size() ) { + ERROR(lex.point_span(), E0000, "Cannot load module from file when reading stdin"); + } + sub_path = "-"; + } + else if( path_attr.size() > 0 ) + { + // #[path] present, add to the parent path + sub_path = dirname(parent_fileinfo.path) + path_attr; + } + else if( mod_fileinfo.controls_dir ) + { + // The parent module is either the crate root, or a `mod.rs` (or otherwise a controller) + sub_path = parent_fileinfo.dir + name; + } + else + { + sub_path = parent_fileinfo.path; + sub_file_controls_dir = false; + } + DEBUG("Mod '" << name << "', sub_path = " << sub_path); + + rv.path = sub_path; + rv.controls_dir = sub_file_controls_dir; + + if( is_cfg_disabled || parent_fileinfo.force_no_load ) + { + rv.force_no_load = true; + } + if( ! is_extern_file ) + { + // If this is an inline module, set the path to just a directory + if( sub_path != "-" ) { + rv.path = sub_path + "/"; + rv.dir = sub_path + "/"; + } + else { + rv.path = "-"; + } + } + else + { + if( sub_path == "-" ) + { + ERROR(lex.point_span(), E0000, "Cannot load module from file when reading stdin"); + } + else + { + ::std::string newpath_dir = sub_path + "/"; + ::std::string newpath_file = path_attr.size() > 0 ? sub_path : sub_path + ".rs"; + DEBUG("newpath_dir = '" << newpath_dir << "', newpath_file = '" << newpath_file << "'"); + ::std::ifstream ifs_dir (newpath_dir + "mod.rs"); + ::std::ifstream ifs_file(newpath_file); + if( ifs_dir.is_open() && ifs_file.is_open() ) + { + // Collision + ERROR(lex.point_span(), E0000, "Both modname.rs and modname/mod.rs exist"); + } + else if( ifs_dir.is_open() ) + { + // Load from dir + rv.path = newpath_dir + "mod.rs"; + rv.dir = newpath_dir; + } + else if( ifs_file.is_open() ) + { + rv.path = newpath_file; + rv.dir = newpath_dir; + rv.controls_dir = false; + } + else + { + // Can't find file + ERROR(sp, E0000, "Can't find file for '" << name << "' in '" << parent_fileinfo.dir << "'"); + } + } + } + return rv; + } +} +#endif + ::AST::Named<::AST::Item> Parse_Mod_Item_S(TokenStream& lex, const AST::Module::FileInfo& mod_fileinfo, const ::AST::Path& mod_path, AST::AttributeList meta_items) { TRACE_FUNCTION_F("mod_path="<string() : ""); - //submod.m_file_info = get_submod_file(lex.end_span(ps), mod_fileinfo, name, path_attr, LOOK_AHEAD(lex) == TOK_SEMICOLON); + //submod.m_file_info = get_submod_file(lex.end_span(ps), mod_fileinfo, name, path_attr, LOOK_AHEAD(lex) == TOK_SEMICOLON, H::check_item_cfg(meta_items)); ::std::string sub_path; bool sub_file_controls_dir = true; @@ -1863,23 +1972,12 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv) submod.m_file_info.path = sub_path; submod.m_file_info.controls_dir = sub_file_controls_dir; - // Check #[cfg] and don't load if it fails - struct H { - static bool check_item_cfg(const ::AST::AttributeList& attrs) - { - for(const auto& at : attrs.m_items) { - if( at.name() == "cfg" && !check_cfg(at.span(), at) ) { - return false; - } - } - return true; - } - }; - switch( GET_TOK(tok, lex) ) { case TOK_BRACE_OPEN: submod.m_file_info.path = sub_path + "/"; + // TODO: If cfg fails, just eat the TT until a matching #[cfg]? + // - Or, mark the file infor as not being valid (so child modules don't try to load) Parse_ModRoot(lex, submod, meta_items); GET_CHECK_TOK(tok, lex, TOK_BRACE_CLOSE); break; @@ -1934,7 +2032,7 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv) else if( ifs_file.is_open() ) { submod.m_file_info.path = newpath_file; - submod.m_file_info.controls_dir = false; + //submod.m_file_info.controls_dir = false; } // TODO: If this is not a controlling file, look in `modname/` for the new module else -- cgit v1.2.3 From 47954747236802644fcfdbd378e320fbb69690bc Mon Sep 17 00:00:00 2001 From: John Hodge Date: Tue, 1 Jan 2019 12:49:30 +0800 Subject: Parse - Tweak module loading rules again, should work this time --- src/parse/root.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/parse/root.cpp b/src/parse/root.cpp index d457d197..2db03c99 100644 --- a/src/parse/root.cpp +++ b/src/parse/root.cpp @@ -1964,7 +1964,8 @@ namespace { } else { - sub_path = mod_fileinfo.path; + sub_path = dirname(mod_fileinfo.path) + mod_path.nodes().back().name() + "/" + name; + //sub_path = mod_fileinfo.path; sub_file_controls_dir = false; } DEBUG("Mod '" << name << "', sub_path = " << sub_path); @@ -2032,7 +2033,10 @@ namespace { else if( ifs_file.is_open() ) { submod.m_file_info.path = newpath_file; - //submod.m_file_info.controls_dir = false; + if( path_attr == "" ) + { + submod.m_file_info.controls_dir = false; + } } // TODO: If this is not a controlling file, look in `modname/` for the new module else -- cgit v1.2.3 From 95d725d80a76e74549329dfdb74f8147c1b075e7 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Tue, 1 Jan 2019 13:06:13 +0800 Subject: Refactor of `use` items to fully-group imports from a single use --- src/ast/ast.cpp | 23 ++--- src/ast/ast.hpp | 32 +++--- src/ast/dump.cpp | 23 +++-- src/expand/mod.cpp | 2 +- src/expand/std_prelude.cpp | 4 +- src/parse/root.cpp | 202 ++++++++++++++----------------------- src/resolve/index.cpp | 64 ++++++------ src/resolve/use.cpp | 244 +++++++++++++++++++++++---------------------- 8 files changed, 286 insertions(+), 308 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index b439553a..f3a81e80 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -241,23 +241,23 @@ bool Impl::has_named_item(const ::std::string& name) const return os << impl.m_def; } -::std::ostream& operator<<(::std::ostream& os, const UseStmt& x) -{ - os << "Use(" << x.path << ")"; - return os; -} - - MacroInvocation MacroInvocation::clone() const { return MacroInvocation(m_span, m_macro_name, m_ident, m_input.clone()); } - -UseStmt UseStmt::clone() const +UseItem UseItem::clone() const { - return UseStmt(sp, AST::Path(path)); + decltype(this->entries) entries; + for(const auto& e : this->entries) + { + entries.push_back({ e.sp, e.path, e.name }); + } + return UseItem { + this->sp, + mv$(entries) + }; } void ExternBlock::add_item(Named named_item) @@ -296,9 +296,6 @@ void Module::add_item(bool is_pub, ::std::string name, Item it, AttributeList at void Module::add_ext_crate(bool is_public, ::std::string ext_name, ::std::string imp_name, AttributeList attrs) { this->add_item( is_public, imp_name, Item::make_Crate({mv$(ext_name)}), mv$(attrs) ); } -void Module::add_alias(bool is_public, UseStmt us, ::std::string name, AttributeList attrs) { - this->add_item( is_public, mv$(name), Item(mv$(us)), mv$(attrs) ); -} void Module::add_macro_invocation(MacroInvocation item) { this->add_item( false, "", Item( mv$(item) ), ::AST::AttributeList {} ); } diff --git a/src/ast/ast.hpp b/src/ast/ast.hpp index 493b397c..8976cfc7 100644 --- a/src/ast/ast.hpp +++ b/src/ast/ast.hpp @@ -462,20 +462,18 @@ public: private: }; -struct UseStmt +struct UseItem { - Span sp; - ::AST::Path path; - - UseStmt(Span sp, Path p): - sp(sp), - path(p) - { - } - - UseStmt clone() const; + Span sp; // Span covering the entire `use foo;` + struct Ent { + Span sp; // Span covering just the path (final component) + ::AST::Path path; + ::std::string name; // If "", this is a glob/wildcard use + }; + ::std::vector entries; - friend ::std::ostream& operator<<(::std::ostream& os, const UseStmt& x); + UseItem clone() const; + //friend ::std::ostream& operator<<(::std::ostream& os, const UseItem& x); }; class ExternBlock @@ -549,6 +547,13 @@ public: }; ::std::vector m_macro_imports; + struct Import { + bool is_pub; + ::std::string name; + ::AST::Path path; // If `name` is "", then this is a module/enum to glob + }; + ::std::vector m_item_imports; + public: Module() {} Module(::AST::Path path): @@ -566,7 +571,6 @@ public: void add_item(Named item); void add_item(bool is_pub, ::std::string name, Item it, AttributeList attrs); void add_ext_crate(bool is_public, ::std::string ext_name, ::std::string imp_name, AttributeList attrs); - void add_alias(bool is_public, UseStmt path, ::std::string name, AttributeList attrs); void add_macro_invocation(MacroInvocation item); void add_macro(bool is_exported, ::std::string name, MacroRulesPtr macro); @@ -595,7 +599,7 @@ TAGGED_UNION_EX(Item, (), None, ( (None, struct {} ), (MacroInv, MacroInvocation), - (Use, UseStmt), + (Use, UseItem), // Nameless items (ExternBlock, ExternBlock), diff --git a/src/ast/dump.cpp b/src/ast/dump.cpp index f1481abf..94ad6271 100644 --- a/src/ast/dump.cpp +++ b/src/ast/dump.cpp @@ -619,17 +619,26 @@ void RustPrinter::handle_module(const AST::Module& mod) // m_os << "\n"; // need_nl = false; //} - if( i_data.path == AST::Path() ) { + if( i_data.entries.empty() ) { continue ; } - m_os << indent() << (i.is_pub ? "pub " : "") << "use " << i_data; - if( i.name == "" ) - { - m_os << "::*"; + m_os << indent() << (i.is_pub ? "pub " : "") << "use "; + if( i_data.entries.size() > 1 ) { + m_os << "{"; } - else if( i_data.path.nodes().back().name() != i.name ) + for(const auto& ent : i_data.entries) { - m_os << " as " << i.name; + if( &ent != &i_data.entries.front() ) + m_os << ", "; + m_os << ent.path; + if( ent.name == "" ) { + m_os << "::*"; + } + else if( ent.name != ent.path.nodes().back().name() ) { + m_os << " as " << ent.name; + } + else { + } } m_os << ";\n"; } diff --git a/src/expand/mod.cpp b/src/expand/mod.cpp index f63f7ab5..da37dea7 100644 --- a/src/expand/mod.cpp +++ b/src/expand/mod.cpp @@ -1051,7 +1051,7 @@ void Expand_Mod(::AST::Crate& crate, LList modstack, ::AST:: if( crate.m_prelude_path != AST::Path() ) { if( mod.m_insert_prelude && ! mod.is_anon() ) { - mod.add_alias(false, ::AST::UseStmt(Span(), crate.m_prelude_path), "", {}); + mod.add_item(false, "", ::AST::UseItem { Span(), ::make_vec1(::AST::UseItem::Ent { Span(), crate.m_prelude_path, "" }) }, {}); } } diff --git a/src/expand/std_prelude.cpp b/src/expand/std_prelude.cpp index d6022959..52c1554c 100644 --- a/src/expand/std_prelude.cpp +++ b/src/expand/std_prelude.cpp @@ -65,12 +65,12 @@ public: void handle(const Span& sp, const AST::Attribute& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item&i) const override { if( i.is_Use() ) { - const auto& p = i.as_Use().path; + const auto& p = i.as_Use().entries.front().path; // TODO: Ensure that this statement is a glob (has a name of "") crate.m_prelude_path = AST::Path(p); } else { - ERROR(sp, E0000, "Invalid use of #[no_prelude] on non-module"); + ERROR(sp, E0000, "Invalid use of #[prelude_import] on non-module"); } } }; diff --git a/src/parse/root.cpp b/src/parse/root.cpp index 2db03c99..28a49287 100644 --- a/src/parse/root.cpp +++ b/src/parse/root.cpp @@ -1322,55 +1322,74 @@ AST::ExternBlock Parse_ExternBlock(TokenStream& lex, ::std::string abi, ::AST::A return rv; } -void Parse_Use_Wildcard(Span sp, AST::Path base_path, ::std::function fcn) +/// Parse multiple items from a use "statement" +void Parse_Use_Inner(TokenStream& lex, ::std::vector& entries, AST::Path& path) { - fcn( AST::UseStmt(mv$(sp), mv$(base_path)), "" ); // HACK! Empty path indicates wilcard import -} -void Parse_Use_Set(TokenStream& lex, const ProtoSpan& ps, const AST::Path& base_path, ::std::function fcn) -{ - TRACE_FUNCTION; - Token tok; - do { - AST::Path path; - ::std::string name; - if( GET_TOK(tok, lex) == TOK_RWORD_SELF ) { - path = ::AST::Path(base_path); - name = base_path[base_path.size()-1].name(); - } - else if( tok.type() == TOK_BRACE_CLOSE ) { - break ; - } - else { - path = ::AST::Path(base_path); - while(1) - { - CHECK_TOK(tok, TOK_IDENT); - path += AST::PathNode(tok.str(), {}); - if( !TARGETVER_1_29 ) - break; - if( lex.lookahead(0) != TOK_DOUBLE_COLON ) - break; - GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON); - GET_TOK(tok, lex); + do + { + switch( GET_TOK(tok, lex) ) + { + case TOK_IDENT: + path.append( AST::PathNode( mv$(tok.str()), {}) ); + break; + case TOK_BRACE_OPEN: + // Can't be an empty list + if( LOOK_AHEAD(lex) == TOK_BRACE_CLOSE ) { + throw ParseError::Unexpected(lex, tok); } - name = mv$(tok.str()); - } + // Keep looping until a comma + do { + if( LOOK_AHEAD(lex) == TOK_BRACE_CLOSE ) { + // Trailing comma + GET_TOK(tok, lex); + break; + } + // - Handle `self` in braces differently + else if( LOOK_AHEAD(lex) == TOK_RWORD_SELF ) { + GET_TOK(tok, lex); + auto name = path.nodes().back().name(); + entries.push_back({ lex.point_span(), AST::Path(path), ::std::move(name) }); + } + else { + size_t l = path.nodes().size(); - if( GET_TOK(tok, lex) == TOK_RWORD_AS ) { - GET_CHECK_TOK(tok, lex, TOK_IDENT); - name = mv$(tok.str()); - } - else { - PUTBACK(tok, lex); + Parse_Use_Inner(lex, entries, path); + + assert(l <= path.nodes().size()); + path.nodes().resize( l ); + } + } while( GET_TOK(tok, lex) == TOK_COMMA ); + CHECK_TOK(tok, TOK_BRACE_CLOSE); + return; + case TOK_STAR: + entries.push_back({ lex.point_span(), AST::Path(path), "" }); + return ; + default: + throw ParseError::Unexpected(lex, tok); } - fcn(AST::UseStmt(lex.end_span(ps), mv$(path)), mv$(name)); - } while( GET_TOK(tok, lex) == TOK_COMMA ); - PUTBACK(tok, lex); -} + } while( GET_TOK(tok, lex) == TOK_DOUBLE_COLON ); + + ::std::string name; -void Parse_Use(TokenStream& lex, ::std::function fcn) + // NOTE: The above loop has to run once, so the last token HAS to have been an ident + if( tok.type() == TOK_RWORD_AS ) + { + GET_CHECK_TOK(tok, lex, TOK_IDENT); + name = mv$(tok.str()); + } + else + { + PUTBACK(tok, lex); + ASSERT_BUG(lex.point_span(), path.nodes().size() > 0, "`use` with no path"); + name = path.nodes().back().name(); + } + + // TODO: Get a span covering the final node. + entries.push_back({ lex.point_span(), AST::Path(path), ::std::move(name) }); +} +::AST::UseItem Parse_Use(TokenStream& lex) { TRACE_FUNCTION; @@ -1379,10 +1398,13 @@ void Parse_Use(TokenStream& lex, ::std::function nodes; ProtoSpan span_start = lex.start_span(); + ::std::vector entries; + switch( GET_TOK(tok, lex) ) { case TOK_RWORD_SELF: path = AST::Path( AST::Path::TagSelf(), {} ); // relative path + GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON); break; case TOK_RWORD_SUPER: { unsigned int count = 1; @@ -1392,11 +1414,11 @@ void Parse_Use(TokenStream& lex, ::std::function 0, "`use` with no path"); - name = path.nodes().back().name(); + break; } - fcn( AST::UseStmt(lex.end_span(span_start), mv$(path)), name); + Parse_Use_Inner(lex, entries, path); + + return AST::UseItem { lex.end_span(span_start), mv$(entries) }; } @@ -1655,16 +1635,7 @@ namespace { switch( GET_TOK(tok, lex) ) { case TOK_RWORD_USE: - // NOTE: The only problem here is with things like `use foo::{a, b, c}` - all others are a single statement. - // - These are caught by the condition in the closure - Parse_Use(lex, [&](AST::UseStmt p, std::string s) { - DEBUG(mod_path << " - use " << p << " as '" << s << "'"); - if( !item_data.is_None() ) - TODO(lex.point_span(), "Encode multi-item use statements as a single Item"); - item_data = ::AST::Item(mv$(p)); - item_name = mv$(s); - }); - assert( !item_data.is_None() ); + item_data = Parse_Use(lex); GET_CHECK_TOK(tok, lex, TOK_SEMICOLON); break; @@ -2072,26 +2043,7 @@ void Parse_Mod_Item(TokenStream& lex, AST::Module& mod, AST::AttributeList meta_ SET_MODULE(lex, mod); lex.parse_state().parent_attrs = &meta_items; - //TRACE_FUNCTION; - Token tok; - - // `use ...` - // TODO: This doesn't spot `pub(path) use`. - if( LOOK_AHEAD(lex) == TOK_RWORD_USE || (lex.lookahead(0) == TOK_RWORD_PUB && lex.lookahead(1) == TOK_RWORD_USE) ) - { - bool is_public = Parse_Publicity(lex); - GET_CHECK_TOK(tok, lex, TOK_RWORD_USE); - - Parse_Use(lex, [&mod,is_public,&meta_items](AST::UseStmt p, std::string s) { - DEBUG(mod.path() << " - use " << p << " as '" << s << "'"); - mod.add_alias(is_public, mv$(p), s, meta_items.clone()); - }); - GET_CHECK_TOK(tok, lex, TOK_SEMICOLON); - } - else - { - mod.add_item( Parse_Mod_Item_S(lex, mod.m_file_info, mod.path(), mv$(meta_items)) ); - } + mod.add_item( Parse_Mod_Item_S(lex, mod.m_file_info, mod.path(), mv$(meta_items)) ); } void Parse_ModRoot_Items(TokenStream& lex, AST::Module& mod) diff --git a/src/resolve/index.cpp b/src/resolve/index.cpp index 48f2d0da..6051b82d 100644 --- a/src/resolve/index.cpp +++ b/src/resolve/index.cpp @@ -17,7 +17,7 @@ enum class IndexName Value, }; -void Resolve_Index_Module_Wildcard__use_stmt(AST::Crate& crate, AST::Module& dst_mod, const AST::UseStmt& i_data, bool is_pub); +void Resolve_Index_Module_Wildcard__use_stmt(AST::Crate& crate, AST::Module& dst_mod, const AST::UseItem::Ent& i_data, bool is_pub); ::std::ostream& operator<<(::std::ostream& os, const IndexName& loc) { @@ -178,8 +178,8 @@ void Resolve_Index_Module_Base(const AST::Crate& crate, AST::Module& mod) { if( ! i.data.is_Use() ) continue ; - const auto& i_data = i.data.as_Use(); - if( i.name != "" ) + for(const auto& i_data : i.data.as_Use().entries) + if( i_data.name != "" ) { // TODO: Ensure that the path is canonical? @@ -190,47 +190,47 @@ void Resolve_Index_Module_Base(const AST::Crate& crate, AST::Module& mod) // - Types {TU_MATCH_HDRA( (i_data.path.m_bindings.type), {) TU_ARMA(Unbound, _e) { - DEBUG(i.name << " - Not a type/module"); + DEBUG(i_data.name << " - Not a type/module"); } TU_ARMA(TypeParameter, e) BUG(sp, "Import was bound to type parameter"); TU_ARMA(Crate , e) - _add_item(sp, mod, IndexName::Namespace, i.name, i.is_pub, i_data.path, !allow_collide); + _add_item(sp, mod, IndexName::Namespace, i_data.name, i.is_pub, i_data.path, !allow_collide); TU_ARMA(Module, e) - _add_item(sp, mod, IndexName::Namespace, i.name, i.is_pub, i_data.path, !allow_collide); + _add_item(sp, mod, IndexName::Namespace, i_data.name, i.is_pub, i_data.path, !allow_collide); TU_ARMA(Enum, e) - _add_item_type(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); + _add_item_type(sp, mod, i_data.name, i.is_pub, i_data.path, !allow_collide); TU_ARMA(Union, e) - _add_item_type(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); + _add_item_type(sp, mod, i_data.name, i.is_pub, i_data.path, !allow_collide); TU_ARMA(Trait, e) - _add_item_type(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); + _add_item_type(sp, mod, i_data.name, i.is_pub, i_data.path, !allow_collide); TU_ARMA(TypeAlias, e) - _add_item_type(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); + _add_item_type(sp, mod, i_data.name, i.is_pub, i_data.path, !allow_collide); TU_ARMA(Struct, e) - _add_item_type(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); + _add_item_type(sp, mod, i_data.name, i.is_pub, i_data.path, !allow_collide); TU_ARMA(EnumVar, e) - _add_item_type(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); + _add_item_type(sp, mod, i_data.name, i.is_pub, i_data.path, !allow_collide); }} // - Values {TU_MATCH_HDRA( (i_data.path.m_bindings.value), {) TU_ARMA(Unbound, _e) { - DEBUG(i.name << " - Not a value"); + DEBUG(i_data.name << " - Not a value"); } TU_ARMA(Variable, e) BUG(sp, "Import was bound to a variable"); TU_ARMA(Struct, e) - _add_item_value(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); + _add_item_value(sp, mod, i_data.name, i.is_pub, i_data.path, !allow_collide); TU_ARMA(EnumVar, e) - _add_item_value(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); + _add_item_value(sp, mod, i_data.name, i.is_pub, i_data.path, !allow_collide); TU_ARMA(Static , e) - _add_item_value(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); + _add_item_value(sp, mod, i_data.name, i.is_pub, i_data.path, !allow_collide); TU_ARMA(Function, e) - _add_item_value(sp, mod, i.name, i.is_pub, i_data.path, !allow_collide); + _add_item_value(sp, mod, i_data.name, i.is_pub, i_data.path, !allow_collide); }} // - Macros {TU_MATCH_HDRA( (i_data.path.m_bindings.macro), {) TU_ARMA(Unbound, _e) { - DEBUG(i.name << " - Not a macro"); + DEBUG(i_data.name << " - Not a macro"); } TU_ARMA(MacroRules, e) { ::std::vector<::std::string> path; @@ -238,7 +238,7 @@ void Resolve_Index_Module_Base(const AST::Crate& crate, AST::Module& mod) for(const auto& node : i_data.path.m_class.as_Absolute().nodes ) path.push_back( node.name() ); mod.m_macro_imports.push_back({ - i.is_pub, i.name, mv$(path), e.mac + i.is_pub, i_data.name, mv$(path), e.mac }); } // TODO: Other imports (e.g. derives, which have different naming structures) @@ -411,16 +411,19 @@ void Resolve_Index_Module_Wildcard__submod(AST::Crate& crate, AST::Module& dst_m { if( ! i.data.is_Use() ) continue ; - if( i.name != "" ) - continue ; - Resolve_Index_Module_Wildcard__use_stmt(crate, dst_mod, i.data.as_Use(), import_as_pub); + for(const auto& e : i.data.as_Use().entries) + { + if( e.name != "" ) + continue ; + Resolve_Index_Module_Wildcard__use_stmt(crate, dst_mod, e, import_as_pub); + } } } stack.erase(&src_mod); } -void Resolve_Index_Module_Wildcard__use_stmt(AST::Crate& crate, AST::Module& dst_mod, const AST::UseStmt& i_data, bool is_pub) +void Resolve_Index_Module_Wildcard__use_stmt(AST::Crate& crate, AST::Module& dst_mod, const AST::UseItem::Ent& i_data, bool is_pub) { const auto& sp = i_data.sp; const auto& b = i_data.path.m_bindings.type; @@ -443,7 +446,9 @@ void Resolve_Index_Module_Wildcard__use_stmt(AST::Crate& crate, AST::Module& dst Resolve_Index_Module_Wildcard__submod(crate, dst_mod, *e.module_, is_pub); } ) - else TU_IFLET(::AST::PathBinding_Type, b, Enum, e, + else if( const auto* ep = b.opt_Enum() ) + { + const auto& e = *ep; ASSERT_BUG(sp, e.enum_ || e.hir, "Glob import but enum pointer not set - " << i_data.path); if( e.enum_ ) { @@ -500,7 +505,7 @@ void Resolve_Index_Module_Wildcard__use_stmt(AST::Crate& crate, AST::Module& dst } } } - ) + } else { BUG(sp, "Invalid path binding for glob import: " << b.tag_str() << " - "< Needs resolve"); - // TODO: Handle possibility of recursion - //out_path = imp_data.path; - return Resolve_Use_GetBinding(sp2, crate, Resolve_Use_AbsolutisePath(sp2, mod.path(), imp_data.path), parent_modules); - } - else { - //out_path = imp_data.path; - return imp_data.path.m_bindings.clone(); - } - } - if( imp.is_pub && imp.name == "" ) { - DEBUG("- Search glob of " << imp_data.path); - // INEFFICIENT! Resolves and throws away the result (because we can't/shouldn't mutate here) - ::AST::Path::Bindings bindings_; - const auto* bindings = &imp_data.path.m_bindings; - if( bindings->type.is_Unbound() ) { - DEBUG("Temp resolving wildcard " << imp_data); - // Handle possibility of recursion - static ::std::vector resolve_stack_ptrs; - if( ::std::find(resolve_stack_ptrs.begin(), resolve_stack_ptrs.end(), &imp_data) == resolve_stack_ptrs.end() ) - { - resolve_stack_ptrs.push_back( &imp_data ); - bindings_ = Resolve_Use_GetBinding(sp2, crate, Resolve_Use_AbsolutisePath(sp2, mod.path(), imp_data.path), parent_modules); - // *waves hand* I'm not evil. - const_cast< ::AST::Path::Bindings&>( imp_data.path.m_bindings ) = bindings_.clone(); - bindings = &bindings_; - resolve_stack_ptrs.pop_back(); + for( const auto& imp_e : imp_data.entries ) + { + const Span& sp2 = imp_e.sp; + if( imp_e.name == des_item_name ) { + DEBUG("- Named import " << imp_e.name << " = " << imp_e.path); + if( !imp_e.path.m_bindings.has_binding() ) { + DEBUG(" > Needs resolve"); + // TODO: Handle possibility of recursion + //out_path = imp_e.path; + return Resolve_Use_GetBinding(sp2, crate, Resolve_Use_AbsolutisePath(sp2, mod.path(), imp_e.path), parent_modules); } else { - continue ; + //out_path = imp_e.path; + return imp_e.path.m_bindings.clone(); } } - else { - //out_path = imp_data.path; - } - TU_MATCH_HDRA( (bindings->type), {) - TU_ARMA(Crate, e) { - assert(e.crate_); - const ::HIR::Module& hmod = e.crate_->m_hir->m_root_module; - auto rv = Resolve_Use_GetBinding__ext(sp2, crate, AST::Path("", { AST::PathNode(des_item_name,{}) }), hmod, 0); - if( rv.has_binding() ) { - return mv$(rv); - } - } - TU_ARMA(Module, e) { - if( e.module_ ) { - // TODO: Prevent infinite recursion? - auto rv = Resolve_Use_GetBinding_Mod(span, crate, *e.module_, des_item_name, {}); - if( rv.has_binding() ) { - return mv$(rv); + if( imp.is_pub && imp_e.name == "" ) + { + DEBUG("- Search glob of " << imp_e.path); + // INEFFICIENT! Resolves and throws away the result (because we can't/shouldn't mutate here) + ::AST::Path::Bindings bindings_; + const auto* bindings = &imp_e.path.m_bindings; + if( bindings->type.is_Unbound() ) { + DEBUG("Temp resolving wildcard " << imp_e.path); + // Handle possibility of recursion + static ::std::vector resolve_stack_ptrs; + if( ::std::find(resolve_stack_ptrs.begin(), resolve_stack_ptrs.end(), &imp_data) == resolve_stack_ptrs.end() ) + { + resolve_stack_ptrs.push_back( &imp_data ); + bindings_ = Resolve_Use_GetBinding(sp2, crate, Resolve_Use_AbsolutisePath(sp2, mod.path(), imp_e.path), parent_modules); + // *waves hand* I'm not evil. + const_cast< ::AST::Path::Bindings&>( imp_e.path.m_bindings ) = bindings_.clone(); + bindings = &bindings_; + resolve_stack_ptrs.pop_back(); } + else { + continue ; + } + } + else { + //out_path = imp_e.path; } - else if( e.hir ) { - const ::HIR::Module& hmod = *e.hir; + + TU_MATCH_HDRA( (bindings->type), {) + TU_ARMA(Crate, e) { + assert(e.crate_); + const ::HIR::Module& hmod = e.crate_->m_hir->m_root_module; auto rv = Resolve_Use_GetBinding__ext(sp2, crate, AST::Path("", { AST::PathNode(des_item_name,{}) }), hmod, 0); if( rv.has_binding() ) { return mv$(rv); } - } - else { - BUG(span, "NULL module for binding on glob of " << imp_data.path); - } - } - TU_ARMA(Enum, e) { - assert(e.enum_ || e.hir); - if( e.enum_ ) { - const auto& enm = *e.enum_; - unsigned int i = 0; - for(const auto& var : enm.variants()) - { - if( var.m_name == des_item_name ) { - ::AST::Path::Bindings rv; - if( var.m_data.is_Struct() ) - rv.type = ::AST::PathBinding_Type::make_EnumVar({ &enm, i }); - else - rv.value = ::AST::PathBinding_Value::make_EnumVar({ &enm, i }); - return rv; + } + TU_ARMA(Module, e) { + if( e.module_ ) { + // TODO: Prevent infinite recursion? + auto rv = Resolve_Use_GetBinding_Mod(span, crate, *e.module_, des_item_name, {}); + if( rv.has_binding() ) { + return mv$(rv); } - i ++; } - } - else { - const auto& enm = *e.hir; - auto idx = enm.find_variant(des_item_name); - if( idx != SIZE_MAX ) - { - ::AST::Path::Bindings rv; - if( enm.m_data.is_Data() && enm.m_data.as_Data()[idx].is_struct ) { - rv.type = ::AST::PathBinding_Type::make_EnumVar({ nullptr, static_cast(idx), &enm }); + else if( e.hir ) { + const ::HIR::Module& hmod = *e.hir; + auto rv = Resolve_Use_GetBinding__ext(sp2, crate, AST::Path("", { AST::PathNode(des_item_name,{}) }), hmod, 0); + if( rv.has_binding() ) { + return mv$(rv); } - else { - rv.value = ::AST::PathBinding_Value::make_EnumVar({ nullptr, static_cast(idx), &enm }); + } + else { + BUG(span, "NULL module for binding on glob of " << imp_e.path); + } + } + TU_ARMA(Enum, e) { + assert(e.enum_ || e.hir); + if( e.enum_ ) { + const auto& enm = *e.enum_; + unsigned int i = 0; + for(const auto& var : enm.variants()) + { + if( var.m_name == des_item_name ) { + ::AST::Path::Bindings rv; + if( var.m_data.is_Struct() ) + rv.type = ::AST::PathBinding_Type::make_EnumVar({ &enm, i }); + else + rv.value = ::AST::PathBinding_Value::make_EnumVar({ &enm, i }); + return rv; + } + i ++; + } + } + else { + const auto& enm = *e.hir; + auto idx = enm.find_variant(des_item_name); + if( idx != SIZE_MAX ) + { + ::AST::Path::Bindings rv; + if( enm.m_data.is_Data() && enm.m_data.as_Data()[idx].is_struct ) { + rv.type = ::AST::PathBinding_Type::make_EnumVar({ nullptr, static_cast(idx), &enm }); + } + else { + rv.value = ::AST::PathBinding_Value::make_EnumVar({ nullptr, static_cast(idx), &enm }); + } + return rv; } - return rv; } + } break; + default: + BUG(sp2, "Wildcard import expanded to an invalid item class - " << bindings->type.tag_str()); + break; } - } break; - default: - BUG(sp2, "Wildcard import expanded to an invalid item class - " << bindings->type.tag_str()); - break; } } } -- cgit v1.2.3 From cfee4a1bc22a3bf4f9c2e8f2afd06fc84ddb8278 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Tue, 1 Jan 2019 13:14:54 +0800 Subject: Parse Path - Slight tweaks for 1.29 --- src/parse/paths.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/parse/paths.cpp b/src/parse/paths.cpp index 26311d83..2a2437ca 100644 --- a/src/parse/paths.cpp +++ b/src/parse/paths.cpp @@ -41,6 +41,7 @@ AST::Path Parse_Path(TokenStream& lex, eParsePathGenericMode generic_mode) case TOK_RWORD_CRATE: GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON); + return Parse_Path(lex, true, generic_mode); case TOK_DOUBLE_COLON: return Parse_Path(lex, true, generic_mode); @@ -82,7 +83,13 @@ AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generi Token tok; if( is_abs ) { - if( GET_TOK(tok, lex) == TOK_STRING ) { + // QUIRK: `::crate::foo` is valid (semi-surprisingly) + if( LOOK_AHEAD(lex) == TOK_RWORD_CRATE ) { + GET_CHECK_TOK(tok, lex, TOK_RWORD_CRATE); + GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON); + return AST::Path("", Parse_PathNodes(lex, generic_mode)); + } + else if( GET_TOK(tok, lex) == TOK_STRING ) { ::std::string cratename = tok.str(); GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON); return AST::Path(cratename, Parse_PathNodes(lex, generic_mode)); -- cgit v1.2.3 From 11a9f976f334534bdaf6e6f7dc4f74f08446c7ee Mon Sep 17 00:00:00 2001 From: John Hodge Date: Tue, 1 Jan 2019 16:20:10 +0800 Subject: Draft support for in_band_lifetimes --- src/resolve/absolute.cpp | 53 +++++++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/src/resolve/absolute.cpp b/src/resolve/absolute.cpp index d0db3c13..557eebe8 100644 --- a/src/resolve/absolute.cpp +++ b/src/resolve/absolute.cpp @@ -78,12 +78,16 @@ namespace unsigned int m_block_level; bool m_frozen_bind_set; + // Destination `GenericParams` for in_band_lifetimes + ::AST::GenericParams* m_ibl_target_generics; + Context(const ::AST::Crate& crate, const ::AST::Module& mod): m_crate(crate), m_mod(mod), m_var_count(~0u), m_block_level(0), - m_frozen_bind_set( false ) + m_frozen_bind_set( false ), + m_ibl_target_generics(nullptr) {} void push(const ::AST::HigherRankedBounds& params) { @@ -1501,6 +1505,30 @@ void Resolve_Absolute_Lifetime(Context& context, const Span& sp, AST::LifetimeRe } } + if( TARGETVER_1_29 ) + { + // If parsing a function header, add a new lifetime param to the function + // - Does the same apply to impl headers? + if( context.m_ibl_target_generics ) + { + ASSERT_BUG(sp, !context.m_name_context.empty(), "Name context stack is empty"); + ASSERT_BUG(sp, context.m_name_context.back().is_Generic(), "Name context stack end not Generic, instead " << context.m_name_context.back().tag_str()); + auto& context_gen = context.m_name_context.back().as_Generic(); + auto& def_gen = *context.m_ibl_target_generics; + // 1. Assert that the last item of `context.m_name_context` is Generic, and matches `m_ibl_target_generics` + ASSERT_BUG(sp, context_gen.lifetimes.size() == def_gen.lft_params().size(), ""); + ASSERT_BUG(sp, context_gen.types.size() == def_gen.ty_params().size(), ""); + //ASSERT_BUG(sp, context_gen.constants.size() == def_gen.val_params().size(), ""); + // 2. Add the new lifetime to both `m_ibl_target_generics` and the last entry in m_name_context + size_t idx = def_gen.lft_params().size(); + def_gen.add_lft_param(AST::LifetimeParam(sp, {}, lft.name())); + // TODO: Is this always a method-level set? + auto level = GenericSlot::Level::Method; + context_gen.lifetimes.push_back( NamedI { lft.name(), GenericSlot { level, static_cast(idx) } } ); + lft.set_binding( idx | (static_cast(level) << 8) ); + return ; + } + } ERROR(sp, E0000, "Couldn't find lifetime " << lft); } } @@ -1929,26 +1957,7 @@ void Resolve_Absolute_ImplItems(Context& item_context, ::AST::NamedList< ::AST: ), (Function, DEBUG("Function - " << i.name); - item_context.push( e.params(), GenericSlot::Level::Method ); - Resolve_Absolute_Generic(item_context, e.params()); - - Resolve_Absolute_Type( item_context, e.rettype() ); - for(auto& arg : e.args()) - Resolve_Absolute_Type( item_context, arg.second ); - - { - auto _h = item_context.enter_rootblock(); - item_context.push_block(); - for(auto& arg : e.args()) { - Resolve_Absolute_Pattern( item_context, false, arg.first ); - } - - Resolve_Absolute_Expr( item_context, e.code() ); - - item_context.pop_block(); - } - - item_context.pop( e.params() ); + Resolve_Absolute_Function(item_context, e); ), (Static, DEBUG("Static - " << i.name); @@ -2009,9 +2018,11 @@ void Resolve_Absolute_Function(Context& item_context, ::AST::Function& fcn) item_context.push( fcn.params(), GenericSlot::Level::Method ); Resolve_Absolute_Generic(item_context, fcn.params()); + item_context.m_ibl_target_generics = &fcn.params(); Resolve_Absolute_Type( item_context, fcn.rettype() ); for(auto& arg : fcn.args()) Resolve_Absolute_Type( item_context, arg.second ); + item_context.m_ibl_target_generics = nullptr; { auto _h = item_context.enter_rootblock(); -- cgit v1.2.3 From b7c4d85d6642a68fc8fcfd1e0466f3b9dae41b30 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Tue, 1 Jan 2019 18:16:10 +0800 Subject: Match ergonomics - Fixes and expansion --- src/hir_typeck/expr_cs.cpp | 10 +++++++++- src/mir/from_hir.cpp | 5 +++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 04cb6f17..041247ba 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -3816,11 +3816,18 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T if( pattern.m_binding.is_valid() ) { // - Binding present, use the current binding mode + pattern.m_binding.m_type = binding_mode; switch(binding_mode) { case ::HIR::PatternBinding::Type::Move: context.equate_types(sp, context.get_var(sp, pattern.m_binding.m_slot), type); break; + case ::HIR::PatternBinding::Type::MutRef: + context.equate_types(sp, context.get_var(sp, pattern.m_binding.m_slot), ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Unique, type.clone())); + break; + case ::HIR::PatternBinding::Type::Ref: + context.equate_types(sp, context.get_var(sp, pattern.m_binding.m_slot), ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, type.clone())); + break; default: TODO(sp, "Assign variable type using mode " << (int)binding_mode << " and " << type); } @@ -3832,7 +3839,8 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T ::HIR::BorrowType bt = ::HIR::BorrowType::Owned; const auto* ty_p = &context.get_type(type); while( ty_p->m_data.is_Borrow() ) { - bt = ::std::max(bt, ty_p->m_data.as_Borrow().type); + DEBUG("bt " << bt << ", " << ty_p->m_data.as_Borrow().type); + bt = ::std::min(bt, ty_p->m_data.as_Borrow().type); ty_p = &context.get_type( *ty_p->m_data.as_Borrow().inner ); n_deref ++; } diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index 2c45f5bb..bea8a38c 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -207,6 +207,11 @@ namespace { allow_refutable = 2; } + for(size_t i = 0; i < pat.m_implicit_deref_count; i ++) + { + lval = ::MIR::LValue::make_Deref({ box$( mv$(lval) ) }); + } + TU_MATCH_HDRA( (pat.m_data), {) TU_ARMA(Any, e) { } -- cgit v1.2.3 From 3ae5e62aedbd7e3c566e02579a76e759f7eb3cb9 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Tue, 1 Jan 2019 18:44:54 +0800 Subject: Target - Handle opaque types in size/align --- src/trans/target.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/trans/target.cpp b/src/trans/target.cpp index dccc566d..9a855036 100644 --- a/src/trans/target.cpp +++ b/src/trans/target.cpp @@ -587,6 +587,8 @@ bool Target_GetSizeAndAlignOf(const Span& sp, const StaticTraitResolve& resolve, } ), (Path, + if( te.binding.is_Opaque() ) + return false; const auto* repr = Target_GetTypeRepr(sp, resolve, ty); if( !repr ) { -- cgit v1.2.3 From 6bb397dadbaabeab1a2f8a44da52948c801833b7 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Tue, 1 Jan 2019 18:45:10 +0800 Subject: Typecheck Expressions - Fallback type for tuples in match ergonomics --- src/hir_typeck/expr_cs.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 041247ba..301c5d54 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -3781,6 +3781,8 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T ::HIR::Pattern& m_pattern; ::HIR::PatternBinding::Type m_outer_mode; + mutable ::std::vector<::HIR::TypeRef> m_temp_ivars; + MatchErgonomicsRevisit(Span sp, ::HIR::TypeRef outer, ::HIR::Pattern& pat, ::HIR::PatternBinding::Type binding_mode=::HIR::PatternBinding::Type::Move): sp(mv$(sp)), m_outer_ty(mv$(outer)), m_pattern(pat), @@ -3852,7 +3854,7 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T if( n_deref == 0 && is_fallback ) { ::HIR::TypeRef possible_type; - // TODO: Get a potential type from the pattern, and set as a possibility. + // Get a potential type from the pattern, and set as a possibility. // - Note, this is only if no derefs were applied TU_MATCH_HDR( (pattern.m_data), { ) TU_ARM(pattern.m_data, Any, pe) { @@ -3871,7 +3873,15 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T BUG(sp, "Match ergonomics - & pattern"); } TU_ARM(pattern.m_data, Tuple, e) { - // TODO: Get type info `(T, U, ...)` + // Get type info `(T, U, ...)` + if( m_temp_ivars.size() != e.sub_patterns.size() ) { + for(size_t i = 0; i < e.sub_patterns.size(); i ++) + m_temp_ivars.push_back( context.m_ivars.new_ivar_tr() ); + } + decltype(m_temp_ivars) tuple; + for(const auto& ty : m_temp_ivars) + tuple.push_back(ty.clone()); + possible_type = ::HIR::TypeRef( ::std::move(tuple) ); } TU_ARM(pattern.m_data, SplitTuple, pe) { // Can't get type information, tuple size is unkown -- cgit v1.2.3 From 36e67e675aec3e488cd4ad07cbe81d2ec5150a04 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Tue, 1 Jan 2019 20:09:54 +0800 Subject: Resolve UFCS - Fix non-wrapped marker impls --- src/hir_conv/resolve_ufcs.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/hir_conv/resolve_ufcs.cpp b/src/hir_conv/resolve_ufcs.cpp index 55fbf593..5481fbb9 100644 --- a/src/hir_conv/resolve_ufcs.cpp +++ b/src/hir_conv/resolve_ufcs.cpp @@ -91,6 +91,25 @@ namespace { auto _g = m_resolve.set_impl_generics(impl.m_params); ::HIR::Visitor::visit_type_impl(impl); } + void visit_marker_impl(const ::HIR::SimplePath& trait_path, ::HIR::MarkerImpl& impl) override { + ::HIR::ItemPath p( impl.m_type, trait_path, impl.m_trait_args ); + TRACE_FUNCTION_F("impl" << impl.m_params.fmt_args() << " " << trait_path << impl.m_trait_args << " for " << impl.m_type << " (mod=" << impl.m_src_module << ")"); + auto _t = this->push_mod_traits( this->m_crate.get_mod_by_path(Span(), impl.m_src_module) ); + auto _g = m_resolve.set_impl_generics(impl.m_params); + + // TODO: Push a bound that `Self: ThisTrait` + m_current_type = &impl.m_type; + m_current_trait = &m_crate.get_trait_by_path(Span(), trait_path); + m_current_trait_path = &p; + + // The implemented trait is always in scope + m_traits.push_back( ::std::make_pair( &trait_path, m_current_trait) ); + ::HIR::Visitor::visit_marker_impl(trait_path, impl); + m_traits.pop_back( ); + + m_current_trait = nullptr; + m_current_type = nullptr; + } void visit_trait_impl(const ::HIR::SimplePath& trait_path, ::HIR::TraitImpl& impl) override { ::HIR::ItemPath p( impl.m_type, trait_path, impl.m_trait_args ); TRACE_FUNCTION_F("impl" << impl.m_params.fmt_args() << " " << trait_path << impl.m_trait_args << " for " << impl.m_type << " (mod=" << impl.m_src_module << ")"); -- cgit v1.2.3 From 5ff7238a4caf78da70987cd9e0851add01425590 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Tue, 1 Jan 2019 20:10:12 +0800 Subject: minicargo - Hack in a environment variable used by backtrace-sys --- tools/minicargo/build.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/minicargo/build.cpp b/tools/minicargo/build.cpp index 35c64f3b..4c116730 100644 --- a/tools/minicargo/build.cpp +++ b/tools/minicargo/build.cpp @@ -869,6 +869,8 @@ bool Builder::build_target(const PackageManifest& manifest, const PackageTarget& env.push_back("OPT_LEVEL", "2"); env.push_back("DEBUG", "0"); env.push_back("PROFILE", "release"); + // TODO: All cfg(foo_bar) become CARGO_CFG_FOO_BAR + env.push_back("CARGO_CFG_TARGET_POINTER_WIDTH", "32"); for(const auto& dep : manifest.dependencies()) { if( ! dep.is_disabled() ) -- cgit v1.2.3 From 1c752cfb7f0fced838e9228aecd3908222958465 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Thu, 3 Jan 2019 22:57:59 +0800 Subject: Typecheck Expressions - Handle placeholder params better --- src/hir_typeck/impl_ref.cpp | 9 +++++++++ src/hir_typeck/impl_ref.hpp | 9 +-------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/hir_typeck/impl_ref.cpp b/src/hir_typeck/impl_ref.cpp index d2dc9fe6..1aa8fc2b 100644 --- a/src/hir_typeck/impl_ref.cpp +++ b/src/hir_typeck/impl_ref.cpp @@ -56,6 +56,15 @@ bool ImplRef::overlaps_with(const ::HIR::Crate& crate, const ImplRef& other) con ) return false; } +bool ImplRef::has_magic_params() const +{ + TU_IFLET(Data, m_data, TraitImpl, e, + for(const auto& t : e.params_ph) + if( visit_ty_with(t, [](const ::HIR::TypeRef& t){ return t.m_data.is_Generic() && (t.m_data.as_Generic().binding >> 8) == 2; }) ) + return true; + ) + return false; +} bool ImplRef::type_is_specialisable(const char* name) const { TU_MATCH(Data, (this->m_data), (e), diff --git a/src/hir_typeck/impl_ref.hpp b/src/hir_typeck/impl_ref.hpp index b1190c61..84d0b404 100644 --- a/src/hir_typeck/impl_ref.hpp +++ b/src/hir_typeck/impl_ref.hpp @@ -59,14 +59,7 @@ struct ImplRef bool more_specific_than(const ImplRef& other) const; bool overlaps_with(const ::HIR::Crate& crate, const ImplRef& other) const; - bool has_magic_params() const { - TU_IFLET(Data, m_data, TraitImpl, e, - for(const auto& t : e.params_ph) - if( t.m_data.is_Generic() && (t.m_data.as_Generic().binding >> 8) == 2 ) - return true; - ) - return false; - } + bool has_magic_params() const; /// HELPER: Returns callback to monomorphise a type using parameters from Data::TraitImpl ::std::function get_cb_monomorph_traitimpl(const Span& sp) const; -- cgit v1.2.3 From 17c5d0e1d12229f6b720708748723811f7f2acd3 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Thu, 3 Jan 2019 22:58:24 +0800 Subject: Lower MIR - Allow "+" at the start of asm output specifiers --- src/mir/from_hir.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index bea8a38c..17de43c2 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -544,7 +544,7 @@ namespace { // Outputs can also (sometimes) be rvalues (only for `*m`?) for(auto& v : node.m_outputs) { this->visit_node_ptr(v.value); - if( v.spec[0] != '=' ) + if( v.spec[0] != '=' && v.spec[0] != '+' ) // TODO: what does '+' mean? ERROR(node.span(), E0000, "Assembly output specifiers must start with ="); ::MIR::LValue lv; if(v.spec[1] == '*') -- cgit v1.2.3 From 777bdf9a8bfcd6a5b1b4c38c6a57f582fc9d5d18 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Thu, 3 Jan 2019 23:11:35 +0800 Subject: HIR Expand - Handle match ergonomics in AVU --- src/hir_expand/annotate_value_usage.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/hir_expand/annotate_value_usage.cpp b/src/hir_expand/annotate_value_usage.cpp index 693c7745..f5acbbc5 100644 --- a/src/hir_expand/annotate_value_usage.cpp +++ b/src/hir_expand/annotate_value_usage.cpp @@ -452,12 +452,20 @@ namespace { throw ""; } - ::HIR::ValueUsage get_usage_for_pattern(const Span& sp, const ::HIR::Pattern& pat, const ::HIR::TypeRef& ty) const + ::HIR::ValueUsage get_usage_for_pattern(const Span& sp, const ::HIR::Pattern& pat, const ::HIR::TypeRef& outer_ty) const { if( pat.m_binding.is_valid() ) { - return get_usage_for_pattern_binding(sp, pat.m_binding, ty); + return get_usage_for_pattern_binding(sp, pat.m_binding, outer_ty); } + // Implicit derefs + const ::HIR::TypeRef* typ = &outer_ty; + for(size_t i = 0; i < pat.m_implicit_deref_count; i ++) + { + typ = &*typ->m_data.as_Borrow().inner; + } + const ::HIR::TypeRef& ty = *typ; + TU_MATCHA( (pat.m_data), (pe), (Any, return ::HIR::ValueUsage::Borrow; -- cgit v1.2.3 From fe650f59cddee21a86b1697c6db6b6e1ab89ecaf Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 4 Jan 2019 22:03:10 +0800 Subject: Resolve - Resolve impl type before handling bounds --- src/resolve/absolute.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/resolve/absolute.cpp b/src/resolve/absolute.cpp index 557eebe8..7fa08aaf 100644 --- a/src/resolve/absolute.cpp +++ b/src/resolve/absolute.cpp @@ -2184,13 +2184,14 @@ void Resolve_Absolute_Mod( Context item_context, ::AST::Module& mod ) { item_context.push_self( def.type() ); item_context.push(def.params(), GenericSlot::Level::Top); - Resolve_Absolute_Generic(item_context, def.params()); Resolve_Absolute_Type(item_context, def.type()); if( def.trait().ent.is_valid() ) { Resolve_Absolute_Path(item_context, def.trait().sp, Context::LookupMode::Type, def.trait().ent); } + Resolve_Absolute_Generic(item_context, def.params()); + Resolve_Absolute_ImplItems(item_context, e.items()); item_context.pop(def.params()); -- cgit v1.2.3 From d681c0cfa1077e4646a292695b6a7426f2056414 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 4 Jan 2019 22:03:41 +0800 Subject: Typecheck Expressions - Short-circuit wildcard pattern matches --- src/hir_typeck/expr_cs.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 301c5d54..a0634022 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -3835,6 +3835,12 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T } } + // For `_` patterns, there's nothing to match, so they just succeed with no derefs + if( pattern.m_data.is_Any() ) + { + return true; + } + // If the type is a borrow, then count derefs required for the borrow // - If the first non-borrow inner is an ivar, return false unsigned n_deref = 0; -- cgit v1.2.3 From 0763219c6c2b29fba23646384e386bbefa094584 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 4 Jan 2019 22:04:30 +0800 Subject: Constant Evaluate - More handling of Defer constants --- src/hir/hir.cpp | 1 + src/hir_conv/constant_evaluation.cpp | 67 ++++++++++++++++++++++++++---------- src/mir/cleanup.cpp | 2 +- 3 files changed, 51 insertions(+), 19 deletions(-) diff --git a/src/hir/hir.cpp b/src/hir/hir.cpp index bd396df9..fdd564d6 100644 --- a/src/hir/hir.cpp +++ b/src/hir/hir.cpp @@ -1319,6 +1319,7 @@ const ::MIR::Function* HIR::Crate::get_or_gen_mir(const ::HIR::ItemPath& ip, con { if( !ep.m_mir ) { + TRACE_FUNCTION_F(ip); ASSERT_BUG(Span(), ep.m_state, "No ExprState for " << ip); auto& ep_mut = const_cast<::HIR::ExprPtr&>(ep); diff --git a/src/hir_conv/constant_evaluation.cpp b/src/hir_conv/constant_evaluation.cpp index 78148ba4..24fd3abc 100644 --- a/src/hir_conv/constant_evaluation.cpp +++ b/src/hir_conv/constant_evaluation.cpp @@ -64,7 +64,7 @@ namespace { { } - ::HIR::Literal evaluate_constant(const ::HIR::ItemPath& ip, const ::HIR::ExprPtr& expr, ::HIR::TypeRef exp); + ::HIR::Literal evaluate_constant(const ::HIR::ItemPath& ip, const ::HIR::ExprPtr& expr, ::HIR::TypeRef exp, MonomorphState ms={}); ::HIR::Literal evaluate_constant_mir(const ::HIR::ItemPath& ip, const ::MIR::Function& fcn, MonomorphState ms, ::HIR::TypeRef exp, ::std::vector< ::HIR::Literal> args); }; @@ -511,6 +511,10 @@ namespace { ), (Cast, auto inval = local_state.read_lval(e.val); + if( inval.is_Defer() ) { + val = ::HIR::Literal::make_Defer({}); + } + else TU_MATCH_DEF(::HIR::TypeRef::Data, (e.type.m_data), (te), ( // NOTE: Can be an unsizing! @@ -696,7 +700,9 @@ namespace { ), (MakeDst, auto ptr = read_param(e.ptr_val); + if(ptr.is_Defer()) return ::HIR::Literal::make_Defer({}); auto meta = read_param(e.meta_val); + if(meta.is_Defer()) return ::HIR::Literal::make_Defer({}); if( ! meta.is_Integer() ) { MIR_TODO(state, "RValue::MakeDst - (non-integral meta) " << ptr << " , " << meta); } @@ -707,26 +713,39 @@ namespace { (Tuple, ::std::vector< ::HIR::Literal> vals; vals.reserve( e.vals.size() ); - for(const auto& v : e.vals) + for(const auto& v : e.vals) { vals.push_back( read_param(v) ); + if( vals.back().is_Defer() ) { + return ::HIR::Literal::make_Defer({}); + } + } val = ::HIR::Literal::make_List( mv$(vals) ); ), (Array, ::std::vector< ::HIR::Literal> vals; vals.reserve( e.vals.size() ); - for(const auto& v : e.vals) + for(const auto& v : e.vals) { vals.push_back( read_param(v) ); + if( vals.back().is_Defer() ) { + return ::HIR::Literal::make_Defer({}); + } + } val = ::HIR::Literal::make_List( mv$(vals) ); ), (Variant, auto ival = read_param(e.val); + if(ival.is_Defer()) return ::HIR::Literal::make_Defer({}); val = ::HIR::Literal::make_Variant({ e.index, box$(ival) }); ), (Struct, ::std::vector< ::HIR::Literal> vals; vals.reserve( e.vals.size() ); - for(const auto& v : e.vals) + for(const auto& v : e.vals) { vals.push_back( read_param(v) ); + if( vals.back().is_Defer() ) { + return ::HIR::Literal::make_Defer({}); + } + } val = ::HIR::Literal::make_List( mv$(vals) ); ) ) @@ -735,15 +754,18 @@ namespace { dst = mv$(val); } state.set_cur_stmt_term(cur_block); - TU_MATCH_DEF( ::MIR::Terminator, (block.terminator), (e), - ( + TU_MATCH_HDRA( (block.terminator), {) + default: MIR_BUG(state, "Unexpected terminator - " << block.terminator); - ), - (Goto, + TU_ARMA(Goto, e) { cur_block = e; - ), - (Return, - if( exp.m_data.is_Primitive() ) + } + TU_ARMA(Return, e) { + if( retval.is_Defer() ) + { + // + } + else if( exp.m_data.is_Primitive() ) { switch( exp.m_data.as_Primitive() ) { @@ -784,8 +806,8 @@ namespace { } } return retval; - ), - (Call, + } + TU_ARMA(Call, e) { auto& dst = local_state.get_lval(e.ret_val); if( const auto* te = e.fcn.opt_Intrinsic() ) { @@ -827,12 +849,12 @@ namespace { MIR_BUG(state, "Unexpected terminator - " << block.terminator); } cur_block = e.ret_block; - ) - ) + } + } } } - ::HIR::Literal Evaluator::evaluate_constant(const ::HIR::ItemPath& ip, const ::HIR::ExprPtr& expr, ::HIR::TypeRef exp) + ::HIR::Literal Evaluator::evaluate_constant(const ::HIR::ItemPath& ip, const ::HIR::ExprPtr& expr, ::HIR::TypeRef exp, MonomorphState ms/*={}*/) { TRACE_FUNCTION_F(ip); const auto* mir = this->resolve.m_crate.get_or_gen_mir(ip, expr, exp); @@ -841,7 +863,6 @@ namespace { ::HIR::TypeRef ty_self { "Self", GENERIC_Self }; // Might want to have a fully-populated MonomorphState for expanding inside impl blocks // HACK: Generate a roughly-correct one - MonomorphState ms; const auto& top_ip = ip.get_top_ip(); if( top_ip.trait && !top_ip.ty ) { ms.self_ty = &ty_self; @@ -936,6 +957,7 @@ namespace { const ::HIR::Crate& m_crate; const ::HIR::Module* m_mod; const ::HIR::ItemPath* m_mod_path; + MonomorphState m_monomorph_state; public: Expander(const ::HIR::Crate& crate): @@ -1025,7 +1047,16 @@ namespace { } } } + + ::HIR::PathParams pp_impl; + for(const auto& tp : impl.m_params.m_types) + pp_impl.m_types.push_back( ::HIR::TypeRef(tp.m_name, pp_impl.m_types.size() | 256) ); + m_monomorph_state.pp_impl = &pp_impl; + ::HIR::Visitor::visit_trait_impl(trait_path, impl); + + m_monomorph_state.pp_impl = nullptr; + m_mod = nullptr; m_mod_path = nullptr; } @@ -1060,7 +1091,7 @@ namespace { if( item.m_value || item.m_value.m_mir ) { auto eval = Evaluator { item.m_value.span(), m_crate, NewvalState { *m_mod, *m_mod_path, FMT(p.get_name() << "$") } }; - item.m_value_res = eval.evaluate_constant(p, item.m_value, item.m_type.clone()); + item.m_value_res = eval.evaluate_constant(p, item.m_value, item.m_type.clone(), m_monomorph_state.clone()); check_lit_type(item.m_value.span(), item.m_type, item.m_value_res); diff --git a/src/mir/cleanup.cpp b/src/mir/cleanup.cpp index f3e987d6..fdc0f3d4 100644 --- a/src/mir/cleanup.cpp +++ b/src/mir/cleanup.cpp @@ -1093,7 +1093,7 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, // 1. Find the constant ::HIR::TypeRef ty; const auto* lit_ptr = MIR_Cleanup_GetConstant(state, ce.p, ty); - if( lit_ptr ) + if( lit_ptr && !lit_ptr->is_Defer() ) { DEBUG("Replace constant " << ce.p << " with " << *lit_ptr); se.src = MIR_Cleanup_LiteralToRValue(state, mutator, *lit_ptr, mv$(ty), mv$(ce.p)); -- cgit v1.2.3 From 611ea37948b415fba9c9f97bb14f8d279ca2eef3 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 4 Jan 2019 22:18:30 +0800 Subject: macro_rules eval - Handle `macro_rules!` in :item capture --- src/macro_rules/eval.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/macro_rules/eval.cpp b/src/macro_rules/eval.cpp index 23ffab77..e7b9a203 100644 --- a/src/macro_rules/eval.cpp +++ b/src/macro_rules/eval.cpp @@ -1586,6 +1586,7 @@ namespace return false; if( !lex.consume_if(TOK_EXCLAM) ) return false; + lex.consume_if(TOK_IDENT); bool need_semicolon = (lex.next() != TOK_BRACE_OPEN); consume_tt(lex); if( need_semicolon ) -- cgit v1.2.3 From c0267e165eca49583ac6ba7c3b48ba68ec4eee49 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 5 Jan 2019 10:52:48 +0800 Subject: HIR Bind - Handle cross-referencing default type params --- src/hir_conv/bind.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/hir_conv/bind.cpp b/src/hir_conv/bind.cpp index 37a6e494..9d15da18 100644 --- a/src/hir_conv/bind.cpp +++ b/src/hir_conv/bind.cpp @@ -317,6 +317,8 @@ namespace { return ; } + TRACE_FUNCTION_F(path); + if( params.m_types.size() == 0 && fill_infer ) { for(const auto& typ : param_defs.m_types) { (void)typ; @@ -337,9 +339,20 @@ namespace { auto ty = clone_ty_with(sp, typ.m_default, [&](const auto& ty, auto& out){ if(const auto* te = ty.m_data.opt_Generic() ) { - if( te->binding != GENERIC_Self || !self_ty ) + if( te->binding == GENERIC_Self ) { + if( !self_ty ) + TODO(sp, "Self enountered in default params, but no Self available - " << ty << " in " << typ.m_default << " for " << path); + out = self_ty->clone(); + } + // NOTE: Should only be seeing impl-level params here. Method-level ones are only seen in expression context. + else if( (te->binding >> 8) == 0 ) { + auto idx = te->binding & 0xFF; + ASSERT_BUG(sp, idx < params.m_types.size(), "TODO: Handle use of latter types in defaults"); + out = params.m_types[idx].clone(); + } + else { TODO(sp, "Monomorphise in fix_param_count - encountered " << ty << " in " << typ.m_default); - out = self_ty->clone(); + } return true; } return false; -- cgit v1.2.3 From 4ead75dea44e61502c8257161ff6b86fcc835adf Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 5 Jan 2019 15:09:30 +0800 Subject: Resolve Use - Handle partial shadowing of items/imports --- src/ast/path.hpp | 8 ++++++++ src/resolve/use.cpp | 55 +++++++++++++++++++++++++++-------------------------- 2 files changed, 36 insertions(+), 27 deletions(-) diff --git a/src/ast/path.hpp b/src/ast/path.hpp index 89804b61..18ebea49 100644 --- a/src/ast/path.hpp +++ b/src/ast/path.hpp @@ -245,6 +245,14 @@ public: bool has_binding() const { return !value.is_Unbound() || !type.is_Unbound() || !macro.is_Unbound(); } + void merge_from(const Bindings& x) { + if(value.is_Unbound()) + value = x.value.clone(); + if(type.is_Unbound()) + type = x.type.clone(); + if(macro.is_Unbound()) + macro = x.macro.clone(); + } } m_bindings; virtual ~Path(); diff --git a/src/resolve/use.cpp b/src/resolve/use.cpp index cde52de1..5fe7ee5c 100644 --- a/src/resolve/use.cpp +++ b/src/resolve/use.cpp @@ -334,10 +334,6 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path TODO(span, "Import of macro - " << des_item_name); } } - if( rv.has_binding() ) - { - return rv; - } // Imports for( const auto& imp : mod.items() ) @@ -352,14 +348,19 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path DEBUG("- Named import " << imp_e.name << " = " << imp_e.path); if( !imp_e.path.m_bindings.has_binding() ) { DEBUG(" > Needs resolve"); - // TODO: Handle possibility of recursion - //out_path = imp_e.path; - return Resolve_Use_GetBinding(sp2, crate, Resolve_Use_AbsolutisePath(sp2, mod.path(), imp_e.path), parent_modules); + static ::std::vector s_mods; + if( ::std::find(s_mods.begin(), s_mods.end(), &mod) == s_mods.end() ) + { + s_mods.push_back(&mod); + rv.merge_from( Resolve_Use_GetBinding(sp2, crate, Resolve_Use_AbsolutisePath(sp2, mod.path(), imp_e.path), parent_modules) ); + s_mods.pop_back(); + } } else { //out_path = imp_e.path; - return imp_e.path.m_bindings.clone(); + rv.merge_from( imp_e.path.m_bindings.clone() ); } + continue ; } if( imp.is_pub && imp_e.name == "" ) @@ -393,25 +394,19 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path TU_ARMA(Crate, e) { assert(e.crate_); const ::HIR::Module& hmod = e.crate_->m_hir->m_root_module; - auto rv = Resolve_Use_GetBinding__ext(sp2, crate, AST::Path("", { AST::PathNode(des_item_name,{}) }), hmod, 0); - if( rv.has_binding() ) { - return mv$(rv); + auto imp_rv = Resolve_Use_GetBinding__ext(sp2, crate, AST::Path("", { AST::PathNode(des_item_name,{}) }), hmod, 0); + if( imp_rv.has_binding() ) { + rv.merge_from( imp_rv ); } } TU_ARMA(Module, e) { if( e.module_ ) { // TODO: Prevent infinite recursion? - auto rv = Resolve_Use_GetBinding_Mod(span, crate, *e.module_, des_item_name, {}); - if( rv.has_binding() ) { - return mv$(rv); - } + rv.merge_from( Resolve_Use_GetBinding_Mod(span, crate, *e.module_, des_item_name, {}) ); } else if( e.hir ) { const ::HIR::Module& hmod = *e.hir; - auto rv = Resolve_Use_GetBinding__ext(sp2, crate, AST::Path("", { AST::PathNode(des_item_name,{}) }), hmod, 0); - if( rv.has_binding() ) { - return mv$(rv); - } + rv.merge_from( Resolve_Use_GetBinding__ext(sp2, crate, AST::Path("", { AST::PathNode(des_item_name,{}) }), hmod, 0) ); } else { BUG(span, "NULL module for binding on glob of " << imp_e.path); @@ -425,12 +420,13 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path for(const auto& var : enm.variants()) { if( var.m_name == des_item_name ) { - ::AST::Path::Bindings rv; + ::AST::Path::Bindings tmp_rv; if( var.m_data.is_Struct() ) - rv.type = ::AST::PathBinding_Type::make_EnumVar({ &enm, i }); + tmp_rv.type = ::AST::PathBinding_Type::make_EnumVar({ &enm, i }); else - rv.value = ::AST::PathBinding_Value::make_EnumVar({ &enm, i }); - return rv; + tmp_rv.value = ::AST::PathBinding_Value::make_EnumVar({ &enm, i }); + rv.merge_from(tmp_rv); + break; } i ++; } @@ -440,14 +436,15 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path auto idx = enm.find_variant(des_item_name); if( idx != SIZE_MAX ) { - ::AST::Path::Bindings rv; + ::AST::Path::Bindings tmp_rv; if( enm.m_data.is_Data() && enm.m_data.as_Data()[idx].is_struct ) { - rv.type = ::AST::PathBinding_Type::make_EnumVar({ nullptr, static_cast(idx), &enm }); + tmp_rv.type = ::AST::PathBinding_Type::make_EnumVar({ nullptr, static_cast(idx), &enm }); } else { - rv.value = ::AST::PathBinding_Value::make_EnumVar({ nullptr, static_cast(idx), &enm }); + tmp_rv.value = ::AST::PathBinding_Value::make_EnumVar({ nullptr, static_cast(idx), &enm }); } - return rv; + rv.merge_from(tmp_rv); + break; } } } break; @@ -458,6 +455,10 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path } } } + if( rv.has_binding() ) + { + return rv; + } if( mod.path().nodes().size() > 0 && mod.path().nodes().back().name()[0] == '#' ) { assert( parent_modules.size() > 0 ); -- cgit v1.2.3 From aa2f7a600ec4044785661a7b66b220420061a7bf Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 5 Jan 2019 15:12:42 +0800 Subject: Typecheck Expressions - Run EAT when checking auto traits --- src/hir_typeck/helpers.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index 3ff39c63..5853a9dc 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -2575,7 +2575,7 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, if( cmp != ::HIR::Compare::Unequal ) { if( markings ) { - ASSERT_BUG(sp, cmp == ::HIR::Compare::Equal, "Auto trait with no params returned a fuzzy match from destructure"); + ASSERT_BUG(sp, cmp == ::HIR::Compare::Equal, "Auto trait with no params returned a fuzzy match from destructure - " << trait << " for " << type); markings->auto_impls.insert( ::std::make_pair(trait, ::HIR::TraitMarkings::AutoMarking { {}, true }) ); } return callback( ImplRef(&type, params_ptr, &null_assoc), cmp ); @@ -2641,7 +2641,7 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, // HELPER: Get a possibily monomorphised version of the input type (stored in `tmp` if needed) auto monomorph_get = [&](const auto& ty)->const ::HIR::TypeRef& { if( monomorphise_type_needed(ty) ) { - return (tmp = monomorphise_type_with(sp, ty, monomorph_cb)); + return (tmp = this->expand_associated_types(sp, monomorphise_type_with(sp, ty, monomorph_cb))); } else { return ty; @@ -2710,9 +2710,11 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, BUG(sp, "UfcsUnknown in typeck - " << type); ), (UfcsKnown, - // If unbound, use Fuzzy - if(e.binding.is_Unbound()) + // If unbound, use Fuzzy { + if(e.binding.is_Unbound()) { + DEBUG("- Unbound UfcsKnown, returning Fuzzy"); return ::HIR::Compare::Fuzzy; + } // Otherwise, it's opaque. Check the bounds on the trait. TODO(sp, "Check trait bounds for bound on " << type); ), -- cgit v1.2.3 From 0be0edd9de59072ca5b780993c2b0bbece0e7aa1 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 5 Jan 2019 15:17:37 +0800 Subject: HIR - Visit result type --- src/hir/expr.cpp | 6 ++++++ src/hir/expr.hpp | 2 ++ src/hir_conv/constant_evaluation.cpp | 6 ++++++ src/hir_expand/closures.cpp | 1 + 4 files changed, 15 insertions(+) diff --git a/src/hir/expr.cpp b/src/hir/expr.cpp index 07504ea7..6b7c2e1a 100644 --- a/src/hir/expr.cpp +++ b/src/hir/expr.cpp @@ -19,6 +19,11 @@ void ::HIR::ExprVisitor::visit_node_ptr(::std::unique_ptr< ::HIR::ExprNode>& nod } void ::HIR::ExprVisitor::visit_node(::HIR::ExprNode& node) { } +void ::HIR::ExprVisitorDef::visit_node_ptr(::std::unique_ptr< ::HIR::ExprNode>& node_ptr) { + assert(node_ptr); + node_ptr->visit(*this); + visit_type(node_ptr->m_res_type); +} DEF_VISIT(ExprNode_Block, node, for(auto& subnode : node.m_nodes) { visit_node_ptr(subnode); @@ -83,6 +88,7 @@ DEF_VISIT(ExprNode_Borrow, node, visit_node_ptr(node.m_value); ) DEF_VISIT(ExprNode_Cast, node, + TRACE_FUNCTION_F("_Cast " << node.m_res_type); visit_node_ptr(node.m_value); ) DEF_VISIT(ExprNode_Unsize, node, diff --git a/src/hir/expr.hpp b/src/hir/expr.hpp index 55a4eaf2..15c0a489 100644 --- a/src/hir/expr.hpp +++ b/src/hir/expr.hpp @@ -865,6 +865,8 @@ class ExprVisitorDef: public: #define NV(nt) virtual void visit(nt& n); + virtual void visit_node_ptr(::std::unique_ptr& node_ptr) override; + NV(ExprNode_Block) NV(ExprNode_Asm) NV(ExprNode_Return) diff --git a/src/hir_conv/constant_evaluation.cpp b/src/hir_conv/constant_evaluation.cpp index 24fd3abc..f81663ec 100644 --- a/src/hir_conv/constant_evaluation.cpp +++ b/src/hir_conv/constant_evaluation.cpp @@ -978,6 +978,11 @@ namespace { m_mod = saved_m; m_mod_path = saved_mp; } + void visit_function(::HIR::ItemPath p, ::HIR::Function& f) override + { + TRACE_FUNCTION_F(p); + ::HIR::Visitor::visit_function(p, f); + } void visit_trait_impl(const ::HIR::SimplePath& trait_path, ::HIR::TraitImpl& impl) override { @@ -1147,6 +1152,7 @@ namespace { void visit_type(::HIR::TypeRef& ty) override { // Need to evaluate array sizes + DEBUG("expr type " << ty); m_exp.visit_type(ty); } void visit_path_params(::HIR::PathParams& pp) override { diff --git a/src/hir_expand/closures.cpp b/src/hir_expand/closures.cpp index 51b2c638..7cc3cee5 100644 --- a/src/hir_expand/closures.cpp +++ b/src/hir_expand/closures.cpp @@ -507,6 +507,7 @@ namespace { params_placeholders.push_back( ::HIR::TypeRef(params.m_types[i].m_name, i) ); impl_path_params.m_types.push_back( ::HIR::TypeRef(params.m_types[i].m_name, i) ); } + DEBUG("params_placeholders = " << params_placeholders << ", ofs_item = " << ofs_item << ", ofs_impl = " << ofs_impl); auto monomorph_cb = [&](const auto& ty)->const ::HIR::TypeRef& { const auto& ge = ty.m_data.as_Generic(); -- cgit v1.2.3 From fa3bf839ff871f862697ee1d992f0e6175c2a25b Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 5 Jan 2019 16:32:14 +0800 Subject: Expand - Macros in traits --- src/expand/mod.cpp | 33 ++++++- src/parse/common.hpp | 1 + src/parse/root.cpp | 261 +++++++++++++++++++++++++++------------------------ 3 files changed, 167 insertions(+), 128 deletions(-) diff --git a/src/expand/mod.cpp b/src/expand/mod.cpp index da37dea7..e4764be1 100644 --- a/src/expand/mod.cpp +++ b/src/expand/mod.cpp @@ -953,7 +953,7 @@ void Expand_Impl(::AST::Crate& crate, LList modstack, ::AST: TU_MATCH_DEF(AST::Item, (*i.data), (e), ( - throw ::std::runtime_error("BUG: Unknown item type in impl block"); + BUG(Span(), "Unknown item type in impl block - " << i.data->tag_str()); ), (None, ), (MacroInv, @@ -1214,17 +1214,44 @@ void Expand_Mod(::AST::Crate& crate, LList modstack, ::AST:: ), (Trait, Expand_GenericParams(crate, modstack, mod, e.params()); - for(auto& ti : e.items()) + auto& trait_items = e.items(); + for(size_t idx = 0; idx < trait_items.size(); idx ++) { + auto& ti = trait_items[idx]; DEBUG(" - " << ti.name << " " << ti.data.tag_str()); auto attrs = mv$(ti.data.attrs); Expand_Attrs(attrs, AttrStage::Pre, crate, AST::Path(), mod, ti.data); TU_MATCH_DEF(AST::Item, (ti.data), (e), ( - throw ::std::runtime_error("BUG: Unknown item type in impl block"); + BUG(Span(), "Unknown item type in trait block - " << ti.data.tag_str()); ), (None, ), + (MacroInv, + if( e.name() != "" ) + { + TRACE_FUNCTION_F("Macro invoke " << e.name()); + // Move out of the module to avoid invalidation if a new macro invocation is added + auto mi_owned = mv$(e); + + auto ttl = Expand_Macro(crate, modstack, mod, mi_owned); + + if( ttl.get() ) + { + // Re-parse tt + size_t insert_pos = idx+1; + while( ttl->lookahead(0) != TOK_EOF ) + { + auto i = Parse_Trait_Item(*ttl); + trait_items.insert( trait_items.begin() + insert_pos, mv$(i) ); + insert_pos ++; + } + // - Any new macro invocations ends up at the end of the list and handled + } + // Move back in (using the index, as the old pointer may be invalid) + trait_items[idx].data.as_MacroInv() = mv$(mi_owned); + } + ), (Function, Expand_GenericParams(crate, modstack, mod, e.params()); for(auto& arg : e.args()) { diff --git a/src/parse/common.hpp b/src/parse/common.hpp index c742fe4f..c8f51520 100644 --- a/src/parse/common.hpp +++ b/src/parse/common.hpp @@ -50,6 +50,7 @@ extern TypeRef Parse_Type(TokenStream& lex, bool allow_trait_list = true); extern AST::Pattern Parse_Pattern(TokenStream& lex, bool is_refutable); extern void Parse_Impl_Item(TokenStream& lex, AST::Impl& impl); +extern AST::Named Parse_Trait_Item(TokenStream& lex); extern void Parse_Mod_Item(TokenStream& lex, AST::Module& mod, AST::AttributeList meta_items); extern ::AST::Named<::AST::Item> Parse_Mod_Item_S(TokenStream& lex, const AST::Module::FileInfo& mod_fileinfo, const ::AST::Path& mod_path, AST::AttributeList meta_items); extern void Parse_ModRoot_Items(TokenStream& lex, AST::Module& mod); diff --git a/src/parse/root.cpp b/src/parse/root.cpp index 28a49287..c3fbfdd1 100644 --- a/src/parse/root.cpp +++ b/src/parse/root.cpp @@ -639,6 +639,141 @@ AST::Struct Parse_Struct(TokenStream& lex, const AST::AttributeList& meta_items) } } +AST::Named Parse_Trait_Item(TokenStream& lex) +{ + Token tok; + + auto item_attrs = Parse_ItemAttrs(lex); + SET_ATTRS(lex, item_attrs); + + auto ps = lex.start_span(); + { + ::AST::MacroInvocation inv; + if( Parse_MacroInvocation_Opt(lex, inv) ) + { + return AST::Named( "", AST::Item(mv$(inv)), false ); + } + } + + GET_TOK(tok, lex); + bool is_specialisable = false; + if( tok.type() == TOK_IDENT && tok.str() == "default" ) { + is_specialisable = true; + GET_TOK(tok, lex); + } + // TODO: Mark specialisation + (void)is_specialisable; + + bool fn_is_const = false; + bool fn_is_unsafe = false; + ::std::string abi = ABI_RUST; + + ::std::string name; + ::AST::Item rv; + switch(tok.type()) + { + case TOK_RWORD_STATIC: { + GET_CHECK_TOK(tok, lex, TOK_IDENT); + name = mv$(tok.str()); + GET_CHECK_TOK(tok, lex, TOK_COLON); + auto ty = Parse_Type(lex); + GET_CHECK_TOK(tok, lex, TOK_SEMICOLON); + + ::AST::Expr val; + if(GET_TOK(tok, lex) == TOK_EQUAL) { + val = Parse_Expr(lex); + GET_TOK(tok, lex); + } + CHECK_TOK(tok, TOK_SEMICOLON); + + rv = ::AST::Static(::AST::Static::STATIC, mv$(ty), val); + break; } + case TOK_RWORD_CONST: { + GET_CHECK_TOK(tok, lex, TOK_IDENT); + name = mv$(tok.str()); + GET_CHECK_TOK(tok, lex, TOK_COLON); + auto ty = Parse_Type(lex); + + ::AST::Expr val; + if(GET_TOK(tok, lex) == TOK_EQUAL) { + val = Parse_Expr(lex); + GET_TOK(tok, lex); + } + CHECK_TOK(tok, TOK_SEMICOLON); + + rv = ::AST::Static(AST::Static::CONST, mv$(ty), val); + break; } + // Associated type + case TOK_RWORD_TYPE: { + auto atype_params = ::AST::GenericParams { }; + GET_CHECK_TOK(tok, lex, TOK_IDENT); + name = mv$(tok.str()); + if( GET_TOK(tok, lex) == TOK_COLON ) + { + // Bounded associated type + Parse_TypeBound(lex, atype_params, TypeRef(lex.point_span(), "Self", 0xFFFF)); + GET_TOK(tok, lex); + } + if( tok.type() == TOK_RWORD_WHERE ) { + throw ParseError::Todo(lex, "Where clause on associated type"); + } + + TypeRef default_type = TypeRef( lex.point_span() ); + if( tok.type() == TOK_EQUAL ) { + default_type = Parse_Type(lex); + GET_TOK(tok, lex); + } + + CHECK_TOK(tok, TOK_SEMICOLON); + rv = ::AST::TypeAlias( mv$(atype_params), mv$(default_type) ); + break; } + + // Functions (possibly unsafe) + case TOK_RWORD_UNSAFE: + fn_is_unsafe = true; + if( GET_TOK(tok, lex) == TOK_RWORD_EXTERN ) + case TOK_RWORD_EXTERN: + { + abi = "C"; + if( GET_TOK(tok, lex) == TOK_STRING ) + abi = tok.str(); + else + PUTBACK(tok, lex); + + GET_TOK(tok, lex); + } + CHECK_TOK(tok, TOK_RWORD_FN); + case TOK_RWORD_FN: { + GET_CHECK_TOK(tok, lex, TOK_IDENT); + name = mv$(tok.str()); + // Self allowed, prototype-form allowed (optional names and no code) + auto fcn = Parse_FunctionDef(lex, abi, true, true, fn_is_unsafe, fn_is_const); + if( GET_TOK(tok, lex) == TOK_BRACE_OPEN ) + { + PUTBACK(tok, lex); + // Enter a new hygine scope for the function body. (TODO: Should this be in Parse_ExprBlock?) + lex.push_hygine(); + fcn.set_code( Parse_ExprBlock(lex) ); + lex.pop_hygine(); + } + else if( tok.type() == TOK_SEMICOLON ) + { + // Accept it + } + else + { + throw ParseError::Unexpected(lex, tok); + } + rv = ::std::move(fcn); + break; } + default: + throw ParseError::Unexpected(lex, tok); + } + + rv.attrs = ::std::move( item_attrs ); + return ::AST::Named<::AST::Item>( mv$(name), mv$(rv), true ); +} + AST::Trait Parse_TraitDef(TokenStream& lex, const AST::AttributeList& meta_items) { TRACE_FUNCTION; @@ -689,131 +824,7 @@ AST::Trait Parse_TraitDef(TokenStream& lex, const AST::AttributeList& meta_items { PUTBACK(tok, lex); - auto item_attrs = Parse_ItemAttrs(lex); - SET_ATTRS(lex, item_attrs); - - auto ps = lex.start_span(); - { - ::AST::MacroInvocation inv; - if( Parse_MacroInvocation_Opt(lex, inv) ) - { - trait.items().push_back( AST::Named("", AST::Item(mv$(inv)), false) ); - continue ; - } - GET_TOK(tok, lex); - } - - bool is_specialisable = false; - if( tok.type() == TOK_IDENT && tok.str() == "default" ) { - is_specialisable = true; - GET_TOK(tok, lex); - } - // TODO: Mark specialisation - (void)is_specialisable; - - bool fn_is_const = false; - bool fn_is_unsafe = false; - ::std::string abi = ABI_RUST; - switch(tok.type()) - { - case TOK_RWORD_STATIC: { - GET_CHECK_TOK(tok, lex, TOK_IDENT); - auto name = mv$(tok.str()); - GET_CHECK_TOK(tok, lex, TOK_COLON); - auto ty = Parse_Type(lex); - GET_CHECK_TOK(tok, lex, TOK_SEMICOLON); - - ::AST::Expr val; - if(GET_TOK(tok, lex) == TOK_EQUAL) { - val = Parse_Expr(lex); - GET_TOK(tok, lex); - } - CHECK_TOK(tok, TOK_SEMICOLON); - - trait.add_static( mv$(name), mv$(item_attrs), ::AST::Static(AST::Static::STATIC, mv$(ty), val) ); - break; } - case TOK_RWORD_CONST: { - GET_CHECK_TOK(tok, lex, TOK_IDENT); - auto name = mv$(tok.str()); - GET_CHECK_TOK(tok, lex, TOK_COLON); - auto ty = Parse_Type(lex); - - ::AST::Expr val; - if(GET_TOK(tok, lex) == TOK_EQUAL) { - val = Parse_Expr(lex); - GET_TOK(tok, lex); - } - CHECK_TOK(tok, TOK_SEMICOLON); - - trait.add_static( mv$(name), mv$(item_attrs), ::AST::Static(AST::Static::CONST, mv$(ty), val) ); - break; } - // Associated type - case TOK_RWORD_TYPE: { - auto atype_params = ::AST::GenericParams { }; - GET_CHECK_TOK(tok, lex, TOK_IDENT); - auto name = mv$(tok.str()); - if( GET_TOK(tok, lex) == TOK_COLON ) - { - // Bounded associated type - Parse_TypeBound(lex, atype_params, TypeRef(lex.point_span(), "Self", 0xFFFF)); - GET_TOK(tok, lex); - } - if( tok.type() == TOK_RWORD_WHERE ) { - throw ParseError::Todo(lex, "Where clause on associated type"); - } - - TypeRef default_type = TypeRef( lex.point_span() ); - if( tok.type() == TOK_EQUAL ) { - default_type = Parse_Type(lex); - GET_TOK(tok, lex); - } - - CHECK_TOK(tok, TOK_SEMICOLON); - trait.add_type( ::std::move(name), mv$(item_attrs), ::std::move(default_type) ); - trait.items().back().data.as_Type().params() = mv$(atype_params); - break; } - - // Functions (possibly unsafe) - case TOK_RWORD_UNSAFE: - fn_is_unsafe = true; - if( GET_TOK(tok, lex) == TOK_RWORD_EXTERN ) - case TOK_RWORD_EXTERN: - { - abi = "C"; - if( GET_TOK(tok, lex) == TOK_STRING ) - abi = tok.str(); - else - PUTBACK(tok, lex); - - GET_TOK(tok, lex); - } - CHECK_TOK(tok, TOK_RWORD_FN); - case TOK_RWORD_FN: { - GET_CHECK_TOK(tok, lex, TOK_IDENT); - ::std::string name = mv$(tok.str()); - // Self allowed, prototype-form allowed (optional names and no code) - auto fcn = Parse_FunctionDef(lex, abi, true, true, fn_is_unsafe, fn_is_const); - if( GET_TOK(tok, lex) == TOK_BRACE_OPEN ) - { - PUTBACK(tok, lex); - // Enter a new hygine scope for the function body. (TODO: Should this be in Parse_ExprBlock?) - lex.push_hygine(); - fcn.set_code( Parse_ExprBlock(lex) ); - lex.pop_hygine(); - } - else if( tok.type() == TOK_SEMICOLON ) - { - // Accept it - } - else - { - throw ParseError::Unexpected(lex, tok); - } - trait.add_function( ::std::move(name), mv$(item_attrs), ::std::move(fcn) ); - break; } - default: - throw ParseError::Unexpected(lex, tok); - } + trait.items().push_back( Parse_Trait_Item(lex) ); } return trait; -- cgit v1.2.3 From 20ae8946a614f93cd8b1d1f9315a4478de2c867f Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 5 Jan 2019 21:29:24 +0800 Subject: Resolve Use - Handle external enums --- src/resolve/use.cpp | 53 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/src/resolve/use.cpp b/src/resolve/use.cpp index 5fe7ee5c..52a4ebb6 100644 --- a/src/resolve/use.cpp +++ b/src/resolve/use.cpp @@ -217,6 +217,9 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path (None, // Deleted, ignore ), + (MacroInv, + // TODO: Should this already be deleted? + ), (Type, ), (Function, @@ -764,33 +767,57 @@ namespace { return Resolve_Use_GetBinding__ext(span, crate, path, *e.crate_, i+1); } TU_ARMA(Enum, e) { - const auto& enum_ = *e.enum_; + ASSERT_BUG(span, e.enum_ || e.hir, "nullptr enum pointer in node " << i << " of " << path); + ASSERT_BUG(span, e.enum_ == nullptr || e.hir == nullptr, "both AST and HIR pointers set in node " << i << " of " << path); i += 1; if( i != nodes.size() - 1 ) { ERROR(span, E0000, "Encountered enum at unexpected location in import"); } + ASSERT_BUG(span, i < nodes.size(), "Enum import position error, " << i << " >= " << nodes.size() << " - " << path); const auto& node2 = nodes[i]; - int variant_index = -1; + + unsigned variant_index = 0; bool is_value; - for( unsigned int j = 0; j < enum_.variants().size(); j ++ ) + if(e.hir) { - if( enum_.variants()[j].m_name == node2.name() ) { - variant_index = j; - is_value = !enum_.variants()[j].m_data.is_Struct(); - break ; + const auto& enum_ = *e.hir; + size_t idx = enum_.find_variant(node2.name()); + if( idx == ~0u ) { + ERROR(span, E0000, "Unknown enum variant " << path); } + TU_MATCH_HDRA( (enum_.m_data), {) + TU_ARMA(Value, ve) { + is_value = true; + } + TU_ARMA(Data, ve) { + is_value = !ve[idx].is_struct; + } + } + DEBUG("AST Enum variant - " << variant_index << ", is_value=" << is_value); } - if( variant_index < 0 ) { - ERROR(span, E0000, "Unknown enum variant '" << node2.name() << "'"); - } + else + { + const auto& enum_ = *e.enum_; + for( const auto& var : enum_.variants() ) + { + if( var.m_name == node2.name() ) { + is_value = !var.m_data.is_Struct(); + break ; + } + variant_index ++; + } + if( variant_index == enum_.variants().size() ) { + ERROR(span, E0000, "Unknown enum variant '" << node2.name() << "'"); + } - DEBUG("AST Enum variant - " << variant_index << ", is_value=" << is_value << " " << enum_.variants()[variant_index].m_data.tag_str()); + DEBUG("AST Enum variant - " << variant_index << ", is_value=" << is_value << " " << enum_.variants()[variant_index].m_data.tag_str()); + } if( is_value ) { - rv.value = ::AST::PathBinding_Value::make_EnumVar({&enum_, static_cast(variant_index)}); + rv.value = ::AST::PathBinding_Value::make_EnumVar({e.enum_, variant_index, e.hir}); } else { - rv.type = ::AST::PathBinding_Type::make_EnumVar({&enum_, static_cast(variant_index)}); + rv.type = ::AST::PathBinding_Type::make_EnumVar({e.enum_, variant_index, e.hir}); } return rv; } -- cgit v1.2.3 From 6d0fe344e94670f2ac0e21094238181f38b0daec Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 5 Jan 2019 21:40:36 +0800 Subject: Handle MacroInv in some more places --- src/hir/from_ast.cpp | 3 +++ src/resolve/absolute.cpp | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/hir/from_ast.cpp b/src/hir/from_ast.cpp index 49e5a4b6..32561a76 100644 --- a/src/hir/from_ast.cpp +++ b/src/hir/from_ast.cpp @@ -1155,6 +1155,9 @@ namespace { (None, // Ignore. ), + (MacroInv, + // Ignore. + ), (Type, bool is_sized = true; ::std::vector< ::HIR::TraitPath> trait_bounds; diff --git a/src/resolve/absolute.cpp b/src/resolve/absolute.cpp index 7fa08aaf..d4147e92 100644 --- a/src/resolve/absolute.cpp +++ b/src/resolve/absolute.cpp @@ -1933,7 +1933,9 @@ void Resolve_Absolute_ImplItems(Context& item_context, ::AST::NamedList< ::AST: { TU_MATCH(AST::Item, (i.data), (e), (None, ), - (MacroInv, BUG(i.data.span, "Resolve_Absolute_ImplItems - MacroInv");), + (MacroInv, + //BUG(i.data.span, "Resolve_Absolute_ImplItems - MacroInv"); + ), (ExternBlock, BUG(i.data.span, "Resolve_Absolute_ImplItems - " << i.data.tag_str());), (Impl, BUG(i.data.span, "Resolve_Absolute_ImplItems - " << i.data.tag_str());), (NegImpl, BUG(i.data.span, "Resolve_Absolute_ImplItems - " << i.data.tag_str());), -- cgit v1.2.3 From c31f5534f50f986f7c5d2121490213280bbec986 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 12 Jan 2019 18:51:59 +0800 Subject: HIR Typecheck - Debugging tweaks --- src/hir/visitor.cpp | 6 ++++++ src/hir_typeck/expr_cs.cpp | 9 ++++++--- src/hir_typeck/helpers.cpp | 8 ++++++-- src/hir_typeck/impl_ref.cpp | 2 +- 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/hir/visitor.cpp b/src/hir/visitor.cpp index 87b790ae..5c9c0dfa 100644 --- a/src/hir/visitor.cpp +++ b/src/hir/visitor.cpp @@ -229,18 +229,21 @@ void ::HIR::Visitor::visit_enum(::HIR::ItemPath p, ::HIR::Enum& item) } void ::HIR::Visitor::visit_union(::HIR::ItemPath p, ::HIR::Union& item) { + TRACE_FUNCTION_F(p); this->visit_params(item.m_params); for(auto& var : item.m_variants) this->visit_type(var.second.ent); } void ::HIR::Visitor::visit_associatedtype(ItemPath p, ::HIR::AssociatedType& item) { + TRACE_FUNCTION_F(p); for(auto& bound : item.m_trait_bounds) this->visit_trait_path(bound); this->visit_type(item.m_default); } void ::HIR::Visitor::visit_function(::HIR::ItemPath p, ::HIR::Function& item) { + TRACE_FUNCTION_F(p); this->visit_params(item.m_params); for(auto& arg : item.m_args) { @@ -252,11 +255,13 @@ void ::HIR::Visitor::visit_function(::HIR::ItemPath p, ::HIR::Function& item) } void ::HIR::Visitor::visit_static(::HIR::ItemPath p, ::HIR::Static& item) { + TRACE_FUNCTION_F(p); this->visit_type(item.m_type); this->visit_expr(item.m_value); } void ::HIR::Visitor::visit_constant(::HIR::ItemPath p, ::HIR::Constant& item) { + TRACE_FUNCTION_F(p); this->visit_params(item.m_params); this->visit_type(item.m_type); this->visit_expr(item.m_value); @@ -264,6 +269,7 @@ void ::HIR::Visitor::visit_constant(::HIR::ItemPath p, ::HIR::Constant& item) void ::HIR::Visitor::visit_params(::HIR::GenericParams& params) { + TRACE_FUNCTION_F(params.fmt_args() << params.fmt_bounds()); for(auto& tps : params.m_types) this->visit_type( tps.m_default ); for(auto& bound : params.m_bounds ) diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index a0634022..4a5171f5 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -256,6 +256,7 @@ namespace { void apply_bounds_as_rules(Context& context, const Span& sp, const ::HIR::GenericParams& params_def, t_cb_generic monomorph_cb, bool is_impl_level) { + TRACE_FUNCTION; for(const auto& bound : params_def.m_bounds) { TU_MATCH(::HIR::GenericBound, (bound), (be), @@ -409,11 +410,13 @@ namespace { // --- Monomorphise the argument/return types (into current context) for(const auto& arg : fcn.m_args) { - DEBUG("Arg " << arg.first << ": " << arg.second); + TRACE_FUNCTION_FR(path << " - Arg " << arg.first << ": " << arg.second, "Arg " << arg.first << " : " << cache.m_arg_types.back()); cache.m_arg_types.push_back( monomorphise_type_with(sp, arg.second, monomorph_cb, false) ); } - DEBUG("Ret " << fcn.m_return); - cache.m_arg_types.push_back( monomorphise_type_with(sp, fcn.m_return, monomorph_cb, false) ); + { + TRACE_FUNCTION_FR(path << " - Ret " << fcn.m_return, "Ret " << cache.m_arg_types.back()); + cache.m_arg_types.push_back( monomorphise_type_with(sp, fcn.m_return, monomorph_cb, false) ); + } // --- Apply bounds by adding them to the associated type ruleset apply_bounds_as_rules(context, sp, *cache.m_fcn_params, cache.m_monomorph_cb, /*is_impl_level=*/false); diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index 5853a9dc..d4d16aad 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -2292,6 +2292,10 @@ bool TraitResolution::find_trait_impls_bound(const Span& sp, const ::HIR::Simple ) ) + //if(type.m_data.is_Infer()) { + // return false; + //} + // NOTE: Even if the type is completely unknown (infer or unbound UFCS), search the bound list. // TODO: A bound can imply something via its associated types. How deep can this go? @@ -2930,9 +2934,9 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, auto i_tp = impl.get_trait_params(); for(auto& t : i_tp.m_types) this->expand_associated_types_inplace( sp, t, {} ); - DEBUG(real_type << " ?= " << i_ty); + DEBUG("[ftic_check_params] " << real_type << " ?= " << i_ty); cmp &= real_type .match_test_generics_fuzz(sp, i_ty, cb_infer, cb_match); - DEBUG(real_trait_path.m_params << " ?= " << i_tp); + DEBUG("[ftic_check_params] " << real_trait_path.m_params << " ?= " << i_tp); cmp &= real_trait_path.m_params .match_test_generics_fuzz(sp, i_tp, cb_infer, cb_match); DEBUG("[ftic_check_params] - Re-check result: " << cmp); } diff --git a/src/hir_typeck/impl_ref.cpp b/src/hir_typeck/impl_ref.cpp index 1aa8fc2b..86f88648 100644 --- a/src/hir_typeck/impl_ref.cpp +++ b/src/hir_typeck/impl_ref.cpp @@ -198,11 +198,11 @@ bool ImplRef::type_is_specialisable(const char* name) const static Span sp; TU_MATCH(Data, (this->m_data), (e), (TraitImpl, - DEBUG("name=" << name << " " << *this); auto it = e.impl->m_types.find(name); if( it == e.impl->m_types.end() ) return ::HIR::TypeRef(); const ::HIR::TypeRef& tpl_ty = it->second.data; + DEBUG("name=" << name << " tpl_ty=" << tpl_ty << " " << *this); if( monomorphise_type_needed(tpl_ty) ) { return monomorphise_type_with(sp, tpl_ty, this->get_cb_monomorph_traitimpl(sp)); } -- cgit v1.2.3 From 22afa5803a6b5466168f281f484826177e89128e Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 12 Jan 2019 22:17:20 +0800 Subject: HIR Typecheck Outer - Duplicate the "Resolve UFCS" pass to use simpler logic for outer context --- Makefile | 4 +- src/hir_conv/main_bindings.hpp | 1 + src/hir_conv/resolve_ufcs.cpp | 9 + src/hir_conv/resolve_ufcs_outer.cpp | 345 ++++++++++++++++++++++++++++++++++++ src/hir_typeck/static.cpp | 19 +- src/main.cpp | 11 ++ 6 files changed, 382 insertions(+), 7 deletions(-) create mode 100644 src/hir_conv/resolve_ufcs_outer.cpp diff --git a/Makefile b/Makefile index 29a8e39e..3eb72d0f 100644 --- a/Makefile +++ b/Makefile @@ -97,7 +97,7 @@ OBJ += hir/hir.o hir/generic_params.o OBJ += hir/crate_ptr.o hir/expr_ptr.o OBJ += hir/type.o hir/path.o hir/expr.o hir/pattern.o OBJ += hir/visitor.o hir/crate_post_load.o -OBJ += hir_conv/expand_type.o hir_conv/constant_evaluation.o hir_conv/resolve_ufcs.o hir_conv/bind.o hir_conv/markings.o +OBJ += hir_conv/expand_type.o hir_conv/constant_evaluation.o hir_conv/resolve_ufcs.o hir_conv/resolve_ufcs_outer.o hir_conv/bind.o hir_conv/markings.o OBJ += hir_typeck/outer.o hir_typeck/common.o hir_typeck/helpers.o hir_typeck/static.o hir_typeck/impl_ref.o OBJ += hir_typeck/expr_visit.o OBJ += hir_typeck/expr_cs.o @@ -222,7 +222,7 @@ rust_tests: RUST_TESTS_run-pass .PHONY: RUST_TESTS RUST_TESTS_run-pass RUST_TESTS: RUST_TESTS_run-pass -RUST_TESTS_run-pass: output/librust_test_helpers.a +RUST_TESTS_run-pass: @$(MAKE) -C tools/testrunner @mkdir -p output/rust_tests/run-pass ./tools/bin/testrunner -o output/rust_tests/run-pass $(RUST_TESTS_DIR)run-pass --exceptions disabled_tests_run-pass.txt diff --git a/src/hir_conv/main_bindings.hpp b/src/hir_conv/main_bindings.hpp index 37488dae..e2ec3e34 100644 --- a/src/hir_conv/main_bindings.hpp +++ b/src/hir_conv/main_bindings.hpp @@ -13,6 +13,7 @@ namespace HIR { extern void ConvertHIR_ExpandAliases(::HIR::Crate& crate); extern void ConvertHIR_Bind(::HIR::Crate& crate); +extern void ConvertHIR_ResolveUFCS_Outer(::HIR::Crate& crate); extern void ConvertHIR_ResolveUFCS(::HIR::Crate& crate); extern void ConvertHIR_Markings(::HIR::Crate& crate); extern void ConvertHIR_ConstantEvaluate(::HIR::Crate& hir_crate); diff --git a/src/hir_conv/resolve_ufcs.cpp b/src/hir_conv/resolve_ufcs.cpp index 5481fbb9..9bdb2feb 100644 --- a/src/hir_conv/resolve_ufcs.cpp +++ b/src/hir_conv/resolve_ufcs.cpp @@ -5,6 +5,8 @@ * hir_conv/resolve_ufcs.cpp * - Resolve unkown UFCS traits into inherent or trait * - HACK: Will likely be replaced with a proper typeck pass (no it won't) + * + * - TODO: What are the rules for UFCS lookup? */ #include "main_bindings.hpp" #include @@ -115,6 +117,13 @@ namespace { TRACE_FUNCTION_F("impl" << impl.m_params.fmt_args() << " " << trait_path << impl.m_trait_args << " for " << impl.m_type << " (mod=" << impl.m_src_module << ")"); auto _t = this->push_mod_traits( this->m_crate.get_mod_by_path(Span(), impl.m_src_module) ); auto _g = m_resolve.set_impl_generics(impl.m_params); + // TODO: Handle resolution of all items in m_resolve.m_type_equalities + // - params might reference each other, so `set_item_generics` has to have been called + // - But `m_type_equalities` can end up with non-resolved UFCS paths + for(auto& e : m_resolve.m_type_equalities) + { + visit_type(e.second); + } // TODO: Push a bound that `Self: ThisTrait` m_current_type = &impl.m_type; diff --git a/src/hir_conv/resolve_ufcs_outer.cpp b/src/hir_conv/resolve_ufcs_outer.cpp new file mode 100644 index 00000000..a8accf4d --- /dev/null +++ b/src/hir_conv/resolve_ufcs_outer.cpp @@ -0,0 +1,345 @@ +/* + * MRustC - Rust Compiler + * - By John Hodge (Mutabah/thePowersGang) + * + * hir_conv/resolve_ufcs_outer.cpp + * - Resolve UfcsUnknown paths in outer scope (signatures/types) + * + * RULES: + * - Only generics are allowed to be UfcsKnown in signatures/types (within bodies anything goes?) + */ +#include "main_bindings.hpp" +#include +#include +#include +#include // monomorphise_genericpath_needed + +namespace { + class Visitor: + public ::HIR::Visitor + { + const ::HIR::Crate& m_crate; + + const ::HIR::GenericParams* m_params_impl = nullptr; + const ::HIR::GenericParams* m_params_method = nullptr; + + const ::HIR::TypeRef* m_current_type = nullptr; // used because sometimes `Self` is already replaced + const ::HIR::Trait* m_current_trait = nullptr; + const ::HIR::ItemPath* m_current_trait_path = nullptr; + + public: + Visitor(const ::HIR::Crate& crate): + m_crate(crate) + {} + + void visit_struct(::HIR::ItemPath p, ::HIR::Struct& item) override { + m_params_method = &item.m_params; + ::HIR::Visitor::visit_struct(p, item); + m_params_method = nullptr; + } + void visit_enum(::HIR::ItemPath p, ::HIR::Enum& item) override { + m_params_method = &item.m_params; + ::HIR::Visitor::visit_enum(p, item); + m_params_method = nullptr; + } + void visit_function(::HIR::ItemPath p, ::HIR::Function& item) override { + m_params_method = &item.m_params; + ::HIR::Visitor::visit_function(p, item); + m_params_method = nullptr; + } + void visit_type_alias(::HIR::ItemPath p, ::HIR::TypeAlias& item) override { + // NOTE: Disabled, becuase generics in type aliases are never checked +#if 0 + auto _ = m_resolve.set_item_generics(item.m_params); + ::HIR::Visitor::visit_function(p, item); +#endif + } + void visit_trait(::HIR::ItemPath p, ::HIR::Trait& trait) override { + m_params_impl = &trait.m_params; + m_current_trait = &trait; + m_current_trait_path = &p; + ::HIR::Visitor::visit_trait(p, trait); + m_current_trait = nullptr; + m_params_impl = nullptr; + } + void visit_type_impl(::HIR::TypeImpl& impl) override { + TRACE_FUNCTION_F("impl" << impl.m_params.fmt_args() << " " << impl.m_type << " (mod=" << impl.m_src_module << ")"); + m_params_impl = &impl.m_params; + m_current_type = &impl.m_type; + ::HIR::Visitor::visit_type_impl(impl); + m_current_type = nullptr; + m_params_impl = nullptr; + } + void visit_marker_impl(const ::HIR::SimplePath& trait_path, ::HIR::MarkerImpl& impl) override { + ::HIR::ItemPath p( impl.m_type, trait_path, impl.m_trait_args ); + TRACE_FUNCTION_F("impl" << impl.m_params.fmt_args() << " " << trait_path << impl.m_trait_args << " for " << impl.m_type << " (mod=" << impl.m_src_module << ")"); + + m_params_impl = &impl.m_params; + m_current_type = &impl.m_type; + m_current_trait = &m_crate.get_trait_by_path(Span(), trait_path); + m_current_trait_path = &p; + + ::HIR::Visitor::visit_marker_impl(trait_path, impl); + + m_current_trait = nullptr; + m_current_type = nullptr; + m_params_impl = nullptr; + } + void visit_trait_impl(const ::HIR::SimplePath& trait_path, ::HIR::TraitImpl& impl) override { + ::HIR::ItemPath p( impl.m_type, trait_path, impl.m_trait_args ); + TRACE_FUNCTION_F("impl" << impl.m_params.fmt_args() << " " << trait_path << impl.m_trait_args << " for " << impl.m_type << " (mod=" << impl.m_src_module << ")"); + + m_params_impl = &impl.m_params; + m_current_type = &impl.m_type; + m_current_trait = &m_crate.get_trait_by_path(Span(), trait_path); + m_current_trait_path = &p; + + ::HIR::Visitor::visit_trait_impl(trait_path, impl); + + m_current_trait = nullptr; + m_current_type = nullptr; + m_params_impl = nullptr; + } + + void visit_expr(::HIR::ExprPtr& expr) override + { + // No inner visiting for expressions + } + + bool locate_trait_item_in_bounds(::HIR::Visitor::PathContext pc, const ::HIR::TypeRef& tr, const ::HIR::GenericParams& params, ::HIR::Path::Data& pd) { + static Span sp; + //const auto& name = pd.as_UfcsUnknown().item; + for(const auto& b : params.m_bounds) + { + TU_IFLET(::HIR::GenericBound, b, TraitBound, e, + DEBUG("- " << e.type << " : " << e.trait.m_path); + if( e.type == tr ) { + DEBUG(" - Match"); + if( locate_in_trait_and_set(pc, e.trait.m_path, m_crate.get_trait_by_path(sp, e.trait.m_path.m_path), pd) ) { + return true; + } + } + ); + // - + } + return false; + } + static ::HIR::Path::Data get_ufcs_known(::HIR::Path::Data::Data_UfcsUnknown e, ::HIR::GenericPath trait_path, const ::HIR::Trait& trait) + { + return ::HIR::Path::Data::make_UfcsKnown({ mv$(e.type), mv$(trait_path), mv$(e.item), mv$(e.params)} ); + } + static bool locate_item_in_trait(::HIR::Visitor::PathContext pc, const ::HIR::Trait& trait, ::HIR::Path::Data& pd) + { + const auto& e = pd.as_UfcsUnknown(); + + switch(pc) + { + case ::HIR::Visitor::PathContext::VALUE: + if( trait.m_values.find( e.item ) != trait.m_values.end() ) { + return true; + } + break; + case ::HIR::Visitor::PathContext::TRAIT: + break; + case ::HIR::Visitor::PathContext::TYPE: + if( trait.m_types.find( e.item ) != trait.m_types.end() ) { + return true; + } + break; + } + return false; + } + static ::HIR::GenericPath make_generic_path(::HIR::SimplePath sp, const ::HIR::Trait& trait) + { + auto trait_path_g = ::HIR::GenericPath( mv$(sp) ); + for(unsigned int i = 0; i < trait.m_params.m_types.size(); i ++ ) { + //trait_path_g.m_params.m_types.push_back( ::HIR::TypeRef(trait.m_params.m_types[i].m_name, i) ); + //trait_path_g.m_params.m_types.push_back( ::HIR::TypeRef() ); + trait_path_g.m_params.m_types.push_back( trait.m_params.m_types[i].m_default.clone() ); + } + return trait_path_g; + } + // Locate the item in `pd` and set `pd` to UfcsResolved if found + // TODO: This code may end up generating paths without the type information they should contain + bool locate_in_trait_and_set(::HIR::Visitor::PathContext pc, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait, ::HIR::Path::Data& pd) { + // TODO: Get the span from caller + static Span _sp; + const auto& sp = _sp; + if( locate_item_in_trait(pc, trait, pd) ) { + pd = get_ufcs_known(mv$(pd.as_UfcsUnknown()), trait_path.clone() /*make_generic_path(trait_path.m_path, trait)*/, trait); + return true; + } + + auto monomorph_cb = [&](const auto& ty)->const ::HIR::TypeRef& { + const auto& ge = ty.m_data.as_Generic(); + if( ge.binding == 0xFFFF ) { + // TODO: This has to be the _exact_ same type, including future ivars. + return *pd.as_UfcsUnknown().type; + } + else if( (ge.binding >> 8) == 0 ) { + auto idx = ge.binding & 0xFF; + ASSERT_BUG(sp, idx < trait.m_params.m_types.size(), ""); + if( idx < trait_path.m_params.m_types.size() ) + return trait_path.m_params.m_types[idx]; + // If the param is omitted, but has a default, use the default. + else if( trait.m_params.m_types[idx].m_default != ::HIR::TypeRef() ) { + const auto& def = trait.m_params.m_types[idx].m_default; + if( ! monomorphise_type_needed(def) ) + return def; + if( def == ::HIR::TypeRef("Self", 0xFFFF) ) + // TODO: This has to be the _exact_ same type, including future ivars. + return *pd.as_UfcsUnknown().type; + TODO(sp, "Monomorphise default arg " << def << " for trait path " << trait_path); + } + else + BUG(sp, "Binding out of range in " << ty << " for trait path " << trait_path); + } + else { + ERROR(sp, E0000, "Unexpected generic binding " << ty); + } + }; + ::HIR::GenericPath par_trait_path_tmp; + auto monomorph_gp_if_needed = [&](const ::HIR::GenericPath& tpl)->const ::HIR::GenericPath& { + // NOTE: This doesn't monomorph if the parameter set is the same + if( monomorphise_genericpath_needed(tpl) && tpl.m_params != trait_path.m_params ) { + DEBUG("- Monomorph " << tpl); + return par_trait_path_tmp = monomorphise_genericpath_with(sp, tpl, monomorph_cb, false /*no infer*/); + } + else { + return tpl; + } + }; + + // Search supertraits (recursively) + for(const auto& pt : trait.m_parent_traits) + { + const auto& par_trait_path = monomorph_gp_if_needed(pt.m_path); + DEBUG("- Check " << par_trait_path); + if( locate_in_trait_and_set(pc, par_trait_path, *pt.m_trait_ptr, pd) ) { + return true; + } + } + for(const auto& pt : trait.m_all_parent_traits) + { + const auto& par_trait_path = monomorph_gp_if_needed(pt.m_path); + DEBUG("- Check (all) " << par_trait_path); + if( locate_item_in_trait(pc, *pt.m_trait_ptr, pd) ) { + // TODO: Don't clone if this is from the temp. + pd = get_ufcs_known(mv$(pd.as_UfcsUnknown()), par_trait_path.clone(), *pt.m_trait_ptr); + return true; + } + } + return false; + } + + bool resolve_UfcsUnknown_inherent(const ::HIR::Path& p, ::HIR::Visitor::PathContext pc, ::HIR::Path::Data& pd) + { + auto& e = pd.as_UfcsUnknown(); + return m_crate.find_type_impls(*e.type, [&](const auto& t)->const auto& { return t; }, [&](const auto& impl) { + DEBUG("- matched inherent impl" << impl.m_params.fmt_args() << " " << impl.m_type); + // Search for item in this block + switch( pc ) + { + case ::HIR::Visitor::PathContext::VALUE: + if( impl.m_methods.find(e.item) != impl.m_methods.end() ) { + } + else if( impl.m_constants.find(e.item) != impl.m_constants.end() ) { + } + else { + return false; + } + // Found it, just keep going (don't care about details here) + break; + case ::HIR::Visitor::PathContext::TRAIT: + case ::HIR::Visitor::PathContext::TYPE: + return false; + } + + auto new_data = ::HIR::Path::Data::make_UfcsInherent({ mv$(e.type), mv$(e.item), mv$(e.params)} ); + pd = mv$(new_data); + DEBUG("- Resolved, replace with " << p); + return true; + }); + } + + void visit_path(::HIR::Path& p, ::HIR::Visitor::PathContext pc) override + { + static Span sp; + + // Explicitly handle UfcsUnknown (doesn't call default) + if(auto* pe = p.m_data.opt_UfcsUnknown()) + { + auto& e = *pe; + TRACE_FUNCTION_FR("UfcsUnknown - p=" << p, p); + + this->visit_type( *e.type ); + this->visit_path_params( e.params ); + + // Search for matching impls in current generic blocks + if( m_params_method != nullptr && locate_trait_item_in_bounds(pc, *e.type, *m_params_method, p.m_data) ) { + DEBUG("Found in item params, p = " << p); + return ; + } + if( m_params_impl != nullptr && locate_trait_item_in_bounds(pc, *e.type, *m_params_impl, p.m_data) ) { + DEBUG("Found in impl params, p = " << p); + return ; + } + + // If processing a trait, and the type is 'Self', search for the type/method on the trait + // - TODO: This could be encoded by a `Self: Trait` bound in the generics, but that may have knock-on issues? + // NOTE: `Self` can already be replaced by the self type (AST resolve does this) + if( *e.type == ::HIR::TypeRef("Self", 0xFFFF) || (m_current_type && *e.type == *m_current_type) ) + { + ::HIR::GenericPath trait_path; + if( m_current_trait_path->trait_path() ) + { + trait_path = ::HIR::GenericPath( *m_current_trait_path->trait_path() ); + trait_path.m_params = m_current_trait_path->trait_args()->clone(); + } + else + { + trait_path = ::HIR::GenericPath( m_current_trait_path->get_simple_path() ); + for(unsigned int i = 0; i < m_current_trait->m_params.m_types.size(); i ++ ) { + trait_path.m_params.m_types.push_back( ::HIR::TypeRef(m_current_trait->m_params.m_types[i].m_name, i) ); + } + } + if( locate_in_trait_and_set(pc, trait_path, *m_current_trait, p.m_data) ) { + DEBUG("Found in Self, p = " << p); + return ; + } + DEBUG("- Item " << e.item << " not found in Self - ty=" << *e.type); + } + + // Cases for the type: + // - Path:UfcsKnown - Search trait impl's ATY bounds (and our own bound set?) + // - Generic - Search local bound set for a suitable implemented trait + // - Anything else - ERROR + if( e.type->m_data.is_Path() && e.type->m_data.as_Path().path.m_data.is_UfcsKnown() ) + { + // TODO: Search bounds on this ATY (in the trait defintiion) + TODO(sp, "Get " << e.item << " for " << *e.type); + } + else if( e.type->m_data.is_Generic()) + { + // Local bounds have already been searched, error now? + TODO(sp, "Get " << e.item << " for " << *e.type); + } + else + { + ERROR(sp, E0000, "Ambigious associated type " << p); // rustc E0223 + } + } + else + { + ::HIR::Visitor::visit_path(p, pc); + } + } + }; + +} + +void ConvertHIR_ResolveUFCS_Outer(::HIR::Crate& crate) +{ + Visitor exp { crate }; + exp.visit_crate( crate ); +} diff --git a/src/hir_typeck/static.cpp b/src/hir_typeck/static.cpp index c9e2bae9..de9b6053 100644 --- a/src/hir_typeck/static.cpp +++ b/src/hir_typeck/static.cpp @@ -434,7 +434,9 @@ bool StaticTraitResolve::find_impl__check_bound( static bool compare_pp(const Span& sp, const ::HIR::PathParams& left, const ::HIR::PathParams& right) { ASSERT_BUG( sp, left.m_types.size() == right.m_types.size(), "Parameter count mismatch" ); for(unsigned int i = 0; i < left.m_types.size(); i ++) { - if( left.m_types[i] != right.m_types[i] ) { + // TODO: Permits fuzzy comparison to handle placeholder params, should instead do a match/test/assign + if( left.m_types[i].compare_with_placeholders(sp, right.m_types[i], [](const auto&t)->const ::HIR::TypeRef&{return t;}) == ::HIR::Compare::Unequal ) { + //if( left.m_types[i] != right.m_types[i] ) { return false; } } @@ -670,7 +672,7 @@ bool StaticTraitResolve::find_impl__check_crate_raw( }); } if( !rv ) { - DEBUG("> Fail (assoc) - " << b_ty_mono << " : " << aty_src_trait); + DEBUG("> Fail (assoc " << aty_name << ") - " << b_ty_mono << " : " << aty_src_trait); return false; } } @@ -1331,10 +1333,17 @@ bool StaticTraitResolve::find_named_trait_in_trait(const Span& sp, auto pt_mono = monomorphise_traitpath_with(sp, pt, monomorph_cb, false); DEBUG(pt << " => " << pt_mono); - if( pt.m_path.m_path == des && pt_mono.m_path.m_params == des_params ) + // TODO: When in pre-typecheck mode, this needs to be a fuzzy match (because there might be a UfcsUnknown in the + // monomorphed version) OR, there may be placeholders + if( pt.m_path.m_path == des ) { - callback( pt_mono.m_path.m_params, mv$(pt_mono.m_type_bounds) ); - return true; + auto cmp = pt_mono.m_path.m_params.compare_with_placeholders(sp, des_params, [](const auto& t)->const ::HIR::TypeRef&{return t;}); + // pt_mono.m_path.m_params == des_params ) + if( cmp != ::HIR::Compare::Unequal ) + { + callback( pt_mono.m_path.m_params, mv$(pt_mono.m_type_bounds) ); + return true; + } } } diff --git a/src/main.cpp b/src/main.cpp index 782e043f..c0f2df9b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -52,6 +52,7 @@ void init_debug_list() g_debug_disable_map.insert( "Resolve Type Aliases" ); g_debug_disable_map.insert( "Resolve Bind" ); + g_debug_disable_map.insert( "Resolve UFCS Outer" ); g_debug_disable_map.insert( "Resolve UFCS paths" ); g_debug_disable_map.insert( "Resolve HIR Markings" ); g_debug_disable_map.insert( "Constant Evaluate" ); @@ -477,6 +478,16 @@ int main(int argc, char *argv[]) CompilePhaseV("Resolve HIR Markings", [&]() { ConvertHIR_Markings(*hir_crate); }); + // Determine what trait to use for ::Foo in outer scope + CompilePhaseV("Resolve UFCS Outer", [&]() { + ConvertHIR_ResolveUFCS_Outer(*hir_crate); + }); + if( params.debug.dump_hir ) { + CompilePhaseV("Dump HIR", [&]() { + ::std::ofstream os (FMT(params.outfile << "_2_hir.rs")); + HIR_Dump( os, *hir_crate ); + }); + } // Determine what trait to use for ::Foo (and does some associated type expansion) CompilePhaseV("Resolve UFCS paths", [&]() { ConvertHIR_ResolveUFCS(*hir_crate); -- cgit v1.2.3 From dc181591986dff3ceff82e865f5b7cc818716d2f Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 19 Jan 2019 09:59:36 +0800 Subject: Typecheck Expressions - Tweak expand_associated_types to get associated type bounds on associated types --- src/hir_conv/resolve_ufcs.cpp | 4 +++- src/hir_typeck/common.hpp | 17 +++++++++++++++++ src/hir_typeck/helpers.cpp | 20 ++++++++++++-------- 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/src/hir_conv/resolve_ufcs.cpp b/src/hir_conv/resolve_ufcs.cpp index 9bdb2feb..19ec84ba 100644 --- a/src/hir_conv/resolve_ufcs.cpp +++ b/src/hir_conv/resolve_ufcs.cpp @@ -6,7 +6,9 @@ * - Resolve unkown UFCS traits into inherent or trait * - HACK: Will likely be replaced with a proper typeck pass (no it won't) * - * - TODO: What are the rules for UFCS lookup? + * TODO: Remove this pass, except maybe for running EAT on outer types + * - Expression code can handle picking UFCS functions better than this code can + * - Outer EAT is nice, but StaticTraitResolve will need to handle non-EAT-ed types when doing lookups */ #include "main_bindings.hpp" #include diff --git a/src/hir_typeck/common.hpp b/src/hir_typeck/common.hpp index c0e495a6..4de874a8 100644 --- a/src/hir_typeck/common.hpp +++ b/src/hir_typeck/common.hpp @@ -29,6 +29,23 @@ extern ::HIR::Path monomorphise_path_with(const Span& sp, const ::HIR::Path& tpl extern ::HIR::TypeRef monomorphise_type_with(const Span& sp, const ::HIR::TypeRef& tpl, t_cb_generic callback, bool allow_infer=true); extern ::HIR::TypeRef monomorphise_type(const Span& sp, const ::HIR::GenericParams& params_def, const ::HIR::PathParams& params, const ::HIR::TypeRef& tpl); +// Wrappers to only monomorphise if required +static inline const ::HIR::TypeRef& monomorphise_type_with_opt(const Span& sp, ::HIR::TypeRef& tmp, const ::HIR::TypeRef& tpl, t_cb_generic callback, bool allow_infer=true) { + return (monomorphise_type_needed(tpl) ? tmp = monomorphise_type_with(sp, tpl, callback, allow_infer) : tpl); +} +static inline const ::HIR::Path& monomorphise_path_with_opt(const Span& sp, ::HIR::Path& tmp, const ::HIR::Path& tpl, t_cb_generic callback, bool allow_infer=true) { + return (monomorphise_path_needed(tpl) ? tmp = monomorphise_path_with(sp, tpl, callback, allow_infer) : tpl); +} +static inline const ::HIR::GenericPath& monomorphise_genericpath_with_opt(const Span& sp, ::HIR::GenericPath& tmp, const ::HIR::GenericPath& tpl, t_cb_generic callback, bool allow_infer=true) { + return (monomorphise_genericpath_needed(tpl) ? tmp = monomorphise_genericpath_with(sp, tpl, callback, allow_infer) : tpl); +} +static inline const ::HIR::TraitPath& monomorphise_traitpath_with_opt(const Span& sp, ::HIR::TraitPath& tmp, const ::HIR::TraitPath& tpl, t_cb_generic callback, bool allow_infer=true) { + return (monomorphise_traitpath_needed(tpl) ? tmp = monomorphise_traitpath_with(sp, tpl, callback, allow_infer) : tpl); +} +static inline const ::HIR::PathParams& monomorphise_pathparams_with_opt(const Span& sp, ::HIR::PathParams& tmp, const ::HIR::PathParams& tpl, t_cb_generic callback, bool allow_infer=true) { + return (monomorphise_pathparams_needed(tpl) ? tmp = monomorphise_path_params_with(sp, tpl, callback, allow_infer) : tpl); +} + typedef ::std::function t_cb_visit_ty; /// Calls the provided callback on every type seen when recursing the type. /// If the callback returns `true`, no further types are visited and the function returns `true`. diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index d4d16aad..0c76b4e5 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -1981,7 +1981,7 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp, ( ), (TraitBound, - DEBUG("Trait bound - " << be.type << " : " << be.trait); + DEBUG("[expand_associated_types_inplace__UfcsKnown] Trait bound - " << be.type << " : " << be.trait); // 1. Check if the type matches // - TODO: This should be a fuzzier match? if( be.type != *pe.type ) @@ -1993,7 +1993,7 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp, if( it == be.trait.m_type_bounds.end() ) { // If not, assume it's opaque and return as such // TODO: What happens if there's two bounds that overlap? 'F: FnMut<()>, F: FnOnce<(), Output=Bar>' - DEBUG("Found impl for " << input << " but no bound on item, assuming opaque"); + DEBUG("[expand_associated_types_inplace__UfcsKnown] Found impl for " << input << " but no bound on item, assuming opaque"); } else { assume_opaque = false; @@ -2066,6 +2066,7 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp, } // If the type of this UfcsKnown is ALSO a UfcsKnown - Check if it's bounded by this trait with equality + // e.g. `<::Baz as Trait2>::Type` may have an ATY bound `trait Bar { type Baz: Trait2 }` // Use bounds on other associated types too (if `pe.type` was resolved to a fixed associated type) TU_IFLET(::HIR::TypeRef::Data, pe.type->m_data, Path, te_inner, TU_IFLET(::HIR::Path::Data, te_inner.path.m_data, UfcsKnown, pe_inner, @@ -2099,7 +2100,10 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp, { // If the bound is for Self and the outer trait // - TODO: Fuzzy check the parameters? - if( bound.m_path == pe.trait ) { + ::HIR::GenericPath tmp_tp; + const auto& bound_tp = monomorphise_genericpath_with_opt(sp, tmp_tp, bound.m_path, cb_placeholders_trait); + DEBUG(bound_tp << " ?= " << pe.trait); + if( bound_tp == pe.trait ) { auto it = bound.m_type_bounds.find( pe.item ); if( it != bound.m_type_bounds.end() ) { if( monomorphise_type_needed(it->second) ) { @@ -2115,10 +2119,10 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp, } // TODO: Find trait in this trait. - const auto& bound_trait = m_crate.get_trait_by_path(sp, bound.m_path.m_path); + const auto& bound_trait = m_crate.get_trait_by_path(sp, bound_tp.m_path); bool replaced = this->find_named_trait_in_trait(sp, pe.trait.m_path,pe.trait.m_params, - bound_trait, bound.m_path.m_path,bound.m_path.m_params, *pe.type, + bound_trait, bound_tp.m_path,bound_tp.m_params, *pe.type, [&](const auto&, const auto& x, const auto& assoc){ auto it = assoc.find(pe.item); if( it != assoc.end() ) { @@ -2292,9 +2296,9 @@ bool TraitResolution::find_trait_impls_bound(const Span& sp, const ::HIR::Simple ) ) - //if(type.m_data.is_Infer()) { - // return false; - //} + if(type.m_data.is_Infer()) { + return false; + } // NOTE: Even if the type is completely unknown (infer or unbound UFCS), search the bound list. -- cgit v1.2.3 From 6d7e663c8fb339e3cea89f32c4767fbd3fccea93 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 19 Jan 2019 18:05:57 +0800 Subject: minicargo - Include a rough progress counter in build reports --- tools/minicargo/build.cpp | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/tools/minicargo/build.cpp b/tools/minicargo/build.cpp index 4c116730..01186b21 100644 --- a/tools/minicargo/build.cpp +++ b/tools/minicargo/build.cpp @@ -62,12 +62,13 @@ class Builder { BuildOptions m_opts; ::helpers::path m_compiler_path; + size_t m_total_targets; public: - Builder(BuildOptions opts); + Builder(BuildOptions opts, size_t total_targets); - bool build_target(const PackageManifest& manifest, const PackageTarget& target, bool is_for_host) const; - bool build_library(const PackageManifest& manifest, bool is_for_host) const; + bool build_target(const PackageManifest& manifest, const PackageTarget& target, bool is_for_host, size_t index) const; + bool build_library(const PackageManifest& manifest, bool is_for_host, size_t index) const; ::helpers::path build_build_script(const PackageManifest& manifest, bool is_for_host, bool* out_is_rebuilt) const; private: @@ -256,7 +257,7 @@ BuildList::BuildList(const PackageManifest& manifest, const BuildOptions& opts): bool BuildList::build(BuildOptions opts, unsigned num_jobs) { bool include_build = !opts.build_script_overrides.is_valid(); - Builder builder { ::std::move(opts) }; + Builder builder { ::std::move(opts), m_list.size() }; // Pre-count how many dependencies are remaining for each package struct BuildState @@ -409,7 +410,7 @@ bool BuildList::build(BuildOptions opts, unsigned num_jobs) } DEBUG("Thread " << my_idx << ": Starting " << cur << " - " << list[cur].package->name()); - if( ! builder->build_library(*list[cur].package, list[cur].is_host) ) + if( ! builder->build_library(*list[cur].package, list[cur].is_host, cur) ) { queue.failure = true; queue.signal_all(); @@ -470,7 +471,7 @@ bool BuildList::build(BuildOptions opts, unsigned num_jobs) { auto cur = state.get_next(); - if( ! builder.build_library(*m_list[cur].package, m_list[cur].is_host) ) + if( ! builder.build_library(*m_list[cur].package, m_list[cur].is_host, cur) ) { return false; } @@ -484,7 +485,7 @@ bool BuildList::build(BuildOptions opts, unsigned num_jobs) { auto cur = state.get_next(); - if( ! builder.build_library(*m_list[cur].package, m_list[cur].is_host) ) + if( ! builder.build_library(*m_list[cur].package, m_list[cur].is_host, cur) ) { return false; } @@ -529,13 +530,14 @@ bool BuildList::build(BuildOptions opts, unsigned num_jobs) // Now that all libraries are done, build the binaries (if present) return this->m_root_manifest.foreach_binaries([&](const auto& bin_target) { - return builder.build_target(this->m_root_manifest, bin_target, /*is_for_host=*/false); + return builder.build_target(this->m_root_manifest, bin_target, /*is_for_host=*/false, ~0u); }); } -Builder::Builder(BuildOptions opts): - m_opts(::std::move(opts)) +Builder::Builder(BuildOptions opts, size_t total_targets): + m_opts(::std::move(opts)), + m_total_targets(total_targets) { #ifdef _WIN32 char buf[1024]; @@ -623,7 +625,7 @@ Builder::Builder(BuildOptions opts): return outfile; } -bool Builder::build_target(const PackageManifest& manifest, const PackageTarget& target, bool is_for_host) const +bool Builder::build_target(const PackageManifest& manifest, const PackageTarget& target, bool is_for_host, size_t index) const { const char* crate_type; ::std::string crate_suffix; @@ -660,7 +662,18 @@ bool Builder::build_target(const PackageManifest& manifest, const PackageTarget& // TODO: Run commands specified by build script (override) } - ::std::cout << "BUILDING " << target.m_name << " from " << manifest.name() << " v" << manifest.version() << " with features [" << manifest.active_features() << "]" << ::std::endl; + { + // TODO: Determine what number and total targets there are + if( index != ~0u ) + ::std::cout << "(" << index << "/" << m_total_targets << ") "; + ::std::cout << "BUILDING "; + if(target.m_name != manifest.name()) + ::std::cout << target.m_name << " from "; + ::std::cout << manifest.name() << " v" << manifest.version(); + if( !manifest.active_features().empty() ) + ::std::cout << " with features [" << manifest.active_features() << "]"; + ::std::cout << ::std::endl; + } StringList args; args.push_back(::helpers::path(manifest.manifest_path()).parent() / ::helpers::path(target.m_path)); args.push_back("--crate-name"); args.push_back(target.m_name.c_str()); @@ -903,7 +916,7 @@ bool Builder::build_target(const PackageManifest& manifest, const PackageTarget& return out_file; } -bool Builder::build_library(const PackageManifest& manifest, bool is_for_host) const +bool Builder::build_library(const PackageManifest& manifest, bool is_for_host, size_t index) const { if( manifest.build_script() != "" ) { @@ -929,7 +942,7 @@ bool Builder::build_library(const PackageManifest& manifest, bool is_for_host) c } } - return this->build_target(manifest, manifest.get_library(), is_for_host); + return this->build_target(manifest, manifest.get_library(), is_for_host, index); } bool Builder::spawn_process_mrustc(const StringList& args, StringListKV env, const ::helpers::path& logfile) const { -- cgit v1.2.3 From 0af7f41208356599ad367a55e089112ebe46929b Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 19 Jan 2019 18:06:27 +0800 Subject: Typecheck Expressions - Handle generics in auto trait magic --- src/hir_typeck/helpers.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index 0c76b4e5..1af269ad 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -2733,7 +2733,9 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, return res; ) else TU_IFLET( ::HIR::TypeRef::Data, type.m_data, Generic, e, - TODO(sp, "Check trait bounds on " << type); + auto l_res = ::HIR::Compare::Unequal; + this->find_trait_impls(sp, trait, *params_ptr, type, [&](auto, auto cmp){ l_res = cmp; return (cmp == ::HIR::Compare::Equal); }); + return l_res; ) else TU_IFLET( ::HIR::TypeRef::Data, type.m_data, Tuple, e, ::HIR::Compare res = ::HIR::Compare::Equal; -- cgit v1.2.3 From af1776f7056c967a0f106e7519afd9b2bd2158d9 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 20 Jan 2019 12:43:01 +0800 Subject: Typecheck Static - Handle resolution with pre-existing placeholders --- src/hir_typeck/static.cpp | 52 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/src/hir_typeck/static.cpp b/src/hir_typeck/static.cpp index de9b6053..457bd44e 100644 --- a/src/hir_typeck/static.cpp +++ b/src/hir_typeck/static.cpp @@ -541,6 +541,8 @@ bool StaticTraitResolve::find_impl__check_crate_raw( auto cb_ident = [](const auto&ty)->const ::HIR::TypeRef&{return ty;}; TRACE_FUNCTION_F("impl" << impl_params_def.fmt_args() << " " << des_trait_path << impl_trait_params << " for " << impl_type << impl_params_def.fmt_bounds()); + // TODO: What if `des_trait_params` already has impl placeholders? + ::std::vector< const ::HIR::TypeRef*> impl_params; impl_params.resize( impl_params_def.m_types.size() ); @@ -548,6 +550,7 @@ bool StaticTraitResolve::find_impl__check_crate_raw( assert( idx < impl_params.size() ); if( ! impl_params[idx] ) { impl_params[idx] = &ty; + DEBUG("[find_impl__check_crate_raw:cb] Set placeholder " << idx << " to " << ty); return ::HIR::Compare::Equal; } else { @@ -555,15 +558,34 @@ bool StaticTraitResolve::find_impl__check_crate_raw( } }; auto match = impl_type.match_test_generics_fuzz(sp, des_type, cb_ident, cb); + unsigned base_impl_placeholder_idx = 0; if( des_trait_params ) { assert( des_trait_params->m_types.size() == impl_trait_params.m_types.size() ); + unsigned max_impl_idx = 0; for( unsigned int i = 0; i < impl_trait_params.m_types.size(); i ++ ) { const auto& l = impl_trait_params.m_types[i]; const auto& r = des_trait_params->m_types[i]; match &= l.match_test_generics_fuzz(sp, r, cb_ident, cb); + + visit_ty_with(r, [&](const ::HIR::TypeRef& t)->bool { + if( t.m_data.is_Generic() && (t.m_data.as_Generic().binding >> 8) == 2 ) { + unsigned impl_idx = t.m_data.as_Generic().binding & 0xFF; + max_impl_idx = ::std::max(max_impl_idx, impl_idx+1); + } + return false; + }); } + base_impl_placeholder_idx = max_impl_idx; + + size_t n_placeholders_needed = 0; + for(unsigned int i = 0; i < impl_params.size(); i ++ ) { + if( !impl_params[i] ) { + n_placeholders_needed ++; + } + } + ASSERT_BUG(sp, base_impl_placeholder_idx + n_placeholders_needed <= 256, "Out of impl placeholders"); } if( match == ::HIR::Compare::Unequal ) { DEBUG(" > Type mismatch"); @@ -575,7 +597,7 @@ bool StaticTraitResolve::find_impl__check_crate_raw( if( !impl_params[i] ) { if( placeholders.size() == 0 ) placeholders.resize(impl_params.size()); - placeholders[i] = ::HIR::TypeRef("impl_?", 2*256 + i); + placeholders[i] = ::HIR::TypeRef("impl_?", 2*256 + i + base_impl_placeholder_idx); DEBUG("Placeholder " << placeholders[i] << " for " << impl_params_def.m_types[i].m_name); } } @@ -584,19 +606,24 @@ bool StaticTraitResolve::find_impl__check_crate_raw( if( ty.m_data.is_Generic() && ty.m_data.as_Generic().binding == idx ) return ::HIR::Compare::Equal; if( idx >> 8 == 2 ) { - auto i = idx % 256; - ASSERT_BUG(sp, !impl_params[i], "Placeholder to populated type returned"); - auto& ph = placeholders[i]; - if( ph.m_data.is_Generic() && ph.m_data.as_Generic().binding == idx ) { - DEBUG("[find_impl__check_crate_raw:cb_match] Bind placeholder " << i << " to " << ty); - ph = ty.clone(); - return ::HIR::Compare::Equal; - } - else if( ph == ty ) { - return ::HIR::Compare::Equal; + if( (idx % 256) >= base_impl_placeholder_idx ) { + auto i = idx % 256 - base_impl_placeholder_idx; + ASSERT_BUG(sp, !impl_params[i], "Placeholder to populated type returned. new " << ty << ", existing " << *impl_params[i]); + auto& ph = placeholders[i]; + if( ph.m_data.is_Generic() && ph.m_data.as_Generic().binding == idx ) { + DEBUG("[find_impl__check_crate_raw:cb_match] Bind placeholder " << i << " to " << ty); + ph = ty.clone(); + return ::HIR::Compare::Equal; + } + else if( ph == ty ) { + return ::HIR::Compare::Equal; + } + else { + TODO(sp, "[find_impl__check_crate_raw:cb_match] Compare placeholder " << i << " " << ph << " == " << ty); + } } else { - TODO(sp, "[find_impl__check_crate_raw:cb_match] Compare placeholder " << i << " " << ph << " == " << ty); + return ::HIR::Compare::Fuzzy; } } else { @@ -664,6 +691,7 @@ bool StaticTraitResolve::find_impl__check_crate_raw( ::HIR::TypeRef have = impl.get_type(aty_name.c_str()); this->expand_associated_types(sp, have); + DEBUG("::" << aty_name << " - " << have << " ?= " << exp); //auto cmp = have .match_test_generics_fuzz(sp, exp, cb_ident, cb_match); auto cmp = exp .match_test_generics_fuzz(sp, have, cb_ident, cb_match); if( cmp == ::HIR::Compare::Unequal ) -- cgit v1.2.3 From 3c710f6320a5a124a8924f9d714bab8a94f7b051 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 20 Jan 2019 13:17:33 +0800 Subject: macro_rules - Handle `[auto] trait` in :item --- src/macro_rules/eval.cpp | 62 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 46 insertions(+), 16 deletions(-) diff --git a/src/macro_rules/eval.cpp b/src/macro_rules/eval.cpp index e7b9a203..3315b24c 100644 --- a/src/macro_rules/eval.cpp +++ b/src/macro_rules/eval.cpp @@ -1712,29 +1712,46 @@ namespace return false; return consume_tt(lex); case TOK_IDENT: - if( lex.next_tok().str() != "union" ) - return false; - lex.consume(); - if( lex.next() == TOK_EXCLAM ) + if( lex.next_tok().str() == "union" ) { - bool need_semicolon = (lex.next() != TOK_BRACE_OPEN); - consume_tt(lex); - if( need_semicolon ) + lex.consume(); + if( lex.next() == TOK_EXCLAM ) + { + bool need_semicolon = (lex.next() != TOK_BRACE_OPEN); + consume_tt(lex); + if( need_semicolon ) + { + if( !lex.consume_if(TOK_SEMICOLON) ) + return false; + } + return true; + } + else { - if( !lex.consume_if(TOK_SEMICOLON) ) + if( !H::maybe_generics(lex) ) return false; + if( !H::maybe_where(lex) ) + return false; + if( lex.next() != TOK_BRACE_OPEN ) + return false; + return consume_tt(lex); } - return true; } - else + else if( lex.next_tok().str() == "auto" ) { - if( !H::maybe_generics(lex) ) - return false; - if( !H::maybe_where(lex) ) - return false; - if( lex.next() != TOK_BRACE_OPEN ) + lex.consume(); + if( lex.consume_if(TOK_RWORD_TRAIT) ) + { + goto trait; + } + else + { return false; - return consume_tt(lex); + } + } + else + { + return false; } break; // const fn @@ -1761,6 +1778,19 @@ namespace return false; } break; + case TOK_RWORD_TRAIT: + lex.consume(); + trait: + if( !lex.consume_if(TOK_IDENT) ) + return false; + + if( !H::maybe_generics(lex) ) + return false; + if(lex.next() != TOK_BRACE_OPEN) + return false; + if( !consume_tt(lex) ) + return false; + break; case TOK_RWORD_EXTERN: lex.consume(); if( lex.consume_if(TOK_RWORD_CRATE) ) -- cgit v1.2.3 From 4c9e71afa9fe11ddf7dc6e660ce8cf38da93b781 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 20 Jan 2019 15:29:26 +0800 Subject: Type resolve static - Cleanups --- src/hir_typeck/static.hpp | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/hir_typeck/static.hpp b/src/hir_typeck/static.hpp index f764f8f7..564d2110 100644 --- a/src/hir_typeck/static.hpp +++ b/src/hir_typeck/static.hpp @@ -16,8 +16,8 @@ class StaticTraitResolve public: const ::HIR::Crate& m_crate; - ::HIR::GenericParams* m_impl_generics; - ::HIR::GenericParams* m_item_generics; + const ::HIR::GenericParams* m_impl_generics; + const ::HIR::GenericParams* m_item_generics; ::std::map< ::HIR::TypeRef, ::HIR::TypeRef> m_type_equalities; @@ -86,19 +86,35 @@ public: ptr = nullptr; } }; - NullOnDrop< ::HIR::GenericParams> set_impl_generics(::HIR::GenericParams& gps) { + NullOnDrop set_impl_generics(const ::HIR::GenericParams& gps) { + set_impl_generics_raw(gps); + return NullOnDrop(m_impl_generics); + } + NullOnDrop set_item_generics(const ::HIR::GenericParams& gps) { + set_item_generics_raw(gps); + return NullOnDrop(m_item_generics); + } + void set_impl_generics_raw(const ::HIR::GenericParams& gps) { assert( !m_impl_generics ); m_impl_generics = &gps; m_type_equalities.clear(); prep_indexes(); - return NullOnDrop< ::HIR::GenericParams>(m_impl_generics); } - NullOnDrop< ::HIR::GenericParams> set_item_generics(::HIR::GenericParams& gps) { + void clear_impl_generics() { + m_impl_generics = nullptr; + m_type_equalities.clear(); + prep_indexes(); + } + void set_item_generics_raw(const ::HIR::GenericParams& gps) { assert( !m_item_generics ); m_item_generics = &gps; m_type_equalities.clear(); prep_indexes(); - return NullOnDrop< ::HIR::GenericParams>(m_item_generics); + } + void clear_item_generics() { + m_item_generics = nullptr; + m_type_equalities.clear(); + prep_indexes(); } /// \} -- cgit v1.2.3 From 793ac4209456b058ee39474b617c89372d0417d0 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 20 Jan 2019 15:29:47 +0800 Subject: HIR Serialise - Tweaks for easier debugging --- src/hir/deserialise.cpp | 5 +++-- src/hir/serialise_lowlevel.cpp | 6 +++++- src/hir/serialise_lowlevel.hpp | 2 ++ 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/hir/deserialise.cpp b/src/hir/deserialise.cpp index 70ff1a34..c6655a80 100644 --- a/src/hir/deserialise.cpp +++ b/src/hir/deserialise.cpp @@ -81,7 +81,7 @@ template ::std::vector deserialise_vec() { - TRACE_FUNCTION_F("<" << typeid(T).name() << ">"); + TRACE_FUNCTION_FR("<" << typeid(T).name() << ">", m_in.get_pos()); size_t n = m_in.read_count(); DEBUG("n = " << n); ::std::vector rv; @@ -971,7 +971,7 @@ } ::HIR::Struct HirDeserialiser::deserialise_struct() { - TRACE_FUNCTION; + TRACE_FUNCTION_FR("", m_in.get_pos()); auto params = deserialise_genericparams(); auto repr = static_cast< ::HIR::Struct::Repr>( m_in.read_tag() ); DEBUG("params = " << params.fmt_args() << params.fmt_bounds()); @@ -995,6 +995,7 @@ BUG(Span(), "Bad tag for HIR::Struct::Data - " << tag); } auto align = static_cast(m_in.read_u64c()); + DEBUG("align = " << align); auto markings = deserialise_markings(); auto str_markings = deserialise_str_markings(); diff --git a/src/hir/serialise_lowlevel.cpp b/src/hir/serialise_lowlevel.cpp index cf8f5506..e69ff848 100644 --- a/src/hir/serialise_lowlevel.cpp +++ b/src/hir/serialise_lowlevel.cpp @@ -186,7 +186,8 @@ void ReadBuffer::populate(ReaderInner& is) Reader::Reader(const ::std::string& filename): m_inner( new ReaderInner(filename) ), - m_buffer(1024) + m_buffer(1024), + m_pos(0) { } Reader::~Reader() @@ -198,6 +199,7 @@ void Reader::read(void* buf, size_t len) { auto used = m_buffer.read(buf, len); if( used == len ) { + m_pos += len; return ; } buf = reinterpret_cast(buf) + used; @@ -214,6 +216,8 @@ void Reader::read(void* buf, size_t len) if( used != len ) throw ::std::runtime_error( FMT("Reader::read - Requested " << len << " bytes from buffer, got " << used) ); } + + m_pos += len; } diff --git a/src/hir/serialise_lowlevel.hpp b/src/hir/serialise_lowlevel.hpp index 6be8ff8c..a35b8e98 100644 --- a/src/hir/serialise_lowlevel.hpp +++ b/src/hir/serialise_lowlevel.hpp @@ -147,12 +147,14 @@ class Reader { ReaderInner* m_inner; ReadBuffer m_buffer; + size_t m_pos; public: Reader(const ::std::string& path); Reader(const Writer&) = delete; Reader(Writer&&) = delete; ~Reader(); + size_t get_pos() const { return m_pos; } void read(void* dst, size_t count); uint8_t read_u8() { -- cgit v1.2.3 From d3bf8767f9db3ec9753b2748508561a94fb4cf52 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 20 Jan 2019 15:30:12 +0800 Subject: HIR Expand Closures - Ensure opaque tagging of UfcsKnown --- src/hir_expand/closures.cpp | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/src/hir_expand/closures.cpp b/src/hir_expand/closures.cpp index 7cc3cee5..e4380f40 100644 --- a/src/hir_expand/closures.cpp +++ b/src/hir_expand/closures.cpp @@ -194,12 +194,20 @@ namespace { public ::HIR::ExprVisitorDef { const ::HIR::Crate& m_crate; + StaticTraitResolve m_resolve; t_cb_generic m_monomorph_cb; + bool m_run_eat; public: - ExprVisitor_Fixup(const ::HIR::Crate& crate, t_cb_generic monomorph_cb): + ExprVisitor_Fixup(const ::HIR::Crate& crate, const ::HIR::GenericParams* params, t_cb_generic monomorph_cb): m_crate(crate), - m_monomorph_cb( mv$(monomorph_cb) ) + m_resolve(crate), + m_monomorph_cb( mv$(monomorph_cb) ), + m_run_eat(false) { + if( params ) { + m_resolve.set_impl_generics_raw(*params); + m_run_eat = true; + } } static void fix_type(const ::HIR::Crate& crate, t_cb_generic monomorph_cb, ::HIR::TypeRef& ty) { @@ -210,6 +218,14 @@ namespace { DEBUG(ty << " -> " << path); ty = ::HIR::TypeRef::new_path( mv$(path), ::HIR::TypeRef::TypePathBinding::make_Struct(&str) ); ) + + if( auto* e = ty.m_data.opt_Path() ) + { + if( e->binding.is_Unbound() && e->path.m_data.is_UfcsKnown() ) + { + e->binding = ::HIR::TypeRef::TypePathBinding::make_Opaque({}); + } + } } void visit_root(::HIR::ExprPtr& root) @@ -258,8 +274,15 @@ namespace { void visit_type(::HIR::TypeRef& ty) override { + bool run_eat = m_run_eat; + m_run_eat = false; fix_type(m_crate, m_monomorph_cb, ty); ::HIR::ExprVisitorDef::visit_type(ty); + if( run_eat ) { + // TODO: Instead of running EAT, just mark any Unbound UfcsKnown types as Opaque + //m_resolve.expand_associated_types(Span(), ty); + m_run_eat = true; + } } }; @@ -628,7 +651,7 @@ namespace { } // - Fix type to replace closure types with known paths - ExprVisitor_Fixup fixup { m_resolve.m_crate, monomorph_cb }; + ExprVisitor_Fixup fixup { m_resolve.m_crate, ¶ms, monomorph_cb }; fixup.visit_type(ty_mono); capture_types.push_back( ::HIR::VisEnt< ::HIR::TypeRef> { false, mv$(ty_mono) } ); } @@ -670,7 +693,7 @@ namespace { { DEBUG("-- Fixing types in body code"); - ExprVisitor_Fixup fixup { m_resolve.m_crate, monomorph_cb }; + ExprVisitor_Fixup fixup { m_resolve.m_crate, ¶ms, monomorph_cb }; fixup.visit_root( body_code ); DEBUG("-- Fixing types in signature"); @@ -1094,7 +1117,7 @@ namespace { } { - ExprVisitor_Fixup fixup(m_resolve.m_crate, [](const auto& x)->const auto&{ return x; }); + ExprVisitor_Fixup fixup(m_resolve.m_crate, nullptr, [](const auto& x)->const auto&{ return x; }); fixup.visit_root( item.m_code ); } } -- cgit v1.2.3 From 4eb0a6d7e4a600aeca52119fdf3a3bcf90cd6cbb Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 20 Jan 2019 15:40:59 +0800 Subject: Trans - Packed types force outer alignment to 1 --- src/trans/target.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/trans/target.cpp b/src/trans/target.cpp index 9a855036..6a65be15 100644 --- a/src/trans/target.cpp +++ b/src/trans/target.cpp @@ -848,7 +848,7 @@ namespace { cur_ofs ++; } } - rv.align = max_align; + rv.align = packed ? 1 : max_align; rv.size = cur_ofs; rv.fields = ::std::move(fields); DEBUG("size = " << rv.size << ", align = " << rv.align); -- cgit v1.2.3 From 878c7bc03640ded25dd6e704aa443845cfd6d144 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 20 Jan 2019 15:45:59 +0800 Subject: macro_rules - Handle `dyn Trait` in :ty --- src/macro_rules/eval.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/macro_rules/eval.cpp b/src/macro_rules/eval.cpp index 3315b24c..e864537c 100644 --- a/src/macro_rules/eval.cpp +++ b/src/macro_rules/eval.cpp @@ -1073,9 +1073,11 @@ namespace case TOK_PAREN_OPEN: case TOK_SQUARE_OPEN: return consume_tt(lex); + case TOK_IDENT: + if( TARGETVER_1_29 && lex.next_tok().str() == "dyn" ) + lex.consume(); case TOK_RWORD_SUPER: case TOK_RWORD_SELF: - case TOK_IDENT: case TOK_DOUBLE_COLON: case TOK_INTERPOLATED_IDENT: case TOK_INTERPOLATED_PATH: -- cgit v1.2.3 From e329b15c2ef08d40535860b5b5779d2ce9b7e881 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 20 Jan 2019 16:20:09 +0800 Subject: Trans Enumerate - Ensure that clone impls called by auto clone impl are enumerated --- src/trans/enumerate.cpp | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/trans/enumerate.cpp b/src/trans/enumerate.cpp index bb6d6e6f..6aeb3485 100644 --- a/src/trans/enumerate.cpp +++ b/src/trans/enumerate.cpp @@ -1393,9 +1393,30 @@ void Trans_Enumerate_FillFrom_Path(EnumState& state, const ::HIR::Path& path, co { const auto& pe = path_mono.m_data.as_UfcsKnown(); ASSERT_BUG(sp, pe.item == "clone", ""); - // TODO: If this is !Copy, then we need to ensure that the inner type's clone impls are also available + const auto& inner_ty = *pe.type; + // If this is !Copy, then we need to ensure that the inner type's clone impls are also available + ::StaticTraitResolve resolve { state.crate }; + if( !resolve.type_is_copy(sp, inner_ty) ) + { + auto enum_impl = [&](const ::HIR::TypeRef& ity) { + if( !resolve.type_is_copy(sp, ity) ) + { + auto p = ::HIR::Path(ity.clone(), pe.trait.clone(), "clone"); + Trans_Enumerate_FillFrom_Path(state, p, {}); + } + }; + if( const auto* te = inner_ty.m_data.opt_Tuple() ) { + for(const auto& ity : *te) + { + enum_impl(ity); + } + } + else { + BUG(sp, "Unhandled magic clone in enumerate - " << inner_ty); + } + } // Add this type to a list of types that will have the impl auto-generated - state.rv.auto_clone_impls.insert( pe.type->clone() ); + state.rv.auto_clone_impls.insert( inner_ty.clone() ); } else { -- cgit v1.2.3 From d599ec44efcb26bb15ea2010086a738394bf184b Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 20 Jan 2019 16:22:06 +0800 Subject: minicargo - Rough build progress counter --- tools/minicargo/build.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/tools/minicargo/build.cpp b/tools/minicargo/build.cpp index 01186b21..7b2027d4 100644 --- a/tools/minicargo/build.cpp +++ b/tools/minicargo/build.cpp @@ -63,6 +63,7 @@ class Builder BuildOptions m_opts; ::helpers::path m_compiler_path; size_t m_total_targets; + mutable size_t m_targets_built; public: Builder(BuildOptions opts, size_t total_targets); @@ -537,7 +538,8 @@ bool BuildList::build(BuildOptions opts, unsigned num_jobs) Builder::Builder(BuildOptions opts, size_t total_targets): m_opts(::std::move(opts)), - m_total_targets(total_targets) + m_total_targets(total_targets), + m_targets_built(0) { #ifdef _WIN32 char buf[1024]; @@ -631,6 +633,8 @@ bool Builder::build_target(const PackageManifest& manifest, const PackageTarget& ::std::string crate_suffix; auto outfile = this->get_crate_path(manifest, target, is_for_host, &crate_type, &crate_suffix); + size_t this_target_idx = (index != ~0u ? m_targets_built++ : ~0u); + // TODO: Determine if it needs re-running // Rerun if: // > `outfile` is missing @@ -664,8 +668,10 @@ bool Builder::build_target(const PackageManifest& manifest, const PackageTarget& { // TODO: Determine what number and total targets there are - if( index != ~0u ) - ::std::cout << "(" << index << "/" << m_total_targets << ") "; + if( index != ~0u ) { + //::std::cout << "(" << index << "/" << m_total_targets << ") "; + ::std::cout << "(" << this_target_idx << "/" << m_total_targets << ") "; + } ::std::cout << "BUILDING "; if(target.m_name != manifest.name()) ::std::cout << target.m_name << " from "; -- cgit v1.2.3 From d750b39f37cc664ecfae0a4e823271b6cec7183b Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 20 Jan 2019 16:22:29 +0800 Subject: MIR Gen - (minor) Commented-out post-gen dump --- src/mir/from_hir.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index 17de43c2..e13b9db1 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -2533,6 +2533,7 @@ namespace { // NOTE: Can't clean up yet, as consteval isn't done //MIR_Cleanup(resolve, path, fcn, args, ptr->m_res_type); + //DEBUG("MIR Dump:" << ::std::endl << FMT_CB(ss, MIR_Dump_Fcn(ss, fcn, 1);)); MIR_Validate(resolve, path, fcn, args, ptr->m_res_type); if( getenv("MRUSTC_VALIDATE_FULL_EARLY") ) { -- cgit v1.2.3 From bbeaa7a86d532e82c3218127e2833933361e3c5f Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 20 Jan 2019 16:47:28 +0800 Subject: Resolve Use - Finer-grained recursion control --- src/resolve/use.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/resolve/use.cpp b/src/resolve/use.cpp index 52a4ebb6..450af742 100644 --- a/src/resolve/use.cpp +++ b/src/resolve/use.cpp @@ -351,13 +351,17 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path DEBUG("- Named import " << imp_e.name << " = " << imp_e.path); if( !imp_e.path.m_bindings.has_binding() ) { DEBUG(" > Needs resolve"); - static ::std::vector s_mods; - if( ::std::find(s_mods.begin(), s_mods.end(), &mod) == s_mods.end() ) + static ::std::vector s_mods; + if( ::std::find(s_mods.begin(), s_mods.end(), &imp_e.path) == s_mods.end() ) { - s_mods.push_back(&mod); + s_mods.push_back(&imp_e.path); rv.merge_from( Resolve_Use_GetBinding(sp2, crate, Resolve_Use_AbsolutisePath(sp2, mod.path(), imp_e.path), parent_modules) ); s_mods.pop_back(); } + else + { + DEBUG("Recursion!"); + } } else { //out_path = imp_e.path; @@ -799,6 +803,7 @@ namespace { else { const auto& enum_ = *e.enum_; + is_value = false; for( const auto& var : enum_.variants() ) { if( var.m_name == node2.name() ) { -- cgit v1.2.3 From 0eaa3d70595bfcb0492528832b08fc1dd85e3f46 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 20 Jan 2019 17:57:36 +0800 Subject: Typecheck Expressions - More work on match ergonomics --- src/hir_typeck/expr_cs.cpp | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 4a5171f5..a9e6e9ad 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -3690,9 +3690,10 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T struct H2 { static bool has_ref_or_borrow(const Span& sp, const ::HIR::Pattern& pat) { - if( pat.m_binding.is_valid() && pat.m_binding.m_type != ::HIR::PatternBinding::Type::Move ) { - return true; - } + // TODO: Turns out that this isn't valid. See libsyntax 1.29 + //if( pat.m_binding.is_valid() && pat.m_binding.m_type != ::HIR::PatternBinding::Type::Move ) { + // return true; + //} if( pat.m_data.is_Ref() ) { return true; } @@ -3821,8 +3822,11 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T if( pattern.m_binding.is_valid() ) { // - Binding present, use the current binding mode - pattern.m_binding.m_type = binding_mode; - switch(binding_mode) + if( pattern.m_binding.m_type == ::HIR::PatternBinding::Type::Move ) + { + pattern.m_binding.m_type = binding_mode; + } + switch(pattern.m_binding.m_type) { case ::HIR::PatternBinding::Type::Move: context.equate_types(sp, context.get_var(sp, pattern.m_binding.m_slot), type); @@ -4006,7 +4010,18 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T rv &= this->revisit_inner(context, e.sub_patterns[i], te[i], binding_mode); } TU_ARM(pattern.m_data, SplitTuple, pe) { - TODO(sp, "Match ergonomics - split-tuple pattern"); + if( !ty.m_data.is_Tuple() ) { + ERROR(sp, E0000, "Matching a non-tuple with a tuple pattern - " << ty); + } + const auto& te = ty.m_data.as_Tuple(); + if( pe.leading.size() + pe.trailing.size() > te.size() ) { + ERROR(sp, E0000, "Split-tuple pattern with an incorrect number of fields, expected at most " << (pe.leading.size() + pe.trailing.size()) << "-tuple, got " << ty); + } + rv = true; + for(size_t i = 0; i < pe.leading.size(); i++) + rv &= this->revisit_inner(context, pe.leading[i], te[i], binding_mode); + for(size_t i = 0; i < pe.trailing.size(); i++) + rv &= this->revisit_inner(context, pe.trailing[i], te[te.size() - pe.trailing.size() + i], binding_mode); } TU_ARM(pattern.m_data, Slice, e) { const ::HIR::TypeRef* slice_inner; -- cgit v1.2.3 From 0293a98f61b2d82a473c5109ce33dc7bb2cb606e Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 20 Jan 2019 19:27:57 +0800 Subject: Typecheck Expressions - Correct SplitTuple logic in Match ergonomics --- src/hir_typeck/expr_cs.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index a9e6e9ad..8b0eedb3 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -4015,8 +4015,9 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T } const auto& te = ty.m_data.as_Tuple(); if( pe.leading.size() + pe.trailing.size() > te.size() ) { - ERROR(sp, E0000, "Split-tuple pattern with an incorrect number of fields, expected at most " << (pe.leading.size() + pe.trailing.size()) << "-tuple, got " << ty); + ERROR(sp, E0000, "Split-tuple pattern with an incorrect number of fields, expected at most " << (pe.leading.size() + pe.trailing.size()) << "-tuple, got " << te.size()); } + pe.total_size = te.size(); rv = true; for(size_t i = 0; i < pe.leading.size(); i++) rv &= this->revisit_inner(context, pe.leading[i], te[i], binding_mode); -- cgit v1.2.3 From e0181acd038e516f4dc61be4afb7906366c1fa80 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 20 Jan 2019 19:28:25 +0800 Subject: HIR Bind - Handle `Enum::Foo { .. }` patterns for everything --- src/hir_conv/bind.cpp | 73 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 68 insertions(+), 5 deletions(-) diff --git a/src/hir_conv/bind.cpp b/src/hir_conv/bind.cpp index 9d15da18..c979b2e6 100644 --- a/src/hir_conv/bind.cpp +++ b/src/hir_conv/bind.cpp @@ -266,6 +266,15 @@ namespace { this->visit_pattern_Value(sp, pat, e.start); this->visit_pattern_Value(sp, pat, e.end); ), + (StructValue, + const auto& str = get_struct_ptr(sp, m_crate, e.path); + TU_IFLET(::HIR::Struct::Data, str.m_data, Unit, _, + e.binding = &str; + ) + else { + ERROR(sp, E0000, "Struct value pattern on non-unit struct " << e.path); + } + ), (StructTuple, const auto& str = get_struct_ptr(sp, m_crate, e.path); TU_IFLET(::HIR::Struct::Data, str.m_data, Tuple, _, @@ -288,6 +297,17 @@ namespace { } e.binding = &str; ), + (EnumValue, + auto p = get_enum_ptr(sp, m_crate, e.path); + if( p.first->m_data.is_Data() ) + { + const auto& var = p.first->m_data.as_Data()[p.second]; + if( var.is_struct || var.type != ::HIR::TypeRef::new_unit() ) + ERROR(sp, E0000, "Enum value pattern on non-unit variant " << e.path); + } + e.binding_ptr = p.first; + e.binding_idx = p.second; + ), (EnumTuple, auto p = get_enum_ptr(sp, m_crate, e.path); if( !p.first->m_data.is_Data() ) @@ -300,11 +320,54 @@ namespace { ), (EnumStruct, auto p = get_enum_ptr(sp, m_crate, e.path); - if( !p.first->m_data.is_Data() ) - ERROR(sp, E0000, "Enum struct pattern `" << pat << "` on non-struct variant " << e.path); - const auto& var = p.first->m_data.as_Data()[p.second]; - if( !var.is_struct ) - ERROR(sp, E0000, "Enum struct pattern `" << pat << "` on non-struct variant " << e.path); + if( !e.is_exhaustive && e.sub_patterns.empty() ) + { + if( !p.first->m_data.is_Data() ) { + pat.m_data = ::HIR::Pattern::Data::make_EnumValue({ + ::std::move(e.path), p.first, p.second + }); + } + else { + const auto& var = p.first->m_data.as_Data()[p.second]; + if( var.type == ::HIR::TypeRef::new_unit() ) + { + pat.m_data = ::HIR::Pattern::Data::make_EnumValue({ + ::std::move(e.path), p.first, p.second + }); + } + else if( !var.is_struct ) + { + ASSERT_BUG(sp, var.type.m_data.is_Path(), ""); + ASSERT_BUG(sp, var.type.m_data.as_Path().binding.is_Struct(), ""); + const auto& str = *var.type.m_data.as_Path().binding.as_Struct(); + ASSERT_BUG(sp, str.m_data.is_Tuple(), ""); + const auto& flds = str.m_data.as_Tuple(); + ::std::vector subpats; + for(size_t i = 0; i < flds.size(); i ++) + subpats.push_back(::HIR::Pattern { }); + pat.m_data = ::HIR::Pattern::Data::make_EnumTuple({ + ::std::move(e.path), p.first, p.second, mv$(subpats) + }); + } + else + { + // Keep as a struct pattern + } + } + } + else + { + if( !p.first->m_data.is_Data() ) + { + ERROR(sp, E0000, "Enum struct pattern `" << pat << "` on non-struct variant " << e.path); + } + else + { + const auto& var = p.first->m_data.as_Data()[p.second]; + if( !var.is_struct ) + ERROR(sp, E0000, "Enum struct pattern `" << pat << "` on non-struct variant " << e.path); + } + } e.binding_ptr = p.first; e.binding_idx = p.second; ) -- cgit v1.2.3 From 5b6ab1bc91bf9b8a7dbc956e2541ba113a186540 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 20 Jan 2019 19:34:05 +0800 Subject: HIR Const Eval - Handle pre-resolved defaulted ATYs --- src/hir_conv/constant_evaluation.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/hir_conv/constant_evaluation.cpp b/src/hir_conv/constant_evaluation.cpp index f81663ec..43a64bbb 100644 --- a/src/hir_conv/constant_evaluation.cpp +++ b/src/hir_conv/constant_evaluation.cpp @@ -1048,7 +1048,19 @@ namespace { )); } else { - TODO(sp, "Assign associated type " << vi.first << " in impl" << impl.m_params.fmt_args() << " " << trait_path << impl.m_trait_args << " for " << impl.m_type); + //TODO(sp, "Assign associated type " << vi.first << " in impl" << impl.m_params.fmt_args() << " " << trait_path << impl.m_trait_args << " for " << impl.m_type); + impl.m_constants.insert(::std::make_pair( + vi.first, + ::HIR::TraitImpl::ImplEnt<::HIR::Constant> { + /*is_specialisable=*/false, + ::HIR::Constant { + template_const.m_params.clone(), + /*m_type=*/ms.monomorph(sp, template_const.m_type), + /*m_value=*/::HIR::ExprPtr(), + clone_literal(template_const.m_value_res) + } + } + )); } } } -- cgit v1.2.3 From feaa7573c2d959d1cf893e8bd772cb22bccf5d62 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 20 Jan 2019 19:34:28 +0800 Subject: HIR Misc - Local asserts with patterns --- src/hir_expand/annotate_value_usage.cpp | 4 ++-- src/mir/from_hir.cpp | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/hir_expand/annotate_value_usage.cpp b/src/hir_expand/annotate_value_usage.cpp index f5acbbc5..491ab4c7 100644 --- a/src/hir_expand/annotate_value_usage.cpp +++ b/src/hir_expand/annotate_value_usage.cpp @@ -560,10 +560,10 @@ namespace { ), (EnumStruct, const auto& enm = *pe.binding_ptr; - ASSERT_BUG(sp, enm.m_data.is_Data(), ""); + ASSERT_BUG(sp, enm.m_data.is_Data(), "EnumStruct pattern on non-data enum"); const auto& var = enm.m_data.as_Data().at(pe.binding_idx); const auto& str = *var.type.m_data.as_Path().binding.as_Struct(); - ASSERT_BUG(sp, str.m_data.is_Named(), ""); + ASSERT_BUG(sp, str.m_data.is_Named(), "EnumStruct pattern on non-struct variant - " << pe.path); const auto& flds = str.m_data.as_Named(); auto monomorph_cb = monomorphise_type_get_cb(sp, nullptr, &pe.path.m_params, nullptr); diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index e13b9db1..ee4cf474 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -251,6 +251,7 @@ namespace { } TU_ARMA(Struct, e) { const auto& str = *e.binding; + ASSERT_BUG(sp, str.m_data.is_Named(), "Struct pattern on non-Named struct - " << e.path); const auto& fields = str.m_data.as_Named(); for(const auto& fld_pat : e.sub_patterns) { @@ -304,6 +305,7 @@ namespace { ASSERT_BUG(sp, enm.m_data.is_Data(), "Expected struct variant - " << pat); const auto& var = enm.m_data.as_Data()[e.binding_idx];; const auto& str = *var.type.m_data.as_Path().binding.as_Struct(); + ASSERT_BUG(sp, str.m_data.is_Named(), "Struct pattern on non-Named struct - " << e.path); const auto& fields = str.m_data.as_Named(); auto lval_var = ::MIR::LValue::make_Downcast({ box$(mv$(lval)), e.binding_idx }); for(const auto& fld_pat : e.sub_patterns) -- cgit v1.2.3 From f8c4d1997464d2c9a87b8e6adc34784a1c0ad863 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 20 Jan 2019 19:42:15 +0800 Subject: Resolve Use - Handle macro_rules imports --- src/resolve/use.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/resolve/use.cpp b/src/resolve/use.cpp index 450af742..c4fb659f 100644 --- a/src/resolve/use.cpp +++ b/src/resolve/use.cpp @@ -334,7 +334,8 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path for(const auto& mac : mod.macros()) { if( mac.name == des_item_name ) { - TODO(span, "Import of macro - " << des_item_name); + rv.macro = ::AST::PathBinding_Macro::make_MacroRules({ nullptr, &*mac.data }); + break; } } -- cgit v1.2.3 From 71be0e9e2cd81ef9c0482ae258e82bcdc8fb6e5c Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 20 Jan 2019 19:59:47 +0800 Subject: Parse - Leading | in match arms (rustc quirk) --- src/parse/expr.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/parse/expr.cpp b/src/parse/expr.cpp index 03c77043..5e38ca81 100644 --- a/src/parse/expr.cpp +++ b/src/parse/expr.cpp @@ -436,6 +436,9 @@ ExprNodeP Parse_Expr_Match(TokenStream& lex) arm.m_attrs = Parse_ItemAttrs(lex); + // HACK: Questionably valid, but 1.29 librustc/hir/lowering.rs needs this + if( LOOK_AHEAD(lex) == TOK_PIPE ) + GET_TOK(tok, lex); do { // Refutable pattern arm.m_patterns.push_back( Parse_Pattern(lex, true) ); -- cgit v1.2.3 From e4437d90f3839e5731d29bb56202a800d78c7d18 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 20 Jan 2019 20:35:26 +0800 Subject: Parse - Trailing commas in Fn(...) handling --- src/parse/paths.cpp | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/parse/paths.cpp b/src/parse/paths.cpp index 2a2437ca..cb704f85 100644 --- a/src/parse/paths.cpp +++ b/src/parse/paths.cpp @@ -142,18 +142,14 @@ AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generi auto ps = lex.start_span(); DEBUG("Fn() hack"); ::std::vector args; - if( GET_TOK(tok, lex) == TOK_PAREN_CLOSE ) - { - // Empty list - } - else - { - PUTBACK(tok, lex); - do { - // TODO: Trailing commas - args.push_back( Parse_Type(lex) ); - } while( GET_TOK(tok, lex) == TOK_COMMA ); - } + do { + // Trailing comma or empty list support + if( lex.lookahead(0) == TOK_PAREN_CLOSE ) { + GET_TOK(tok, lex); + break; + } + args.push_back( Parse_Type(lex) ); + } while( GET_TOK(tok, lex) == TOK_COMMA ); CHECK_TOK(tok, TOK_PAREN_CLOSE); TypeRef ret_type = TypeRef( TypeRef::TagUnit(), Span(tok.get_pos()) ); -- cgit v1.2.3 From 150aa5de75f69ba2d91360a51a8aaf5e4b5a2a03 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 20 Jan 2019 20:42:11 +0800 Subject: Parse - More HRTBs --- src/parse/common.hpp | 1 + src/parse/types.cpp | 12 +++++------- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/parse/common.hpp b/src/parse/common.hpp index c8f51520..6ee0d3f4 100644 --- a/src/parse/common.hpp +++ b/src/parse/common.hpp @@ -42,6 +42,7 @@ extern AST::PathParams Parse_Path_GenericList(TokenStream& lex); extern AST::Visibility Parse_Publicity(TokenStream& lex, bool allow_restricted=true); extern AST::HigherRankedBounds Parse_HRB(TokenStream& lex); +extern ::AST::HigherRankedBounds Parse_HRB_Opt(TokenStream& lex); extern AST::AttributeList Parse_ItemAttrs(TokenStream& lex); extern void Parse_ParentAttrs(TokenStream& lex, AST::AttributeList& out); extern AST::Attribute Parse_MetaItem(TokenStream& lex); diff --git a/src/parse/types.cpp b/src/parse/types.cpp index bbcff489..d261c403 100644 --- a/src/parse/types.cpp +++ b/src/parse/types.cpp @@ -94,7 +94,8 @@ TypeRef Parse_Type_Int(TokenStream& lex, bool allow_trait_list) return rv; } else { - return Parse_Type_TraitObject(lex, {}); + ::AST::HigherRankedBounds hrbs = Parse_HRB_Opt(lex); + return Parse_Type_TraitObject(lex, mv$(hrbs)); } } // or a primitive @@ -198,7 +199,8 @@ TypeRef Parse_Type_Int(TokenStream& lex, bool allow_trait_list) types.push_back( Parse_Type(lex) ); } CHECK_TOK(tok, TOK_PAREN_CLOSE); - return TypeRef(TypeRef::TagTuple(), lex.end_span(ps), mv$(types)); } + return TypeRef(TypeRef::TagTuple(), lex.end_span(ps), mv$(types)); + } } default: throw ParseError::Unexpected(lex, tok); @@ -369,11 +371,7 @@ TypeRef Parse_Type_ErasedType(TokenStream& lex, bool allow_trait_list) } else { - AST::HigherRankedBounds hrbs; - if( lex.lookahead(0) == TOK_RWORD_FOR ) - { - hrbs = Parse_HRB(lex); - } + AST::HigherRankedBounds hrbs = Parse_HRB_Opt(lex); traits.push_back({ mv$(hrbs), Parse_Path(lex, PATH_GENERIC_TYPE) }); } } while( GET_TOK(tok, lex) == TOK_PLUS ); -- cgit v1.2.3 From e52b02d47c71fd8c926ac9cac90d3bf6d9b1ba0a Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 20 Jan 2019 20:47:51 +0800 Subject: Parse - Handle `use {self as foo}` --- src/parse/root.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/parse/root.cpp b/src/parse/root.cpp index c3fbfdd1..4d9c96e0 100644 --- a/src/parse/root.cpp +++ b/src/parse/root.cpp @@ -1361,6 +1361,11 @@ void Parse_Use_Inner(TokenStream& lex, ::std::vector& entries else if( LOOK_AHEAD(lex) == TOK_RWORD_SELF ) { GET_TOK(tok, lex); auto name = path.nodes().back().name(); + if( LOOK_AHEAD(lex) == TOK_RWORD_AS ) { + GET_TOK(tok, lex); + GET_CHECK_TOK(tok, lex, TOK_IDENT); + name = mv$(tok.str()); + } entries.push_back({ lex.point_span(), AST::Path(path), ::std::move(name) }); } else { -- cgit v1.2.3 From 86f47abeb42c98d450c9ff4c0418320077b3f0cd Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 20 Jan 2019 21:49:09 +0800 Subject: HIR Serialise - Handle HIR::Literal::Defer --- src/hir/deserialise.cpp | 3 ++- src/hir/serialise.cpp | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/hir/deserialise.cpp b/src/hir/deserialise.cpp index c6655a80..2f9b752e 100644 --- a/src/hir/deserialise.cpp +++ b/src/hir/deserialise.cpp @@ -1027,6 +1027,7 @@ { #define _(x, ...) case ::HIR::Literal::TAG_##x: return ::HIR::Literal::make_##x(__VA_ARGS__); _(Invalid, {}) + _(Defer, {}) _(List, deserialise_vec< ::HIR::Literal>() ) _(Variant, { static_cast(m_in.read_count()), @@ -1039,7 +1040,7 @@ _(String, m_in.read_string() ) #undef _ default: - BUG(Span(), "Unknown literal when deserialising - " << tag); + BUG(Span(), "Unknown HIR::Literal tag when deserialising - " << tag); } } diff --git a/src/hir/serialise.cpp b/src/hir/serialise.cpp index c3a27998..8d92267a 100644 --- a/src/hir/serialise.cpp +++ b/src/hir/serialise.cpp @@ -479,6 +479,8 @@ (Invalid, //BUG(Span(), "Literal::Invalid encountered in HIR"); ), + (Defer, + ), (List, serialise_vec(e); ), -- cgit v1.2.3 From 048666d6415bf8dfff11ddbf287fc488833ab609 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Mon, 21 Jan 2019 08:15:58 +0800 Subject: macro_rules - :lifetime fragment --- src/macro_rules/eval.cpp | 9 ++++++++- src/macro_rules/macro_rules.hpp | 1 + src/macro_rules/mod.cpp | 2 ++ src/macro_rules/parse.cpp | 14 ++++++++++++++ 4 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/macro_rules/eval.cpp b/src/macro_rules/eval.cpp index e864537c..fd0f5648 100644 --- a/src/macro_rules/eval.cpp +++ b/src/macro_rules/eval.cpp @@ -654,9 +654,11 @@ bool Macro_TryPatternCap(TokenStream& lex, MacroPatEnt::Type type) case MacroPatEnt::PAT_META: return LOOK_AHEAD(lex) == TOK_IDENT || LOOK_AHEAD(lex) == TOK_INTERPOLATED_META; case MacroPatEnt::PAT_ITEM: - return is_token_item( LOOK_AHEAD(lex) ) || LOOK_AHEAD(lex) == TOK_IDENT; + return is_token_item( LOOK_AHEAD(lex) ) || LOOK_AHEAD(lex) == TOK_IDENT; // Huh? Ident? case MacroPatEnt::PAT_VIS: return is_token_vis( LOOK_AHEAD(lex) ); + case MacroPatEnt::PAT_LIFETIME: + return LOOK_AHEAD(lex) == TOK_LIFETIME; } BUG(lex.point_span(), "Fell through"); } @@ -727,6 +729,9 @@ InterpolatedFragment Macro_HandlePatternCap(TokenStream& lex, MacroPatEnt::Type return InterpolatedFragment( TokenTree(lex.getHygiene(), tok) ); case MacroPatEnt::PAT_VIS: return InterpolatedFragment( Parse_Publicity(lex, /*allow_restricted=*/true) ); + case MacroPatEnt::PAT_LIFETIME: + GET_CHECK_TOK(tok, lex, TOK_LIFETIME); + return InterpolatedFragment( TokenTree(lex.getHygiene(), tok) ); } throw ""; } @@ -1950,6 +1955,8 @@ namespace return consume_item(lex); case MacroPatEnt::PAT_VIS: return consume_vis(lex); + case MacroPatEnt::PAT_LIFETIME: + return lex.consume_if(TOK_LIFETIME); } return true; } diff --git a/src/macro_rules/macro_rules.hpp b/src/macro_rules/macro_rules.hpp index 9ec6a6bb..29c4f93d 100644 --- a/src/macro_rules/macro_rules.hpp +++ b/src/macro_rules/macro_rules.hpp @@ -61,6 +61,7 @@ struct MacroPatEnt PAT_META, PAT_ITEM, // :item PAT_VIS, + PAT_LIFETIME, } type; MacroPatEnt(): diff --git a/src/macro_rules/mod.cpp b/src/macro_rules/mod.cpp index 3297a139..04f1577a 100644 --- a/src/macro_rules/mod.cpp +++ b/src/macro_rules/mod.cpp @@ -200,6 +200,7 @@ MacroRulesPtr::~MacroRulesPtr() case MacroPatEnt::PAT_META: os << "meta"; break; case MacroPatEnt::PAT_ITEM: os << "item"; break; case MacroPatEnt::PAT_VIS: os << "vis"; break; + case MacroPatEnt::PAT_LIFETIME: os << "lifetime"; break; } break; } @@ -222,6 +223,7 @@ MacroRulesPtr::~MacroRulesPtr() case MacroPatEnt::PAT_META: os << "PAT_META"; break; case MacroPatEnt::PAT_ITEM: os << "PAT_ITEM"; break; case MacroPatEnt::PAT_VIS: os << "PAT_VIS"; break; + case MacroPatEnt::PAT_LIFETIME: os << "PAT_LIFETIME"; break; } return os; } diff --git a/src/macro_rules/parse.cpp b/src/macro_rules/parse.cpp index e6d9d7ae..8af9bd07 100644 --- a/src/macro_rules/parse.cpp +++ b/src/macro_rules/parse.cpp @@ -84,6 +84,8 @@ public: ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_ITEM) ); else if( /*TARGETVER_1_29 && */ type == "vis" ) // TODO: Should this be selective? ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_VIS) ); + else if( /*TARGETVER_1_29 && */ type == "lifetime" ) // TODO: Should this be selective? + ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_LIFETIME) ); else ERROR(lex.point_span(), E0000, "Unknown fragment type '" << type << "'"); break; } @@ -443,6 +445,18 @@ bool patterns_are_same(const Span& sp, const MacroPatEnt& left, const MacroPatEn default: ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left); } + case MacroPatEnt::PAT_LIFETIME: + switch(left.type) + { + case MacroPatEnt::PAT_TOKEN: + if( left.tok.type() == TOK_LIFETIME ) + ERROR(sp, E0000, "Incompatible macro fragments"); + return false; + case MacroPatEnt::PAT_LIFETIME: + return true; + default: + ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left); + } } throw ""; } -- cgit v1.2.3 From d1ea840742dac3d3af66667508c8a841a6c6ca70 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Mon, 21 Jan 2019 08:16:22 +0800 Subject: Parse (partial) - `extern { type Foo; }`, very rough --- src/ast/ast.cpp | 2 +- src/parse/root.cpp | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index f3a81e80..9893e87f 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -262,7 +262,7 @@ UseItem UseItem::clone() const void ExternBlock::add_item(Named named_item) { - ASSERT_BUG(named_item.data.span, named_item.data.is_Function() || named_item.data.is_Static(), "Incorrect item type for ExternBlock"); + ASSERT_BUG(named_item.data.span, named_item.data.is_Function() || named_item.data.is_Static() || named_item.data.is_Type(), "Incorrect item type for ExternBlock - " << named_item.data.tag_str()); m_items.push_back( mv$(named_item) ); } ExternBlock ExternBlock::clone() const diff --git a/src/parse/root.cpp b/src/parse/root.cpp index 4d9c96e0..a58e05d5 100644 --- a/src/parse/root.cpp +++ b/src/parse/root.cpp @@ -1325,8 +1325,19 @@ AST::ExternBlock Parse_ExternBlock(TokenStream& lex, ::std::string abi, ::AST::A i.span = lex.end_span(ps); rv.add_item( AST::Named { mv$(name), mv$(i), is_public } ); break; } + case TOK_RWORD_TYPE: { + GET_CHECK_TOK(tok, lex, TOK_IDENT); + auto name = mv$(tok.str()); + GET_CHECK_TOK(tok, lex, TOK_SEMICOLON); + auto sp = lex.end_span(ps); + //TODO(sp, "Extern type"); + auto i = ::AST::Item(::AST::TypeAlias( ::AST::GenericParams(), ::TypeRef(sp) )); + i.attrs = mv$(meta_items); + i.span = mv$(sp); + rv.add_item( AST::Named { mv$(name), mv$(i), is_public } ); + break; } default: - throw ParseError::Unexpected(lex, tok, {TOK_RWORD_FN, TOK_RWORD_STATIC}); + throw ParseError::Unexpected(lex, tok, {TOK_RWORD_FN, TOK_RWORD_STATIC, TOK_RWORD_TYPE}); } } -- cgit v1.2.3 From 4f48058690ffc6af273a49eeb909d792163cade9 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 27 Jan 2019 11:06:21 +0800 Subject: macro_rules - Rework pattern matching into a "compiled" format (easier to disambiguate) --- src/hir/deserialise.cpp | 41 ++- src/hir/serialise.cpp | 28 ++ src/include/tagged_union.hpp | 2 +- src/macro_rules/eval.cpp | 757 ++++++---------------------------------- src/macro_rules/macro_rules.hpp | 40 ++- src/macro_rules/mod.cpp | 36 +- src/macro_rules/parse.cpp | 452 ++++++++++++++---------- 7 files changed, 512 insertions(+), 844 deletions(-) diff --git a/src/hir/deserialise.cpp b/src/hir/deserialise.cpp index 2f9b752e..30d05b40 100644 --- a/src/hir/deserialise.cpp +++ b/src/hir/deserialise.cpp @@ -244,6 +244,45 @@ } return rv; } + ::SimplePatIfCheck deserialise_simplepatifcheck() { + return ::SimplePatIfCheck { + static_cast<::MacroPatEnt::Type>(m_in.read_tag()), + deserialise_token() + }; + } + ::SimplePatEnt deserialise_simplepatent() { + auto tag = static_cast< ::SimplePatEnt::Tag>( m_in.read_tag() ); + switch(tag) + { + case ::SimplePatEnt::TAG_End: + return ::SimplePatEnt::make_End({}); + case ::SimplePatEnt::TAG_LoopStart: + return ::SimplePatEnt::make_LoopStart({}); + case ::SimplePatEnt::TAG_LoopNext: + return ::SimplePatEnt::make_LoopNext({}); + case ::SimplePatEnt::TAG_LoopEnd: + return ::SimplePatEnt::make_LoopEnd({}); + case ::SimplePatEnt::TAG_Jump: + return ::SimplePatEnt::make_Jump({ m_in.read_count() }); + case ::SimplePatEnt::TAG_ExpectTok: + return SimplePatEnt::make_ExpectTok({ + deserialise_token() + }); + case ::SimplePatEnt::TAG_ExpectPat: + return SimplePatEnt::make_ExpectPat({ + static_cast<::MacroPatEnt::Type>(m_in.read_tag()), + static_cast(m_in.read_count()) + }); + case SimplePatEnt::TAG_If: + return SimplePatEnt::make_If({ + m_in.read_bool(), + m_in.read_count(), + deserialise_vec_c< SimplePatIfCheck>([&](){ return deserialise_simplepatifcheck(); }) + }); + default: + BUG(Span(), "Bad tag for MacroPatEnt - #" << static_cast(tag)); + } + } ::MacroPatEnt deserialise_macropatent() { auto s = m_in.read_string(); auto n = static_cast(m_in.read_count()); @@ -278,7 +317,7 @@ ::MacroRulesArm deserialise_macrorulesarm() { ::MacroRulesArm rv; rv.m_param_names = deserialise_vec< ::std::string>(); - rv.m_pattern = deserialise_vec_c< ::MacroPatEnt>( [&](){ return deserialise_macropatent(); } ); + rv.m_pattern = deserialise_vec_c< ::SimplePatEnt>( [&](){ return deserialise_simplepatent(); } ); rv.m_contents = deserialise_vec_c< ::MacroExpansionEnt>( [&](){ return deserialise_macroexpansionent(); } ); return rv; } diff --git a/src/hir/serialise.cpp b/src/hir/serialise.cpp index 8d92267a..c91cf93f 100644 --- a/src/hir/serialise.cpp +++ b/src/hir/serialise.cpp @@ -415,6 +415,34 @@ serialise_vec(pe.subpats); } } + void serialise(const ::SimplePatIfCheck& e) { + m_out.write_tag( static_cast(e.ty) ); + serialise(e.tok); + } + void serialise(const ::SimplePatEnt& pe) { + m_out.write_tag( pe.tag() ); + TU_MATCH_HDRA( (pe), { ) + TU_ARMA(End, _e) {} + TU_ARMA(LoopStart, _e) {} + TU_ARMA(LoopNext, _e) {} + TU_ARMA(LoopEnd, _e) {} + TU_ARMA(Jump, e) { + m_out.write_count(e.jump_target); + } + TU_ARMA(ExpectTok, e) { + serialise(e); + } + TU_ARMA(ExpectPat, e) { + m_out.write_tag( static_cast(e.type) ); + m_out.write_count(e.idx); + } + TU_ARMA(If, e) { + m_out.write_bool(e.is_equal); + m_out.write_count(e.jump_target); + serialise_vec(e.ents); + } + } + } void serialise(const ::MacroRulesArm& arm) { serialise_vec(arm.m_param_names); serialise_vec(arm.m_pattern); diff --git a/src/include/tagged_union.hpp b/src/include/tagged_union.hpp index d249de13..dab7f8ea 100644 --- a/src/include/tagged_union.hpp +++ b/src/include/tagged_union.hpp @@ -122,7 +122,7 @@ #define TU_ARM(VAR, TAG, NAME) break; case ::std::remove_reference::type::TAG_##TAG: for(bool tu_lc = true; tu_lc; tu_lc=false) for(auto& NAME = (VAR).as_##TAG(); (void)NAME, tu_lc; tu_lc=false) #define TU_MATCH_HDRA(VARS, brace) TU_MATCH_HDRA_(::std::remove_reference::type, VARS, brace) -#define TU_MATCH_HDRA_(CLASS, VARS, brace) const auto& tu_match_hdr2_v = (TU_FIRST VARS); switch( tu_match_hdr2_v.tag() ) brace case CLASS::TAGDEAD: assert(!"ERROR: destructed tagged union used"); +#define TU_MATCH_HDRA_(CLASS, VARS, brace) auto& tu_match_hdr2_v = (TU_FIRST VARS); switch( tu_match_hdr2_v.tag() ) brace case CLASS::TAGDEAD: assert(!"ERROR: destructed tagged union used"); // Evil hack: two for loops, the inner stops the outer after it's done. #define TU_ARMA(TAG, NAME) break; case ::std::remove_reference::type::TAG_##TAG: for(bool tu_lc = true; tu_lc; tu_lc=false) for(auto& NAME = tu_match_hdr2_v.as_##TAG(); (void)NAME, tu_lc; tu_lc=false) diff --git a/src/macro_rules/eval.cpp b/src/macro_rules/eval.cpp index fd0f5648..03c5609c 100644 --- a/src/macro_rules/eval.cpp +++ b/src/macro_rules/eval.cpp @@ -93,60 +93,43 @@ private: CapturedVal& get_cap(const ::std::vector& iterations, unsigned int name_idx); }; -/// Simple pattern entry for macro_rules! arm patterns -TAGGED_UNION( SimplePatEnt, End, - // End of the pattern stream - (End, struct{}), - // Expect a specific token - (ExpectTok, Token), - // Expect a pattern match - (ExpectPat, struct { - MacroPatEnt::Type type; - unsigned int idx; - }), - // Compare the head of the input stream and poke the pattern stream - (IfTok, struct { - bool is_equal; - Token tok; - }), - // Compare the head of the input stream and poke the pattern stream - (IfPat, struct { - bool is_equal; - MacroPatEnt::Type type; - }) - ); class MacroPatternStream { - const ::std::vector* m_pattern; - // Position in each nested pattern - ::std::vector m_pos; + const ::std::vector& m_simple_ents; + size_t m_cur_pos; + + bool m_last_was_cond; + bool m_condition_met; + ::std::vector m_condition_history; + + const ::std::vector* m_condition_replay; + size_t m_condition_replay_pos; + // Iteration index of each active loop level ::std::vector m_loop_iterations; - ::std::vector m_stack; - unsigned int m_skip_count; - - SimplePatEnt m_peek_cache; bool m_peek_cache_valid = false; + const SimplePatEnt* m_peek_cache; - bool m_break_if_not = false; - bool m_condition_fired = false; public: - MacroPatternStream(const ::std::vector& pattern): - m_pattern(&pattern), - m_pos({0}) + MacroPatternStream(const ::std::vector& ents, const ::std::vector* condition_replay=nullptr): + m_simple_ents(ents), + m_cur_pos(0), + m_last_was_cond(false), + m_condition_replay(condition_replay), + m_condition_replay_pos(0) { } /// Get the next pattern entry - SimplePatEnt next(); + const SimplePatEnt& next(); const SimplePatEnt& peek() { if( !m_peek_cache_valid ) { - m_peek_cache = next(); + m_peek_cache = &next(); m_peek_cache_valid = true; } - return m_peek_cache; + return *m_peek_cache; } /// Inform the stream that the `if` rule that was just returned succeeded @@ -156,16 +139,9 @@ public: return m_loop_iterations; } -private: - SimplePatEnt emit_loop_start(const MacroPatEnt& pat); - - SimplePatEnt emit_seq(SimplePatEnt v1, SimplePatEnt v2) { - assert( m_stack.empty() ); - m_stack.push_back( mv$(v2) ); - return v1; + ::std::vector take_history() { + return ::std::move(m_condition_history); } - - void break_loop(); }; // === Prototypes === @@ -312,223 +288,74 @@ bool ParameterMappings::dec_count(const ::std::vector& iterations, // MacroPatternStream // ------------------------------------ -SimplePatEnt MacroPatternStream::next() +const SimplePatEnt& MacroPatternStream::next() { - TRACE_FUNCTION_F("m_pos=[" << m_pos << "], m_stack.size()=" << m_stack.size()); - assert(m_pos.size() >= 1); - if( m_peek_cache_valid ) { m_peek_cache_valid = false; - return mv$(m_peek_cache); - } - - // Pop off the generation stack - if( ! m_stack.empty() ) { - auto rv = mv$(m_stack.back()); - m_stack.pop_back(); - return rv; - } - - if( m_break_if_not && ! m_condition_fired ) { - // Break out of the current loop then continue downwards. - break_loop(); - } - - m_skip_count = 0; - m_break_if_not = false; - m_condition_fired = false; - - const MacroPatEnt* parent_pat = nullptr; - decltype(m_pattern) parent_ents = nullptr; - const auto* ents = m_pattern; - for(unsigned int i = 0; i < m_pos.size() - 1; i ++) - { - auto idx = m_pos[i]; - //DEBUG(i << " idx=" << idx << " ents->size()=" << ents->size()); - assert( idx < ents->size() ); - assert( (*ents)[idx].type == MacroPatEnt::PAT_LOOP ); - parent_pat = &(*ents)[idx]; - parent_ents = ents; - ents = &parent_pat->subpats; + return *m_peek_cache; } - DEBUG( (m_pos.size()-1) << " " << m_pos.back() << " / " << ents->size()); - if( m_pos.back() < ents->size() ) + for(;;) { - const auto& pat = ents->at( m_pos.back() ); - - if( pat.type == MacroPatEnt::PAT_LOOP ) { - DEBUG("Enter " << pat); - // Increase level, return entry control - m_pos.push_back( 0 ); - m_loop_iterations.push_back( 0 ); - - if( pat.name == "*" ) - { - return emit_loop_start(pat); - } - else - { - // If the name is "+" then this is should always be entered, so just recurse - assert( pat.name == "+" ); - return next(); - } - } - else if( pat.type == MacroPatEnt::PAT_TOKEN ) { - m_pos.back() += 1; - return SimplePatEnt::make_ExpectTok( pat.tok.clone() ); - } - else { - m_pos.back() += 1; - return SimplePatEnt::make_ExpectPat({ pat.type, pat.name_index }); - } - } - else - { - if( parent_pat ) + // If not replaying, and the previous entry was a conditional, record the result of that conditional + if( !m_condition_replay && m_last_was_cond ) { - // Last entry in a loop - return the breakout control - // - Reset the loop back to the start - m_pos.back() = 0; - m_loop_iterations.back() += 1; - - // - Emit break conditions - if( parent_pat->tok == TOK_NULL ) { - // Loop separator is TOK_NULL - get the first token of the loop and use it. - // - This shares the code that controls if a loop is entered - DEBUG("No separator"); - return emit_loop_start(*parent_pat); - } - else { - // If the next token is the same as the separator emit: Expect(separator), ShouldEnter - - auto i = m_pos[ m_pos.size() - 2 ] + 1; - if( i < parent_ents->size() ) - { - DEBUG("sep = " << parent_pat->tok << ", next = " << parent_ents->at(i) << ", start = " << ents->at(0)); - if( parent_ents->at(i).type == MacroPatEnt::PAT_TOKEN && parent_pat->tok == parent_ents->at(i).tok ) - { - DEBUG("MAGIC: Reverse conditions for case where sep==next"); - // > Mark to skip the next token after the end of the loop - m_skip_count = 1; - // - Yeild `EXPECT sep` then the entry condition of this loop - auto pat = emit_loop_start(*parent_pat); - m_stack.push_back( mv$(pat) ); - return SimplePatEnt::make_ExpectTok( parent_pat->tok.clone() ); - } - } - // - Yeild `IF NOT sep BREAK` and `EXPECT sep` - DEBUG("Separator = " << parent_pat->tok); - return emit_seq( - SimplePatEnt::make_IfTok({ false, parent_pat->tok.clone() }), - SimplePatEnt::make_ExpectTok( parent_pat->tok.clone() ) - ); - } + m_condition_history.push_back(m_condition_met); } - else - { - // End of the input sequence - return SimplePatEnt::make_End({}); + m_last_was_cond = false; + // End of list? return End entry + if( m_cur_pos == m_simple_ents.size() ) { + static SimplePatEnt END = SimplePatEnt::make_End({}); + return END; } - } -} - -namespace { - void get_loop_entry_pats(const MacroPatEnt& pat, ::std::vector& entry_pats) - { - assert( pat.type == MacroPatEnt::PAT_LOOP ); - - // If this pattern is a loop, get the entry concrete patterns for it - // - Otherwise, just - unsigned int i = 0; - while( i < pat.subpats.size() && pat.subpats[i].type == MacroPatEnt::PAT_LOOP ) + const auto& cur_ent = m_simple_ents[m_cur_pos]; + // If replaying, and this is a conditional + if( m_condition_replay && cur_ent.is_If() ) { - const auto& cur_pat = pat.subpats[i]; - bool is_optional = (cur_pat.name == "*"); - - get_loop_entry_pats(cur_pat, entry_pats); - - if( !is_optional ) - { - // Non-optional loop, MUST be entered, so return after recursing - return ; - } - // Optional, so continue the loop. - i ++; - } - - // First non-loop pattern - if( i < pat.subpats.size() ) - { - entry_pats.push_back( &pat.subpats[i] ); - } - } -} // namespace - -/// Returns (and primes m_stack) the rules to control the start of a loop -/// This code emits rules to break out of the loop if the entry conditions are not met -SimplePatEnt MacroPatternStream::emit_loop_start(const MacroPatEnt& pat) -{ - // Find the next non-loop pattern to control if this loop should be entered - ::std::vector m_entry_pats; - - get_loop_entry_pats(pat, m_entry_pats); - DEBUG("m_entry_pats = [" << FMT_CB(ss, for(const auto* p : m_entry_pats) { ss << *p << ","; }) << "]"); - - struct H { - static SimplePatEnt get_if(bool flag, const MacroPatEnt& mpe) { - if( mpe.type == MacroPatEnt::PAT_TOKEN ) - return SimplePatEnt::make_IfTok({ flag, mpe.tok.clone() }); + // Skip the conditional (following its target or just skipping over) + if( (*m_condition_replay)[m_condition_replay_pos++] ) + m_cur_pos = cur_ent.as_If().jump_target; else - return SimplePatEnt::make_IfPat({ flag, mpe.type }); + m_cur_pos += 1; + continue ; } - }; - - const auto* entry_pat = m_entry_pats.back(); - m_entry_pats.pop_back(); - if( m_entry_pats.size() > 0 ) - { - DEBUG("Multiple entry possibilities, reversing condition"); - m_break_if_not = true; - for(auto pat_ptr : m_entry_pats) - { - m_stack.push_back( H::get_if(true, *pat_ptr) ); + m_cur_pos += 1; + TU_MATCH_HDRA( (cur_ent), {) + default: + if( cur_ent.is_If() ) + { + m_last_was_cond = true; + m_condition_met = false; + } + return cur_ent; + TU_ARMA(End, _e) + BUG(Span(), "Unexpected End"); + TU_ARMA(Jump, e) + m_cur_pos = e.jump_target; + TU_ARMA(LoopStart, _e) { + m_loop_iterations.push_back(0); + } + TU_ARMA(LoopNext, _e) { + m_loop_iterations.back() += 1; + } + TU_ARMA(LoopEnd, _e) { + m_loop_iterations.pop_back(); + } } - return H::get_if(true, *entry_pat); - } - else - { - // Emit an if based on it - return H::get_if(false, *entry_pat); } } void MacroPatternStream::if_succeeded() { - if( m_break_if_not ) - { - m_condition_fired = true; - } - else - { - break_loop(); + assert(m_cur_pos > 0); + assert(m_last_was_cond); + TU_MATCH_HDRA( (m_simple_ents[m_cur_pos-1]), {) + default: + BUG(Span(), "Unexpected " << m_simple_ents[m_cur_pos-1]); + TU_ARMA(If, e) + m_cur_pos = e.jump_target; } -} -void MacroPatternStream::break_loop() -{ - DEBUG("- Break out of loop, m_skip_count = " << m_skip_count); - // Break out of an active loop (pop level and increment parent level) - assert( m_pos.size() >= 1 ); - // - This should never be called when on the top level - assert( m_pos.size() != 1 ); - - // HACK: Clear the stack if an if succeeded - m_stack.clear(); - - m_pos.pop_back(); - m_pos.back() += 1 + m_skip_count; - - m_loop_iterations.pop_back(); + m_condition_met = true; } // ---------------------------------------------------------------- @@ -616,73 +443,6 @@ namespace { } } -// TODO: This shouldn't exist, and can false-positives -// - Ideally, this would use consume_from_frag (which takes a clone-able input) -bool Macro_TryPatternCap(TokenStream& lex, MacroPatEnt::Type type) -{ - switch(type) - { - case MacroPatEnt::PAT_TOKEN: - BUG(lex.point_span(), ""); - case MacroPatEnt::PAT_LOOP: - BUG(lex.point_span(), ""); - case MacroPatEnt::PAT_BLOCK: - return LOOK_AHEAD(lex) == TOK_BRACE_OPEN || LOOK_AHEAD(lex) == TOK_INTERPOLATED_BLOCK; - case MacroPatEnt::PAT_IDENT: - return LOOK_AHEAD(lex) == TOK_IDENT || is_reserved_word(LOOK_AHEAD(lex)); - case MacroPatEnt::PAT_TT: - switch(LOOK_AHEAD(lex)) - { - case TOK_EOF: - case TOK_PAREN_CLOSE: - case TOK_BRACE_CLOSE: - case TOK_SQUARE_CLOSE: - return false; - default: - return true; - } - case MacroPatEnt::PAT_PATH: - return is_token_path( LOOK_AHEAD(lex) ); - case MacroPatEnt::PAT_TYPE: - return is_token_type( LOOK_AHEAD(lex) ); - case MacroPatEnt::PAT_EXPR: - return is_token_expr( LOOK_AHEAD(lex) ); - case MacroPatEnt::PAT_STMT: - return is_token_stmt( LOOK_AHEAD(lex) ); - case MacroPatEnt::PAT_PAT: - return is_token_pat( LOOK_AHEAD(lex) ); - case MacroPatEnt::PAT_META: - return LOOK_AHEAD(lex) == TOK_IDENT || LOOK_AHEAD(lex) == TOK_INTERPOLATED_META; - case MacroPatEnt::PAT_ITEM: - return is_token_item( LOOK_AHEAD(lex) ) || LOOK_AHEAD(lex) == TOK_IDENT; // Huh? Ident? - case MacroPatEnt::PAT_VIS: - return is_token_vis( LOOK_AHEAD(lex) ); - case MacroPatEnt::PAT_LIFETIME: - return LOOK_AHEAD(lex) == TOK_LIFETIME; - } - BUG(lex.point_span(), "Fell through"); -} -bool Macro_TryPattern(TokenStream& lex, const MacroPatEnt& pat) -{ - DEBUG("pat = " << pat); - Token tok; - switch(pat.type) - { - case MacroPatEnt::PAT_TOKEN: { - GET_TOK(tok, lex); - bool rv = (tok == pat.tok); - PUTBACK(tok, lex); - return rv; - } - case MacroPatEnt::PAT_LOOP: - if( pat.name == "*" ) - return true; - return Macro_TryPattern(lex, pat.subpats[0]); - default: - return Macro_TryPatternCap(lex, pat.type); - } -} - InterpolatedFragment Macro_HandlePatternCap(TokenStream& lex, MacroPatEnt::Type type) { Token tok; @@ -761,7 +521,6 @@ InterpolatedFragment Macro_HandlePatternCap(TokenStream& lex, MacroPatEnt::Type return ::std::unique_ptr( ret_ptr ); } -#if 1 // Collection of functions that consume a specific fragment type from a token stream // - Does very loose consuming namespace @@ -1887,7 +1646,7 @@ namespace { case MacroPatEnt::PAT_TOKEN: case MacroPatEnt::PAT_LOOP: - throw ""; + BUG(Span(), "Encountered " << type << " in consume_from_frag");; case MacroPatEnt::PAT_BLOCK: if( lex.next() == TOK_BRACE_OPEN ) { return consume_tt(lex); @@ -1966,13 +1725,7 @@ unsigned int Macro_InvokeRules_MatchPattern(const Span& sp, const MacroRules& ru { TRACE_FUNCTION; - struct ActiveArm { - unsigned int index; - MacroPatternStream pat_stream; - TokenStreamRO in_stream; - }; - - ::std::vector matches; + ::std::vector< ::std::pair> > matches; for(size_t i = 0; i < rules.m_rules.size(); i ++) { auto lex = TokenStreamRO(input); @@ -1981,29 +1734,38 @@ unsigned int Macro_InvokeRules_MatchPattern(const Span& sp, const MacroRules& ru bool fail = false; for(;;) { - auto pat = arm_stream.next(); + const auto& pat = arm_stream.next(); + DEBUG(i << " " << pat); if(pat.is_End()) { - DEBUG(i << " End"); if( lex.next() != TOK_EOF ) fail = true; break; } - else if( const auto* e = pat.opt_IfPat() ) + else if( const auto* e = pat.opt_If() ) { - DEBUG(i << " IfPat(" << (e->is_equal ? "==" : "!=") << " ?" << e->type << ")"); auto lc = lex.clone(); - if( consume_from_frag(lc, e->type) == e->is_equal ) + bool rv = true; + for(const auto& check : e->ents) { - DEBUG("- Succeeded"); - arm_stream.if_succeeded(); + if( check.ty != MacroPatEnt::PAT_TOKEN ) { + if( !consume_from_frag(lc, check.ty) ) + { + rv = false; + break; + } + } + else + { + if( lc.next_tok() != check.tok ) + { + rv = false; + break; + } + lc.consume(); + } } - } - else if( const auto* e = pat.opt_IfTok() ) - { - DEBUG(i << " IfTok(" << (e->is_equal ? "==" : "!=") << " ?" << e->tok << ")"); - const auto& tok = lex.next_tok(); - if( (tok == e->tok) == e->is_equal ) + if( rv == e->is_equal ) { DEBUG("- Succeeded"); arm_stream.if_succeeded(); @@ -2038,7 +1800,7 @@ unsigned int Macro_InvokeRules_MatchPattern(const Span& sp, const MacroRules& ru if( ! fail ) { - matches.push_back(i); + matches.push_back( ::std::make_pair(i, arm_stream.take_history()) ); DEBUG(i << " MATCHED"); } else @@ -2057,12 +1819,13 @@ unsigned int Macro_InvokeRules_MatchPattern(const Span& sp, const MacroRules& ru // yay! // NOTE: There can be multiple arms active, take the first. - auto i = matches[0]; + auto i = matches[0].first; + const auto& history = matches[0].second; DEBUG("Evalulating arm " << i); auto lex = TTStreamO(sp, mv$(input)); SET_MODULE(lex, mod); - auto arm_stream = MacroPatternStream(rules.m_rules[i].m_pattern); + auto arm_stream = MacroPatternStream(rules.m_rules[i].m_pattern, &history); struct Capture { unsigned int binding_idx; @@ -2074,30 +1837,15 @@ unsigned int Macro_InvokeRules_MatchPattern(const Span& sp, const MacroRules& ru for(;;) { - auto pat = arm_stream.next(); + const auto& pat = arm_stream.next(); + DEBUG(i << " " << pat); if(pat.is_End()) { break; } - else if( const auto* e = pat.opt_IfPat() ) - { - DEBUG(i << " IfPat(" << (e->is_equal ? "==" : "!=") << " ?" << e->type << ")"); - if( Macro_TryPatternCap(lex, e->type) == e->is_equal ) - { - DEBUG("- Succeeded"); - arm_stream.if_succeeded(); - } - } - else if( const auto* e = pat.opt_IfTok() ) + else if( pat.is_If() ) { - DEBUG(i << " IfTok(" << (e->is_equal ? "==" : "!=") << " ?" << e->tok << ")"); - auto tok = lex.getToken(); - if( (tok == e->tok) == e->is_equal ) - { - DEBUG("- Succeeded"); - arm_stream.if_succeeded(); - } - lex.putback( mv$(tok) ); + BUG(sp, "Unexpected If pattern during final matching - " << pat); } else if( const auto* e = pat.opt_ExpectTok() ) { @@ -2132,305 +1880,6 @@ unsigned int Macro_InvokeRules_MatchPattern(const Span& sp, const MacroRules& ru return i; } } -#else -unsigned int Macro_InvokeRules_MatchPattern(const Span& sp, const MacroRules& rules, TokenTree input, AST::Module& mod, ParameterMappings& bound_tts) -{ - TRACE_FUNCTION; - Span sp;// = input.span(); - - struct Capture { - unsigned int binding_idx; - ::std::vector iterations; - unsigned int cap_idx; - }; - struct ActiveArm { - unsigned int index; - ::std::vector captures; - MacroPatternStream stream; - }; - // - List of active rules (rules that haven't yet failed) - ::std::vector< ActiveArm > active_arms; - active_arms.reserve( rules.m_rules.size() ); - for(unsigned int i = 0; i < rules.m_rules.size(); i ++) - { - active_arms.push_back( ActiveArm { i, {}, MacroPatternStream(rules.m_rules[i].m_pattern) } ); - } - - // - List of captured values - ::std::vector captures; - - TTStreamO lex(sp, mv$(input) ); - SET_MODULE(lex, mod); - while(true) - { - DEBUG("--- ---"); - // 1. Get concrete patterns for all active rules (i.e. no If* patterns) - ::std::vector arm_pats; - for(auto& arm : active_arms) - { - auto idx = arm.index; - SimplePatEnt pat; - // Consume all If* rules - do - { - pat = arm.stream.next(); - TU_IFLET( SimplePatEnt, pat, IfPat, e, - DEBUG(idx << " IfPat(" << (e.is_equal ? "==" : "!=") << " ?" << e.type << ")"); - if( Macro_TryPatternCap(lex, e.type) == e.is_equal ) - { - DEBUG("- Succeeded"); - arm.stream.if_succeeded(); - } - ) - else TU_IFLET( SimplePatEnt, pat, IfTok, e, - DEBUG(idx << " IfTok(" << (e.is_equal ? "==" : "!=") << " ?" << e.tok << ")"); - auto tok = lex.getToken(); - if( (tok == e.tok) == e.is_equal ) - { - DEBUG("- Succeeded"); - arm.stream.if_succeeded(); - } - lex.putback( mv$(tok) ); - ) - else { - break; - } - } while( pat.is_IfPat() || pat.is_IfTok() ); - - TU_MATCH( SimplePatEnt, (pat), (e), - (IfPat, BUG(sp, "IfTok unexpected here");), - (IfTok, BUG(sp, "IfTok unexpected here");), - (ExpectTok, - DEBUG(idx << " ExpectTok(" << e << ")"); - ), - (ExpectPat, - DEBUG(idx << " ExpectPat(" << e.type << " => $" << e.idx << ")"); - ), - (End, - DEBUG(idx << " End"); - ) - ) - arm_pats.push_back( mv$(pat) ); - } - assert( arm_pats.size() == active_arms.size() ); - - // 2. Prune imposible arms - for(unsigned int i = 0, j = 0; i < arm_pats.size(); ) - { - auto idx = active_arms[i].index; - const auto& pat = arm_pats[i]; - bool fail = false; - - TU_MATCH( SimplePatEnt, (pat), (e), - (IfPat, BUG(sp, "IfTok unexpected here");), - (IfTok, BUG(sp, "IfTok unexpected here");), - (ExpectTok, - auto tok = lex.getToken(); - DEBUG(j<<"="< $" << e.idx << ")"); - fail = !Macro_TryPatternCap(lex, e.type); - ), - (End, - DEBUG(j<<"="<as_ExpectTok() ) - ERROR(lex.getPosition(), E0000, "Incompatible macro arms - " << tok_pat->as_ExpectTok() << " vs " << e); - } - else { - tok_pat = &pat; - } - ) - else TU_IFLET(SimplePatEnt, pat, ExpectPat, e, - if( e.type == MacroPatEnt::PAT_IDENT ) { - ident_pat_idx = i; - } - else { - has_non_ident_pat = true; - } - ) - } - - if( tok_pat ) - { - auto tok = lex.getToken(); - const auto& e = tok_pat->as_ExpectTok(); - // NOTE: This should never fail. - if( tok != e ) { - ERROR(lex.getPosition(), E0000, "Unexpected " << tok << ", expected " << e); - } - } - else - { - if( has_non_ident_pat && ident_pat_idx < arm_pats.size() ) - { - // For all :ident patterns present, check the next rule. - // - If this rule would fail, remove the arm. - bool ident_rule_kept = false; - for( unsigned int i = 0; i < arm_pats.size(); ) - { - bool discard = false; - const auto& pat = arm_pats[i]; - const auto& e = pat.as_ExpectPat(); - if( e.type == MacroPatEnt::PAT_IDENT ) - { - const auto& next = active_arms[i].stream.peek(); - TU_MATCHA( (next), (ne), - (IfPat, TODO(sp, "Handle IfPat following a conflicting :ident");), - (IfTok, TODO(sp, "IfTok following a conflicting :ident");), - (ExpectTok, - if( ne.type() != lex.lookahead(1) ) { - DEBUG("Discard active arm " << i << " due to next token mismatch"); - discard = true; - } - else { - ident_rule_kept = true; - } - ), - (ExpectPat, - TODO(sp, "Handle ExpectPat following a conflicting :ident"); - ), - (End, TODO(sp, "Handle End following a conflicting :ident"); ) - ) - } - - if( discard ) { - arm_pats.erase( arm_pats.begin() + i ); - active_arms.erase( active_arms.begin() + i ); - } - else { - ++ i; - } - } - - // If there are any remaining ident rules, erase the non-ident rules. - if( ident_rule_kept ) { - // If no rules were discarded, remove the non-ident rules - for( unsigned int i = 0; i < arm_pats.size(); ) - { - if( arm_pats[i].as_ExpectPat().type != MacroPatEnt::PAT_IDENT ) { - arm_pats.erase( arm_pats.begin() + i ); - active_arms.erase( active_arms.begin() + i ); - } - else { - ++ i; - } - } - } - assert(arm_pats.size() > 0); - assert(arm_pats.size() == active_arms.size()); - } - - // 3. Check that all remaining arms are the same pattern. - const auto& active_pat = arm_pats[0]; - for(unsigned int i = 1; i < arm_pats.size(); i ++) - { - if( active_pat.tag() != arm_pats[i].tag() ) { - ERROR(lex.getPosition(), E0000, "Incompatible macro arms " - << "- " << active_arms[0].index << " SimplePatEnt::" << active_pat.tag_str() - << " vs " << active_arms[i].index<< " SimplePatEnt::" << arm_pats[i].tag_str() - ); - } - TU_MATCH( SimplePatEnt, (active_pat, arm_pats[i]), (e1, e2), - (IfPat, BUG(sp, "IfPat unexpected here");), - (IfTok, BUG(sp, "IfTok unexpected here");), - (ExpectTok, - BUG(sp, "ExpectTok unexpected here"); - ), - (ExpectPat, - // Can fail, as :expr and :stmt overlap in their trigger set - if( e1.type != e2.type ) { - ERROR(lex.getPosition(), E0000, "Incompatible macro arms - mismatched patterns " << e1.type << " and " << e2.type); - } - ), - (End, - ) - ) - } - - // 4. Apply patterns. - TU_MATCH( SimplePatEnt, (arm_pats[0]), (e), - (End, - auto tok = lex.getToken(); - if( tok.type() != TOK_EOF ) { - ERROR(lex.getPosition(), E0000, "Unexpected " << tok << ", expected TOK_EOF"); - } - // NOTE: There can be multiple arms active, take the first. - for(const auto& cap : active_arms[0].captures) - { - bound_tts.insert( cap.binding_idx, cap.iterations, mv$(captures[cap.cap_idx]) ); - } - return active_arms[0].index; - ), - (IfPat, BUG(sp, "IfPat unexpected here");), - (IfTok, BUG(sp, "IfTok unexpected here");), - (ExpectTok, - BUG(sp, "ExpectTok should have been handled already"); - ), - (ExpectPat, - struct H { - static bool is_prefix(const ::std::vector& needle, const ::std::vector& haystack) { - if( needle.size() > haystack.size() ) { - return false; - } - else { - for(unsigned int i = 0; i < needle.size(); i ++) { - if(needle[i] != haystack[i]) - return false; - } - return true; - } - } - }; - - auto cap = Macro_HandlePatternCap(lex, e.type); - - unsigned int cap_idx = captures.size(); - captures.push_back( mv$(cap) ); - for(unsigned int i = 0; i < active_arms.size(); i ++) - { - auto& arm = active_arms[i]; - const auto& pat_e = arm_pats[i].as_ExpectPat(); - arm.captures.push_back( Capture { pat_e.idx, arm.stream.get_loop_iters(), cap_idx } ); - } - ) - ) - } - - // Keep looping - breakout is handled in 'End' above - } -} -#endif void Macro_InvokeRules_CountSubstUses(ParameterMappings& bound_tts, const ::std::vector& contents) { diff --git a/src/macro_rules/macro_rules.hpp b/src/macro_rules/macro_rules.hpp index 29c4f93d..02b302d8 100644 --- a/src/macro_rules/macro_rules.hpp +++ b/src/macro_rules/macro_rules.hpp @@ -18,6 +18,7 @@ #include class MacroExpander; +class SimplePatEnt; TAGGED_UNION(MacroExpansionEnt, Token, // TODO: have a "raw" stream instead of just tokens @@ -42,6 +43,7 @@ struct MacroPatEnt { ::std::string name; unsigned int name_index = 0; + // TODO: Include a point span for the token? Token tok; ::std::vector subpats; @@ -95,6 +97,39 @@ struct MacroPatEnt friend ::std::ostream& operator<<(::std::ostream& os, const MacroPatEnt::Type& x); }; +struct SimplePatIfCheck +{ + MacroPatEnt::Type ty; // If PAT_TOKEN, token is checked + Token tok; +}; + +/// Simple pattern entry for macro_rules! arm patterns +TAGGED_UNION( SimplePatEnt, End, + // End of the pattern stream (expects EOF, and terminates the match process) + (End, struct{}), + (LoopStart, struct{}), + (LoopNext, struct{}), + (LoopEnd, struct{}), + (Jump, struct { + size_t jump_target; + }), + // Expect a specific token, erroring/failing the arm if nt met + (ExpectTok, Token), + // Expect a pattern match + (ExpectPat, struct { + MacroPatEnt::Type type; + unsigned int idx; + }), + // Compare the head of the input stream and poke the pattern stream + (If, struct { + bool is_equal; + size_t jump_target; + ::std::vector ents; + }) + ); + +extern::std::ostream& operator<<(::std::ostream& os, const SimplePatEnt& x); + /// An expansion arm within a macro_rules! blcok struct MacroRulesArm { @@ -102,14 +137,15 @@ struct MacroRulesArm ::std::vector< ::std::string> m_param_names; /// Patterns - ::std::vector m_pattern; + ::std::vector m_pattern; /// Rule contents ::std::vector m_contents; + ~MacroRulesArm(); MacroRulesArm() {} - MacroRulesArm(::std::vector pattern, ::std::vector contents): + MacroRulesArm(::std::vector pattern, ::std::vector contents): m_pattern( mv$(pattern) ), m_contents( mv$(contents) ) {} diff --git a/src/macro_rules/mod.cpp b/src/macro_rules/mod.cpp index 04f1577a..e9ecb504 100644 --- a/src/macro_rules/mod.cpp +++ b/src/macro_rules/mod.cpp @@ -182,7 +182,7 @@ MacroRulesPtr::~MacroRulesPtr() switch(x.type) { case MacroPatEnt::PAT_TOKEN: os << "=" << x.tok; break; - case MacroPatEnt::PAT_LOOP: os << "loop w/ " << x.tok << " [" << x.subpats << "]"; break; + case MacroPatEnt::PAT_LOOP: os << "loop" << x.name << " w/ " << x.tok << " [" << x.subpats << "]"; break; default: os << "$" << x.name << ":"; switch(x.type) @@ -228,6 +228,37 @@ MacroRulesPtr::~MacroRulesPtr() return os; } +::std::ostream& operator<<(::std::ostream& os, const SimplePatEnt& x) +{ + TU_MATCH_HDRA( (x), { ) + TU_ARMA(End, _e) os << "End"; + TU_ARMA(LoopStart, _e) os << "LoopStart"; + TU_ARMA(LoopNext, _e) os << "LoopNext"; + TU_ARMA(LoopEnd, _e) os << "LoopEnd"; + TU_ARMA(Jump, e) { + os << "Jump(->" << e.jump_target << ")"; + } + TU_ARMA(ExpectTok, e) { + os << "Expect(" << e << ")"; + } + TU_ARMA(ExpectPat, e) { + os << "Expect($" << e.idx << " = " << e.type << ")"; + } + TU_ARMA(If, e) { + os << "If(" << (e.is_equal ? "=" : "!=") << "["; + for(const auto& p : e.ents) { + if(p.ty == MacroPatEnt::PAT_TOKEN) + os << p.tok; + else + os << p.ty; + os << ", "; + } + os << "] ->" << e.jump_target << ")"; + } + } + return os; +} + ::std::ostream& operator<<(::std::ostream& os, const MacroExpansionEnt& x) { TU_MATCH( MacroExpansionEnt, (x), (e), @@ -252,4 +283,7 @@ MacroRulesPtr::~MacroRulesPtr() MacroRules::~MacroRules() { } +MacroRulesArm::~MacroRulesArm() +{ +} diff --git a/src/macro_rules/parse.cpp b/src/macro_rules/parse.cpp index 8af9bd07..689a81f1 100644 --- a/src/macro_rules/parse.cpp +++ b/src/macro_rules/parse.cpp @@ -12,13 +12,21 @@ #include "pattern_checks.hpp" MacroRulesPtr Parse_MacroRules(TokenStream& lex); +namespace { + ::std::vector macro_pattern_to_simple(const Span& sp, const ::std::vector& pattern); +} /// A rule within a macro_rules! blcok class MacroRule { public: ::std::vector m_pattern; + Span m_pat_span; ::std::vector m_contents; + + MacroRule() {} + MacroRule(MacroRule&&) = default; + MacroRule(const MacroRule&) = delete; }; /// Parse the pattern of a macro_rules! arm @@ -261,7 +269,11 @@ MacroRule Parse_MacroRules_Var(TokenStream& lex) } // - Pattern entries ::std::vector< ::std::string> names; - rule.m_pattern = Parse_MacroRules_Pat(lex, tok.type(), close, names); + { + auto ps = lex.start_span(); + rule.m_pattern = Parse_MacroRules_Pat(lex, tok.type(), close, names); + rule.m_pat_span = lex.end_span(ps); + } GET_CHECK_TOK(tok, lex, TOK_FATARROW); @@ -280,189 +292,9 @@ MacroRule Parse_MacroRules_Var(TokenStream& lex) return rule; } -bool patterns_are_same(const Span& sp, const MacroPatEnt& left, const MacroPatEnt& right) -{ - if( left.type > right.type ) - return patterns_are_same(sp, right, left); - - //if( left.name != right.name ) { - // TODO(sp, "Handle different binding names " << left << " != " << right); - //} - - // NOTE: left.type <= right.type - switch(right.type) - { - case MacroPatEnt::PAT_TOKEN: - assert( left.type == MacroPatEnt::PAT_TOKEN ); - return right.tok == left.tok; - case MacroPatEnt::PAT_LOOP: - switch(left.type) - { - case MacroPatEnt::PAT_TOKEN: - // - Check for compatibility, but these two don't match - if( patterns_are_same(sp, left, right.subpats.at(0)) == true ) - ERROR(sp, E0000, "Incompatible use of loop with matching non-loop"); - return false; - case MacroPatEnt::PAT_LOOP: - TODO(sp, "patterns_are_same - PAT_LOOP"); - default: - assert( !"" ); - } - - case MacroPatEnt::PAT_TT: - if( left.type == right.type ) - return true; - ERROR(sp, E0000, "Incompatible macro fragments - " << right << " used with " << left); - break; - - case MacroPatEnt::PAT_PAT: - switch(left.type) - { - case MacroPatEnt::PAT_TOKEN: - // - If this token is a valid pattern token, error - if( is_token_pat(left.tok.type()) ) - ERROR(sp, E0000, "Incompatible macro fragments - " << right << " used with " << left); - return false; - case MacroPatEnt::PAT_PAT: - return true; - default: - ERROR(sp, E0000, "Incompatible macro fragments - " << right << " used with " << left); - } - break; - // `:ident` - Compatible with just other tokens - case MacroPatEnt::PAT_IDENT: - switch(left.type) - { - case MacroPatEnt::PAT_TOKEN: - if( left.tok.type() == TOK_IDENT ) - ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left); - return false; - case MacroPatEnt::PAT_IDENT: - return true; - default: - ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left); - } - case MacroPatEnt::PAT_PATH: - switch(left.type) - { - case MacroPatEnt::PAT_TOKEN: - if( is_token_path(left.tok.type()) ) - ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left); - return false; - case MacroPatEnt::PAT_PATH: - return true; - default: - ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left); - } - case MacroPatEnt::PAT_TYPE: - switch(left.type) - { - case MacroPatEnt::PAT_TOKEN: - if( is_token_type(left.tok.type()) ) - ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left); - return false; - case MacroPatEnt::PAT_TYPE: - return true; - default: - ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left); - } - case MacroPatEnt::PAT_EXPR: - switch(left.type) - { - case MacroPatEnt::PAT_TOKEN: - if( is_token_expr(left.tok.type()) ) - ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left); - return false; - // TODO: Allow a loop starting with an expr? - // - Consume, add split based on loop condition or next arm - // - Possible problem with binding levels. - case MacroPatEnt::PAT_EXPR: - return true; - default: - ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left); - } - case MacroPatEnt::PAT_STMT: - switch(left.type) - { - case MacroPatEnt::PAT_TOKEN: - if( is_token_stmt(left.tok.type()) ) - ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left); - return false; - case MacroPatEnt::PAT_STMT: - return true; - default: - ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left); - } - // Block - Expects '{' - Compatible with everything but a literal '{' - case MacroPatEnt::PAT_BLOCK: - switch(left.type) - { - case MacroPatEnt::PAT_TOKEN: - if( left.tok.type() == TOK_BRACE_OPEN ) - ERROR(sp, E0000, "Incompatible macro fragments"); - return false; - case MacroPatEnt::PAT_BLOCK: - return true; - default: - return false; - } - // Matches meta/attribute fragments. - case MacroPatEnt::PAT_META: - switch(left.type) - { - case MacroPatEnt::PAT_TOKEN: - if( left.tok.type() == TOK_IDENT ) - ERROR(sp, E0000, "Incompatible macro fragments"); - return false; - case MacroPatEnt::PAT_META: - return true; - default: - ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left); - } - // Matches items - case MacroPatEnt::PAT_ITEM: - switch(left.type) - { - case MacroPatEnt::PAT_TOKEN: - if( is_token_item(left.tok.type()) ) - ERROR(sp, E0000, "Incompatible macro fragments"); - return false; - case MacroPatEnt::PAT_ITEM: - return true; - default: - ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left); - } - // Matches visibility specifiers - case MacroPatEnt::PAT_VIS: - switch(left.type) - { - case MacroPatEnt::PAT_TOKEN: - if( is_token_vis(left.tok.type()) ) - ERROR(sp, E0000, "Incompatible macro fragments"); - return false; - case MacroPatEnt::PAT_VIS: - return true; - default: - ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left); - } - case MacroPatEnt::PAT_LIFETIME: - switch(left.type) - { - case MacroPatEnt::PAT_TOKEN: - if( left.tok.type() == TOK_LIFETIME ) - ERROR(sp, E0000, "Incompatible macro fragments"); - return false; - case MacroPatEnt::PAT_LIFETIME: - return true; - default: - ERROR(sp, E0000, "Incompatible macro fragments " << right << " used with " << left); - } - } - throw ""; -} - // TODO: Also count the number of times each variable is used? -void enumerate_names(const ::std::vector& pats, ::std::vector< ::std::string>& names) { +void enumerate_names(const ::std::vector& pats, ::std::vector< ::std::string>& names) +{ for( const auto& pat : pats ) { if( pat.type == MacroPatEnt::PAT_LOOP ) { @@ -504,9 +336,11 @@ MacroRulesPtr Parse_MacroRules(TokenStream& lex) // Re-parse the patterns into a unified form for(auto& rule : rules) { - MacroRulesArm arm = MacroRulesArm( mv$(rule.m_pattern), mv$(rule.m_contents) ); + // TODO: Transform the pattern into a DFA or similar here (seekable instruction stream?) - enumerate_names(arm.m_pattern, arm.m_param_names); + auto rule_sequence = macro_pattern_to_simple(rule.m_pat_span, rule.m_pattern); + MacroRulesArm arm = MacroRulesArm( mv$(rule_sequence), mv$(rule.m_contents) ); + enumerate_names(rule.m_pattern, arm.m_param_names); rule_arms.push_back( mv$(arm) ); } @@ -517,3 +351,251 @@ MacroRulesPtr Parse_MacroRules(TokenStream& lex) return MacroRulesPtr(rv); } + +namespace { + + struct ExpTok { + MacroPatEnt::Type ty; + const Token* tok; + ExpTok(MacroPatEnt::Type ty, const Token* tok): ty(ty), tok(tok) {} + bool operator==(const ExpTok& t) const { return this->ty == t.ty && *this->tok == *t.tok; } + }; + ::std::ostream& operator<<(::std::ostream& os, const ExpTok& t) { + os << "ExpTok(" << t.ty << " " << *t.tok << ")"; + return os; + } + + // Yields all possible ExpectTok/ExpectPat entries from a pattern position + // Returns `true` if there's no fall-through + bool macro_pattern_get_head_set_inner(::std::vector& rv, const ::std::vector& pattern, size_t direct_pos, size_t indirect_ofs) + { + for(size_t idx = direct_pos; idx < pattern.size(); idx ++) + { + const auto& ent = pattern[idx]; + switch(ent.type) + { + case MacroPatEnt::PAT_LOOP: + if( macro_pattern_get_head_set_inner(rv, ent.subpats, 0, indirect_ofs) ) + { + // + loops have to iterate at least once, so if the set is closed by the sub-patterns, close us too + if(ent.name == "+") + { + return true; + } + // for * and ? loops, they can be skipped entirely. + // - No separator, this is for the skip case + } + else + { + // If the inner pattern didn't close the option set, then the next token can be the separator + if( ent.tok != TOK_NULL ) + { + // If indirect is non-zero, decrement without doing anything + if( indirect_ofs > 0 ) + { + indirect_ofs --; + } + else + { + rv.push_back(ExpTok(MacroPatEnt::PAT_TOKEN, &ent.tok)); + } + } + } + break; + default: + // If indirect is non-zero, decrement + if( indirect_ofs > 0 ) + { + indirect_ofs --; + } + else + { + rv.push_back( ExpTok(ent.type, &ent.tok) ); + return true; + } + break; + } + } + return false; + } + ::std::vector macro_pattern_get_head_set(const ::std::vector& pattern, size_t direct_pos, size_t indirect_ofs) + { + ::std::vector rv; + macro_pattern_get_head_set_inner(rv, pattern, direct_pos, indirect_ofs); + return rv; + } + + void macro_pattern_to_simple_inner(const Span& sp, ::std::vector& rv, const ::std::vector& pattern) + { + size_t level_start = rv.size(); + TRACE_FUNCTION_FR("[" << pattern << "]", "[" << FMT_CB(ss, for(auto it = rv.begin()+level_start; it != rv.end(); ++it) { ss << *it << ", "; }) << "]"); + auto push = [&rv](SimplePatEnt spe) { + DEBUG("[macro_pattern_to_simple_inner] rv[" << rv.size() << "] = " << spe); + rv.push_back( ::std::move(spe) ); + }; + auto push_ifv = [&push](bool is_equal, ::std::vector ents, size_t tgt) { + push(SimplePatEnt::make_If({ is_equal, tgt, mv$(ents) })); + }; + auto push_if = [&push_ifv](bool is_equal, MacroPatEnt::Type ty, const Token& tok, size_t tgt) { + push_ifv(is_equal, make_vec1(SimplePatIfCheck { ty, tok }), tgt); + }; + for(size_t idx = 0; idx < pattern.size(); idx ++) + { + const auto& ent = pattern[idx]; + DEBUG("[" << idx << "] ent = " << ent); + switch(ent.type) + { + case MacroPatEnt::PAT_LOOP: { + auto entry_pats = macro_pattern_get_head_set(ent.subpats, 0, 0); + DEBUG("Entry = [" << entry_pats << "]"); + ASSERT_BUG(sp, entry_pats.size() > 0, "No entry conditions extracted from sub-pattern [" << ent.subpats << "]"); + auto skip_pats = macro_pattern_get_head_set(pattern, idx+1, 0); + DEBUG("Skip = [" << skip_pats << "]"); + + // - Duplicates need special handling (build up a subseqent set) + for(const auto& ee : entry_pats) + { + if( ::std::find(skip_pats.begin(), skip_pats.end(), ee) != skip_pats.end() ) + { + TODO(sp, "Entry and skip patterns share an entry, ambigious - " << ee); + } + } + + // TODO: Combine the two cases below into one + + // If the loop is a $()+ loop, then just recurse into it + if( ent.name == "+" ) + { + push( SimplePatEnt::make_LoopStart({}) ); + size_t start = rv.size(); + macro_pattern_to_simple_inner(sp, rv, ent.subpats); + push( SimplePatEnt::make_LoopNext({}) ); + if( ent.tok != TOK_NULL ) + { + size_t end = rv.size() + 3; + if( ::std::find(skip_pats.begin(), skip_pats.end(), ExpTok(MacroPatEnt::PAT_TOKEN, &ent.tok)) != skip_pats.end() ) { + for(const auto& p : entry_pats) + { + auto v = ::make_vec2( + { MacroPatEnt::PAT_TOKEN, ent.tok}, + { p.ty, *p.tok } + ); + push_ifv(false, mv$(v), ~0u); + } + } + else { + push_if( false, MacroPatEnt::PAT_TOKEN, ent.tok, end ); + } + push( SimplePatEnt::make_ExpectTok(ent.tok) ); + push( SimplePatEnt::make_Jump({ start }) ); + } + else + { + // TODO: What if there's a collision at this level? + for(const auto& p : entry_pats) + { + push_if(true, p.ty, *p.tok, start); + } + } + push( SimplePatEnt::make_LoopEnd({}) ); + } + else + { + push( SimplePatEnt::make_LoopStart({}) ); + + // Options: + // - Enter the loop (if the next token is one of the head set of the loop) + // - Skip the loop (the next token is the head set of the subsequent entries) + size_t rewrite_start = rv.size(); + if( ent.name != "+" ) + { + if( entry_pats.size() == 1 ) + { + // If not the entry pattern, skip. + push_if(false, entry_pats.front().ty, *entry_pats.front().tok, ~0u); + } + else if( skip_pats.empty() ) + { + // No skip patterns, try all entry patterns + size_t start = rv.size() + entry_pats.size() + 1; + for(const auto& p : entry_pats) + { + push_if(true, p.ty, *p.tok, start); + } + push(SimplePatEnt::make_Jump({ ~0u })); + } + else + { + for(const auto& p : skip_pats) + { + push_if(true, p.ty, *p.tok, ~0u); + } + } + } + + macro_pattern_to_simple_inner(sp, rv, ent.subpats); + push( SimplePatEnt::make_LoopNext({}) ); + + if( ent.name != "?" ) + { + if( ent.tok != TOK_NULL ) + { + // If the joiner is also valid after the loop, handle by also checking the entry conditions + if( ::std::find(skip_pats.begin(), skip_pats.end(), ExpTok(MacroPatEnt::PAT_TOKEN, &ent.tok)) != skip_pats.end() ) { + // Try all re-loop (joiner + entry) patterns, if any fail then jump to the end. + for(const auto& p : entry_pats) { + auto v = ::make_vec2( + { MacroPatEnt::PAT_TOKEN, ent.tok}, + { p.ty, *p.tok } + ); + push_ifv(false, mv$(v), ~0u); + } + } + else { + // If not the joiner, jump to the end + push_if(false, MacroPatEnt::PAT_TOKEN, ent.tok, ~0u); + } + push( SimplePatEnt::make_ExpectTok(ent.tok) ); + } + // Jump back to the entry check. + push(SimplePatEnt::make_Jump({ rewrite_start })); + } + else + { + ASSERT_BUG(sp, ent.tok == TOK_NULL, "$()? with a separator isn't valid"); + } + size_t post_loop = rv.size(); + for(size_t i = rewrite_start; i < post_loop; i++) + { + if( auto* pe = rv[i].opt_If() ) { + if(pe->jump_target == ~0u) { + pe->jump_target = post_loop; + } + } + if( auto* pe = rv[i].opt_Jump() ) { + if(pe->jump_target == ~0u) { + pe->jump_target = post_loop; + } + } + } + push( SimplePatEnt::make_LoopEnd({}) ); + } + } break; + case MacroPatEnt::PAT_TOKEN: + push( SimplePatEnt::make_ExpectTok(ent.tok) ); + break; + default: + push( SimplePatEnt::make_ExpectPat({ ent.type, ent.name_index }) ); + break; + } + } + } + + ::std::vector macro_pattern_to_simple(const Span& sp, const ::std::vector& pattern) + { + ::std::vector rv; + TRACE_FUNCTION_FR(pattern, rv); + macro_pattern_to_simple_inner(sp, rv, pattern); + return rv; + } +} -- cgit v1.2.3 From dd4114b9e985f2fea0cf0f73ed765484d3df2f47 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 27 Jan 2019 11:07:20 +0800 Subject: AST - (minor) Tweak printing of lifetime params --- src/ast/path.cpp | 2 +- src/ast/types.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ast/path.cpp b/src/ast/path.cpp index 0c8c4c69..092f5962 100644 --- a/src/ast/path.cpp +++ b/src/ast/path.cpp @@ -109,7 +109,7 @@ PathBinding_Macro PathBinding_Macro::clone() const for(const auto& v : x.m_lifetimes) { if(needs_comma) os << ", "; needs_comma = true; - os << "'" << v; + os << v; } for(const auto& v : x.m_types) { if(needs_comma) os << ", "; diff --git a/src/ast/types.cpp b/src/ast/types.cpp index 98bc6ee1..f9103b37 100644 --- a/src/ast/types.cpp +++ b/src/ast/types.cpp @@ -323,7 +323,7 @@ namespace AST { os << "'_"; } else { - os << "'" << x.m_name; + os << "'" << x.m_name.name; if( x.m_binding != LifetimeRef::BINDING_UNBOUND ) { os << "/*" << x.m_binding << "*/"; } -- cgit v1.2.3 From d47282806d50359851a92bf72fdf5253574d2e17 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 27 Jan 2019 11:08:31 +0800 Subject: Expand - Slight tweaks to avoid crashes/bugs --- src/expand/format_args.cpp | 2 +- src/expand/mod.cpp | 79 ++++++++++++++++++++++++---------------------- src/expand/stringify.cpp | 3 ++ 3 files changed, 46 insertions(+), 38 deletions(-) diff --git a/src/expand/format_args.cpp b/src/expand/format_args.cpp index fe2bdfb4..e2ee35d3 100644 --- a/src/expand/format_args.cpp +++ b/src/expand/format_args.cpp @@ -183,7 +183,7 @@ namespace { s ++; } while(isdigit(*s)); if( arg_idx >= n_free ) - ERROR(sp, E0000, "Positional argument " << arg_idx << " out of range"); + ERROR(sp, E0000, "Positional argument " << arg_idx << " out of range in \"" << format_string << "\""); index = arg_idx; } else { diff --git a/src/expand/mod.cpp b/src/expand/mod.cpp index e4764be1..751b14eb 100644 --- a/src/expand/mod.cpp +++ b/src/expand/mod.cpp @@ -1068,11 +1068,11 @@ void Expand_Mod(::AST::Crate& crate, LList modstack, ::AST:: auto dat = mv$(i.data); - TU_MATCH(::AST::Item, (dat), (e), - (None, - // Skip, nothing - ), - (MacroInv, + TU_MATCH_HDRA( (dat), {) + TU_ARMA(None, e) { + // Skip: nothing + } + TU_ARMA(MacroInv, e) { // Move out of the module to avoid invalidation if a new macro invocation is added auto mi_owned = mv$(e); @@ -1089,11 +1089,11 @@ void Expand_Mod(::AST::Crate& crate, LList modstack, ::AST:: Parse_ModRoot_Items(*ttl, mod); } dat.as_MacroInv() = mv$(mi_owned); - ), - (Use, + } + TU_ARMA(Use, e) { // No inner expand. - ), - (ExternBlock, + } + TU_ARMA(ExternBlock, e) { // TODO: Run expand on inner items? // HACK: Just convert inner items into outer items auto items = mv$( e.items() ); @@ -1101,32 +1101,32 @@ void Expand_Mod(::AST::Crate& crate, LList modstack, ::AST:: { mod.items().push_back( mv$(i2) ); } - ), - (Impl, + } + TU_ARMA(Impl, e) { Expand_Impl(crate, modstack, modpath, mod, e); if( e.def().type().is_wildcard() ) { dat = AST::Item(); } - ), - (NegImpl, + } + TU_ARMA(NegImpl, e) { Expand_ImplDef(crate, modstack, modpath, mod, e); if( e.type().is_wildcard() ) { dat = AST::Item(); } - ), - (Module, + } + TU_ARMA(Module, e) { LList sub_modstack(&modstack, &e); Expand_Mod(crate, sub_modstack, path, e); - ), - (Crate, + } + TU_ARMA(Crate, e) { // Can't recurse into an `extern crate` if(crate.m_extern_crates.count(e.name) == 0) { e.name = crate.load_extern_crate( i.data.span, e.name ); } - ), + } - (Struct, + TU_ARMA(Struct, e) { Expand_GenericParams(crate, modstack, mod, e.params()); TU_MATCH(AST::StructData, (e.m_data), (sd), (Unit, @@ -1158,8 +1158,8 @@ void Expand_Mod(::AST::Crate& crate, LList modstack, ::AST:: } ) ) - ), - (Enum, + } + TU_ARMA(Enum, e) { Expand_GenericParams(crate, modstack, mod, e.params()); for(auto& var : e.variants()) { Expand_Attrs(var.m_attrs, AttrStage::Pre, [&](const auto& sp, const auto& d, const auto& a){ d.handle(sp, a, crate, var); }); @@ -1197,10 +1197,11 @@ void Expand_Mod(::AST::Crate& crate, LList modstack, ::AST:: ++ it; } } - ), - (Union, + } + TU_ARMA(Union, e) { Expand_GenericParams(crate, modstack, mod, e.m_params); - for(auto it = e.m_variants.begin(); it != e.m_variants.end(); ) { + for(auto it = e.m_variants.begin(); it != e.m_variants.end(); ) + { auto& si = *it; Expand_Attrs(si.m_attrs, AttrStage::Pre, [&](const auto& sp, const auto& d, const auto& a){ d.handle(sp, a, crate, si); }); Expand_Type(crate, modstack, mod, si.m_type); @@ -1211,8 +1212,8 @@ void Expand_Mod(::AST::Crate& crate, LList modstack, ::AST:: else ++it; } - ), - (Trait, + } + TU_ARMA(Trait, e) { Expand_GenericParams(crate, modstack, mod, e.params()); auto& trait_items = e.items(); for(size_t idx = 0; idx < trait_items.size(); idx ++) @@ -1270,16 +1271,20 @@ void Expand_Mod(::AST::Crate& crate, LList modstack, ::AST:: ) ) - Expand_Attrs(attrs, AttrStage::Post, crate, AST::Path(), mod, ti.data); - if( ti.data.attrs.m_items.size() == 0 ) - ti.data.attrs = mv$(attrs); + { + auto& ti = trait_items[idx]; + + Expand_Attrs(attrs, AttrStage::Post, crate, AST::Path(), mod, ti.data); + if( ti.data.attrs.m_items.size() == 0 ) + ti.data.attrs = mv$(attrs); + } } - ), - (Type, + } + TU_ARMA(Type, e) { Expand_Type(crate, modstack, mod, e.type()); - ), + } - (Function, + TU_ARMA(Function, e) { Expand_GenericParams(crate, modstack, mod, e.params()); for(auto& arg : e.args()) { Expand_Pattern(crate, modstack, mod, arg.first, false); @@ -1287,12 +1292,12 @@ void Expand_Mod(::AST::Crate& crate, LList modstack, ::AST:: } Expand_Type(crate, modstack, mod, e.rettype()); Expand_Expr(crate, modstack, e.code()); - ), - (Static, + } + TU_ARMA(Static, e) { Expand_Expr(crate, modstack, e.value()); Expand_Type(crate, modstack, mod, e.type()); - ) - ) + } + } Expand_Attrs(attrs, AttrStage::Post, crate, path, mod, dat); { diff --git a/src/expand/stringify.cpp b/src/expand/stringify.cpp index b85c23c6..f552ffd4 100644 --- a/src/expand/stringify.cpp +++ b/src/expand/stringify.cpp @@ -26,6 +26,9 @@ class CExpander: rv += tok.to_str(); } + // TODO: Strip out any `{...}` sequences that aren't from nested + // strings. + return box$( TTStreamO(sp, TokenTree(Token(TOK_STRING, mv$(rv)))) ); } }; -- cgit v1.2.3 From 098e210150f071d5cb7d8761f79dd3e8046bc829 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 27 Jan 2019 11:08:55 +0800 Subject: Parse - A few more TOK_INTERPOLATED_* instances --- src/parse/expr.cpp | 7 ++++++- src/parse/root.cpp | 9 +++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/parse/expr.cpp b/src/parse/expr.cpp index 5e38ca81..6e18f0eb 100644 --- a/src/parse/expr.cpp +++ b/src/parse/expr.cpp @@ -57,13 +57,18 @@ ExprNodeP Parse_ExprBlockNode(TokenStream& lex, bool is_unsafe/*=false*/) ::std::shared_ptr local_mod; + if( LOOK_AHEAD(lex) == TOK_INTERPOLATED_BLOCK ) + { + GET_TOK(tok, lex); + return tok.take_frag_node(); + } + GET_CHECK_TOK(tok, lex, TOK_BRACE_OPEN); bool last_value_yielded = false; while( LOOK_AHEAD(lex) != TOK_BRACE_CLOSE ) { last_value_yielded = false; - DEBUG("tok = " << tok); // NOTE: Doc comments can appear within a function and apply to the function if( lex.parse_state().parent_attrs ) diff --git a/src/parse/root.cpp b/src/parse/root.cpp index a58e05d5..d79df434 100644 --- a/src/parse/root.cpp +++ b/src/parse/root.cpp @@ -1499,14 +1499,19 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv) { // Good } + else if( lex.lookahead(0) == TOK_INTERPOLATED_PATH && lex.lookahead(1) == TOK_EXCLAM ) + { + // Also good. + } else { return false; } auto ps = lex.start_span(); - GET_CHECK_TOK(tok, lex, TOK_IDENT); - auto name = tok.str(); + auto name_path = Parse_Path(lex, PATH_GENERIC_NONE); + ASSERT_BUG(lex.point_span(), name_path.nodes().size() == 1, "TODO: Support multi-component paths in macro invocations"); + auto name = name_path.nodes()[0].name(); GET_CHECK_TOK(tok, lex, TOK_EXCLAM); bool is_braced = (lex.lookahead(0) == TOK_BRACE_OPEN || (lex.lookahead(0) == TOK_IDENT && lex.lookahead(1) == TOK_BRACE_OPEN)); -- cgit v1.2.3 From 28b71bb7098339085a85d6e4eb4813b4eee4b73d Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 27 Jan 2019 11:33:20 +0800 Subject: Minicargo - Tweaks for building cargo --- tools/minicargo/cfg.cpp | 7 +++++++ tools/minicargo/manifest.cpp | 17 +++++++++++++++-- tools/minicargo/manifest.h | 12 +++++++++++- 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/tools/minicargo/cfg.cpp b/tools/minicargo/cfg.cpp index e8c732d8..85bff327 100644 --- a/tools/minicargo/cfg.cpp +++ b/tools/minicargo/cfg.cpp @@ -215,6 +215,13 @@ bool CfgChecker::check_cfg(CfgParseLexer& p) const rv &= check_cfg(p); } while(p.consume_if(',')); } + else if( name == "any" ) { + rv = false; + do + { + rv |= check_cfg(p); + } while(p.consume_if(',')); + } else { TODO("Unknown fragment in cfg - " << name.to_string()); } diff --git a/tools/minicargo/manifest.cpp b/tools/minicargo/manifest.cpp index 79db0e35..8f49c538 100644 --- a/tools/minicargo/manifest.cpp +++ b/tools/minicargo/manifest.cpp @@ -865,6 +865,10 @@ PackageVersionSpec PackageVersionSpec::from_string(const ::std::string& s) // Default, compatible pos ++; break; + case '~': + ty = PackageVersionSpec::Bound::Type::MinorCompatible; + pos ++; + break; case '=': ty = PackageVersionSpec::Bound::Type::Equal; pos ++; @@ -921,6 +925,9 @@ PackageVersionSpec PackageVersionSpec::from_string(const ::std::string& s) } else { + // NOTE: This changes the behaviour of ~ rules to be bounded on the major version instead + if( ty == PackageVersionSpec::Bound::Type::MinorCompatible ) + ty = PackageVersionSpec::Bound::Type::Compatible; v.minor = 0; v.patch = 0; } @@ -943,13 +950,19 @@ bool PackageVersionSpec::accepts(const PackageVersion& v) const switch(b.ty) { case Bound::Type::Compatible: - // To be compatible, it has to be higher? - // - TODO: Isn't a patch version compatible? + // ^ rules are >= specified, and < next major/breaking if( !(v >= b.ver) ) return false; if( !(v < b.ver.next_breaking()) ) return false; break; + case Bound::Type::MinorCompatible: + // ~ rules are >= specified, and < next minor + if( !(v >= b.ver) ) + return false; + if( !(v < b.ver.next_minor()) ) + return false; + break; case Bound::Type::GreaterEqual: if( !(v >= b.ver) ) return false; diff --git a/tools/minicargo/manifest.h b/tools/minicargo/manifest.h index 4bb8b843..be19a7b1 100644 --- a/tools/minicargo/manifest.h +++ b/tools/minicargo/manifest.h @@ -26,6 +26,14 @@ struct PackageVersion static PackageVersion from_string(const ::std::string& s); + PackageVersion next_minor() const { + if(major == 0) { + return PackageVersion { 0, minor, patch+1 }; + } + else { + return PackageVersion { major, minor+1, 0 }; + } + } PackageVersion next_breaking() const { if(major == 0) { return PackageVersion { 0, minor + 1, 0 }; @@ -87,7 +95,8 @@ struct PackageVersionSpec { enum class Type { - Compatible, + Compatible, // "^" - Allows anything up to the next major version + MinorCompatible, // "~X.Y" - Allows anything up to the next minor version Greater, GreaterEqual, Equal, @@ -116,6 +125,7 @@ struct PackageVersionSpec switch(b.ty) { case Bound::Type::Compatible: os << "^"; break; + case Bound::Type::MinorCompatible: os << "~"; break; case Bound::Type::Greater: os << ">"; break; case Bound::Type::GreaterEqual: os << ">="; break; case Bound::Type::Equal: os << "="; break; -- cgit v1.2.3 From 2fc8e093a36a8b39d4937b1f863fe1d471350fdd Mon Sep 17 00:00:00 2001 From: John Hodge Date: Mon, 28 Jan 2019 15:39:24 +0800 Subject: Resolve Use - More correct handling of publicity in wildcard imports --- src/ast/path.cpp | 22 ++++++++++++++++++++++ src/ast/path.hpp | 2 +- src/resolve/use.cpp | 38 ++++++++++++++++++++++++-------------- 3 files changed, 47 insertions(+), 15 deletions(-) diff --git a/src/ast/path.cpp b/src/ast/path.cpp index 092f5962..d156f465 100644 --- a/src/ast/path.cpp +++ b/src/ast/path.cpp @@ -230,6 +230,28 @@ AST::Path::Path(const Path& x): ) } +bool Path::is_parent_of(const Path& x) const +{ + if( !this->m_class.is_Absolute() || !x.m_class.is_Absolute() ) + return false; + const auto& te = this->m_class.as_Absolute(); + const auto& xe = x.m_class.as_Absolute(); + + if( te.crate != xe.crate ) + return false; + + if( te.nodes.size() > xe.nodes.size() ) + return false; + + for(size_t i = 0; i < te.nodes.size(); i ++) + { + if( te.nodes[i].name() != xe.nodes[i].name() ) + return false; + } + + return true; +} + void Path::bind_variable(unsigned int slot) { m_bindings.value = PathBinding_Value::make_Variable({slot}); diff --git a/src/ast/path.hpp b/src/ast/path.hpp index 18ebea49..faa1ffe6 100644 --- a/src/ast/path.hpp +++ b/src/ast/path.hpp @@ -372,7 +372,7 @@ public: } //const ::std::string& crate() const { return m_crate; } - bool is_concrete() const; + bool is_parent_of(const Path& x) const; void bind_variable(unsigned int slot); diff --git a/src/resolve/use.cpp b/src/resolve/use.cpp index c4fb659f..8c9266a2 100644 --- a/src/resolve/use.cpp +++ b/src/resolve/use.cpp @@ -22,7 +22,7 @@ enum class Lookup ::AST::Path Resolve_Use_AbsolutisePath(const ::AST::Path& base_path, ::AST::Path path); void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path path, ::std::span< const ::AST::Module* > parent_modules={}); -::AST::Path::Bindings Resolve_Use_GetBinding(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path, ::std::span< const ::AST::Module* > parent_modules); +::AST::Path::Bindings Resolve_Use_GetBinding(const Span& span, const ::AST::Crate& crate, const ::AST::Path& source_mod_path, const ::AST::Path& path, ::std::span< const ::AST::Module* > parent_modules); ::AST::Path::Bindings Resolve_Use_GetBinding__ext(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path, const ::HIR::Module& hmodr, unsigned int start); @@ -124,7 +124,7 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path // - values ("value namespace") // - macros ("macro namespace") // TODO: Have Resolve_Use_GetBinding return the actual path - use_ent.path.m_bindings = Resolve_Use_GetBinding(span, crate, use_ent.path, parent_modules); + use_ent.path.m_bindings = Resolve_Use_GetBinding(span, crate, path, use_ent.path, parent_modules); if( !use_ent.path.m_bindings.has_binding() ) { ERROR(span, E0000, "Unable to resolve `use` target " << use_ent.path); @@ -251,7 +251,7 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path ::AST::Path::Bindings Resolve_Use_GetBinding_Mod( const Span& span, - const ::AST::Crate& crate, const ::AST::Module& mod, + const ::AST::Crate& crate, const ::AST::Path& source_mod_path, const ::AST::Module& mod, const ::std::string& des_item_name, ::std::span< const ::AST::Module* > parent_modules ) @@ -356,7 +356,7 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path if( ::std::find(s_mods.begin(), s_mods.end(), &imp_e.path) == s_mods.end() ) { s_mods.push_back(&imp_e.path); - rv.merge_from( Resolve_Use_GetBinding(sp2, crate, Resolve_Use_AbsolutisePath(sp2, mod.path(), imp_e.path), parent_modules) ); + rv.merge_from( Resolve_Use_GetBinding(sp2, crate, mod.path(), Resolve_Use_AbsolutisePath(sp2, mod.path(), imp_e.path), parent_modules) ); s_mods.pop_back(); } else @@ -371,9 +371,10 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path continue ; } - if( imp.is_pub && imp_e.name == "" ) + // TODO: Correct privacy rules (if the origin of this lookup can see this item) + if( (imp.is_pub || mod.path().is_parent_of(source_mod_path)) && imp_e.name == "" ) { - DEBUG("- Search glob of " << imp_e.path); + DEBUG("- Search glob of " << imp_e.path << " in " << mod.path()); // INEFFICIENT! Resolves and throws away the result (because we can't/shouldn't mutate here) ::AST::Path::Bindings bindings_; const auto* bindings = &imp_e.path.m_bindings; @@ -384,7 +385,7 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path if( ::std::find(resolve_stack_ptrs.begin(), resolve_stack_ptrs.end(), &imp_data) == resolve_stack_ptrs.end() ) { resolve_stack_ptrs.push_back( &imp_data ); - bindings_ = Resolve_Use_GetBinding(sp2, crate, Resolve_Use_AbsolutisePath(sp2, mod.path(), imp_e.path), parent_modules); + bindings_ = Resolve_Use_GetBinding(sp2, crate, mod.path(), Resolve_Use_AbsolutisePath(sp2, mod.path(), imp_e.path), parent_modules); // *waves hand* I'm not evil. const_cast< ::AST::Path::Bindings&>( imp_e.path.m_bindings ) = bindings_.clone(); bindings = &bindings_; @@ -410,7 +411,17 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path TU_ARMA(Module, e) { if( e.module_ ) { // TODO: Prevent infinite recursion? - rv.merge_from( Resolve_Use_GetBinding_Mod(span, crate, *e.module_, des_item_name, {}) ); + static ::std::vector s_use_glob_mod_stack; + if( ::std::find(s_use_glob_mod_stack.begin(), s_use_glob_mod_stack.end(), &*e.module_) == s_use_glob_mod_stack.end() ) + { + s_use_glob_mod_stack.push_back( &*e.module_ ); + rv.merge_from( Resolve_Use_GetBinding_Mod(span, crate, mod.path(), *e.module_, des_item_name, {}) ); + s_use_glob_mod_stack.pop_back(); + } + else + { + DEBUG("Recursion prevented of " << e.module_->path()); + } } else if( e.hir ) { const ::HIR::Module& hmod = *e.hir; @@ -470,7 +481,7 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path if( mod.path().nodes().size() > 0 && mod.path().nodes().back().name()[0] == '#' ) { assert( parent_modules.size() > 0 ); - return Resolve_Use_GetBinding_Mod(span, crate, *parent_modules.back(), des_item_name, parent_modules.subspan(0, parent_modules.size()-1)); + return Resolve_Use_GetBinding_Mod(span, crate, source_mod_path, *parent_modules.back(), des_item_name, parent_modules.subspan(0, parent_modules.size()-1)); } else { //if( allow == Lookup::Any ) @@ -731,7 +742,7 @@ namespace { return rv; } -::AST::Path::Bindings Resolve_Use_GetBinding(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path, ::std::span< const ::AST::Module* > parent_modules) +::AST::Path::Bindings Resolve_Use_GetBinding(const Span& span, const ::AST::Crate& crate, const ::AST::Path& source_mod_path, const ::AST::Path& path, ::std::span< const ::AST::Module* > parent_modules) { TRACE_FUNCTION_F(path); //::AST::Path rv; @@ -760,7 +771,7 @@ namespace { //rv = Resolve_Use_CanoniseAndBind_Mod(span, crate, *mod, mv$(rv), nodes[i].name(), parent_modules, Lookup::Type); //const auto& b = rv.binding(); assert(mod); - auto b = Resolve_Use_GetBinding_Mod(span, crate, *mod, nodes.at(i).name(), parent_modules); + auto b = Resolve_Use_GetBinding_Mod(span, crate, source_mod_path, *mod, nodes.at(i).name(), parent_modules); TU_MATCH_HDRA( (b.type), {) default: ERROR(span, E0000, "Unexpected item type " << b.type.tag_str() << " in import of " << path); @@ -783,7 +794,7 @@ namespace { const auto& node2 = nodes[i]; unsigned variant_index = 0; - bool is_value; + bool is_value = false; if(e.hir) { const auto& enum_ = *e.hir; @@ -804,7 +815,6 @@ namespace { else { const auto& enum_ = *e.enum_; - is_value = false; for( const auto& var : enum_.variants() ) { if( var.m_name == node2.name() ) { @@ -841,7 +851,7 @@ namespace { } assert(mod); - return Resolve_Use_GetBinding_Mod(span, crate, *mod, nodes.back().name(), parent_modules); + return Resolve_Use_GetBinding_Mod(span, crate, source_mod_path, *mod, nodes.back().name(), parent_modules); } //::AST::PathBinding_Macro Resolve_Use_GetBinding_Macro(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path, ::std::span< const ::AST::Module* > parent_modules) -- cgit v1.2.3 From fbeb6e8fe4e8600f84b08a0014f2f6a2713789ce Mon Sep 17 00:00:00 2001 From: John Hodge Date: Mon, 28 Jan 2019 16:40:21 +0800 Subject: Resolve Index - (minor) Better error mesage on collision --- src/resolve/index.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/resolve/index.cpp b/src/resolve/index.cpp index 6051b82d..ec1fcd8d 100644 --- a/src/resolve/index.cpp +++ b/src/resolve/index.cpp @@ -67,7 +67,7 @@ void _add_item(const Span& sp, AST::Module& mod, IndexName location, const ::std { if( error_on_collision ) { - ERROR(sp, E0000, "Duplicate definition of name '" << name << "' in " << location << " scope (" << mod.path() << ")"); + ERROR(sp, E0000, "Duplicate definition of name '" << name << "' in " << location << " scope (" << mod.path() << ") " << ir << ", and " << list[name].path); } else if( list.at(name).path == ir ) { -- cgit v1.2.3 From f614ee2ad81efe77ba78b0d056171677b09eb93a Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 2 Feb 2019 15:10:46 +0800 Subject: Resolve Absolute - More in-band-lifetimes, tweak resolve for globbed value variants --- src/ast/types.hpp | 2 + src/resolve/absolute.cpp | 120 +++++++++++++++++++++++++++++++++++++---------- 2 files changed, 98 insertions(+), 24 deletions(-) diff --git a/src/ast/types.hpp b/src/ast/types.hpp index af07ba2d..0b0f205e 100644 --- a/src/ast/types.hpp +++ b/src/ast/types.hpp @@ -41,10 +41,12 @@ namespace AST { class LifetimeRef { + public: static const uint16_t BINDING_STATIC = 0xFFFF; static const uint16_t BINDING_UNBOUND = 0xFFFE; static const uint16_t BINDING_INFER = 0xFFFD; + private: Ident m_name; uint16_t m_binding; diff --git a/src/resolve/absolute.cpp b/src/resolve/absolute.cpp index d4147e92..3652fb3a 100644 --- a/src/resolve/absolute.cpp +++ b/src/resolve/absolute.cpp @@ -65,6 +65,9 @@ namespace }), (Generic, struct { // Map of names to slots + GenericSlot::Level level; + ::AST::GenericParams* params_def; // TODO: What if it's HRBs?, they have a different type + //::AST::HigherRankedBounds* hrbs_def; ::std::vector< Named< GenericSlot > > types; ::std::vector< Named< GenericSlot > > constants; ::std::vector< NamedI< GenericSlot > > lifetimes; @@ -91,7 +94,7 @@ namespace {} void push(const ::AST::HigherRankedBounds& params) { - auto e = Ent::make_Generic({}); + auto e = Ent::make_Generic({ GenericSlot::Level::Hrb, nullptr /*, ¶ms*/ }); auto& data = e.as_Generic(); for(size_t i = 0; i < params.m_lifetimes.size(); i ++) @@ -101,8 +104,8 @@ namespace m_name_context.push_back(mv$(e)); } - void push(const ::AST::GenericParams& params, GenericSlot::Level level, bool has_self=false) { - auto e = Ent::make_Generic({}); + void push(/*const */::AST::GenericParams& params, GenericSlot::Level level, bool has_self=false) { + auto e = Ent::make_Generic({ level, ¶ms }); auto& data = e.as_Generic(); if( has_self ) { @@ -283,6 +286,7 @@ namespace Type, Constant, PatternValue, + //PatternAny, Variable, }; static const char* lookup_mode_msg(LookupMode mode) { @@ -341,7 +345,38 @@ namespace return true; } } + // HACK: For `Enum::Var { .. }` patterns matching value variants + { + auto v = mod.m_value_items.find(name); + if( v != mod.m_value_items.end() ) { + const auto& b = v->second.path.m_bindings.value; + if( b.is_EnumVar() ) { + DEBUG("- TY: Enum variant " << v->second.path); + path = ::AST::Path( v->second.path ); + return true; + } + } + } break; + //case LookupMode::PatternAny: + // { + // auto v = mod.m_type_items.find(name); + // if( v != mod.m_type_items.end() ) { + // DEBUG("- TY: Type " << v->second.path); + // path = ::AST::Path( v->second.path ); + // return true; + // } + // auto v2 = mod.m_value_items.find(name); + // if( v2 != mod.m_value_items.end() ) { + // const auto& b = v2->second.path.m_bindings.value; + // if( b.is_EnumVar() ) { + // DEBUG("- TY: Enum variant " << v2->second.path); + // path = ::AST::Path( v2->second.path ); + // return true; + // } + // } + // } + // break; case LookupMode::PatternValue: { auto v = mod.m_value_items.find(name); @@ -548,6 +583,11 @@ void Resolve_Absolute_Function(Context& item_context, ::AST::Function& fcn); void Resolve_Absolute_PathParams(/*const*/ Context& context, const Span& sp, ::AST::PathParams& args) { + // TODO: Lifetime params + for(auto& arg : args.m_lifetimes) + { + Resolve_Absolute_Lifetime(context, sp, arg); + } for(auto& arg : args.m_types) { Resolve_Absolute_Type(context, arg); @@ -1489,6 +1529,17 @@ void Resolve_Absolute_Lifetime(Context& context, const Span& sp, AST::LifetimeRe return ; } + if( lft.name() == "_" ) + { + if( TARGETVER_1_19 ) + { + ERROR(sp, E0000, "'_ is not a valid lifetime name in 1.19 mode"); + } + // Note: '_ is just an explicit elided lifetime + lft.set_binding(AST::LifetimeRef::BINDING_INFER); + return ; + } + for(auto it = context.m_name_context.rbegin(); it != context.m_name_context.rend(); ++ it) { if( const auto* e = it->opt_Generic() ) @@ -1508,25 +1559,33 @@ void Resolve_Absolute_Lifetime(Context& context, const Span& sp, AST::LifetimeRe if( TARGETVER_1_29 ) { // If parsing a function header, add a new lifetime param to the function - // - Does the same apply to impl headers? + // - Does the same apply to impl headers? Yes it does. if( context.m_ibl_target_generics ) { ASSERT_BUG(sp, !context.m_name_context.empty(), "Name context stack is empty"); - ASSERT_BUG(sp, context.m_name_context.back().is_Generic(), "Name context stack end not Generic, instead " << context.m_name_context.back().tag_str()); - auto& context_gen = context.m_name_context.back().as_Generic(); - auto& def_gen = *context.m_ibl_target_generics; - // 1. Assert that the last item of `context.m_name_context` is Generic, and matches `m_ibl_target_generics` - ASSERT_BUG(sp, context_gen.lifetimes.size() == def_gen.lft_params().size(), ""); - ASSERT_BUG(sp, context_gen.types.size() == def_gen.ty_params().size(), ""); - //ASSERT_BUG(sp, context_gen.constants.size() == def_gen.val_params().size(), ""); - // 2. Add the new lifetime to both `m_ibl_target_generics` and the last entry in m_name_context - size_t idx = def_gen.lft_params().size(); - def_gen.add_lft_param(AST::LifetimeParam(sp, {}, lft.name())); - // TODO: Is this always a method-level set? - auto level = GenericSlot::Level::Method; - context_gen.lifetimes.push_back( NamedI { lft.name(), GenericSlot { level, static_cast(idx) } } ); - lft.set_binding( idx | (static_cast(level) << 8) ); - return ; + auto it = context.m_name_context.rbegin(); + ASSERT_BUG(sp, it->is_Generic(), "Name context stack end not Generic, instead " << it->tag_str()); + while( it->as_Generic().level == GenericSlot::Level::Hrb ) { + it ++; + ASSERT_BUG(sp, it != context.m_name_context.rend(), ""); + ASSERT_BUG(sp, it->is_Generic(), "Name context stack end not Generic, instead " << it->tag_str()); + } + if( it->as_Generic().level != GenericSlot::Level::Hrb ) + { + auto& context_gen = it->as_Generic(); + auto& def_gen = *context.m_ibl_target_generics; + auto level = context_gen.level; + // 1. Assert that the last item of `context.m_name_context` is Generic, and matches `m_ibl_target_generics` + ASSERT_BUG(sp, context_gen.lifetimes.size() == def_gen.lft_params().size(), ""); + ASSERT_BUG(sp, context_gen.types.size() == def_gen.ty_params().size(), ""); + //ASSERT_BUG(sp, context_gen.constants.size() == def_gen.val_params().size(), ""); + // 2. Add the new lifetime to both `m_ibl_target_generics` and the last entry in m_name_context + size_t idx = def_gen.lft_params().size(); + def_gen.add_lft_param(AST::LifetimeParam(sp, {}, lft.name())); + context_gen.lifetimes.push_back( NamedI { lft.name(), GenericSlot { level, static_cast(idx) } } ); + lft.set_binding( idx | (static_cast(level) << 8) ); + return ; + } } } ERROR(sp, E0000, "Couldn't find lifetime " << lft); @@ -1903,6 +1962,10 @@ void Resolve_Absolute_Pattern(Context& context, bool allow_refutable, ::AST::Pa Resolve_Absolute_Pattern(context, allow_refutable, sp); ), (Struct, + // TODO: `Struct { .. }` patterns can match anything + //if( e.sub_patterns.empty() && !e.is_exhaustive ) { + // auto rv = this->lookup_opt(name, src_context, mode); + //} Resolve_Absolute_Path(context, pat.span(), Context::LookupMode::Type, e.path); for(auto& sp : e.sub_patterns) Resolve_Absolute_Pattern(context, allow_refutable, sp.second); @@ -2165,14 +2228,17 @@ void Resolve_Absolute_Mod( Context item_context, ::AST::Module& mod ) ), (Impl, auto& def = e.def(); - DEBUG("impl " << def.trait().ent << " for " << def.type()); if( !def.type().is_valid() ) { - DEBUG("---- MARKER IMPL for " << def.trait().ent); + TRACE_FUNCTION_F("impl " << def.trait().ent << " for .."); item_context.push(def.params(), GenericSlot::Level::Top); - Resolve_Absolute_Generic(item_context, def.params()); + + item_context.m_ibl_target_generics = &def.params(); assert( def.trait().ent.is_valid() ); Resolve_Absolute_Path(item_context, def.trait().sp, Context::LookupMode::Type, def.trait().ent); + item_context.m_ibl_target_generics = nullptr; + + Resolve_Absolute_Generic(item_context, def.params()); if( e.items().size() != 0 ) { ERROR(i.data.span, E0000, "impl Trait for .. with methods"); @@ -2184,13 +2250,16 @@ void Resolve_Absolute_Mod( Context item_context, ::AST::Module& mod ) } else { + TRACE_FUNCTION_F("impl " << def.trait().ent << " for " << def.type()); item_context.push_self( def.type() ); item_context.push(def.params(), GenericSlot::Level::Top); + item_context.m_ibl_target_generics = &def.params(); Resolve_Absolute_Type(item_context, def.type()); if( def.trait().ent.is_valid() ) { Resolve_Absolute_Path(item_context, def.trait().sp, Context::LookupMode::Type, def.trait().ent); } + item_context.m_ibl_target_generics = nullptr; Resolve_Absolute_Generic(item_context, def.params()); @@ -2202,15 +2271,18 @@ void Resolve_Absolute_Mod( Context item_context, ::AST::Module& mod ) ), (NegImpl, auto& impl_def = e; - DEBUG("impl ! " << impl_def.trait().ent << " for " << impl_def.type()); + TRACE_FUNCTION_F("impl ! " << impl_def.trait().ent << " for " << impl_def.type()); item_context.push_self( impl_def.type() ); item_context.push(impl_def.params(), GenericSlot::Level::Top); - Resolve_Absolute_Generic(item_context, impl_def.params()); + item_context.m_ibl_target_generics = &impl_def.params(); Resolve_Absolute_Type(item_context, impl_def.type()); if( !impl_def.trait().ent.is_valid() ) BUG(i.data.span, "Encountered negative impl with no trait"); Resolve_Absolute_Path(item_context, impl_def.trait().sp, Context::LookupMode::Type, impl_def.trait().ent); + item_context.m_ibl_target_generics = nullptr; + + Resolve_Absolute_Generic(item_context, impl_def.params()); // No items -- cgit v1.2.3 From aab9f94620c7d78377ffbd3fdbcb845657c86503 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 2 Feb 2019 17:34:02 +0800 Subject: HIR From AST - repr fiddling --- src/hir/from_ast.cpp | 66 ++++++++++++++++++++++++++++------------------- src/hir/from_ast_expr.cpp | 1 + src/resolve/absolute.cpp | 2 +- 3 files changed, 42 insertions(+), 27 deletions(-) diff --git a/src/hir/from_ast.cpp b/src/hir/from_ast.cpp index 32561a76..899d0b0c 100644 --- a/src/hir/from_ast.cpp +++ b/src/hir/from_ast.cpp @@ -156,28 +156,26 @@ const ::AST::Crate* g_ast_crate_ptr; } }; - TU_MATCH(::AST::Pattern::Data, (pat.data()), (e), - (MaybeBind, + TU_MATCH_HDRA( (pat.data()), {) + TU_ARMA(MaybeBind, e) { BUG(pat.span(), "Encountered MaybeBind pattern"); - ), - (Macro, + } + TU_ARMA(Macro, e) { BUG(pat.span(), "Encountered Macro pattern"); - ), - (Any, + } + TU_ARMA(Any, e) return ::HIR::Pattern { mv$(binding), ::HIR::Pattern::Data::make_Any({}) }; - ), - (Box, + TU_ARMA(Box, e) return ::HIR::Pattern { mv$(binding), ::HIR::Pattern::Data::make_Box({ box$(LowerHIR_Pattern( *e.sub )) }) }; - ), - (Ref, + TU_ARMA(Ref, e) return ::HIR::Pattern { mv$(binding), ::HIR::Pattern::Data::make_Ref({ @@ -185,8 +183,7 @@ const ::AST::Crate* g_ast_crate_ptr; box$(LowerHIR_Pattern( *e.sub )) }) }; - ), - (Tuple, + TU_ARMA(Tuple, e) { auto leading = H::lowerhir_patternvec( e.start ); auto trailing = H::lowerhir_patternvec( e.end ); @@ -209,9 +206,8 @@ const ::AST::Crate* g_ast_crate_ptr; }) }; } - ), - - (StructTuple, + } + TU_ARMA(StructTuple, e) { unsigned int leading_count = e.tup_pat.start.size(); unsigned int trailing_count = e.tup_pat.end .size(); TU_MATCH_HDRA( (e.path.m_bindings.value), {) @@ -318,12 +314,25 @@ const ::AST::Crate* g_ast_crate_ptr; }; } } - ), - (Struct, + } + TU_ARMA(Struct, e) { ::std::vector< ::std::pair< ::std::string, ::HIR::Pattern> > sub_patterns; for(const auto& sp : e.sub_patterns) sub_patterns.push_back( ::std::make_pair(sp.first, LowerHIR_Pattern(sp.second)) ); + if( e.sub_patterns.empty() && !e.is_exhaustive ) { + if( e.path.m_bindings.value.is_EnumVar() ) { + return ::HIR::Pattern { + mv$(binding), + ::HIR::Pattern::Data::make_EnumStruct({ + LowerHIR_GenericPath(pat.span(), e.path), + nullptr, 0, + mv$(sub_patterns), + e.is_exhaustive + }) + }; + } + } TU_MATCH_HDRA( (e.path.m_bindings.type), {) default: @@ -362,9 +371,9 @@ const ::AST::Crate* g_ast_crate_ptr; }; } } - ), + } - (Value, + TU_ARMA(Value, e) { struct H { static ::HIR::CoreType get_int_type(const Span& sp, const ::eCoreType ct) { switch(ct) @@ -448,8 +457,8 @@ const ::AST::Crate* g_ast_crate_ptr; }) }; } - ), - (Slice, + } + TU_ARMA(Slice, e) { ::std::vector< ::HIR::Pattern> leading; for(const auto& sp : e.sub_pats) leading.push_back( LowerHIR_Pattern(sp) ); @@ -459,8 +468,8 @@ const ::AST::Crate* g_ast_crate_ptr; mv$(leading) }) }; - ), - (SplitSlice, + } + TU_ARMA(SplitSlice, e) { ::std::vector< ::HIR::Pattern> leading; for(const auto& sp : e.leading) leading.push_back( LowerHIR_Pattern(sp) ); @@ -483,8 +492,8 @@ const ::AST::Crate* g_ast_crate_ptr; mv$(trailing) }) }; - ) - ) + } + } throw "unreachable"; } @@ -889,12 +898,17 @@ namespace { { ASSERT_BUG(attr_repr->span(), attr_repr->has_sub_items(), "#[repr] attribute malformed, " << *attr_repr); ASSERT_BUG(attr_repr->span(), attr_repr->items().size() > 0, "#[repr] attribute malformed, " << *attr_repr); + // TODO: Change reprs to be a flag set (instead of an enum)? + // (Or at least make C be a flag) for( const auto& a : attr_repr->items() ) { const auto& repr_str = a.name(); if( repr_str == "C" ) { ASSERT_BUG(a.span(), a.has_noarg(), "#[repr] attribute malformed, " << *attr_repr); - if( rv.m_repr != ::HIR::Struct::Repr::Packed ) + if( rv.m_repr == ::HIR::Struct::Repr::Aligned ) + { + } + else if( rv.m_repr != ::HIR::Struct::Repr::Packed ) { ASSERT_BUG(a.span(), rv.m_repr == ::HIR::Struct::Repr::Rust, "Conflicting #[repr] attributes - " << rv.m_repr << ", " << repr_str); rv.m_repr = ::HIR::Struct::Repr::C; diff --git a/src/hir/from_ast_expr.cpp b/src/hir/from_ast_expr.cpp index cc642482..55c742ad 100644 --- a/src/hir/from_ast_expr.cpp +++ b/src/hir/from_ast_expr.cpp @@ -526,6 +526,7 @@ struct LowerHIR_ExprNode_Visitor: ::HIR::ExprNode_StructLiteral::t_values values; for(const auto& val : v.m_values) values.push_back( ::std::make_pair(val.name, LowerHIR_ExprNode_Inner(*val.value)) ); + // TODO: What if `v.m_path` is an associated type (that's known to be a struct) m_rv.reset( new ::HIR::ExprNode_StructLiteral( v.span(), LowerHIR_GenericPath(v.span(), v.m_path), ! v.m_path.m_bindings.type.is_EnumVar(), diff --git a/src/resolve/absolute.cpp b/src/resolve/absolute.cpp index 3652fb3a..d2609e9e 100644 --- a/src/resolve/absolute.cpp +++ b/src/resolve/absolute.cpp @@ -350,7 +350,7 @@ namespace auto v = mod.m_value_items.find(name); if( v != mod.m_value_items.end() ) { const auto& b = v->second.path.m_bindings.value; - if( b.is_EnumVar() ) { + if( const auto* be = b.opt_EnumVar() ) { DEBUG("- TY: Enum variant " << v->second.path); path = ::AST::Path( v->second.path ); return true; -- cgit v1.2.3 From 4960edb7d948e43efc58a28ecd05fa9237c8d240 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 3 Feb 2019 13:42:13 +0800 Subject: HIR Expr - Have _StructLiteral take a HIR::Path (to allow associated types to be used) --- src/hir/expr.cpp | 2 +- src/hir/expr.hpp | 4 ++-- src/hir/from_ast.cpp | 12 ++++++++++- src/hir/from_ast_expr.cpp | 2 +- src/hir_conv/bind.cpp | 2 +- src/hir_conv/expand_type.cpp | 5 +++-- src/hir_expand/annotate_value_usage.cpp | 6 ++++-- src/hir_typeck/expr_check.cpp | 6 ++++-- src/hir_typeck/expr_cs.cpp | 15 ++++++++------ src/mir/from_hir.cpp | 35 +++++++++++++++++++-------------- 10 files changed, 56 insertions(+), 33 deletions(-) diff --git a/src/hir/expr.cpp b/src/hir/expr.cpp index 6b7c2e1a..589e2811 100644 --- a/src/hir/expr.cpp +++ b/src/hir/expr.cpp @@ -158,7 +158,7 @@ DEF_VISIT(ExprNode_PathValue, node, ) DEF_VISIT(ExprNode_Variable, , ) DEF_VISIT(ExprNode_StructLiteral, node, - visit_generic_path(::HIR::Visitor::PathContext::VALUE, node.m_path); + visit_path(::HIR::Visitor::PathContext::VALUE, node.m_path); if( node.m_base_value ) visit_node_ptr(node.m_base_value); for(auto& val : node.m_values) diff --git a/src/hir/expr.hpp b/src/hir/expr.hpp index 15c0a489..140ba817 100644 --- a/src/hir/expr.hpp +++ b/src/hir/expr.hpp @@ -694,7 +694,7 @@ struct ExprNode_StructLiteral: { typedef ::std::vector< ::std::pair< ::std::string, ExprNodeP > > t_values; - ::HIR::GenericPath m_path; + ::HIR::Path m_path; bool m_is_struct; ::HIR::ExprNodeP m_base_value; t_values m_values; @@ -702,7 +702,7 @@ struct ExprNode_StructLiteral: /// Monomorphised types of each field. ::std::vector< ::HIR::TypeRef> m_value_types; - ExprNode_StructLiteral(Span sp, ::HIR::GenericPath path, bool is_struct, ::HIR::ExprNodeP base_value, t_values values): + ExprNode_StructLiteral(Span sp, ::HIR::Path path, bool is_struct, ::HIR::ExprNodeP base_value, t_values values): ExprNode( mv$(sp) ), m_path( mv$(path) ), m_is_struct( is_struct ), diff --git a/src/hir/from_ast.cpp b/src/hir/from_ast.cpp index 899d0b0c..768593c4 100644 --- a/src/hir/from_ast.cpp +++ b/src/hir/from_ast.cpp @@ -628,7 +628,17 @@ const ::AST::Crate* g_ast_crate_ptr; return ::HIR::Path( LowerHIR_GenericPath(sp, path) ); ), (UFCS, - if( e.nodes.size() != 1 ) + if( e.nodes.size() == 0 ) + { + if( !e.trait ) + TODO(sp, "Handle UFCS inherent and no nodes - " << path); + if( e.trait->is_valid() ) + TODO(sp, "Handle UFCS w/ trait and no nodes - " << path); + auto type = LowerHIR_Type(*e.type); + ASSERT_BUG(sp, type.m_data.is_Path(), "No nodes and non-Path type - " << path); + return mv$(type.m_data.as_Path().path); + } + if( e.nodes.size() > 1 ) TODO(sp, "Handle UFCS with multiple nodes - " << path); // - No associated type bounds allowed in UFCS paths auto params = LowerHIR_PathParams(sp, e.nodes.front().args(), false); diff --git a/src/hir/from_ast_expr.cpp b/src/hir/from_ast_expr.cpp index 55c742ad..23797382 100644 --- a/src/hir/from_ast_expr.cpp +++ b/src/hir/from_ast_expr.cpp @@ -528,7 +528,7 @@ struct LowerHIR_ExprNode_Visitor: values.push_back( ::std::make_pair(val.name, LowerHIR_ExprNode_Inner(*val.value)) ); // TODO: What if `v.m_path` is an associated type (that's known to be a struct) m_rv.reset( new ::HIR::ExprNode_StructLiteral( v.span(), - LowerHIR_GenericPath(v.span(), v.m_path), + LowerHIR_Path(v.span(), v.m_path), ! v.m_path.m_bindings.type.is_EnumVar(), LowerHIR_ExprNode_Inner_Opt(v.m_base_value.get()), mv$(values) diff --git a/src/hir_conv/bind.cpp b/src/hir_conv/bind.cpp index c979b2e6..9b5043f4 100644 --- a/src/hir_conv/bind.cpp +++ b/src/hir_conv/bind.cpp @@ -645,7 +645,7 @@ namespace { void visit(::HIR::ExprNode_StructLiteral& node) override { - upper_visitor.visit_generic_path(node.m_path, ::HIR::Visitor::PathContext::TYPE); + upper_visitor.visit_path(node.m_path, ::HIR::Visitor::PathContext::TYPE); ::HIR::ExprVisitorDef::visit(node); } void visit(::HIR::ExprNode_ArraySized& node) override diff --git a/src/hir_conv/expand_type.cpp b/src/hir_conv/expand_type.cpp index dcdf79bd..6b06a748 100644 --- a/src/hir_conv/expand_type.cpp +++ b/src/hir_conv/expand_type.cpp @@ -255,9 +255,10 @@ public: { if( node.m_is_struct ) { - auto new_path = upper_visitor.expand_alias_gp(node.span(), node.m_path); - if( new_path.m_path.m_components.size() != 0 ) + auto new_type = ConvertHIR_ExpandAliases_GetExpansion(upper_visitor.m_crate, node.m_path, /*in_expr=*/true); + if( new_type != ::HIR::TypeRef() ) { + auto new_path = mv$(new_type.m_data.as_Path().path); DEBUG("Replacing " << node.m_path << " with " << new_path); node.m_path = mv$(new_path); } diff --git a/src/hir_expand/annotate_value_usage.cpp b/src/hir_expand/annotate_value_usage.cpp index 491ab4c7..1754bdac 100644 --- a/src/hir_expand/annotate_value_usage.cpp +++ b/src/hir_expand/annotate_value_usage.cpp @@ -356,13 +356,15 @@ namespace { void visit(::HIR::ExprNode_StructLiteral& node) override { const auto& sp = node.span(); + ASSERT_BUG(sp, node.m_path.m_data.is_Generic(), "Struct literal with non-Generic path - " << node.m_path); + auto& ty_path = node.m_path.m_data.as_Generic(); if( node.m_base_value ) { bool is_moved = false; const auto& tpb = node.m_base_value->m_res_type.m_data.as_Path().binding; const ::HIR::Struct* str; if( tpb.is_Enum() ) { const auto& enm = *tpb.as_Enum(); - auto idx = enm.find_variant(node.m_path.m_path.m_components.back()); + auto idx = enm.find_variant(ty_path.m_path.m_components.back()); ASSERT_BUG(sp, idx != SIZE_MAX, ""); const auto& var_ty = enm.m_data.as_Data()[idx].type; str = var_ty.m_data.as_Path().binding.as_Struct(); @@ -379,7 +381,7 @@ namespace { provided_mask[idx] = true; } - const auto monomorph_cb = monomorphise_type_get_cb(node.span(), nullptr, &node.m_path.m_params, nullptr); + const auto monomorph_cb = monomorphise_type_get_cb(node.span(), nullptr, &ty_path.m_params, nullptr); for( unsigned int i = 0; i < fields.size(); i ++ ) { if( ! provided_mask[i] ) { const auto& ty_o = fields[i].second.ent; diff --git a/src/hir_typeck/expr_check.cpp b/src/hir_typeck/expr_check.cpp index cd57c471..adb3c426 100644 --- a/src/hir_typeck/expr_check.cpp +++ b/src/hir_typeck/expr_check.cpp @@ -496,6 +496,8 @@ namespace { if( node.m_base_value) { check_types_equal( node.m_base_value->span(), node.m_res_type, node.m_base_value->m_res_type ); } + ASSERT_BUG(sp, node.m_path.m_data.is_Generic(), "_StructLiteral with non-Generic path - " << node.m_path); + auto& ty_path = node.m_path.m_data.as_Generic(); // - Create ivars in path, and set result type const auto& ty = node.m_res_type; @@ -506,7 +508,7 @@ namespace { (Unbound, ), (Opaque, ), (Enum, - const auto& var_name = node.m_path.m_path.m_components.back(); + const auto& var_name = ty_path.m_path.m_components.back(); const auto& enm = *e; auto idx = enm.find_variant(var_name); ASSERT_BUG(sp, idx != SIZE_MAX, ""); @@ -536,7 +538,7 @@ namespace { const ::HIR::t_struct_fields& fields = *fields_ptr; #if 1 - const auto& ty_params = node.m_path.m_params.m_types; + const auto& ty_params = ty_path.m_params.m_types; auto monomorph_cb = [&](const auto& gt)->const ::HIR::TypeRef& { const auto& ge = gt.m_data.as_Generic(); if( ge.binding == 0xFFFF ) { diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 8b0eedb3..4a53bd4d 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -1193,7 +1193,10 @@ namespace { { const auto& sp = node.span(); TRACE_FUNCTION_F(&node << " " << node.m_path << "{...} [" << (node.m_is_struct ? "struct" : "enum") << "]"); - this->add_ivars_generic_path(node.span(), node.m_path); + ASSERT_BUG(sp, node.m_path.m_data.is_Generic(), "Struct literal with non-Generic path - " << node.m_path); + auto& ty_path = node.m_path.m_data.as_Generic(); + + this->add_ivars_generic_path(node.span(), ty_path); for( auto& val : node.m_values ) { this->context.add_ivars( val.second->m_res_type ); } @@ -1202,7 +1205,7 @@ namespace { } // - Create ivars in path, and set result type - const auto ty = this->get_structenum_ty(node.span(), node.m_is_struct, node.m_path); + const auto ty = this->get_structenum_ty(node.span(), node.m_is_struct, ty_path); this->context.equate_types(node.span(), node.m_res_type, ty); if( node.m_base_value ) { this->context.equate_types(node.span(), node.m_base_value->m_res_type, ty); @@ -1214,7 +1217,7 @@ namespace { (Unbound, ), (Opaque, ), (Enum, - const auto& var_name = node.m_path.m_path.m_components.back(); + const auto& var_name = ty_path.m_path.m_components.back(); const auto& enm = *e; auto idx = enm.find_variant(var_name); ASSERT_BUG(sp, idx != SIZE_MAX, ""); @@ -1257,7 +1260,7 @@ namespace { ASSERT_BUG(node.span(), fields_ptr, ""); const ::HIR::t_struct_fields& fields = *fields_ptr; - const auto& ty_params = node.m_path.m_params.m_types; + const auto& ty_params = ty_path.m_params.m_types; auto monomorph_cb = [&](const auto& gt)->const ::HIR::TypeRef& { const auto& ge = gt.m_data.as_Generic(); if( ge.binding == 0xFFFF ) { @@ -1281,7 +1284,7 @@ namespace { { const auto& name = val.first; auto it = ::std::find_if(fields.begin(), fields.end(), [&](const auto& v)->bool{ return v.first == name; }); - ASSERT_BUG(node.span(), it != fields.end(), "Field '" << name << "' not found in struct " << node.m_path); + ASSERT_BUG(node.span(), it != fields.end(), "Field '" << name << "' not found in struct " << ty_path); const auto& des_ty_r = it->second.ent; auto& des_ty_cache = node.m_value_types[it - fields.begin()]; const auto* des_ty = &des_ty_r; @@ -3164,7 +3167,7 @@ namespace { this->check_type_resolved_genericpath(node.span(), node.m_path); } void visit(::HIR::ExprNode_StructLiteral& node) override { - this->check_type_resolved_pp(node.span(), node.m_path.m_params, ::HIR::TypeRef()); + this->check_type_resolved_path(node.span(), node.m_path); for(auto& ty : node.m_value_types) { if( ty != ::HIR::TypeRef() ) { this->check_type_resolved_top(node.span(), ty); diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index ee4cf474..9ce40a74 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -2365,13 +2365,18 @@ namespace { { TRACE_FUNCTION_F("_StructLiteral"); - TU_MATCH(::HIR::TypeRef::TypePathBinding, (node.m_res_type.m_data.as_Path().binding), (e), - (Unbound, ), - (Opaque, ), - (Enum, - auto enum_path = node.m_path.clone(); + ASSERT_BUG(node.span(), node.m_path.m_data.is_Generic(), "_StructLiteral with non-Generic path - " << node.m_path); + const auto& ty_path = node.m_path.m_data.as_Generic(); + + TU_MATCH_HDRA( (node.m_res_type.m_data.as_Path().binding), {) + TU_ARMA(Unbound, _e) { + } + TU_ARMA(Opaque, _e) { + } + TU_ARMA(Enum, e) { + auto enum_path = ty_path.clone(); enum_path.m_path.m_components.pop_back(); - const auto& var_name = node.m_path.m_path.m_components.back(); + const auto& var_name = ty_path.m_path.m_components.back(); const auto& enm = *e; size_t idx = enm.find_variant(var_name); @@ -2381,7 +2386,7 @@ namespace { const auto& str = *var_ty.m_data.as_Path().binding.as_Struct(); // Take advantage of the identical generics to cheaply clone/monomorph the path. - ::HIR::GenericPath struct_path = node.m_path.clone(); + ::HIR::GenericPath struct_path = ty_path.clone(); struct_path.m_path = var_ty.m_data.as_Path().path.m_data.as_Generic().m_path; this->visit_sl_inner(node, str, struct_path); @@ -2396,22 +2401,22 @@ namespace { static_cast(idx), mv$(v) }) ); - ), - (Union, + } + TU_ARMA(Union, e) { BUG(node.span(), "_StructLiteral Union isn't valid?"); - ), - (Struct, + } + TU_ARMA(Struct, e) { if(e->m_data.is_Unit()) { m_builder.set_result( node.span(), ::MIR::RValue::make_Struct({ - node.m_path.clone(), + ty_path.clone(), {} }) ); return ; } - this->visit_sl_inner(node, *e, node.m_path); - ) - ) + this->visit_sl_inner(node, *e, ty_path); + } + } } void visit(::HIR::ExprNode_UnionLiteral& node) override { -- cgit v1.2.3 From 42b9c8704fe4aab25e8f9d0cca15a74b025eee43 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 3 Feb 2019 17:48:32 +0800 Subject: HIR - Minimally-tested support for `extern { type }` --- src/hir/from_ast.cpp | 10 ++++++++ src/hir/hir.hpp | 8 +++++++ src/hir/serialise.cpp | 9 ++++++++ src/hir/type.cpp | 2 ++ src/hir/type.hpp | 2 ++ src/hir/visitor.cpp | 3 +++ src/hir_conv/bind.cpp | 4 ++++ src/hir_conv/constant_evaluation.cpp | 2 ++ src/hir_conv/markings.cpp | 1 + src/hir_typeck/expr_check.cpp | 9 ++++++++ src/hir_typeck/expr_cs.cpp | 18 +++++++++++++++ src/hir_typeck/helpers.cpp | 13 +++++++++++ src/hir_typeck/outer.cpp | 4 ++++ src/hir_typeck/static.cpp | 15 ++++++++++++ src/mir/from_hir.cpp | 3 +++ src/mir/from_hir_match.cpp | 15 ++++++++++++ src/resolve/absolute.cpp | 44 +++++++++++++++++------------------- src/resolve/index.cpp | 13 ++++++++++- src/resolve/use.cpp | 3 +++ src/trans/auto_impls.cpp | 6 ++--- src/trans/codegen.cpp | 3 +++ src/trans/codegen_c.cpp | 11 +++++++++ src/trans/enumerate.cpp | 16 ++++++------- 23 files changed, 178 insertions(+), 36 deletions(-) diff --git a/src/hir/from_ast.cpp b/src/hir/from_ast.cpp index 768593c4..fb8096f7 100644 --- a/src/hir/from_ast.cpp +++ b/src/hir/from_ast.cpp @@ -1187,6 +1187,7 @@ namespace { ::std::vector< ::HIR::TraitPath> trait_bounds; ::std::string lifetime_bound; auto gps = LowerHIR_GenericParams(i.params(), &is_sized); + for(auto& b : gps.m_bounds) { TU_MATCH(::HIR::GenericBound, (b), (be), @@ -1463,6 +1464,15 @@ void _add_mod_val_item(::HIR::Module& mod, ::std::string name, bool is_pub, ::H _add_mod_ns_item( mod, item.name, item.is_pub, ::HIR::TypeItem::make_Import({ ::HIR::SimplePath(e.name, {}), false, 0} ) ); ), (Type, + if( e.type().m_data.is_Any() ) + { + if( !e.params().lft_params().empty() || !e.params().ty_params().empty() || !e.params().bounds().empty() ) + { + ERROR(item.data.span, E0000, "Generics on extern type"); + } + _add_mod_ns_item(mod, item.name, item.is_pub, ::HIR::ExternType {}); + break; + } _add_mod_ns_item( mod, item.name, item.is_pub, ::HIR::TypeItem::make_TypeAlias( LowerHIR_TypeAlias(e) ) ); ), (Struct, diff --git a/src/hir/hir.hpp b/src/hir/hir.hpp index fc4a19e8..48787583 100644 --- a/src/hir/hir.hpp +++ b/src/hir/hir.hpp @@ -215,6 +215,13 @@ struct StructMarkings unsigned int coerce_param = ~0u; }; +class ExternType +{ +public: + // TODO: do extern types need any associated data? + TraitMarkings m_markings; +}; + class Enum { public: @@ -367,6 +374,7 @@ TAGGED_UNION(TypeItem, Import, (Import, struct { ::HIR::SimplePath path; bool is_variant; unsigned int idx; }), (Module, Module), (TypeAlias, TypeAlias), // NOTE: These don't introduce new values + (ExternType, ExternType), (Enum, Enum), (Struct, Struct), (Union, Union), diff --git a/src/hir/serialise.cpp b/src/hir/serialise.cpp index c91cf93f..e5fe8ed5 100644 --- a/src/hir/serialise.cpp +++ b/src/hir/serialise.cpp @@ -834,6 +834,10 @@ (Union, m_out.write_tag(6); serialise(e); + ), + (ExternType, + m_out.write_tag(7); + serialise(e); ) ) } @@ -1020,6 +1024,11 @@ serialise(item.m_markings); } + void serialise(const ::HIR::ExternType& item) + { + TRACE_FUNCTION_F("ExternType"); + serialise(item.m_markings); + } void serialise(const ::HIR::Trait& item) { TRACE_FUNCTION_F("_trait:"); diff --git a/src/hir/type.cpp b/src/hir/type.cpp index 2c24e3e1..981ed0b3 100644 --- a/src/hir/type.cpp +++ b/src/hir/type.cpp @@ -85,6 +85,7 @@ void ::HIR::TypeRef::fmt(::std::ostream& os) const TU_MATCH(::HIR::TypeRef::TypePathBinding, (e.binding), (be), (Unbound, os << "/*?*/";), (Opaque, os << "/*O*/";), + (ExternType, os << "/*X*/";), (Struct, os << "/*S*/";), (Union, os << "/*U*/";), (Enum, os << "/*E*/";) @@ -782,6 +783,7 @@ bool ::HIR::TypeRef::match_test_generics(const Span& sp, const ::HIR::TypeRef& x TU_MATCH(::HIR::TypeRef::TypePathBinding, (*this), (e), (Unbound, return ::HIR::TypeRef::TypePathBinding::make_Unbound({}); ), (Opaque , return ::HIR::TypeRef::TypePathBinding::make_Opaque({}); ), + (ExternType, return ::HIR::TypeRef::TypePathBinding(e); ), (Struct, return ::HIR::TypeRef::TypePathBinding(e); ), (Union , return ::HIR::TypeRef::TypePathBinding(e); ), (Enum , return ::HIR::TypeRef::TypePathBinding(e); ) diff --git a/src/hir/type.hpp b/src/hir/type.hpp index 480b32c4..0c98773f 100644 --- a/src/hir/type.hpp +++ b/src/hir/type.hpp @@ -19,6 +19,7 @@ namespace HIR { +class ExternType; class Struct; class Union; class Enum; @@ -152,6 +153,7 @@ public: TAGGED_UNION_EX(TypePathBinding, (), Unbound, ( (Unbound, struct {}), // Not yet bound, either during lowering OR during resolution (when associated and still being resolved) (Opaque, struct {}), // Opaque, i.e. An associated type of a generic (or Self in a trait) + (ExternType, const ::HIR::ExternType*), (Struct, const ::HIR::Struct*), (Union, const ::HIR::Union*), (Enum, const ::HIR::Enum*) diff --git a/src/hir/visitor.cpp b/src/hir/visitor.cpp index 5c9c0dfa..f23bae88 100644 --- a/src/hir/visitor.cpp +++ b/src/hir/visitor.cpp @@ -47,6 +47,9 @@ void ::HIR::Visitor::visit_module(::HIR::ItemPath p, ::HIR::Module& mod) DEBUG("type " << name); this->visit_type_alias(p + name, e); ), + (ExternType, + DEBUG("extern type " << name); + ), (Enum, DEBUG("enum " << name); this->visit_enum(p + name, e); diff --git a/src/hir_conv/bind.cpp b/src/hir_conv/bind.cpp index 9b5043f4..b616a64f 100644 --- a/src/hir_conv/bind.cpp +++ b/src/hir_conv/bind.cpp @@ -456,6 +456,10 @@ namespace { (TypeAlias, BUG(sp, "TypeAlias encountered after `Resolve Type Aliases` - " << ty); ), + (ExternType, + e.binding = ::HIR::TypeRef::TypePathBinding::make_ExternType(&e3); + DEBUG("- " << ty); + ), (Struct, fix_param_count(sp, pe, e3.m_params, pe.m_params); e.binding = ::HIR::TypeRef::TypePathBinding::make_Struct(&e3); diff --git a/src/hir_conv/constant_evaluation.cpp b/src/hir_conv/constant_evaluation.cpp index 43a64bbb..3d1bf4a5 100644 --- a/src/hir_conv/constant_evaluation.cpp +++ b/src/hir_conv/constant_evaluation.cpp @@ -169,6 +169,8 @@ namespace { ), (Enum, ), + (ExternType, + ), (TypeAlias, ) ) diff --git a/src/hir_conv/markings.cpp b/src/hir_conv/markings.cpp index df7fbd36..d43db2b5 100644 --- a/src/hir_conv/markings.cpp +++ b/src/hir_conv/markings.cpp @@ -333,6 +333,7 @@ public: TU_MATCHA( (te.binding), (tpb), (Unbound, ), (Opaque, ), + (ExternType, markings_ptr = &tpb->m_markings; ), (Struct, markings_ptr = &tpb->m_markings; ), (Union , markings_ptr = &tpb->m_markings; ), (Enum , markings_ptr = &tpb->m_markings; ) diff --git a/src/hir_typeck/expr_check.cpp b/src/hir_typeck/expr_check.cpp index adb3c426..7d5a9c6f 100644 --- a/src/hir_typeck/expr_check.cpp +++ b/src/hir_typeck/expr_check.cpp @@ -462,6 +462,9 @@ namespace { (Union, BUG(sp, "Union in TupleVariant"); ), + (ExternType, + BUG(sp, "ExternType in TupleVariant"); + ), (Struct, ASSERT_BUG(sp, e->m_data.is_Tuple(), "Pointed struct in TupleVariant (" << node.m_path << ") isn't a Tuple"); fields_ptr = &e->m_data.as_Tuple(); @@ -522,6 +525,9 @@ namespace { (Union, TODO(sp, "Union in StructLiteral"); ), + (ExternType, + BUG(sp, "ExternType in StructLiteral"); + ), (Struct, if( e->m_data.is_Unit() ) { @@ -611,6 +617,9 @@ namespace { (Union, BUG(sp, "Union with _UnitVariant"); ), + (ExternType, + BUG(sp, "ExternType with _UnitVariant"); + ), (Struct, assert( e->m_data.is_Unit() ); ) diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 4a53bd4d..291dcd84 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -1144,6 +1144,9 @@ namespace { ), (Union, BUG(sp, "TupleVariant pointing to a union"); + ), + (ExternType, + BUG(sp, "TupleVariant pointing to a extern type"); ) ) assert(fields_ptr); @@ -1216,6 +1219,7 @@ namespace { TU_MATCH(::HIR::TypeRef::TypePathBinding, (ty.m_data.as_Path().binding), (e), (Unbound, ), (Opaque, ), + (ExternType, ), // Error? (Enum, const auto& var_name = ty_path.m_path.m_components.back(); const auto& enm = *e; @@ -4900,6 +4904,10 @@ void Context::require_sized(const Span& sp, const ::HIR::TypeRef& ty_) // Already checked by type_is_sized params_def = nullptr; ), + (ExternType, + static ::HIR::GenericParams empty_params; + params_def = &empty_params; + ), (Enum, params_def = &pb->m_params; ), @@ -5551,6 +5559,13 @@ namespace { (Opaque, // Handled above in bounded ), + (ExternType, + // Must be equal + if( sbe == dbe ) + { + return CoerceResult::Equality; + } + ), (Enum, // Must be equal if( sbe == dbe ) @@ -6474,6 +6489,9 @@ namespace { // TODO: Check bounds? return false; ), + (ExternType, + return false; + ), (Struct, if(pbe_a != pbe_b) return false; if( !pbe_a->m_struct_markings.can_unsize ) diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index 1af269ad..5c0696e3 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -2477,6 +2477,9 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, ), (Opaque, ), + (ExternType, + markings = &tpb->m_markings; + ), (Struct, markings = &tpb->m_markings; ), @@ -2710,6 +2713,9 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, ), (Union, TODO(sp, "Check auto trait destructure on union " << type); + ), + (ExternType, + TODO(sp, "Check auto trait destructure on extern type " << type); ) ) DEBUG("- Nothing failed, calling callback"); @@ -3141,6 +3147,10 @@ bool TraitResolution::trait_contains_type(const Span& sp, const ::HIR::GenericPa (Opaque, // TODO: Check bounds ), + (ExternType, + // Is it sized? No. + return ::HIR::Compare::Unequal; + ), (Enum, // HAS to be Sized ), @@ -4323,6 +4333,9 @@ bool TraitResolution::find_field(const Span& sp, const ::HIR::TypeRef& ty, const (Enum, // No fields on enums either ), + (ExternType, + // No fields on extern types + ), (Union, const auto& unm = *be; const auto& params = e.path.m_data.as_Generic().m_params; diff --git a/src/hir_typeck/outer.cpp b/src/hir_typeck/outer.cpp index 63e92d8b..6a8e8b35 100644 --- a/src/hir_typeck/outer.cpp +++ b/src/hir_typeck/outer.cpp @@ -52,6 +52,10 @@ namespace { (TypeAlias, BUG(sp, "Type path pointed to type alias - " << path); ), + (ExternType, + static ::HIR::GenericParams empty_params; + return empty_params; + ), (Module, BUG(sp, "Type path pointed to module - " << path); ), diff --git a/src/hir_typeck/static.cpp b/src/hir_typeck/static.cpp index 457bd44e..ce7faf6c 100644 --- a/src/hir_typeck/static.cpp +++ b/src/hir_typeck/static.cpp @@ -851,6 +851,9 @@ bool StaticTraitResolve::find_impl__check_crate( ), (Union, TODO(sp, "Check auto trait destructure on union " << type); + ), + (ExternType, + TODO(sp, "Check auto trait destructure on extern type " << type); ) ) DEBUG("- Nothing failed, calling callback"); @@ -1629,6 +1632,10 @@ bool StaticTraitResolve::type_is_sized(const Span& sp, const ::HIR::TypeRef& ty) return false; } ), + (ExternType, + // Extern types aren't Sized + return false; + ), (Enum, ), (Union, @@ -1732,6 +1739,10 @@ bool StaticTraitResolve::type_is_impossible(const Span& sp, const ::HIR::TypeRef (Union, // TODO: Check all variants? Or just one? TODO(sp, "type_is_impossible for union " << ty); + ), + (ExternType, + // Extern types are possible, just not usable + return false; ) ) return true; @@ -2032,6 +2043,10 @@ bool StaticTraitResolve::type_needs_drop_glue(const Span& sp, const ::HIR::TypeR (Union, // Unions don't have drop glue unless they impl Drop return false; + ), + (ExternType, + // Extern types don't have drop glue + return false; ) ) ), diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index 9ce40a74..fb214dda 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -2405,6 +2405,9 @@ namespace { TU_ARMA(Union, e) { BUG(node.span(), "_StructLiteral Union isn't valid?"); } + TU_ARMA(ExternType, e) { + BUG(node.span(), "_StructLiteral ExternType isn't valid?"); + } TU_ARMA(Struct, e) { if(e->m_data.is_Unit()) { m_builder.set_result( node.span(), ::MIR::RValue::make_Struct({ diff --git a/src/mir/from_hir_match.cpp b/src/mir/from_hir_match.cpp index 264c74c5..6fb77a3b 100644 --- a/src/mir/from_hir_match.cpp +++ b/src/mir/from_hir_match.cpp @@ -802,6 +802,9 @@ void PatternRulesetBuilder::append_from_lit(const Span& sp, const ::HIR::Literal ) ) ), + (ExternType, + TODO(sp, "Match extern type"); + ), (Union, TODO(sp, "Match union"); ), @@ -1217,6 +1220,9 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa (Union, TODO(sp, "Match over union - " << ty); ), + (ExternType, + TODO(sp, "Match over extern type - " << ty); + ), (Enum, auto monomorph = [&](const auto& ty) { auto rv = monomorphise_type(sp, pbe->m_params, e.path.m_data.as_Generic().m_params, ty); @@ -1738,6 +1744,9 @@ namespace { (Opaque, BUG(sp, "Destructuring an opaque type - " << *cur_ty); ), + (ExternType, + BUG(sp, "Destructuring an extern type - " << *cur_ty); + ), (Struct, // TODO: Should this do a call to expand_associated_types? auto monomorph = [&](const auto& ty) { @@ -2173,6 +2182,9 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& (Union, TODO(sp, "Match over Union"); ), + (ExternType, + TODO(sp, "Match over ExternType"); + ), (Enum, auto monomorph = [&](const auto& ty) { auto rv = monomorphise_type(sp, pbe->m_params, te.path.m_data.as_Generic().m_params, ty); @@ -2827,6 +2839,9 @@ void MatchGenGrouped::gen_dispatch(const ::std::vector& rules, s (Union, TODO(sp, "Match over Union"); ), + (ExternType, + TODO(sp, "Match over ExternType - " << ty); + ), (Enum, ) ) diff --git a/src/resolve/absolute.cpp b/src/resolve/absolute.cpp index d2609e9e..75a0857f 100644 --- a/src/resolve/absolute.cpp +++ b/src/resolve/absolute.cpp @@ -350,7 +350,7 @@ namespace auto v = mod.m_value_items.find(name); if( v != mod.m_value_items.end() ) { const auto& b = v->second.path.m_bindings.value; - if( const auto* be = b.opt_EnumVar() ) { + if( /*const auto* be =*/ b.opt_EnumVar() ) { DEBUG("- TY: Enum variant " << v->second.path); path = ::AST::Path( v->second.path ); return true; @@ -832,6 +832,9 @@ namespace { (TypeAlias, pb.type = ::AST::PathBinding_Type::make_TypeAlias({nullptr/*, &e*/}); ), + (ExternType, + pb.type = ::AST::PathBinding_Type::make_TypeAlias({nullptr/*, &e*/}); + ), (Struct, pb.type = ::AST::PathBinding_Type::make_Struct({nullptr, &e}); ), @@ -880,8 +883,8 @@ namespace { if( it == hmod->m_mod_items.end() ) ERROR(sp, E0000, "Couldn't find path component '" << n.name() << "' of " << path); - TU_MATCH(::HIR::TypeItem, (it->second->ent), (e), - (Import, + TU_MATCH_HDRA( (it->second->ent), {) + TU_ARMA(Import, e) { // - Update path then restart auto newpath = AST::Path(e.path.m_crate_name, {}); for(const auto& n : e.path.m_components) @@ -892,11 +895,11 @@ namespace { // TODO: Recursion limit Resolve_Absolute_Path_BindAbsolute(context, sp, mode, path); return ; - ), - (Module, + } + TU_ARMA(Module, e) { hmod = &e; - ), - (Trait, + } + TU_ARMA(Trait, e) { auto trait_path = ::AST::Path( crate.m_name, {} ); for(unsigned int j = start; j <= i; j ++) trait_path.nodes().push_back( path_abs.nodes[j].name() ); @@ -940,23 +943,15 @@ namespace { path = mv$(new_path); return Resolve_Absolute_Path_BindUFCS(context, sp, mode, path); - ), - (TypeAlias, - path = split_into_crate(sp, mv$(path), start, crate.m_name); - path = split_into_ufcs_ty(sp, mv$(path), i-start); - return Resolve_Absolute_Path_BindUFCS(context, sp, mode, path); - ), - (Struct, - path = split_into_crate(sp, mv$(path), start, crate.m_name); - path = split_into_ufcs_ty(sp, mv$(path), i-start); - return Resolve_Absolute_Path_BindUFCS(context, sp, mode, path); - ), - (Union, + } + case ::HIR::TypeItem::TAG_ExternType: + case ::HIR::TypeItem::TAG_TypeAlias: + case ::HIR::TypeItem::TAG_Struct: + case ::HIR::TypeItem::TAG_Union: path = split_into_crate(sp, mv$(path), start, crate.m_name); path = split_into_ufcs_ty(sp, mv$(path), i-start); return Resolve_Absolute_Path_BindUFCS(context, sp, mode, path); - ), - (Enum, + TU_ARMA(Enum, e) { const auto& last_node = path_abs.nodes.back(); // If this refers to an enum variant, return the full path auto idx = e.find_variant(last_node.name()); @@ -982,8 +977,8 @@ namespace { path = split_into_crate(sp, mv$(path), start, crate.m_name); path = split_into_ufcs_ty(sp, mv$(path), i-start); return Resolve_Absolute_Path_BindUFCS(context, sp, mode, path); - ) - ) + } + } } const auto& name = path_abs.nodes.back().name(); @@ -1007,6 +1002,9 @@ namespace { (Module, path.m_bindings.type = ::AST::PathBinding_Type::make_Module({nullptr, &e}); ), + (ExternType, + path.m_bindings.type = ::AST::PathBinding_Type::make_TypeAlias({nullptr/*, &e*/}); + ), (TypeAlias, path.m_bindings.type = ::AST::PathBinding_Type::make_TypeAlias({nullptr/*, &e*/}); ), diff --git a/src/resolve/index.cpp b/src/resolve/index.cpp index ec1fcd8d..ddeffa0c 100644 --- a/src/resolve/index.cpp +++ b/src/resolve/index.cpp @@ -241,7 +241,15 @@ void Resolve_Index_Module_Base(const AST::Crate& crate, AST::Module& mod) i.is_pub, i_data.name, mv$(path), e.mac }); } - // TODO: Other imports (e.g. derives, which have different naming structures) + TU_ARMA(ProcMacro, e) { + TODO(sp, "ProcMacro import"); + } + TU_ARMA(ProcMacroAttribute, e) { + TODO(sp, "ProcMacroAttribute import"); + } + TU_ARMA(ProcMacroDerive, e) { + TODO(sp, "ProcMacroDerive import"); + } }} } else @@ -318,6 +326,9 @@ void Resolve_Index_Module_Wildcard__glob_in_hir_mod(const Span& sp, const AST::C p.m_bindings.type = ::AST::PathBinding_Type::make_Enum({nullptr}); ), (TypeAlias, + p.m_bindings.type = ::AST::PathBinding_Type::make_TypeAlias({nullptr}); + ), + (ExternType, p.m_bindings.type = ::AST::PathBinding_Type::make_TypeAlias({nullptr}); ) ) diff --git a/src/resolve/use.cpp b/src/resolve/use.cpp index 8c9266a2..95e6d2c1 100644 --- a/src/resolve/use.cpp +++ b/src/resolve/use.cpp @@ -645,6 +645,9 @@ namespace { (TypeAlias, rv.type = ::AST::PathBinding_Type::make_TypeAlias({nullptr}); ), + (ExternType, + rv.type = ::AST::PathBinding_Type::make_TypeAlias({nullptr}); // Lazy. + ), (Enum, rv.type = ::AST::PathBinding_Type::make_Enum({nullptr, &e}); ), diff --git a/src/trans/auto_impls.cpp b/src/trans/auto_impls.cpp index 418a338b..877659b2 100644 --- a/src/trans/auto_impls.cpp +++ b/src/trans/auto_impls.cpp @@ -74,7 +74,7 @@ void Trans_AutoImpl_Clone(State& state, ::HIR::TypeRef ty) // For each field of the tuple, create a clone (either using Copy if posible, or calling Clone::clone) for(const auto& subty : te) { - auto fld_lvalue = ::MIR::LValue::make_Field({ box$(::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Argument({ 0 })) })), values.size() }); + auto fld_lvalue = ::MIR::LValue::make_Field({ box$(::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Argument({ 0 })) })), static_cast(values.size()) }); if( state.resolve.type_is_copy(sp, subty) ) { values.push_back( ::std::move(fld_lvalue) ); @@ -94,8 +94,8 @@ void Trans_AutoImpl_Clone(State& state, ::HIR::TypeRef ty) ::MIR::RValue::make_Borrow({ 0, ::HIR::BorrowType::Shared, mv$(fld_lvalue) }) })); bb.terminator = ::MIR::Terminator::make_Call({ - mir_fcn.blocks.size() + 2, // return block (after the panic block below) - mir_fcn.blocks.size() + 1, // panic block (next block) + static_cast(mir_fcn.blocks.size() + 2), // return block (after the panic block below) + static_cast(mir_fcn.blocks.size() + 1), // panic block (next block) res_lv.clone(), ::MIR::CallTarget( ::HIR::Path(subty.clone(), lang_Clone, "clone") ), ::make_vec1<::MIR::Param>( ::std::move(borrow_lv) ) diff --git a/src/trans/codegen.cpp b/src/trans/codegen.cpp index 9e93caba..b2b614a9 100644 --- a/src/trans/codegen.cpp +++ b/src/trans/codegen.cpp @@ -43,6 +43,9 @@ void Trans_Codegen(const ::std::string& outfile, const TransOptions& opt, const TU_MATCHA( (te.binding), (tpb), (Unbound, throw ""; ), (Opaque, throw ""; ), + (ExternType, + //codegen->emit_extern_type(sp, te.path.m_data.as_Generic(), *tpb); + ), (Struct, codegen->emit_struct(sp, te.path.m_data.as_Generic(), *tpb); ), diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 2c40c991..979da88d 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -1013,6 +1013,9 @@ namespace { (Struct, m_of << "struct s_" << Trans_Mangle(te.path) << ";\n"; ), + (ExternType, + m_of << "struct x_" << Trans_Mangle(te.path) << ";\n"; + ), (Union, m_of << "union u_" << Trans_Mangle(te.path) << ";\n"; ), @@ -1837,6 +1840,7 @@ namespace { TU_MATCHA((te.binding), (pbe), (Unbound, MIR_BUG(*m_mir_res, "Unbound type path " << ty); ), (Opaque, MIR_BUG(*m_mir_res, "Opaque type path " << ty); ), + (ExternType, MIR_BUG(*m_mir_res, "Extern type literal " << ty); ), (Struct, TU_MATCHA( (pbe->m_data), (se), (Unit, @@ -5351,6 +5355,9 @@ namespace { TU_MATCHA((te.binding), (pbe), (Unbound, MIR_BUG(*m_mir_res, "Unbound type path " << ty); ), (Opaque, MIR_BUG(*m_mir_res, "Opaque type path " << ty); ), + (ExternType, + MIR_BUG(*m_mir_res, "Extern type literal"); + ), (Struct, TU_MATCHA( (pbe->m_data), (se), (Unit, @@ -5835,6 +5842,10 @@ namespace { (Enum, m_of << "struct e_" << Trans_Mangle(te.path); ), + (ExternType, + m_of << "struct x_" << Trans_Mangle(te.path); + //return ; + ), (Unbound, MIR_BUG(*m_mir_res, "Unbound type path in trans - " << ty); ), diff --git a/src/trans/enumerate.cpp b/src/trans/enumerate.cpp index 6aeb3485..c326d125 100644 --- a/src/trans/enumerate.cpp +++ b/src/trans/enumerate.cpp @@ -570,6 +570,9 @@ namespace { (Opaque, BUG(Span(), "Opaque type hit in enumeration - " << ty); ), + (ExternType, + // No innards to visit + ), (Struct, visit_struct(te.path.m_data.as_Generic(), *tpb); ), @@ -1064,15 +1067,10 @@ void Trans_Enumerate_Types(EnumState& state) TU_MATCHA( (te.binding), (tpb), (Unbound, ), (Opaque, ), - (Struct, - markings_ptr = &tpb->m_markings; - ), - (Union, - markings_ptr = &tpb->m_markings; - ), - (Enum, - markings_ptr = &tpb->m_markings; - ) + (ExternType, markings_ptr = &tpb->m_markings; ), + (Struct, markings_ptr = &tpb->m_markings; ), + (Union, markings_ptr = &tpb->m_markings; ), + (Enum, markings_ptr = &tpb->m_markings; ) ) ASSERT_BUG(Span(), markings_ptr, "Path binding not set correctly - " << ty); -- cgit v1.2.3 From f907e918d75bff4d0c5030fb5c626194c5f2dc89 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 3 Feb 2019 21:51:26 +0800 Subject: Typecheck Expresions - closure->fn and closure Clone rough --- src/hir_typeck/expr_cs.cpp | 32 ++++++++++++++++++++++++++++++++ src/hir_typeck/helpers.cpp | 4 ++++ 2 files changed, 36 insertions(+) diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 291dcd84..794f3a9c 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -5965,6 +5965,38 @@ namespace { return CoerceResult::Equality; } } + else if( src.m_data.is_Closure() ) + { + if( dst.m_data.is_Function() ) + { + const auto& de = dst.m_data.as_Function(); + const auto& se = src.m_data.as_Closure(); + auto& node_ptr = *node_ptr_ptr; + auto span = node_ptr->span(); + if( de.m_abi != ABI_RUST ) { + ERROR(span, E0000, "Cannot use closure for extern function pointer"); + } + if( de.m_arg_types.size() != se.m_arg_types.size() ) { + ERROR(span, E0000, "Mismatched argument count coercing closure to fn(...)"); + } + for(size_t i = 0; i < de.m_arg_types.size(); i++) + { + context.equate_types(sp, de.m_arg_types[i], se.m_arg_types[i]); + } + context.equate_types(sp, *de.m_rettype, *se.m_rettype); + node_ptr = NEWNODE( dst.clone(), span, _Cast, mv$(node_ptr), dst.clone() ); + return CoerceResult::Custom; + } + else if( const auto* dep = dst.m_data.opt_Infer() ) + { + context.possible_equate_type_coerce_from(dep->index, src); + return CoerceResult::Unknown; + } + else + { + return CoerceResult::Equality; + } + } else { // TODO: ! should be handled above or in caller? diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index 5c0696e3..dd6409c0 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -3354,6 +3354,10 @@ bool TraitResolution::trait_contains_type(const Span& sp, const ::HIR::GenericPa (Function, return ::HIR::Compare::Equal; ), + (Closure, + // NOTE: This isn't strictly true, we're leaving the actual checking up to the validate pass + return ::HIR::Compare::Equal; + ), (Array, // TODO: Clone here? return type_is_copy(sp, *e.inner); -- cgit v1.2.3 From 054faa303107d5940463465d729cc0d1e2ec8473 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 9 Feb 2019 22:32:40 +0800 Subject: Typecheck - Various fixes for librustc --- src/hir/pattern.hpp | 4 ++ src/hir/type.cpp | 30 +++++----- src/hir_conv/resolve_ufcs.cpp | 5 ++ src/hir_expand/annotate_value_usage.cpp | 6 ++ src/hir_typeck/expr_cs.cpp | 103 +++++++++++++++++++++++--------- src/hir_typeck/helpers.cpp | 3 +- 6 files changed, 108 insertions(+), 43 deletions(-) diff --git a/src/hir/pattern.hpp b/src/hir/pattern.hpp index b17ebcb4..cd6c7422 100644 --- a/src/hir/pattern.hpp +++ b/src/hir/pattern.hpp @@ -102,6 +102,10 @@ struct Pattern const Struct* binding; ::std::vector< ::std::pair< ::std::string, Pattern> > sub_patterns; bool is_exhaustive; + + bool is_wildcard() const { + return sub_patterns.empty() && !is_exhaustive; + } } ), // Refutable (Value, struct { Value val; } ), diff --git a/src/hir/type.cpp b/src/hir/type.cpp index 981ed0b3..ff4742e6 100644 --- a/src/hir/type.cpp +++ b/src/hir/type.cpp @@ -177,12 +177,10 @@ void ::HIR::TypeRef::fmt(::std::ostream& os) const } TU_ARM(m_data, Closure, e) { os << "closure["< " << *e.m_rettype; - */ } } } @@ -901,6 +899,22 @@ bool ::HIR::TypeRef::match_test_generics(const Span& sp, const ::HIR::TypeRef& x return Compare::Equal; } + // Unbound paths and placeholder generics + if( left.m_data.tag() != right.m_data.tag() ) { + if( left.m_data.is_Path() && left.m_data.as_Path().binding.is_Unbound() ) { + return Compare::Fuzzy; + } + if( right.m_data.is_Path() && right.m_data.as_Path().binding.is_Unbound() ) { + return Compare::Fuzzy; + } + if( left.m_data.is_Generic() && (left.m_data.as_Generic().binding >> 8) == 2 ) { + return Compare::Fuzzy; + } + if( right.m_data.is_Generic() && (right.m_data.as_Generic().binding >> 8) == 2 ) { + return Compare::Fuzzy; + } + } + // If left is infer TU_IFLET(::HIR::TypeRef::Data, left.m_data, Infer, e, switch(e.ty_class) @@ -1025,18 +1039,6 @@ bool ::HIR::TypeRef::match_test_generics(const Span& sp, const ::HIR::TypeRef& x // - See `(Generic,` below if( left.m_data.tag() != right.m_data.tag() ) { - if( left.m_data.is_Path() && left.m_data.as_Path().binding.is_Unbound() ) { - return Compare::Fuzzy; - } - if( right.m_data.is_Path() && right.m_data.as_Path().binding.is_Unbound() ) { - return Compare::Fuzzy; - } - if( left.m_data.is_Generic() && (left.m_data.as_Generic().binding >> 8) == 2 ) { - return Compare::Fuzzy; - } - if( right.m_data.is_Generic() && (right.m_data.as_Generic().binding >> 8) == 2 ) { - return Compare::Fuzzy; - } return Compare::Unequal; } TU_MATCH(::HIR::TypeRef::Data, (left.m_data, right.m_data), (le, re), diff --git a/src/hir_conv/resolve_ufcs.cpp b/src/hir_conv/resolve_ufcs.cpp index 19ec84ba..90b3868d 100644 --- a/src/hir_conv/resolve_ufcs.cpp +++ b/src/hir_conv/resolve_ufcs.cpp @@ -187,6 +187,11 @@ namespace { upper_visitor.visit_path(node.m_path, ::HIR::Visitor::PathContext::VALUE); ::HIR::ExprVisitorDef::visit(node); } + void visit(::HIR::ExprNode_StructLiteral& node) override + { + upper_visitor.visit_path(node.m_path, ::HIR::Visitor::PathContext::TYPE); + ::HIR::ExprVisitorDef::visit(node); + } void visit(::HIR::ExprNode_Match& node) override { diff --git a/src/hir_expand/annotate_value_usage.cpp b/src/hir_expand/annotate_value_usage.cpp index 1754bdac..e763586c 100644 --- a/src/hir_expand/annotate_value_usage.cpp +++ b/src/hir_expand/annotate_value_usage.cpp @@ -520,6 +520,12 @@ namespace { ), (Struct, const auto& str = *pe.binding; + if( pe.is_wildcard() ) + return ::HIR::ValueUsage::Borrow; + if( pe.sub_patterns.empty() && (TU_TEST1(str.m_data, Tuple, .empty()) || str.m_data.is_Unit()) ) { + return ::HIR::ValueUsage::Borrow; + } + ASSERT_BUG(sp, str.m_data.is_Named(), "Struct pattern on non-brace struct"); const auto& flds = str.m_data.as_Named(); auto monomorph_cb = monomorphise_type_get_cb(sp, nullptr, &pe.path.m_params, nullptr); diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 794f3a9c..70b9c26c 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -1196,10 +1196,9 @@ namespace { { const auto& sp = node.span(); TRACE_FUNCTION_F(&node << " " << node.m_path << "{...} [" << (node.m_is_struct ? "struct" : "enum") << "]"); - ASSERT_BUG(sp, node.m_path.m_data.is_Generic(), "Struct literal with non-Generic path - " << node.m_path); - auto& ty_path = node.m_path.m_data.as_Generic(); - this->add_ivars_generic_path(node.span(), ty_path); + this->add_ivars_path(node.span(), node.m_path); + for( auto& val : node.m_values ) { this->context.add_ivars( val.second->m_res_type ); } @@ -1207,6 +1206,15 @@ namespace { this->context.add_ivars( node.m_base_value->m_res_type ); } + // TODO: The path can be a Ufcs (any type) + if( !node.m_path.m_data.is_Generic() ) + { + auto t = this->context.m_resolve.expand_associated_types(sp, ::HIR::TypeRef::new_path( mv$(node.m_path), {} )); + node.m_path = mv$(t.m_data.as_Path().path); + } + ASSERT_BUG(sp, node.m_path.m_data.is_Generic(), "Struct literal with non-Generic path - " << node.m_path); + auto& ty_path = node.m_path.m_data.as_Generic(); + // - Create ivars in path, and set result type const auto ty = this->get_structenum_ty(node.span(), node.m_is_struct, ty_path); this->context.equate_types(node.span(), node.m_res_type, ty); @@ -3997,8 +4005,21 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T rv = true; } TU_ARM(pattern.m_data, Box, pe) { - // TODO: inner pattern - TODO(sp, "Match ergonomics - box pattern"); + // Box + if( TU_TEST2(ty.m_data, Path, .path.m_data, Generic, .m_path == context.m_lang_Box) ) + { + const auto& path = ty.m_data.as_Path().path.m_data.as_Generic(); + const auto& inner = path.m_params.m_types.at(0); + rv = this->revisit_inner(context, *pe.sub, inner, binding_mode); + } + else + { + TODO(sp, "Match ergonomics - box pattern - Non Box type: " << ty); + //auto inner = this->m_ivars.new_ivar_tr(); + //this->handle_pattern_direct_inner(sp, *e.sub, inner); + //::HIR::GenericPath path { m_lang_Box, ::HIR::PathParams(mv$(inner)) }; + //this->equate_types( sp, type, ::HIR::TypeRef::new_path(mv$(path), ::HIR::TypeRef::TypePathBinding(&m_crate.get_struct_by_path(sp, m_lang_Box))) ); + } } TU_ARM(pattern.m_data, Ref, pe) { BUG(sp, "Match ergonomics - & pattern"); @@ -4082,25 +4103,34 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T assert(e.binding); const auto& str = *e.binding; - // - assert check from earlier pass - ASSERT_BUG(sp, str.m_data.is_Named(), "Struct pattern on non-Named struct"); - const auto& sd = str.m_data.as_Named(); - const auto& params = e.path.m_params; - - rv = true; - for( auto& field_pat : e.sub_patterns ) + //if( ! e.is_wildcard() ) + if( e.sub_patterns.empty() ) { - unsigned int f_idx = ::std::find_if( sd.begin(), sd.end(), [&](const auto& x){ return x.first == field_pat.first; } ) - sd.begin(); - if( f_idx == sd.size() ) { - ERROR(sp, E0000, "Struct " << e.path << " doesn't have a field " << field_pat.first); - } - const ::HIR::TypeRef& field_type = sd[f_idx].second.ent; - if( monomorphise_type_needed(field_type) ) { - auto field_type_mono = monomorphise_type(sp, str.m_params, params, field_type); - rv &= this->revisit_inner(context, field_pat.second, field_type_mono, binding_mode); - } - else { - rv &= this->revisit_inner(context, field_pat.second, field_type, binding_mode); + // TODO: Check the field count? + rv = true; + } + else + { + // - assert check from earlier pass + ASSERT_BUG(sp, str.m_data.is_Named(), "Struct pattern on non-Named struct"); + const auto& sd = str.m_data.as_Named(); + const auto& params = e.path.m_params; + + rv = true; + for( auto& field_pat : e.sub_patterns ) + { + unsigned int f_idx = ::std::find_if( sd.begin(), sd.end(), [&](const auto& x){ return x.first == field_pat.first; } ) - sd.begin(); + if( f_idx == sd.size() ) { + ERROR(sp, E0000, "Struct " << e.path << " doesn't have a field " << field_pat.first); + } + const ::HIR::TypeRef& field_type = sd[f_idx].second.ent; + if( monomorphise_type_needed(field_type) ) { + auto field_type_mono = monomorphise_type(sp, str.m_params, params, field_type); + rv &= this->revisit_inner(context, field_pat.second, field_type_mono, binding_mode); + } + else { + rv &= this->revisit_inner(context, field_pat.second, field_type, binding_mode); + } } } } @@ -4684,7 +4714,7 @@ void Context::handle_pattern_direct_inner(const Span& sp, ::HIR::Pattern& pat, c this->add_ivars_params( e.path.m_params ); this->equate_types( sp, type, ::HIR::TypeRef::new_path(e.path.clone(), ::HIR::TypeRef::TypePathBinding(e.binding)) ); - if( e.sub_patterns.empty() ) + if( e.is_wildcard() ) return ; assert(e.binding); @@ -5140,6 +5170,7 @@ namespace { { DEBUG("- Moving into block"); assert( p->m_value_node ); + // Block result and the inner node's result must be the same type ASSERT_BUG( p->span(), context.m_ivars.types_equal(p->m_res_type, p->m_value_node->m_res_type), "Block and result mismatch - " << context.m_ivars.fmt_type(p->m_res_type) << " != " << context.m_ivars.fmt_type(p->m_value_node->m_res_type)); // - Override the the result type to the desired result @@ -5253,7 +5284,7 @@ namespace { return CoerceResult::Equality; } context.possible_equate_type_unsize_to(sep->index, dst); - DEBUG("Src ivar"); + DEBUG("Src is ivar (" << src << "), return Unknown"); return CoerceResult::Unknown; } else @@ -5926,10 +5957,20 @@ namespace { context.m_ivars.mark_change(); // Continue on with coercion (now that node_ptr is updated) - switch( check_unsize_tys(context, sp, *dep->inner, *se.inner, node_ptr_ptr) ) + switch( check_unsize_tys(context, sp, *dep->inner, *se.inner, &node_ptr) ) { case CoerceResult::Unknown: - return CoerceResult::Unknown; + // Add new coercion at the new inner point + if( &node_ptr != node_ptr_ptr ) + { + DEBUG("Unknown check_unsize_tys after autoderef - " << dst << " := " << node_ptr->m_res_type); + context.equate_types_coerce(sp, dst, node_ptr); + return CoerceResult::Custom; + } + else + { + return CoerceResult::Unknown; + } case CoerceResult::Custom: return CoerceResult::Custom; case CoerceResult::Equality: @@ -6824,9 +6865,17 @@ namespace { const auto& re_inner = r.m_data.is_Borrow() ? r.m_data.as_Borrow().inner : r.m_data.as_Pointer().inner; if( le.type < re_borrow_type ) { + if( !context.m_ivars.types_equal(*le.inner, *re_inner) ) { + return DedupKeep::Both; + } + DEBUG("- Remove " << r); return DedupKeep::Left; } else if( le.type > re_borrow_type ) { + if( !context.m_ivars.types_equal(*le.inner, *re_inner) ) { + return DedupKeep::Both; + } + DEBUG("- Remove " << l); return DedupKeep::Right; } else { diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index dd6409c0..15c61bc7 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -3359,8 +3359,7 @@ bool TraitResolution::trait_contains_type(const Span& sp, const ::HIR::GenericPa return ::HIR::Compare::Equal; ), (Array, - // TODO: Clone here? - return type_is_copy(sp, *e.inner); + return type_is_clone(sp, *e.inner); ) ) } -- cgit v1.2.3 From ebe84a819577aaf0d06171a33e343e04b1d4717e Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 24 Feb 2019 16:12:56 +0800 Subject: Typecheck Expr - Refactor of ivar possibilities to simplify logic --- src/common.hpp | 5 + src/hir_typeck/expr_cs.cpp | 1085 ++++++++++++++++++-------------------------- src/hir_typeck/helpers.cpp | 10 +- 3 files changed, 444 insertions(+), 656 deletions(-) diff --git a/src/common.hpp b/src/common.hpp index f46f93fd..7521b2de 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -243,6 +243,11 @@ inline Join join(const char *sep, const ::std::vector v) { namespace std { +template +inline auto operator<<(::std::ostream& os, const T& v) -> decltype(v.fmt(os)) { + return v.fmt(os); +} + template inline ::std::ostream& operator<<(::std::ostream& os, const ::std::vector& v) { if( v.size() > 0 ) diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 70b9c26c..90146635 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -27,6 +27,15 @@ namespace { rv.m_path.m_components.pop_back(); return rv; } + + bool type_contains_impl_placeholder(const ::HIR::TypeRef& t) { + return visit_ty_with(t, [&](const auto& ty)->bool { + if( ty.m_data.is_Generic() && ty.m_data.as_Generic().binding >> 8 == 2 ) { + return true; + } + return false; + }); + } } #define NEWNODE(TY, SP, CLASS, ...) mk_exprnodep(new HIR::ExprNode##CLASS(SP ,## __VA_ARGS__), TY) @@ -221,7 +230,7 @@ struct Context /// Default type //void possible_equate_type_def(unsigned int ivar_index, const ::HIR::TypeRef& t); /// Add a possible type for an ivar (which is used if only one possibility meets available bounds) - void possible_equate_type_bound(unsigned int ivar_index, const ::HIR::TypeRef& t); + void possible_equate_type_bound(const Span& sp, unsigned int ivar_index, const ::HIR::TypeRef& t); void possible_equate_type(unsigned int ivar_index, const ::HIR::TypeRef& t, bool is_to, bool is_borrow); void possible_equate_type_disable(unsigned int ivar_index, bool is_to); @@ -2726,7 +2735,9 @@ namespace { const auto& sp = node.span(); const auto& ty = this->context.get_type(node.m_value->m_res_type); - TRACE_FUNCTION_F("(CallMethod) {" << this->context.m_ivars.fmt_type(ty) << "}." << node.m_method << node.m_params); + TRACE_FUNCTION_F("(CallMethod) {" << this->context.m_ivars.fmt_type(ty) << "}." << node.m_method << node.m_params + << "(" << FMT_CB(os, for( const auto& arg_node : node.m_args ) os << this->context.m_ivars.fmt_type(arg_node->m_res_type) << ", ";) << ")" + ); // Make sure that no mentioned types are inferred until this method is known this->context.equate_types_from_shadow(node.span(), node.m_res_type); @@ -2747,7 +2758,7 @@ namespace { if( possible_methods.empty() ) { //ERROR(sp, E0000, "Could not find method `" << method_name << "` on type `" << top_ty << "`"); - ERROR(sp, E0000, "No applicable methods for {" << ty << "}." << node.m_method); + ERROR(sp, E0000, "No applicable methods for {" << this->context.m_ivars.fmt_type(ty) << "}." << node.m_method); } if( possible_methods.size() > 1 ) { @@ -3399,18 +3410,8 @@ void Context::equate_types(const Span& sp, const ::HIR::TypeRef& li, const ::HIR // Instantly apply equality TRACE_FUNCTION_F(li << " == " << ri); - visit_ty_with(ri, [&](const auto& ty)->bool { - if( ty.m_data.is_Generic() && ty.m_data.as_Generic().binding >> 8 == 2 ) { - BUG(sp, "Type contained an impl placeholder parameter - " << ri); - } - return false; - }); - visit_ty_with(li, [&](const auto& ty)->bool { - if( ty.m_data.is_Generic() && ty.m_data.as_Generic().binding >> 8 == 2 ) { - BUG(sp, "Type contained an impl placeholder parameter - " << li); - } - return false; - }); + ASSERT_BUG(sp, !type_contains_impl_placeholder(ri), "Type contained an impl placeholder parameter - " << ri); + ASSERT_BUG(sp, !type_contains_impl_placeholder(li), "Type contained an impl placeholder parameter - " << li); ::HIR::TypeRef l_tmp; ::HIR::TypeRef r_tmp; @@ -3956,6 +3957,11 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T MatchErgonomicsRevisit::disable_possibilities_on_bindings(sp, context, pattern); return false; } + if( TU_TEST1(ty_p->m_data, Path, .binding.is_Unbound()) ) { + // TODO: Visit all inner bindings and disable coercion fallbacks on them. + MatchErgonomicsRevisit::disable_possibilities_on_bindings(sp, context, pattern); + return false; + } const auto& ty = *ty_p; // Here we have a known type and binding mode for this pattern @@ -5005,7 +5011,7 @@ void Context::possible_equate_type(unsigned int ivar_index, const ::HIR::TypeRef ); list.push_back( t.clone() ); } -void Context::possible_equate_type_bound(unsigned int ivar_index, const ::HIR::TypeRef& t) { +void Context::possible_equate_type_bound(const Span& sp, unsigned int ivar_index, const ::HIR::TypeRef& t) { { ::HIR::TypeRef ty_l; ty_l.m_data.as_Infer().index = ivar_index; @@ -5015,6 +5021,8 @@ void Context::possible_equate_type_bound(unsigned int ivar_index, const ::HIR::T DEBUG("IVar " << ivar_index << " is actually " << real_ty); return ; } + + ASSERT_BUG(sp, !type_contains_impl_placeholder(t), "Type contained an impl placeholder parameter - " << t); } if( ivar_index >= possible_ivar_vals.size() ) { @@ -5219,8 +5227,11 @@ namespace { }; // TODO: Add a (two?) callback(s) that handle type equalities (and possible equalities) so this function doesn't have to mutate the context - CoerceResult check_unsize_tys(Context& context, const Span& sp, const ::HIR::TypeRef& dst_raw, const ::HIR::TypeRef& src_raw, ::HIR::ExprNodeP* node_ptr_ptr=nullptr) + CoerceResult check_unsize_tys(Context& context_mut_r, const Span& sp, const ::HIR::TypeRef& dst_raw, const ::HIR::TypeRef& src_raw, ::HIR::ExprNodeP* node_ptr_ptr=nullptr, bool allow_mutate=true) { + Context* context_mut = (allow_mutate ? &context_mut_r : nullptr); + const Context& context = context_mut_r; + const auto& dst = context.m_ivars.get_type(dst_raw); const auto& src = context.m_ivars.get_type(src_raw); TRACE_FUNCTION_F("dst=" << dst << ", src=" << src); @@ -5258,8 +5269,11 @@ namespace { DEBUG("Literal ivars"); return CoerceResult::Equality; } - context.possible_equate_type_unsize_to(src.m_data.as_Infer().index, dst); - context.possible_equate_type_unsize_from(dst.m_data.as_Infer().index, src); + if( context_mut ) + { + context_mut->possible_equate_type_unsize_to(src.m_data.as_Infer().index, dst); + context_mut->possible_equate_type_unsize_from(dst.m_data.as_Infer().index, src); + } DEBUG("Both ivars"); return CoerceResult::Unknown; } @@ -5271,7 +5285,10 @@ namespace { DEBUG("Literal with primitive"); return CoerceResult::Equality; } - context.possible_equate_type_unsize_from(dep->index, src); + if( context_mut ) + { + context_mut->possible_equate_type_unsize_from(dep->index, src); + } DEBUG("Dst ivar"); return CoerceResult::Unknown; } @@ -5283,7 +5300,10 @@ namespace { DEBUG("Literal with primitive"); return CoerceResult::Equality; } - context.possible_equate_type_unsize_to(sep->index, dst); + if( context_mut ) + { + context_mut->possible_equate_type_unsize_to(sep->index, dst); + } DEBUG("Src is ivar (" << src << "), return Unknown"); return CoerceResult::Unknown; } @@ -5295,7 +5315,10 @@ namespace { // Array unsize (quicker than going into deref search) if(dst.m_data.is_Slice() && src.m_data.is_Array()) { - context.equate_types(sp, *dst.m_data.as_Slice().inner, *src.m_data.as_Array().inner); + if( context_mut ) + { + context_mut->equate_types(sp, *dst.m_data.as_Slice().inner, *src.m_data.as_Array().inner); + } if(node_ptr_ptr) { // TODO: Insert deref (instead of leading to a _Unsize op) @@ -5329,10 +5352,9 @@ namespace { // Deref coercions // - If right can be dereferenced to left - if(node_ptr_ptr) + if(node_ptr_ptr || !allow_mutate) { DEBUG("-- Deref coercions"); - auto& node_ptr = *node_ptr_ptr; ::HIR::TypeRef tmp_ty; const ::HIR::TypeRef* out_ty_p = &src; unsigned int count = 0; @@ -5342,9 +5364,26 @@ namespace { const auto& out_ty = context.m_ivars.get_type(*out_ty_p); count += 1; - if( out_ty.m_data.is_Infer() && !out_ty.m_data.as_Infer().is_lit() ) { - // Hit a _, so can't keep going - break; + if( const auto* sep = out_ty.m_data.opt_Infer() ) + { + if( !sep->is_lit() ) + { + // Hit a _, so can't keep going + if( context_mut ) + { + // Could also be any deref chain of the destination type + ::HIR::TypeRef tmp_ty2; + const ::HIR::TypeRef* d_ty_p = &dst; + context_mut->possible_equate_type_unsize_to(sep->index, dst); + for(unsigned int i = 0; i < count && (d_ty_p = context.m_resolve.autoderef(sp, *d_ty_p, tmp_ty2)); i ++) + { + context_mut->possible_equate_type_unsize_to(sep->index, *d_ty_p); + } + } + DEBUG("Src derefs to ivar (" << src << "), return Unknown"); + return CoerceResult::Unknown; + } + // Literal infer, keep going (but remember how many times we dereferenced?) } types.push_back( out_ty.clone() ); @@ -5363,11 +5402,17 @@ namespace { continue ; } DEBUG("Same tag and fuzzy match - assuming " << dst << " == " << out_ty); - context.equate_types(sp, dst, out_ty); + if( context_mut ) + { + context_mut->equate_types(sp, dst, out_ty); + } ), (Slice, // Equate! - context.equate_types(sp, dst, out_ty); + if(context_mut) + { + context_mut->equate_types(sp, dst, out_ty); + } // - Fall through ) ) @@ -5377,21 +5422,25 @@ namespace { } } - add_coerce_borrow(context, node_ptr, types.back(), [&](auto& node_ptr)->void { - // node_ptr = node that yeilds ty_src - assert( count == types.size() ); - for(unsigned int i = 0; i < types.size(); i ++ ) - { - auto span = node_ptr->span(); - // TODO: Replace with a call to context.create_autoderef to handle cases where the below assertion would fire. - ASSERT_BUG(span, !node_ptr->m_res_type.m_data.is_Array(), "Array->Slice shouldn't be in deref coercions"); - auto ty = mv$(types[i]); - node_ptr = ::HIR::ExprNodeP(new ::HIR::ExprNode_Deref( mv$(span), mv$(node_ptr) )); - DEBUG("- Deref " << &*node_ptr << " -> " << ty); - node_ptr->m_res_type = mv$(ty); - context.m_ivars.get_type(node_ptr->m_res_type); - } - }); + if( context_mut && node_ptr_ptr ) + { + auto& node_ptr = *node_ptr_ptr; + add_coerce_borrow(*context_mut, node_ptr, types.back(), [&](auto& node_ptr)->void { + // node_ptr = node that yeilds ty_src + assert( count == types.size() ); + for(unsigned int i = 0; i < types.size(); i ++ ) + { + auto span = node_ptr->span(); + // TODO: Replace with a call to context.create_autoderef to handle cases where the below assertion would fire. + ASSERT_BUG(span, !node_ptr->m_res_type.m_data.is_Array(), "Array->Slice shouldn't be in deref coercions"); + auto ty = mv$(types[i]); + node_ptr = ::HIR::ExprNodeP(new ::HIR::ExprNode_Deref( mv$(span), mv$(node_ptr) )); + DEBUG("- Deref " << &*node_ptr << " -> " << ty); + node_ptr->m_res_type = mv$(ty); + context.m_ivars.get_type(node_ptr->m_res_type); + } + }); + } return CoerceResult::Custom; } @@ -5414,9 +5463,12 @@ namespace { } const auto& tys_d = dep->m_trait.m_path.m_params.m_types; const auto& tys_s = sep->m_trait.m_path.m_params.m_types; - for(size_t i = 0; i < tys_d.size(); i ++) + if( context_mut ) { - context.equate_types(sp, tys_d[i], tys_s.at(i)); + for(size_t i = 0; i < tys_d.size(); i ++) + { + context_mut->equate_types(sp, tys_d[i], tys_s.at(i)); + } } // 2. Destination markers must be a strict subset @@ -5476,24 +5528,27 @@ namespace { } // TODO: Get a better way of equating these that doesn't require getting copies of the impl's types - context.equate_types(sp, src, best_impl.get_impl_type()); - auto args = best_impl.get_trait_params(); - assert(trait.m_params.m_types.size() == args.m_types.size()); - for(unsigned int i = 0; i < trait.m_params.m_types.size(); i ++) - { - context.equate_types(sp, trait.m_params.m_types[i], args.m_types[i]); - } - for(const auto& tyb : dep->m_trait.m_type_bounds) + if( context_mut ) { - auto ty = best_impl.get_type(tyb.first.c_str()); - if( ty != ::HIR::TypeRef() ) + context_mut->equate_types(sp, src, best_impl.get_impl_type()); + auto args = best_impl.get_trait_params(); + assert(trait.m_params.m_types.size() == args.m_types.size()); + for(unsigned int i = 0; i < trait.m_params.m_types.size(); i ++) { - context.equate_types(sp, tyb.second, ty); + context_mut->equate_types(sp, trait.m_params.m_types[i], args.m_types[i]); } - else + for(const auto& tyb : dep->m_trait.m_type_bounds) { - // Error? Log? ... - DEBUG("Associated type " << tyb.first << " not present in impl, can't equate"); + auto ty = best_impl.get_type(tyb.first.c_str()); + if( ty != ::HIR::TypeRef() ) + { + context_mut->equate_types(sp, tyb.second, ty); + } + else + { + // Error? Log? ... + DEBUG("Associated type " << tyb.first << " not present in impl, can't equate"); + } } } } @@ -5563,7 +5618,10 @@ namespace { { auto pp = best_impl.get_trait_params(); DEBUG("Fuzzy, best was Unsize" << pp); - context.equate_types(sp, dst, pp.m_types.at(0)); + if( context_mut ) + { + context_mut->equate_types(sp, dst, pp.m_types.at(0)); + } return CoerceResult::Unsize; } else @@ -5619,7 +5677,7 @@ namespace { { const auto& isrc = se.path.m_data.as_Generic().m_params.m_types.at(sm.unsized_param); const auto& idst = de.path.m_data.as_Generic().m_params.m_types.at(sm.unsized_param); - return check_unsize_tys(context, sp, idst, isrc, nullptr); + return check_unsize_tys(context_mut_r, sp, idst, isrc, nullptr, allow_mutate); } else { @@ -5634,9 +5692,15 @@ namespace { ) } - DEBUG("Reached end of check_unsize_tys, return Unknown"); + // If the destination is an Unbound path, return Unknown + if( TU_TEST1(dst.m_data, Path, .binding.is_Unbound()) ) + { + return CoerceResult::Unknown; + } + + DEBUG("Reached end of check_unsize_tys, return Equality"); // TODO: Determine if this unsizing could ever happen. - return CoerceResult::Unknown; + return CoerceResult::Equality; } /// Checks if two types can be a valid coercion @@ -6326,7 +6390,7 @@ namespace { if( TU_TEST1(impl_ty.m_data, Infer, .is_lit() == false) ) { DEBUG("Unbounded ivar, waiting - TODO: Add possibility " << impl_ty << " == " << possible_impl_ty); - //context.possible_equate_type_bound(impl_ty.m_data.as_Infer().index, possible_impl_ty); + //context.possible_equate_type_bound(sp, impl_ty.m_data.as_Infer().index, possible_impl_ty); return false; } // Only one possible impl @@ -6389,7 +6453,15 @@ namespace { { const auto& t = context.get_type(v.params.m_types[i]); if( const auto* e = t.m_data.opt_Infer() ) { - context.possible_equate_type_bound(e->index, pi.params.m_types[i]); + const auto& pi_t = pi.params.m_types[i]; + if( !type_contains_impl_placeholder(pi_t) ) + { + context.possible_equate_type_bound(sp, e->index, pi_t); + } + else + { + DEBUG("Not adding placeholder-containing type as a bound - " << pi_t); + } } } } @@ -6437,7 +6509,7 @@ namespace { bound_failed = false; return true; }); - if( bound_failed ) { + if( bound_failed && ! t.m_data.is_Infer() ) { // If none was found, remove from the possibility list DEBUG("Remove possibility " << new_ty << " because it failed a bound"); return true; @@ -6463,7 +6535,7 @@ namespace { ::std::vector<::std::pair> possible_methods; unsigned int deref_count = context.m_resolve.autoderef_find_method(node.span(), node.m_traits, node.m_trait_param_ivars, t, node.m_method, possible_methods); DEBUG("> deref_count = " << deref_count << ", " << possible_methods); - if( possible_methods.empty() ) + if( !t.m_data.is_Infer() && possible_methods.empty() ) { // No method found, which would be an error return true; @@ -6477,661 +6549,358 @@ namespace { return false; } - bool check_ivar_poss__coercions(Context& context, unsigned int i, Context::IVarPossible& ivar_ent, const ::HIR::TypeRef& ty_l, bool honour_disable=true) + /// Check IVar possibilities, from both coercion/unsizing (which have well-encoded rules) and from trait impls + bool check_ivar_poss(Context& context, unsigned int i, Context::IVarPossible& ivar_ent, bool honour_disable=true) { static Span _span; const auto& sp = _span; - bool allow_unsized = !(i < context.m_ivars_sized.size() ? context.m_ivars_sized.at(i) : false); + if( honour_disable && (ivar_ent.force_no_to || ivar_ent.force_no_from) ) + { + DEBUG(i << ": forced unknown"); + return false; + } - enum class DedupKeep { - Both, - Left, - Right, - }; - struct H { - static void dedup_type_list_with(::std::vector< ::HIR::TypeRef>& list, ::std::function cmp) { - if( list.size() <= 1 ) - return ; + ::HIR::TypeRef ty_l_ivar; + ty_l_ivar.m_data.as_Infer().index = i; + const auto& ty_l = context.m_ivars.get_type(ty_l_ivar); - for( auto it = list.begin(); it != list.end(); ) - { - bool found = false; - for( auto it2 = list.begin(); it2 != it; ++ it2 ) { - auto action = cmp(*it, *it2); - if( action != DedupKeep::Both ) - { - if( action == DedupKeep::Right ) { - //DEBUG("Keep " << *it << ", toss " << *it2); - } - else { - ::std::swap(*it2, *it); - //DEBUG("Keep " << *it << ", toss " << *it2 << " (swapped)"); - } - found = true; - break; - } - } - if( found ) { - it = list.erase(it); - } - else { - ++ it; - } - } - } - // De-duplicate list (taking into account other ivars) - // - TODO: Use the direction and do a fuzzy equality based on coercion possibility - static void dedup_type_list(const Context& context, ::std::vector< ::HIR::TypeRef>& list) { - dedup_type_list_with(list, [&context](const auto& l, const auto& r){ return H::equal_to(context, l, r) ? DedupKeep::Left : DedupKeep::Both; }); + if( ty_l != ty_l_ivar ) { + if( ivar_ent.has_rules() ) + { + DEBUG("- IVar " << i << " had possibilities, but was known to be " << ty_l); + // Completely clear by reinitialising + ivar_ent = Context::IVarPossible(); } + return false; + } - // Types are equal from the view of being coercion targets - // - Inequality here means that the targets could coexist in the list (e.g. &[u8; N] and &[u8]) - // - Equality means that they HAVE to be equal (even if they're not currently due to ivars) - // - E.g. &mut HashMap<_1> and &mut HashMap would unify - static bool equal_to(const Context& context, const ::HIR::TypeRef& ia, const ::HIR::TypeRef& ib) { - const auto& a = context.m_ivars.get_type(ia); - const auto& b = context.m_ivars.get_type(ib); - if( a.m_data.tag() != b.m_data.tag() ) - return false; - TU_MATCH_DEF(::HIR::TypeRef::Data, (a.m_data, b.m_data), (e_a, e_b), - ( - return context.m_ivars.types_equal(a, b); - ), - (Borrow, - if( e_a.type != e_b.type ) - return false; - const auto& ia = context.m_ivars.get_type(*e_a.inner); - const auto& ib = context.m_ivars.get_type(*e_b.inner); - if( ia.m_data.tag() != ib.m_data.tag() ) - return false; - TU_MATCH_DEF(::HIR::TypeRef::Data, (ia.m_data, ib.m_data), (e_ia, e_ib), - ( - return context.m_ivars.types_equal(ia, ib); - ), - (Infer, - return false; - ), - (Path, - if( e_ia.binding.tag() != e_ib.binding.tag() ) - return false; - TU_MATCHA( (e_ia.binding, e_ib.binding), (pbe_a, pbe_b), - (Unbound, return false; ), - (Opaque, - // TODO: Check bounds? - return false; - ), - (ExternType, - return false; - ), - (Struct, - if(pbe_a != pbe_b) return false; - if( !pbe_a->m_struct_markings.can_unsize ) - return true; - // It _could_ unsize, so let it coexist - return false; - ), - (Union, - return false; - ), - (Enum, - return false; - ) - ) - ), - (Slice, - const auto& ia2 = context.m_ivars.get_type(*e_ia.inner); - const auto& ib2 = context.m_ivars.get_type(*e_ib.inner); - if(ia2.m_data.is_Infer() || ib2.m_data.is_Infer()) - return true; - return context.m_ivars.types_equal(ia2, ib2); - ) - ) - ), - (Pointer, - if( e_a.type != e_b.type ) - return false; - // TODO: Rules are subtly different when coercing from a pointer? - const auto& ia2 = context.m_ivars.get_type(*e_a.inner); - const auto& ib2 = context.m_ivars.get_type(*e_b.inner); - if(ia2.m_data.is_Infer() || ib2.m_data.is_Infer()) - return true; - return context.m_ivars.types_equal(ia2, ib2); - ) - ) - // - return context.m_ivars.types_equal(a, b); - } - // Types are equal from the view of being coercion sources - static bool equal_from(const Context& context, const ::HIR::TypeRef& a, const ::HIR::TypeRef& b) { - return context.m_ivars.types_equal(a, b); - } + if( ! ivar_ent.has_rules() ) { + // No rules, don't do anything (and don't print) + DEBUG(i << ": No rules"); + return false; + } - // TODO: `can_unsize_to` - static bool can_coerce_to(const Context& context, const ::HIR::TypeRef& dst, const ::HIR::TypeRef& src) { - if( dst.m_data.is_Infer() ) - return false; - if( src.m_data.is_Infer() ) - return false; + TRACE_FUNCTION_F(i << (honour_disable ? "" : " fallback")); - if( dst.m_data.is_Borrow() && src.m_data.is_Borrow() ) { - const auto& d_e = dst.m_data.as_Borrow(); - const auto& s_e = src.m_data.as_Borrow(); - // Higher = more specific (e.g. Unique > Shared) - if( s_e.type < d_e.type ) { - return false; - } - else if( s_e.type == d_e.type ) { - // Check relationship - // - 1. Deref chain. - // - 2. Trait object? - } - else { - return context.m_ivars.types_equal(*s_e.inner, *d_e.inner); - } - } + bool has_no_coerce_posiblities; - if( dst.m_data.is_Pointer() && src.m_data.is_Pointer() ) { - const auto& d_e = dst.m_data.as_Pointer(); - const auto& s_e = src.m_data.as_Pointer(); - // Higher = more specific (e.g. Unique > Shared) - if( s_e.type < d_e.type ) { - return false; - } - else if( s_e.type == d_e.type ) { - // Check relationship - // - 1. Deref chain. - // - 2. Trait object? - } - else { - return context.m_ivars.types_equal(*s_e.inner, *d_e.inner); - } + // Fill a single list with all possibilities, and pick the most suitable type. + // - This list needs to include flags to say if the type can be dereferenced. + { + struct PossibleType { + bool is_pointer; // I.e. it's from a coerce + bool can_deref; // I.e. from an unsize or coerce, AND it's a "from" + const ::HIR::TypeRef* ty; + + bool operator<(const PossibleType& o) const { + if( *ty != *o.ty ) + return *ty < *o.ty; + if( is_pointer != o.is_pointer ) + return is_pointer < o.is_pointer; + if( can_deref < o.can_deref ) + return can_deref < o.can_deref; + return false; } - - if( dst.m_data.is_Pointer() && src.m_data.is_Borrow() ) { - const auto& d_e = dst.m_data.as_Pointer(); - const auto& s_e = src.m_data.as_Borrow(); - if( s_e.type == d_e.type ) { - return context.m_ivars.types_equal(*s_e.inner, *d_e.inner); - } + ::std::ostream& fmt(::std::ostream& os) const { + return os << (is_pointer ? "C" : "-") << (can_deref ? "D" : "-") << " " << *ty; } - return false; - } + }; - // Returns true if the `src` concretely cannot coerce to `dst` - static bool cannot_coerce_to(const Context& context, const ::HIR::TypeRef& dst, const ::HIR::TypeRef& src) { - TU_IFLET( ::HIR::TypeRef::Data, src.m_data, Borrow, se, - TU_IFLET( ::HIR::TypeRef::Data, dst.m_data, Borrow, de, - ) - else TU_IFLET( ::HIR::TypeRef::Data, dst.m_data, Pointer, de, - ) - else { - return true; - } - ) - return false; - } + bool allow_unsized = !(i < context.m_ivars_sized.size() ? context.m_ivars_sized.at(i) : false); - static const ::HIR::TypeRef* find_lowest_type(const Context& context, const ::std::vector< ::HIR::TypeRef>& list) + ::std::vector possible_tys; + static ::HIR::TypeRef null_placeholder; + if( honour_disable && ivar_ent.force_no_from ) // TODO: This can't happen, there's an early return above. { - // 1. Locate types that cannot coerce to anything - // - &TraitObject and &[T] are the main pair - for(const auto& ty : list) { - TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Borrow, e, - TU_MATCH_DEF(::HIR::TypeRef::Data, (e.inner->m_data), (e2), - ( - ), - (Slice, - return &ty; - ), - (TraitObject, - return &ty; - ) - ) - ) - } - - // 2. Search the list for a type that is a valid coercion target for all other types in the list - // - NOTE: Ivars return `false` nomatter what order - const auto* cur_type = &list[0]; - for(const auto& ty : list) { - // If ty can be coerced to the current type - if( H::can_coerce_to(context, *cur_type, ty) ) { - // - Keep current type - } - else if( H::can_coerce_to(context, ty, *cur_type) ) { - cur_type = &ty; - } - else { - // Error? Give up. - cur_type = nullptr; - break; - } - } - if( cur_type ) { - // TODO: Replace - //return cur_type; - } - - return nullptr; + possible_tys.push_back(PossibleType { false, true, &null_placeholder }); } - - /// Returns true if `dst` is found when dereferencing `src` - static bool type_derefs_from(const Span& sp, const Context& context, const ::HIR::TypeRef& dst, const ::HIR::TypeRef& src) + for(const auto& new_ty : ivar_ent.types_coerce_from ) { - ::HIR::TypeRef tmp; - const ::HIR::TypeRef* ty = &src; - do - { - if( context.m_ivars.types_equal(*ty, dst) ) - return true; - } while( (ty = context.m_resolve.autoderef(sp, *ty, tmp)) ); - return false; + possible_tys.push_back(PossibleType { true , true, &new_ty }); } - - static ::std::vector<::HIR::TypeRef>& merge_lists(const Context& context, ::std::vector<::HIR::TypeRef>& list_a, ::std::vector<::HIR::TypeRef>& list_b, ::std::vector<::HIR::TypeRef>& out) + for(const auto& new_ty : ivar_ent.types_unsize_from ) { - if( list_a.size() == 0 ) - return list_b; - else if( list_b.size() == 0 ) - return list_a; - else { - for(const auto& t : list_a) { - out.push_back( t.clone() ); - } - for(const auto& t : list_b ) { - out.push_back( t.clone() ); - } - H::dedup_type_list(context, out); - return out; - } + possible_tys.push_back(PossibleType { false, true, &new_ty }); } - }; - - // If this type has an infer class active, don't allw a non-primitive to coerce over it. - if( ty_l.m_data.as_Infer().is_lit() ) - { - DEBUG("Literal checks"); - // TODO: Actively search possibility list for the real type. - for(const auto& ty : ivar_ent.types_coerce_to) - if( ty.m_data.is_Primitive() ) { - context.equate_types(sp, ty_l, ty); - return true; - } - for(const auto& ty : ivar_ent.types_unsize_to) - if( ty.m_data.is_Primitive() ) { - context.equate_types(sp, ty_l, ty); - return true; - } - for(const auto& ty : ivar_ent.types_coerce_from) - if( ty.m_data.is_Primitive() ) { - context.equate_types(sp, ty_l, ty); - return true; - } - for(const auto& ty : ivar_ent.types_unsize_from) - if( ty.m_data.is_Primitive() ) { - context.equate_types(sp, ty_l, ty); - return true; - } - return false; - } - - if( honour_disable && (ivar_ent.force_no_to || ivar_ent.force_no_from) ) - { - DEBUG("- IVar " << ty_l << " is forced unknown"); - return false; - } - else - { - // TODO: Dedup based on context? - // - The dedup should probably be aware of the way the types are used (for coercions). - H::dedup_type_list(context, ivar_ent.types_coerce_to); - H::dedup_type_list(context, ivar_ent.types_unsize_to); - H::dedup_type_list(context, ivar_ent.types_coerce_from); - H::dedup_type_list(context, ivar_ent.types_unsize_from); - - #if 0 - // If there is a default type compatible with all possibilities, use that. - if( ivar_ent.types_default.size() > 0 ) { - // TODO: Should multiple options be valid? - ASSERT_BUG(Span(), ivar_ent.types_def.size() == 1, "TODO: Multiple default types for an ivar - " << ivar_ent.types_def); + if( honour_disable && ivar_ent.force_no_to ) // TODO: This can't happen, there's an early return above. + { + possible_tys.push_back(PossibleType { false, false, &null_placeholder }); } - #endif - - if( ivar_ent.types_coerce_from.size() == 0 && ivar_ent.types_coerce_to.size() == 0 - && ivar_ent.types_unsize_from.size() == 0 && ivar_ent.types_unsize_to.size() == 0 - ) + for(const auto& new_ty : ivar_ent.types_coerce_to ) { - DEBUG("-- No known options for " << ty_l); - return false; + possible_tys.push_back(PossibleType { true , false, &new_ty }); } - DEBUG("-- " << ty_l << " FROM=Coerce:{" << ivar_ent.types_coerce_from << "} / Unsize:{" << ivar_ent.types_unsize_from << "}," - << " TO=Coerce:{" << ivar_ent.types_coerce_to << "} / Unsize:{" << ivar_ent.types_unsize_to << "}"); - - // Find an entry in the `types_unsize_from` list that all other entries can unsize to - H::dedup_type_list_with(ivar_ent.types_unsize_from, [&](const auto& l, const auto& r) { - if( l.m_data.is_Infer() || r.m_data.is_Infer() ) - return DedupKeep::Both; - - // Check for fuzzy equality of types, and keep only one - // TODO: Ensure that whatever ivar differs can't be different (i.e. it wouldn't change the unsize/coerce) - // TODO: Use `check_unsize_tys` instead - if( l.compare_with_placeholders(sp, r, context.m_ivars.callback_resolve_infer()) != ::HIR::Compare::Unequal ) - { - DEBUG("Possible match, keep left"); - return DedupKeep::Left; - } - - // &T and T - TU_IFLET( ::HIR::TypeRef::Data, l.m_data, Borrow, le, - TU_IFLET( ::HIR::TypeRef::Data, r.m_data, Borrow, re, - ) - else { - // if *le.inner == r, return DedupKeep::Right - if( context.m_ivars.types_equal(*le.inner, r) ) - return DedupKeep::Right; - } - ) - else { - TU_IFLET( ::HIR::TypeRef::Data, r.m_data, Borrow, re, - // if *re.inner == l, return DedupKeep::Left - if( context.m_ivars.types_equal(*re.inner, l) ) - return DedupKeep::Left; - ) - } - return DedupKeep::Both; - }); - // Find an entry in the `types_coerce_from` list that all other entries can coerce to - H::dedup_type_list_with(ivar_ent.types_coerce_from, [&](const auto& l, const auto& r) { - if( l.m_data.is_Infer() || r.m_data.is_Infer() ) - return DedupKeep::Both; - - // Check for fuzzy equality of types, and keep only one - // TODO: Ensure that whatever ivar differs can't be different (i.e. it wouldn't change the unsize/coerce) - // TODO: Use `check_coerce_tys` instead - if( l.compare_with_placeholders(sp, r, context.m_ivars.callback_resolve_infer()) != ::HIR::Compare::Unequal ) - { - DEBUG("Possible match, keep left"); - return DedupKeep::Left; - } - - if( l.m_data.is_Borrow() ) + for(const auto& new_ty : ivar_ent.types_unsize_to ) + { + possible_tys.push_back(PossibleType { false, false, &new_ty }); + } +#if 1 + DEBUG("possible_tys = " << possible_tys); + DEBUG("Adding bounded [" << ivar_ent.bounded << "]"); + if( !possible_tys.empty() ) + { + for(const auto& new_ty : ivar_ent.bounded) { - const auto& le = l.m_data.as_Borrow(); - ASSERT_BUG(sp, r.m_data.is_Borrow() || r.m_data.is_Pointer(), "Coerce source for borrow isn't a borrow/pointert - " << r); - const auto re_borrow_type = r.m_data.is_Borrow() ? r.m_data.as_Borrow().type : r.m_data.as_Pointer().type; - const auto& re_inner = r.m_data.is_Borrow() ? r.m_data.as_Borrow().inner : r.m_data.as_Pointer().inner; - - if( le.type < re_borrow_type ) { - if( !context.m_ivars.types_equal(*le.inner, *re_inner) ) { - return DedupKeep::Both; + bool failed_a_bound = false; + // Check if this bounded type _cannot_ work with any of the existing bounds + // - Don't add to the possiblity list if so + for(const auto& opt : possible_tys) + { + CoerceResult res; + if( opt.can_deref ) { + DEBUG(" > " << new_ty << " =? " << *opt.ty); + res = check_unsize_tys(context, sp, new_ty, *opt.ty, nullptr, false); } - DEBUG("- Remove " << r); - return DedupKeep::Left; - } - else if( le.type > re_borrow_type ) { - if( !context.m_ivars.types_equal(*le.inner, *re_inner) ) { - return DedupKeep::Both; + else { + // Destination type, this option must deref to it + DEBUG(" > " << *opt.ty << " =? " << new_ty); + res = check_unsize_tys(context, sp, *opt.ty, new_ty, nullptr, false); + } + DEBUG(" = " << res); + if( res == CoerceResult::Equality ) { + failed_a_bound = true; + break; + } + else if( res == CoerceResult::Unknown ) { + // Should this also be treated as a fail? } - DEBUG("- Remove " << l); - return DedupKeep::Right; } - else { + if( !failed_a_bound ) + { + possible_tys.push_back(PossibleType { false, false, &new_ty }); } - - // Dereference `*re.inner` until it isn't possible or it equals `*le.inner` - // - Repeat going the other direction. - if( H::type_derefs_from(sp, context, *le.inner, *re_inner) ) - return DedupKeep::Left; - if( H::type_derefs_from(sp, context, *re_inner, *le.inner) ) - return DedupKeep::Right; } - return DedupKeep::Both; - }); - - - // If there's one option for both desination types, and nothing for the source ... - if( ivar_ent.types_coerce_to.size() == 1 && ivar_ent.types_unsize_to.size() == 1 && ivar_ent.types_coerce_from.empty() && ivar_ent.types_unsize_from.empty() ) + } +#endif + DEBUG("possible_tys = " << possible_tys); + // Filter out useless options and impossiblities + for(auto it = possible_tys.begin(); it != possible_tys.end(); ) { - // And the coercion can unsize to the unsize, pick the coercion (it's valid, the other way around isn't) - // TODO: Use a `can_unsize_to` functon instead (that handles Unsize as well as Deref) - if( H::type_derefs_from(sp, context, ivar_ent.types_unsize_to[0], ivar_ent.types_coerce_to[0]) ) + bool remove_option = false; + if( *it->ty == ty_l ) { - const auto& new_ty = ivar_ent.types_coerce_to[0]; - DEBUG("- IVar " << ty_l << " = " << new_ty << " (unsize to)"); - context.equate_types(sp, ty_l, new_ty); - return true; + remove_option = true; } - } - #if 0 - // If there's only one coerce and unsize from, ... - if( ivar_ent.types_coerce_from.size() == 1 && ivar_ent.types_unsize_from.size() == 1 && ivar_ent.types_coerce_to.empty() && ivar_ent.types_unsize_to.empty() ) - { - // and if the coerce can unsize to the unsize target. - if( H::can_coerce_to(context, ivar_ent.types_unsize_from[0], ivar_ent.types_coerce_from[0]) ) + else if( !allow_unsized && context.m_resolve.type_is_sized(sp, *it->ty) == ::HIR::Compare::Unequal ) { - const auto& new_ty = ivar_ent.types_coerce_from[0]; - DEBUG("- IVar " << ty_l << " = " << new_ty << " (coerce from)"); - context.equate_types(sp, ty_l, new_ty); - return true; + remove_option = true; } - } - #endif - - // - - // HACK: Merge into a single lists - ::std::vector< ::HIR::TypeRef> types_from_o; - auto& types_from = H::merge_lists(context, ivar_ent.types_coerce_from, ivar_ent.types_unsize_from, types_from_o); - ::std::vector< ::HIR::TypeRef> types_to_o; - auto& types_to = H::merge_lists(context, ivar_ent.types_coerce_to , ivar_ent.types_unsize_to , types_to_o ); - DEBUG(" " << ty_l << " FROM={" << types_from << "}, TO={" << types_to << "}"); - - // TODO: If there is only a single option and it's from an Unsize, is it valid? - - // TODO: Loop both lists and if there's T<_{int}> and T unify those. - - // Same type on both sides, pick it. - if( types_from == types_to && types_from.size() == 1 ) { - const auto& new_ty = types_from[0]; - DEBUG("- IVar " << ty_l << " = " << new_ty << " (only)"); - context.equate_types(sp, ty_l, new_ty); - return true; - } - - // Eliminate possibilities that don't fit known constraints - if( types_to.size() > 0 && types_from.size() > 0 ) - { - // TODO: Search `types_to` too - for(auto it = types_from.begin(); it != types_from.end(); ) + else { - bool remove = false; - const auto& new_ty = context.get_type(*it); - if( !new_ty.m_data.is_Infer() ) - { - remove = check_ivar_poss__fails_bounds(sp, context, ty_l, new_ty); - - if( !remove && !allow_unsized ) - { - if( context.m_resolve.type_is_sized(sp, new_ty) == ::HIR::Compare::Unequal ) - { - remove = true; - DEBUG("Remove possibility " << new_ty << " because it isn't Sized"); - } - } - } - - if( remove ) { - it = types_from.erase(it); - } - else { - ++it; - } + // Keep } - // Eliminate `to` types that can't be coerced from `from` types - if(types_from.size() > 0) - for(auto it = types_to.begin(); it != types_to.end(); ) + it = (remove_option ? possible_tys.erase(it) : it + 1); + } + DEBUG("possible_tys = " << possible_tys); + for(auto it = possible_tys.begin(); it != possible_tys.end(); ) + { + bool remove_option = false; + for(const auto& other_opt : possible_tys) { - if( it->m_data.is_Infer() ) { - ++ it; - continue; - } - bool remove = false; - - for(const auto& src : types_from) + if( &other_opt == &*it ) + continue ; + if( *other_opt.ty == *it->ty ) { - if( H::cannot_coerce_to(context, *it, src) ) { - remove = true; - DEBUG("Remove target type " << *it << " because it cannot be created from a source type"); + // Potential duplicate + // - If the flag set is the same, then it is a duplicate + if( other_opt.can_deref == it->can_deref && other_opt.is_pointer == it->is_pointer ) { + remove_option = true; break; } - } - - if( !remove && !allow_unsized ) - { - if( context.m_resolve.type_is_sized(sp, *it) == ::HIR::Compare::Unequal ) + // If not an ivar, AND both are either unsize/pointer AND the deref flags are different + if( !it->ty->m_data.is_Infer() && other_opt.is_pointer == it->is_pointer && other_opt.can_deref != it->can_deref ) { - remove = true; - DEBUG("Remove possibility " << *it << " because it isn't Sized"); + DEBUG("Source and destination possibility, picking " << *it->ty); + context.equate_types(sp, ty_l, *it->ty); + return true; + } + // - Otherwise, we want to keep the option which doesn't allow dereferencing (remove current + // if it's the deref option) + if( it->can_deref && other_opt.is_pointer == it->is_pointer ) { + remove_option = true; + break; } - } - - if( remove ) { - it = types_to.erase(it); - } - else { - ++it; } } + it = (remove_option ? possible_tys.erase(it) : it + 1); } - - // De-duplicate lists (after unification) using strict equality - H::dedup_type_list_with(types_from, [&](const auto& l, const auto& r) { - return context.m_ivars.types_equal(l, r) ? DedupKeep::Left : DedupKeep::Both; - }); - H::dedup_type_list_with(types_to, [&](const auto& l, const auto& r) { - return context.m_ivars.types_equal(l, r) ? DedupKeep::Left : DedupKeep::Both; - }); - - // If there is a common type in both lists, use it - for(const auto& t1 : types_from) + DEBUG("possible_tys = " << possible_tys); + // Remove any options that are filled by other options (e.g. `str` and a derferencable String) + for(auto it = possible_tys.begin(); it != possible_tys.end(); ) { - for(const auto& t2 : types_to) + bool remove_option = false; + if( it->can_deref && !it->ty->m_data.is_Infer() ) { - if(t1 == t2) { - DEBUG("- IVar " << ty_l << " = " << t1 << " (present in both lists)"); - context.equate_types(sp, ty_l, t1); - return true; - } - } - } - - // Prefer cases where this type is being created from a known type - if( types_from.size() == 1 || types_to.size() == 1 ) { - const char* list_name = (types_from.size() ? "from" : "to"); - const ::HIR::TypeRef& ty_r = (types_from.size() == 1 ? types_from[0] : types_to[0]); - // Only one possibility - // - If it would ivar unify, don't if the target has guessing disabled - if( const auto* e = ty_r.m_data.opt_Infer() ) - { - if( e->index < context.possible_ivar_vals.size() ) + DEBUG("> " << *it); + // Dereference once before starting the search + ::HIR::TypeRef tmp, tmp2; + const auto* dty = it->ty; + auto src_bty = ::HIR::BorrowType::Shared; + if(it->is_pointer) + { + if( dty->m_data.is_Borrow() ) + src_bty = dty->m_data.as_Borrow().type; + dty = context.m_resolve.autoderef(sp, *dty, tmp); + // NOTE: Coercions can also do closure->fn, so deref isn't always possible + //ASSERT_BUG(sp, dty, "Pointer (coercion source) that can't dereference - " << *it->ty); + } + //while( dty && !remove_option && (dty = context.m_resolve.autoderef(sp, *dty, tmp)) ) + if( dty ) { - const auto& p = context.possible_ivar_vals[e->index]; - if( honour_disable && (p.force_no_to || p.force_no_from) ) + for(const auto& other_opt : possible_tys) { - DEBUG("- IVar " << ty_l << " ?= " << ty_r << " (single " << list_name << ", rhs disabled)"); - return false; + if( &other_opt == &*it ) + continue ; + if( other_opt.ty->m_data.is_Infer() ) + continue ; + DEBUG(" > " << other_opt); + + const auto* oty = other_opt.ty; + auto o_bty = ::HIR::BorrowType::Owned; + if(other_opt.is_pointer) + { + if( oty->m_data.is_Borrow() ) + o_bty = oty->m_data.as_Borrow().type; + oty = context.m_resolve.autoderef(sp, *oty, tmp2); + //ASSERT_BUG(sp, oty, "Pointer (coercion src/dst) that can't dereference - " << *other_opt.ty); + } + if( o_bty > src_bty ) // Smaller means less powerful. Converting & -> &mut is invalid + { + // Borrow types aren't compatible + DEBUG("BT " << o_bty << " > " << src_bty); + break; + } + // TODO: Check if unsize is possible from `dty` to `oty` + if( oty ) + { + DEBUG(" > " << *dty << " =? " << *oty); + auto cmp = check_unsize_tys(context, sp, *oty, *dty, nullptr, false); + DEBUG(" = " << cmp); + if( cmp == CoerceResult::Equality ) + { + //TODO(sp, "Impossibility for " << *oty << " := " << *dty); + } + else if( cmp == CoerceResult::Unknown ) + { + } + else + { + remove_option = true; + DEBUG("- Remove " << *it << ", can deref to " << other_opt); + break; + } + } } } } - // If there are from options, AND the to option is an Unsize - if( types_from.size() > 1 && ivar_ent.types_unsize_to.size() == 1 && ivar_ent.types_coerce_to.size() == 0 - && ::std::any_of(types_from.begin(), types_from.end(), [](const auto&x){ return x.m_data.is_Infer(); }) ) { - DEBUG("- IVar " << ty_l << " != " << ty_r << " (single " << list_name << ", but was unsize and from has ivars)"); - return false; + if( !remove_option && !it->ty->m_data.is_Infer() && check_ivar_poss__fails_bounds(sp, context, ty_l, *it->ty) ) + { + remove_option = true; + DEBUG("- Remove " << *it << " due to bounds"); } + it = (remove_option ? possible_tys.erase(it) : it + 1); + } + DEBUG("possible_tys = " << possible_tys); - DEBUG("- IVar " << ty_l << " = " << ty_r << " (single " << list_name << ")"); - context.equate_types(sp, ty_l, ty_r); + if( possible_tys.size() == 1 ) + { + const auto& new_ty = *possible_tys[0].ty; + DEBUG("Only " << new_ty << " is an option"); + context.equate_types(sp, ty_l, new_ty); + return true; + } + // If there's only one non-deref in the list OR there's only one deref in the list + if( !honour_disable && ::std::count_if(possible_tys.begin(), possible_tys.end(), [](const PossibleType& pt){ return pt.can_deref; }) == 1 ) + { + auto it = ::std::find_if(possible_tys.begin(), possible_tys.end(), [](const PossibleType& pt){ return pt.can_deref; }); + const auto& new_ty = *it->ty; + DEBUG("Picking " << new_ty << " as the only source [" << possible_tys << "]"); + context.equate_types(sp, ty_l, new_ty); + return true; + } + if( !honour_disable && ::std::count_if(possible_tys.begin(), possible_tys.end(), [](const PossibleType& pt){ return !pt.can_deref; }) == 1 ) + { + auto it = ::std::find_if(possible_tys.begin(), possible_tys.end(), [](const PossibleType& pt){ return !pt.can_deref; }); + const auto& new_ty = *it->ty; + DEBUG("Picking " << new_ty << " as the only target [" << possible_tys << "]"); + context.equate_types(sp, ty_l, new_ty); + return true; + } + // If there's multiple possiblilties, we're in fallback mode, AND there's no ivars in the list + if( possible_tys.size() > 0 && !honour_disable && !::std::any_of(possible_tys.begin(), possible_tys.end(), [](const PossibleType& pt){ return pt.ty->m_data.is_Infer(); }) ) + { + //::std::sort(possible_tys.begin(), possible_tys.end()); // Sorts ivars to the front + const auto& new_ty = *possible_tys.back().ty; + DEBUG("Picking " << new_ty << " as an arbitary an option from [" << possible_tys << "]"); + context.equate_types(sp, ty_l, new_ty); return true; } - else { - DEBUG("- IVar " << ty_l << " not concretely known {" << types_from << "} and {" << types_to << "}" ); - // If one side is completely unknown, pick the most liberal of the other side - if( types_to.size() == 0 && types_from.size() > 0 ) + // If only one bound meets the possible set, use it + if( ! possible_tys.empty() ) + { + DEBUG("Checking bounded [" << ivar_ent.bounded << "]"); + ::std::vector feasable_bounds; + for(const auto& new_ty : ivar_ent.bounded) { - // Search for the lowest-level source type (e.g. &[T]) - const auto* lowest_type = H::find_lowest_type(context, types_from); - if( lowest_type ) + bool failed_a_bound = false; + // TODO: Check if this bounded type _cannot_ work with any of the existing bounds + // - Don't add to the possiblity list if so + for(const auto& opt : possible_tys) { - const ::HIR::TypeRef& ty_r = *lowest_type; - DEBUG("- IVar " << ty_l << " = " << ty_r << " (from, lowest)"); - context.equate_types(sp, ty_l, ty_r); - return true; + if( opt.can_deref ) { + const auto* dty = opt.ty; + + DEBUG(" > " << new_ty << " =? " << *dty); + auto cmp = check_unsize_tys(context, sp, new_ty, *dty, nullptr, false); + DEBUG(" = " << cmp); + if( cmp == CoerceResult::Equality ) { + failed_a_bound = true; + break; + } + } + else { + // Destination type, this option must deref to it + DEBUG(" > " << *opt.ty << " =? " << new_ty); + auto cmp = check_unsize_tys(context, sp, *opt.ty, new_ty, nullptr, false); + DEBUG(" = " << cmp); + if( cmp == CoerceResult::Equality ) { + failed_a_bound = true; + break; + } + } + } + // TODO: Should this also check check_ivar_poss__fails_bounds + if( !failed_a_bound ) + { + feasable_bounds.push_back(&new_ty); } } - else if( types_to.size() > 0 && types_from.size() == 0 ) - { - // TODO: Get highest-level target type - } - else + if( feasable_bounds.size() == 1 ) { + const auto& new_ty = *feasable_bounds.front(); + DEBUG("Picking " << new_ty << " as it's the only bound that fits coercions"); + context.equate_types(sp, ty_l, new_ty); + return true; } } - } - - return false; - } - - /// Check IVar possibilities, from both coercion/unsizing (which have well-encoded rules) and from trait impls - bool check_ivar_poss(Context& context, unsigned int i, Context::IVarPossible& ivar_ent, bool honour_disable=true) - { - static Span _span; - const auto& sp = _span; - - if( honour_disable && (ivar_ent.force_no_to || ivar_ent.force_no_from) ) - { - DEBUG(i << ": forced unknown"); - return false; - } - - ::HIR::TypeRef ty_l_ivar; - ty_l_ivar.m_data.as_Infer().index = i; - const auto& ty_l = context.m_ivars.get_type(ty_l_ivar); - - if( ty_l != ty_l_ivar ) { - if( ivar_ent.has_rules() ) + else { - DEBUG("- IVar " << i << " had possibilities, but was known to be " << ty_l); - // Completely clear by reinitialising - ivar_ent = Context::IVarPossible(); + // Not checking bounded list, because there's nothing to check } - return false; - } - if( ! ivar_ent.has_rules() ) { - // No rules, don't do anything (and don't print) - DEBUG(i << ": No rules"); - return false; - } - - TRACE_FUNCTION_F(i); - - - if( check_ivar_poss__coercions(context, i, ivar_ent, ty_l, honour_disable) ) - { - return true; + has_no_coerce_posiblities = possible_tys.empty(); } - if( !ivar_ent.bounded.empty() ) + if( has_no_coerce_posiblities && !ivar_ent.bounded.empty() ) { // TODO: Search know possibilties and check if they satisfy the bounds for this ivar DEBUG("Options: " << ivar_ent.bounded); unsigned int n_good = 0; + unsigned int n_good_ints = 0; const ::HIR::TypeRef* only_good = nullptr; for(const auto& new_ty : ivar_ent.bounded) { @@ -7144,22 +6913,28 @@ namespace { n_good ++; if( !only_good ) only_good = &new_ty; + + if( new_ty.m_data.is_Primitive() ) + n_good_ints ++; + DEBUG("> " << new_ty << " feasible"); } } // Picks the first if in fallback mode (which is signalled by `honour_disable` being false) // - This handles the case where there's multiple valid options (needed for libcompiler_builtins) - if( (honour_disable ? n_good == 1 : n_good > 0) - && ivar_ent.types_coerce_from.size() == 0 && ivar_ent.types_coerce_to.size() == 0 - && ivar_ent.types_unsize_from.size() == 0 && ivar_ent.types_unsize_to.size() == 0 - ) + // TODO: Only pick any if all options are the same class (or just all are integers) + if( (honour_disable ? n_good == 1 : n_good > 0) ) + //if( n_good == 1 || (honour_disable ? false : n_good == n_good_ints) ) { - DEBUG("Only " << *only_good << " fits current bound sets"); + if( honour_disable ) + DEBUG("Only " << *only_good << " fits current bound sets"); + else + DEBUG("Picking " << *only_good << " as first of " << n_good << " options"); // Since it's the only possibility, choose it? context.equate_types(sp, ty_l, *only_good); return true; } - DEBUG(n_good << " valid options"); + DEBUG(n_good << " valid options (" << n_good_ints << " primitives)"); } return false; @@ -7411,6 +7186,9 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR: for(unsigned int i = context.possible_ivar_vals.size(); i --; ) { if( check_ivar_poss(context, i, context.possible_ivar_vals[i], /*honour_disable=*/false) ) { +#if 1 + break; +#else static Span sp; assert( context.possible_ivar_vals[i].has_rules() ); // Disable all metioned ivars in the possibilities @@ -7442,6 +7220,7 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR: context.equate_types_shadow(sp, t, false); } } +#endif } else { //assert( !context.m_ivars.peek_changed() ); diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index 15c61bc7..7e282cb0 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -3651,12 +3651,16 @@ const ::HIR::TypeRef* TraitResolution::autoderef(const Span& sp, const ::HIR::Ty DEBUG("Deref " << ty << " into " << *e.inner); return &this->m_ivars.get_type(*e.inner); ) - // TODO: Just doing `*[1,2,3]` doesn't work, but this is needed to allow `[1,2,3].iter()` to work + // HACK?: Just doing `*[1,2,3]` doesn't work, but this is needed to allow `[1,2,3].iter()` to work else TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Array, e, DEBUG("Deref " << ty << " into [" << *e.inner << "]"); tmp_type = ::HIR::TypeRef::new_slice( e.inner->clone() ); return &tmp_type; ) + // Shortcut, don't look up a Deref impl for primitives or slices + else if( ty.m_data.is_Slice() || ty.m_data.is_Primitive() ) { + return nullptr; + } else { bool succ = this->find_trait_impls(sp, this->m_crate.get_lang_item_path(sp, "deref"), ::HIR::PathParams {}, ty, [&](auto impls, auto match) { tmp_type = impls.get_type("Target"); @@ -3812,7 +3816,7 @@ const ::HIR::TypeRef* TraitResolution::check_method_receiver(const Span& sp, con case ::HIR::Function::Receiver::Value: if( access >= TraitResolution::MethodAccess::Move ) { - return &ty; + return &this->m_ivars.get_type(ty); } break; case ::HIR::Function::Receiver::BorrowOwned: @@ -3865,7 +3869,7 @@ const ::HIR::TypeRef* TraitResolution::check_method_receiver(const Span& sp, con }; if( fcn.m_args.front().second .match_test_generics(sp, ty, this->m_ivars.callback_resolve_infer(), cb_getself) ) { assert(detected_self_ty); - return detected_self_ty; + return &this->m_ivars.get_type(*detected_self_ty); } } return nullptr; -- cgit v1.2.3 From db6124cc20b8adf3017803d4eab13e54ffee52f4 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 24 Feb 2019 22:05:50 +0800 Subject: Typecheck Expressions - EAT before doing match ergonomincs, better error messages --- src/hir_typeck/expr_cs.cpp | 89 ++++++++++++++++++++++++++++++---------------- 1 file changed, 58 insertions(+), 31 deletions(-) diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 90146635..423ad3a1 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -45,6 +45,7 @@ struct Context class Revisitor { public: + virtual const Span& span() const = 0; virtual void fmt(::std::ostream& os) const = 0; virtual bool revisit(Context& context, bool is_fallback) = 0; }; @@ -3809,11 +3810,15 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T m_outer_mode(binding_mode) {} + const Span& span() const override { + return sp; + } void fmt(::std::ostream& os) const override { os << "MatchErgonomicsRevisit { " << m_pattern << " : " << m_outer_ty << " }"; } bool revisit(Context& context, bool is_fallback_mode) override { TRACE_FUNCTION_F("Match ergonomics - " << m_pattern << " : " << m_outer_ty << (is_fallback_mode ? " (fallback)": "")); + m_outer_ty = context.m_resolve.expand_associated_types(sp, mv$(m_outer_ty)); return this->revisit_inner_real(context, m_pattern, m_outer_ty, m_outer_mode, is_fallback_mode); } // TODO: Recurse into inner patterns, creating new revisitors? @@ -3876,7 +3881,8 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T n_deref ++; } DEBUG("- " << n_deref << " derefs of class " << bt << " to get " << *ty_p); - if( ty_p->m_data.is_Infer() ) { + if( ty_p->m_data.is_Infer() || TU_TEST1(ty_p->m_data, Path, .binding.is_Unbound()) ) + { // Still pure infer, can't do anything // - What if it's a literal? @@ -3957,11 +3963,6 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T MatchErgonomicsRevisit::disable_possibilities_on_bindings(sp, context, pattern); return false; } - if( TU_TEST1(ty_p->m_data, Path, .binding.is_Unbound()) ) { - // TODO: Visit all inner bindings and disable coercion fallbacks on them. - MatchErgonomicsRevisit::disable_possibilities_on_bindings(sp, context, pattern); - return false; - } const auto& ty = *ty_p; // Here we have a known type and binding mode for this pattern @@ -4092,14 +4093,20 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T ASSERT_BUG(sp, str.m_data.is_Tuple(), "Struct-tuple pattern on non-Tuple struct"); const auto& sd = str.m_data.as_Tuple(); const auto& params = e.path.m_params; + ::HIR::TypeRef tmp; + auto maybe_monomorph = [&](const ::HIR::TypeRef& field_type)->const ::HIR::TypeRef& { + return (monomorphise_type_needed(field_type) + ? (tmp = context.m_resolve.expand_associated_types(sp, monomorphise_type(sp, str.m_params, params, field_type))) + : field_type + ); + }; rv = true; for( unsigned int i = 0; i < e.sub_patterns.size(); i ++ ) { /*const*/ auto& sub_pat = e.sub_patterns[i]; const auto& field_type = sd[i].ent; - ::HIR::TypeRef tmp; - const auto& var_ty = (monomorphise_type_needed(field_type) ? (tmp = monomorphise_type(sp, str.m_params, params, field_type)) : field_type); + const auto& var_ty = maybe_monomorph(field_type); rv &= this->revisit_inner(context, sub_pat, var_ty, binding_mode); } } @@ -4122,6 +4129,14 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T const auto& sd = str.m_data.as_Named(); const auto& params = e.path.m_params; + ::HIR::TypeRef tmp; + auto maybe_monomorph = [&](const ::HIR::TypeRef& field_type)->const ::HIR::TypeRef& { + return (monomorphise_type_needed(field_type) + ? (tmp = context.m_resolve.expand_associated_types(sp, monomorphise_type(sp, str.m_params, params, field_type))) + : field_type + ); + }; + rv = true; for( auto& field_pat : e.sub_patterns ) { @@ -4129,14 +4144,8 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T if( f_idx == sd.size() ) { ERROR(sp, E0000, "Struct " << e.path << " doesn't have a field " << field_pat.first); } - const ::HIR::TypeRef& field_type = sd[f_idx].second.ent; - if( monomorphise_type_needed(field_type) ) { - auto field_type_mono = monomorphise_type(sp, str.m_params, params, field_type); - rv &= this->revisit_inner(context, field_pat.second, field_type_mono, binding_mode); - } - else { - rv &= this->revisit_inner(context, field_pat.second, field_type, binding_mode); - } + const ::HIR::TypeRef& field_type = maybe_monomorph(sd[f_idx].second.ent); + rv &= this->revisit_inner(context, field_pat.second, field_type, binding_mode); } } } @@ -4155,6 +4164,14 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T const auto& params = e.path.m_params; + ::HIR::TypeRef tmp; + auto maybe_monomorph = [&](const ::HIR::TypeRef& field_type)->const ::HIR::TypeRef& { + return (monomorphise_type_needed(field_type) + ? (tmp = context.m_resolve.expand_associated_types(sp, monomorphise_type(sp, str.m_params, params, field_type))) + : field_type + ); + }; + if( e.sub_patterns.size() != tup_var.size() ) { ERROR(sp, E0000, "Enum pattern with an incorrect number of fields - " << e.path << " - expected " << tup_var.size() << ", got " << e.sub_patterns.size() ); } @@ -4162,13 +4179,8 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T rv = true; // &= below ensures that all must be complete to return complete for( unsigned int i = 0; i < e.sub_patterns.size(); i ++ ) { - if( monomorphise_type_needed(tup_var[i].ent) ) { - auto var_ty = monomorphise_type(sp, enm.m_params, params, tup_var[i].ent); - rv &= this->revisit_inner(context, e.sub_patterns[i], var_ty, binding_mode); - } - else { - rv &= this->revisit_inner(context, e.sub_patterns[i], tup_var[i].ent, binding_mode); - } + const auto& var_ty = maybe_monomorph(tup_var[i].ent); + rv &= this->revisit_inner(context, e.sub_patterns[i], var_ty, binding_mode); } } TU_ARM(pattern.m_data, EnumStruct, e) { @@ -4181,6 +4193,14 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T const auto& tup_var = str.m_data.as_Named(); const auto& params = e.path.m_params; + ::HIR::TypeRef tmp; + auto maybe_monomorph = [&](const ::HIR::TypeRef& field_type)->const ::HIR::TypeRef& { + return (monomorphise_type_needed(field_type) + ? (tmp = context.m_resolve.expand_associated_types(sp, monomorphise_type(sp, str.m_params, params, field_type))) + : field_type + ); + }; + rv = true; // &= below ensures that all must be complete to return complete for( auto& field_pat : e.sub_patterns ) { @@ -4188,14 +4208,8 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T if( f_idx == tup_var.size() ) { ERROR(sp, E0000, "Enum variant " << e.path << " doesn't have a field " << field_pat.first); } - const ::HIR::TypeRef& field_type = tup_var[f_idx].second.ent; - if( monomorphise_type_needed(field_type) ) { - auto field_type_mono = monomorphise_type(sp, enm.m_params, params, field_type); - rv &= this->revisit_inner(context, field_pat.second, field_type_mono, binding_mode); - } - else { - rv &= this->revisit_inner(context, field_pat.second, field_type, binding_mode); - } + const ::HIR::TypeRef& field_type = maybe_monomorph(tup_var[f_idx].second.ent); + rv &= this->revisit_inner(context, field_pat.second, field_type, binding_mode); } } } @@ -4510,6 +4524,9 @@ void Context::handle_pattern_direct_inner(const Span& sp, ::HIR::Pattern& pat, c m_pat_total_size(pat_total_size) {} + const Span& span() const override { + return sp; + } void fmt(::std::ostream& os) const override { os << "SplitTuplePatRevisit { " << m_outer_ty << " = (" << m_leading_tys << ", ..., " << m_trailing_tys << ") }"; } @@ -4566,6 +4583,9 @@ void Context::handle_pattern_direct_inner(const Span& sp, ::HIR::Pattern& pat, c sp(mv$(sp)), inner(mv$(inner)), type(mv$(type)), size(size) {} + const Span& span() const override { + return sp; + } void fmt(::std::ostream& os) const override { os << "SlicePatRevisit { " << inner << ", " << type << ", " << size; } bool revisit(Context& context, bool is_fallback) override { const auto& ty = context.get_type(type); @@ -4641,6 +4661,9 @@ void Context::handle_pattern_direct_inner(const Span& sp, ::HIR::Pattern& pat, c sp(mv$(sp)), inner(mv$(inner)), type(mv$(type)), var_ty(mv$(var_ty)), min_size(size) {} + const Span& span() const override { + return sp; + } void fmt(::std::ostream& os) const override { os << "SplitSlice inner=" << inner << ", outer=" << type << ", binding="<type); @@ -7293,6 +7316,10 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR: { } } + for(const auto& adv : context.adv_revisits) + { + WARNING(adv->span(), W0000, "Spare Rule - " << FMT_CB(os, adv->fmt(os))); + } BUG(root_ptr->span(), "Spare rules left after typecheck stabilised"); } DEBUG("root_ptr = " << typeid(*root_ptr).name() << " " << root_ptr->m_res_type); -- cgit v1.2.3 From 25185eacb41ccd14cdb6a6a4bf49c4f6fef92adb Mon Sep 17 00:00:00 2001 From: John Hodge Date: Thu, 28 Feb 2019 22:47:09 +0800 Subject: HIR Typecheck - Tweak to validation code for closure casts --- src/hir_typeck/expr_check.cpp | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/src/hir_typeck/expr_check.cpp b/src/hir_typeck/expr_check.cpp index 7d5a9c6f..fc0814aa 100644 --- a/src/hir_typeck/expr_check.cpp +++ b/src/hir_typeck/expr_check.cpp @@ -306,11 +306,10 @@ namespace { } // Check castability - TU_MATCH_DEF(::HIR::TypeRef::Data, (dst_ty.m_data), (de), - ( - ERROR(sp, E0000, "Invalid cast to " << dst_ty); - ), - (Pointer, + TU_MATCH_HDRA( (dst_ty.m_data), {) + default: + ERROR(sp, E0000, "Invalid cast to\n " << dst_ty << "\n from\n " << src_ty); + TU_ARMA(Pointer, de) { TU_MATCH_DEF(::HIR::TypeRef::Data, (src_ty.m_data), (se), ( ERROR(sp, E0000, "Invalid cast to " << dst_ty << " from " << src_ty); @@ -346,11 +345,29 @@ namespace { this->check_types_equal(sp, *de.inner, *se.inner); ) ) - ), - (Primitive, + } + TU_ARMA(Function, de) { + // NOTE: cast fn() only valid from: + // - the same function pointer (already checked, but eventually could be a stripping of the path tag) + // - A capture-less closure + TU_MATCH_HDRA( (src_ty.m_data), {) + default: + // TODO: Closure structs are also allowed, iff they don't have captures + //ERROR(sp, E0000, "Invalid cast to " << dst_ty << " from " << src_ty); + break; + //TU_ARMA(Path, se) { + // } + //TU_ARMA(Function, se) { + // } + TU_ARMA(Closure, se) { + // Allowed, but won't exist after expansion + } + } + } + TU_ARMA(Primitive, de) { // TODO: Check cast to primitive - ) - ) + } + } node.m_value->visit( *this ); } -- cgit v1.2.3 From ed4d41c9762303bd06ff270593b358e8077cd534 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 1 Mar 2019 18:35:05 +0800 Subject: HIR Annotate Usage - Handle `break` --- src/hir_expand/annotate_value_usage.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/hir_expand/annotate_value_usage.cpp b/src/hir_expand/annotate_value_usage.cpp index e763586c..5a7dfbd8 100644 --- a/src/hir_expand/annotate_value_usage.cpp +++ b/src/hir_expand/annotate_value_usage.cpp @@ -122,6 +122,10 @@ namespace { void visit(::HIR::ExprNode_LoopControl& node) override { // NOTE: Leaf + if( node.m_value ) + { + this->visit_node_ptr(node.m_value); + } } void visit(::HIR::ExprNode_Match& node) override { -- cgit v1.2.3 From f955d04099a70bca8fe238a77c8c328150ff028c Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 1 Mar 2019 22:19:09 +0800 Subject: Expand - Use discriminant_value to reduce size of auto-generated matches --- src/expand/derive.cpp | 114 ++++++++++++-------------------------------------- 1 file changed, 26 insertions(+), 88 deletions(-) diff --git a/src/expand/derive.cpp b/src/expand/derive.cpp index a03992da..dddd82b6 100644 --- a/src/expand/derive.cpp +++ b/src/expand/derive.cpp @@ -832,54 +832,21 @@ public: // TODO: Compare the discriminants using the `discriminant_value` intrinsic // - Requires a way of emitting said intrinsic into the AST - for(unsigned int a = 0; a < enm.variants().size(); a ++ ) + // - LAZY WAY - hard-code ::"core"::intrinsics::discriminant_value { - for(unsigned int b = 0; b < enm.variants().size(); b ++ ) - { - if( a == b ) - continue ; - - struct H { - static ::AST::Pattern get_pat_nc(const Span& sp, const AST::Path& base_path, const AST::EnumVariant& v) { - AST::Path var_path = base_path + v.m_name; - - TU_MATCH(::AST::EnumVariantData, (v.m_data), (e), - (Value, - return AST::Pattern(AST::Pattern::TagValue(), sp, AST::Pattern::Value::make_Named(var_path)); - ), - (Tuple, - return AST::Pattern(AST::Pattern::TagNamedTuple(), sp, var_path, AST::Pattern::TuplePat { {}, true, {} }); - ), - (Struct, - return AST::Pattern(AST::Pattern::TagStruct(), sp, var_path, {}, false); - ) - ) - throw ""; - } - }; - ::AST::Pattern pat_a = H::get_pat_nc(sp, base_path, enm.variants()[a]); - ::AST::Pattern pat_b = H::get_pat_nc(sp, base_path, enm.variants()[b]); - - ::std::vector< AST::Pattern> pats; - { - ::std::vector< AST::Pattern> tuple_pats; - tuple_pats.push_back( AST::Pattern(AST::Pattern::TagReference(), sp, false, mv$(pat_a)) ); - tuple_pats.push_back( AST::Pattern(AST::Pattern::TagReference(), sp, false, mv$(pat_b)) ); - pats.push_back( AST::Pattern(AST::Pattern::TagTuple(), sp, mv$(tuple_pats)) ); - } - - auto code = NEWNODE(CallPath, this->get_path(opts.core_name, "option", "Option", "Some"), - ::make_vec1( - NEWNODE(NamedValue, this->get_path(opts.core_name, "cmp", "Ordering", (a < b ? "Less" : "Greater"))) - ) - ); + auto code = NEWNODE(CallPath, this->get_path(opts.core_name, "cmp", "PartialOrd", "partial_cmp"), + ::make_vec2( + NEWNODE(UniOp, AST::ExprNode_UniOp::REF, NEWNODE(CallPath, this->get_path(opts.core_name, "intrinsics", "discriminant_value"), make_vec1( NEWNODE(NamedValue, AST::Path("self")) )) ), + NEWNODE(UniOp, AST::ExprNode_UniOp::REF, NEWNODE(CallPath, this->get_path(opts.core_name, "intrinsics", "discriminant_value"), make_vec1( NEWNODE(NamedValue, AST::Path("v")) )) ) + ) + ); + ::std::vector< AST::Pattern> pats = make_vec1( AST::Pattern() ); - arms.push_back(AST::ExprNode_Match_Arm( - mv$(pats), - nullptr, - mv$(code) - )); - } + arms.push_back(AST::ExprNode_Match_Arm( + mv$(pats), + nullptr, + mv$(code) + )); } ::std::vector vals; @@ -1217,50 +1184,21 @@ public: )); } - for(unsigned int a = 0; a < enm.variants().size(); a ++ ) - { - for(unsigned int b = 0; b < enm.variants().size(); b ++ ) - { - if( a == b ) - continue ; - - struct H { - static ::AST::Pattern get_pat_nc(const Span& sp, const AST::Path& base_path, const AST::EnumVariant& v) { - AST::Path var_path = base_path + v.m_name; - - TU_MATCH(::AST::EnumVariantData, (v.m_data), (e), - (Value, - return AST::Pattern(AST::Pattern::TagValue(), sp, AST::Pattern::Value::make_Named(var_path)); - ), - (Tuple, - return AST::Pattern(AST::Pattern::TagNamedTuple(), sp, var_path, AST::Pattern::TuplePat { {}, true, {} }); - ), - (Struct, - return AST::Pattern(AST::Pattern::TagStruct(), sp, var_path, {}, false); - ) - ) - throw ""; - } - }; - ::AST::Pattern pat_a = H::get_pat_nc(sp, base_path, enm.variants()[a]); - ::AST::Pattern pat_b = H::get_pat_nc(sp, base_path, enm.variants()[b]); - ::std::vector< AST::Pattern> pats; - { - ::std::vector< AST::Pattern> tuple_pats; - tuple_pats.push_back( AST::Pattern(AST::Pattern::TagReference(), sp, false, mv$(pat_a)) ); - tuple_pats.push_back( AST::Pattern(AST::Pattern::TagReference(), sp, false, mv$(pat_b)) ); - pats.push_back( AST::Pattern(AST::Pattern::TagTuple(), sp, mv$(tuple_pats)) ); - } - - auto code = NEWNODE(NamedValue, this->get_path(opts.core_name, "cmp", "Ordering", (a < b ? "Less" : "Greater"))); + { + auto code = NEWNODE(CallPath, this->get_path(opts.core_name, "cmp", "Ord", "cmp"), + ::make_vec2( + NEWNODE(UniOp, AST::ExprNode_UniOp::REF, NEWNODE(CallPath, this->get_path(opts.core_name, "intrinsics", "discriminant_value"), make_vec1( NEWNODE(NamedValue, AST::Path("self")) )) ), + NEWNODE(UniOp, AST::ExprNode_UniOp::REF, NEWNODE(CallPath, this->get_path(opts.core_name, "intrinsics", "discriminant_value"), make_vec1( NEWNODE(NamedValue, AST::Path("v")) )) ) + ) + ); + ::std::vector< AST::Pattern> pats = make_vec1( AST::Pattern() ); - arms.push_back(AST::ExprNode_Match_Arm( - mv$(pats), - nullptr, - mv$(code) - )); - } + arms.push_back(AST::ExprNode_Match_Arm( + mv$(pats), + nullptr, + mv$(code) + )); } ::std::vector vals; -- cgit v1.2.3 From 0bf33b8dc69b4f73d0207e277498858486057c29 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 2 Mar 2019 09:32:27 +0800 Subject: HIR - Clone deref count when cloning pattern --- src/hir/pattern.cpp | 64 +++++++++++++++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 29 deletions(-) diff --git a/src/hir/pattern.cpp b/src/hir/pattern.cpp index a86dbfa7..d25b25e7 100644 --- a/src/hir/pattern.cpp +++ b/src/hir/pattern.cpp @@ -184,102 +184,108 @@ namespace { } } // namespace -::HIR::Pattern HIR::Pattern::clone() const +namespace { ::HIR::Pattern::Data clone_pattern_data(const ::HIR::Pattern::Data& m_data) { TU_MATCH(::HIR::Pattern::Data, (m_data), (e), (Any, - return Pattern(m_binding, Data::make_Any({})); + return ::HIR::Pattern::Data::make_Any({}); ), (Box, - return Pattern(m_binding, Data::make_Box({ + return ::HIR::Pattern::Data::make_Box({ box$( e.sub->clone() ) - })); + }); ), (Ref, - return Pattern(m_binding, Data::make_Ref({ + return ::HIR::Pattern::Data::make_Ref({ e.type, box$(e.sub->clone()) - })); + }); ), (Tuple, - return Pattern(m_binding, Data::make_Tuple({ + return ::HIR::Pattern::Data::make_Tuple({ clone_pat_vec(e.sub_patterns) - })); + }); ), (SplitTuple, - return Pattern(m_binding, Data::make_SplitTuple({ + return ::HIR::Pattern::Data::make_SplitTuple({ clone_pat_vec(e.leading), clone_pat_vec(e.trailing), e.total_size - })); + }); ), (StructValue, - return Pattern(m_binding, Data::make_StructValue({ + return ::HIR::Pattern::Data::make_StructValue({ e.path.clone(), e.binding - })); + }); ), (StructTuple, - return Pattern(m_binding, Data::make_StructTuple({ + return ::HIR::Pattern::Data::make_StructTuple({ e.path.clone(), e.binding, clone_pat_vec(e.sub_patterns) - })); + }); ), (Struct, - return Pattern(m_binding, Data::make_Struct({ + return ::HIR::Pattern::Data::make_Struct({ e.path.clone(), e.binding, clone_pat_fields(e.sub_patterns), e.is_exhaustive - })); + }); ), (Value, - return Pattern(m_binding, Data::make_Value({ + return ::HIR::Pattern::Data::make_Value({ clone_patval(e.val) - })); + }); ), (Range, - return Pattern(m_binding, Data::make_Range({ + return ::HIR::Pattern::Data::make_Range({ clone_patval(e.start), clone_patval(e.end) - })); + }); ), (EnumValue, - return Pattern(m_binding, Data::make_EnumValue({ e.path.clone(), e.binding_ptr, e.binding_idx })); + return ::HIR::Pattern::Data::make_EnumValue({ e.path.clone(), e.binding_ptr, e.binding_idx }); ), (EnumTuple, - return Pattern(m_binding, Data::make_EnumTuple({ + return ::HIR::Pattern::Data::make_EnumTuple({ e.path.clone(), e.binding_ptr, e.binding_idx, clone_pat_vec(e.sub_patterns) - })); + }); ), (EnumStruct, - return Pattern(m_binding, Data::make_EnumStruct({ + return ::HIR::Pattern::Data::make_EnumStruct({ e.path.clone(), e.binding_ptr, e.binding_idx, clone_pat_fields(e.sub_patterns), e.is_exhaustive - })); + }); ), (Slice, - return Pattern(m_binding, Data::make_Slice({ + return ::HIR::Pattern::Data::make_Slice({ clone_pat_vec(e.sub_patterns) - })); + }); ), (SplitSlice, - return Pattern(m_binding, Data::make_SplitSlice({ + return ::HIR::Pattern::Data::make_SplitSlice({ clone_pat_vec(e.leading), e.extra_bind, clone_pat_vec(e.trailing) - })); + }); ) ) throw ""; +} } +::HIR::Pattern HIR::Pattern::clone() const +{ + auto rv = Pattern(m_binding, clone_pattern_data(m_data)); + rv.m_implicit_deref_count = m_implicit_deref_count; + return rv; } -- cgit v1.2.3 From f5833a7d8c2ea28e5aa39bc4ac6acd7c1d801ac2 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 2 Mar 2019 09:32:51 +0800 Subject: HIR Dump - Print break value --- src/hir/dump.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/hir/dump.cpp b/src/hir/dump.cpp index 6d786a90..a60ec643 100644 --- a/src/hir/dump.cpp +++ b/src/hir/dump.cpp @@ -384,6 +384,10 @@ namespace { if( node.m_label != "" ) { m_os << " '" << node.m_label; } + if( node.m_value ) { + m_os << " "; + this->visit_node_ptr(node.m_value); + } } void visit(::HIR::ExprNode_Match& node) override { -- cgit v1.2.3 From 5edbd3f02a393ba6e46008f09d7747a57e19472c Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 2 Mar 2019 15:05:06 +0800 Subject: HIR Expand Closures - Cast/coerce closure to fn() --- src/hir_expand/closures.cpp | 184 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 173 insertions(+), 11 deletions(-) diff --git a/src/hir_expand/closures.cpp b/src/hir_expand/closures.cpp index e4380f40..bdf6ddf0 100644 --- a/src/hir_expand/closures.cpp +++ b/src/hir_expand/closures.cpp @@ -210,11 +210,11 @@ namespace { } } - static void fix_type(const ::HIR::Crate& crate, t_cb_generic monomorph_cb, ::HIR::TypeRef& ty) { + static void fix_type(const ::HIR::Crate& crate, const Span& sp, t_cb_generic monomorph_cb, ::HIR::TypeRef& ty) { TU_IFLET( ::HIR::TypeRef::Data, ty.m_data, Closure, e, DEBUG("Closure: " << e.node->m_obj_path_base); - auto path = monomorphise_genericpath_with(Span(), e.node->m_obj_path_base, monomorph_cb, false); - const auto& str = crate.get_struct_by_path( Span(), path.m_path ); + auto path = monomorphise_genericpath_with(sp, e.node->m_obj_path_base, monomorph_cb, false); + const auto& str = crate.get_struct_by_path(sp, path.m_path); DEBUG(ty << " -> " << path); ty = ::HIR::TypeRef::new_path( mv$(path), ::HIR::TypeRef::TypePathBinding::make_Struct(&str) ); ) @@ -249,6 +249,42 @@ namespace { visit_type(node->m_res_type); } + void visit(::HIR::ExprNode_Cast& node) override + { + const Span& sp = node.span(); + // Handle casts from closures to function pointers + if( node.m_value->m_res_type.m_data.is_Closure() ) + { + const auto& src_te = node.m_value->m_res_type.m_data.as_Closure(); + ASSERT_BUG(sp, node.m_res_type.m_data.is_Function(), "Cannot convert closure to non-fn type"); + //const auto& dte = node.m_res_type.m_data.as_Function(); + if( src_te.node->m_class != ::HIR::ExprNode_Closure::Class::NoCapture ) + { + ERROR(sp, E0000, "Cannot cast a closure with captures to a fn() type"); + } + + ::HIR::FunctionType fcn_ty_inner { /*is_unsafe=*/false, ABI_RUST, box$(src_te.node->m_return.clone()), {} }; + ::std::vector<::HIR::TypeRef> arg_types; + fcn_ty_inner.m_arg_types.reserve(src_te.node->m_args.size()); + arg_types.reserve(src_te.node->m_args.size()); + for(const auto& arg : src_te.node->m_args) + { + fcn_ty_inner.m_arg_types.push_back( arg.second.clone() ); + arg_types.push_back(arg.second.clone()); + } + auto trait_params = ::HIR::PathParams( ::HIR::TypeRef(mv$(arg_types)) ); + auto res_ty = ::HIR::TypeRef(mv$(fcn_ty_inner)); + + const auto& str = m_crate.get_struct_by_path(sp, src_te.node->m_obj_path.m_path); + auto closure_type = ::HIR::TypeRef::new_path( src_te.node->m_obj_path.clone(), &str ); + auto fn_path = ::HIR::Path(mv$(closure_type), "call_free"); + fn_path.m_data.as_UfcsInherent().impl_params = src_te.node->m_obj_path.m_params.clone(); + + node.m_value = NEWNODE(mv$(res_ty), PathValue, sp, mv$(fn_path), ::HIR::ExprNode_PathValue::FUNCTION); + } + ::HIR::ExprVisitorDef::visit(node); + } + void visit(::HIR::ExprNode_CallValue& node) override { TU_IFLET( ::HIR::TypeRef::Data, node.m_value->m_res_type.m_data, Closure, e, @@ -276,7 +312,7 @@ namespace { { bool run_eat = m_run_eat; m_run_eat = false; - fix_type(m_crate, m_monomorph_cb, ty); + fix_type(m_crate, Span(), m_monomorph_cb, ty); ::HIR::ExprVisitorDef::visit_type(ty); if( run_eat ) { // TODO: Instead of running EAT, just mark any Unbound UfcsKnown types as Opaque @@ -303,6 +339,35 @@ namespace { code.m_bindings[0] = self_ty.clone(); } } + static ::HIR::TraitImpl make_fnfree( + ::HIR::GenericParams params, + ::HIR::TypeRef closure_type, + ::std::vector<::std::pair< ::HIR::Pattern, ::HIR::TypeRef>> args, + ::HIR::TypeRef ret_ty, + ::HIR::ExprPtr code + ) + { + // NOTE: Fixup isn't needed, there's no self + //fix_fn_params(code, closure_type, args_argent.second); + return ::HIR::TraitImpl { + mv$(params), {}, mv$(closure_type), + make_map1( + ::std::string("call_free"), ::HIR::TraitImpl::ImplEnt< ::HIR::Function> { false, ::HIR::Function { + false, ::HIR::Linkage {}, + ::HIR::Function::Receiver::Free, + ABI_RUST, false, false, + {}, + mv$(args), false, + ret_ty.clone(), + mv$(code) + } } + ), + {}, + {}, + {}, + ::HIR::SimplePath() + }; + } static ::HIR::TraitImpl make_fnonce( ::HIR::GenericParams params, ::HIR::PathParams trait_params, @@ -711,7 +776,83 @@ namespace { { case ::HIR::ExprNode_Closure::Class::Unknown: node.m_class = ::HIR::ExprNode_Closure::Class::NoCapture; - case ::HIR::ExprNode_Closure::Class::NoCapture: + case ::HIR::ExprNode_Closure::Class::NoCapture: { + + struct H2 { + static ::std::pair<::HIR::ExprNode_Closure::Class, HIR::TraitImpl> make_dispatch( + const Span& sp, + ::HIR::ExprNode_Closure::Class c, + ::HIR::GenericParams params, + ::HIR::PathParams trait_params, + const ::HIR::TypeRef& closure_type, + const ::HIR::TypeRef& args_ty, + const ::HIR::TypeRef& ret_type + ) + { + const auto& args_tup_inner = args_ty.m_data.as_Tuple(); + // 1. Create a list of `arg.0, arg.1, arg.2, ...` for the dispatch methods + ::std::vector dispatch_args; + ::std::vector dispatch_node_args_cache; + dispatch_args.reserve( args_tup_inner.size() ); + dispatch_node_args_cache.reserve( args_tup_inner.size()+1 ); + for(size_t i = 0; i < args_tup_inner.size(); i ++) + { + const auto& ty = args_tup_inner[i]; + dispatch_args.push_back( NEWNODE(ty.clone(), Field, sp, NEWNODE(args_ty.clone(), Variable, sp, "arg", 1), FMT(i)) ); + dispatch_node_args_cache.push_back( ty.clone() ); + } + dispatch_node_args_cache.push_back( ret_type.clone() ); + auto path = ::HIR::Path(closure_type.clone(), "call_free"); + path.m_data.as_UfcsInherent().impl_params = closure_type.m_data.as_Path().path.m_data.as_Generic().m_params.clone(); + HIR::ExprNodeP dispatch_node = NEWNODE(ret_type.clone(), CallPath, sp, + mv$(path), + mv$(dispatch_args) + ); + dynamic_cast<::HIR::ExprNode_CallPath&>(*dispatch_node).m_cache.m_arg_types = mv$(dispatch_node_args_cache); + + auto args_arg = ::std::make_pair( + ::HIR::Pattern { {false, ::HIR::PatternBinding::Type::Move, "args", 1}, {} }, + args_ty.clone() + ); + HIR::TraitImpl fcn; + switch(c) + { + case ::HIR::ExprNode_Closure::Class::Once: + fcn = H::make_fnonce( mv$(params), mv$(trait_params), closure_type.clone(), mv$(args_arg), ret_type.clone(), mv$(dispatch_node) ); + break; + case ::HIR::ExprNode_Closure::Class::Mut: + fcn = H::make_fnmut( mv$(params), mv$(trait_params), closure_type.clone(), mv$(args_arg), ret_type.clone(), mv$(dispatch_node) ); + break; + case ::HIR::ExprNode_Closure::Class::Shared: + fcn = H::make_fn( mv$(params), mv$(trait_params), closure_type.clone(), mv$(args_arg), ret_type.clone(), mv$(dispatch_node) ); + break; + default: + throw ""; + } + return ::std::make_pair(c, mv$(fcn)); + } + }; + m_out_impls.push_back( H2::make_dispatch(sp, ::HIR::ExprNode_Closure::Class::Once , params.clone(), trait_params.clone(), closure_type, args_ty, ret_type) ); + m_out_impls.push_back( H2::make_dispatch(sp, ::HIR::ExprNode_Closure::Class::Mut , params.clone(), trait_params.clone(), closure_type, args_ty, ret_type) ); + m_out_impls.push_back( H2::make_dispatch(sp, ::HIR::ExprNode_Closure::Class::Shared, params.clone(), mv$(trait_params) , closure_type, args_ty, ret_type) ); + + // 2. Split args_pat/args_ty into separate arguments + ::std::vector<::std::pair< ::HIR::Pattern, ::HIR::TypeRef>> args_split; + args_split.reserve( node.m_args.size() ); + for(size_t i = 0; i < node.m_args.size(); i ++) + { + args_split.push_back(::std::make_pair( + mv$( args_pat.m_data.as_Tuple().sub_patterns[i] ), + mv$( args_ty.m_data.as_Tuple()[i] ) + )); + } + // - Create fn_free free method + m_out_impls.push_back(::std::make_pair( + ::HIR::ExprNode_Closure::Class::NoCapture, + H::make_fnfree( mv$(params), mv$(closure_type), mv$(args_split), mv$(ret_type), mv$(body_code) ) + )); + + } break; case ::HIR::ExprNode_Closure::Class::Shared: { const auto& lang_Fn = m_resolve.m_crate.get_lang_item_path(node.span(), "fn"); const auto method_self_ty = ::HIR::TypeRef::new_borrow( ::HIR::BorrowType::Shared, closure_type.clone() ); @@ -1048,12 +1189,33 @@ namespace { for(auto& impl : m_new_trait_impls) { - const auto& trait = - impl.first == ::HIR::ExprNode_Closure::Class::Once ? crate.get_lang_item_path(sp, "fn_once") - : impl.first == ::HIR::ExprNode_Closure::Class::Mut ? crate.get_lang_item_path(sp, "fn_mut") - : /*impl.first == ::HIR::ExprNode_Closure::Class::Shared ?*/ crate.get_lang_item_path(sp, "fn") - ; - crate.m_trait_impls.insert( ::std::make_pair(trait.clone(), mv$(impl.second)) ); + switch(impl.first) + { + case ::HIR::ExprNode_Closure::Class::Once: + crate.m_trait_impls.insert( ::std::make_pair(crate.get_lang_item_path(sp, "fn_once"), mv$(impl.second)) ); + break; + case ::HIR::ExprNode_Closure::Class::Mut: + crate.m_trait_impls.insert( ::std::make_pair(crate.get_lang_item_path(sp, "fn_mut" ), mv$(impl.second)) ); + break; + case ::HIR::ExprNode_Closure::Class::Shared: + crate.m_trait_impls.insert( ::std::make_pair(crate.get_lang_item_path(sp, "fn" ), mv$(impl.second)) ); + break; + case ::HIR::ExprNode_Closure::Class::NoCapture: + assert(impl.second.m_methods.size() == 1); + assert(impl.second.m_types.empty()); + assert(impl.second.m_constants.empty()); + crate.m_type_impls.push_back( ::HIR::TypeImpl { + mv$(impl.second.m_params), + mv$(impl.second.m_type), + make_map1(impl.second.m_methods.begin()->first, ::HIR::TypeImpl::VisImplEnt< ::HIR::Function> { true, false, mv$(impl.second.m_methods.begin()->second.data) }), + {}, + mv$(impl.second.m_src_module) + } ); + break; + case ::HIR::ExprNode_Closure::Class::Unknown: + BUG(Span(), "Encountered Unkown closure type in new impls"); + break; + } } m_new_trait_impls.resize(0); } -- cgit v1.2.3 From 6013ebc332f9b55658c0cc548ccff7cc58e34d00 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 2 Mar 2019 15:08:15 +0800 Subject: HIR Typecheck Validate - Debugging tweaks --- src/hir_typeck/expr_check.cpp | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/hir_typeck/expr_check.cpp b/src/hir_typeck/expr_check.cpp index fc0814aa..bc3b7f3d 100644 --- a/src/hir_typeck/expr_check.cpp +++ b/src/hir_typeck/expr_check.cpp @@ -352,15 +352,13 @@ namespace { // - A capture-less closure TU_MATCH_HDRA( (src_ty.m_data), {) default: - // TODO: Closure structs are also allowed, iff they don't have captures - //ERROR(sp, E0000, "Invalid cast to " << dst_ty << " from " << src_ty); + ERROR(sp, E0000, "Invalid cast to " << dst_ty << " from " << src_ty); break; - //TU_ARMA(Path, se) { - // } //TU_ARMA(Function, se) { // } TU_ARMA(Closure, se) { // Allowed, but won't exist after expansion + // TODO: Check argument types } } } @@ -659,8 +657,8 @@ namespace { const ::HIR::Function* fcn_ptr = nullptr; ::std::function monomorph_cb; - TU_MATCH(::HIR::Path::Data, (path.m_data), (e), - (Generic, + TU_MATCH_HDRA( (path.m_data), {) + TU_ARMA(Generic, e) { const auto& path_params = e.m_params; const auto& fcn = m_resolve.m_crate.get_function_by_path(sp, e.m_path); @@ -685,8 +683,8 @@ namespace { BUG(sp, "Generic bounding out of total range"); } }; - ), - (UfcsKnown, + } + TU_ARMA(UfcsKnown, e) { const auto& trait_params = e.trait.m_params; const auto& path_params = e.params; @@ -705,11 +703,11 @@ namespace { fcn_ptr = &fcn; monomorph_cb = monomorphise_type_get_cb(sp, &*e.type, &trait_params, &path_params); - ), - (UfcsUnknown, + } + TU_ARMA(UfcsUnknown, e) { TODO(sp, "Hit a UfcsUnknown (" << path << ") - Is this an error?"); - ), - (UfcsInherent, + } + TU_ARMA(UfcsInherent, e) { // - Locate function (and impl block) const ::HIR::TypeImpl* impl_ptr = nullptr; m_resolve.m_crate.find_type_impls(*e.type, [&](const auto& ty)->const ::HIR::TypeRef& { return ty; }, @@ -731,14 +729,15 @@ namespace { // NOTE: Trusts the existing cache. - ASSERT_BUG(sp, e.impl_params.m_types.size() == impl_ptr->m_params.m_types.size(), ""); + ASSERT_BUG(sp, e.impl_params.m_types.size() == impl_ptr->m_params.m_types.size(), + "Path impl_params cache is missized - " << e.impl_params.m_types.size() << " != " << impl_ptr->m_params.m_types.size()); auto& impl_params = e.impl_params; // Create monomorphise callback const auto& fcn_params = e.params; monomorph_cb = monomorphise_type_get_cb(sp, &*e.type, &impl_params, &fcn_params); - ) - ) + } + } assert( fcn_ptr ); const auto& fcn = *fcn_ptr; -- cgit v1.2.3 From ac1133b8af5d6bd35523635377285039db925a4e Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 2 Mar 2019 19:30:04 +0800 Subject: HIR Expand Closures - Rename closures to include a #, fix minor bug --- src/hir_expand/closures.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/hir_expand/closures.cpp b/src/hir_expand/closures.cpp index bdf6ddf0..ee0cff08 100644 --- a/src/hir_expand/closures.cpp +++ b/src/hir_expand/closures.cpp @@ -349,6 +349,8 @@ namespace { { // NOTE: Fixup isn't needed, there's no self //fix_fn_params(code, closure_type, args_argent.second); + assert(code.m_bindings.size() > 0); + code.m_bindings[0] = ::HIR::TypeRef::new_unit(); return ::HIR::TraitImpl { mv$(params), {}, mv$(closure_type), make_map1( @@ -1178,7 +1180,7 @@ namespace { ::HIR::SimplePath root_mod_path(crate.m_crate_name,{}); m_cur_mod_path = &root_mod_path; m_new_type = [&](auto s)->auto { - auto name = FMT("closure_I_" << closure_count); + auto name = FMT("closure#I_" << closure_count); closure_count += 1; auto boxed = box$(( ::HIR::VisEnt< ::HIR::TypeItem> { false, ::HIR::TypeItem( mv$(s) ) } )); crate.m_root_module.m_mod_items.insert( ::std::make_pair(name, mv$(boxed)) ); @@ -1229,7 +1231,7 @@ namespace { unsigned int closure_count = 0; auto saved_nt = mv$(m_new_type); m_new_type = [&](auto s)->auto { - auto name = FMT("closure_" << closure_count); + auto name = FMT("closure#" << closure_count); closure_count += 1; auto boxed = box$( (::HIR::VisEnt< ::HIR::TypeItem> { false, ::HIR::TypeItem( mv$(s) ) }) ); mod.m_mod_items.insert( ::std::make_pair(name, mv$(boxed)) ); -- cgit v1.2.3 From e48bf928679b008cdb342420beeb245d44c56ba9 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 2 Mar 2019 19:31:57 +0800 Subject: MIR Gen - Handle extern types in match --- src/mir/from_hir_match.cpp | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/src/mir/from_hir_match.cpp b/src/mir/from_hir_match.cpp index 6fb77a3b..853e646f 100644 --- a/src/mir/from_hir_match.cpp +++ b/src/mir/from_hir_match.cpp @@ -1094,19 +1094,19 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa } TU_ARM(ty.m_data, Path, e) { // This is either a struct destructure or an enum - TU_MATCHA( (e.binding), (pbe), - (Unbound, + TU_MATCH_HDRA( (e.binding), {) + TU_ARMA(Unbound, pbe) { BUG(sp, "Encounterd unbound path - " << e.path); - ), - (Opaque, + } + TU_ARMA(Opaque, be) { TU_MATCH_DEF( ::HIR::Pattern::Data, (pat.m_data), (pe), ( BUG(sp, "Matching opaque type with invalid pattern - " << pat); ), (Any, this->push_rule( PatternRule::make_Any({}) ); ) ) - ), - (Struct, + } + TU_ARMA(Struct, pbe) { auto monomorph = [&](const auto& ty) { auto rv = monomorphise_type(sp, pbe->m_params, e.path.m_data.as_Generic().m_params, ty); this->m_resolve.expand_associated_types(sp, rv); @@ -1216,14 +1216,19 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa ) ) ) - ), - (Union, + } + TU_ARMA(Union, pbe) { TODO(sp, "Match over union - " << ty); - ), - (ExternType, - TODO(sp, "Match over extern type - " << ty); - ), - (Enum, + } + TU_ARMA(ExternType, pbe) { + TU_MATCH_DEF( ::HIR::Pattern::Data, (pat.m_data), (pe), + ( BUG(sp, "Matching extern type with invalid pattern - " << pat); ), + (Any, + this->push_rule( PatternRule::make_Any({}) ); + ) + ) + } + TU_ARMA(Enum, pbe) { auto monomorph = [&](const auto& ty) { auto rv = monomorphise_type(sp, pbe->m_params, e.path.m_data.as_Generic().m_params, ty); this->m_resolve.expand_associated_types(sp, rv); @@ -1310,8 +1315,8 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa this->push_rule( PatternRule::make_Variant({ pe.binding_idx, mv$(sub_builder.m_rules) }) ); ) ) - ) - ) + } + } } TU_ARM(ty.m_data, Generic, e) { // Generics don't destructure, so the only valid pattern is `_` -- cgit v1.2.3 From 2807f5db9f212314571d791cc02c63d861cc0566 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 2 Mar 2019 22:45:24 +0800 Subject: HIR Typecheck Static - Misc fiddling --- src/hir_typeck/static.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/hir_typeck/static.cpp b/src/hir_typeck/static.cpp index ce7faf6c..1dabb2c2 100644 --- a/src/hir_typeck/static.cpp +++ b/src/hir_typeck/static.cpp @@ -105,7 +105,8 @@ bool StaticTraitResolve::find_impl( } } else if( TARGETVER_1_29 && trait_path == m_lang_Clone ) { - if( type.m_data.is_Tuple() || type.m_data.is_Array() || type.m_data.is_Function() ) + if( type.m_data.is_Tuple() || type.m_data.is_Array() || type.m_data.is_Function() || type.m_data.is_Closure() + || TU_TEST2(type.m_data, Path, .path.m_data, Generic, .m_path.m_components.back().compare(0, 8, "closure#") == 0 ) ) { if( this->type_is_clone(sp, type) ) { return found_cb( ImplRef(&type, &null_params, &null_assoc), false ); @@ -1517,11 +1518,18 @@ bool StaticTraitResolve::type_is_clone(const Span& sp, const ::HIR::TypeRef& ty) return rv; ), (Path, - { + if(true) { auto it = m_clone_cache.find(ty); if( it != m_clone_cache.end() ) return it->second; } + if( TU_TEST1(e.path.m_data, Generic, .m_path.m_components.back().compare(0, 8, "closure#") == 0 ) ) + { + bool rv = true; + // TODO: Check all captures + m_clone_cache.insert(::std::make_pair( ty.clone(), rv )); + return rv; + } auto pp = ::HIR::PathParams(); bool rv = this->find_impl(sp, m_lang_Clone, &pp, ty, [&](auto , bool){ return true; }, true); m_clone_cache.insert(::std::make_pair( ty.clone(), rv )); @@ -2257,12 +2265,12 @@ StaticTraitResolve::ValuePtr StaticTraitResolve::get_value(const Span& sp, const m_crate.find_type_impls(*pe.type, [](const auto&x)->const ::HIR::TypeRef& { return x; }, [&](const auto& impl) { DEBUG("Found impl" << impl.m_params.fmt_args() << " " << impl.m_type); // TODO: Populate pp_impl - ASSERT_BUG(sp, impl.m_params.m_types.size() == pe.impl_params.m_types.size(), ""); // TODO: Specialisation { auto fit = impl.m_methods.find(pe.item); if( fit != impl.m_methods.end() ) { + ASSERT_BUG(sp, impl.m_params.m_types.size() == pe.impl_params.m_types.size(), "Mismatch in param counts " << p << ", params are " << impl.m_params.fmt_args()); DEBUG("- Contains method, good"); rv = ValuePtr { &fit->second.data }; return true; @@ -2272,6 +2280,7 @@ StaticTraitResolve::ValuePtr StaticTraitResolve::get_value(const Span& sp, const auto it = impl.m_constants.find(pe.item); if( it != impl.m_constants.end() ) { + ASSERT_BUG(sp, impl.m_params.m_types.size() == pe.impl_params.m_types.size(), "Mismatch in param counts " << p << ", params are " << impl.m_params.fmt_args()); rv = ValuePtr { &it->second.data }; return true; } -- cgit v1.2.3 From 0350472ab8113fdb875ba9783678e30694551f77 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 2 Mar 2019 22:45:59 +0800 Subject: Lower MIR - Wildcard pattern handling --- src/mir/from_hir.cpp | 44 +++++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index fb214dda..9c7e0b25 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -251,12 +251,15 @@ namespace { } TU_ARMA(Struct, e) { const auto& str = *e.binding; - ASSERT_BUG(sp, str.m_data.is_Named(), "Struct pattern on non-Named struct - " << e.path); - const auto& fields = str.m_data.as_Named(); - for(const auto& fld_pat : e.sub_patterns) + if( !e.sub_patterns.empty() ) { - unsigned idx = ::std::find_if( fields.begin(), fields.end(), [&](const auto&x){ return x.first == fld_pat.first; } ) - fields.begin(); - destructure_from_ex(sp, fld_pat.second, ::MIR::LValue::make_Field({ box$( lval.clone() ), idx}), allow_refutable); + ASSERT_BUG(sp, str.m_data.is_Named(), "Struct pattern on non-Named struct - " << pat); + const auto& fields = str.m_data.as_Named(); + for(const auto& fld_pat : e.sub_patterns) + { + unsigned idx = ::std::find_if( fields.begin(), fields.end(), [&](const auto&x){ return x.first == fld_pat.first; } ) - fields.begin(); + destructure_from_ex(sp, fld_pat.second, ::MIR::LValue::make_Field({ box$( lval.clone() ), idx}), allow_refutable); + } } } // Refutable @@ -1256,11 +1259,10 @@ namespace { auto val = m_builder.get_result_in_lvalue(node.m_value->span(), node.m_value->m_res_type); - TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty_out.m_data), (de), - ( + TU_MATCH_HDRA( (ty_out.m_data), {) + default: BUG(node.span(), "Invalid cast to " << ty_out << " from " << ty_in); - ), - (Pointer, + TU_ARMA(Pointer, de) { if( ty_in.m_data.is_Primitive() ) { const auto& ie = ty_in.m_data.as_Primitive(); switch(ie) @@ -1294,8 +1296,8 @@ namespace { else { BUG(node.span(), "Cannot cast to pointer from " << ty_in); } - ), - (Primitive, + } + TU_ARMA(Primitive, de) { switch(de) { case ::HIR::CoreType::Str: @@ -1362,8 +1364,8 @@ namespace { } break; } - ) - ) + } + } auto res = m_builder.new_temporary(node.m_res_type); m_builder.push_stmt_assign(node.span(), res.clone(), ::MIR::RValue::make_Cast({ mv$(val), node.m_res_type.clone() })); m_builder.set_result( node.span(), mv$(res) ); @@ -1506,8 +1508,8 @@ namespace { this->visit_node_ptr(node.m_value); auto val = m_builder.get_result_in_lvalue(node.m_value->span(), ty_val); - TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty_val.m_data), (te), - ( + TU_MATCH_HDRA( (ty_val.m_data), {) + default: { if( m_builder.is_type_owned_box( ty_val ) ) { // Box magically derefs. @@ -1568,14 +1570,14 @@ namespace { m_builder.set_cur_block(ok_block); } - ), - (Pointer, + } + TU_ARMA(Pointer, te) { // Deref on a pointer - TODO: Requires unsafe - ), - (Borrow, + } + TU_ARMA(Borrow, te) { // Deref on a borrow - Always valid... assuming borrowck is there :) - ) - ) + } + } m_builder.set_result( node.span(), ::MIR::LValue::make_Deref({ box$(val) }) ); } -- cgit v1.2.3 From b3eb51cb50f50db0ca81ff6e9f149143537dc60c Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 3 Mar 2019 19:30:33 +0800 Subject: Codegen C - Don't emit extern types --- src/trans/codegen_c.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 979da88d..13421096 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -1169,6 +1169,7 @@ namespace { TRACE_FUNCTION_F(p); auto item_ty = ::HIR::TypeRef::new_path(p.clone(), &item); const auto* repr = Target_GetTypeRepr(sp, m_resolve, item_ty); + MIR_ASSERT(*m_mir_res, repr, "No repr for struct " << p); ::std::vector fields; for(const auto& ent : repr->fields) @@ -5843,8 +5844,8 @@ namespace { m_of << "struct e_" << Trans_Mangle(te.path); ), (ExternType, - m_of << "struct x_" << Trans_Mangle(te.path); - //return ; + //m_of << "struct x_" << Trans_Mangle(te.path); + return ; ), (Unbound, MIR_BUG(*m_mir_res, "Unbound type path in trans - " << ty); -- cgit v1.2.3 From 5035bc8a18ff44e86d1b05b5893a8954e354bedf Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 3 Mar 2019 19:31:34 +0800 Subject: Trans Enumerate - Add auto clone impl for closures, specialisation fix, and a slight optimisation --- src/trans/enumerate.cpp | 149 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 99 insertions(+), 50 deletions(-) diff --git a/src/trans/enumerate.cpp b/src/trans/enumerate.cpp index c326d125..e1e2bbd5 100644 --- a/src/trans/enumerate.cpp +++ b/src/trans/enumerate.cpp @@ -1205,6 +1205,7 @@ namespace { const auto& trait_vi = trait_vi_it->second; bool is_dynamic = false; + bool any_impl = false; ::std::vector<::HIR::TypeRef> best_impl_params; const ::HIR::TraitImpl* best_impl = nullptr; resolve.find_impl(sp, pe->trait.m_path, pe->trait.m_params, *pe->type, [&](auto impl_ref, auto is_fuzz) { @@ -1216,12 +1217,12 @@ namespace { // TODO: This can only really happen if it's a trait object magic impl, which should become a vtable lookup. return true; } + any_impl = true; const auto& impl_ref_e = impl_ref.m_data.as_TraitImpl(); const auto& impl = *impl_ref_e.impl; ASSERT_BUG(sp, impl.m_trait_args.m_types.size() == pe->trait.m_params.m_types.size(), "Trait parameter count mismatch " << impl.m_trait_args << " vs " << pe->trait.m_params); if( best_impl == nullptr || impl.more_specific_than(*best_impl) ) { - best_impl = &impl; bool is_spec = false; TU_MATCHA( (trait_vi), (ve), (Constant, @@ -1235,7 +1236,8 @@ namespace { (Static, if( pe->item == "vtable#" ) { is_spec = true; - break; + DEBUG("VTable, quick return"); + return true; } auto it = impl.m_statics.find(pe->item); if( it == impl.m_statics.end() ) { @@ -1253,6 +1255,7 @@ namespace { is_spec = fit->second.is_specialisable; ) ) + best_impl = &impl; best_impl_params.clear(); for(unsigned int i = 0; i < impl_ref_e.params.size(); i ++) { @@ -1271,50 +1274,62 @@ namespace { }); if( is_dynamic ) return EntPtr::make_AutoGenerate( {} ); - if( !best_impl ) + if( !any_impl ) return EntPtr {}; - const auto& impl = *best_impl; + if( best_impl ) + { + const auto& impl = *best_impl; - impl_pp.m_types = mv$(best_impl_params); + impl_pp.m_types = mv$(best_impl_params); - TU_MATCHA( (trait_vi), (ve), - (Constant, - auto it = impl.m_constants.find(pe->item); - if( it != impl.m_constants.end() ) - { + // Fallback on default/provided items + TU_MATCH_HDRA( (trait_vi), {) + TU_ARMA(Constant, ve) { + auto it = impl.m_constants.find(pe->item); + ASSERT_BUG(sp, it != impl.m_constants.end(), "best_impl set, but item not found - " << path); DEBUG("Found impl" << impl.m_params.fmt_args() << " " << impl.m_type); return EntPtr { &it->second.data }; - } - TODO(sp, "Associated constant - " << path); - ), - (Static, - if( pe->item == "vtable#" ) - { - DEBUG("VTable, autogen"); - return EntPtr::make_AutoGenerate( {} ); - } - auto it = impl.m_statics.find(pe->item); - if( it != impl.m_statics.end() ) - { + } + TU_ARMA(Static, ve) { + assert(pe->item != "vtable#"); + auto it = impl.m_statics.find(pe->item); + ASSERT_BUG(sp, it != impl.m_statics.end(), "best_impl set, but item not found - " << path); DEBUG("Found impl" << impl.m_params.fmt_args() << " " << impl.m_type); return EntPtr { &it->second.data }; - } - TODO(sp, "Associated static - " << path); - ), - (Function, - auto fit = impl.m_methods.find(pe->item); - if( fit != impl.m_methods.end() ) - { + } + TU_ARMA(Function, ve) { + auto fit = impl.m_methods.find(pe->item); + ASSERT_BUG(sp, fit != impl.m_methods.end(), "best_impl set, but item not found - " << path); DEBUG("Found impl" << impl.m_params.fmt_args() << " " << impl.m_type); return EntPtr { &fit->second.data }; + } } - impl_pp = pe->trait.m_params.clone(); - // HACK! By adding a new parameter here, the MIR will always be monomorphised - impl_pp.m_types.push_back( ::HIR::TypeRef() ); - return EntPtr { &ve }; - ) - ) - BUG(sp, ""); + } + else + { + // Fallback on default/provided items + TU_MATCH_HDRA( (trait_vi), {) + TU_ARMA(Constant, ve) { + TODO(sp, "Associated constant - " << path); + } + TU_ARMA(Static, ve) { + if( pe->item == "vtable#" ) + { + DEBUG("VTable, autogen"); + return EntPtr::make_AutoGenerate( {} ); + } + TODO(sp, "Associated static - " << path); + } + TU_ARMA(Function, ve) { + ASSERT_BUG(sp, ve.m_code.m_mir, "Attempting to use default method with no body MIR - " << path); + impl_pp = pe->trait.m_params.clone(); + // HACK! By adding a new parameter here, the MIR will always be monomorphised + impl_pp.m_types.push_back( ::HIR::TypeRef() ); + return EntPtr { &ve }; + } + } + } + throw "unreachable"; } else { @@ -1331,6 +1346,24 @@ void Trans_Enumerate_FillFrom_Path(EnumState& state, const ::HIR::Path& path, co Span sp; auto path_mono = pp.monomorph(state.crate, path); DEBUG("- " << path_mono); + // TODO: If already in the list, return early + if( state.rv.m_functions.count(path) ) { + DEBUG("> Already done function"); + return ; + } + if( state.rv.m_statics.count(path) ) { + DEBUG("> Already done static"); + return ; + } + if( state.rv.m_constants.count(path) ) { + DEBUG("> Already done constant"); + return ; + } + if( state.rv.m_vtables.count(path) ) { + DEBUG("> Already done vtable"); + return ; + } + Trans_Params sub_pp(sp); TU_MATCHA( (path_mono.m_data), (pe), (Generic, @@ -1352,11 +1385,11 @@ void Trans_Enumerate_FillFrom_Path(EnumState& state, const ::HIR::Path& path, co // Get the item type // - Valid types are Function and Static auto item_ref = get_ent_fullpath(sp, state.crate, path_mono, sub_pp.pp_impl); - TU_MATCHA( (item_ref), (e), - (NotFound, + TU_MATCH_HDRA( (item_ref), {) + TU_ARMA(NotFound, e) { BUG(sp, "Item not found for " << path_mono); - ), - (AutoGenerate, + } + TU_ARMA(AutoGenerate, e) { if( path_mono.m_data.is_Generic() ) { // Leave generation of struct/enum constructors to codgen @@ -1390,7 +1423,7 @@ void Trans_Enumerate_FillFrom_Path(EnumState& state, const ::HIR::Path& path, co else if( TARGETVER_1_29 && path_mono.m_data.is_UfcsKnown() && path_mono.m_data.as_UfcsKnown().trait == state.crate.get_lang_item_path_opt("clone") ) { const auto& pe = path_mono.m_data.as_UfcsKnown(); - ASSERT_BUG(sp, pe.item == "clone", ""); + ASSERT_BUG(sp, pe.item == "clone" || pe.item == "clone_from", "Unexpected Clone method called, " << path_mono); const auto& inner_ty = *pe.type; // If this is !Copy, then we need to ensure that the inner type's clone impls are also available ::StaticTraitResolve resolve { state.crate }; @@ -1399,7 +1432,7 @@ void Trans_Enumerate_FillFrom_Path(EnumState& state, const ::HIR::Path& path, co auto enum_impl = [&](const ::HIR::TypeRef& ity) { if( !resolve.type_is_copy(sp, ity) ) { - auto p = ::HIR::Path(ity.clone(), pe.trait.clone(), "clone"); + auto p = ::HIR::Path(ity.clone(), pe.trait.clone(), pe.item); Trans_Enumerate_FillFrom_Path(state, p, {}); } }; @@ -1409,6 +1442,22 @@ void Trans_Enumerate_FillFrom_Path(EnumState& state, const ::HIR::Path& path, co enum_impl(ity); } } + else if( const auto* te = inner_ty.m_data.opt_Array() ) { + enum_impl(*te->inner); + } + else if( TU_TEST2(inner_ty.m_data, Path, .path.m_data, Generic, .m_path.m_components.back().compare(0, 8, "closure#") == 0) ) { + const auto& gp = inner_ty.m_data.as_Path().path.m_data.as_Generic(); + const auto& str = state.crate.get_struct_by_path(sp, gp.m_path); + Trans_Params p; + p.sp = sp; + p.pp_impl = gp.m_params.clone(); + for(const auto& fld : str.m_data.as_Tuple()) + { + ::HIR::TypeRef tmp; + const auto& ty_m = monomorphise_type_needed(fld.ent) ? (tmp = p.monomorph(resolve, fld.ent)) : fld.ent; + enum_impl(ty_m); + } + } else { BUG(sp, "Unhandled magic clone in enumerate - " << inner_ty); } @@ -1420,21 +1469,21 @@ void Trans_Enumerate_FillFrom_Path(EnumState& state, const ::HIR::Path& path, co { BUG(sp, "AutoGenerate returned for unknown path type - " << path_mono); } - ), - (Function, + } + TU_ARMA(Function, e) { // Add this path (monomorphised) to the queue state.enum_fcn(mv$(path_mono), *e, mv$(sub_pp)); - ), - (Static, + } + TU_ARMA(Static, e) { if( auto* ptr = state.rv.add_static(mv$(path_mono)) ) { Trans_Enumerate_FillFrom(state, *e, *ptr, mv$(sub_pp)); } - ), - (Constant, + } + TU_ARMA(Constant, e) { Trans_Enumerate_FillFrom_Literal(state, e->m_value_res, sub_pp); - ) - ) + } + } } void Trans_Enumerate_FillFrom_MIR_LValue(EnumState& state, const ::MIR::LValue& lv, const Trans_Params& pp) { -- cgit v1.2.3 From cf70b8c572509244b2b62d68a6f19aecff3cdc47 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 3 Mar 2019 19:32:55 +0800 Subject: Trans Auto Impls - Clone for closures --- src/trans/auto_impls.cpp | 129 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 91 insertions(+), 38 deletions(-) diff --git a/src/trans/auto_impls.cpp b/src/trans/auto_impls.cpp index 877659b2..ec4b8a42 100644 --- a/src/trans/auto_impls.cpp +++ b/src/trans/auto_impls.cpp @@ -44,6 +44,48 @@ namespace { }; } +namespace { + ::MIR::Param clone_field(const State& state, const Span& sp, ::MIR::Function& mir_fcn, const ::HIR::TypeRef& subty, ::MIR::LValue fld_lvalue) + { + if( state.resolve.type_is_copy(sp, subty) ) + { + return ::std::move(fld_lvalue); + } + else + { + const auto& lang_Clone = state.resolve.m_crate.get_lang_item_path(sp, "clone"); + // Allocate to locals (one for the `&T`, the other for the cloned `T`) + auto borrow_lv = ::MIR::LValue::make_Local( mir_fcn.locals.size() ); + mir_fcn.locals.push_back(::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, subty.clone())); + auto res_lv = ::MIR::LValue::make_Local( mir_fcn.locals.size() ); + mir_fcn.locals.push_back(subty.clone()); + + // Call `::clone`, passing a borrow of the field + ::MIR::BasicBlock bb; + bb.statements.push_back(::MIR::Statement::make_Assign({ + borrow_lv.clone(), + ::MIR::RValue::make_Borrow({ 0, ::HIR::BorrowType::Shared, mv$(fld_lvalue) }) + })); + bb.terminator = ::MIR::Terminator::make_Call({ + static_cast(mir_fcn.blocks.size() + 2), // return block (after the panic block below) + static_cast(mir_fcn.blocks.size() + 1), // panic block (next block) + res_lv.clone(), + ::MIR::CallTarget( ::HIR::Path(subty.clone(), lang_Clone, "clone") ), + ::make_vec1<::MIR::Param>( ::std::move(borrow_lv) ) + }); + mir_fcn.blocks.push_back(::std::move( bb )); + + // Stub panic handling (TODO: Make this iterate `values` and drop all of them) + ::MIR::BasicBlock panic_bb; + bb.terminator = ::MIR::Terminator::make_Diverge({}); + mir_fcn.blocks.push_back(::std::move( panic_bb )); + + // Save the output of the `clone` call + return ::std::move(res_lv); + } + } +} + void Trans_AutoImpl_Clone(State& state, ::HIR::TypeRef ty) { Span sp; @@ -63,53 +105,64 @@ void Trans_AutoImpl_Clone(State& state, ::HIR::TypeRef ty) } else { - const auto& lang_Clone = state.resolve.m_crate.get_lang_item_path(sp, "clone"); TU_MATCH_HDRA( (ty.m_data), {) default: - TODO(sp, "auto Clone for " << ty << " - Not Copy"); + TODO(sp, "auto Clone for " << ty << " - Unknown and not Copy"); + TU_ARMA(Path, te) { + // closures are identified by the name starting with 'closure#' + if( TU_TEST1(te.path.m_data, Generic, .m_path.m_components.back().compare(0, 8, "closure#") == 0) ) { + const auto& gp = te.path.m_data.as_Generic(); + const auto& str = state.resolve.m_crate.get_struct_by_path(sp, gp.m_path); + Trans_Params p; + p.sp = sp; + p.pp_impl = gp.m_params.clone(); + ::std::vector< ::MIR::Param> values; values.reserve( str.m_data.as_Tuple().size() ); + for(const auto& fld : str.m_data.as_Tuple()) + { + ::HIR::TypeRef tmp; + const auto& ty_m = monomorphise_type_needed(fld.ent) ? (tmp = p.monomorph(state.resolve, fld.ent)) : fld.ent; + auto fld_lvalue = ::MIR::LValue::make_Field({ box$(::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Argument({ 0 })) })), static_cast(values.size()) }); + values.push_back( clone_field(state, sp, mir_fcn, ty_m, mv$(fld_lvalue)) ); + } + // Construct the result value + ::MIR::BasicBlock bb; + bb.statements.push_back(::MIR::Statement::make_Assign({ + ::MIR::LValue::make_Return({}), + ::MIR::RValue::make_Struct({ gp.clone(), mv$(values) }) + })); + bb.terminator = ::MIR::Terminator::make_Return({}); + mir_fcn.blocks.push_back(::std::move( bb )); + } + else { + TODO(sp, "auto Clone for " << ty << " - Unknown and not Copy"); + } + } + TU_ARMA(Array, te) { + ASSERT_BUG(sp, te.size_val < 256, "TODO: Is more than 256 elements sane for auto-generated non-Copy Clone impl? " << ty); + ::std::vector< ::MIR::Param> values; values.reserve(te.size_val); + for(size_t i = 0; i < te.size_val; i ++) + { + auto fld_lvalue = ::MIR::LValue::make_Field({ box$(::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Argument({ 0 })) })), static_cast(i) }); + values.push_back( clone_field(state, sp, mir_fcn, *te.inner, mv$(fld_lvalue)) ); + } + // Construct the result + ::MIR::BasicBlock bb; + bb.statements.push_back(::MIR::Statement::make_Assign({ + ::MIR::LValue::make_Return({}), + ::MIR::RValue::make_Array({ mv$(values) }) + })); + bb.terminator = ::MIR::Terminator::make_Return({}); + mir_fcn.blocks.push_back(::std::move( bb )); + } TU_ARMA(Tuple, te) { assert(te.size() > 0); - ::std::vector< ::MIR::Param> values; + ::std::vector< ::MIR::Param> values; values.reserve(te.size()); // For each field of the tuple, create a clone (either using Copy if posible, or calling Clone::clone) for(const auto& subty : te) { auto fld_lvalue = ::MIR::LValue::make_Field({ box$(::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Argument({ 0 })) })), static_cast(values.size()) }); - if( state.resolve.type_is_copy(sp, subty) ) - { - values.push_back( ::std::move(fld_lvalue) ); - } - else - { - // Allocate to locals (one for the `&T`, the other for the cloned `T`) - auto borrow_lv = ::MIR::LValue::make_Local( mir_fcn.locals.size() ); - mir_fcn.locals.push_back(::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, subty.clone())); - auto res_lv = ::MIR::LValue::make_Local( mir_fcn.locals.size() ); - mir_fcn.locals.push_back(subty.clone()); - - // Call `::clone`, passing a borrow of the field - ::MIR::BasicBlock bb; - bb.statements.push_back(::MIR::Statement::make_Assign({ - borrow_lv.clone(), - ::MIR::RValue::make_Borrow({ 0, ::HIR::BorrowType::Shared, mv$(fld_lvalue) }) - })); - bb.terminator = ::MIR::Terminator::make_Call({ - static_cast(mir_fcn.blocks.size() + 2), // return block (after the panic block below) - static_cast(mir_fcn.blocks.size() + 1), // panic block (next block) - res_lv.clone(), - ::MIR::CallTarget( ::HIR::Path(subty.clone(), lang_Clone, "clone") ), - ::make_vec1<::MIR::Param>( ::std::move(borrow_lv) ) - }); - mir_fcn.blocks.push_back(::std::move( bb )); - - // Stub panic handling (TODO: Make this iterate `values` and drop all of them) - ::MIR::BasicBlock panic_bb; - bb.terminator = ::MIR::Terminator::make_Diverge({}); - mir_fcn.blocks.push_back(::std::move( panic_bb )); - - // Save the output of the `clone` call - values.push_back( ::std::move(res_lv) ); - } + values.push_back( clone_field(state, sp, mir_fcn, subty, mv$(fld_lvalue)) ); } // Construct the result tuple -- cgit v1.2.3 From 9e803f50b3bf0357665626fe59ea6160772b7da4 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 3 Mar 2019 19:33:29 +0800 Subject: Target - Return zero/infinite for extern type align/size --- src/trans/target.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/trans/target.cpp b/src/trans/target.cpp index 6a65be15..141f5b78 100644 --- a/src/trans/target.cpp +++ b/src/trans/target.cpp @@ -589,6 +589,13 @@ bool Target_GetSizeAndAlignOf(const Span& sp, const StaticTraitResolve& resolve, (Path, if( te.binding.is_Opaque() ) return false; + if( te.binding.is_ExternType() ) + { + DEBUG("sizeof on extern type - unsized"); + out_align = 0; + out_size = SIZE_MAX; + return true; + } const auto* repr = Target_GetTypeRepr(sp, resolve, ty); if( !repr ) { @@ -1158,6 +1165,11 @@ namespace { { return make_type_repr_enum(sp, resolve, ty); } + else if( TU_TEST1(ty.m_data, Path, .binding.is_ExternType()) ) + { + // TODO: Do extern types need anything? + return nullptr; + } else if( ty.m_data.is_Primitive() ) { return nullptr; -- cgit v1.2.3 From 3fd7b58fcb650c2504662b5ddcc1b469c5f77958 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 3 Mar 2019 19:34:10 +0800 Subject: Trans Monomorph - (minor) Better assertion --- src/trans/monomorphise.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/trans/monomorphise.cpp b/src/trans/monomorphise.cpp index 892cb730..3b958fec 100644 --- a/src/trans/monomorphise.cpp +++ b/src/trans/monomorphise.cpp @@ -117,6 +117,7 @@ namespace { { static Span sp; TRACE_FUNCTION; + assert(tpl); ::MIR::Function output; @@ -350,6 +351,7 @@ void Trans_Monomorphise_List(const ::HIR::Crate& crate, TransList& list) const auto& path = fcn_ent.first; const auto& pp = fcn_ent.second->pp; TRACE_FUNCTION_FR(path, path); + ASSERT_BUG(Span(), fcn.m_code.m_mir, "No code for " << path); auto mir = Trans_Monomorphise(resolve, fcn_ent.second->pp, fcn.m_code.m_mir); -- cgit v1.2.3 From 90d82839a0d90845879f9df9314e408edf6ef419 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 3 Mar 2019 21:05:48 +0800 Subject: Codegen C - Cast to int128_t for literals --- src/trans/codegen_c.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 13421096..98d0d3de 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -5659,6 +5659,7 @@ namespace { } else { + m_of << "(int128_t)"; m_of << c.v; m_of << "ll"; } @@ -5692,6 +5693,7 @@ namespace { } else { + m_of << "(uint128_t)"; m_of << ::std::hex << "0x" << c.v << "ull" << ::std::dec; } break; -- cgit v1.2.3 From 877757367fc67c42acd3398a230d08027264583e Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 3 Mar 2019 21:16:51 +0800 Subject: HIR Serialise - Deserialise extern type --- src/hir/deserialise.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/hir/deserialise.cpp b/src/hir/deserialise.cpp index 30d05b40..cc376474 100644 --- a/src/hir/deserialise.cpp +++ b/src/hir/deserialise.cpp @@ -536,6 +536,13 @@ } } + ::HIR::ExternType deserialise_externtype() + { + return ::HIR::ExternType { + deserialise_markings() + }; + } + ::HIR::TypeItem deserialise_typeitem() { switch(auto tag = m_in.read_tag()) @@ -557,6 +564,8 @@ return ::HIR::TypeItem( deserialise_trait() ); case 6: return ::HIR::TypeItem( deserialise_union() ); + case 7: + return ::HIR::TypeItem( deserialise_externtype() ); default: BUG(Span(), "Bad tag for HIR::TypeItem - " << tag); } -- cgit v1.2.3 From a84d9310b5c838c0816c84ba96754906d4f5d667 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Mon, 4 Mar 2019 09:53:06 +0800 Subject: Resolve - Tweak IBL, add support for extern_prelude --- src/ast/crate.cpp | 1 + src/ast/crate.hpp | 1 + src/resolve/absolute.cpp | 19 +++++++++++++++++-- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/ast/crate.cpp b/src/ast/crate.cpp index 3db09f1b..69db669e 100644 --- a/src/ast/crate.cpp +++ b/src/ast/crate.cpp @@ -180,6 +180,7 @@ void Crate::load_externs() ExternCrate::ExternCrate(const ::std::string& name, const ::std::string& path): m_name(name), + m_short_name(name), m_filename(path) { TRACE_FUNCTION_F("name=" << name << ", path='" << path << "'"); diff --git a/src/ast/crate.hpp b/src/ast/crate.hpp index 87a9f867..11fba9c0 100644 --- a/src/ast/crate.hpp +++ b/src/ast/crate.hpp @@ -98,6 +98,7 @@ class ExternCrate { public: ::std::string m_name; + ::std::string m_short_name; ::std::string m_filename; ::HIR::CratePtr m_hir; diff --git a/src/resolve/absolute.cpp b/src/resolve/absolute.cpp index 75a0857f..95e01d18 100644 --- a/src/resolve/absolute.cpp +++ b/src/resolve/absolute.cpp @@ -500,6 +500,18 @@ namespace break; } + // #![feature(extern_prelude)] - 2018-style extern paths + if( mode == LookupMode::Namespace && TARGETVER_1_29 && true /*m_crate.has_feature("extern_prelude")*/ ) + { + DEBUG("Extern crates - " << FMT_CB(os, for(const auto& v: m_crate.m_extern_crates) os << v.first << ":" << v.second.m_short_name <<",";)); + auto it = ::std::find_if(m_crate.m_extern_crates.begin(), m_crate.m_extern_crates.end(), [&](const auto& x){ return x.second.m_short_name == name; }); + if( it != m_crate.m_extern_crates.end() ) + { + DEBUG("- Found '" << name << "'"); + return AST::Path(it->first, {}); + } + } + return AST::Path(); } @@ -583,7 +595,6 @@ void Resolve_Absolute_Function(Context& item_context, ::AST::Function& fcn); void Resolve_Absolute_PathParams(/*const*/ Context& context, const Span& sp, ::AST::PathParams& args) { - // TODO: Lifetime params for(auto& arg : args.m_lifetimes) { Resolve_Absolute_Lifetime(context, sp, arg); @@ -1560,6 +1571,7 @@ void Resolve_Absolute_Lifetime(Context& context, const Span& sp, AST::LifetimeRe // - Does the same apply to impl headers? Yes it does. if( context.m_ibl_target_generics ) { + DEBUG("Considering in-band-lifetimes"); ASSERT_BUG(sp, !context.m_name_context.empty(), "Name context stack is empty"); auto it = context.m_name_context.rbegin(); ASSERT_BUG(sp, it->is_Generic(), "Name context stack end not Generic, instead " << it->tag_str()); @@ -2079,14 +2091,17 @@ void Resolve_Absolute_Function(Context& item_context, ::AST::Function& fcn) { TRACE_FUNCTION_F(""); item_context.push( fcn.params(), GenericSlot::Level::Method ); + item_context.m_ibl_target_generics = &fcn.params(); + DEBUG("- Generics"); Resolve_Absolute_Generic(item_context, fcn.params()); - item_context.m_ibl_target_generics = &fcn.params(); + DEBUG("- Prototype types"); Resolve_Absolute_Type( item_context, fcn.rettype() ); for(auto& arg : fcn.args()) Resolve_Absolute_Type( item_context, arg.second ); item_context.m_ibl_target_generics = nullptr; + DEBUG("- Body"); { auto _h = item_context.enter_rootblock(); item_context.push_block(); -- cgit v1.2.3 From a473a4eddc80b54e3458739ef2c4b18c24d50f92 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Mon, 4 Mar 2019 10:38:43 +0800 Subject: Parse - Handle `do catch` (aka `try`) --- src/ast/dump.cpp | 4 ++++ src/ast/expr.cpp | 9 +++++++++ src/ast/expr.hpp | 15 +++++++++++++++ src/expand/mod.cpp | 3 +++ src/expand/proc_macro.cpp | 3 +++ src/hir/from_ast_expr.cpp | 3 +++ src/parse/expr.cpp | 29 +++++++++++++++++++++++++++++ 7 files changed, 66 insertions(+) diff --git a/src/ast/dump.cpp b/src/ast/dump.cpp index 94ad6271..f0bdfa11 100644 --- a/src/ast/dump.cpp +++ b/src/ast/dump.cpp @@ -71,6 +71,10 @@ public: dec_indent(); m_os << indent() << "}"; } + virtual void visit(AST::ExprNode_Try& n) override { + m_os << "try "; + AST::NodeVisitor::visit(n.m_inner); + } virtual void visit(AST::ExprNode_Macro& n) override { m_expr_root = false; m_os << n.m_name << "!( /* TODO: Macro TT */ )"; diff --git a/src/ast/expr.cpp b/src/ast/expr.cpp index 5111bad6..dc006212 100644 --- a/src/ast/expr.cpp +++ b/src/ast/expr.cpp @@ -93,6 +93,12 @@ NODE(ExprNode_Block, { return NEWNODE(ExprNode_Block, m_is_unsafe, m_yields_final_value, mv$(nodes), m_local_mod); }) +NODE(ExprNode_Try, { + os << "try " << *m_inner; +},{ + return NEWNODE(ExprNode_Try, m_inner->clone()); +}) + NODE(ExprNode_Macro, { os << m_name << "!"; if( m_ident.size() > 0 ) @@ -471,6 +477,9 @@ NV(ExprNode_Block, { visit(child); //UNINDENT(); }) +NV(ExprNode_Try, { + visit(node.m_inner); +}) NV(ExprNode_Macro, { BUG(node.span(), "Hit unexpanded macro in expression - " << node); diff --git a/src/ast/expr.hpp b/src/ast/expr.hpp index f3981db5..7675b29a 100644 --- a/src/ast/expr.hpp +++ b/src/ast/expr.hpp @@ -74,6 +74,19 @@ struct ExprNode_Block: NODE_METHODS(); }; +struct ExprNode_Try: + public ExprNode +{ + ExprNodeP m_inner; + + ExprNode_Try(ExprNodeP inner): + m_inner(mv$(inner)) + { + } + + NODE_METHODS(); +}; + struct ExprNode_Macro: public ExprNode { @@ -633,6 +646,7 @@ public: virtual void visit(nt& node) = 0/*; \ virtual void visit(const nt& node) = 0*/ NT(ExprNode_Block); + NT(ExprNode_Try); NT(ExprNode_Macro); NT(ExprNode_Asm); NT(ExprNode_Flow); @@ -678,6 +692,7 @@ public: virtual void visit(nt& node) override;/* \ virtual void visit(const nt& node) override*/ NT(ExprNode_Block); + NT(ExprNode_Try); NT(ExprNode_Macro); NT(ExprNode_Asm); NT(ExprNode_Flow); diff --git a/src/expand/mod.cpp b/src/expand/mod.cpp index 751b14eb..8e36bd95 100644 --- a/src/expand/mod.cpp +++ b/src/expand/mod.cpp @@ -547,6 +547,9 @@ struct CExpandExpr: this->modstack = mv$(prev_modstack); } + void visit(::AST::ExprNode_Try& node) override { + this->visit_nodelete(node, node.m_inner); + } void visit(::AST::ExprNode_Asm& node) override { for(auto& v : node.m_output) this->visit_nodelete(node, v.value); diff --git a/src/expand/proc_macro.cpp b/src/expand/proc_macro.cpp index 3f26c648..f0f28f5a 100644 --- a/src/expand/proc_macro.cpp +++ b/src/expand/proc_macro.cpp @@ -516,6 +516,9 @@ namespace { TODO(sp, ""); m_pmi.send_symbol("}"); } + void visit(::AST::ExprNode_Try& node) { + TODO(sp, "ExprNode_Try"); + } void visit(::AST::ExprNode_Macro& node) { TODO(sp, "ExprNode_Macro"); } diff --git a/src/hir/from_ast_expr.cpp b/src/hir/from_ast_expr.cpp index 23797382..7d676bf8 100644 --- a/src/hir/from_ast_expr.cpp +++ b/src/hir/from_ast_expr.cpp @@ -47,6 +47,9 @@ struct LowerHIR_ExprNode_Visitor: m_rv.reset( static_cast< ::HIR::ExprNode*>(rv) ); } + virtual void visit(::AST::ExprNode_Try& v) override { + TODO(v.span(), "Handle _Try"); + } virtual void visit(::AST::ExprNode_Macro& v) override { BUG(v.span(), "Hit ExprNode_Macro"); } diff --git a/src/parse/expr.cpp b/src/parse/expr.cpp index 6e18f0eb..6cc94d74 100644 --- a/src/parse/expr.cpp +++ b/src/parse/expr.cpp @@ -254,6 +254,7 @@ ExprNodeP Parse_ExprBlockLine(TokenStream& lex, bool *add_silence) case TOK_BRACE_OPEN: { PUTBACK(tok, lex); ret = Parse_ExprBlockNode(lex); } + // If the block is followed by `.` or `?`, it's actually an expression! if( lex.lookahead(0) == TOK_DOT || lex.lookahead(0) == TOK_QMARK ) { lex.putback( Token(Token::TagTakeIP(), InterpolatedFragment(InterpolatedFragment::EXPR, ret.release())) ); return Parse_ExprBlockLine_Stmt(lex, *add_silence); @@ -470,6 +471,17 @@ ExprNodeP Parse_Expr_Match(TokenStream& lex) return NEWNODE( AST::ExprNode_Match, ::std::move(switch_val), ::std::move(arms) ); } +/// "do catch" block +ExprNodeP Parse_Expr_Try(TokenStream& lex) +{ + TRACE_FUNCTION; + //Token tok; + + auto inner = Parse_ExprBlockNode(lex); + //TODO(lex.point_span(), "do catch"); + return NEWNODE(AST::ExprNode_Try, ::std::move(inner)); +} + /// Parses the 'stmt' fragment specifier /// - Flow control /// - Expressions @@ -1126,6 +1138,23 @@ ExprNodeP Parse_ExprVal(TokenStream& lex) return Parse_WhileStmt(lex, ""); case TOK_RWORD_FOR: return Parse_ForStmt(lex, ""); + case TOK_RWORD_DO: + if( TARGETVER_1_29 ) + { + // `do catch` - stabilised later as `try` + if( GET_TOK(tok, lex) == TOK_IDENT && tok.str() == "catch" ) + { + return Parse_Expr_Try(lex); + } + else + { + throw ParseError::Unexpected(lex, tok); + } + } + else + { + throw ParseError::Unexpected(lex, tok); + } case TOK_RWORD_MATCH: return Parse_Expr_Match(lex); case TOK_RWORD_IF: -- cgit v1.2.3 From 3f6ad4a766e6daef9ed82b989e8cd2044a3d3679 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Mon, 4 Mar 2019 11:18:04 +0800 Subject: Parse - TOK_RWORD_MACRO and stub handler --- src/parse/eTokenType.enum.h | 1 + src/parse/lex.cpp | 1 + src/parse/root.cpp | 8 ++++++++ src/parse/token.cpp | 1 + 4 files changed, 11 insertions(+) diff --git a/src/parse/eTokenType.enum.h b/src/parse/eTokenType.enum.h index 93590264..d5a0eb86 100644 --- a/src/parse/eTokenType.enum.h +++ b/src/parse/eTokenType.enum.h @@ -140,6 +140,7 @@ _(TOK_RWORD_SUPER) _(TOK_RWORD_PROC) _(TOK_RWORD_MOVE) +_(TOK_RWORD_MACRO) _(TOK_RWORD_ABSTRACT) _(TOK_RWORD_FINAL) diff --git a/src/parse/lex.cpp b/src/parse/lex.cpp index 0b145379..477ff9af 100644 --- a/src/parse/lex.cpp +++ b/src/parse/lex.cpp @@ -155,6 +155,7 @@ static const struct { TOKENT("in", TOK_RWORD_IN), TOKENT("let", TOK_RWORD_LET), TOKENT("loop", TOK_RWORD_LOOP), + TOKENT("macro", TOK_RWORD_MACRO), TOKENT("match", TOK_RWORD_MATCH), TOKENT("mod", TOK_RWORD_MOD), TOKENT("move", TOK_RWORD_MOVE), diff --git a/src/parse/root.cpp b/src/parse/root.cpp index d79df434..a85812ea 100644 --- a/src/parse/root.cpp +++ b/src/parse/root.cpp @@ -1921,6 +1921,14 @@ namespace { item_data = ::AST::Item( Parse_TraitDef(lex, meta_items) ); break; + case TOK_RWORD_MACRO: + if( TARGETVER_1_19 ) + { + throw ParseError::Unexpected(lex, tok); + } + TODO(lex.point_span(), "macro items"); + break; + case TOK_RWORD_MOD: { GET_CHECK_TOK(tok, lex, TOK_IDENT); auto name = mv$(tok.str()); diff --git a/src/parse/token.cpp b/src/parse/token.cpp index f9c168e8..d8a68d88 100644 --- a/src/parse/token.cpp +++ b/src/parse/token.cpp @@ -477,6 +477,7 @@ struct EscapedString { case TOK_RWORD_BE: return "be"; case TOK_RWORD_UNSIZED: return "unsized"; + case TOK_RWORD_MACRO: return "macro"; } throw ParseError::BugCheck("Reached end of Token::to_str"); } -- cgit v1.2.3 From 9637c5a8a580acd6caec02bc34c24d13f7f76344 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Mon, 4 Mar 2019 12:58:20 +0800 Subject: Expand format_args - Support unicode pad character --- src/expand/format_args.cpp | 88 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 80 insertions(+), 8 deletions(-) diff --git a/src/expand/format_args.cpp b/src/expand/format_args.cpp index e2ee35d3..6cc81af6 100644 --- a/src/expand/format_args.cpp +++ b/src/expand/format_args.cpp @@ -34,7 +34,7 @@ namespace { }; Align align = Align::Unspec; - char align_char = ' '; + uint32_t align_char = ' '; Sign sign = Sign::Unspec; bool alternate = false; @@ -118,6 +118,71 @@ namespace { } }; + uint32_t parse_utf8(const char* s, int& out_len) + { + uint8_t v1 = s[0]; + if( v1 < 0x80 ) + { + out_len = 1; + return v1; + } + else if( (v1 & 0xC0) == 0x80 ) + { + // Invalid (continuation) + out_len = 1; + return 0xFFFE; + } + else if( (v1 & 0xE0) == 0xC0 ) { + // Two bytes + out_len = 2; + + uint8_t e1 = s[1]; + if( (e1 & 0xC0) != 0x80 ) return 0xFFFE; + + uint32_t outval + = ((v1 & 0x1F) << 6) + | ((e1 & 0x3F) <<0) + ; + return outval; + } + else if( (v1 & 0xF0) == 0xE0 ) { + // Three bytes + out_len = 3; + uint8_t e1 = s[1]; + if( (e1 & 0xC0) != 0x80 ) return 0xFFFE; + uint8_t e2 = s[2]; + if( (e2 & 0xC0) != 0x80 ) return 0xFFFE; + + uint32_t outval + = ((v1 & 0x0F) << 12) + | ((e1 & 0x3F) << 6) + | ((e2 & 0x3F) << 0) + ; + return outval; + } + else if( (v1 & 0xF8) == 0xF0 ) { + // Four bytes + out_len = 4; + uint8_t e1 = s[1]; + if( (e1 & 0xC0) != 0x80 ) return 0xFFFE; + uint8_t e2 = s[2]; + if( (e2 & 0xC0) != 0x80 ) return 0xFFFE; + uint8_t e3 = s[3]; + if( (e3 & 0xC0) != 0x80 ) return 0xFFFE; + + uint32_t outval + = ((v1 & 0x07) << 18) + | ((e1 & 0x3F) << 12) + | ((e2 & 0x3F) << 6) + | ((e3 & 0x3F) << 0) + ; + return outval; + } + else { + throw ""; // Should be impossible. + } + } + /// Parse a format string into a sequence of fragments. /// /// Returns a list of fragments, and the remaining free text after the last format sequence @@ -209,9 +274,15 @@ namespace { s ++; // eat ':' // Alignment - if( s[0] != '\0' && (s[1] == '<' || s[1] == '^' || s[1] == '>') ) { - args.align_char = s[0]; - s ++; + // - Padding character, a single unicode codepoint followed by '<'/'^'/'>' + { + int next_c_i; + uint32_t ch = parse_utf8(s, next_c_i); + char next_c = s[next_c_i]; + if( ch != '}' && ch != '\0' && (next_c == '<' || next_c == '^' || next_c == '>') ) { + args.align_char = ch; + s += next_c_i; + } } if( *s == '<' ) { args.align = FmtArgs::Align::Left; @@ -338,16 +409,17 @@ namespace { } } + if( s[0] == '\0' ) + ERROR(sp, E0000, "Unexpected end of formatting string"); + // Parse ident? // - Lazy way is to just handle a single char and ensure that it is just a single char - if( s[0] != '}' && s[0] != '\0' && s[1] != '}' ) { - TODO(sp, "Parse formatting fragment at \"" << fmt_frag_str << "\" (long type)"); + if( s[0] != '}' && s[1] != '}' ) { + TODO(sp, "Parse formatting fragment at \"" << fmt_frag_str << "\" (long type) - s=...\"" << s << "\""); } switch(s[0]) { - case '\0': - ERROR(sp, E0000, "Unexpected end of formatting string"); default: ERROR(sp, E0000, "Unknown formatting type specifier '" << *s << "'"); case '}': trait_name = "Display"; break; -- cgit v1.2.3 From bc13507c42e0e26dd280799b4f29867ee45235ac Mon Sep 17 00:00:00 2001 From: John Hodge Date: Mon, 4 Mar 2019 12:59:38 +0800 Subject: Expand - Desugar `try` into a loop --- src/expand/mod.cpp | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/expand/mod.cpp b/src/expand/mod.cpp index 8e36bd95..fd188345 100644 --- a/src/expand/mod.cpp +++ b/src/expand/mod.cpp @@ -347,6 +347,10 @@ struct CExpandExpr: LList modstack; ::std::unique_ptr<::AST::ExprNode> replacement; + // Stack of `try { ... }` blocks (the string is the loop label for the desugaring) + ::std::vector< ::std::string> m_try_stack; + unsigned m_try_index = 0; + AST::ExprNode_Block* current_block = nullptr; CExpandExpr(::AST::Crate& crate, LList ms): @@ -548,7 +552,20 @@ struct CExpandExpr: this->modstack = mv$(prev_modstack); } void visit(::AST::ExprNode_Try& node) override { + // Desugar into + // ``` + // loop '#tryNNN { + // break '#tryNNN { ... } + // } + // ``` + // NOTE: MIR lowering and HIR typecheck need to know to skip these (OR resolve should handle naming all loop blocks) + m_try_stack.push_back(FMT("#try" << m_try_index++)); this->visit_nodelete(node, node.m_inner); + auto loop_name = mv$(m_try_stack.back()); + m_try_stack.pop_back(); + + auto break_node = AST::ExprNodeP(new AST::ExprNode_Flow(AST::ExprNode_Flow::BREAK, loop_name, mv$(node.m_inner))); + this->replacement = AST::ExprNodeP(new AST::ExprNode_Loop(loop_name, mv$(break_node))); } void visit(::AST::ExprNode_Asm& node) override { for(auto& v : node.m_output) @@ -837,8 +854,8 @@ struct CExpandExpr: ::make_vec1( ::AST::Pattern(::AST::Pattern::TagNamedTuple(), node.span(), path_Err, ::make_vec1( ::AST::Pattern(::AST::Pattern::TagBind(), node.span(), "e") )) ), nullptr, ::AST::ExprNodeP(new ::AST::ExprNode_Flow( - ::AST::ExprNode_Flow::RETURN, - "", + (m_try_stack.empty() ? ::AST::ExprNode_Flow::RETURN : ::AST::ExprNode_Flow::BREAK), // NOTE: uses `break 'tryblock` instead of return if in a try block. + (m_try_stack.empty() ? "" : m_try_stack.back()), ::AST::ExprNodeP(new ::AST::ExprNode_CallPath( ::AST::Path(path_Try_from_error), ::make_vec1( -- cgit v1.2.3 From b8910145acd02f09a0e30cda31125802ffefa01b Mon Sep 17 00:00:00 2001 From: John Hodge Date: Mon, 4 Mar 2019 13:00:09 +0800 Subject: Parse - Hackily parse `macro` --- src/parse/root.cpp | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/src/parse/root.cpp b/src/parse/root.cpp index a85812ea..c055c190 100644 --- a/src/parse/root.cpp +++ b/src/parse/root.cpp @@ -1922,11 +1922,45 @@ namespace { break; case TOK_RWORD_MACRO: - if( TARGETVER_1_19 ) + if( TARGETVER_1_29 ) + { + GET_CHECK_TOK(tok, lex, TOK_IDENT); + auto name = tok.str(); + if( lex.lookahead(0) != TOK_PAREN_OPEN ) + { + GET_TOK(tok, lex); + throw ParseError::Unexpected(lex, tok); + } + + //::std::vector< ::std::string> names; + //auto arm_pat = Parse_MacroRules_Pat(lex, TOK_PAREN_OPEN, TOK_PAREN_CLOSE, names); + auto args_tt = Parse_TT(lex, false); + if( lex.lookahead(0) != TOK_BRACE_OPEN ) + { + GET_TOK(tok, lex); + throw ParseError::Unexpected(lex, tok); + } + //auto body = Parse_MacroRules_Cont(lex, TOK_BRACE_OPEN, TOK_BRACE_CLOSE, names); + auto body_tt = Parse_TT(lex, false); + + // TODO: Invoke the macro_rules parsers here + // - Could also do the same level of parsing when `macro_rules! foo {` is seen (i.e. parse macros at parse + // time, instead of during expand). + // - That would simplify some of the expand logic... + + // Lazy option: create a TT + ::std::vector out; + out.push_back(mv$(args_tt)); + out.push_back(TokenTree( Token(TOK_FATARROW) )); + out.push_back(mv$(body_tt)); + + item_name = ""; + item_data = ::AST::Item( AST::MacroInvocation(lex.end_span(ps), "macro_rules", name, TokenTree({}, mv$(out))) ); + } + else { throw ParseError::Unexpected(lex, tok); } - TODO(lex.point_span(), "macro items"); break; case TOK_RWORD_MOD: { -- cgit v1.2.3 From 49c3799a2d6839add1ff4c3dd0526cf4b705784c Mon Sep 17 00:00:00 2001 From: John Hodge Date: Mon, 4 Mar 2019 13:31:31 +0800 Subject: HIR Expand Type Aliases - Handle default parameters --- src/hir_conv/expand_type.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/hir_conv/expand_type.cpp b/src/hir_conv/expand_type.cpp index 6b06a748..2dfffb73 100644 --- a/src/hir_conv/expand_type.cpp +++ b/src/hir_conv/expand_type.cpp @@ -21,8 +21,14 @@ // Anything else - leave it be ), (TypeAlias, - if( !is_expr && path.m_params.m_types.size() != e2.m_params.m_types.size() ) { - ERROR(sp, E0000, "Mismatched parameter count in " << path << ", expected " << e2.m_params.m_types.size() << " got " << path.m_params.m_types.size()); + auto pp = path.m_params.clone(); + if( !is_expr ) { + while( pp.m_types.size() < e2.m_params.m_types.size() && e2.m_params.m_types[pp.m_types.size()].m_default != ::HIR::TypeRef() ) { + pp.m_types.push_back( e2.m_params.m_types[pp.m_types.size()].m_default.clone() ); + } + if( pp.m_types.size() != e2.m_params.m_types.size() ) { + ERROR(sp, E0000, "Mismatched parameter count in " << path << ", expected " << e2.m_params.m_types.size() << " got " << pp.m_types.size()); + } } if( e2.m_params.m_types.size() > 0 ) { // TODO: Better `monomorphise_type` @@ -33,8 +39,8 @@ } else if( (ge.binding >> 8) == 0 ) { auto idx = ge.binding & 0xFF; - if( idx < path.m_params.m_types.size() ) - return path.m_params.m_types[idx]; + if( idx < pp.m_types.size() ) + return pp.m_types[idx]; else if( is_expr ) return empty_type; else -- cgit v1.2.3 From 413fcf4f318e1530dcbdd8abb879bf77b714a91c Mon Sep 17 00:00:00 2001 From: John Hodge Date: Mon, 4 Mar 2019 13:54:42 +0800 Subject: HIR Conv Bind - Minor tweak to ordering --- src/hir_conv/bind.cpp | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/src/hir_conv/bind.cpp b/src/hir_conv/bind.cpp index b616a64f..c26ae03f 100644 --- a/src/hir_conv/bind.cpp +++ b/src/hir_conv/bind.cpp @@ -256,17 +256,17 @@ namespace { ::HIR::Visitor::visit_pattern(pat); - TU_MATCH_DEF(::HIR::Pattern::Data, (pat.m_data), (e), - ( - ), - (Value, + TU_MATCH_HDRA( (pat.m_data), {) + default: + // Nothing + TU_ARMA(Value, e) { this->visit_pattern_Value(sp, pat, e.val); - ), - (Range, + } + TU_ARMA(Range, e) { this->visit_pattern_Value(sp, pat, e.start); this->visit_pattern_Value(sp, pat, e.end); - ), - (StructValue, + } + TU_ARMA(StructValue, e) { const auto& str = get_struct_ptr(sp, m_crate, e.path); TU_IFLET(::HIR::Struct::Data, str.m_data, Unit, _, e.binding = &str; @@ -274,8 +274,8 @@ namespace { else { ERROR(sp, E0000, "Struct value pattern on non-unit struct " << e.path); } - ), - (StructTuple, + } + TU_ARMA(StructTuple, e) { const auto& str = get_struct_ptr(sp, m_crate, e.path); TU_IFLET(::HIR::Struct::Data, str.m_data, Tuple, _, e.binding = &str; @@ -283,8 +283,8 @@ namespace { else { ERROR(sp, E0000, "Struct tuple pattern on non-tuple struct " << e.path); } - ), - (Struct, + } + TU_ARMA(Struct, e) { const auto& str = get_struct_ptr(sp, m_crate, e.path); if(str.m_data.is_Named() ) { } @@ -296,8 +296,8 @@ namespace { ERROR(sp, E0000, "Struct pattern `" << pat << "` on field-less struct " << e.path); } e.binding = &str; - ), - (EnumValue, + } + TU_ARMA(EnumValue, e) { auto p = get_enum_ptr(sp, m_crate, e.path); if( p.first->m_data.is_Data() ) { @@ -307,8 +307,8 @@ namespace { } e.binding_ptr = p.first; e.binding_idx = p.second; - ), - (EnumTuple, + } + TU_ARMA(EnumTuple, e) { auto p = get_enum_ptr(sp, m_crate, e.path); if( !p.first->m_data.is_Data() ) ERROR(sp, E0000, "Enum tuple pattern on non-tuple variant " << e.path); @@ -317,8 +317,8 @@ namespace { ERROR(sp, E0000, "Enum tuple pattern on non-tuple variant " << e.path); e.binding_ptr = p.first; e.binding_idx = p.second; - ), - (EnumStruct, + } + TU_ARMA(EnumStruct, e) { auto p = get_enum_ptr(sp, m_crate, e.path); if( !e.is_exhaustive && e.sub_patterns.empty() ) { @@ -338,7 +338,7 @@ namespace { else if( !var.is_struct ) { ASSERT_BUG(sp, var.type.m_data.is_Path(), ""); - ASSERT_BUG(sp, var.type.m_data.as_Path().binding.is_Struct(), ""); + ASSERT_BUG(sp, var.type.m_data.as_Path().binding.is_Struct(), "EnumStruct pattern on unexpected variant " << e.path << " with " << var.type.m_data.as_Path().binding.tag_str()); const auto& str = *var.type.m_data.as_Path().binding.as_Struct(); ASSERT_BUG(sp, str.m_data.is_Tuple(), ""); const auto& flds = str.m_data.as_Tuple(); @@ -370,8 +370,8 @@ namespace { } e.binding_ptr = p.first; e.binding_idx = p.second; - ) - ) + } + } } static void fix_param_count(const Span& sp, const ::HIR::GenericPath& path, const ::HIR::GenericParams& param_defs, ::HIR::PathParams& params, bool fill_infer=true, const ::HIR::TypeRef* self_ty=nullptr) { @@ -862,11 +862,12 @@ namespace { void ConvertHIR_Bind(::HIR::Crate& crate) { Visitor exp { crate }; - exp.visit_crate( crate ); // Also visit extern crates to update their pointers for(auto& ec : crate.m_ext_crates) { exp.visit_crate( *ec.second.m_data ); } + + exp.visit_crate( crate ); } -- cgit v1.2.3 From 1008d1cb81a86c6a2d2467032815eefe150b2e6c Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 17 Mar 2019 15:53:22 +0800 Subject: Expand - Return part of catch blocks --- src/expand/mod.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/expand/mod.cpp b/src/expand/mod.cpp index fd188345..fd851c89 100644 --- a/src/expand/mod.cpp +++ b/src/expand/mod.cpp @@ -564,7 +564,10 @@ struct CExpandExpr: auto loop_name = mv$(m_try_stack.back()); m_try_stack.pop_back(); - auto break_node = AST::ExprNodeP(new AST::ExprNode_Flow(AST::ExprNode_Flow::BREAK, loop_name, mv$(node.m_inner))); + auto core_crate = (crate.m_load_std == ::AST::Crate::LOAD_NONE ? "" : "core"); + auto path_Ok = ::AST::Path(core_crate, {::AST::PathNode("result"), ::AST::PathNode("Result"), ::AST::PathNode("Ok")}); + auto ok_node = ::AST::ExprNodeP(new ::AST::ExprNode_CallPath( mv$(path_Ok), ::make_vec1(mv$(node.m_inner)) )); + auto break_node = AST::ExprNodeP(new AST::ExprNode_Flow(AST::ExprNode_Flow::BREAK, loop_name, mv$(ok_node))); this->replacement = AST::ExprNodeP(new AST::ExprNode_Loop(loop_name, mv$(break_node))); } void visit(::AST::ExprNode_Asm& node) override { -- cgit v1.2.3 From 0d8048c2d1b146d74081a7fd6b15dc7231e48d94 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 22 Mar 2019 08:04:40 +0800 Subject: AST - (minor) Comment around macro handling --- src/ast/ast.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ast/ast.hpp b/src/ast/ast.hpp index 8976cfc7..43a0e027 100644 --- a/src/ast/ast.hpp +++ b/src/ast/ast.hpp @@ -599,6 +599,7 @@ TAGGED_UNION_EX(Item, (), None, ( (None, struct {} ), (MacroInv, MacroInvocation), + // TODO: MacroDefinition (Use, UseItem), // Nameless items -- cgit v1.2.3 From 85743c7319a9a9b7b44761b77af04957d637bad9 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 22 Mar 2019 08:07:32 +0800 Subject: Common - Add another `ord` overload, fix breakage from that --- src/common.hpp | 4 ++++ src/mir/from_hir_match.cpp | 2 +- src/mir/mir.cpp | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/common.hpp b/src/common.hpp index 7521b2de..4cea1633 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -105,6 +105,10 @@ static inline Ordering ord(signed char l, signed char r) { return (l == r ? OrdEqual : (l > r ? OrdGreater : OrdLess)); } +static inline Ordering ord(int l, int r) +{ + return (l == r ? OrdEqual : (l > r ? OrdGreater : OrdLess)); +} static inline Ordering ord(short l, short r) { return (l == r ? OrdEqual : (l > r ? OrdGreater : OrdLess)); diff --git a/src/mir/from_hir_match.cpp b/src/mir/from_hir_match.cpp index 853e646f..32c97682 100644 --- a/src/mir/from_hir_match.cpp +++ b/src/mir/from_hir_match.cpp @@ -1489,7 +1489,7 @@ namespace { Ordering ord_rule_compatible(const PatternRule& a, const PatternRule& b) { if(a.tag() != b.tag()) - return ::ord( (unsigned)a.tag(), b.tag() ); + return ::ord( (unsigned)a.tag(), (unsigned)b.tag() ); TU_MATCHA( (a, b), (ae, be), (Any, diff --git a/src/mir/mir.cpp b/src/mir/mir.cpp index 840db1ac..ee6c1a6c 100644 --- a/src/mir/mir.cpp +++ b/src/mir/mir.cpp @@ -55,7 +55,7 @@ namespace MIR { ::Ordering Constant::ord(const Constant& b) const { if( this->tag() != b.tag() ) - return ::ord( static_cast(this->tag()), b.tag() ); + return ::ord( static_cast(this->tag()), static_cast(b.tag()) ); TU_MATCHA( (*this,b), (ae,be), (Int, if( ae.v != be.v ) -- cgit v1.2.3 From 31ccd19a38dd21c8bac4a34eaf88183e038b050a Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 22 Mar 2019 08:14:42 +0800 Subject: MIR From HIR - TODO for try-catch handling --- src/mir/from_hir.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index 9c7e0b25..a20c4257 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -671,6 +671,11 @@ namespace { } target_block = &*it; } + else { + if( target_block->label != "" && target_block->label[0] == '#' ) { + TODO(node.span(), "Break within try block, want to break parent loop instead"); + } + } if( node.m_continue ) { ASSERT_BUG(node.span(), !node.m_value, "Continue with a value isn't valid"); -- cgit v1.2.3 From 880ac52842f1d70a5f7a7f766404055bd0d1b5ee Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 22 Mar 2019 19:49:54 +0800 Subject: HIR Typecheck - Lots of messing about, kinda works up to midway through rustc --- src/hir_typeck/expr_cs.cpp | 351 +++++++++++++++++++++++++++++++++++++++++++-- src/hir_typeck/helpers.cpp | 16 ++- 2 files changed, 346 insertions(+), 21 deletions(-) diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 423ad3a1..1f43a89c 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -3419,6 +3419,13 @@ void Context::equate_types(const Span& sp, const ::HIR::TypeRef& li, const ::HIR const auto& l_t = this->m_resolve.expand_associated_types(sp, this->m_ivars.get_type(li), l_tmp); const auto& r_t = this->m_resolve.expand_associated_types(sp, this->m_ivars.get_type(ri), r_tmp); + if( l_t.m_data.is_Diverge() && !r_t.m_data.is_Infer() ) { + return ; + } + if( r_t.m_data.is_Diverge() && !l_t.m_data.is_Infer() ) { + return; + } + equate_types_inner(sp, l_t, r_t); } @@ -6595,6 +6602,10 @@ namespace { // Completely clear by reinitialising ivar_ent = Context::IVarPossible(); } + else + { + //DEBUG(i << ": known " << ty_l); + } return false; } @@ -6604,7 +6615,7 @@ namespace { return false; } - TRACE_FUNCTION_F(i << (honour_disable ? "" : " fallback")); + TRACE_FUNCTION_F(i << (honour_disable ? "" : " fallback") << " - " << ty_l); bool has_no_coerce_posiblities; @@ -6659,6 +6670,244 @@ namespace { { possible_tys.push_back(PossibleType { false, false, &new_ty }); } + + // If exactly the same type is both a source and destination, equate. + // NOTE: Not correct, especially when there's ivars in the list which could become a destination + { + for(const auto& ent : possible_tys) + { + if( !ent.can_deref ) + continue ; + for(const auto& ent2 : possible_tys) + { + if( &ent2 == &ent ) + break; + if( ent.can_deref ) + continue ; + if( *ent.ty == *ent2.ty ) { + DEBUG("- Source/Destination type"); + context.equate_types(sp, ty_l, *ent.ty); + return true; + } + // TODO: Compare such that &[_; 1] == &[u8; 1]? + } + } + } + DEBUG("possible_tys = " << possible_tys); + + // Filter out ivars + // - TODO: Should this also remove &_ types? (maybe not, as they give information about borrow classes) + size_t n_ivars; + size_t n_src_ivars; + size_t n_dst_ivars; + { + auto new_end = ::std::remove_if(possible_tys.begin(), possible_tys.end(), [](const PossibleType& ent) { + return ent.ty->m_data.is_Infer(); + }); + n_ivars = possible_tys.end() - new_end; + n_src_ivars = 0; + n_dst_ivars = 0; + for(auto it = new_end; it != possible_tys.end(); ++it) + { + if( it->can_deref ) + { + n_src_ivars += 1; + } + else + { + n_dst_ivars += 1; + } + } + possible_tys.erase(new_end, possible_tys.end()); + } + (void)n_ivars; + + // If there's multiple source types (which means that this ivar has to be a coercion from one of them) + // Look for the least permissive of the available destination types and assign to that + #if 1 + if( ::std::all_of(possible_tys.begin(), possible_tys.end(), [](const auto& ent){ return ent.is_pointer; }) + || ::std::none_of(possible_tys.begin(), possible_tys.end(), [](const auto& ent){ return ent.is_pointer; }) + ) + { + // 1. Count distinct (and non-ivar) source types + // - This also ignores &_ types + size_t num_distinct = 0; + for(const auto& ent : possible_tys) + { + if( !ent.can_deref ) + continue ; + // Ignore infer borrows + if( TU_TEST1(ent.ty->m_data, Borrow, .inner->m_data.is_Infer()) ) + continue; + bool is_duplicate = false; + for(const auto& ent2 : possible_tys) + { + if( &ent2 == &ent ) + break; + if( !ent.can_deref ) + continue ; + if( *ent.ty == *ent2.ty ) { + is_duplicate = true; + break; + } + // TODO: Compare such that &[_; 1] == &[u8; 1]? + } + if( !is_duplicate ) + { + num_distinct += 1; + } + } + // 2. Find the most restrictive destination type + // - Borrows are more restrictive than pointers + // - Borrows of Sized types are more restrictive than any other + // - Decreasing borrow type ordering: Owned, Unique, Shared + const ::HIR::TypeRef* dest_type = nullptr; + for(const auto& ent : possible_tys) + { + if( ent.can_deref ) + continue ; + // Ignore &_ types? + // - No, need to handle them below + if( !dest_type ) { + dest_type = ent.ty; + continue ; + } + + // Get ordering of this type to the current destination + // - If lesser/greater then ignore/update + // - If equal then what? (Instant error? Leave as-is and let the asignment happen? Disable the asignment?) + static const ::HIR::TypeRef::Data::Tag tag_ordering[] = { + ::HIR::TypeRef::Data::TAG_Pointer, + ::HIR::TypeRef::Data::TAG_Borrow, + ::HIR::TypeRef::Data::TAG_Path, // Strictly speaking, Path == Generic + ::HIR::TypeRef::Data::TAG_Generic, + }; + static const ::HIR::TypeRef::Data::Tag* tag_ordering_end = &tag_ordering[ sizeof(tag_ordering) / sizeof(tag_ordering[0] )]; + Ordering cmp; // Ordering of this type relative to the current most restrictve destination (of restrictiveness) + if( dest_type->m_data.tag() != ent.ty->m_data.tag() ) + { + auto p1 = ::std::find(tag_ordering, tag_ordering_end, dest_type->m_data.tag()); + auto p2 = ::std::find(tag_ordering, tag_ordering_end, ent.ty->m_data.tag()); + if( p1 == tag_ordering_end ) { + TODO(sp, "Type " << *dest_type << " not in ordering list"); + } + if( p2 == tag_ordering_end ) { + TODO(sp, "Type " << *dest_type << " not in ordering list"); + } + cmp = ord( static_cast(p2-p1), 0 ); + } + else + { + struct H { + static Ordering get_ordering_infer(const Span& sp, const ::HIR::TypeRef& r) + { + // For infer, only concrete types are more restrictive + TU_MATCH_HDRA( (r.m_data), { ) + default: + return OrdLess; + TU_ARMA(Path, te) { + if( te.binding.is_Opaque() ) + return OrdLess; + if( te.binding.is_Unbound() ) + return OrdEqual; + // TODO: Check if the type is concrete? (Check an unsizing param if present) + return OrdLess; + } + TU_ARMA(Borrow, _) + return OrdEqual; + TU_ARMA(Infer, _) + return OrdEqual; + TU_ARMA(Pointer, _) + return OrdEqual; + } + throw ""; + } + static Ordering get_ordering_ty(const Span& sp, const Context& context, const ::HIR::TypeRef& l, const ::HIR::TypeRef& r) + { + if( l == r ) { + return OrdEqual; + } + if( l.m_data.is_Infer() ) { + return get_ordering_infer(sp, r); + } + if( r.m_data.is_Infer() ) { + switch( H::get_ordering_infer(sp, l) ) + { + case OrdLess: return OrdGreater; + case OrdEqual: return OrdEqual; + case OrdGreater:return OrdLess; + } + } + if( l.m_data.is_Path() ) { + // Path types can be unsize targets, and can also act like infers + // - If it's a Unbound treat as Infer + // - If Opaque, then search for a CoerceUnsized/Unsize bound? + // - If Struct, look for ^ tag + // - Else, more/equal specific + TODO(sp, l << " with " << r << " - LHS is Path"); + } + if( r.m_data.is_Path() ) { + // Path types can be unsize targets, and can also act like infers + TODO(sp, l << " with " << r << " - RHS is Path"); + } + + TODO(sp, "Compare " << l << " and " << r); + } + }; + TU_MATCH_HDRA( (ent.ty->m_data), { ) + default: + BUG(sp, "Unexpected type class " << *ent.ty); + break; + TU_ARMA(Generic, _te2) { + cmp = OrdEqual; + } + TU_ARMA(Path, te2) { + //const auto& te = dest_type->m_data.as_Path(); + // TODO: Prevent this rule from applying? + cmp = OrdEqual; + } + TU_ARMA(Borrow, te2) { + const auto& te = dest_type->m_data.as_Borrow(); + cmp = ord( (int)te2.type, (int)te.type ); // Note, reversed ordering because we want Unique>Shared + if( cmp == OrdEqual ) + { + cmp = H::get_ordering_ty(sp, context, context.m_ivars.get_type(*te.inner), context.m_ivars.get_type(*te2.inner)); + } + } + TU_ARMA(Pointer, te2) { + const auto& te = dest_type->m_data.as_Pointer(); + cmp = ord( (int)te2.type, (int)te.type ); // Note, reversed ordering because we want Unique>Shared + if( cmp == OrdEqual ) + { + cmp = H::get_ordering_ty(sp, context, context.m_ivars.get_type(*te.inner), context.m_ivars.get_type(*te2.inner)); + } + } + } + } + + switch(cmp) + { + case OrdLess: + // This entry is less restrictive, so don't update `dest_type` + break; + case OrdEqual: + break; + case OrdGreater: + // This entry is mode restrictive, so DO update `dest_type` + dest_type = ent.ty; + break; + } + } + // TODO: Unsized types? Don't pick an unsized if coercions are present? + if( num_distinct > 1 && dest_type ) + { + DEBUG("- Most-restrictive destination " << *dest_type); + context.equate_types(sp, ty_l, *dest_type); + return true; + } + } +#endif + #if 1 DEBUG("possible_tys = " << possible_tys); DEBUG("Adding bounded [" << ivar_ent.bounded << "]"); @@ -6692,7 +6941,15 @@ namespace { } if( !failed_a_bound ) { - possible_tys.push_back(PossibleType { false, false, &new_ty }); + // TODO: Don't add ivars? + if( new_ty.m_data.is_Infer() ) + { + n_ivars += 1; + } + else + { + possible_tys.push_back(PossibleType { false, false, &new_ty }); + } } } } @@ -6715,6 +6972,24 @@ namespace { // Keep } + // TODO: Ivars have been removed, this sort of check should be moved elsewhere. + if( !remove_option && ty_l.m_data.as_Infer().ty_class == ::HIR::InferClass::Integer ) + { + if( const auto* te = it->ty->m_data.opt_Primitive() ) { + (void)te; + } + else if( const auto* te = it->ty->m_data.opt_Path() ) { + // If not Unbound, remove option + (void)te; + } + else if( const auto* te = it->ty->m_data.opt_Infer() ) { + (void)te; + } + else { + remove_option = true; + } + } + it = (remove_option ? possible_tys.erase(it) : it + 1); } DEBUG("possible_tys = " << possible_tys); @@ -6734,8 +7009,10 @@ namespace { break; } // If not an ivar, AND both are either unsize/pointer AND the deref flags are different + // TODO: Ivars have been removed? if( !it->ty->m_data.is_Infer() && other_opt.is_pointer == it->is_pointer && other_opt.can_deref != it->can_deref ) { + // TODO: Possible duplicate with a check above... DEBUG("Source and destination possibility, picking " << *it->ty); context.equate_types(sp, ty_l, *it->ty); return true; @@ -6828,7 +7105,7 @@ namespace { } DEBUG("possible_tys = " << possible_tys); - if( possible_tys.size() == 1 ) + if( possible_tys.size() == 1 && n_ivars == 0 ) { const auto& new_ty = *possible_tys[0].ty; DEBUG("Only " << new_ty << " is an option"); @@ -6836,7 +7113,7 @@ namespace { return true; } // If there's only one non-deref in the list OR there's only one deref in the list - if( !honour_disable && ::std::count_if(possible_tys.begin(), possible_tys.end(), [](const PossibleType& pt){ return pt.can_deref; }) == 1 ) + if( !honour_disable && n_src_ivars == 0 && ::std::count_if(possible_tys.begin(), possible_tys.end(), [](const PossibleType& pt){ return pt.can_deref; }) == 1 ) { auto it = ::std::find_if(possible_tys.begin(), possible_tys.end(), [](const PossibleType& pt){ return pt.can_deref; }); const auto& new_ty = *it->ty; @@ -6844,7 +7121,7 @@ namespace { context.equate_types(sp, ty_l, new_ty); return true; } - if( !honour_disable && ::std::count_if(possible_tys.begin(), possible_tys.end(), [](const PossibleType& pt){ return !pt.can_deref; }) == 1 ) + if( !honour_disable && n_dst_ivars == 0 && ::std::count_if(possible_tys.begin(), possible_tys.end(), [](const PossibleType& pt){ return !pt.can_deref; }) == 1 ) { auto it = ::std::find_if(possible_tys.begin(), possible_tys.end(), [](const PossibleType& pt){ return !pt.can_deref; }); const auto& new_ty = *it->ty; @@ -6853,7 +7130,7 @@ namespace { return true; } // If there's multiple possiblilties, we're in fallback mode, AND there's no ivars in the list - if( possible_tys.size() > 0 && !honour_disable && !::std::any_of(possible_tys.begin(), possible_tys.end(), [](const PossibleType& pt){ return pt.ty->m_data.is_Infer(); }) ) + if( possible_tys.size() > 0 && !honour_disable && n_ivars == 0 ) { //::std::sort(possible_tys.begin(), possible_tys.end()); // Sorts ivars to the front const auto& new_ty = *possible_tys.back().ty; @@ -6915,7 +7192,7 @@ namespace { // Not checking bounded list, because there's nothing to check } - has_no_coerce_posiblities = possible_tys.empty(); + has_no_coerce_posiblities = possible_tys.empty() && n_ivars == 0; } if( has_no_coerce_posiblities && !ivar_ent.bounded.empty() ) @@ -7035,6 +7312,7 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR: { DEBUG("- Consumed coercion " << ent.left_ty << " := " << src_ty); +#if 0 // If this isn't the last item in the list if( i != context.link_coerce.size() - 1 ) { @@ -7043,6 +7321,9 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR: } // Remove the last item. context.link_coerce.pop_back(); +#else + context.link_coerce.erase( context.link_coerce.begin() + i ); +#endif } else { @@ -7143,6 +7424,7 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR: context.equate_types_to_shadow(sp,ty); // Also disable inferrence (for this pass) for all ivars in affected bounds + if(false) for(const auto& la : context.link_assoc) { bool found = false; @@ -7200,7 +7482,37 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR: #endif } // `if peek_changed` (node revisits) + if( !context.m_ivars.peek_changed() ) + { + size_t len = context.adv_revisits.size(); + for(size_t i = 0; i < len; i ++) + { + auto& ent = *context.adv_revisits[i]; + ent.revisit(context, /*is_fallback=*/true); + } + } + +#if 0 + if( !context.m_ivars.peek_changed() ) + { + DEBUG("--- Coercion consume"); + if( ! context.link_coerce.empty() ) + { + auto ent = mv$(context.link_coerce.front()); + context.link_coerce.erase( context.link_coerce.begin() ); + + const auto& sp = (*ent.right_node_ptr)->span(); + auto& src_ty = (**ent.right_node_ptr).m_res_type; + //src_ty = context.m_resolve.expand_associated_types( sp, mv$(src_ty) ); + ent.left_ty = context.m_resolve.expand_associated_types( sp, mv$(ent.left_ty) ); + DEBUG("- Equate coercion " << ent.left_ty << " := " << src_ty); + + context.equate_types(sp, ent.left_ty, src_ty); + } + } +#endif // If nothing has changed, run check_ivar_poss again but ignoring the 'disable' flag +#if 1 if( !context.m_ivars.peek_changed() ) { // Check the possible equations @@ -7209,9 +7521,9 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR: for(unsigned int i = context.possible_ivar_vals.size(); i --; ) { if( check_ivar_poss(context, i, context.possible_ivar_vals[i], /*honour_disable=*/false) ) { -#if 1 +# if 1 break; -#else +# else static Span sp; assert( context.possible_ivar_vals[i].has_rules() ); // Disable all metioned ivars in the possibilities @@ -7243,23 +7555,34 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR: context.equate_types_shadow(sp, t, false); } } -#endif +# endif } else { //assert( !context.m_ivars.peek_changed() ); } } +#endif } // `if peek_changed` (ivar possibilities #2) +#if 1 if( !context.m_ivars.peek_changed() ) { - size_t len = context.adv_revisits.size(); - for(size_t i = 0; i < len; i ++) + DEBUG("--- Coercion consume"); + if( ! context.link_coerce.empty() ) { - auto& ent = *context.adv_revisits[i]; - ent.revisit(context, /*is_fallback=*/true); + auto ent = mv$(context.link_coerce.front()); + context.link_coerce.erase( context.link_coerce.begin() ); + + const auto& sp = (*ent.right_node_ptr)->span(); + auto& src_ty = (**ent.right_node_ptr).m_res_type; + //src_ty = context.m_resolve.expand_associated_types( sp, mv$(src_ty) ); + ent.left_ty = context.m_resolve.expand_associated_types( sp, mv$(ent.left_ty) ); + DEBUG("- Equate coercion " << ent.left_ty << " := " << src_ty); + + context.equate_types(sp, ent.left_ty, src_ty); } } +#endif // Finally. If nothing changed, apply ivar defaults if( !context.m_ivars.peek_changed() ) diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index 7e282cb0..cb26f0be 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -597,13 +597,15 @@ void HMTypeInferrence::set_ivar_to(unsigned int slot, ::HIR::TypeRef type) case ::HIR::InferClass::Integer: case ::HIR::InferClass::Float: // `type` can't be an ivar, so it has to be a primitive (or an associated?) - TU_MATCH_DEF(::HIR::TypeRef::Data, (type.m_data), (l_e), - ( - ), - (Primitive, - check_type_class_primitive(sp, type, e.ty_class, l_e); - ) - ) + if( const auto* l_e = type.m_data.opt_Primitive() ) { + check_type_class_primitive(sp, type, e.ty_class, *l_e); + } + else if( type.m_data.is_Diverge() ) { + // ... acceptable + } + else { + BUG(sp, "Setting primitive to " << type); + } break; } ) -- cgit v1.2.3 From e65566c6fcf645f28560b226ab93c9e52bdbf2a7 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 23 Mar 2019 16:06:59 +0800 Subject: HIR - Split hir.cpp a bit to allow hackery --- Makefile | 2 +- src/hir/hir.cpp | 1046 -------------------------------------------------- src/hir/hir_ops.cpp | 1062 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1063 insertions(+), 1047 deletions(-) create mode 100644 src/hir/hir_ops.cpp diff --git a/Makefile b/Makefile index 3eb72d0f..91a9d2de 100644 --- a/Makefile +++ b/Makefile @@ -93,7 +93,7 @@ OBJ += macro_rules/mod.o macro_rules/eval.o macro_rules/parse.o OBJ += resolve/use.o resolve/index.o resolve/absolute.o OBJ += hir/from_ast.o hir/from_ast_expr.o OBJ += hir/dump.o -OBJ += hir/hir.o hir/generic_params.o +OBJ += hir/hir.o hir/hir_ops.o hir/generic_params.o OBJ += hir/crate_ptr.o hir/expr_ptr.o OBJ += hir/type.o hir/path.o hir/expr.o hir/pattern.o OBJ += hir/visitor.o hir/crate_post_load.o diff --git a/src/hir/hir.cpp b/src/hir/hir.cpp index fdd564d6..4b9aef10 100644 --- a/src/hir/hir.cpp +++ b/src/hir/hir.cpp @@ -150,932 +150,6 @@ uint32_t HIR::Enum::get_value(size_t idx) const } } -namespace { - bool matches_genericpath(const ::HIR::GenericParams& params, const ::HIR::GenericPath& left, const ::HIR::GenericPath& right, ::HIR::t_cb_resolve_type ty_res, bool expand_generic); - - bool matches_type_int(const ::HIR::GenericParams& params, const ::HIR::TypeRef& left, const ::HIR::TypeRef& right_in, ::HIR::t_cb_resolve_type ty_res, bool expand_generic) - { - assert(! left.m_data.is_Infer() ); - const auto& right = (right_in.m_data.is_Infer() || (right_in.m_data.is_Generic() && expand_generic) ? ty_res(right_in) : right_in); - if( right_in.m_data.is_Generic() ) - expand_generic = false; - - //DEBUG("left = " << left << ", right = " << right); - - // TODO: What indicates what out of ty_res? - - if( const auto* re = right.m_data.opt_Infer() ) - { - //DEBUG("left = " << left << ", right = " << right); - switch(re->ty_class) - { - case ::HIR::InferClass::None: - case ::HIR::InferClass::Diverge: - //return left.m_data.is_Generic(); - return true; - case ::HIR::InferClass::Integer: - TU_IFLET(::HIR::TypeRef::Data, left.m_data, Primitive, le, - return is_integer(le); - ) - else { - return left.m_data.is_Generic(); - } - break; - case ::HIR::InferClass::Float: - TU_IFLET(::HIR::TypeRef::Data, left.m_data, Primitive, le, - return is_float(le); - ) - else { - return left.m_data.is_Generic(); - } - break; - } - throw ""; - } - - // A local generic could match anything, leave that up to the caller - if( left.m_data.is_Generic() ) { - DEBUG("> Generic left, success"); - return true; - } - // A local UfcsKnown can only be becuase it couldn't be expanded earlier, assume it could match - if( left.m_data.is_Path() && left.m_data.as_Path().path.m_data.is_UfcsKnown() ) { - // True? - //DEBUG("> UFCS Unknown left, success"); - return true; - } - - // If the RHS (provided) is generic, it can only match if it binds to a local type parameter - if( right.m_data.is_Generic() ) { - // TODO: This is handled above? - //DEBUG("> Generic right, only if left generic"); - return left.m_data.is_Generic(); - } - // If the RHS (provided) is generic, it can only match if it binds to a local type parameter - if( TU_TEST1(right.m_data, Path, .binding.is_Unbound()) ) { - //DEBUG("> UFCS Unknown right, fuzzy"); - return true; - } - - if( left.m_data.tag() != right.m_data.tag() ) { - //DEBUG("> Tag mismatch, failure"); - return false; - } - TU_MATCH(::HIR::TypeRef::Data, (left.m_data, right.m_data), (le, re), - (Infer, assert(!"infer");), - (Diverge, return true; ), - (Primitive, return le == re;), - (Path, - if( le.path.m_data.tag() != re.path.m_data.tag() ) - return false; - TU_MATCH_DEF(::HIR::Path::Data, (le.path.m_data, re.path.m_data), (ple, pre), - ( - return false; - ), - (Generic, - return matches_genericpath(params, ple, pre, ty_res, expand_generic); - ) - ) - ), - (Generic, - throw ""; - ), - (TraitObject, - if( !matches_genericpath(params, le.m_trait.m_path, re.m_trait.m_path, ty_res, expand_generic) ) - return false; - if( le.m_markers.size() != re.m_markers.size() ) - return false; - for(unsigned int i = 0; i < le.m_markers.size(); i ++) - { - const auto& lm = le.m_markers[i]; - const auto& rm = re.m_markers[i]; - if( !matches_genericpath(params, lm, rm, ty_res, expand_generic) ) - return false; - } - return true; - ), - (ErasedType, - throw "Unexpected ErasedType in matches_type_int"; - ), - (Array, - if( ! matches_type_int(params, *le.inner, *re.inner, ty_res, expand_generic) ) - return false; - if( le.size_val != re.size_val ) - return false; - return true; - ), - (Slice, - return matches_type_int(params, *le.inner, *re.inner, ty_res, expand_generic); - ), - (Tuple, - if( le.size() != re.size() ) - return false; - for( unsigned int i = 0; i < le.size(); i ++ ) - if( !matches_type_int(params, le[i], re[i], ty_res, expand_generic) ) - return false; - return true; - ), - (Borrow, - if( le.type != re.type ) - return false; - return matches_type_int(params, *le.inner, *re.inner, ty_res, expand_generic); - ), - (Pointer, - if( le.type != re.type ) - return false; - return matches_type_int(params, *le.inner, *re.inner, ty_res, expand_generic); - ), - (Function, - if( le.is_unsafe != re.is_unsafe ) - return false; - if( le.m_abi != re.m_abi ) - return false; - if( le.m_arg_types.size() != re.m_arg_types.size() ) - return false; - for( unsigned int i = 0; i < le.m_arg_types.size(); i ++ ) - if( !matches_type_int(params, le.m_arg_types[i], re.m_arg_types[i], ty_res, expand_generic) ) - return false; - return matches_type_int(params, *le.m_rettype, *re.m_rettype, ty_res, expand_generic); - ), - (Closure, - return le.node == re.node; - ) - ) - return false; - } - bool matches_genericpath(const ::HIR::GenericParams& params, const ::HIR::GenericPath& left, const ::HIR::GenericPath& right, ::HIR::t_cb_resolve_type ty_res, bool expand_generic) - { - if( left.m_path.m_crate_name != right.m_path.m_crate_name ) - return false; - if( left.m_path.m_components.size() != right.m_path.m_components.size() ) - return false; - for(unsigned int i = 0; i < left.m_path.m_components.size(); i ++ ) - { - if( left.m_path.m_components[i] != right.m_path.m_components[i] ) - return false; - } - - if( left.m_params.m_types.size() > 0 || right.m_params.m_types.size() > 0 ) - { - // Count mismatch. Allow due to defaults. - if( left.m_params.m_types.size() != right.m_params.m_types.size() ) { - return true; - //TODO(Span(), "Match generic paths " << left << " and " << right << " - count mismatch"); - } - for( unsigned int i = 0; i < right.m_params.m_types.size(); i ++ ) - { - if( ! matches_type_int(params, left.m_params.m_types[i], right.m_params.m_types[i], ty_res, expand_generic) ) - return false; - } - } - return true; - } -} - -//::HIR::TypeRef HIR::Function::make_ty(const Span& sp, const ::HIR::PathParams& params) const -//{ -// // TODO: Obtain function type for this function (i.e. a type that is specifically for this function) -// auto fcn_ty_data = ::HIR::FunctionType { -// m_is_unsafe, -// m_abi, -// box$( monomorphise_type(sp, m_params, params, m_return) ), -// {} -// }; -// fcn_ty_data.m_arg_types.reserve( m_args.size() ); -// for(const auto& arg : m_args) -// { -// fcn_ty_data.m_arg_types.push_back( monomorphise_type(sp, m_params, params, arg.second) ); -// } -// return ::HIR::TypeRef( mv$(fcn_ty_data) ); -//} - -namespace { - bool is_unbounded_infer(const ::HIR::TypeRef& type) { - TU_IFLET( ::HIR::TypeRef::Data, type.m_data, Infer, e, - return e.ty_class == ::HIR::InferClass::None || e.ty_class == ::HIR::InferClass::Diverge; - ) - else { - return false; - } - } -} - -bool ::HIR::TraitImpl::matches_type(const ::HIR::TypeRef& type, ::HIR::t_cb_resolve_type ty_res) const -{ - // NOTE: Don't return any impls when the type is an unbouned ivar. Wouldn't be able to pick anything anyway - // TODO: For `Unbound`, it could be valid, if the target is a generic. - // - Pure infer could also be useful (for knowing if there's any other potential impls) - if( is_unbounded_infer(type) || TU_TEST1(type.m_data, Path, .binding.is_Unbound()) ) { - return false; - } - return matches_type_int(m_params, m_type, type, ty_res, true); -} -bool ::HIR::TypeImpl::matches_type(const ::HIR::TypeRef& type, ::HIR::t_cb_resolve_type ty_res) const -{ - if( is_unbounded_infer(type) || TU_TEST1(type.m_data, Path, .binding.is_Unbound()) ) { - return false; - } - return matches_type_int(m_params, m_type, type, ty_res, true); -} -bool ::HIR::MarkerImpl::matches_type(const ::HIR::TypeRef& type, ::HIR::t_cb_resolve_type ty_res) const -{ - if( is_unbounded_infer(type) || TU_TEST1(type.m_data, Path, .binding.is_Unbound()) ) { - return false; - } - return matches_type_int(m_params, m_type, type, ty_res, true); -} - -namespace { - - struct TypeOrdSpecific_MixedOrdering - { - }; - - ::Ordering typelist_ord_specific(const Span& sp, const ::std::vector<::HIR::TypeRef>& left, const ::std::vector<::HIR::TypeRef>& right); - - ::Ordering type_ord_specific(const Span& sp, const ::HIR::TypeRef& left, const ::HIR::TypeRef& right) - { - // TODO: What happens if you get `impl Foo for T` vs `impl Foo for T` - - // A generic can't be more specific than any other type we can see - // - It's equally as specific as another Generic, so still false - if( left.m_data.is_Generic() ) { - return right.m_data.is_Generic() ? ::OrdEqual : ::OrdLess; - } - // - A generic is always less specific than anything but itself (handled above) - if( right.m_data.is_Generic() ) { - return ::OrdGreater; - } - - TU_MATCH(::HIR::TypeRef::Data, (left.m_data), (le), - (Generic, - throw ""; - ), - (Infer, - BUG(sp, "Hit infer"); - ), - (Diverge, - BUG(sp, "Hit diverge"); - ), - (Closure, - BUG(sp, "Hit closure"); - ), - (Primitive, - TU_IFLET(::HIR::TypeRef::Data, right.m_data, Primitive, re, - if( le != re ) - BUG(sp, "Mismatched types - " << left << " and " << right); - return ::OrdEqual; - ) - else { - BUG(sp, "Mismatched types - " << left << " and " << right); - } - ), - (Path, - if( !right.m_data.is_Path() || le.path.m_data.tag() != right.m_data.as_Path().path.m_data.tag() ) - BUG(sp, "Mismatched types - " << left << " and " << right); - TU_MATCHA( (le.path.m_data, right.m_data.as_Path().path.m_data), (lpe, rpe), - (Generic, - if( lpe.m_path != rpe.m_path ) - BUG(sp, "Mismatched types - " << left << " and " << right); - return typelist_ord_specific(sp, lpe.m_params.m_types, rpe.m_params.m_types); - ), - (UfcsUnknown, - ), - (UfcsKnown, - ), - (UfcsInherent, - ) - ) - TODO(sp, "Path - " << le.path << " and " << right); - ), - (TraitObject, - ASSERT_BUG(sp, right.m_data.is_TraitObject(), "Mismatched types - "<< left << " vs " << right); - const auto& re = right.m_data.as_TraitObject(); - ASSERT_BUG(sp, le.m_trait.m_path.m_path == re.m_trait.m_path.m_path, "Mismatched types - "<< left << " vs " << right); - ASSERT_BUG(sp, le.m_markers.size() == re.m_markers.size(), "Mismatched types - "<< left << " vs " << right); - - auto ord = typelist_ord_specific(sp, le.m_trait.m_path.m_params.m_types, re.m_trait.m_path.m_params.m_types); - if( ord != ::OrdEqual ) - return ord; - for(size_t i = 0; i < le.m_markers.size(); i ++) - { - ASSERT_BUG(sp, le.m_markers[i].m_path == re.m_markers[i].m_path, "Mismatched types - " << left << " vs " << right); - ord = typelist_ord_specific(sp, le.m_markers[i].m_params.m_types, re.m_markers[i].m_params.m_types); - if(ord != ::OrdEqual) - return ord; - } - return ::OrdEqual; - ), - (ErasedType, - TODO(sp, "ErasedType - " << left); - ), - (Function, - TU_IFLET(::HIR::TypeRef::Data, right.m_data, Function, re, - TODO(sp, "Function"); - //return typelist_ord_specific(sp, le.arg_types, re.arg_types); - ) - else { - BUG(sp, "Mismatched types - " << left << " and " << right); - } - ), - (Tuple, - TU_IFLET(::HIR::TypeRef::Data, right.m_data, Tuple, re, - return typelist_ord_specific(sp, le, re); - ) - else { - BUG(sp, "Mismatched types - " << left << " and " << right); - } - ), - (Slice, - TU_IFLET(::HIR::TypeRef::Data, right.m_data, Slice, re, - return type_ord_specific(sp, *le.inner, *re.inner); - ) - else { - BUG(sp, "Mismatched types - " << left << " and " << right); - } - ), - (Array, - TU_IFLET(::HIR::TypeRef::Data, right.m_data, Array, re, - if( le.size_val != re.size_val ) - BUG(sp, "Mismatched types - " << left << " and " << right); - return type_ord_specific(sp, *le.inner, *re.inner); - ) - else { - BUG(sp, "Mismatched types - " << left << " and " << right); - } - ), - (Pointer, - TU_IFLET(::HIR::TypeRef::Data, right.m_data, Pointer, re, - if( le.type != re.type ) - BUG(sp, "Mismatched types - " << left << " and " << right); - return type_ord_specific(sp, *le.inner, *re.inner); - ) - else { - BUG(sp, "Mismatched types - " << left << " and " << right); - } - ), - (Borrow, - TU_IFLET(::HIR::TypeRef::Data, right.m_data, Borrow, re, - if( le.type != re.type ) - BUG(sp, "Mismatched types - " << left << " and " << right); - return type_ord_specific(sp, *le.inner, *re.inner); - ) - else { - BUG(sp, "Mismatched types - " << left << " and " << right); - } - ) - ) - throw "Fell off end of type_ord_specific"; - } - - ::Ordering typelist_ord_specific(const Span& sp, const ::std::vector<::HIR::TypeRef>& le, const ::std::vector<::HIR::TypeRef>& re) - { - auto rv = ::OrdEqual; - assert(le.size() == re.size()); - for(unsigned int i = 0; i < le.size(); i ++) { - auto a = type_ord_specific(sp, le[i], re[i]); - if( a != ::OrdEqual ) { - if( rv != ::OrdEqual && a != rv ) - { - DEBUG("Inconsistent ordering between type lists - i=" << i << " [" << le << "] vs [" << re << "]"); - throw TypeOrdSpecific_MixedOrdering {}; - } - rv = a; - } - } - return rv; - } -} - -namespace { - void add_bound_from_trait(::std::vector< ::HIR::GenericBound>& rv, const ::HIR::TypeRef& type, const ::HIR::TraitPath& cur_trait) - { - static Span sp; - assert( cur_trait.m_trait_ptr ); - const auto& tr = *cur_trait.m_trait_ptr; - auto monomorph_cb = monomorphise_type_get_cb(sp, &type, &cur_trait.m_path.m_params, nullptr); - - for(const auto& trait_path_raw : tr.m_all_parent_traits) - { - // 1. Monomorph - auto trait_path_mono = monomorphise_traitpath_with(sp, trait_path_raw, monomorph_cb, false); - // 2. Add - rv.push_back( ::HIR::GenericBound::make_TraitBound({ type.clone(), mv$(trait_path_mono) }) ); - } - - // TODO: Add traits from `Self: Foo` bounds? - // TODO: Move associated types to the source trait. - } - ::std::vector< ::HIR::GenericBound> flatten_bounds(const ::std::vector<::HIR::GenericBound>& bounds) - { - ::std::vector< ::HIR::GenericBound > rv; - for(const auto& b : bounds) - { - TU_MATCHA( (b), (be), - (Lifetime, - rv.push_back( ::HIR::GenericBound(be) ); - ), - (TypeLifetime, - rv.push_back( ::HIR::GenericBound::make_TypeLifetime({ be.type.clone(), be.valid_for }) ); - ), - (TraitBound, - rv.push_back( ::HIR::GenericBound::make_TraitBound({ be.type.clone(), be.trait.clone() }) ); - add_bound_from_trait(rv, be.type, be.trait); - ), - (TypeEquality, - rv.push_back( ::HIR::GenericBound::make_TypeEquality({ be.type.clone(), be.other_type.clone() }) ); - ) - ) - } - ::std::sort(rv.begin(), rv.end(), [](const auto& a, const auto& b){ return ::ord(a,b) == OrdLess; }); - return rv; - } -} - -bool ::HIR::TraitImpl::more_specific_than(const ::HIR::TraitImpl& other) const -{ - static const Span _sp; - const Span& sp = _sp; - TRACE_FUNCTION; - //DEBUG("this = " << *this); - //DEBUG("other = " << other); - - // >> https://github.com/rust-lang/rfcs/blob/master/text/1210-impl-specialization.md#defining-the-precedence-rules - // 1. If this->m_type is less specific than other.m_type: return false - try - { - auto ord = type_ord_specific(sp, this->m_type, other.m_type); - // If `*this` < `other` : false - if( ord != ::OrdEqual ) { - DEBUG("- Type " << this->m_type << " " << (ord == ::OrdLess ? "less" : "more") << " specific than " << other.m_type); - return ord == ::OrdGreater; - } - // 2. If any in te.impl->m_params is less specific than oe.impl->m_params: return false - ord = typelist_ord_specific(sp, this->m_trait_args.m_types, other.m_trait_args.m_types); - if( ord != ::OrdEqual ) { - DEBUG("- Trait arguments " << (ord == ::OrdLess ? "less" : "more") << " specific"); - return ord == ::OrdGreater; - } - } - catch(const TypeOrdSpecific_MixedOrdering& e) - { - BUG(sp, "Mixed ordering in more_specific_than"); - } - - //if( other.m_params.m_bounds.size() == 0 ) { - // DEBUG("- Params (none in other, some in this)"); - // return m_params.m_bounds.size() > 0; - //} - // 3. Compare bound set, if there is a rule in oe that is missing from te; return false - // TODO: Cache these lists (calculate after outer typecheck?) - auto bounds_t = flatten_bounds(m_params.m_bounds); - auto bounds_o = flatten_bounds(other.m_params.m_bounds); - - DEBUG("bounds_t = " << bounds_t); - DEBUG("bounds_o = " << bounds_o); - - // If there are less bounds in this impl, it can't be more specific. - if( bounds_t.size() < bounds_o.size() ) - { - DEBUG("Bound count"); - return false; - } - - auto it_t = bounds_t.begin(); - auto it_o = bounds_o.begin(); - while( it_t != bounds_t.end() && it_o != bounds_o.end() ) - { - auto cmp = ::ord(*it_t, *it_o); - if( cmp == OrdEqual ) - { - ++it_t; - ++it_o; - continue ; - } - - // If the two bounds are similar - if( it_t->tag() == it_o->tag() && it_t->is_TraitBound() ) - { - const auto& b_t = it_t->as_TraitBound(); - const auto& b_o = it_o->as_TraitBound(); - // Check if the type is equal - if( b_t.type == b_o.type && b_t.trait.m_path.m_path == b_o.trait.m_path.m_path ) - { - const auto& params_t = b_t.trait.m_path.m_params; - const auto& params_o = b_o.trait.m_path.m_params; - switch( typelist_ord_specific(sp, params_t.m_types, params_o.m_types) ) - { - case ::OrdLess: return false; - case ::OrdGreater: return true; - case ::OrdEqual: break; - } - // TODO: Find cases where there's `T: Foo` and `T: Foo` - for(unsigned int i = 0; i < params_t.m_types.size(); i ++ ) - { - if( params_t.m_types[i] != params_o.m_types[i] && params_t.m_types[i] == b_t.type ) - { - return true; - } - } - TODO(sp, *it_t << " ?= " << *it_o); - } - } - - if( cmp == OrdLess ) - { - ++ it_t; - } - else - { - //++ it_o; - return false; - } - } - if( it_t != bounds_t.end() ) - { - return true; - } - else - { - return false; - } -} - -// Returns `true` if the two impls overlap in the types they will accept -bool ::HIR::TraitImpl::overlaps_with(const Crate& crate, const ::HIR::TraitImpl& other) const -{ - // TODO: Pre-calculate impl trees (with pointers to parent impls) - struct H { - static bool types_overlap(const ::HIR::PathParams& a, const ::HIR::PathParams& b) - { - for(unsigned int i = 0; i < ::std::min(a.m_types.size(), b.m_types.size()); i ++) - { - if( ! H::types_overlap(a.m_types[i], b.m_types[i]) ) - return false; - } - return true; - } - static bool types_overlap(const ::HIR::TypeRef& a, const ::HIR::TypeRef& b) - { - static Span sp; - //DEBUG("(" << a << "," << b << ")"); - if( a.m_data.is_Generic() || b.m_data.is_Generic() ) - return true; - // TODO: Unbound/Opaque paths? - if( a.m_data.tag() != b.m_data.tag() ) - return false; - TU_MATCHA( (a.m_data, b.m_data), (ae, be), - (Generic, - ), - (Infer, - ), - (Diverge, - ), - (Closure, - BUG(sp, "Hit closure"); - ), - (Primitive, - if( ae != be ) - return false; - ), - (Path, - if( ae.path.m_data.tag() != be.path.m_data.tag() ) - return false; - TU_MATCHA( (ae.path.m_data, be.path.m_data), (ape, bpe), - (Generic, - if( ape.m_path != bpe.m_path ) - return false; - return H::types_overlap(ape.m_params, bpe.m_params); - ), - (UfcsUnknown, - ), - (UfcsKnown, - ), - (UfcsInherent, - ) - ) - TODO(sp, "Path - " << ae.path << " and " << be.path); - ), - (TraitObject, - if( ae.m_trait.m_path.m_path != be.m_trait.m_path.m_path ) - return false; - if( !H::types_overlap(ae.m_trait.m_path.m_params, be.m_trait.m_path.m_params) ) - return false; - // Marker traits only overlap if the lists are the same (with overlap) - if( ae.m_markers.size() != be.m_markers.size() ) - return false; - for(size_t i = 0; i < ae.m_markers.size(); i++) - { - if( ae.m_markers[i].m_path != be.m_markers[i].m_path ) - return false; - if( !H::types_overlap(ae.m_markers[i].m_params, be.m_markers[i].m_params) ) - return false; - } - return true; - ), - (ErasedType, - TODO(sp, "ErasedType - " << a); - ), - (Function, - if( ae.is_unsafe != be.is_unsafe ) - return false; - if( ae.m_abi != be.m_abi ) - return false; - if( ae.m_arg_types.size() != be.m_arg_types.size() ) - return false; - for(unsigned int i = 0; i < ae.m_arg_types.size(); i ++) - { - if( ! H::types_overlap(ae.m_arg_types[i], be.m_arg_types[i]) ) - return false; - } - ), - (Tuple, - if( ae.size() != be.size() ) - return false; - for(unsigned int i = 0; i < ae.size(); i ++) - { - if( ! H::types_overlap(ae[i], be[i]) ) - return false; - } - ), - (Slice, - return H::types_overlap( *ae.inner, *be.inner ); - ), - (Array, - if( ae.size_val != be.size_val ) - return false; - return H::types_overlap( *ae.inner, *be.inner ); - ), - (Pointer, - if( ae.type != be.type ) - return false; - return H::types_overlap( *ae.inner, *be.inner ); - ), - (Borrow, - if( ae.type != be.type ) - return false; - return H::types_overlap( *ae.inner, *be.inner ); - ) - ) - return true; - } - }; - - // Quick Check: If the types are equal, they do overlap - if(this->m_type == other.m_type && this->m_trait_args == other.m_trait_args) - { - return true; - } - - // 1. Are the impl types of the same form (or is one generic) - if( ! H::types_overlap(this->m_type, other.m_type) ) - return false; - if( ! H::types_overlap(this->m_trait_args, other.m_trait_args) ) - return false; - - DEBUG("TODO: Handle potential overlap (when not exactly equal)"); - //return this->m_type == other.m_type && this->m_trait_args == other.m_trait_args; - Span sp; - - // TODO: Use `type_ord_specific` but treat any case of mixed ordering as this returning `false` - try - { - type_ord_specific(sp, this->m_type, other.m_type); - typelist_ord_specific(sp, this->m_trait_args.m_types, other.m_trait_args.m_types); - } - catch(const TypeOrdSpecific_MixedOrdering& /*e*/) - { - return false; - } - - // TODO: Detect `impl Foo for Bar` vs `impl Foo<&T> for Bar` - // > Create values for impl params from the type, then check if the trait params are compatible - // > Requires two lists, and telling which one to use by the end - auto cb_ident = [](const ::HIR::TypeRef& x)->const ::HIR::TypeRef& { return x; }; - bool is_reversed = false; - ::std::vector impl_tys; - auto cb_match = [&](unsigned int idx, const auto& /*name*/, const ::HIR::TypeRef& x)->::HIR::Compare { - assert(idx < impl_tys.size()); - if( impl_tys.at(idx) ) - { - DEBUG("Compare " << x << " and " << *impl_tys.at(idx)); - return (x == *impl_tys.at(idx) ? ::HIR::Compare::Equal : ::HIR::Compare::Unequal); - } - else - { - impl_tys.at(idx) = &x; - return ::HIR::Compare::Equal; - } - }; - impl_tys.resize( this->m_params.m_types.size() ); - if( ! this->m_type.match_test_generics(sp, other.m_type, cb_ident, cb_match) ) - { - DEBUG("- Type mismatch, try other ordering"); - is_reversed = true; - impl_tys.clear(); impl_tys.resize( other.m_params.m_types.size() ); - if( !other.m_type.match_test_generics(sp, this->m_type, cb_ident, cb_match) ) - { - DEBUG("- Type mismatch in both orderings"); - return false; - } - if( other.m_trait_args.match_test_generics_fuzz(sp, this->m_trait_args, cb_ident, cb_match) != ::HIR::Compare::Equal ) - { - DEBUG("- Params mismatch"); - return false; - } - // Matched with second ording - } - else if( this->m_trait_args.match_test_generics_fuzz(sp, other.m_trait_args, cb_ident, cb_match) != ::HIR::Compare::Equal ) - { - DEBUG("- Param mismatch, try other ordering"); - is_reversed = true; - impl_tys.clear(); impl_tys.resize( other.m_params.m_types.size() ); - if( !other.m_type.match_test_generics(sp, this->m_type, cb_ident, cb_match) ) - { - DEBUG("- Type mismatch in alt ordering"); - return false; - } - if( other.m_trait_args.match_test_generics_fuzz(sp, this->m_trait_args, cb_ident, cb_match) != ::HIR::Compare::Equal ) - { - DEBUG("- Params mismatch in alt ordering"); - return false; - } - // Matched with second ordering - } - else - { - // Matched with first ordering - } - - struct H2 { - static const ::HIR::TypeRef& monomorph(const Span& sp, const ::HIR::TypeRef& in_ty, const ::std::vector& args, ::HIR::TypeRef& tmp) - { - if( ! monomorphise_type_needed(in_ty) ) { - return in_ty; - } - else if( const auto* tep = in_ty.m_data.opt_Generic() ) { - ASSERT_BUG(sp, tep->binding < args.size(), ""); - ASSERT_BUG(sp, args[tep->binding], ""); - return *args[tep->binding]; - } - else { - auto monomorph_cb = [&](const auto& t)->const auto& { - const auto& te = t.m_data.as_Generic(); - assert(te.binding < args.size()); - ASSERT_BUG(sp, te.binding < args.size(), ""); - ASSERT_BUG(sp, args[te.binding], ""); - return *args[te.binding]; - }; - tmp = monomorphise_type_with(sp, in_ty, monomorph_cb); - // TODO: EAT? - return tmp; - } - } - static const ::HIR::TraitPath& monomorph(const Span& sp, const ::HIR::TraitPath& in, const ::std::vector& args, ::HIR::TraitPath& tmp) - { - if( ! monomorphise_traitpath_needed(in) ) { - return in; - } - else { - auto monomorph_cb = [&](const auto& t)->const auto& { - const auto& te = t.m_data.as_Generic(); - assert(te.binding < args.size()); - ASSERT_BUG(sp, te.binding < args.size(), ""); - ASSERT_BUG(sp, args[te.binding], ""); - return *args[te.binding]; - }; - tmp = monomorphise_traitpath_with(sp, in, monomorph_cb, true); - // TODO: EAT? - return tmp; - } - } - static bool check_bounds(const ::HIR::Crate& crate, const ::HIR::TraitImpl& id, const ::std::vector& args, const ::HIR::TraitImpl& g_src) - { - TRACE_FUNCTION; - static Span sp; - for(const auto& tb : id.m_params.m_bounds) - { - if(tb.is_TraitBound()) - { - ::HIR::TypeRef tmp_ty; - ::HIR::TraitPath tmp_tp; - const auto& ty = H2::monomorph(sp, tb.as_TraitBound().type, args, tmp_ty); - const auto& trait = H2::monomorph(sp, tb.as_TraitBound().trait, args, tmp_tp);; - - // Determine if `ty` would be bounded (it's an ATY or generic) - if( ty.m_data.is_Generic() ) { - bool found = false; - for(const auto& bound : g_src.m_params.m_bounds) - { - if(const auto* be = bound.opt_TraitBound()) - { - if( be->type != ty ) continue; - if( be->trait != trait ) continue; - found = true; - } - } - if( !found ) - { - DEBUG("No matching bound for " << ty << " : " << trait << " in source bounds - " << g_src.m_params.fmt_bounds()); - return false; - } - } - else if( TU_TEST1(ty.m_data, Path, .binding.is_Opaque()) ) { - TODO(Span(), "Check bound " << ty << " : " << trait << " in source bounds or trait bounds"); - } - else { - // Search the crate for an impl - bool rv = crate.find_trait_impls(trait.m_path.m_path, ty, [](const auto&t)->const auto&{ return t; }, [&](const ::HIR::TraitImpl& ti)->bool { - DEBUG("impl" << ti.m_params.fmt_args() << " " << trait.m_path.m_path << ti.m_trait_args << " for " << ti.m_type << ti.m_params.fmt_bounds()); - - ::std::vector impl_tys { ti.m_params.m_types.size() }; - auto cb_ident = [](const ::HIR::TypeRef& x)->const ::HIR::TypeRef& { return x; }; - auto cb_match = [&](unsigned int idx, const auto& /*name*/, const ::HIR::TypeRef& x)->::HIR::Compare { - assert(idx < impl_tys.size()); - if( impl_tys.at(idx) ) - { - DEBUG("Compare " << x << " and " << *impl_tys.at(idx)); - return (x == *impl_tys.at(idx) ? ::HIR::Compare::Equal : ::HIR::Compare::Unequal); - } - else - { - impl_tys.at(idx) = &x; - return ::HIR::Compare::Equal; - } - }; - // 1. Triple-check the type matches (and get generics) - if( ! ti.m_type.match_test_generics(sp, ty, cb_ident, cb_match) ) - return false; - // 2. Check trait params - assert(trait.m_path.m_params.m_types.size() == ti.m_trait_args.m_types.size()); - for(size_t i = 0; i < trait.m_path.m_params.m_types.size(); i ++) - { - if( !ti.m_trait_args.m_types[i].match_test_generics(sp, trait.m_path.m_params.m_types[i], cb_ident, cb_match) ) - return false; - } - // 3. Check bounds on the impl - if( !H2::check_bounds(crate, ti, impl_tys, g_src) ) - return false; - // 4. Check ATY bounds on the trait path - for(const auto& atyb : trait.m_type_bounds) - { - const auto& aty = ti.m_types.at(atyb.first); - if( !aty.data.match_test_generics(sp, atyb.second, cb_ident, cb_match) ) - return false; - } - // All those pass? It's good. - return true; - }); - if( !rv ) - { - return false; - } - } - } - else - { - // TODO: Other bound types? - } - } - // No bounds failed, it's good - return true; - } - }; - - // The two impls could overlap, pending on trait bounds - if(is_reversed) - { - DEBUG("(reversed) impl params " << FMT_CB(os, - for(auto* p : impl_tys) - { - if(p) - os << *p; - else - os << "?"; - os << ","; - } - )); - // Check bounds on `other` using these params - // TODO: Take a callback that does the checks. Or somehow return a "maybe overlaps" result? - return H2::check_bounds(crate, other, impl_tys, *this); - } - else - { - DEBUG("impl params " << FMT_CB(os, - for(auto* p : impl_tys) - { - if(p) - os << *p; - else - os << "?"; - os << ","; - } - )); - // Check bounds on `*this` - return H2::check_bounds(crate, *this, impl_tys, other); - } -} - const ::HIR::SimplePath& ::HIR::Crate::get_lang_item_path(const Span& sp, const char* name) const { @@ -1248,123 +322,3 @@ const ::HIR::Function& ::HIR::Crate::get_function_by_path(const Span& sp, const } } -bool ::HIR::Crate::find_trait_impls(const ::HIR::SimplePath& trait, const ::HIR::TypeRef& type, t_cb_resolve_type ty_res, ::std::function callback) const -{ - auto its = this->m_trait_impls.equal_range( trait ); - for( auto it = its.first; it != its.second; ++ it ) - { - const auto& impl = it->second; - if( impl.matches_type(type, ty_res) ) { - if( callback(impl) ) { - return true; - } - } - } - for( const auto& ec : this->m_ext_crates ) - { - if( ec.second.m_data->find_trait_impls(trait, type, ty_res, callback) ) { - return true; - } - } - return false; -} -bool ::HIR::Crate::find_auto_trait_impls(const ::HIR::SimplePath& trait, const ::HIR::TypeRef& type, t_cb_resolve_type ty_res, ::std::function callback) const -{ - auto its = this->m_marker_impls.equal_range( trait ); - for( auto it = its.first; it != its.second; ++ it ) - { - const auto& impl = it->second; - if( impl.matches_type(type, ty_res) ) { - if( callback(impl) ) { - return true; - } - } - } - for( const auto& ec : this->m_ext_crates ) - { - if( ec.second.m_data->find_auto_trait_impls(trait, type, ty_res, callback) ) { - return true; - } - } - return false; -} -bool ::HIR::Crate::find_type_impls(const ::HIR::TypeRef& type, t_cb_resolve_type ty_res, ::std::function callback) const -{ - // TODO: Restrict which crate is searched based on the type. - for( const auto& impl : this->m_type_impls ) - { - if( impl.matches_type(type, ty_res) ) { - if( callback(impl) ) { - return true; - } - } - } - for( const auto& ec : this->m_ext_crates ) - { - //DEBUG("- " << ec.first); - if( ec.second.m_data->find_type_impls(type, ty_res, callback) ) { - return true; - } - } - return false; -} - -const ::MIR::Function* HIR::Crate::get_or_gen_mir(const ::HIR::ItemPath& ip, const ::HIR::ExprPtr& ep, const ::HIR::Function::args_t& args, const ::HIR::TypeRef& ret_ty) const -{ - if( !ep ) - { - return &*ep.m_mir; - } - else - { - if( !ep.m_mir ) - { - TRACE_FUNCTION_F(ip); - ASSERT_BUG(Span(), ep.m_state, "No ExprState for " << ip); - - auto& ep_mut = const_cast<::HIR::ExprPtr&>(ep); - - // Ensure typechecked - if( ep.m_state->stage < ::HIR::ExprState::Stage::Typecheck ) - { - if( ep.m_state->stage == ::HIR::ExprState::Stage::TypecheckRequest ) - ERROR(Span(), E0000, "Loop in constant evaluation"); - ep.m_state->stage = ::HIR::ExprState::Stage::TypecheckRequest; - - // TODO: Set debug/timing stage - //Debug_SetStagePre("HIR Typecheck"); - // - Can store that on the Expr, OR get it from the item path - typeck::ModuleState ms { const_cast<::HIR::Crate&>(*this) }; - ms.m_impl_generics = ep.m_state->m_impl_generics; - ms.m_item_generics = ep.m_state->m_item_generics; - ms.m_traits = ep.m_state->m_traits; - Typecheck_Code(ms, const_cast<::HIR::Function::args_t&>(args), ret_ty, ep_mut); - //Debug_SetStagePre("Expand HIR Annotate"); - HIR_Expand_AnnotateUsage_Expr(*this, ep_mut); - //Debug_SetStagePre("Expand HIR Closures"); - HIR_Expand_Closures_Expr(*this, ep_mut); - //Debug_SetStagePre("Expand HIR Calls"); - HIR_Expand_UfcsEverything_Expr(*this, ep_mut); - //Debug_SetStagePre("Expand HIR Reborrows"); - HIR_Expand_Reborrows_Expr(*this, ep_mut); - //Debug_SetStagePre("Expand HIR ErasedType"); - //HIR_Expand_ErasedType(*this, ep_mut); // - Maybe? - //Typecheck_Expressions_Validate(*hir_crate); - - ep.m_state->stage = ::HIR::ExprState::Stage::Typecheck; - } - // Generate MIR - if( ep.m_state->stage < ::HIR::ExprState::Stage::Mir ) - { - if( ep.m_state->stage == ::HIR::ExprState::Stage::MirRequest ) - ERROR(Span(), E0000, "Loop in constant evaluation"); - ep.m_state->stage = ::HIR::ExprState::Stage::MirRequest; - //Debug_SetStage("Lower MIR"); - HIR_GenerateMIR_Expr(*this, ip, ep_mut, args, ret_ty); - ep.m_state->stage = ::HIR::ExprState::Stage::Mir; - } - assert(ep.m_mir); - } - return &*ep.m_mir; - } -} diff --git a/src/hir/hir_ops.cpp b/src/hir/hir_ops.cpp new file mode 100644 index 00000000..a082becd --- /dev/null +++ b/src/hir/hir_ops.cpp @@ -0,0 +1,1062 @@ +/* + * MRustC - Rust Compiler + * - By John Hodge (Mutabah/thePowersGang) + * + * hir/hir_ops.cpp + * - Complex operations on the HIR + */ +#include "hir.hpp" +#include +#include +#include // for invoking typecheck +#include "item_path.hpp" +#include "expr_state.hpp" +#include +#include + +namespace { + bool matches_genericpath(const ::HIR::GenericParams& params, const ::HIR::GenericPath& left, const ::HIR::GenericPath& right, ::HIR::t_cb_resolve_type ty_res, bool expand_generic); + + bool matches_type_int(const ::HIR::GenericParams& params, const ::HIR::TypeRef& left, const ::HIR::TypeRef& right_in, ::HIR::t_cb_resolve_type ty_res, bool expand_generic) + { + assert(! left.m_data.is_Infer() ); + const auto& right = (right_in.m_data.is_Infer() || (right_in.m_data.is_Generic() && expand_generic) ? ty_res(right_in) : right_in); + if( right_in.m_data.is_Generic() ) + expand_generic = false; + + //DEBUG("left = " << left << ", right = " << right); + + // TODO: What indicates what out of ty_res? + + if( const auto* re = right.m_data.opt_Infer() ) + { + //DEBUG("left = " << left << ", right = " << right); + switch(re->ty_class) + { + case ::HIR::InferClass::None: + case ::HIR::InferClass::Diverge: + //return left.m_data.is_Generic(); + return true; + case ::HIR::InferClass::Integer: + TU_IFLET(::HIR::TypeRef::Data, left.m_data, Primitive, le, + return is_integer(le); + ) + else { + return left.m_data.is_Generic(); + } + break; + case ::HIR::InferClass::Float: + TU_IFLET(::HIR::TypeRef::Data, left.m_data, Primitive, le, + return is_float(le); + ) + else { + return left.m_data.is_Generic(); + } + break; + } + throw ""; + } + + // A local generic could match anything, leave that up to the caller + if( left.m_data.is_Generic() ) { + DEBUG("> Generic left, success"); + return true; + } + // A local UfcsKnown can only be becuase it couldn't be expanded earlier, assume it could match + if( left.m_data.is_Path() && left.m_data.as_Path().path.m_data.is_UfcsKnown() ) { + // True? + //DEBUG("> UFCS Unknown left, success"); + return true; + } + + // If the RHS (provided) is generic, it can only match if it binds to a local type parameter + if( right.m_data.is_Generic() ) { + // TODO: This is handled above? + //DEBUG("> Generic right, only if left generic"); + return left.m_data.is_Generic(); + } + // If the RHS (provided) is generic, it can only match if it binds to a local type parameter + if( TU_TEST1(right.m_data, Path, .binding.is_Unbound()) ) { + //DEBUG("> UFCS Unknown right, fuzzy"); + return true; + } + + if( left.m_data.tag() != right.m_data.tag() ) { + //DEBUG("> Tag mismatch, failure"); + return false; + } + TU_MATCH(::HIR::TypeRef::Data, (left.m_data, right.m_data), (le, re), + (Infer, assert(!"infer");), + (Diverge, return true; ), + (Primitive, return le == re;), + (Path, + if( le.path.m_data.tag() != re.path.m_data.tag() ) + return false; + TU_MATCH_DEF(::HIR::Path::Data, (le.path.m_data, re.path.m_data), (ple, pre), + ( + return false; + ), + (Generic, + return matches_genericpath(params, ple, pre, ty_res, expand_generic); + ) + ) + ), + (Generic, + throw ""; + ), + (TraitObject, + if( !matches_genericpath(params, le.m_trait.m_path, re.m_trait.m_path, ty_res, expand_generic) ) + return false; + if( le.m_markers.size() != re.m_markers.size() ) + return false; + for(unsigned int i = 0; i < le.m_markers.size(); i ++) + { + const auto& lm = le.m_markers[i]; + const auto& rm = re.m_markers[i]; + if( !matches_genericpath(params, lm, rm, ty_res, expand_generic) ) + return false; + } + return true; + ), + (ErasedType, + throw "Unexpected ErasedType in matches_type_int"; + ), + (Array, + if( ! matches_type_int(params, *le.inner, *re.inner, ty_res, expand_generic) ) + return false; + if( le.size_val != re.size_val ) + return false; + return true; + ), + (Slice, + return matches_type_int(params, *le.inner, *re.inner, ty_res, expand_generic); + ), + (Tuple, + if( le.size() != re.size() ) + return false; + for( unsigned int i = 0; i < le.size(); i ++ ) + if( !matches_type_int(params, le[i], re[i], ty_res, expand_generic) ) + return false; + return true; + ), + (Borrow, + if( le.type != re.type ) + return false; + return matches_type_int(params, *le.inner, *re.inner, ty_res, expand_generic); + ), + (Pointer, + if( le.type != re.type ) + return false; + return matches_type_int(params, *le.inner, *re.inner, ty_res, expand_generic); + ), + (Function, + if( le.is_unsafe != re.is_unsafe ) + return false; + if( le.m_abi != re.m_abi ) + return false; + if( le.m_arg_types.size() != re.m_arg_types.size() ) + return false; + for( unsigned int i = 0; i < le.m_arg_types.size(); i ++ ) + if( !matches_type_int(params, le.m_arg_types[i], re.m_arg_types[i], ty_res, expand_generic) ) + return false; + return matches_type_int(params, *le.m_rettype, *re.m_rettype, ty_res, expand_generic); + ), + (Closure, + return le.node == re.node; + ) + ) + return false; + } + bool matches_genericpath(const ::HIR::GenericParams& params, const ::HIR::GenericPath& left, const ::HIR::GenericPath& right, ::HIR::t_cb_resolve_type ty_res, bool expand_generic) + { + if( left.m_path.m_crate_name != right.m_path.m_crate_name ) + return false; + if( left.m_path.m_components.size() != right.m_path.m_components.size() ) + return false; + for(unsigned int i = 0; i < left.m_path.m_components.size(); i ++ ) + { + if( left.m_path.m_components[i] != right.m_path.m_components[i] ) + return false; + } + + if( left.m_params.m_types.size() > 0 || right.m_params.m_types.size() > 0 ) + { + // Count mismatch. Allow due to defaults. + if( left.m_params.m_types.size() != right.m_params.m_types.size() ) { + return true; + //TODO(Span(), "Match generic paths " << left << " and " << right << " - count mismatch"); + } + for( unsigned int i = 0; i < right.m_params.m_types.size(); i ++ ) + { + if( ! matches_type_int(params, left.m_params.m_types[i], right.m_params.m_types[i], ty_res, expand_generic) ) + return false; + } + } + return true; + } +} + +//::HIR::TypeRef HIR::Function::make_ty(const Span& sp, const ::HIR::PathParams& params) const +//{ +// // TODO: Obtain function type for this function (i.e. a type that is specifically for this function) +// auto fcn_ty_data = ::HIR::FunctionType { +// m_is_unsafe, +// m_abi, +// box$( monomorphise_type(sp, m_params, params, m_return) ), +// {} +// }; +// fcn_ty_data.m_arg_types.reserve( m_args.size() ); +// for(const auto& arg : m_args) +// { +// fcn_ty_data.m_arg_types.push_back( monomorphise_type(sp, m_params, params, arg.second) ); +// } +// return ::HIR::TypeRef( mv$(fcn_ty_data) ); +//} + +namespace { + bool is_unbounded_infer(const ::HIR::TypeRef& type) { + TU_IFLET( ::HIR::TypeRef::Data, type.m_data, Infer, e, + return e.ty_class == ::HIR::InferClass::None || e.ty_class == ::HIR::InferClass::Diverge; + ) + else { + return false; + } + } +} + +bool ::HIR::TraitImpl::matches_type(const ::HIR::TypeRef& type, ::HIR::t_cb_resolve_type ty_res) const +{ + // NOTE: Don't return any impls when the type is an unbouned ivar. Wouldn't be able to pick anything anyway + // TODO: For `Unbound`, it could be valid, if the target is a generic. + // - Pure infer could also be useful (for knowing if there's any other potential impls) + if( is_unbounded_infer(type) || TU_TEST1(type.m_data, Path, .binding.is_Unbound()) ) { + return false; + } + return matches_type_int(m_params, m_type, type, ty_res, true); +} +bool ::HIR::TypeImpl::matches_type(const ::HIR::TypeRef& type, ::HIR::t_cb_resolve_type ty_res) const +{ + if( is_unbounded_infer(type) || TU_TEST1(type.m_data, Path, .binding.is_Unbound()) ) { + return false; + } + return matches_type_int(m_params, m_type, type, ty_res, true); +} +bool ::HIR::MarkerImpl::matches_type(const ::HIR::TypeRef& type, ::HIR::t_cb_resolve_type ty_res) const +{ + if( is_unbounded_infer(type) || TU_TEST1(type.m_data, Path, .binding.is_Unbound()) ) { + return false; + } + return matches_type_int(m_params, m_type, type, ty_res, true); +} + +namespace { + + struct TypeOrdSpecific_MixedOrdering + { + }; + + ::Ordering typelist_ord_specific(const Span& sp, const ::std::vector<::HIR::TypeRef>& left, const ::std::vector<::HIR::TypeRef>& right); + + ::Ordering type_ord_specific(const Span& sp, const ::HIR::TypeRef& left, const ::HIR::TypeRef& right) + { + // TODO: What happens if you get `impl Foo for T` vs `impl Foo for T` + + // A generic can't be more specific than any other type we can see + // - It's equally as specific as another Generic, so still false + if( left.m_data.is_Generic() ) { + return right.m_data.is_Generic() ? ::OrdEqual : ::OrdLess; + } + // - A generic is always less specific than anything but itself (handled above) + if( right.m_data.is_Generic() ) { + return ::OrdGreater; + } + + TU_MATCH(::HIR::TypeRef::Data, (left.m_data), (le), + (Generic, + throw ""; + ), + (Infer, + BUG(sp, "Hit infer"); + ), + (Diverge, + BUG(sp, "Hit diverge"); + ), + (Closure, + BUG(sp, "Hit closure"); + ), + (Primitive, + TU_IFLET(::HIR::TypeRef::Data, right.m_data, Primitive, re, + if( le != re ) + BUG(sp, "Mismatched types - " << left << " and " << right); + return ::OrdEqual; + ) + else { + BUG(sp, "Mismatched types - " << left << " and " << right); + } + ), + (Path, + if( !right.m_data.is_Path() || le.path.m_data.tag() != right.m_data.as_Path().path.m_data.tag() ) + BUG(sp, "Mismatched types - " << left << " and " << right); + TU_MATCHA( (le.path.m_data, right.m_data.as_Path().path.m_data), (lpe, rpe), + (Generic, + if( lpe.m_path != rpe.m_path ) + BUG(sp, "Mismatched types - " << left << " and " << right); + return typelist_ord_specific(sp, lpe.m_params.m_types, rpe.m_params.m_types); + ), + (UfcsUnknown, + ), + (UfcsKnown, + ), + (UfcsInherent, + ) + ) + TODO(sp, "Path - " << le.path << " and " << right); + ), + (TraitObject, + ASSERT_BUG(sp, right.m_data.is_TraitObject(), "Mismatched types - "<< left << " vs " << right); + const auto& re = right.m_data.as_TraitObject(); + ASSERT_BUG(sp, le.m_trait.m_path.m_path == re.m_trait.m_path.m_path, "Mismatched types - "<< left << " vs " << right); + ASSERT_BUG(sp, le.m_markers.size() == re.m_markers.size(), "Mismatched types - "<< left << " vs " << right); + + auto ord = typelist_ord_specific(sp, le.m_trait.m_path.m_params.m_types, re.m_trait.m_path.m_params.m_types); + if( ord != ::OrdEqual ) + return ord; + for(size_t i = 0; i < le.m_markers.size(); i ++) + { + ASSERT_BUG(sp, le.m_markers[i].m_path == re.m_markers[i].m_path, "Mismatched types - " << left << " vs " << right); + ord = typelist_ord_specific(sp, le.m_markers[i].m_params.m_types, re.m_markers[i].m_params.m_types); + if(ord != ::OrdEqual) + return ord; + } + return ::OrdEqual; + ), + (ErasedType, + TODO(sp, "ErasedType - " << left); + ), + (Function, + TU_IFLET(::HIR::TypeRef::Data, right.m_data, Function, re, + TODO(sp, "Function"); + //return typelist_ord_specific(sp, le.arg_types, re.arg_types); + ) + else { + BUG(sp, "Mismatched types - " << left << " and " << right); + } + ), + (Tuple, + TU_IFLET(::HIR::TypeRef::Data, right.m_data, Tuple, re, + return typelist_ord_specific(sp, le, re); + ) + else { + BUG(sp, "Mismatched types - " << left << " and " << right); + } + ), + (Slice, + TU_IFLET(::HIR::TypeRef::Data, right.m_data, Slice, re, + return type_ord_specific(sp, *le.inner, *re.inner); + ) + else { + BUG(sp, "Mismatched types - " << left << " and " << right); + } + ), + (Array, + TU_IFLET(::HIR::TypeRef::Data, right.m_data, Array, re, + if( le.size_val != re.size_val ) + BUG(sp, "Mismatched types - " << left << " and " << right); + return type_ord_specific(sp, *le.inner, *re.inner); + ) + else { + BUG(sp, "Mismatched types - " << left << " and " << right); + } + ), + (Pointer, + TU_IFLET(::HIR::TypeRef::Data, right.m_data, Pointer, re, + if( le.type != re.type ) + BUG(sp, "Mismatched types - " << left << " and " << right); + return type_ord_specific(sp, *le.inner, *re.inner); + ) + else { + BUG(sp, "Mismatched types - " << left << " and " << right); + } + ), + (Borrow, + TU_IFLET(::HIR::TypeRef::Data, right.m_data, Borrow, re, + if( le.type != re.type ) + BUG(sp, "Mismatched types - " << left << " and " << right); + return type_ord_specific(sp, *le.inner, *re.inner); + ) + else { + BUG(sp, "Mismatched types - " << left << " and " << right); + } + ) + ) + throw "Fell off end of type_ord_specific"; + } + + ::Ordering typelist_ord_specific(const Span& sp, const ::std::vector<::HIR::TypeRef>& le, const ::std::vector<::HIR::TypeRef>& re) + { + auto rv = ::OrdEqual; + assert(le.size() == re.size()); + for(unsigned int i = 0; i < le.size(); i ++) { + auto a = type_ord_specific(sp, le[i], re[i]); + if( a != ::OrdEqual ) { + if( rv != ::OrdEqual && a != rv ) + { + DEBUG("Inconsistent ordering between type lists - i=" << i << " [" << le << "] vs [" << re << "]"); + throw TypeOrdSpecific_MixedOrdering {}; + } + rv = a; + } + } + return rv; + } +} + +namespace { + void add_bound_from_trait(::std::vector< ::HIR::GenericBound>& rv, const ::HIR::TypeRef& type, const ::HIR::TraitPath& cur_trait) + { + static Span sp; + assert( cur_trait.m_trait_ptr ); + const auto& tr = *cur_trait.m_trait_ptr; + auto monomorph_cb = monomorphise_type_get_cb(sp, &type, &cur_trait.m_path.m_params, nullptr); + + for(const auto& trait_path_raw : tr.m_all_parent_traits) + { + // 1. Monomorph + auto trait_path_mono = monomorphise_traitpath_with(sp, trait_path_raw, monomorph_cb, false); + // 2. Add + rv.push_back( ::HIR::GenericBound::make_TraitBound({ type.clone(), mv$(trait_path_mono) }) ); + } + + // TODO: Add traits from `Self: Foo` bounds? + // TODO: Move associated types to the source trait. + } + ::std::vector< ::HIR::GenericBound> flatten_bounds(const ::std::vector<::HIR::GenericBound>& bounds) + { + ::std::vector< ::HIR::GenericBound > rv; + for(const auto& b : bounds) + { + TU_MATCHA( (b), (be), + (Lifetime, + rv.push_back( ::HIR::GenericBound(be) ); + ), + (TypeLifetime, + rv.push_back( ::HIR::GenericBound::make_TypeLifetime({ be.type.clone(), be.valid_for }) ); + ), + (TraitBound, + rv.push_back( ::HIR::GenericBound::make_TraitBound({ be.type.clone(), be.trait.clone() }) ); + add_bound_from_trait(rv, be.type, be.trait); + ), + (TypeEquality, + rv.push_back( ::HIR::GenericBound::make_TypeEquality({ be.type.clone(), be.other_type.clone() }) ); + ) + ) + } + ::std::sort(rv.begin(), rv.end(), [](const auto& a, const auto& b){ return ::ord(a,b) == OrdLess; }); + return rv; + } +} + +bool ::HIR::TraitImpl::more_specific_than(const ::HIR::TraitImpl& other) const +{ + static const Span _sp; + const Span& sp = _sp; + TRACE_FUNCTION; + //DEBUG("this = " << *this); + //DEBUG("other = " << other); + + // >> https://github.com/rust-lang/rfcs/blob/master/text/1210-impl-specialization.md#defining-the-precedence-rules + // 1. If this->m_type is less specific than other.m_type: return false + try + { + auto ord = type_ord_specific(sp, this->m_type, other.m_type); + // If `*this` < `other` : false + if( ord != ::OrdEqual ) { + DEBUG("- Type " << this->m_type << " " << (ord == ::OrdLess ? "less" : "more") << " specific than " << other.m_type); + return ord == ::OrdGreater; + } + // 2. If any in te.impl->m_params is less specific than oe.impl->m_params: return false + ord = typelist_ord_specific(sp, this->m_trait_args.m_types, other.m_trait_args.m_types); + if( ord != ::OrdEqual ) { + DEBUG("- Trait arguments " << (ord == ::OrdLess ? "less" : "more") << " specific"); + return ord == ::OrdGreater; + } + } + catch(const TypeOrdSpecific_MixedOrdering& e) + { + BUG(sp, "Mixed ordering in more_specific_than"); + } + + //if( other.m_params.m_bounds.size() == 0 ) { + // DEBUG("- Params (none in other, some in this)"); + // return m_params.m_bounds.size() > 0; + //} + // 3. Compare bound set, if there is a rule in oe that is missing from te; return false + // TODO: Cache these lists (calculate after outer typecheck?) + auto bounds_t = flatten_bounds(m_params.m_bounds); + auto bounds_o = flatten_bounds(other.m_params.m_bounds); + + DEBUG("bounds_t = " << bounds_t); + DEBUG("bounds_o = " << bounds_o); + + // If there are less bounds in this impl, it can't be more specific. + if( bounds_t.size() < bounds_o.size() ) + { + DEBUG("Bound count"); + return false; + } + + auto it_t = bounds_t.begin(); + auto it_o = bounds_o.begin(); + while( it_t != bounds_t.end() && it_o != bounds_o.end() ) + { + auto cmp = ::ord(*it_t, *it_o); + if( cmp == OrdEqual ) + { + ++it_t; + ++it_o; + continue ; + } + + // If the two bounds are similar + if( it_t->tag() == it_o->tag() && it_t->is_TraitBound() ) + { + const auto& b_t = it_t->as_TraitBound(); + const auto& b_o = it_o->as_TraitBound(); + // Check if the type is equal + if( b_t.type == b_o.type && b_t.trait.m_path.m_path == b_o.trait.m_path.m_path ) + { + const auto& params_t = b_t.trait.m_path.m_params; + const auto& params_o = b_o.trait.m_path.m_params; + switch( typelist_ord_specific(sp, params_t.m_types, params_o.m_types) ) + { + case ::OrdLess: return false; + case ::OrdGreater: return true; + case ::OrdEqual: break; + } + // TODO: Find cases where there's `T: Foo` and `T: Foo` + for(unsigned int i = 0; i < params_t.m_types.size(); i ++ ) + { + if( params_t.m_types[i] != params_o.m_types[i] && params_t.m_types[i] == b_t.type ) + { + return true; + } + } + TODO(sp, *it_t << " ?= " << *it_o); + } + } + + if( cmp == OrdLess ) + { + ++ it_t; + } + else + { + //++ it_o; + return false; + } + } + if( it_t != bounds_t.end() ) + { + return true; + } + else + { + return false; + } +} + +// Returns `true` if the two impls overlap in the types they will accept +bool ::HIR::TraitImpl::overlaps_with(const Crate& crate, const ::HIR::TraitImpl& other) const +{ + // TODO: Pre-calculate impl trees (with pointers to parent impls) + struct H { + static bool types_overlap(const ::HIR::PathParams& a, const ::HIR::PathParams& b) + { + for(unsigned int i = 0; i < ::std::min(a.m_types.size(), b.m_types.size()); i ++) + { + if( ! H::types_overlap(a.m_types[i], b.m_types[i]) ) + return false; + } + return true; + } + static bool types_overlap(const ::HIR::TypeRef& a, const ::HIR::TypeRef& b) + { + static Span sp; + //DEBUG("(" << a << "," << b << ")"); + if( a.m_data.is_Generic() || b.m_data.is_Generic() ) + return true; + // TODO: Unbound/Opaque paths? + if( a.m_data.tag() != b.m_data.tag() ) + return false; + TU_MATCHA( (a.m_data, b.m_data), (ae, be), + (Generic, + ), + (Infer, + ), + (Diverge, + ), + (Closure, + BUG(sp, "Hit closure"); + ), + (Primitive, + if( ae != be ) + return false; + ), + (Path, + if( ae.path.m_data.tag() != be.path.m_data.tag() ) + return false; + TU_MATCHA( (ae.path.m_data, be.path.m_data), (ape, bpe), + (Generic, + if( ape.m_path != bpe.m_path ) + return false; + return H::types_overlap(ape.m_params, bpe.m_params); + ), + (UfcsUnknown, + ), + (UfcsKnown, + ), + (UfcsInherent, + ) + ) + TODO(sp, "Path - " << ae.path << " and " << be.path); + ), + (TraitObject, + if( ae.m_trait.m_path.m_path != be.m_trait.m_path.m_path ) + return false; + if( !H::types_overlap(ae.m_trait.m_path.m_params, be.m_trait.m_path.m_params) ) + return false; + // Marker traits only overlap if the lists are the same (with overlap) + if( ae.m_markers.size() != be.m_markers.size() ) + return false; + for(size_t i = 0; i < ae.m_markers.size(); i++) + { + if( ae.m_markers[i].m_path != be.m_markers[i].m_path ) + return false; + if( !H::types_overlap(ae.m_markers[i].m_params, be.m_markers[i].m_params) ) + return false; + } + return true; + ), + (ErasedType, + TODO(sp, "ErasedType - " << a); + ), + (Function, + if( ae.is_unsafe != be.is_unsafe ) + return false; + if( ae.m_abi != be.m_abi ) + return false; + if( ae.m_arg_types.size() != be.m_arg_types.size() ) + return false; + for(unsigned int i = 0; i < ae.m_arg_types.size(); i ++) + { + if( ! H::types_overlap(ae.m_arg_types[i], be.m_arg_types[i]) ) + return false; + } + ), + (Tuple, + if( ae.size() != be.size() ) + return false; + for(unsigned int i = 0; i < ae.size(); i ++) + { + if( ! H::types_overlap(ae[i], be[i]) ) + return false; + } + ), + (Slice, + return H::types_overlap( *ae.inner, *be.inner ); + ), + (Array, + if( ae.size_val != be.size_val ) + return false; + return H::types_overlap( *ae.inner, *be.inner ); + ), + (Pointer, + if( ae.type != be.type ) + return false; + return H::types_overlap( *ae.inner, *be.inner ); + ), + (Borrow, + if( ae.type != be.type ) + return false; + return H::types_overlap( *ae.inner, *be.inner ); + ) + ) + return true; + } + }; + + // Quick Check: If the types are equal, they do overlap + if(this->m_type == other.m_type && this->m_trait_args == other.m_trait_args) + { + return true; + } + + // 1. Are the impl types of the same form (or is one generic) + if( ! H::types_overlap(this->m_type, other.m_type) ) + return false; + if( ! H::types_overlap(this->m_trait_args, other.m_trait_args) ) + return false; + + DEBUG("TODO: Handle potential overlap (when not exactly equal)"); + //return this->m_type == other.m_type && this->m_trait_args == other.m_trait_args; + Span sp; + + // TODO: Use `type_ord_specific` but treat any case of mixed ordering as this returning `false` + try + { + type_ord_specific(sp, this->m_type, other.m_type); + typelist_ord_specific(sp, this->m_trait_args.m_types, other.m_trait_args.m_types); + } + catch(const TypeOrdSpecific_MixedOrdering& /*e*/) + { + return false; + } + + // TODO: Detect `impl Foo for Bar` vs `impl Foo<&T> for Bar` + // > Create values for impl params from the type, then check if the trait params are compatible + // > Requires two lists, and telling which one to use by the end + auto cb_ident = [](const ::HIR::TypeRef& x)->const ::HIR::TypeRef& { return x; }; + bool is_reversed = false; + ::std::vector impl_tys; + auto cb_match = [&](unsigned int idx, const auto& /*name*/, const ::HIR::TypeRef& x)->::HIR::Compare { + assert(idx < impl_tys.size()); + if( impl_tys.at(idx) ) + { + DEBUG("Compare " << x << " and " << *impl_tys.at(idx)); + return (x == *impl_tys.at(idx) ? ::HIR::Compare::Equal : ::HIR::Compare::Unequal); + } + else + { + impl_tys.at(idx) = &x; + return ::HIR::Compare::Equal; + } + }; + impl_tys.resize( this->m_params.m_types.size() ); + if( ! this->m_type.match_test_generics(sp, other.m_type, cb_ident, cb_match) ) + { + DEBUG("- Type mismatch, try other ordering"); + is_reversed = true; + impl_tys.clear(); impl_tys.resize( other.m_params.m_types.size() ); + if( !other.m_type.match_test_generics(sp, this->m_type, cb_ident, cb_match) ) + { + DEBUG("- Type mismatch in both orderings"); + return false; + } + if( other.m_trait_args.match_test_generics_fuzz(sp, this->m_trait_args, cb_ident, cb_match) != ::HIR::Compare::Equal ) + { + DEBUG("- Params mismatch"); + return false; + } + // Matched with second ording + } + else if( this->m_trait_args.match_test_generics_fuzz(sp, other.m_trait_args, cb_ident, cb_match) != ::HIR::Compare::Equal ) + { + DEBUG("- Param mismatch, try other ordering"); + is_reversed = true; + impl_tys.clear(); impl_tys.resize( other.m_params.m_types.size() ); + if( !other.m_type.match_test_generics(sp, this->m_type, cb_ident, cb_match) ) + { + DEBUG("- Type mismatch in alt ordering"); + return false; + } + if( other.m_trait_args.match_test_generics_fuzz(sp, this->m_trait_args, cb_ident, cb_match) != ::HIR::Compare::Equal ) + { + DEBUG("- Params mismatch in alt ordering"); + return false; + } + // Matched with second ordering + } + else + { + // Matched with first ordering + } + + struct H2 { + static const ::HIR::TypeRef& monomorph(const Span& sp, const ::HIR::TypeRef& in_ty, const ::std::vector& args, ::HIR::TypeRef& tmp) + { + if( ! monomorphise_type_needed(in_ty) ) { + return in_ty; + } + else if( const auto* tep = in_ty.m_data.opt_Generic() ) { + ASSERT_BUG(sp, tep->binding < args.size(), ""); + ASSERT_BUG(sp, args[tep->binding], ""); + return *args[tep->binding]; + } + else { + auto monomorph_cb = [&](const auto& t)->const auto& { + const auto& te = t.m_data.as_Generic(); + assert(te.binding < args.size()); + ASSERT_BUG(sp, te.binding < args.size(), ""); + ASSERT_BUG(sp, args[te.binding], ""); + return *args[te.binding]; + }; + tmp = monomorphise_type_with(sp, in_ty, monomorph_cb); + // TODO: EAT? + return tmp; + } + } + static const ::HIR::TraitPath& monomorph(const Span& sp, const ::HIR::TraitPath& in, const ::std::vector& args, ::HIR::TraitPath& tmp) + { + if( ! monomorphise_traitpath_needed(in) ) { + return in; + } + else { + auto monomorph_cb = [&](const auto& t)->const auto& { + const auto& te = t.m_data.as_Generic(); + assert(te.binding < args.size()); + ASSERT_BUG(sp, te.binding < args.size(), ""); + ASSERT_BUG(sp, args[te.binding], ""); + return *args[te.binding]; + }; + tmp = monomorphise_traitpath_with(sp, in, monomorph_cb, true); + // TODO: EAT? + return tmp; + } + } + static bool check_bounds(const ::HIR::Crate& crate, const ::HIR::TraitImpl& id, const ::std::vector& args, const ::HIR::TraitImpl& g_src) + { + TRACE_FUNCTION; + static Span sp; + for(const auto& tb : id.m_params.m_bounds) + { + if(tb.is_TraitBound()) + { + ::HIR::TypeRef tmp_ty; + ::HIR::TraitPath tmp_tp; + const auto& ty = H2::monomorph(sp, tb.as_TraitBound().type, args, tmp_ty); + const auto& trait = H2::monomorph(sp, tb.as_TraitBound().trait, args, tmp_tp);; + + // Determine if `ty` would be bounded (it's an ATY or generic) + if( ty.m_data.is_Generic() ) { + bool found = false; + for(const auto& bound : g_src.m_params.m_bounds) + { + if(const auto* be = bound.opt_TraitBound()) + { + if( be->type != ty ) continue; + if( be->trait != trait ) continue; + found = true; + } + } + if( !found ) + { + DEBUG("No matching bound for " << ty << " : " << trait << " in source bounds - " << g_src.m_params.fmt_bounds()); + return false; + } + } + else if( TU_TEST1(ty.m_data, Path, .binding.is_Opaque()) ) { + TODO(Span(), "Check bound " << ty << " : " << trait << " in source bounds or trait bounds"); + } + else { + // Search the crate for an impl + bool rv = crate.find_trait_impls(trait.m_path.m_path, ty, [](const auto&t)->const auto&{ return t; }, [&](const ::HIR::TraitImpl& ti)->bool { + DEBUG("impl" << ti.m_params.fmt_args() << " " << trait.m_path.m_path << ti.m_trait_args << " for " << ti.m_type << ti.m_params.fmt_bounds()); + + ::std::vector impl_tys { ti.m_params.m_types.size() }; + auto cb_ident = [](const ::HIR::TypeRef& x)->const ::HIR::TypeRef& { return x; }; + auto cb_match = [&](unsigned int idx, const auto& /*name*/, const ::HIR::TypeRef& x)->::HIR::Compare { + assert(idx < impl_tys.size()); + if( impl_tys.at(idx) ) + { + DEBUG("Compare " << x << " and " << *impl_tys.at(idx)); + return (x == *impl_tys.at(idx) ? ::HIR::Compare::Equal : ::HIR::Compare::Unequal); + } + else + { + impl_tys.at(idx) = &x; + return ::HIR::Compare::Equal; + } + }; + // 1. Triple-check the type matches (and get generics) + if( ! ti.m_type.match_test_generics(sp, ty, cb_ident, cb_match) ) + return false; + // 2. Check trait params + assert(trait.m_path.m_params.m_types.size() == ti.m_trait_args.m_types.size()); + for(size_t i = 0; i < trait.m_path.m_params.m_types.size(); i ++) + { + if( !ti.m_trait_args.m_types[i].match_test_generics(sp, trait.m_path.m_params.m_types[i], cb_ident, cb_match) ) + return false; + } + // 3. Check bounds on the impl + if( !H2::check_bounds(crate, ti, impl_tys, g_src) ) + return false; + // 4. Check ATY bounds on the trait path + for(const auto& atyb : trait.m_type_bounds) + { + const auto& aty = ti.m_types.at(atyb.first); + if( !aty.data.match_test_generics(sp, atyb.second, cb_ident, cb_match) ) + return false; + } + // All those pass? It's good. + return true; + }); + if( !rv ) + { + return false; + } + } + } + else + { + // TODO: Other bound types? + } + } + // No bounds failed, it's good + return true; + } + }; + + // The two impls could overlap, pending on trait bounds + if(is_reversed) + { + DEBUG("(reversed) impl params " << FMT_CB(os, + for(auto* p : impl_tys) + { + if(p) + os << *p; + else + os << "?"; + os << ","; + } + )); + // Check bounds on `other` using these params + // TODO: Take a callback that does the checks. Or somehow return a "maybe overlaps" result? + return H2::check_bounds(crate, other, impl_tys, *this); + } + else + { + DEBUG("impl params " << FMT_CB(os, + for(auto* p : impl_tys) + { + if(p) + os << *p; + else + os << "?"; + os << ","; + } + )); + // Check bounds on `*this` + return H2::check_bounds(crate, *this, impl_tys, other); + } +} + +bool ::HIR::Crate::find_trait_impls(const ::HIR::SimplePath& trait, const ::HIR::TypeRef& type, t_cb_resolve_type ty_res, ::std::function callback) const +{ + auto its = this->m_trait_impls.equal_range( trait ); + for( auto it = its.first; it != its.second; ++ it ) + { + const auto& impl = it->second; + if( impl.matches_type(type, ty_res) ) { + if( callback(impl) ) { + return true; + } + } + } + for( const auto& ec : this->m_ext_crates ) + { + if( ec.second.m_data->find_trait_impls(trait, type, ty_res, callback) ) { + return true; + } + } + return false; +} +bool ::HIR::Crate::find_auto_trait_impls(const ::HIR::SimplePath& trait, const ::HIR::TypeRef& type, t_cb_resolve_type ty_res, ::std::function callback) const +{ + auto its = this->m_marker_impls.equal_range( trait ); + for( auto it = its.first; it != its.second; ++ it ) + { + const auto& impl = it->second; + if( impl.matches_type(type, ty_res) ) { + if( callback(impl) ) { + return true; + } + } + } + for( const auto& ec : this->m_ext_crates ) + { + if( ec.second.m_data->find_auto_trait_impls(trait, type, ty_res, callback) ) { + return true; + } + } + return false; +} +bool ::HIR::Crate::find_type_impls(const ::HIR::TypeRef& type, t_cb_resolve_type ty_res, ::std::function callback) const +{ + // TODO: Restrict which crate is searched based on the type. + for( const auto& impl : this->m_type_impls ) + { + if( impl.matches_type(type, ty_res) ) { + if( callback(impl) ) { + return true; + } + } + } + for( const auto& ec : this->m_ext_crates ) + { + //DEBUG("- " << ec.first); + if( ec.second.m_data->find_type_impls(type, ty_res, callback) ) { + return true; + } + } + return false; +} + +const ::MIR::Function* HIR::Crate::get_or_gen_mir(const ::HIR::ItemPath& ip, const ::HIR::ExprPtr& ep, const ::HIR::Function::args_t& args, const ::HIR::TypeRef& ret_ty) const +{ + if( !ep ) + { + return &*ep.m_mir; + } + else + { + if( !ep.m_mir ) + { + TRACE_FUNCTION_F(ip); + ASSERT_BUG(Span(), ep.m_state, "No ExprState for " << ip); + + auto& ep_mut = const_cast<::HIR::ExprPtr&>(ep); + + // Ensure typechecked + if( ep.m_state->stage < ::HIR::ExprState::Stage::Typecheck ) + { + if( ep.m_state->stage == ::HIR::ExprState::Stage::TypecheckRequest ) + ERROR(Span(), E0000, "Loop in constant evaluation"); + ep.m_state->stage = ::HIR::ExprState::Stage::TypecheckRequest; + + // TODO: Set debug/timing stage + //Debug_SetStagePre("HIR Typecheck"); + // - Can store that on the Expr, OR get it from the item path + typeck::ModuleState ms { const_cast<::HIR::Crate&>(*this) }; + ms.m_impl_generics = ep.m_state->m_impl_generics; + ms.m_item_generics = ep.m_state->m_item_generics; + ms.m_traits = ep.m_state->m_traits; + Typecheck_Code(ms, const_cast<::HIR::Function::args_t&>(args), ret_ty, ep_mut); + //Debug_SetStagePre("Expand HIR Annotate"); + HIR_Expand_AnnotateUsage_Expr(*this, ep_mut); + //Debug_SetStagePre("Expand HIR Closures"); + HIR_Expand_Closures_Expr(*this, ep_mut); + //Debug_SetStagePre("Expand HIR Calls"); + HIR_Expand_UfcsEverything_Expr(*this, ep_mut); + //Debug_SetStagePre("Expand HIR Reborrows"); + HIR_Expand_Reborrows_Expr(*this, ep_mut); + //Debug_SetStagePre("Expand HIR ErasedType"); + //HIR_Expand_ErasedType(*this, ep_mut); // - Maybe? + //Typecheck_Expressions_Validate(*hir_crate); + + ep.m_state->stage = ::HIR::ExprState::Stage::Typecheck; + } + // Generate MIR + if( ep.m_state->stage < ::HIR::ExprState::Stage::Mir ) + { + if( ep.m_state->stage == ::HIR::ExprState::Stage::MirRequest ) + ERROR(Span(), E0000, "Loop in constant evaluation"); + ep.m_state->stage = ::HIR::ExprState::Stage::MirRequest; + //Debug_SetStage("Lower MIR"); + HIR_GenerateMIR_Expr(*this, ip, ep_mut, args, ret_ty); + ep.m_state->stage = ::HIR::ExprState::Stage::Mir; + } + assert(ep.m_mir); + } + return &*ep.m_mir; + } +} -- cgit v1.2.3 From 129e7c0d3e91ee3fdf6835464bf8ec97f2ffc9a5 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 23 Mar 2019 16:07:27 +0800 Subject: Tools - add a hacky crate metadata dump tool (macros only currently) --- tools/dump_hirfile/Makefile | 56 +++++++++++++++++++ tools/dump_hirfile/main.cpp | 128 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 184 insertions(+) create mode 100644 tools/dump_hirfile/Makefile create mode 100644 tools/dump_hirfile/main.cpp diff --git a/tools/dump_hirfile/Makefile b/tools/dump_hirfile/Makefile new file mode 100644 index 00000000..10fb8e81 --- /dev/null +++ b/tools/dump_hirfile/Makefile @@ -0,0 +1,56 @@ +# +ifeq ($(OS),Windows_NT) + EXESUF ?= .exe +endif +EXESUF ?= + +V ?= @ + +OBJDIR := .obj/ + +BIN := ../bin/dump_hirfile$(EXESUF) +OBJS := main.o +OBJS += debug.o rc_string.o span.o ident.o +OBJS += parse/parseerror.o # Why is this needed? ast/path.cpp uses it in binding +OBJS += hir/hir.o hir/type.o hir/deserialise.o hir/serialise_lowlevel.o +OBJS += hir/crate_ptr.o hir/generic_params.o hir/path.o hir/pattern.o hir/expr_ptr.o +OBJS += hir/expr.o # Why is this needed? +OBJS += parse/token.o parse/tokentree.o parse/tokenstream.o +OBJS += ast/ast.o ast/expr.o ast/path.o ast/types.o ast/pattern.o +OBJS += mir/mir.o mir/mir_ptr.o +OBJS += macro_rules/mod.o + +LINKFLAGS := -g -lpthread -lz +CXXFLAGS := -Wall -std=c++14 -g -O2 +CXXFLAGS += -I ../common -I ../../src -I ../../src/include + +OBJS := $(OBJS:%=$(OBJDIR)%) + +.PHONY: all clean + +all: $(BIN) + +clean: + rm $(BIN) $(OBJS) + +$(BIN): $(OBJS) ../bin/common_lib.a + @mkdir -p $(dir $@) + @echo [CXX] -o $@ + $V$(CXX) -o $@ $(OBJS) ../bin/common_lib.a $(LINKFLAGS) + +$(OBJDIR)%.o: %.cpp + @mkdir -p $(dir $@) + @echo [CXX] $< + $V$(CXX) -o $@ -c $< $(CXXFLAGS) -MMD -MP -MF $@.dep + +$(OBJDIR)%.o: ../../src/%.cpp + @mkdir -p $(dir $@) + @echo [CXX] $< + $V$(CXX) -o $@ -c $< $(CXXFLAGS) -MMD -MP -MF $@.dep + +../bin/common_lib.a: $(wildcard ../common/*.* ../common/Makefile) + make -C ../common + +-include $(OBJS:%.o=%.o.dep) + + diff --git a/tools/dump_hirfile/main.cpp b/tools/dump_hirfile/main.cpp new file mode 100644 index 00000000..df3e48df --- /dev/null +++ b/tools/dump_hirfile/main.cpp @@ -0,0 +1,128 @@ +#include +#include +#include + +int g_debug_indent_level = 0; + +struct Args +{ + Args(int argc, const char* const argv[]); + + ::std::string infile; +}; + +int main(int argc, const char* argv[]) +{ + Args args(argc, argv); + + auto hir = HIR_Deserialise(args.infile, ""); + + // Dump macros + for(const auto& mac : hir->m_exported_macros) + { + ::std::cout << "macro_rules! " << mac.first << "{" << std::endl; + for(const auto& arm : mac.second->m_rules) + { + ::std::cout << " ("; + for(const auto& pat : arm.m_pattern) + { + TU_MATCH_HDRA( (pat), {) + TU_ARMA(End, e) + ::std::cout << " EOS"; + TU_ARMA(LoopStart, e) + ::std::cout << " ("; + TU_ARMA(LoopNext, e) + ::std::cout << " ^"; + TU_ARMA(LoopEnd, e) + ::std::cout << " )"; + TU_ARMA(Jump, e) + ::std::cout << " <" << e.jump_target; + TU_ARMA(ExpectTok, e) + ::std::cout << " =" << e; + TU_ARMA(ExpectPat, e) + ::std::cout << " " << e.idx << "=" << e.type; + TU_ARMA(If, e) { + ::std::cout << " ?" << (e.is_equal ? "" : "!") << "{"; + for(const auto& ent : e.ents) { + if(ent.ty == MacroPatEnt::PAT_TOKEN) + ::std::cout << " =" << ent.tok; + else + ::std::cout << " " << ent.ty; + } + ::std::cout << "}->" << e.jump_target; + } + } + } + ::std::cout << " ) => {" << ::std::endl; + // TODO... + ::std::cout << " }" << ::std::endl; + } + ::std::cout << "}" << ::std::endl; + ::std::cout << ::std::endl; + } +} + +bool debug_enabled() +{ + return false; +} +::std::ostream& debug_output(int indent, const char* function) +{ + return ::std::cout << "- " << RepeatLitStr { " ", indent } << function << ": "; +} + +Args::Args(int argc, const char* const argv[]) +{ + this->infile = argv[1]; +} + +// TODO: This is copy-pasted from src/main.cpp, should live somewhere better +::std::ostream& operator<<(::std::ostream& os, const FmtEscaped& x) +{ + os << ::std::hex; + for(auto s = x.s; *s != '\0'; s ++) + { + switch(*s) + { + case '\0': os << "\\0"; break; + case '\n': os << "\\n"; break; + case '\\': os << "\\\\"; break; + case '"': os << "\\\""; break; + default: + uint8_t v = *s; + if( v < 0x80 ) + { + if( v < ' ' || v > 0x7F ) + os << "\\u{" << ::std::hex << (unsigned int)v << "}"; + else + os << v; + } + else if( v < 0xC0 ) + ; + else if( v < 0xE0 ) + { + uint32_t val = (uint32_t)(v & 0x1F) << 6; + v = (uint8_t)*++s; if( (v & 0xC0) != 0x80 ) { s--; continue ; } val |= (uint32_t)v << 6; + os << "\\u{" << ::std::hex << val << "}"; + } + else if( v < 0xF0 ) + { + uint32_t val = (uint32_t)(v & 0x0F) << 12; + v = (uint8_t)*++s; if( (v & 0xC0) != 0x80 ) { s--; continue ; } val |= (uint32_t)v << 12; + v = (uint8_t)*++s; if( (v & 0xC0) != 0x80 ) { s--; continue ; } val |= (uint32_t)v << 6; + os << "\\u{" << ::std::hex << val << "}"; + } + else if( v < 0xF8 ) + { + uint32_t val = (uint32_t)(v & 0x07) << 18; + v = (uint8_t)*++s; if( (v & 0xC0) != 0x80 ) { s--; continue ; } val |= (uint32_t)v << 18; + v = (uint8_t)*++s; if( (v & 0xC0) != 0x80 ) { s--; continue ; } val |= (uint32_t)v << 12; + v = (uint8_t)*++s; if( (v & 0xC0) != 0x80 ) { s--; continue ; } val |= (uint32_t)v << 6; + os << "\\u{" << ::std::hex << val << "}"; + } + break; + } + } + os << ::std::dec; + return os; +} -- cgit v1.2.3 From 5fd6eeedff9834ba03cffdb6a95d5a38b84eee12 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 23 Mar 2019 17:07:23 +0800 Subject: Makefile - Configurable output directory --- Makefile | 66 ++++++++++++++++++++++++++++++++-------------------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/Makefile b/Makefile index 91a9d2de..8da0e1be 100644 --- a/Makefile +++ b/Makefile @@ -48,7 +48,7 @@ CXXFLAGS += -Wno-unknown-warning-option RUST_FLAGS := --cfg debug_assertions RUST_FLAGS += -g RUST_FLAGS += -O -RUST_FLAGS += -L output/ +RUST_FLAGS += -L output$(OUTDIR_SUF)/ RUST_FLAGS += $(RUST_FLAGS_EXTRA) SHELL = bash @@ -143,22 +143,22 @@ $(error Unknown rustc channel) endif RUSTC_SRC_DL := $(RUSTCSRC)/dl-version -MAKE_MINICARGO = $(MAKE) -f minicargo.mk RUSTC_VERSION=$(RUSTC_VERSION) RUSTC_CHANNEL=$(RUSTC_SRC_TY) +MAKE_MINICARGO = $(MAKE) -f minicargo.mk RUSTC_VERSION=$(RUSTC_VERSION) RUSTC_CHANNEL=$(RUSTC_SRC_TY) OUTDIR_SUF=$(OUTDIR_SUF) -output/libstd.hir: $(BIN) +output$(OUTDIR_SUF)/libstd.hir: $(BIN) $(MAKE_MINICARGO) $@ -output/libtest.hir output/libpanic_unwind.hir output/libproc_macro.hir: output/libstd.hir +output$(OUTDIR_SUF)/libtest.hir output$(OUTDIR_SUF)/libpanic_unwind.hir output$(OUTDIR_SUF)/libproc_macro.hir: output$(OUTDIR_SUF)/libstd.hir $(MAKE_MINICARGO) $@ -output/rustc output/cargo: output/libtest.hir +output$(OUTDIR_SUF)/rustc output$(OUTDIR_SUF)/cargo: output$(OUTDIR_SUF)/libtest.hir $(MAKE_MINICARGO) $@ -TEST_DEPS := output/libstd.hir output/libtest.hir output/libpanic_unwind.hir +TEST_DEPS := output$(OUTDIR_SUF)/libstd.hir output$(OUTDIR_SUF)/libtest.hir output$(OUTDIR_SUF)/libpanic_unwind.hir ifeq ($(RUSTC_VERSION),1.19.0) -TEST_DEPS += output/librust_test_helpers.a +TEST_DEPS += output$(OUTDIR_SUF)/librust_test_helpers.a endif -fcn_extcrate = $(patsubst %,output/lib%.hir,$(1)) +fcn_extcrate = $(patsubst %,output$(OUTDIR_SUF)/lib%.hir,$(1)) fn_getdeps = \ $(shell cat $1 \ @@ -208,8 +208,8 @@ endif .PHONY: local_tests local_tests: @$(MAKE) -C tools/testrunner - @mkdir -p output/local_tests - ./tools/bin/testrunner -o output/local_tests samples/test + @mkdir -p output$(OUTDIR_SUF)/local_tests + ./tools/bin/testrunner -o output$(OUTDIR_SUF)/local_tests samples/test # # RUSTC TESTS @@ -224,12 +224,12 @@ rust_tests: RUST_TESTS_run-pass RUST_TESTS: RUST_TESTS_run-pass RUST_TESTS_run-pass: @$(MAKE) -C tools/testrunner - @mkdir -p output/rust_tests/run-pass - ./tools/bin/testrunner -o output/rust_tests/run-pass $(RUST_TESTS_DIR)run-pass --exceptions disabled_tests_run-pass.txt -output/librust_test_helpers.a: output/rust_test_helpers.o + @mkdir -p output$(OUTDIR_SUF)/rust_tests/run-pass + ./tools/bin/testrunner -o output$(OUTDIR_SUF)/rust_tests/run-pass $(RUST_TESTS_DIR)run-pass --exceptions disabled_tests_run-pass.txt +output$(OUTDIR_SUF)/librust_test_helpers.a: output$(OUTDIR_SUF)/rust_test_helpers.o @mkdir -p $(dir $@) ar cur $@ $< -output/rust_test_helpers.o: $(RUSTCSRC)src/rt/rust_test_helpers.c +output$(OUTDIR_SUF)/rust_test_helpers.o: $(RUSTCSRC)src/rt/rust_test_helpers.c @mkdir -p $(dir $@) $(CC) -c $< -o $@ @@ -240,40 +240,40 @@ output/rust_test_helpers.o: $(RUSTCSRC)src/rt/rust_test_helpers.c LIB_TESTS := collections #std #LIB_TESTS += rustc_data_structures -rust_tests-libs: $(patsubst %,output/lib%-test_out.txt, $(LIB_TESTS)) +rust_tests-libs: $(patsubst %,output$(OUTDIR_SUF)/lib%-test_out.txt, $(LIB_TESTS)) -RUNTIME_ARGS_output/libcollections-test := --test-threads 1 -RUNTIME_ARGS_output/libstd-test := --test-threads 1 -RUNTIME_ARGS_output/libstd-test += --skip ::collections::hash::map::test_map::test_index_nonexistent -RUNTIME_ARGS_output/libstd-test += --skip ::collections::hash::map::test_map::test_drops -RUNTIME_ARGS_output/libstd-test += --skip ::collections::hash::map::test_map::test_placement_drop -RUNTIME_ARGS_output/libstd-test += --skip ::collections::hash::map::test_map::test_placement_panic -RUNTIME_ARGS_output/libstd-test += --skip ::io::stdio::tests::panic_doesnt_poison # Unbounded execution +RUNTIME_ARGS_output$(OUTDIR_SUF)/libcollections-test := --test-threads 1 +RUNTIME_ARGS_output$(OUTDIR_SUF)/libstd-test := --test-threads 1 +RUNTIME_ARGS_output$(OUTDIR_SUF)/libstd-test += --skip ::collections::hash::map::test_map::test_index_nonexistent +RUNTIME_ARGS_output$(OUTDIR_SUF)/libstd-test += --skip ::collections::hash::map::test_map::test_drops +RUNTIME_ARGS_output$(OUTDIR_SUF)/libstd-test += --skip ::collections::hash::map::test_map::test_placement_drop +RUNTIME_ARGS_output$(OUTDIR_SUF)/libstd-test += --skip ::collections::hash::map::test_map::test_placement_panic +RUNTIME_ARGS_output$(OUTDIR_SUF)/libstd-test += --skip ::io::stdio::tests::panic_doesnt_poison # Unbounded execution -output/lib%-test: $(RUSTCSRC)src/lib%/lib.rs $(TEST_DEPS) +output$(OUTDIR_SUF)/lib%-test: $(RUSTCSRC)src/lib%/lib.rs $(TEST_DEPS) @echo "--- [MRUSTC] --test -o $@" - @mkdir -p output/ + @mkdir -p output$(OUTDIR_SUF)/ @rm -f $@ $(DBG) $(ENV_$@) $(BIN) --test $< -o $@ $(RUST_FLAGS) $(ARGS_$@) $(PIPECMD) # # HACK: Work around gdb returning success even if the program crashed @test -e $@ -output/lib%-test: $(RUSTCSRC)src/lib%/src/lib.rs $(TEST_DEPS) +output$(OUTDIR_SUF)/lib%-test: $(RUSTCSRC)src/lib%/src/lib.rs $(TEST_DEPS) @echo "--- [MRUSTC] $@" - @mkdir -p output/ + @mkdir -p output$(OUTDIR_SUF)/ @rm -f $@ $(DBG) $(ENV_$@) $(BIN) --test $< -o $@ $(RUST_FLAGS) $(ARGS_$@) $(PIPECMD) # # HACK: Work around gdb returning success even if the program crashed @test -e $@ -output/%_out.txt: output/% +output$(OUTDIR_SUF)/%_out.txt: output$(OUTDIR_SUF)/% @echo "--- [$<]" $V./$< $(RUNTIME_ARGS_$<) > $@ || (tail -n 1 $@; mv $@ $@_fail; false) # "hello, world" test - Invoked by the `make test` target -output/rust/test_run-pass_hello: $(RUST_TESTS_DIR)run-pass/hello.rs $(TEST_DEPS) +output$(OUTDIR_SUF)/rust/test_run-pass_hello: $(RUST_TESTS_DIR)run-pass/hello.rs $(TEST_DEPS) @mkdir -p $(dir $@) @echo "--- [MRUSTC] -o $@" $(DBG) $(BIN) $< -o $@ $(RUST_FLAGS) $(PIPECMD) -output/rust/test_run-pass_hello_out.txt: output/rust/test_run-pass_hello +output$(OUTDIR_SUF)/rust/test_run-pass_hello_out.txt: output$(OUTDIR_SUF)/rust/test_run-pass_hello @echo "--- [$<]" @./$< | tee $@ @@ -283,22 +283,22 @@ output/rust/test_run-pass_hello_out.txt: output/rust/test_run-pass_hello # # TEST: Rust standard library and the "hello, world" run-pass test # -test: output/libstd.hir output/rust/test_run-pass_hello_out.txt $(BIN) +test: output$(OUTDIR_SUF)/libstd.hir output$(OUTDIR_SUF)/rust/test_run-pass_hello_out.txt $(BIN) # # TEST: Attempt to compile rust_os (Tifflin) from ../rust_os # -test_rustos: $(addprefix output/rust_os/,libkernel.hir) +test_rustos: $(addprefix output$(OUTDIR_SUF)/rust_os/,libkernel.hir) RUSTOS_ENV := RUST_VERSION="mrustc 0.1" RUSTOS_ENV += TK_GITSPEC="unknown" RUSTOS_ENV += TK_VERSION="0.1" RUSTOS_ENV += TK_BUILD="mrustc:0" -output/rust_os/libkernel.hir: ../rust_os/Kernel/Core/main.rs output/libcore.hir output/libstack_dst.hir $(BIN) +output$(OUTDIR_SUF)/rust_os/libkernel.hir: ../rust_os/Kernel/Core/main.rs output$(OUTDIR_SUF)/libcore.hir output$(OUTDIR_SUF)/libstack_dst.hir $(BIN) @mkdir -p $(dir $@) export $(RUSTOS_ENV) ; $(DBG) $(BIN) $(RUST_FLAGS) $< -o $@ --cfg arch=amd64 $(PIPECMD) -output/libstack_dst.hir: ../rust_os/externals/crates.io/stack_dst/src/lib.rs $(BIN) +output$(OUTDIR_SUF)/libstack_dst.hir: ../rust_os/externals/crates.io/stack_dst/src/lib.rs $(BIN) @mkdir -p $(dir $@) $(DBG) $(BIN) $(RUST_FLAGS) $< -o $@ --cfg feature=no_std $(PIPECMD) -- cgit v1.2.3 From 866ae6ef036fe26026a0247decb2f8cd67aafcd9 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 24 Mar 2019 10:57:31 +0800 Subject: HIR Macro Export - Hacky workarounds and defensive asserts with macro exports --- src/hir/from_ast.cpp | 6 ++++++ src/hir/serialise.cpp | 1 + src/macro_rules/eval.cpp | 6 +++++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/hir/from_ast.cpp b/src/hir/from_ast.cpp index fb8096f7..014b744c 100644 --- a/src/hir/from_ast.cpp +++ b/src/hir/from_ast.cpp @@ -1834,6 +1834,9 @@ public: auto res = macros.insert( mv$(v) ); DEBUG("- Import " << mac.name << "! (from \"" << res.first->second->m_source_crate << "\")"); } + else if( v.second->m_rules.empty() ) { + // Skip + } else { DEBUG("- Replace " << mac.name << "! (from \"" << it->second->m_source_crate << "\") with one from \"" << v.second->m_source_crate << "\""); it->second = mv$( v.second ); @@ -1853,6 +1856,9 @@ public: auto res = macros.insert( mv$(v) ); DEBUG("- Import " << mac.name << "! (from \"" << res.first->second->m_source_crate << "\")"); } + else if( v.second->m_rules.empty() ) { + // Skip + } else { DEBUG("- Replace " << mac.name << "! (from \"" << it->second->m_source_crate << "\") with one from \"" << v.second->m_source_crate << "\""); it->second = mv$( v.second ); diff --git a/src/hir/serialise.cpp b/src/hir/serialise.cpp index e5fe8ed5..0d01ed25 100644 --- a/src/hir/serialise.cpp +++ b/src/hir/serialise.cpp @@ -400,6 +400,7 @@ void serialise(const ::MacroRules& mac) { //m_exported: IGNORE, should be set + assert(mac.m_rules.size() > 0); serialise_vec(mac.m_rules); m_out.write_string(mac.m_source_crate); } diff --git a/src/macro_rules/eval.cpp b/src/macro_rules/eval.cpp index 03c5609c..9caff7b8 100644 --- a/src/macro_rules/eval.cpp +++ b/src/macro_rules/eval.cpp @@ -352,8 +352,10 @@ void MacroPatternStream::if_succeeded() TU_MATCH_HDRA( (m_simple_ents[m_cur_pos-1]), {) default: BUG(Span(), "Unexpected " << m_simple_ents[m_cur_pos-1]); - TU_ARMA(If, e) + TU_ARMA(If, e) { + ASSERT_BUG(Span(), e.jump_target < m_simple_ents.size(), "Jump target " << e.jump_target << " out of range " << m_simple_ents.size()); m_cur_pos = e.jump_target; + } } m_condition_met = true; } @@ -1724,6 +1726,7 @@ namespace unsigned int Macro_InvokeRules_MatchPattern(const Span& sp, const MacroRules& rules, TokenTree input, AST::Module& mod, ParameterMappings& bound_tts) { TRACE_FUNCTION; + ASSERT_BUG(sp, rules.m_rules.size() > 0, "Empty macro_rules set"); ::std::vector< ::std::pair> > matches; for(size_t i = 0; i < rules.m_rules.size(); i ++) @@ -1812,6 +1815,7 @@ unsigned int Macro_InvokeRules_MatchPattern(const Span& sp, const MacroRules& ru if( matches.size() == 0 ) { // ERROR! + // TODO: Keep track of where each arm failed. TODO(sp, "No arm matched"); } else -- cgit v1.2.3 From fcb473d1cc380b039b5c84cfa0104f8e54e5fc2b Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 24 Mar 2019 10:58:33 +0800 Subject: macro_rules - Fix bad "codegen" for $()+ --- src/macro_rules/parse.cpp | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/src/macro_rules/parse.cpp b/src/macro_rules/parse.cpp index 689a81f1..98163998 100644 --- a/src/macro_rules/parse.cpp +++ b/src/macro_rules/parse.cpp @@ -470,20 +470,27 @@ namespace { size_t start = rv.size(); macro_pattern_to_simple_inner(sp, rv, ent.subpats); push( SimplePatEnt::make_LoopNext({}) ); + size_t rewrite_start = rv.size(); if( ent.tok != TOK_NULL ) { - size_t end = rv.size() + 3; + // If the loop terminator is also valid after the loop + // - Terminate the loop if the next two tokens aren't `` folled by any of `` if( ::std::find(skip_pats.begin(), skip_pats.end(), ExpTok(MacroPatEnt::PAT_TOKEN, &ent.tok)) != skip_pats.end() ) { + size_t expect_and_jump_pos = rv.size() + entry_pats.size() + 1; for(const auto& p : entry_pats) { auto v = ::make_vec2( { MacroPatEnt::PAT_TOKEN, ent.tok}, { p.ty, *p.tok } ); - push_ifv(false, mv$(v), ~0u); + // Jump if equal + push_ifv(true, mv$(v), expect_and_jump_pos); } + // If any of the above succeeded, they'll jump past this jump + push( SimplePatEnt::make_Jump({ ~0u }) ); } else { + size_t end = rv.size() + 3; push_if( false, MacroPatEnt::PAT_TOKEN, ent.tok, end ); } push( SimplePatEnt::make_ExpectTok(ent.tok) ); @@ -497,6 +504,21 @@ namespace { push_if(true, p.ty, *p.tok, start); } } + + size_t post_loop = rv.size(); + for(size_t i = rewrite_start; i < post_loop; i++) + { + if( auto* pe = rv[i].opt_If() ) { + if(pe->jump_target == ~0u) { + pe->jump_target = post_loop; + } + } + if( auto* pe = rv[i].opt_Jump() ) { + if(pe->jump_target == ~0u) { + pe->jump_target = post_loop; + } + } + } push( SimplePatEnt::make_LoopEnd({}) ); } else @@ -589,6 +611,20 @@ namespace { break; } } + + for(size_t i = level_start; i < rv.size(); i ++) + { + TU_MATCH_HDRA( (rv[i]), { ) + default: + // Ignore + TU_ARMA(If, e) { + ASSERT_BUG(sp, e.jump_target < rv.size(), "If target out of bounds, " << e.jump_target << " >= " << rv.size()); + } + TU_ARMA(Jump, e) { + ASSERT_BUG(sp, e.jump_target < rv.size(), "Jump target out of bounds, " << e.jump_target << " >= " << rv.size()); + } + } + } } ::std::vector macro_pattern_to_simple(const Span& sp, const ::std::vector& pattern) -- cgit v1.2.3 From c8bf1f820e9605751b9ff2cc3a4f0083d564c90e Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 30 Mar 2019 10:22:34 +0800 Subject: Typecheck Expr - More little rules/tweaks * Non-overridable ivar disable for ATY results * Disable closure return/argument ivars when closure is coerced --- src/hir_typeck/expr_cs.cpp | 124 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 104 insertions(+), 20 deletions(-) diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 1f43a89c..6d101cbd 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -94,6 +94,7 @@ struct Context struct IVarPossible { + bool force_disable = false; bool force_no_to = false; bool force_no_from = false; // Target types for coercion/unsizing (these types are known to exist in the function) @@ -203,6 +204,7 @@ struct Context equate_types_shadow(sp, l, false); } void equate_types_shadow(const Span& sp, const ::HIR::TypeRef& ty, bool is_to); + void equate_types_shadow_strong(const Span& sp, const ::HIR::TypeRef& ty); /// Possible type that this ivar can coerce to void possible_equate_type_coerce_to(unsigned int ivar_index, const ::HIR::TypeRef& t) { @@ -235,6 +237,7 @@ struct Context void possible_equate_type(unsigned int ivar_index, const ::HIR::TypeRef& t, bool is_to, bool is_borrow); void possible_equate_type_disable(unsigned int ivar_index, bool is_to); + void possible_equate_type_disable_strong(const Span& sp, unsigned int ivar_index); // - Add a pattern binding (forcing the type to match) void handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::TypeRef& type); @@ -4894,6 +4897,46 @@ void Context::equate_types_shadow(const Span& sp, const ::HIR::TypeRef& l, bool ) ) } +void Context::equate_types_shadow_strong(const Span& sp, const ::HIR::TypeRef& ty) +{ + // TODO: Would like to use visit_ty_with in a way that can be told to not recurse (for non-Generic paths) + TU_MATCH_DEF(::HIR::TypeRef::Data, (this->get_type(ty).m_data), (e), + ( + // TODO: Shadow sub-types too + ), + (Path, + TU_MATCH_DEF( ::HIR::Path::Data, (e.path.m_data), (pe), + ( + ), + (Generic, + for(const auto& sty : pe.m_params.m_types) + this->equate_types_shadow_strong(sp, sty); + ) + ) + ), + (Tuple, + for(const auto& sty : e) + this->equate_types_shadow_strong(sp, sty); + ), + (Borrow, + this->equate_types_shadow_strong(sp, *e.inner); + ), + (Array, + this->equate_types_shadow_strong(sp, *e.inner); + ), + (Slice, + this->equate_types_shadow_strong(sp, *e.inner); + ), + (Closure, + for(const auto& aty : e.m_arg_types) + this->equate_types_shadow_strong(sp, aty); + this->equate_types_shadow_strong(sp, *e.m_rettype); + ), + (Infer, + this->possible_equate_type_disable_strong(sp, e.index); + ) + ) +} void Context::equate_types_assoc(const Span& sp, const ::HIR::TypeRef& l, const ::HIR::SimplePath& trait, ::HIR::PathParams pp, const ::HIR::TypeRef& impl_ty, const char *name, bool is_op) { for(const auto& a : this->link_assoc) @@ -5095,6 +5138,21 @@ void Context::possible_equate_type_disable(unsigned int ivar_index, bool is_to) ent.force_no_from = true; } } +void Context::possible_equate_type_disable_strong(const Span& sp, unsigned int ivar_index) +{ + DEBUG(ivar_index << " = ??"); + { + ::HIR::TypeRef ty_l; + ty_l.m_data.as_Infer().index = ivar_index; + ASSERT_BUG(sp, m_ivars.get_type(ty_l).m_data.is_Infer(), "possible_equate_type_disable_strong on known ivar"); + } + + if( ivar_index >= possible_ivar_vals.size() ) { + possible_ivar_vals.resize( ivar_index + 1 ); + } + auto& ent = possible_ivar_vals[ivar_index]; + ent.force_disable = true; +} void Context::add_var(const Span& sp, unsigned int index, const ::std::string& name, ::HIR::TypeRef type) { DEBUG("(" << index << " " << name << " : " << type << ")"); @@ -6102,10 +6160,10 @@ namespace { } else if( src.m_data.is_Closure() ) { + const auto& se = src.m_data.as_Closure(); if( dst.m_data.is_Function() ) { const auto& de = dst.m_data.as_Function(); - const auto& se = src.m_data.as_Closure(); auto& node_ptr = *node_ptr_ptr; auto span = node_ptr->span(); if( de.m_abi != ABI_RUST ) { @@ -6124,6 +6182,11 @@ namespace { } else if( const auto* dep = dst.m_data.opt_Infer() ) { + // Prevent inferrence of argument/return types + for(const auto& at : se.m_arg_types) + context.equate_types_to_shadow(sp, at); + context.equate_types_to_shadow(sp, *se.m_rettype); + // Add as a possiblity context.possible_equate_type_coerce_from(dep->index, src); return CoerceResult::Unknown; } @@ -6231,7 +6294,7 @@ namespace { // - This generates an exact equation. if( v.left_ty != ::HIR::TypeRef() ) { - context.equate_types_from_shadow(sp, v.left_ty); + context.equate_types_shadow_strong(sp, v.left_ty); } // Locate applicable trait impl @@ -6522,13 +6585,16 @@ namespace { if( bound.name != "" ) { auto aty = impl.get_type(bound.name.c_str()); + // The associated type is not present, what does that mean? if( aty == ::HIR::TypeRef() ) { + DEBUG("[check_ivar_poss__fails_bounds] No ATY for " << bound.name << " in impl"); // A possible match was found, so don't delete just yet bound_failed = false; // - Return false to keep searching return false; } else if( aty.compare_with_placeholders(sp, bound.left_ty, context.m_ivars.callback_resolve_infer()) == HIR::Compare::Unequal ) { + DEBUG("[check_ivar_poss__fails_bounds] ATY " << context.m_ivars.fmt_type(aty) << " != left " << context.m_ivars.fmt_type(bound.left_ty)); bound_failed = true; // - Bail instantly return true; @@ -6585,11 +6651,16 @@ namespace { static Span _span; const auto& sp = _span; - if( honour_disable && (ivar_ent.force_no_to || ivar_ent.force_no_from) ) + if( ivar_ent.force_disable ) { DEBUG(i << ": forced unknown"); return false; } + if( honour_disable && (ivar_ent.force_no_to || ivar_ent.force_no_from) ) + { + DEBUG(i << ": coercion blocked"); + return false; + } ::HIR::TypeRef ty_l_ivar; ty_l_ivar.m_data.as_Infer().index = i; @@ -7199,9 +7270,9 @@ namespace { { // TODO: Search know possibilties and check if they satisfy the bounds for this ivar DEBUG("Options: " << ivar_ent.bounded); - unsigned int n_good = 0; unsigned int n_good_ints = 0; - const ::HIR::TypeRef* only_good = nullptr; + ::std::vector good_types; + good_types.reserve(ivar_ent.bounded.size()); for(const auto& new_ty : ivar_ent.bounded) { DEBUG("- Test " << new_ty << " against current rules"); @@ -7210,9 +7281,7 @@ namespace { } else { - n_good ++; - if( !only_good ) - only_good = &new_ty; + good_types.push_back(&new_ty); if( new_ty.m_data.is_Primitive() ) n_good_ints ++; @@ -7220,21 +7289,36 @@ namespace { DEBUG("> " << new_ty << " feasible"); } } + DEBUG(good_types.size() << " valid options (" << n_good_ints << " primitives)"); // Picks the first if in fallback mode (which is signalled by `honour_disable` being false) // - This handles the case where there's multiple valid options (needed for libcompiler_builtins) // TODO: Only pick any if all options are the same class (or just all are integers) - if( (honour_disable ? n_good == 1 : n_good > 0) ) - //if( n_good == 1 || (honour_disable ? false : n_good == n_good_ints) ) + if( good_types.empty() ) + { + + } + else if( good_types.size() == 1 ) { - if( honour_disable ) - DEBUG("Only " << *only_good << " fits current bound sets"); - else - DEBUG("Picking " << *only_good << " as first of " << n_good << " options"); // Since it's the only possibility, choose it? - context.equate_types(sp, ty_l, *only_good); + DEBUG("Only " << *good_types.front() << " fits current bound sets"); + context.equate_types(sp, ty_l, *good_types.front()); return true; } - DEBUG(n_good << " valid options (" << n_good_ints << " primitives)"); + else if( good_types.size() > 0 && !honour_disable ) + { + auto typ_is_borrow = [&](const ::HIR::TypeRef* typ) { return typ->m_data.is_Borrow(); }; + // NOTE: We want to select from sets of primitives and generics (which can be interchangable) + if( ::std::all_of(good_types.begin(), good_types.end(), typ_is_borrow) == ::std::any_of(good_types.begin(), good_types.end(), typ_is_borrow) ) + { + DEBUG("Picking " << *good_types.front() << " as first of " << good_types.size() << " options"); + context.equate_types(sp, ty_l, *good_types.front()); + return true; + } + else + { + // Mix of borrows with non-borrows + } + } } return false; @@ -7407,8 +7491,8 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR: // Check the possible equations DEBUG("--- IVar possibilities"); // TODO: De-duplicate this with the block ~80 lines below - // NOTE: Ordering is a hack for libgit2 - for(unsigned int i = context.possible_ivar_vals.size(); i --; ) + for(unsigned int i = context.possible_ivar_vals.size(); i --; ) // NOTE: Ordering is a hack for libgit2 + //for(unsigned int i = 0; i < context.possible_ivar_vals.size(); i ++ ) { if( check_ivar_poss(context, i, context.possible_ivar_vals[i]) ) { static Span sp; @@ -7517,8 +7601,8 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR: { // Check the possible equations DEBUG("--- IVar possibilities (fallback)"); - // NOTE: Ordering is a hack for libgit2 - for(unsigned int i = context.possible_ivar_vals.size(); i --; ) + for(unsigned int i = context.possible_ivar_vals.size(); i --; ) // NOTE: Ordering is a hack for libgit2 + //for(unsigned int i = 0; i < context.possible_ivar_vals.size(); i ++ ) { if( check_ivar_poss(context, i, context.possible_ivar_vals[i], /*honour_disable=*/false) ) { # if 1 -- cgit v1.2.3 From 294d62e815e6014a7e9d326b652eb1377d8b1fc7 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 31 Mar 2019 16:32:38 +0800 Subject: Typecheck Expr - Fiddling with more custom rules! --- src/hir_typeck/expr_cs.cpp | 307 ++++++++++++++++++++++++++++----------------- 1 file changed, 189 insertions(+), 118 deletions(-) diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 6d101cbd..76661d66 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -2534,8 +2534,9 @@ namespace { const auto& ty_o = this->context.get_type(node.m_value->m_res_type); TRACE_FUNCTION_F("CallValue: ty=" << ty_o); + //this->context.equate_types_from_shadow(node.span(), node.m_res_type); + this->context.equate_types_shadow_strong(node.span(), node.m_res_type); // - Shadow (prevent ivar guessing) every parameter - this->context.equate_types_from_shadow(node.span(), node.m_res_type); for( const auto& arg_ty : node.m_arg_ivars ) { this->context.equate_types_to_shadow(node.span(), arg_ty); } @@ -2974,7 +2975,8 @@ namespace { const auto& field_name = node.m_field; TRACE_FUNCTION_F("(Field) name=" << field_name << ", ty = " << this->context.m_ivars.fmt_type(node.m_value->m_res_type)); - this->context.equate_types_from_shadow(node.span(), node.m_res_type); + //this->context.equate_types_from_shadow(node.span(), node.m_res_type); + this->context.equate_types_shadow_strong(node.span(), node.m_res_type); ::HIR::TypeRef out_type; @@ -6793,11 +6795,146 @@ namespace { } (void)n_ivars; + struct TypeRestrictiveOrdering { + static Ordering get_ordering_infer(const Span& sp, const ::HIR::TypeRef& r) + { + // For infer, only concrete types are more restrictive + TU_MATCH_HDRA( (r.m_data), { ) + default: + return OrdLess; + TU_ARMA(Path, te) { + if( te.binding.is_Opaque() ) + return OrdLess; + if( te.binding.is_Unbound() ) + return OrdEqual; + // TODO: Check if the type is concrete? (Check an unsizing param if present) + return OrdLess; + } + TU_ARMA(Borrow, _) + return OrdEqual; + TU_ARMA(Infer, _) + return OrdEqual; + TU_ARMA(Pointer, _) + return OrdEqual; + } + throw ""; + } + // Ordering of `l` relative to `r`, OrdLess means that the LHS is less restrictive + static Ordering get_ordering_ty(const Span& sp, const Context& context, const ::HIR::TypeRef& l, const ::HIR::TypeRef& r) + { + if( l == r ) { + return OrdEqual; + } + if( l.m_data.is_Infer() ) { + return get_ordering_infer(sp, r); + } + if( r.m_data.is_Infer() ) { + switch( get_ordering_infer(sp, l) ) + { + case OrdLess: return OrdGreater; + case OrdEqual: return OrdEqual; + case OrdGreater:return OrdLess; + } + } + if( l.m_data.is_Path() ) { + // Path types can be unsize targets, and can also act like infers + // - If it's a Unbound treat as Infer + // - If Opaque, then search for a CoerceUnsized/Unsize bound? + // - If Struct, look for ^ tag + // - Else, more/equal specific + TODO(sp, l << " with " << r << " - LHS is Path"); + } + if( r.m_data.is_Path() ) { + // Path types can be unsize targets, and can also act like infers + TODO(sp, l << " with " << r << " - RHS is Path"); + } + + // Slice < Array + if( l.m_data.tag() == r.m_data.tag() ) { + return OrdEqual; + } + else { + if( l.m_data.is_Slice() && r.m_data.is_Array() ) { + return OrdGreater; + } + if( l.m_data.is_Array() && r.m_data.is_Slice() ) { + return OrdLess; + } + TODO(sp, "Compare " << l << " and " << r); + } + } + + // Returns the restrictiveness ordering of `l` relative to `r` + // - &T is more restrictive than *const T + // - &mut T is more restrictive than &T + // Restrictive means that left can't be coerced from right + static Ordering get_ordering_ptr(const Span& sp, const Context& context, const ::HIR::TypeRef& l, const ::HIR::TypeRef& r) + { + Ordering cmp; + TRACE_FUNCTION_FR(l << " , " << r, cmp); + // Get ordering of this type to the current destination + // - If lesser/greater then ignore/update + // - If equal then what? (Instant error? Leave as-is and let the asignment happen? Disable the asignment?) + static const ::HIR::TypeRef::Data::Tag tag_ordering[] = { + ::HIR::TypeRef::Data::TAG_Pointer, + ::HIR::TypeRef::Data::TAG_Borrow, + ::HIR::TypeRef::Data::TAG_Path, // Strictly speaking, Path == Generic + ::HIR::TypeRef::Data::TAG_Generic, + }; + static const ::HIR::TypeRef::Data::Tag* tag_ordering_end = &tag_ordering[ sizeof(tag_ordering) / sizeof(tag_ordering[0] )]; + if( l.m_data.tag() != r.m_data.tag() ) + { + auto p_l = ::std::find(tag_ordering, tag_ordering_end, l.m_data.tag()); + auto p_r = ::std::find(tag_ordering, tag_ordering_end, r.m_data.tag()); + if( p_l == tag_ordering_end ) { + TODO(sp, "Type " << l << " not in ordering list"); + } + if( p_r == tag_ordering_end ) { + TODO(sp, "Type " << r << " not in ordering list"); + } + cmp = ord( static_cast(p_l-p_r), 0 ); + } + else + { + TU_MATCH_HDRA( (l.m_data), { ) + default: + BUG(sp, "Unexpected type class " << l << " in get_ordering_ty"); + break; + TU_ARMA(Generic, _te_l) { + cmp = OrdEqual; + } + TU_ARMA(Path, te_l) { + //const auto& te = dest_type->m_data.as_Path(); + // TODO: Prevent this rule from applying? + return OrdEqual; + } + TU_ARMA(Borrow, te_l) { + const auto& te_r = r.m_data.as_Borrow(); + cmp = ord( (int)te_l.type, (int)te_r.type ); // Unique>Shared in the listing, and Unique is more restrictive than Shared + if( cmp == OrdEqual ) + { + cmp = get_ordering_ty(sp, context, context.m_ivars.get_type(*te_l.inner), context.m_ivars.get_type(*te_r.inner)); + } + } + TU_ARMA(Pointer, te_l) { + const auto& te_r = r.m_data.as_Pointer(); + cmp = ord( (int)te_r.type, (int)te_l.type ); // Note, reversed ordering because we want Unique>Shared + if( cmp == OrdEqual ) + { + cmp = get_ordering_ty(sp, context, context.m_ivars.get_type(*te_l.inner), context.m_ivars.get_type(*te_r.inner)); + } + } + } + } + return cmp; + } + }; + // If there's multiple source types (which means that this ivar has to be a coercion from one of them) // Look for the least permissive of the available destination types and assign to that #if 1 if( ::std::all_of(possible_tys.begin(), possible_tys.end(), [](const auto& ent){ return ent.is_pointer; }) - || ::std::none_of(possible_tys.begin(), possible_tys.end(), [](const auto& ent){ return ent.is_pointer; }) + //|| ::std::none_of(possible_tys.begin(), possible_tys.end(), [](const auto& ent){ return ent.is_pointer; }) ) { // 1. Count distinct (and non-ivar) source types @@ -6828,6 +6965,7 @@ namespace { num_distinct += 1; } } + DEBUG("- " << num_distinct << " distinct possibilities"); // 2. Find the most restrictive destination type // - Borrows are more restrictive than pointers // - Borrows of Sized types are more restrictive than any other @@ -6844,128 +6982,17 @@ namespace { continue ; } - // Get ordering of this type to the current destination - // - If lesser/greater then ignore/update - // - If equal then what? (Instant error? Leave as-is and let the asignment happen? Disable the asignment?) - static const ::HIR::TypeRef::Data::Tag tag_ordering[] = { - ::HIR::TypeRef::Data::TAG_Pointer, - ::HIR::TypeRef::Data::TAG_Borrow, - ::HIR::TypeRef::Data::TAG_Path, // Strictly speaking, Path == Generic - ::HIR::TypeRef::Data::TAG_Generic, - }; - static const ::HIR::TypeRef::Data::Tag* tag_ordering_end = &tag_ordering[ sizeof(tag_ordering) / sizeof(tag_ordering[0] )]; - Ordering cmp; // Ordering of this type relative to the current most restrictve destination (of restrictiveness) - if( dest_type->m_data.tag() != ent.ty->m_data.tag() ) - { - auto p1 = ::std::find(tag_ordering, tag_ordering_end, dest_type->m_data.tag()); - auto p2 = ::std::find(tag_ordering, tag_ordering_end, ent.ty->m_data.tag()); - if( p1 == tag_ordering_end ) { - TODO(sp, "Type " << *dest_type << " not in ordering list"); - } - if( p2 == tag_ordering_end ) { - TODO(sp, "Type " << *dest_type << " not in ordering list"); - } - cmp = ord( static_cast(p2-p1), 0 ); - } - else - { - struct H { - static Ordering get_ordering_infer(const Span& sp, const ::HIR::TypeRef& r) - { - // For infer, only concrete types are more restrictive - TU_MATCH_HDRA( (r.m_data), { ) - default: - return OrdLess; - TU_ARMA(Path, te) { - if( te.binding.is_Opaque() ) - return OrdLess; - if( te.binding.is_Unbound() ) - return OrdEqual; - // TODO: Check if the type is concrete? (Check an unsizing param if present) - return OrdLess; - } - TU_ARMA(Borrow, _) - return OrdEqual; - TU_ARMA(Infer, _) - return OrdEqual; - TU_ARMA(Pointer, _) - return OrdEqual; - } - throw ""; - } - static Ordering get_ordering_ty(const Span& sp, const Context& context, const ::HIR::TypeRef& l, const ::HIR::TypeRef& r) - { - if( l == r ) { - return OrdEqual; - } - if( l.m_data.is_Infer() ) { - return get_ordering_infer(sp, r); - } - if( r.m_data.is_Infer() ) { - switch( H::get_ordering_infer(sp, l) ) - { - case OrdLess: return OrdGreater; - case OrdEqual: return OrdEqual; - case OrdGreater:return OrdLess; - } - } - if( l.m_data.is_Path() ) { - // Path types can be unsize targets, and can also act like infers - // - If it's a Unbound treat as Infer - // - If Opaque, then search for a CoerceUnsized/Unsize bound? - // - If Struct, look for ^ tag - // - Else, more/equal specific - TODO(sp, l << " with " << r << " - LHS is Path"); - } - if( r.m_data.is_Path() ) { - // Path types can be unsize targets, and can also act like infers - TODO(sp, l << " with " << r << " - RHS is Path"); - } - - TODO(sp, "Compare " << l << " and " << r); - } - }; - TU_MATCH_HDRA( (ent.ty->m_data), { ) - default: - BUG(sp, "Unexpected type class " << *ent.ty); - break; - TU_ARMA(Generic, _te2) { - cmp = OrdEqual; - } - TU_ARMA(Path, te2) { - //const auto& te = dest_type->m_data.as_Path(); - // TODO: Prevent this rule from applying? - cmp = OrdEqual; - } - TU_ARMA(Borrow, te2) { - const auto& te = dest_type->m_data.as_Borrow(); - cmp = ord( (int)te2.type, (int)te.type ); // Note, reversed ordering because we want Unique>Shared - if( cmp == OrdEqual ) - { - cmp = H::get_ordering_ty(sp, context, context.m_ivars.get_type(*te.inner), context.m_ivars.get_type(*te2.inner)); - } - } - TU_ARMA(Pointer, te2) { - const auto& te = dest_type->m_data.as_Pointer(); - cmp = ord( (int)te2.type, (int)te.type ); // Note, reversed ordering because we want Unique>Shared - if( cmp == OrdEqual ) - { - cmp = H::get_ordering_ty(sp, context, context.m_ivars.get_type(*te.inner), context.m_ivars.get_type(*te2.inner)); - } - } - } - } - + auto cmp = TypeRestrictiveOrdering::get_ordering_ptr(sp, context, *ent.ty, *dest_type); switch(cmp) { case OrdLess: - // This entry is less restrictive, so don't update `dest_type` + // This entry is less restrictive, so DO update `dest_type` + dest_type = ent.ty; break; case OrdEqual: break; case OrdGreater: - // This entry is mode restrictive, so DO update `dest_type` - dest_type = ent.ty; + // This entry is more restrictive, so don't update `dest_type` break; } } @@ -6979,6 +7006,50 @@ namespace { } #endif + // TODO: If in fallback mode, pick the most permissive option + // - E.g. If the options are &mut T and *const T, use the *const T + if( !honour_disable ) + { + // All are coercions (not unsizings) + if( ::std::all_of(possible_tys.begin(), possible_tys.end(), [](const auto& ent){ return ent.is_pointer; }) && n_ivars == 0 ) + { + // Find the least restrictive destination, and most restrictive source + const ::HIR::TypeRef* dest_type = nullptr; + bool any_ivar_present = false; + for(const auto& ent : possible_tys) + { + if( visit_ty_with(*ent.ty, [](const ::HIR::TypeRef& t){ return t.m_data.is_Infer(); }) ) { + any_ivar_present = true; + } + if( !dest_type ) { + dest_type = ent.ty; + continue ; + } + + auto cmp = TypeRestrictiveOrdering::get_ordering_ptr(sp, context, *ent.ty, *dest_type); + switch(cmp) + { + case OrdLess: + // This entry is less restrictive, so DO update `dest_type` + dest_type = ent.ty; + break; + case OrdEqual: + break; + case OrdGreater: + // This entry is more restrictive, so don't update `dest_type` + break; + } + } + + if( dest_type && n_ivars == 0 && any_ivar_present == false ) + { + DEBUG("Suitable option " << *dest_type << " from " << possible_tys); + context.equate_types(sp, ty_l, *dest_type); + return true; + } + } + } + #if 1 DEBUG("possible_tys = " << possible_tys); DEBUG("Adding bounded [" << ivar_ent.bounded << "]"); -- cgit v1.2.3 From b82f4f8d88fc533b75cb552dad39f49fad164c49 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 14 Apr 2019 17:11:36 +0800 Subject: HIR Typecheck - Ugh --- src/hir_typeck/expr_cs.cpp | 47 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 76661d66..f012386e 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -2742,6 +2742,7 @@ namespace { const auto& ty = this->context.get_type(node.m_value->m_res_type); TRACE_FUNCTION_F("(CallMethod) {" << this->context.m_ivars.fmt_type(ty) << "}." << node.m_method << node.m_params << "(" << FMT_CB(os, for( const auto& arg_node : node.m_args ) os << this->context.m_ivars.fmt_type(arg_node->m_res_type) << ", ";) << ")" + << " -> " << this->context.m_ivars.fmt_type(node.m_res_type) ); // Make sure that no mentioned types are inferred until this method is known @@ -6430,7 +6431,11 @@ namespace { else if( count == 0 ) { // No applicable impl // - TODO: This should really only fire when there isn't an impl. But it currently fires when _ - DEBUG("No impl of " << v.trait << context.m_ivars.fmt(v.params) << " for " << context.m_ivars.fmt_type(v.impl_ty)); + if( v.name == "" ) + DEBUG("No impl of " << v.trait << context.m_ivars.fmt(v.params) << " for " << context.m_ivars.fmt_type(v.impl_ty)); + else + DEBUG("No impl of " << v.trait << context.m_ivars.fmt(v.params) << " for " << context.m_ivars.fmt_type(v.impl_ty) + << " with " << v.name << " = " << context.m_ivars.fmt_type(v.left_ty)); const auto& ty = context.get_type(v.impl_ty); bool is_known = !ty.m_data.is_Infer() && !(ty.m_data.is_Path() && ty.m_data.as_Path().binding.is_Unbound()); @@ -6837,16 +6842,52 @@ namespace { } } if( l.m_data.is_Path() ) { + const auto& te_l = l.m_data.as_Path(); // Path types can be unsize targets, and can also act like infers // - If it's a Unbound treat as Infer // - If Opaque, then search for a CoerceUnsized/Unsize bound? // - If Struct, look for ^ tag // - Else, more/equal specific - TODO(sp, l << " with " << r << " - LHS is Path"); + TU_MATCH_HDRA( (r.m_data), { ) + default: + // An ivar is less restrictive? + if( te_l.binding.is_Unbound() ) + return OrdLess; + TODO(sp, l << " with " << r << " - LHS is Path, RHS is ?"); + TU_ARMA(Path, te_r) { + if( te_l.binding.is_Unbound() && te_r.binding.is_Unbound() ) + { + return OrdEqual; + } + if( te_l.binding.is_Unbound() ) + return OrdLess; + if( te_r.binding.is_Unbound() ) + { + return OrdGreater; + } + else if( te_r.binding.is_Opaque() ) + { + TODO(sp, l << " with " << r << " - LHS is Path, RHS is opaque type"); + } + else if( TU_TEST1(te_r.binding, Struct, ->m_struct_markings.can_unsize) ) + { + TODO(sp, l << " with " << r << " - LHS is Path, RHS is unsize-capable struct"); + } + else + { + return OrdEqual; + } + } + } } if( r.m_data.is_Path() ) { // Path types can be unsize targets, and can also act like infers - TODO(sp, l << " with " << r << " - RHS is Path"); + switch( get_ordering_ty(sp, context, r, l) ) + { + case OrdLess: return OrdGreater; + case OrdEqual: return OrdEqual; + case OrdGreater:return OrdLess; + } } // Slice < Array -- cgit v1.2.3 From 7dca0b4a6ff1158edf1ab17772e96bab488c1b32 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 20 Apr 2019 11:50:34 +0800 Subject: HIR Typecheck - Bulk commit of typecheck fixes, less magic --- src/hir/type.cpp | 14 ++ src/hir/type.hpp | 3 + src/hir_typeck/expr_cs.cpp | 441 +++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 441 insertions(+), 17 deletions(-) diff --git a/src/hir/type.cpp b/src/hir/type.cpp index ff4742e6..ccd5cd21 100644 --- a/src/hir/type.cpp +++ b/src/hir/type.cpp @@ -789,6 +789,20 @@ bool ::HIR::TypeRef::match_test_generics(const Span& sp, const ::HIR::TypeRef& x assert(!"Fell off end of clone_binding"); throw ""; } +bool HIR::TypeRef::TypePathBinding::operator==(const HIR::TypeRef::TypePathBinding& x) const +{ + if( this->tag() != x.tag() ) + return false; + TU_MATCH(::HIR::TypeRef::TypePathBinding, (*this, x), (te, xe), + (Unbound, return true;), + (Opaque, return true;), + (ExternType, return te == xe;), + (Struct, return te == xe;), + (Union , return te == xe;), + (Enum , return te == xe;) + ) + throw ""; +} ::HIR::TypeRef HIR::TypeRef::clone() const diff --git a/src/hir/type.hpp b/src/hir/type.hpp index 0c98773f..2fc1179d 100644 --- a/src/hir/type.hpp +++ b/src/hir/type.hpp @@ -159,6 +159,9 @@ public: (Enum, const ::HIR::Enum*) ), (), (), ( TypePathBinding clone() const; + + bool operator==(const TypePathBinding& x) const; + bool operator!=(const TypePathBinding& x) const { return !(*this == x); } ) ); diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index f012386e..641dddc5 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -3064,7 +3064,7 @@ namespace { void no_revisit(::HIR::ExprNode& node) { BUG(node.span(), "Node revisit unexpected - " << typeid(node).name()); } - }; + }; // class ExprVisitor_Revisit // ----------------------------------------------------------------------- // Post-inferrence visitor @@ -3379,7 +3379,133 @@ namespace { // All good } } - }; + }; // class ExprVisitor_Apply + + class ExprVisitor_Print: + public ::HIR::ExprVisitor + { + const Context& context; + ::std::ostream& m_os; + public: + ExprVisitor_Print(const Context& context, ::std::ostream& os): + context(context), + m_os(os) + {} + + void visit(::HIR::ExprNode_Block& node) override { + m_os << "_Block {" << context.m_ivars.fmt_type(node.m_nodes.back()->m_res_type) << "}"; + } + void visit(::HIR::ExprNode_Asm& node) override { + no_revisit(node); + } + void visit(::HIR::ExprNode_Return& node) override { + no_revisit(node); + } + void visit(::HIR::ExprNode_Let& node) override { + no_revisit(node); + } + void visit(::HIR::ExprNode_Loop& node) override { + no_revisit(node); + } + void visit(::HIR::ExprNode_LoopControl& node) override { + no_revisit(node); + } + void visit(::HIR::ExprNode_Match& node) override { + no_revisit(node); + } + void visit(::HIR::ExprNode_If& node) override { + no_revisit(node); + } + void visit(::HIR::ExprNode_Assign& node) override { + no_revisit(node); + } + void visit(::HIR::ExprNode_BinOp& node) override { + no_revisit(node); + } + void visit(::HIR::ExprNode_UniOp& node) override { + no_revisit(node); + } + void visit(::HIR::ExprNode_Borrow& node) override { + no_revisit(node); + } + void visit(::HIR::ExprNode_Cast& node) override { + m_os << "_Cast {" << context.m_ivars.fmt_type(node.m_value->m_res_type) << "}"; + } + void visit(::HIR::ExprNode_Unsize& node) override { + no_revisit(node); + } + void visit(::HIR::ExprNode_Index& node) override { + m_os << "_Index {" << fmt_res_ty(*node.m_value) << "}[{" << fmt_res_ty(*node.m_index) << "}]"; + } + void visit(::HIR::ExprNode_Deref& node) override { + m_os << "_Deref {" << fmt_res_ty(*node.m_value) << "}"; + } + void visit(::HIR::ExprNode_Emplace& node) override { + m_os << "_Emplace(" << fmt_res_ty(*node.m_value) << " in " << fmt_res_ty(*node.m_place) << ")"; + } + + void visit(::HIR::ExprNode_TupleVariant& node) override { + no_revisit(node); + } + void visit(::HIR::ExprNode_CallPath& node) override { + no_revisit(node); + } + void visit(::HIR::ExprNode_CallValue& node) override { + m_os << "_CallValue {" << fmt_res_ty(*node.m_value) << "}("; + for(const auto& arg : node.m_args) + m_os << "{" << fmt_res_ty(*arg) << "}, "; + m_os << ")"; + } + void visit(::HIR::ExprNode_CallMethod& node) override { + m_os << "_CallMethod {" << fmt_res_ty(*node.m_value) << "}." << node.m_method << "("; + for(const auto& arg : node.m_args) + m_os << "{" << fmt_res_ty(*arg) << "}, "; + m_os << ")"; + } + void visit(::HIR::ExprNode_Field& node) override { + m_os << "_Field {" << fmt_res_ty(*node.m_value) << "}." << node.m_field; + } + + void visit(::HIR::ExprNode_Literal& node) override { + no_revisit(node); + } + void visit(::HIR::ExprNode_UnitVariant& node) override { + no_revisit(node); + } + void visit(::HIR::ExprNode_PathValue& node) override { + no_revisit(node); + } + void visit(::HIR::ExprNode_Variable& node) override { + no_revisit(node); + } + + void visit(::HIR::ExprNode_StructLiteral& node) override { + no_revisit(node); + } + void visit(::HIR::ExprNode_UnionLiteral& node) override { + no_revisit(node); + } + void visit(::HIR::ExprNode_Tuple& node) override { + no_revisit(node); + } + void visit(::HIR::ExprNode_ArrayList& node) override { + no_revisit(node); + } + void visit(::HIR::ExprNode_ArraySized& node) override { + no_revisit(node); + } + + void visit(::HIR::ExprNode_Closure& node) override { + no_revisit(node); + } + private: + HMTypeInferrence::FmtType fmt_res_ty(const ::HIR::ExprNode& n) { + return context.m_ivars.fmt_type(n.m_res_type); + } + void no_revisit(::HIR::ExprNode& n) { + throw ""; + } + }; // class ExprVisitor_Print } @@ -3393,13 +3519,14 @@ void Context::dump() const { m_ivars.dump(); DEBUG("--- CS Context - " << link_coerce.size() << " Coercions, " << link_assoc.size() << " associated, " << to_visit.size() << " nodes, " << adv_revisits.size() << " callbacks"); for(const auto& v : link_coerce) { - DEBUG(v); + //DEBUG(v); + DEBUG(this->m_ivars.fmt_type(v.left_ty) << " := " << v.right_node_ptr << " " << &**v.right_node_ptr << " (" << this->m_ivars.fmt_type((*v.right_node_ptr)->m_res_type) << ")"); } for(const auto& v : link_assoc) { DEBUG(v); } for(const auto& v : to_visit) { - DEBUG(&*v << " " << typeid(*v).name() << " -> " << this->m_ivars.fmt_type(v->m_res_type)); + DEBUG(&*v << " " << FMT_CB(os, { ExprVisitor_Print ev(*this, os); v->visit(ev); }) << " -> " << this->m_ivars.fmt_type(v->m_res_type)); } for(const auto& v : adv_revisits) { DEBUG(FMT_CB(ss, v->fmt(ss);)); @@ -5403,6 +5530,18 @@ namespace { // Neither side is an ivar, keep going. } + // If either side is an unbound path, then return Unknown + if( TU_TEST1(src.m_data, Path, .binding.is_Unbound()) ) + { + DEBUG("Source unbound path"); + return CoerceResult::Unknown; + } + if( TU_TEST1(dst.m_data, Path, .binding.is_Unbound()) ) + { + DEBUG("Destination unbound path"); + return CoerceResult::Unknown; + } + // Array unsize (quicker than going into deref search) if(dst.m_data.is_Slice() && src.m_data.is_Array()) { @@ -6652,18 +6791,34 @@ namespace { return false; } + enum class IvarPossFallbackType { + None, // No fallback, only make safe decisions + Assume, // Picks an option, even if there's non source/destination types + IgnoreWeakDisable, // Ignores the weaker disable flags + }; + ::std::ostream& operator<<(::std::ostream& os, IvarPossFallbackType t) { + switch(t) + { + case IvarPossFallbackType::None: os << ""; break; + case IvarPossFallbackType::Assume: os << " weak"; break; + case IvarPossFallbackType::IgnoreWeakDisable: os << " unblock"; break; + } + return os; + } /// Check IVar possibilities, from both coercion/unsizing (which have well-encoded rules) and from trait impls - bool check_ivar_poss(Context& context, unsigned int i, Context::IVarPossible& ivar_ent, bool honour_disable=true) + bool check_ivar_poss(Context& context, unsigned int i, Context::IVarPossible& ivar_ent, IvarPossFallbackType fallback_ty=IvarPossFallbackType::None) { static Span _span; const auto& sp = _span; + const bool honour_disable = (fallback_ty != IvarPossFallbackType::IgnoreWeakDisable); if( ivar_ent.force_disable ) { DEBUG(i << ": forced unknown"); return false; } - if( honour_disable && (ivar_ent.force_no_to || ivar_ent.force_no_from) ) + // TODO: This shouldn't just return, it should instead add a placeholder possibility + if( fallback_ty != IvarPossFallbackType::IgnoreWeakDisable && (ivar_ent.force_no_to || ivar_ent.force_no_from) ) { DEBUG(i << ": coercion blocked"); return false; @@ -6693,7 +6848,7 @@ namespace { return false; } - TRACE_FUNCTION_F(i << (honour_disable ? "" : " fallback") << " - " << ty_l); + TRACE_FUNCTION_F(i << fallback_ty << " - " << ty_l); bool has_no_coerce_posiblities; @@ -6701,6 +6856,7 @@ namespace { // Fill a single list with all possibilities, and pick the most suitable type. // - This list needs to include flags to say if the type can be dereferenced. { + // TODO: Move this to its own function. struct PossibleType { bool is_pointer; // I.e. it's from a coerce bool can_deref; // I.e. from an unsize or coerce, AND it's a "from" @@ -6750,7 +6906,7 @@ namespace { } // If exactly the same type is both a source and destination, equate. - // NOTE: Not correct, especially when there's ivars in the list which could become a destination + // - This is always correct, even if one of the types is an ivar (you can't go A -> B -> A with a coercion) { for(const auto& ent : possible_tys) { @@ -6758,10 +6914,12 @@ namespace { continue ; for(const auto& ent2 : possible_tys) { - if( &ent2 == &ent ) - break; - if( ent.can_deref ) + if( &ent == &ent2 ) { + continue; + } + if( ent2.can_deref ) { continue ; + } if( *ent.ty == *ent2.ty ) { DEBUG("- Source/Destination type"); context.equate_types(sp, ty_l, *ent.ty); @@ -6974,6 +7132,7 @@ namespace { // If there's multiple source types (which means that this ivar has to be a coercion from one of them) // Look for the least permissive of the available destination types and assign to that #if 1 + // NOTE: This only works for coercions (not usizings), so is restricted to all options being pointers if( ::std::all_of(possible_tys.begin(), possible_tys.end(), [](const auto& ent){ return ent.is_pointer; }) //|| ::std::none_of(possible_tys.begin(), possible_tys.end(), [](const auto& ent){ return ent.is_pointer; }) ) @@ -7045,11 +7204,192 @@ namespace { return true; } } -#endif + #endif + + // TODO: Remove any types that are covered by another type + // - E.g. &[T] and &[U] can be considered equal, because [T] can't unsize again + // - Comparison function: Returns one of Incomparible,Less,Same,More - Representing the amount of type information present. + { + struct InfoOrdering + { + enum Ordering { + Incompatible, // The types are incompatible + Less, // The LHS type provides less information (e.g. has more ivars) + Same, // Same number of ivars + More, // The RHS provides more information (less ivars) + }; + static bool is_infer(const ::HIR::TypeRef& ty) { + if( ty.m_data.is_Infer() ) + return true; + if( TU_TEST1(ty.m_data, Path, .binding.is_Unbound()) ) + return true; + return false; + } + static Ordering compare(const ::HIR::TypeRef& ty_l, const ::HIR::TypeRef& ty_r) { + if( is_infer(ty_l) ) { + if( is_infer(ty_r) ) + return Same; + return Less; + } + else { + if( is_infer(ty_r) ) + return More; + } + if( ty_l.m_data.tag() != ty_r.m_data.tag() ) { + return Incompatible; + } + TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty_l.m_data, ty_r.m_data), (le, re), + ( + return Incompatible; + ), + (Tuple, + if( le.size() != re.size() ) + return Incompatible; + int score = 0; + for(size_t i = 0; i < le.size(); i ++) + { + switch(compare(le[i], re[i])) + { + case Incompatible: + return Incompatible; + case Less: score --; break; + case Same: break; + case More: score ++; break; + } + } + if( score < 0 ) + return Less; + else if( score > 0 ) + return More; + else + return Same; + ) + ) + } + static Ordering compare_top(const Context& context, const ::HIR::TypeRef& ty_l, const ::HIR::TypeRef& ty_r, bool should_deref) { + if( context.m_ivars.types_equal(ty_l, ty_r) ) + return Same; + if( is_infer(ty_l) ) + return Incompatible; + if( is_infer(ty_r) ) + return Incompatible; + if( ty_l.m_data.tag() != ty_r.m_data.tag() ) { + return Incompatible; + } + if( should_deref ) { + if( const auto* le = ty_l.m_data.opt_Borrow() ) { + const auto& re = ty_r.m_data.as_Borrow(); + if( le->type != re.type ) + return Incompatible; + return compare_top(context, context.m_ivars.get_type(*le->inner), context.m_ivars.get_type(*re.inner), false); + } + else if( const auto* le = ty_l.m_data.opt_Pointer() ) { + const auto& re = ty_r.m_data.as_Pointer(); + if( le->type != re.type ) + return Incompatible; + return compare_top(context, context.m_ivars.get_type(*le->inner), context.m_ivars.get_type(*re.inner), false); + } + else if( TU_TEST2(ty_l.m_data, Path, .binding, Struct, ->m_struct_markings.coerce_unsized != ::HIR::StructMarkings::Coerce::None) ) + { + const auto& le = ty_l.m_data.as_Path(); + const auto& re = ty_l.m_data.as_Path(); + if( le.binding != re.binding ) + return Incompatible; + auto param_idx = le.binding.as_Struct()->m_struct_markings.coerce_param; + assert(param_idx != ~0u); + return compare_top(context, + context.m_ivars.get_type(le.path.m_data.as_Generic().m_params.m_types.at(param_idx)), + context.m_ivars.get_type(re.path.m_data.as_Generic().m_params.m_types.at(param_idx)), + false + ); + } + else + { + BUG(Span(), "Can't deref " << ty_l << " / " << ty_r); + } + } + TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty_l.m_data, ty_r.m_data), (le, re), + ( + return Incompatible; + ), + (Slice, + switch(compare(context.m_ivars.get_type(*le.inner), context.m_ivars.get_type(*re.inner))) + { + case Less: return Less; + case More: return More; + case Same: + case Incompatible: + return Same; + } + throw ""; + ) + ) + } + static const ::HIR::TypeRef& get_pointer_inner(const Context& context, const ::HIR::TypeRef& t_raw) { + const auto& t = context.m_ivars.get_type(t_raw); + if( const auto* te = t.m_data.opt_Borrow() ) { + return context.m_ivars.get_type(*te->inner); + } + else if( const auto* te = t.m_data.opt_Pointer() ) { + return context.m_ivars.get_type(*te->inner); + } + else if( TU_TEST2(t.m_data, Path, .binding, Struct, ->m_struct_markings.coerce_unsized != ::HIR::StructMarkings::Coerce::None) ) + { + const auto& te = t.m_data.as_Path(); + auto param_idx = te.binding.as_Struct()->m_struct_markings.coerce_param; + assert(param_idx != ~0u); + const auto& path = te.path.m_data.as_Generic(); + return context.m_ivars.get_type(path.m_params.m_types.at(param_idx)); + } + else { + throw ""; + //return t; + } + } + }; + + // De-duplicate destinations and sources separately + for(auto it = possible_tys.begin(); it != possible_tys.end(); ++it) + { + if( !it->ty ) + continue; + for(auto it2 = it + 1; it2 != possible_tys.end(); ++it2) + { + if( !it2->ty ) + continue; + if(it->can_deref != it2->can_deref) { + continue; + } + if(it->is_pointer != it2->is_pointer) { + continue; + } + + switch(InfoOrdering::compare_top(context, *it->ty, *it2->ty, /*should_deref=*/it->is_pointer)) + { + case InfoOrdering::Incompatible: + break; + case InfoOrdering::Less: + case InfoOrdering::Same: + DEBUG("Remove " << *it << ", keep " << *it2); + it->ty = it2->ty; + it->is_pointer = it2->is_pointer; + it2->ty = nullptr; + break; + case InfoOrdering::More: + DEBUG("Keep " << *it << ", remove " << *it2); + it2->ty = nullptr; + break; + } + } + } + auto new_end = ::std::remove_if(possible_tys.begin(), possible_tys.end(), [](const auto& e){ return e.ty == nullptr; }); + DEBUG("Removing " << (possible_tys.end() - new_end) << " redundant possibilities"); + possible_tys.erase(new_end, possible_tys.end()); + } // TODO: If in fallback mode, pick the most permissive option // - E.g. If the options are &mut T and *const T, use the *const T - if( !honour_disable ) + if( fallback_ty == IvarPossFallbackType::Assume ) { // All are coercions (not unsizings) if( ::std::all_of(possible_tys.begin(), possible_tys.end(), [](const auto& ent){ return ent.is_pointer; }) && n_ivars == 0 ) @@ -7091,9 +7431,9 @@ namespace { } } -#if 1 DEBUG("possible_tys = " << possible_tys); - DEBUG("Adding bounded [" << ivar_ent.bounded << "]"); + DEBUG("- Bounded [" << ivar_ent.bounded << "]"); +#if 1 if( !possible_tys.empty() ) { for(const auto& new_ty : ivar_ent.bounded) @@ -7125,7 +7465,10 @@ namespace { if( !failed_a_bound ) { // TODO: Don't add ivars? - if( new_ty.m_data.is_Infer() ) + if( new_ty == ty_l ) + { + } + else if( new_ty.m_data.is_Infer() ) { n_ivars += 1; } @@ -7322,6 +7665,57 @@ namespace { return true; } + // If there's no ivars, and no instances of &_ or Box<_>, then error/bug here. +#if 0 + if( possible_tys.size() > 0 ) + { + struct H { + static const ::HIR::TypeRef& get_pointer_inner(const Context& context, const ::HIR::TypeRef& t_raw) { + const auto& t = context.m_ivars.get_type(t_raw); + if( const auto* te = t.m_data.opt_Borrow() ) { + return get_pointer_inner(context, *te->inner); + } + else if( const auto* te = t.m_data.opt_Pointer() ) { + return get_pointer_inner(context, *te->inner); + } + else if( TU_TEST2(t.m_data, Path, .binding, Struct, ->m_struct_markings.coerce_unsized != ::HIR::StructMarkings::Coerce::None) ) + { + const auto& te = t.m_data.as_Path(); + auto param_idx = te.binding.as_Struct()->m_struct_markings.coerce_param; + assert(param_idx != ~0u); + const auto& path = te.path.m_data.as_Generic(); + return get_pointer_inner(context, path.m_params.m_types.at(param_idx)); + } + else { + return t; + } + } + }; + bool has_all_info = true; + if( n_ivars > 0 ) + { + has_all_info = false; + } + for(const auto& e : possible_tys) + { + const auto& inner = H::get_pointer_inner(context, *e.ty); + DEBUG(e << ", inner=" << inner); + if( inner.m_data.is_Infer() ) + { + has_all_info = false; + } + if( TU_TEST1(inner.m_data, Path, .binding.is_Unbound()) ) + { + has_all_info = false; + } + } + if( has_all_info ) + { + BUG(sp, "Sufficient information for " << ty_l << " but didn't pick a type - options are [" << possible_tys << "]"); + } + } +#endif + // If only one bound meets the possible set, use it if( ! possible_tys.empty() ) { @@ -7707,6 +8101,19 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR: } } #endif + // If nothing has changed, run check_ivar_poss again but allow it to assume is has all the options + if( !context.m_ivars.peek_changed() ) + { + // Check the possible equations + DEBUG("--- IVar possibilities (fallback 1)"); + for(unsigned int i = context.possible_ivar_vals.size(); i --; ) // NOTE: Ordering is a hack for libgit2 + //for(unsigned int i = 0; i < context.possible_ivar_vals.size(); i ++ ) + { + if( check_ivar_poss(context, i, context.possible_ivar_vals[i], IvarPossFallbackType::Assume) ) { + break; + } + } + } // If nothing has changed, run check_ivar_poss again but ignoring the 'disable' flag #if 1 if( !context.m_ivars.peek_changed() ) @@ -7716,7 +8123,7 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR: for(unsigned int i = context.possible_ivar_vals.size(); i --; ) // NOTE: Ordering is a hack for libgit2 //for(unsigned int i = 0; i < context.possible_ivar_vals.size(); i ++ ) { - if( check_ivar_poss(context, i, context.possible_ivar_vals[i], /*honour_disable=*/false) ) { + if( check_ivar_poss(context, i, context.possible_ivar_vals[i], IvarPossFallbackType::IgnoreWeakDisable) ) { # if 1 break; # else -- cgit v1.2.3 From 8fc434a3fd67e1e72de1f92c1ba3a8df726c170b Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 20 Apr 2019 13:25:46 +0800 Subject: Resolve - Handle glob imports that import enum variants --- src/resolve/index.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/resolve/index.cpp b/src/resolve/index.cpp index ddeffa0c..f010b420 100644 --- a/src/resolve/index.cpp +++ b/src/resolve/index.cpp @@ -296,10 +296,19 @@ void Resolve_Index_Module_Wildcard__glob_in_hir_mod(const Span& sp, const AST::C ASSERT_BUG(sp, crate.m_extern_crates.count(spath.m_crate_name) == 1, "Crate " << spath.m_crate_name << " is not loaded"); const auto* hmod = &crate.m_extern_crates.at(spath.m_crate_name).m_hir->m_root_module; for(unsigned int i = 0; i < spath.m_components.size()-1; i ++) { - const auto& it = hmod->m_mod_items.at( spath.m_components[i] ); - ASSERT_BUG(sp, it->ent.is_Module(), ""); - hmod = &it->ent.as_Module(); + const auto& hit = hmod->m_mod_items.at( spath.m_components[i] ); + // Only support enums on the penultimate component + if( i == spath.m_components.size()-2 && hit->ent.is_Enum() ) { + p.m_bindings.type = ::AST::PathBinding_Type::make_EnumVar({nullptr, 0}); + _add_item_type( sp, dst_mod, it.first, is_pub, mv$(p), false ); + hmod = nullptr; + break ; + } + ASSERT_BUG(sp, hit->ent.is_Module(), "Path component " << spath.m_components[i] << " of " << spath << " is not a module, instead " << hit->ent.tag_str()); + hmod = &hit->ent.as_Module(); } + if( !hmod ) + continue ; vep = &hmod->m_mod_items.at( spath.m_components.back() )->ent; } else { -- cgit v1.2.3 From f96264846fdc79aa220e46b12afcb25f1d12b135 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 20 Apr 2019 18:09:28 +0800 Subject: Typecheck Expressions - Little tweaks --- src/hir_typeck/expr_cs.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 641dddc5..6ad8032b 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -7631,7 +7631,8 @@ namespace { } DEBUG("possible_tys = " << possible_tys); - if( possible_tys.size() == 1 && n_ivars == 0 ) + // If there's only one option (or one real option w/ ivars, if in fallback mode) - equate it + if( possible_tys.size() == 1 && (n_ivars == 0 || !honour_disable) ) { const auto& new_ty = *possible_tys[0].ty; DEBUG("Only " << new_ty << " is an option"); @@ -7810,7 +7811,7 @@ namespace { context.equate_types(sp, ty_l, *good_types.front()); return true; } - else if( good_types.size() > 0 && !honour_disable ) + else if( good_types.size() > 0 && !honour_disable && good_types.size() > n_good_ints ) { auto typ_is_borrow = [&](const ::HIR::TypeRef* typ) { return typ->m_data.is_Borrow(); }; // NOTE: We want to select from sets of primitives and generics (which can be interchangable) -- cgit v1.2.3 From d7543b18d1f5480925d92b590869b8f569d34872 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 21 Apr 2019 09:08:25 +0800 Subject: Typecheck Expressions - Improved trait object coercions --- src/hir_typeck/expr_cs.cpp | 112 +++++++++++++++++---------------------------- 1 file changed, 42 insertions(+), 70 deletions(-) diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 6ad8032b..78bf45f8 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -5512,18 +5512,28 @@ namespace { } else if(const auto* sep = src.m_data.opt_Infer()) { - if(sep->is_lit() && !dst.m_data.is_TraitObject()) + if(sep->is_lit()) { - // Literal to anything other than a trait object must be an equality - DEBUG("Literal with primitive"); - return CoerceResult::Equality; + if( !dst.m_data.is_TraitObject()) + { + // Literal to anything other than a trait object must be an equality + DEBUG("Literal with primitive"); + return CoerceResult::Equality; + } + else + { + // Fall through + } } - if( context_mut ) + else { - context_mut->possible_equate_type_unsize_to(sep->index, dst); + if( context_mut ) + { + context_mut->possible_equate_type_unsize_to(sep->index, dst); + } + DEBUG("Src is ivar (" << src << "), return Unknown"); + return CoerceResult::Unknown; } - DEBUG("Src is ivar (" << src << "), return Unknown"); - return CoerceResult::Unknown; } else { @@ -5727,79 +5737,35 @@ namespace { // Check for trait impl if( trait.m_path != ::HIR::SimplePath() ) { - ImplRef best_impl; - unsigned int count = 0; - bool found = context.m_resolve.find_trait_impls(sp, trait.m_path, trait.m_params, src, [&](auto impl, auto cmp) { - DEBUG("TraitObject coerce from - cmp="<m_trait << " is not implemented for " << src); - } - DEBUG("No impl, but there may eventaully be one"); - return CoerceResult::Unknown; - } - if( !found ) - { - if(count > 1) + for(const auto& tyb : dep->m_trait.m_type_bounds) { - DEBUG("Defer as there are multiple applicable impls"); - return CoerceResult::Unknown; - } - - if( best_impl.has_magic_params() ) { - DEBUG("Defer as there were magic parameters"); - return CoerceResult::Unknown; + context_mut->equate_types_assoc(sp, tyb.second, trait.m_path, trait.m_params.clone(), src, tyb.first.c_str(), false); } - - // TODO: Get a better way of equating these that doesn't require getting copies of the impl's types - if( context_mut ) + if( dep->m_trait.m_type_bounds.empty() ) { - context_mut->equate_types(sp, src, best_impl.get_impl_type()); - auto args = best_impl.get_trait_params(); - assert(trait.m_params.m_types.size() == args.m_types.size()); - for(unsigned int i = 0; i < trait.m_params.m_types.size(); i ++) - { - context_mut->equate_types(sp, trait.m_params.m_types[i], args.m_types[i]); - } - for(const auto& tyb : dep->m_trait.m_type_bounds) - { - auto ty = best_impl.get_type(tyb.first.c_str()); - if( ty != ::HIR::TypeRef() ) - { - context_mut->equate_types(sp, tyb.second, ty); - } - else - { - // Error? Log? ... - DEBUG("Associated type " << tyb.first << " not present in impl, can't equate"); - } - } + context_mut->add_trait_bound(sp, src, trait.m_path, trait.m_params.clone()); } } + else + { + // TODO: Should this check? + } } - for(const auto& marker : dep->m_markers) + if( context_mut ) { - bool found = context.m_resolve.find_trait_impls(sp, marker.m_path, marker.m_params, src, [&](auto impl, auto cmp) { - DEBUG("TraitObject coerce from - cmp="<m_markers) { - // TODO: Get a better idea of when there won't ever be an applicable impl - if( !context.m_ivars.type_contains_ivars(src) ) { - ERROR(sp, E0000, "The trait " << marker << " is not implemented for " << src); - } - return CoerceResult::Unknown; + context_mut->add_trait_bound(sp, src, marker.m_path, marker.m_params.clone()); } } + else + { + // TODO: Should this check? + } // Add _Unsize operator return CoerceResult::Unsize; @@ -6842,6 +6808,12 @@ namespace { return false; } + // Don't attempt to guess literalS + if( ty_l.m_data.as_Infer().is_lit() ) + { + DEBUG(i << ": Literal " << ty_l); + return false; + } if( ! ivar_ent.has_rules() ) { // No rules, don't do anything (and don't print) DEBUG(i << ": No rules"); @@ -7811,7 +7783,7 @@ namespace { context.equate_types(sp, ty_l, *good_types.front()); return true; } - else if( good_types.size() > 0 && !honour_disable && good_types.size() > n_good_ints ) + else if( good_types.size() > 0 && !honour_disable ) { auto typ_is_borrow = [&](const ::HIR::TypeRef* typ) { return typ->m_data.is_Borrow(); }; // NOTE: We want to select from sets of primitives and generics (which can be interchangable) -- cgit v1.2.3 From 4f32d84dd1af27d36156e5523ad30dcfad28a093 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 21 Apr 2019 09:23:44 +0800 Subject: Typecheck Expressions - (debug) Give each rule its own identifier, for easier tracing --- src/hir_typeck/expr_cs.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 78bf45f8..66a99a1c 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -60,16 +60,18 @@ struct Context /// Inferrence variable equalities struct Coercion { + unsigned rule_idx; ::HIR::TypeRef left_ty; ::HIR::ExprNodeP* right_node_ptr; friend ::std::ostream& operator<<(::std::ostream& os, const Coercion& v) { - os << v.left_ty << " := " << v.right_node_ptr << " " << &**v.right_node_ptr << " (" << (*v.right_node_ptr)->m_res_type << ")"; + os << "R" << v.rule_idx << " " << v.left_ty << " := " << v.right_node_ptr << " " << &**v.right_node_ptr << " (" << (*v.right_node_ptr)->m_res_type << ")"; return os; } }; struct Associated { + unsigned rule_idx; Span span; ::HIR::TypeRef left_ty; @@ -83,10 +85,10 @@ struct Context friend ::std::ostream& operator<<(::std::ostream& os, const Associated& v) { if( v.name == "" ) { - os << "req ty " << v.impl_ty << " impl " << v.trait << v.params; + os << "R" << v.rule_idx << " " << "req ty " << v.impl_ty << " impl " << v.trait << v.params; } else { - os << v.left_ty << " = " << "< `" << v.impl_ty << "` as `" << v.trait << v.params << "` >::" << v.name; + os << "R" << v.rule_idx << " " << v.left_ty << " = " << "< `" << v.impl_ty << "` as `" << v.trait << v.params << "` >::" << v.name; } return os; } @@ -136,6 +138,7 @@ struct Context HMTypeInferrence m_ivars; TraitResolution m_resolve; + unsigned next_rule_idx; ::std::vector link_coerce; ::std::vector link_assoc; /// Nodes that need revisiting (e.g. method calls when the receiver isn't known) @@ -3520,7 +3523,7 @@ void Context::dump() const { DEBUG("--- CS Context - " << link_coerce.size() << " Coercions, " << link_assoc.size() << " associated, " << to_visit.size() << " nodes, " << adv_revisits.size() << " callbacks"); for(const auto& v : link_coerce) { //DEBUG(v); - DEBUG(this->m_ivars.fmt_type(v.left_ty) << " := " << v.right_node_ptr << " " << &**v.right_node_ptr << " (" << this->m_ivars.fmt_type((*v.right_node_ptr)->m_res_type) << ")"); + DEBUG("R" << v.rule_idx << " " << this->m_ivars.fmt_type(v.left_ty) << " := " << v.right_node_ptr << " " << &**v.right_node_ptr << " (" << this->m_ivars.fmt_type((*v.right_node_ptr)->m_res_type) << ")"); } for(const auto& v : link_assoc) { DEBUG(v); @@ -4983,9 +4986,10 @@ void Context::equate_types_coerce(const Span& sp, const ::HIR::TypeRef& l, ::HIR this->m_ivars.get_type(l); // - Just record the equality this->link_coerce.push_back(Coercion { + this->next_rule_idx ++, l.clone(), &node_ptr }); - DEBUG("equate_types_coerce(" << this->link_coerce.back() << ")"); + DEBUG("++ " << this->link_coerce.back()); this->m_ivars.mark_change(); } void Context::equate_types_shadow(const Span& sp, const ::HIR::TypeRef& l, bool is_to) @@ -5088,6 +5092,7 @@ void Context::equate_types_assoc(const Span& sp, const ::HIR::TypeRef& l, const return ; } this->link_assoc.push_back(Associated { + this->next_rule_idx ++, sp, l.clone(), @@ -5097,7 +5102,7 @@ void Context::equate_types_assoc(const Span& sp, const ::HIR::TypeRef& l, const name, is_op }); - DEBUG("(" << this->link_assoc.back() << ")"); + DEBUG("++ " << this->link_assoc.back()); this->m_ivars.mark_change(); } void Context::add_revisit(::HIR::ExprNode& node) { -- cgit v1.2.3 From 4a938cd5c9295319d02e51cd6f9a88afb9d6b19e Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 21 Apr 2019 15:33:55 +0800 Subject: MIR Lower - Fix wrong type used for validation return type --- src/mir/from_hir.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index a20c4257..a2d0c790 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -2549,9 +2549,9 @@ namespace { } // NOTE: Can't clean up yet, as consteval isn't done - //MIR_Cleanup(resolve, path, fcn, args, ptr->m_res_type); + //MIR_Cleanup(resolve, path, fcn, args, ret_ty); //DEBUG("MIR Dump:" << ::std::endl << FMT_CB(ss, MIR_Dump_Fcn(ss, fcn, 1);)); - MIR_Validate(resolve, path, fcn, args, ptr->m_res_type); + MIR_Validate(resolve, path, fcn, args, ret_ty); if( getenv("MRUSTC_VALIDATE_FULL_EARLY") ) { MIR_Validate_Full(resolve, path, fcn, args, ptr->m_res_type); -- cgit v1.2.3 From 54d0563ccb4f1129aa65f736773066297b3eac17 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 21 Apr 2019 15:34:39 +0800 Subject: Typecheck Expressions - Least permissive source, diverge possibility, ... --- src/hir_typeck/expr_cs.cpp | 157 ++++++++++++++++++++++++++++++++++++++++++++- src/hir_typeck/helpers.cpp | 4 +- 2 files changed, 156 insertions(+), 5 deletions(-) diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 66a99a1c..9b1b35b5 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -155,8 +155,9 @@ struct Context Context(const ::HIR::Crate& crate, const ::HIR::GenericParams* impl_params, const ::HIR::GenericParams* item_params): m_crate(crate), - m_resolve(m_ivars, crate, impl_params, item_params), - m_lang_Box( crate.get_lang_item_path_opt("owned_box") ) + m_resolve(m_ivars, crate, impl_params, item_params) + ,next_rule_idx( 0 ) + ,m_lang_Box( crate.get_lang_item_path_opt("owned_box") ) { } @@ -6908,6 +6909,22 @@ namespace { } DEBUG("possible_tys = " << possible_tys); + if( ty_l.m_data.as_Infer().ty_class == ::HIR::InferClass::Diverge ) + { + // There's a coercion (not an unsizing) AND there's no sources + // - This ensures that the ! is directly as a value, and not as a generic param or behind a pointer + if( ::std::any_of(possible_tys.begin(), possible_tys.end(), [](const PossibleType& ent){ return ent.is_pointer; }) + && ::std::none_of(possible_tys.begin(), possible_tys.end(), [](const PossibleType& ent){ return ent.can_deref; }) + ) + { + // There are no source possibilities, this has to be a `!` + DEBUG("- Diverge with no source types, force setting to !"); + DEBUG("Set IVar " << i << " = !"); + context.m_ivars.get_type(ty_l_ivar) = ::HIR::TypeRef::new_diverge(); + return true; + } + } + // Filter out ivars // - TODO: Should this also remove &_ types? (maybe not, as they give information about borrow classes) size_t n_ivars; @@ -6915,6 +6932,7 @@ namespace { size_t n_dst_ivars; { auto new_end = ::std::remove_if(possible_tys.begin(), possible_tys.end(), [](const PossibleType& ent) { + // TODO: Should this remove Unbound associated types too? return ent.ty->m_data.is_Infer(); }); n_ivars = possible_tys.end() - new_end; @@ -6935,6 +6953,138 @@ namespace { } (void)n_ivars; + // === If there's no source ivars, find the least permissive source === + // - If this source can't be unsized (e.g. in `&_, &str`, `&str` is the least permissive, and can't be + // coerced without a `*const _` in the list), then equate to that + // 1. Find the most accepting pointer type (if there is at least one coercion source) + // 2. Look for an option that uses that pointer type, and contains an unsized type (that isn't a trait + // object with markers) + // 3. Assign to that known most-permissive option + // Do the oposite for the destination types (least permissive pointer, pick any Sized type) + if( n_src_ivars == 0 || fallback_ty == IvarPossFallbackType::Assume ) + { + static const ::HIR::TypeRef::Data::Tag tag_ordering[] = { + //::HIR::TypeRef::Data::TAG_Generic, + ::HIR::TypeRef::Data::TAG_Path, // Strictly speaking, Path == Generic? + ::HIR::TypeRef::Data::TAG_Borrow, + ::HIR::TypeRef::Data::TAG_Pointer, + }; + struct H { + static Ordering ord_accepting_ptr(const ::HIR::TypeRef& ty_l, const ::HIR::TypeRef& ty_r) + { + // Ordering in increasing acceptiveness: + // - Paths, Borrows, Raw Pointers + if( ty_l.m_data.tag() != ty_r.m_data.tag() ) + { + const auto* tag_ordering_end = tag_ordering+sizeof(tag_ordering)/sizeof(tag_ordering[0]); + auto it_l = ::std::find(tag_ordering, tag_ordering_end, ty_l.m_data.tag()); + auto it_r = ::std::find(tag_ordering, tag_ordering_end, ty_r.m_data.tag()); + if( it_l == tag_ordering_end || it_r == tag_ordering_end ) { + // Huh? + return OrdEqual; + } + if( it_l < it_r ) + return OrdLess; + else if( it_l > it_r ) + return OrdGreater; + else + throw "Impossible"; + } + + switch(ty_l.m_data.tag()) + { + case ::HIR::TypeRef::Data::TAG_Borrow: + // Reverse order - Shared is numerically lower than Unique, but is MORE accepting + return ::ord( static_cast(ty_r.m_data.as_Borrow().type), static_cast(ty_l.m_data.as_Borrow().type) ); + case ::HIR::TypeRef::Data::TAG_Pointer: + // Reverse order - Shared is numerically lower than Unique, but is MORE accepting + return ::ord( static_cast(ty_r.m_data.as_Pointer().type), static_cast(ty_l.m_data.as_Pointer().type) ); + case ::HIR::TypeRef::Data::TAG_Path: + return OrdEqual; + case ::HIR::TypeRef::Data::TAG_Generic: + return OrdEqual; + default: + // Technically a bug/error + return OrdEqual; + } + } + + static const ::HIR::TypeRef* match_and_extract_ptr_ty(const ::HIR::TypeRef& ptr_tpl, const ::HIR::TypeRef& ty) + { + if( ty.m_data.tag() != ptr_tpl.m_data.tag() ) + return nullptr; + TU_MATCH_HDRA( (ty.m_data), { ) + TU_ARMA(Borrow, te) { + if( te.type == ptr_tpl.m_data.as_Borrow().type ) { + return &*te.inner; + } + } + TU_ARMA(Pointer, te) { + if( te.type == ptr_tpl.m_data.as_Pointer().type ) { + return &*te.inner; + } + } + TU_ARMA(Path, te) { + if( te.binding == ptr_tpl.m_data.as_Path().binding ) { + // TODO: Get inner + } + } break; + default: + break; + } + return nullptr; + } + }; + const ::HIR::TypeRef* ptr_ty = nullptr; + if( ::std::any_of(possible_tys.begin(), possible_tys.end(), [&](const auto& ent){ return ent.can_deref && ent.is_pointer; }) ) + { + for(const auto& ent : possible_tys) + { + if( !ent.can_deref ) + continue; + + if( ptr_ty == nullptr ) + { + ptr_ty = ent.ty; + } + else if( H::ord_accepting_ptr(*ent.ty, *ptr_ty) == OrdGreater ) + { + ptr_ty = ent.ty; + } + else + { + } + } + } + + for(const auto& ent : possible_tys) + { + // Sources only + if( ! ent.can_deref ) + continue ; + // Must match `ptr_ty`'s outer pointer + const ::HIR::TypeRef* inner_ty = (ptr_ty ? H::match_and_extract_ptr_ty(*ptr_ty, *ent.ty) : ent.ty); + if( !inner_ty ) + continue; + + bool is_max_accepting = false; + if( inner_ty->m_data.is_Slice() ) { + is_max_accepting = true; + } + else if( TU_TEST1(inner_ty->m_data, Primitive, == ::HIR::CoreType::Str) ) { + is_max_accepting = true; + } + else { + } + if( is_max_accepting ) + { + DEBUG("Most accepting pointer class, and most permissive inner type - " << *ent.ty); + context.equate_types(sp, ty_l, *ent.ty); + return true; + } + } + } + struct TypeRestrictiveOrdering { static Ordering get_ordering_infer(const Span& sp, const ::HIR::TypeRef& r) { @@ -7609,7 +7759,8 @@ namespace { DEBUG("possible_tys = " << possible_tys); // If there's only one option (or one real option w/ ivars, if in fallback mode) - equate it - if( possible_tys.size() == 1 && (n_ivars == 0 || !honour_disable) ) + //if( possible_tys.size() == 1 && (n_ivars == 0 || !honour_disable) ) + if( possible_tys.size() == 1 && n_ivars == 0 ) { const auto& new_ty = *possible_tys[0].ty; DEBUG("Only " << new_ty << " is an option"); diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index cb26f0be..529d2727 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -619,9 +619,9 @@ void HMTypeInferrence::set_ivar_to(unsigned int slot, ::HIR::TypeRef type) } #if 1 - TU_IFLET(::HIR::TypeRef::Data, type.m_data, Diverge, e, + if( type.m_data.is_Diverge() ) { root_ivar.type->m_data.as_Infer().ty_class = ::HIR::InferClass::Diverge; - ) + } else #endif root_ivar.type = box$( mv$(type) ); -- cgit v1.2.3 From 76c596bc8e054a45d0814097b90e426b63bae549 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 21 Apr 2019 16:48:43 +0800 Subject: Helper script - Extracts the last (or a named) function from the debug log --- scripts/log_get_last_function.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 scripts/log_get_last_function.py diff --git a/scripts/log_get_last_function.py b/scripts/log_get_last_function.py new file mode 100644 index 00000000..7a148639 --- /dev/null +++ b/scripts/log_get_last_function.py @@ -0,0 +1,26 @@ +import argparse +import sys + +def main(): + argp = argparse.ArgumentParser() + argp.add_argument("-o", "--output", type=lambda v: open(v, 'w'), default=sys.stdout) + argp.add_argument("logfile", type=open) + argp.add_argument("fcn_name", type=str, nargs='?') + args = argp.parse_args() + + fcn_lines = [] + found_fcn = False + for line in args.logfile: + if 'visit_function: ' in line: + if found_fcn: + break + fcn_lines = [] + if args.fcn_name is not None and args.fcn_name in line: + found_fcn = True + fcn_lines.append(line.strip()) + + for l in fcn_lines: + args.output.write(l) + args.output.write("\n") + +main() -- cgit v1.2.3 From 3bf9a102de5421864863c26626f667ab2429e8bc Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 21 Apr 2019 19:18:20 +0800 Subject: Typecheck Expessions - Improved handling of overlapping bounds, diverging ivars --- src/hir_typeck/expr_cs.cpp | 27 +++++++++++++++++++++------ src/hir_typeck/helpers.cpp | 9 +++++++-- src/hir_typeck/helpers.hpp | 1 + src/hir_typeck/impl_ref.cpp | 31 +++++++++++++++++++++++++++++-- 4 files changed, 58 insertions(+), 10 deletions(-) diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 9b1b35b5..3bc7cfe5 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -84,12 +84,15 @@ struct Context bool is_operator; friend ::std::ostream& operator<<(::std::ostream& os, const Associated& v) { + os << "R" << v.rule_idx << " "; if( v.name == "" ) { - os << "R" << v.rule_idx << " " << "req ty " << v.impl_ty << " impl " << v.trait << v.params; + os << "req ty " << v.impl_ty << " impl " << v.trait << v.params; } else { - os << "R" << v.rule_idx << " " << v.left_ty << " = " << "< `" << v.impl_ty << "` as `" << v.trait << v.params << "` >::" << v.name; + os << v.left_ty << " = " << "< `" << v.impl_ty << "` as `" << v.trait << v.params << "` >::" << v.name; } + if( v.is_operator ) + os << " - op"; return os; } }; @@ -5802,13 +5805,23 @@ namespace { unsigned int count = 0; ::HIR::PathParams pp { dst.clone() }; - bool found = context.m_resolve.find_trait_impls(sp, lang_Unsize, pp, src, [&best_impl,&count](auto impl, auto cmp){ + bool found = context.m_resolve.find_trait_impls(sp, lang_Unsize, pp, src, [&best_impl,&count,&context](auto impl, auto cmp){ DEBUG("[check_unsize_tys] Found impl " << impl << (cmp == ::HIR::Compare::Fuzzy ? " (fuzzy)" : "")); - if( impl.more_specific_than(best_impl) ) + if( !impl.overlaps_with(context.m_crate, best_impl) ) { - best_impl = mv$(impl); + // No overlap, count it as a new possibility + if( count == 0 ) + best_impl = mv$(impl); count ++; } + else if( impl.more_specific_than(best_impl) ) + { + best_impl = mv$(impl); + } + else + { + // Less specific + } // TODO: Record the best impl (if fuzzy) and equate params return cmp != ::HIR::Compare::Fuzzy; }); @@ -5830,6 +5843,7 @@ namespace { { // TODO: Fuzzy? //context.equate_types(sp, *e.inner, *s_e.inner); + DEBUG("Multiple impls"); } } @@ -6814,7 +6828,8 @@ namespace { return false; } - // Don't attempt to guess literalS + // Don't attempt to guess literals + // - What about if they're bounded? if( ty_l.m_data.as_Infer().is_lit() ) { DEBUG(i << ": Literal " << ty_l); diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index 529d2727..053aab4d 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -619,8 +619,12 @@ void HMTypeInferrence::set_ivar_to(unsigned int slot, ::HIR::TypeRef type) } #if 1 - if( type.m_data.is_Diverge() ) { - root_ivar.type->m_data.as_Infer().ty_class = ::HIR::InferClass::Diverge; + if( type.m_data.is_Diverge() ) + { + if( root_ivar.type->m_data.as_Infer().ty_class == ::HIR::InferClass::None ) + { + root_ivar.type->m_data.as_Infer().ty_class = ::HIR::InferClass::Diverge; + } } else #endif @@ -2276,6 +2280,7 @@ bool TraitResolution::find_named_trait_in_trait(const Span& sp, //DEBUG(pt << " => " << pt_mono); if( pt.m_path.m_path == des ) { + //DEBUG("Found potential " << pt_mono); // NOTE: Doesn't quite work... //auto cmp = this->compare_pp(sp, pt_mono.m_path.m_params, des_params); //if( cmp != ::HIR::Compare::Unequal ) diff --git a/src/hir_typeck/helpers.hpp b/src/hir_typeck/helpers.hpp index fcd17cfb..651a36c8 100644 --- a/src/hir_typeck/helpers.hpp +++ b/src/hir_typeck/helpers.hpp @@ -57,6 +57,7 @@ public: public: // ?? - Needed once, anymore? struct IVar { + //bool could_be_diverge; // TODO: use this instead of InferClass::Diverge unsigned int alias; // If not ~0, this points to another ivar ::std::unique_ptr< ::HIR::TypeRef> type; // Type (only nullptr if alias!=0) diff --git a/src/hir_typeck/impl_ref.cpp b/src/hir_typeck/impl_ref.cpp index 86f88648..910a3c5e 100644 --- a/src/hir_typeck/impl_ref.cpp +++ b/src/hir_typeck/impl_ref.cpp @@ -32,10 +32,24 @@ bool ImplRef::more_specific_than(const ImplRef& other) const ) ), (BoundedPtr, - return true; + if( !other.m_data.is_BoundedPtr() ) + return false; + const auto& oe = other.m_data.as_BoundedPtr(); + assert( *te.type == *oe.type ); + assert( *te.trait_args == *oe.trait_args ); + if( te.assoc->size() > oe.assoc->size() ) + return true; + return false; ), (Bounded, - return true; + if( !other.m_data.is_Bounded() ) + return false; + const auto& oe = other.m_data.as_Bounded(); + assert( te.type == oe.type ); + assert( te.trait_args == oe.trait_args ); + if( te.assoc.size() > oe.assoc.size() ) + return true; + return false; ) ) throw ""; @@ -50,8 +64,21 @@ bool ImplRef::overlaps_with(const ::HIR::Crate& crate, const ImplRef& other) con return te.impl->overlaps_with( crate, *oe.impl ); ), (BoundedPtr, + // TODO: Bounded and BoundedPtr are compatible + if( *te.type != *oe.type ) + return false; + if( *te.trait_args != *oe.trait_args ) + return false; + // Don't check associated types + return true; ), (Bounded, + if( te.type != oe.type ) + return false; + if( te.trait_args != oe.trait_args ) + return false; + // Don't check associated types + return true; ) ) return false; -- cgit v1.2.3 From 018a5a14dbf4ea94bdbb1bd17db9f7ef3852c2b0 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Mon, 22 Apr 2019 08:09:31 +0800 Subject: Typecheck Expressions - Minor tweaks from trying to use all trait impls in impl search --- src/hir/hir_ops.cpp | 6 +++++- src/hir_typeck/helpers.cpp | 31 +++++++++++++++++++------------ 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/src/hir/hir_ops.cpp b/src/hir/hir_ops.cpp index a082becd..4b35a0f0 100644 --- a/src/hir/hir_ops.cpp +++ b/src/hir/hir_ops.cpp @@ -271,6 +271,10 @@ namespace { return ::OrdGreater; } + if( left == right ) { + return ::OrdEqual; + } + TU_MATCH(::HIR::TypeRef::Data, (left.m_data), (le), (Generic, throw ""; @@ -335,7 +339,7 @@ namespace { ), (Function, TU_IFLET(::HIR::TypeRef::Data, right.m_data, Function, re, - TODO(sp, "Function"); + TODO(sp, "Function - " << left << " vs " << right); //return typelist_ord_specific(sp, le.arg_types, re.arg_types); ) else { diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index 053aab4d..5db296ea 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -2637,10 +2637,12 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, }; // - If the type is a path (struct/enum/...), search for impls for all contained types. - TU_IFLET( ::HIR::TypeRef::Data, type.m_data, Path, e, + if(const auto* ep = type.m_data.opt_Path()) + { + const auto& e = *ep; ::HIR::Compare res = ::HIR::Compare::Equal; - TU_MATCH( ::HIR::Path::Data, (e.path.m_data), (pe), - (Generic, + TU_MATCH_HDRA( (e.path.m_data), {) + TU_ARMA(Generic, pe) { //( ::HIR::TypeRef tmp; auto monomorph_cb = [&](const auto& gt)->const ::HIR::TypeRef& { const auto& ge = gt.m_data.as_Generic(); @@ -2726,25 +2728,30 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, ) ) DEBUG("- Nothing failed, calling callback"); - ), - (UfcsUnknown, + } + TU_ARMA(UfcsUnknown, pe) { BUG(sp, "UfcsUnknown in typeck - " << type); - ), - (UfcsKnown, + } + TU_ARMA(UfcsKnown, pe) { // If unbound, use Fuzzy { if(e.binding.is_Unbound()) { DEBUG("- Unbound UfcsKnown, returning Fuzzy"); return ::HIR::Compare::Fuzzy; } // Otherwise, it's opaque. Check the bounds on the trait. + if( TU_TEST1(pe.type->m_data, Generic, .binding >> 8 == 2) ) + { + DEBUG("- UfcsKnown of placeholder, returning Fuzzy"); + return ::HIR::Compare::Fuzzy; + } TODO(sp, "Check trait bounds for bound on " << type); - ), - (UfcsInherent, + } + TU_ARMA(UfcsInherent, pe) { TODO(sp, "Auto trait lookup on UFCS Inherent type"); - ) - ) + } + } return res; - ) + } else TU_IFLET( ::HIR::TypeRef::Data, type.m_data, Generic, e, auto l_res = ::HIR::Compare::Unequal; this->find_trait_impls(sp, trait, *params_ptr, type, [&](auto, auto cmp){ l_res = cmp; return (cmp == ::HIR::Compare::Equal); }); -- cgit v1.2.3 From 1c4623b57314f67aabe196e416c2ef72a9743112 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Mon, 22 Apr 2019 14:49:57 +0800 Subject: Typecheck Expressions - More hackery --- src/hir_typeck/expr_cs.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 3bc7cfe5..f402c2d2 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -4033,6 +4033,7 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T // Still pure infer, can't do anything // - What if it's a literal? + // TODO: Don't do fallback if the ivar is marked as being hard blocked if( n_deref == 0 && is_fallback ) { ::HIR::TypeRef possible_type; @@ -6425,6 +6426,12 @@ namespace { context.equate_types_shadow_strong(sp, v.left_ty); } + // HACK? Soft-prevent inferrence of the param types + for(const auto& t : v.params.m_types) + { + context.equate_types_to_shadow(sp, t); + } + // Locate applicable trait impl unsigned int count = 0; DEBUG("Searching for impl " << v.trait << v.params << " for " << context.m_ivars.fmt_type(v.impl_ty)); @@ -6940,6 +6947,14 @@ namespace { } } + // If there's no disable flags set, and there's only one option, pick it. + // - Slight hack to speed up flow-down inference + if( possible_tys.size() == 1 && possible_tys[0].can_deref && !(ivar_ent.force_no_to || ivar_ent.force_no_from) ) { + DEBUG("One possibility (before ivar removal), setting to " << *possible_tys[0].ty); + context.equate_types(sp, ty_l, *possible_tys[0].ty); + return true; + } + // Filter out ivars // - TODO: Should this also remove &_ types? (maybe not, as they give information about borrow classes) size_t n_ivars; -- cgit v1.2.3 From 17ca4b82d5c8af93e95e04a549153656e494cdae Mon Sep 17 00:00:00 2001 From: John Hodge Date: Tue, 23 Apr 2019 14:47:46 +0800 Subject: Typecheck fiddling --- src/hir_typeck/expr_cs.cpp | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index f402c2d2..7f910415 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -2266,6 +2266,7 @@ namespace { { if( dst_inner.m_data.is_Infer() ) { + DEBUG("- Fallback mode, assume inner types are equal"); this->context.equate_types(sp, *e.inner, *s_e.inner); } } @@ -4034,6 +4035,17 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T // - What if it's a literal? // TODO: Don't do fallback if the ivar is marked as being hard blocked + if( const auto* te = ty_p->m_data.opt_Infer() ) + { + if( te->index < context.possible_ivar_vals.size() + && context.possible_ivar_vals[te->index].force_disable + ) + { + MatchErgonomicsRevisit::disable_possibilities_on_bindings(sp, context, pattern); + return false; + } + } + if( n_deref == 0 && is_fallback ) { ::HIR::TypeRef possible_type; @@ -6810,7 +6822,6 @@ namespace { DEBUG(i << ": forced unknown"); return false; } - // TODO: This shouldn't just return, it should instead add a placeholder possibility if( fallback_ty != IvarPossFallbackType::IgnoreWeakDisable && (ivar_ent.force_no_to || ivar_ent.force_no_from) ) { DEBUG(i << ": coercion blocked"); @@ -6874,6 +6885,8 @@ namespace { ::std::ostream& fmt(::std::ostream& os) const { return os << (is_pointer ? "C" : "-") << (can_deref ? "D" : "-") << " " << *ty; } + + bool is_source() const { return this->can_deref; } }; bool allow_unsized = !(i < context.m_ivars_sized.size() ? context.m_ivars_sized.at(i) : false); @@ -6920,7 +6933,7 @@ namespace { if( ent2.can_deref ) { continue ; } - if( *ent.ty == *ent2.ty ) { + if( *ent.ty != ::HIR::TypeRef() && *ent.ty == *ent2.ty ) { DEBUG("- Source/Destination type"); context.equate_types(sp, ty_l, *ent.ty); return true; @@ -6947,13 +6960,25 @@ namespace { } } - // If there's no disable flags set, and there's only one option, pick it. + // If there's no disable flags set, and there's only one source, pick it. // - Slight hack to speed up flow-down inference - if( possible_tys.size() == 1 && possible_tys[0].can_deref && !(ivar_ent.force_no_to || ivar_ent.force_no_from) ) { + if( possible_tys.size() == 1 && possible_tys[0].can_deref && !ivar_ent.force_no_from ) { DEBUG("One possibility (before ivar removal), setting to " << *possible_tys[0].ty); context.equate_types(sp, ty_l, *possible_tys[0].ty); return true; } + //if( possible_tys.size() == 1 && !possible_tys[0].can_deref && !ivar_ent.force_no_to ) { + // DEBUG("One possibility (before ivar removal), setting to " << *possible_tys[0].ty); + // context.equate_types(sp, ty_l, *possible_tys[0].ty); + // return true; + //} + + // TODO: This shouldn't just return, instead the above null placeholders should be tested + if( fallback_ty != IvarPossFallbackType::IgnoreWeakDisable && (ivar_ent.force_no_to || ivar_ent.force_no_from) ) + { + DEBUG(i << ": coercion blocked"); + return false; + } // Filter out ivars // - TODO: Should this also remove &_ types? (maybe not, as they give information about borrow classes) @@ -8238,6 +8263,9 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR: { auto& ent = *context.adv_revisits[i]; ent.revisit(context, /*is_fallback=*/true); + if( context.m_ivars.peek_changed() ) { + break; + } } } -- cgit v1.2.3 From 444f4915d27837ac3d6515f081519f4fe2e07eed Mon Sep 17 00:00:00 2001 From: John Hodge Date: Wed, 24 Apr 2019 12:21:20 +0800 Subject: Typecheck Expressions - Add an unsize target instead of hard equality in match ergonoics --- src/hir/hir_ops.cpp | 8 ++- src/hir_typeck/expr_cs.cpp | 172 ++++++++++++++++++++++++++++----------------- src/hir_typeck/helpers.cpp | 2 + 3 files changed, 113 insertions(+), 69 deletions(-) diff --git a/src/hir/hir_ops.cpp b/src/hir/hir_ops.cpp index 4b35a0f0..b09dbdf7 100644 --- a/src/hir/hir_ops.cpp +++ b/src/hir/hir_ops.cpp @@ -215,9 +215,9 @@ namespace { namespace { bool is_unbounded_infer(const ::HIR::TypeRef& type) { - TU_IFLET( ::HIR::TypeRef::Data, type.m_data, Infer, e, - return e.ty_class == ::HIR::InferClass::None || e.ty_class == ::HIR::InferClass::Diverge; - ) + if( const auto* e = type.m_data.opt_Infer() ) { + return e->ty_class == ::HIR::InferClass::None || e->ty_class == ::HIR::InferClass::Diverge; + } else { return false; } @@ -229,6 +229,8 @@ bool ::HIR::TraitImpl::matches_type(const ::HIR::TypeRef& type, ::HIR::t_cb_reso // NOTE: Don't return any impls when the type is an unbouned ivar. Wouldn't be able to pick anything anyway // TODO: For `Unbound`, it could be valid, if the target is a generic. // - Pure infer could also be useful (for knowing if there's any other potential impls) + + // TODO: Allow unbounded types iff there's some non-unbounded parameters? if( is_unbounded_infer(type) || TU_TEST1(type.m_data, Path, .binding.is_Unbound()) ) { return false; } diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 7f910415..762adf5a 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -2324,6 +2324,9 @@ namespace { do { const auto& ty = this->context.get_type(*current_ty); DEBUG("(Index): (: " << ty << ")[: " << trait_pp.m_types[0] << "]"); + if( ty.m_data.is_Infer() ) { + return ; + } ::HIR::TypeRef possible_index_type; ::HIR::TypeRef possible_res_type; @@ -3951,6 +3954,7 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T ::HIR::PatternBinding::Type m_outer_mode; mutable ::std::vector<::HIR::TypeRef> m_temp_ivars; + mutable ::HIR::TypeRef m_possible_type; MatchErgonomicsRevisit(Span sp, ::HIR::TypeRef outer, ::HIR::Pattern& pat, ::HIR::PatternBinding::Type binding_mode=::HIR::PatternBinding::Type::Move): sp(mv$(sp)), m_outer_ty(mv$(outer)), @@ -3983,6 +3987,78 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T } return true; } + const ::HIR::TypeRef& get_possible_type(Context& context, ::HIR::Pattern& pattern) const + { + if( m_possible_type == ::HIR::TypeRef() ) + { + ::HIR::TypeRef possible_type; + // Get a potential type from the pattern, and set as a possibility. + // - Note, this is only if no derefs were applied + TU_MATCH_HDR( (pattern.m_data), { ) + TU_ARM(pattern.m_data, Any, pe) { + // No type information. + } + TU_ARM(pattern.m_data, Value, pe) { + // TODO: Get type info + } + TU_ARM(pattern.m_data, Range, pe) { + // TODO: Get type info (same as Value) + } + TU_ARM(pattern.m_data, Box, pe) { + // TODO: Get type info (Box<_>) + } + TU_ARM(pattern.m_data, Ref, pe) { + BUG(sp, "Match ergonomics - & pattern"); + } + TU_ARM(pattern.m_data, Tuple, e) { + // Get type info `(T, U, ...)` + if( m_temp_ivars.size() != e.sub_patterns.size() ) { + for(size_t i = 0; i < e.sub_patterns.size(); i ++) + m_temp_ivars.push_back( context.m_ivars.new_ivar_tr() ); + } + decltype(m_temp_ivars) tuple; + for(const auto& ty : m_temp_ivars) + tuple.push_back(ty.clone()); + possible_type = ::HIR::TypeRef( ::std::move(tuple) ); + } + TU_ARM(pattern.m_data, SplitTuple, pe) { + // Can't get type information, tuple size is unkown + } + TU_ARM(pattern.m_data, Slice, e) { + // Can be either a [T] or [T; n]. Can't provide a hint + } + TU_ARM(pattern.m_data, SplitSlice, pe) { + // Can be either a [T] or [T; n]. Can't provide a hint + } + TU_ARM(pattern.m_data, StructValue, e) { + context.add_ivars_params( e.path.m_params ); + possible_type = ::HIR::TypeRef::new_path(e.path.clone(), ::HIR::TypeRef::TypePathBinding(e.binding)); + } + TU_ARM(pattern.m_data, StructTuple, e) { + context.add_ivars_params( e.path.m_params ); + possible_type = ::HIR::TypeRef::new_path(e.path.clone(), ::HIR::TypeRef::TypePathBinding(e.binding)); + } + TU_ARM(pattern.m_data, Struct, e) { + context.add_ivars_params( e.path.m_params ); + possible_type = ::HIR::TypeRef::new_path(e.path.clone(), ::HIR::TypeRef::TypePathBinding(e.binding)); + } + TU_ARM(pattern.m_data, EnumValue, e) { + context.add_ivars_params( e.path.m_params ); + possible_type = ::HIR::TypeRef::new_path(get_parent_path(e.path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)); + } + TU_ARM(pattern.m_data, EnumTuple, e) { + context.add_ivars_params( e.path.m_params ); + possible_type = ::HIR::TypeRef::new_path(get_parent_path(e.path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)); + } + TU_ARM(pattern.m_data, EnumStruct, e) { + context.add_ivars_params( e.path.m_params ); + possible_type = ::HIR::TypeRef::new_path(get_parent_path(e.path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)); + } + } + m_possible_type = ::std::move(possible_type); + } + return m_possible_type; + } bool revisit_inner_real(Context& context, ::HIR::Pattern& pattern, const ::HIR::TypeRef& type, ::HIR::PatternBinding::Type binding_mode, bool is_fallback) const { TRACE_FUNCTION_F(pattern << " : " << type); @@ -4046,76 +4122,30 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T } } - if( n_deref == 0 && is_fallback ) + // If there's no dereferences done, then + if( n_deref == 0 ) { - ::HIR::TypeRef possible_type; - // Get a potential type from the pattern, and set as a possibility. - // - Note, this is only if no derefs were applied - TU_MATCH_HDR( (pattern.m_data), { ) - TU_ARM(pattern.m_data, Any, pe) { - // No type information. - } - TU_ARM(pattern.m_data, Value, pe) { - // TODO: Get type info - } - TU_ARM(pattern.m_data, Range, pe) { - // TODO: Get type info (same as Value) - } - TU_ARM(pattern.m_data, Box, pe) { - // TODO: Get type info (Box<_>) - } - TU_ARM(pattern.m_data, Ref, pe) { - BUG(sp, "Match ergonomics - & pattern"); - } - TU_ARM(pattern.m_data, Tuple, e) { - // Get type info `(T, U, ...)` - if( m_temp_ivars.size() != e.sub_patterns.size() ) { - for(size_t i = 0; i < e.sub_patterns.size(); i ++) - m_temp_ivars.push_back( context.m_ivars.new_ivar_tr() ); - } - decltype(m_temp_ivars) tuple; - for(const auto& ty : m_temp_ivars) - tuple.push_back(ty.clone()); - possible_type = ::HIR::TypeRef( ::std::move(tuple) ); - } - TU_ARM(pattern.m_data, SplitTuple, pe) { - // Can't get type information, tuple size is unkown - } - TU_ARM(pattern.m_data, Slice, e) { - // Can be either a [T] or [T; n]. Can't provide a hint - } - TU_ARM(pattern.m_data, SplitSlice, pe) { - // Can be either a [T] or [T; n]. Can't provide a hint - } - TU_ARM(pattern.m_data, StructValue, e) { - context.add_ivars_params( e.path.m_params ); - possible_type = ::HIR::TypeRef::new_path(e.path.clone(), ::HIR::TypeRef::TypePathBinding(e.binding)); - } - TU_ARM(pattern.m_data, StructTuple, e) { - context.add_ivars_params( e.path.m_params ); - possible_type = ::HIR::TypeRef::new_path(e.path.clone(), ::HIR::TypeRef::TypePathBinding(e.binding)); - } - TU_ARM(pattern.m_data, Struct, e) { - context.add_ivars_params( e.path.m_params ); - possible_type = ::HIR::TypeRef::new_path(e.path.clone(), ::HIR::TypeRef::TypePathBinding(e.binding)); - } - TU_ARM(pattern.m_data, EnumValue, e) { - context.add_ivars_params( e.path.m_params ); - possible_type = ::HIR::TypeRef::new_path(get_parent_path(e.path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)); + const ::HIR::TypeRef& possible_type = get_possible_type(context, pattern); + if( possible_type != ::HIR::TypeRef() ) + { + if( const auto* te = ty_p->m_data.opt_Infer() ) + { + context.possible_equate_type_unsize_to(te->index, possible_type); } - TU_ARM(pattern.m_data, EnumTuple, e) { - context.add_ivars_params( e.path.m_params ); - possible_type = ::HIR::TypeRef::new_path(get_parent_path(e.path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)); + else if( is_fallback ) + { + DEBUG("Fallback equate " << possible_type); + context.equate_types(sp, *ty_p, possible_type); } - TU_ARM(pattern.m_data, EnumStruct, e) { - context.add_ivars_params( e.path.m_params ); - possible_type = ::HIR::TypeRef::new_path(get_parent_path(e.path), ::HIR::TypeRef::TypePathBinding(e.binding_ptr)); + else + { } - } - if( possible_type != ::HIR::TypeRef() ) - { - DEBUG("Possible equate " << possible_type); - context.equate_types( sp, *ty_p, possible_type ); + + //if( is_fallback ) + //{ + // DEBUG("Possible equate " << possible_type); + // context.equate_types( sp, *ty_p, possible_type ); + //} } } @@ -6444,6 +6474,16 @@ namespace { context.equate_types_to_shadow(sp, t); } + // If the impl type is an unbounded ivar, and there's no trait args - don't bother searching + if( const auto* e = context.m_ivars.get_type(v.impl_ty).m_data.opt_Infer() ) + { + // TODO: ? + if( !e->is_lit() && v.params.m_types.empty() ) + { + return false; + } + } + // Locate applicable trait impl unsigned int count = 0; DEBUG("Searching for impl " << v.trait << v.params << " for " << context.m_ivars.fmt_type(v.impl_ty)); diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index 5db296ea..f94cdf26 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -2445,6 +2445,8 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, t_cb_trait_impl_r callback ) const { + // TODO: Have a global cache of impls that don't reference either generics or ivars + static ::std::map< ::std::string, ::HIR::TypeRef> null_assoc; TRACE_FUNCTION_F(trait << FMT_CB(ss, if(params_ptr) { ss << *params_ptr; } else { ss << ""; }) << " for " << type); -- cgit v1.2.3 From 40e8a2d1e5e72afcaae0ca876d17019894c2fd95 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Wed, 24 Apr 2019 13:03:57 +0800 Subject: format_args - Fix named argument support --- src/expand/format_args.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/expand/format_args.cpp b/src/expand/format_args.cpp index 6cc81af6..d79fd9d5 100644 --- a/src/expand/format_args.cpp +++ b/src/expand/format_args.cpp @@ -383,7 +383,7 @@ namespace { if( next_free == n_free ) { ERROR(sp, E0000, "Not enough arguments passed, expected at least " << n_free+1); } - args.prec = next_free + n_named; + args.prec = next_free; next_free ++; } else if( ::std::isdigit(*s) ) { @@ -447,7 +447,7 @@ namespace { if( next_free == n_free ) { ERROR(sp, E0000, "Not enough arguments passed, expected at least " << n_free+1); } - index = next_free + n_named; + index = next_free; next_free ++; } -- cgit v1.2.3 From 7a1a685ef5e0d831f6762f1bc9171de66d933e32 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Thu, 25 Apr 2019 12:38:17 +0800 Subject: HIR - Add more complete privacy handling (allowing for autoderef to skip private fields) --- src/hir/deserialise.cpp | 10 +++-- src/hir/dump.cpp | 4 +- src/hir/expr_ptr.cpp | 6 +++ src/hir/expr_state.hpp | 3 +- src/hir/from_ast.cpp | 78 +++++++++++++++++++++++------------- src/hir/hir.hpp | 64 ++++++++++++++++++++++++++++- src/hir/hir_ops.cpp | 1 + src/hir/serialise.cpp | 6 +-- src/hir_conv/bind.cpp | 28 +++++++++---- src/hir_conv/constant_evaluation.cpp | 3 +- src/hir_expand/closures.cpp | 8 ++-- src/hir_expand/vtable.cpp | 10 ++--- src/hir_typeck/expr_cs.cpp | 7 ++-- src/hir_typeck/expr_visit.cpp | 8 ++-- src/hir_typeck/expr_visit.hpp | 6 ++- src/hir_typeck/helpers.cpp | 10 ++--- src/hir_typeck/helpers.hpp | 4 +- src/resolve/index.cpp | 4 +- src/trans/enumerate.cpp | 4 +- 19 files changed, 189 insertions(+), 75 deletions(-) diff --git a/src/hir/deserialise.cpp b/src/hir/deserialise.cpp index cc376474..9933255f 100644 --- a/src/hir/deserialise.cpp +++ b/src/hir/deserialise.cpp @@ -101,10 +101,14 @@ rv.push_back( cb() ); return rv; } + ::HIR::Publicity deserialise_pub() + { + return (m_in.read_bool() ? ::HIR::Publicity::new_global() : ::HIR::Publicity::new_none()); + } template ::HIR::VisEnt deserialise_visent() { - return ::HIR::VisEnt { m_in.read_bool(), D::des(*this) }; + return ::HIR::VisEnt { deserialise_pub(), D::des(*this) }; } template @@ -153,7 +157,7 @@ { auto name = m_in.read_string(); rv.m_methods.insert( ::std::make_pair( mv$(name), ::HIR::TypeImpl::VisImplEnt< ::HIR::Function> { - m_in.read_bool(), m_in.read_bool(), deserialise_function() + deserialise_pub(), m_in.read_bool(), deserialise_function() } ) ); } size_t const_count = m_in.read_count(); @@ -161,7 +165,7 @@ { auto name = m_in.read_string(); rv.m_constants.insert( ::std::make_pair( mv$(name), ::HIR::TypeImpl::VisImplEnt< ::HIR::Constant> { - m_in.read_bool(), m_in.read_bool(), deserialise_constant() + deserialise_pub(), m_in.read_bool(), deserialise_constant() } ) ); } // m_src_module doesn't matter after typeck diff --git a/src/hir/dump.cpp b/src/hir/dump.cpp index a60ec643..3b981e26 100644 --- a/src/hir/dump.cpp +++ b/src/hir/dump.cpp @@ -152,7 +152,7 @@ namespace { m_os << "("; for(const auto& fld : flds) { - m_os << (fld.is_public ? "pub " : "") << fld.ent << ", "; + m_os << fld.publicity << " " << fld.ent << ", "; } if( item.m_params.m_bounds.empty() ) { @@ -175,7 +175,7 @@ namespace { inc_indent(); for(const auto& fld : flds) { - m_os << indent() << (fld.second.is_public ? "pub " : "") << fld.first << ": " << fld.second.ent << ",\n"; + m_os << indent() << fld.second.publicity << " " << fld.first << ": " << fld.second.ent << ",\n"; } dec_indent(); m_os << indent() << "}\n"; diff --git a/src/hir/expr_ptr.cpp b/src/hir/expr_ptr.cpp index 7b3a6811..0c219e0f 100644 --- a/src/hir/expr_ptr.cpp +++ b/src/hir/expr_ptr.cpp @@ -90,6 +90,12 @@ void HIR::ExprPtr::set_mir(::MIR::FunctionPointer mir) { assert( !this->m_mir ); m_mir = ::std::move(mir); + // Reset the HIR tree to be a placeholder node (thus freeing the backing memory) + //if( node ) + //{ + // auto sp = node->span(); + // node = ExprPtrInner(::std::unique_ptr(new ::HIR::ExprNode_Tuple(sp, {}))); + //} } diff --git a/src/hir/expr_state.hpp b/src/hir/expr_state.hpp index 5491b4d3..11fffe67 100644 --- a/src/hir/expr_state.hpp +++ b/src/hir/expr_state.hpp @@ -10,8 +10,9 @@ namespace HIR { -struct ExprState +class ExprState { +public: ::HIR::SimplePath m_mod_path; const ::HIR::Module& m_module; diff --git a/src/hir/from_ast.cpp b/src/hir/from_ast.cpp index 014b744c..af6bc9cb 100644 --- a/src/hir/from_ast.cpp +++ b/src/hir/from_ast.cpp @@ -868,9 +868,20 @@ const ::AST::Crate* g_ast_crate_ptr; namespace { template - ::HIR::VisEnt new_visent(bool pub, T v) { + ::HIR::VisEnt new_visent(HIR::Publicity pub, T v) { return ::HIR::VisEnt { pub, mv$(v) }; } + + ::HIR::SimplePath get_parent_module(const ::HIR::ItemPath& p) { + const ::HIR::ItemPath* parent_ip = p.parent; + assert(parent_ip); + while(parent_ip->name && parent_ip->name[0] == '#') + { + parent_ip = parent_ip->parent; + assert(parent_ip); + } + return parent_ip->get_simple_path(); + } } ::HIR::Struct LowerHIR_Struct(::HIR::ItemPath path, const ::AST::Struct& ent, const ::AST::AttributeList& attrs) @@ -878,6 +889,9 @@ namespace { TRACE_FUNCTION_F(path); ::HIR::Struct::Data data; + auto priv_path = ::HIR::Publicity::new_priv( get_parent_module(path) ); + auto get_pub = [&](bool is_pub){ return is_pub ? ::HIR::Publicity::new_global() : priv_path; }; + TU_MATCH(::AST::StructData, (ent.m_data), (e), (Unit, data = ::HIR::Struct::Data::make_Unit({}); @@ -886,14 +900,14 @@ namespace { ::HIR::Struct::Data::Data_Tuple fields; for(const auto& field : e.ents) - fields.push_back( { field.m_is_public, LowerHIR_Type(field.m_type) } ); + fields.push_back( { get_pub(field.m_is_public), LowerHIR_Type(field.m_type) } ); data = ::HIR::Struct::Data::make_Tuple( mv$(fields) ); ), (Struct, ::HIR::Struct::Data::Data_Named fields; for(const auto& field : e.ents) - fields.push_back( ::std::make_pair( field.m_name, new_visent(field.m_is_public, LowerHIR_Type(field.m_type)) ) ); + fields.push_back( ::std::make_pair( field.m_name, new_visent( get_pub(field.m_is_public), LowerHIR_Type(field.m_type)) ) ); data = ::HIR::Struct::Data::make_Named( mv$(fields) ); ) ) @@ -956,7 +970,6 @@ namespace { ::HIR::Enum LowerHIR_Enum(::HIR::ItemPath path, const ::AST::Enum& ent, const ::AST::AttributeList& attrs, ::std::function push_struct) { - // 1. Figure out what sort of enum this is (value or data) bool has_value = false; bool has_data = false; @@ -1053,14 +1066,14 @@ namespace { { ::HIR::Struct::Data::Data_Tuple fields; for(const auto& field : ve->m_sub_types) - fields.push_back( new_visent(true, LowerHIR_Type(field)) ); + fields.push_back( new_visent(::HIR::Publicity::new_global(), LowerHIR_Type(field)) ); data = ::HIR::Struct::Data::make_Tuple( mv$(fields) ); } else if( const auto* ve = var.m_data.opt_Struct() ) { ::HIR::Struct::Data::Data_Named fields; for(const auto& field : ve->m_fields) - fields.push_back( ::std::make_pair( field.m_name, new_visent(true, LowerHIR_Type(field.m_type)) ) ); + fields.push_back( ::std::make_pair( field.m_name, new_visent(::HIR::Publicity::new_global(), LowerHIR_Type(field.m_type)) ) ); data = ::HIR::Struct::Data::make_Named( mv$(fields) ); } else @@ -1106,6 +1119,9 @@ namespace { } ::HIR::Union LowerHIR_Union(::HIR::ItemPath path, const ::AST::Union& f, const ::AST::AttributeList& attrs) { + auto priv_path = ::HIR::Publicity::new_priv( get_parent_module(path) ); + auto get_pub = [&](bool is_pub){ return is_pub ? ::HIR::Publicity::new_global() : priv_path; }; + auto repr = ::HIR::Union::Repr::Rust; if( const auto* attr_repr = attrs.get("repr") ) @@ -1124,7 +1140,7 @@ namespace { ::HIR::Struct::Data::Data_Named variants; for(const auto& field : f.m_variants) - variants.push_back( ::std::make_pair( field.m_name, new_visent(field.m_is_public, LowerHIR_Type(field.m_type)) ) ); + variants.push_back( ::std::make_pair( field.m_name, new_visent(get_pub(field.m_is_public), LowerHIR_Type(field.m_type)) ) ); return ::HIR::Union { LowerHIR_GenericParams(f.m_params, nullptr), @@ -1369,10 +1385,10 @@ namespace { }; } -void _add_mod_ns_item(::HIR::Module& mod, ::std::string name, bool is_pub, ::HIR::TypeItem ti) { +void _add_mod_ns_item(::HIR::Module& mod, ::std::string name, ::HIR::Publicity is_pub, ::HIR::TypeItem ti) { mod.m_mod_items.insert( ::std::make_pair( mv$(name), ::make_unique_ptr(::HIR::VisEnt< ::HIR::TypeItem> { is_pub, mv$(ti) }) ) ); } -void _add_mod_val_item(::HIR::Module& mod, ::std::string name, bool is_pub, ::HIR::ValueItem ti) { +void _add_mod_val_item(::HIR::Module& mod, ::std::string name, ::HIR::Publicity is_pub, ::HIR::ValueItem ti) { mod.m_value_items.insert( ::std::make_pair( mv$(name), ::make_unique_ptr(::HIR::VisEnt< ::HIR::ValueItem> { is_pub, mv$(ti) }) ) ); } @@ -1383,6 +1399,9 @@ void _add_mod_val_item(::HIR::Module& mod, ::std::string name, bool is_pub, ::H mod.m_traits = mv$(traits); + auto priv_path = ::HIR::Publicity::new_priv( path.get_simple_path() ); + auto get_pub = [&](bool is_pub)->::HIR::Publicity{ return (is_pub ? ::HIR::Publicity::new_global() : priv_path); }; + // Populate trait list for(const auto& item : ast_mod.m_type_items) { @@ -1402,7 +1421,7 @@ void _add_mod_val_item(::HIR::Module& mod, ::std::string name, bool is_pub, ::H ::std::string name = FMT("#" << i); auto item_path = ::HIR::ItemPath(path, name.c_str()); auto ti = ::HIR::TypeItem::make_Module( LowerHIR_Module(submod, item_path, mod.m_traits) ); - _add_mod_ns_item( mod, mv$(name), false, mv$(ti) ); + _add_mod_ns_item( mod, mv$(name), get_pub(false), mv$(ti) ); } } @@ -1456,12 +1475,12 @@ void _add_mod_val_item(::HIR::Module& mod, ::std::string name, bool is_pub, ::H // Ignore - The index is used to add `Import`s ), (Module, - _add_mod_ns_item( mod, item.name, item.is_pub, LowerHIR_Module(e, mv$(item_path)) ); + _add_mod_ns_item( mod, item.name, get_pub(item.is_pub), LowerHIR_Module(e, mv$(item_path)) ); ), (Crate, // All 'extern crate' items should be normalised into a list in the crate root // - If public, add a namespace import here referring to the root of the imported crate - _add_mod_ns_item( mod, item.name, item.is_pub, ::HIR::TypeItem::make_Import({ ::HIR::SimplePath(e.name, {}), false, 0} ) ); + _add_mod_ns_item( mod, item.name, get_pub(item.is_pub), ::HIR::TypeItem::make_Import({ ::HIR::SimplePath(e.name, {}), false, 0} ) ); ), (Type, if( e.type().m_data.is_Any() ) @@ -1470,39 +1489,39 @@ void _add_mod_val_item(::HIR::Module& mod, ::std::string name, bool is_pub, ::H { ERROR(item.data.span, E0000, "Generics on extern type"); } - _add_mod_ns_item(mod, item.name, item.is_pub, ::HIR::ExternType {}); + _add_mod_ns_item(mod, item.name, get_pub(item.is_pub), ::HIR::ExternType {}); break; } - _add_mod_ns_item( mod, item.name, item.is_pub, ::HIR::TypeItem::make_TypeAlias( LowerHIR_TypeAlias(e) ) ); + _add_mod_ns_item( mod, item.name, get_pub(item.is_pub), ::HIR::TypeItem::make_TypeAlias( LowerHIR_TypeAlias(e) ) ); ), (Struct, /// Add value reference if( e.m_data.is_Unit() ) { - _add_mod_val_item( mod, item.name, item.is_pub, ::HIR::ValueItem::make_StructConstant({item_path.get_simple_path()}) ); + _add_mod_val_item( mod, item.name, get_pub(item.is_pub), ::HIR::ValueItem::make_StructConstant({item_path.get_simple_path()}) ); } else if( e.m_data.is_Tuple() ) { - _add_mod_val_item( mod, item.name, item.is_pub, ::HIR::ValueItem::make_StructConstructor({item_path.get_simple_path()}) ); + _add_mod_val_item( mod, item.name, get_pub(item.is_pub), ::HIR::ValueItem::make_StructConstructor({item_path.get_simple_path()}) ); } else { } - _add_mod_ns_item( mod, item.name, item.is_pub, LowerHIR_Struct(item_path, e, item.data.attrs) ); + _add_mod_ns_item( mod, item.name, get_pub(item.is_pub), LowerHIR_Struct(item_path, e, item.data.attrs) ); ), (Enum, - auto enm = LowerHIR_Enum(item_path, e, item.data.attrs, [&](auto name, auto str){ _add_mod_ns_item(mod, name, item.is_pub, mv$(str)); }); - _add_mod_ns_item( mod, item.name, item.is_pub, mv$(enm) ); + auto enm = LowerHIR_Enum(item_path, e, item.data.attrs, [&](auto name, auto str){ _add_mod_ns_item(mod, name, get_pub(item.is_pub), mv$(str)); }); + _add_mod_ns_item( mod, item.name, get_pub(item.is_pub), mv$(enm) ); ), (Union, - _add_mod_ns_item( mod, item.name, item.is_pub, LowerHIR_Union(item_path, e, item.data.attrs) ); + _add_mod_ns_item( mod, item.name, get_pub(item.is_pub), LowerHIR_Union(item_path, e, item.data.attrs) ); ), (Trait, - _add_mod_ns_item( mod, item.name, item.is_pub, LowerHIR_Trait(item_path.get_simple_path(), e) ); + _add_mod_ns_item( mod, item.name, get_pub(item.is_pub), LowerHIR_Trait(item_path.get_simple_path(), e) ); ), (Function, - _add_mod_val_item(mod, item.name, item.is_pub, LowerHIR_Function(item_path, item.data.attrs, e, ::HIR::TypeRef{})); + _add_mod_val_item(mod, item.name, get_pub(item.is_pub), LowerHIR_Function(item_path, item.data.attrs, e, ::HIR::TypeRef{})); ), (Static, if( e.s_class() == ::AST::Static::CONST ) - _add_mod_val_item(mod, item.name, item.is_pub, ::HIR::ValueItem::make_Constant(::HIR::Constant { + _add_mod_val_item(mod, item.name, get_pub(item.is_pub), ::HIR::ValueItem::make_Constant(::HIR::Constant { ::HIR::GenericParams {}, LowerHIR_Type( e.type() ), LowerHIR_Expr( e.value() ) @@ -1516,7 +1535,7 @@ void _add_mod_val_item(::HIR::Module& mod, ::std::string name, bool is_pub, ::H linkage.name = item.name; } - _add_mod_val_item(mod, item.name, item.is_pub, ::HIR::ValueItem::make_Static(::HIR::Static { + _add_mod_val_item(mod, item.name, get_pub(item.is_pub), ::HIR::ValueItem::make_Static(::HIR::Static { mv$(linkage), (e.s_class() == ::AST::Static::MUT), LowerHIR_Type( e.type() ), @@ -1542,7 +1561,7 @@ void _add_mod_val_item(::HIR::Module& mod, ::std::string name, bool is_pub, ::H DEBUG("Import NS " << ie.first << " = " << hir_path); ti = ::HIR::TypeItem::make_Import({ mv$(hir_path), false, 0 }); } - _add_mod_ns_item(mod, ie.first, ie.second.is_pub, mv$(ti)); + _add_mod_ns_item(mod, ie.first, get_pub(ie.second.is_pub), mv$(ti)); } } for( const auto& ie : ast_mod.m_value_items ) @@ -1561,7 +1580,7 @@ void _add_mod_val_item(::HIR::Module& mod, ::std::string name, bool is_pub, ::H vi = ::HIR::ValueItem::make_Import({ mv$(hir_path), true, pb.idx }); } } - _add_mod_val_item(mod, ie.first, ie.second.is_pub, mv$(vi)); + _add_mod_val_item(mod, ie.first, get_pub(ie.second.is_pub), mv$(vi)); } } @@ -1687,6 +1706,9 @@ void LowerHIR_Module_Impls(const ::AST::Module& ast_mod, ::HIR::Crate& hir_crat auto type = LowerHIR_Type(impl.def().type()); ::HIR::ItemPath path(type); + auto priv_path = ::HIR::Publicity::new_priv( LowerHIR_SimplePath(Span(), ast_mod.path()) ); // TODO: Does this need to consume anon modules? + auto get_pub = [&](bool is_pub){ return is_pub ? ::HIR::Publicity::new_global() : priv_path; }; + ::std::map< ::std::string, ::HIR::TypeImpl::VisImplEnt< ::HIR::Function> > methods; ::std::map< ::std::string, ::HIR::TypeImpl::VisImplEnt< ::HIR::Constant> > constants; @@ -1703,7 +1725,7 @@ void LowerHIR_Module_Impls(const ::AST::Module& ast_mod, ::HIR::Crate& hir_crat ), (Static, if( e.s_class() == ::AST::Static::CONST ) { - constants.insert( ::std::make_pair(item.name, ::HIR::TypeImpl::VisImplEnt< ::HIR::Constant> { item.is_pub, item.is_specialisable, ::HIR::Constant { + constants.insert( ::std::make_pair(item.name, ::HIR::TypeImpl::VisImplEnt< ::HIR::Constant> { get_pub(item.is_pub), item.is_specialisable, ::HIR::Constant { ::HIR::GenericParams {}, LowerHIR_Type( e.type() ), LowerHIR_Expr( e.value() ) @@ -1715,7 +1737,7 @@ void LowerHIR_Module_Impls(const ::AST::Module& ast_mod, ::HIR::Crate& hir_crat ), (Function, methods.insert( ::std::make_pair(item.name, ::HIR::TypeImpl::VisImplEnt< ::HIR::Function> { - item.is_pub, item.is_specialisable, LowerHIR_Function(item_path, item.data->attrs, e, type) + get_pub(item.is_pub), item.is_specialisable, LowerHIR_Function(item_path, item.data->attrs, e, type) } ) ); ) ) diff --git a/src/hir/hir.hpp b/src/hir/hir.hpp index 48787583..f0844580 100644 --- a/src/hir/hir.hpp +++ b/src/hir/hir.hpp @@ -41,10 +41,70 @@ class TypeItem; class ItemPath; +class Publicity +{ + ::std::shared_ptr<::HIR::SimplePath> vis_path; + + Publicity(::std::shared_ptr<::HIR::SimplePath> p) + :vis_path(p) + { + } +public: + + static Publicity new_global() { + return Publicity({}); + } + static Publicity new_none() { + static ::std::shared_ptr<::HIR::SimplePath> none_path = ::std::make_shared(); + return Publicity(none_path); + } + static Publicity new_priv(::HIR::SimplePath p) { + return Publicity(::std::make_shared(::std::move(p))); + } + + bool is_global() const { + return !vis_path; + } + bool is_visible(const ::HIR::SimplePath& p) const { + // No path = global public + if( !vis_path ) + return true; + // Empty simple path = full private + if( *vis_path == ::HIR::SimplePath() ) { + return false; + } + // Crate names must match + if(p.m_crate_name != vis_path->m_crate_name) + return false; + // `p` must be a child of vis_path + if(p.m_components.size() < vis_path->m_components.size()) + return false; + for(size_t i = 0; i < vis_path->m_components.size(); i ++) + { + if(p.m_components[i] != vis_path->m_components[i]) + return false; + } + return true; + } + + friend ::std::ostream& operator<<(::std::ostream& os, const Publicity& x) { + if( !x.vis_path ) { + os << "pub"; + } + else if( *x.vis_path == ::HIR::SimplePath() ) { + os << "priv"; + } + else { + os << "pub(" << *x.vis_path << ")"; + } + return os; + } +}; + template struct VisEnt { - bool is_public; + Publicity publicity; Ent ent; }; @@ -396,7 +456,7 @@ class TypeImpl public: template struct VisImplEnt { - bool is_pub; + Publicity publicity; bool is_specialisable; T data; }; diff --git a/src/hir/hir_ops.cpp b/src/hir/hir_ops.cpp index b09dbdf7..89e48c80 100644 --- a/src/hir/hir_ops.cpp +++ b/src/hir/hir_ops.cpp @@ -1036,6 +1036,7 @@ const ::MIR::Function* HIR::Crate::get_or_gen_mir(const ::HIR::ItemPath& ip, con ms.m_impl_generics = ep.m_state->m_impl_generics; ms.m_item_generics = ep.m_state->m_item_generics; ms.m_traits = ep.m_state->m_traits; + ms.m_mod_paths.push_back(ep.m_state->m_mod_path); Typecheck_Code(ms, const_cast<::HIR::Function::args_t&>(args), ret_ty, ep_mut); //Debug_SetStagePre("Expand HIR Annotate"); HIR_Expand_AnnotateUsage_Expr(*this, ep_mut); diff --git a/src/hir/serialise.cpp b/src/hir/serialise.cpp index 0d01ed25..dd81596f 100644 --- a/src/hir/serialise.cpp +++ b/src/hir/serialise.cpp @@ -60,7 +60,7 @@ template void serialise(const ::HIR::VisEnt& e) { - m_out.write_bool(e.is_public); + m_out.write_bool(e.publicity.is_global()); // At this stage, we only care if the item is visible outside the crate or not serialise(e.ent); } template @@ -322,14 +322,14 @@ m_out.write_count(impl.m_methods.size()); for(const auto& v : impl.m_methods) { m_out.write_string(v.first); - m_out.write_bool(v.second.is_pub); + m_out.write_bool(v.second.publicity.is_global()); m_out.write_bool(v.second.is_specialisable); serialise(v.second.data); } m_out.write_count(impl.m_constants.size()); for(const auto& v : impl.m_constants) { m_out.write_string(v.first); - m_out.write_bool(v.second.is_pub); + m_out.write_bool(v.second.publicity.is_global()); m_out.write_bool(v.second.is_specialisable); serialise(v.second.data); } diff --git a/src/hir_conv/bind.cpp b/src/hir_conv/bind.cpp index c26ae03f..a3b0041b 100644 --- a/src/hir_conv/bind.cpp +++ b/src/hir_conv/bind.cpp @@ -120,7 +120,7 @@ namespace { m_cur_module.ptr = &mod; m_cur_module.path = &p; - m_ms.push_traits(mod); + m_ms.push_traits(p, mod); ::HIR::Visitor::visit_module(p, mod); m_ms.pop_traits(mod); @@ -512,12 +512,16 @@ namespace { void visit_type_impl(::HIR::TypeImpl& impl) override { - TRACE_FUNCTION_F("impl " << impl.m_type); + TRACE_FUNCTION_F("impl " << impl.m_type << " - from " << impl.m_src_module); auto _ = this->m_ms.set_impl_generics(impl.m_params); + auto mod_ip = ::HIR::ItemPath(impl.m_src_module); const auto* mod = (impl.m_src_module != ::HIR::SimplePath() ? &this->m_ms.m_crate.get_mod_by_path(Span(), impl.m_src_module) : nullptr); - if(mod) - m_ms.push_traits(*mod); + if(mod) { + m_ms.push_traits(impl.m_src_module, *mod); + m_cur_module.ptr = mod; + m_cur_module.path = &mod_ip; + } ::HIR::Visitor::visit_type_impl(impl); if(mod) m_ms.pop_traits(*mod); @@ -527,9 +531,13 @@ namespace { TRACE_FUNCTION_F("impl " << trait_path << " for " << impl.m_type); auto _ = this->m_ms.set_impl_generics(impl.m_params); + auto mod_ip = ::HIR::ItemPath(impl.m_src_module); const auto* mod = (impl.m_src_module != ::HIR::SimplePath() ? &this->m_ms.m_crate.get_mod_by_path(Span(), impl.m_src_module) : nullptr); - if(mod) - m_ms.push_traits(*mod); + if(mod) { + m_ms.push_traits(impl.m_src_module, *mod); + m_cur_module.ptr = mod; + m_cur_module.path = &mod_ip; + } m_ms.m_traits.push_back( ::std::make_pair( &trait_path, &this->m_ms.m_crate.get_trait_by_path(Span(), trait_path) ) ); ::HIR::Visitor::visit_trait_impl(trait_path, impl); m_ms.m_traits.pop_back( ); @@ -541,9 +549,13 @@ namespace { TRACE_FUNCTION_F("impl " << trait_path << " for " << impl.m_type << " { }"); auto _ = this->m_ms.set_impl_generics(impl.m_params); + auto mod_ip = ::HIR::ItemPath(impl.m_src_module); const auto* mod = (impl.m_src_module != ::HIR::SimplePath() ? &this->m_ms.m_crate.get_mod_by_path(Span(), impl.m_src_module) : nullptr); - if(mod) - m_ms.push_traits(*mod); + if(mod) { + m_ms.push_traits(impl.m_src_module, *mod); + m_cur_module.ptr = mod; + m_cur_module.path = &mod_ip; + } ::HIR::Visitor::visit_marker_impl(trait_path, impl); if(mod) m_ms.pop_traits(*mod); diff --git a/src/hir_conv/constant_evaluation.cpp b/src/hir_conv/constant_evaluation.cpp index 3d1bf4a5..6049056c 100644 --- a/src/hir_conv/constant_evaluation.cpp +++ b/src/hir_conv/constant_evaluation.cpp @@ -1035,6 +1035,7 @@ namespace { tp.pp_impl = ms.pp_impl->clone(); ep.m_mir = Trans_Monomorphise(resolve, mv$(tp), template_const.m_value.m_mir); ep.m_state = ::HIR::ExprStatePtr( ::HIR::ExprState(*m_mod, m_mod_path->get_simple_path()) ); + DEBUG("TMP TMP " << trait_path << " - " << ep.m_state->m_mod_path); ep.m_state->stage = ::HIR::ExprState::Stage::Mir; impl.m_constants.insert(::std::make_pair( vi.first, @@ -1211,7 +1212,7 @@ namespace { { // ::std::unique_ptr> ::std::unique_ptr<::HIR::VisEnt<::HIR::ValueItem>> iv; - iv.reset( new ::HIR::VisEnt<::HIR::ValueItem> { false, ::HIR::ValueItem::make_Static(mv$(v.second)) } ); + iv.reset( new ::HIR::VisEnt<::HIR::ValueItem> { ::HIR::Publicity::new_none(), ::HIR::ValueItem::make_Static(mv$(v.second)) } ); mod.m_value_items.insert(::std::make_pair( v.first, mv$(iv) )); } mod.m_inline_statics.clear(); diff --git a/src/hir_expand/closures.cpp b/src/hir_expand/closures.cpp index ee0cff08..d7d476e5 100644 --- a/src/hir_expand/closures.cpp +++ b/src/hir_expand/closures.cpp @@ -720,7 +720,7 @@ namespace { // - Fix type to replace closure types with known paths ExprVisitor_Fixup fixup { m_resolve.m_crate, ¶ms, monomorph_cb }; fixup.visit_type(ty_mono); - capture_types.push_back( ::HIR::VisEnt< ::HIR::TypeRef> { false, mv$(ty_mono) } ); + capture_types.push_back( ::HIR::VisEnt< ::HIR::TypeRef> { ::HIR::Publicity::new_none(), mv$(ty_mono) } ); } auto closure_struct_path = m_new_type( ::HIR::Struct { @@ -1182,7 +1182,7 @@ namespace { m_new_type = [&](auto s)->auto { auto name = FMT("closure#I_" << closure_count); closure_count += 1; - auto boxed = box$(( ::HIR::VisEnt< ::HIR::TypeItem> { false, ::HIR::TypeItem( mv$(s) ) } )); + auto boxed = box$(( ::HIR::VisEnt< ::HIR::TypeItem> { ::HIR::Publicity::new_none(), ::HIR::TypeItem( mv$(s) ) } )); crate.m_root_module.m_mod_items.insert( ::std::make_pair(name, mv$(boxed)) ); return ::HIR::SimplePath(crate.m_crate_name, {}) + name; }; @@ -1209,7 +1209,7 @@ namespace { crate.m_type_impls.push_back( ::HIR::TypeImpl { mv$(impl.second.m_params), mv$(impl.second.m_type), - make_map1(impl.second.m_methods.begin()->first, ::HIR::TypeImpl::VisImplEnt< ::HIR::Function> { true, false, mv$(impl.second.m_methods.begin()->second.data) }), + make_map1(impl.second.m_methods.begin()->first, ::HIR::TypeImpl::VisImplEnt< ::HIR::Function> { ::HIR::Publicity::new_global(), false, mv$(impl.second.m_methods.begin()->second.data) }), {}, mv$(impl.second.m_src_module) } ); @@ -1233,7 +1233,7 @@ namespace { m_new_type = [&](auto s)->auto { auto name = FMT("closure#" << closure_count); closure_count += 1; - auto boxed = box$( (::HIR::VisEnt< ::HIR::TypeItem> { false, ::HIR::TypeItem( mv$(s) ) }) ); + auto boxed = box$( (::HIR::VisEnt< ::HIR::TypeItem> { ::HIR::Publicity::new_none(), ::HIR::TypeItem( mv$(s) ) }) ); mod.m_mod_items.insert( ::std::make_pair(name, mv$(boxed)) ); return (p + name).get_simple_path(); }; diff --git a/src/hir_expand/vtable.cpp b/src/hir_expand/vtable.cpp index 79e163ac..2b3dcfb4 100644 --- a/src/hir_expand/vtable.cpp +++ b/src/hir_expand/vtable.cpp @@ -32,7 +32,7 @@ namespace { ::std::vector< decltype(mod.m_mod_items)::value_type> new_types; m_new_type = [&](bool pub, auto name, auto s)->auto { - auto boxed = box$( (::HIR::VisEnt< ::HIR::TypeItem> { pub, ::HIR::TypeItem( mv$(s) ) }) ); + auto boxed = box$( (::HIR::VisEnt< ::HIR::TypeItem> { (pub ? ::HIR::Publicity::new_global() : ::HIR::Publicity::new_none()), ::HIR::TypeItem( mv$(s) ) }) ); auto ret = (p + name).get_simple_path(); new_types.push_back( ::std::make_pair( mv$(name), mv$(boxed)) ); return ret; @@ -173,7 +173,7 @@ namespace { DEBUG("- '" << vi.first << "' is @" << fields.size()); fields.push_back( ::std::make_pair( vi.first, - ::HIR::VisEnt< ::HIR::TypeRef> { true, mv$(fcn_type) } + ::HIR::VisEnt< ::HIR::TypeRef> { ::HIR::Publicity::new_global(), mv$(fcn_type) } ) ); ), (Static, @@ -204,11 +204,11 @@ namespace { ft.m_abi = ABI_RUST; ft.m_rettype.reset( new ::HIR::TypeRef(::HIR::TypeRef::new_unit()) ); ft.m_arg_types.push_back( ::HIR::TypeRef::new_pointer(::HIR::BorrowType::Owned, ::HIR::TypeRef::new_unit()) ); - vtc.fields.push_back(::std::make_pair( "#drop_glue", ::HIR::VisEnt<::HIR::TypeRef> { false, ::HIR::TypeRef(mv$(ft)) } )); + vtc.fields.push_back(::std::make_pair( "#drop_glue", ::HIR::VisEnt<::HIR::TypeRef> { ::HIR::Publicity::new_none(), ::HIR::TypeRef(mv$(ft)) } )); // - Size of data - vtc.fields.push_back(::std::make_pair( "#size", ::HIR::VisEnt<::HIR::TypeRef> { false, ::HIR::CoreType::Usize } )); + vtc.fields.push_back(::std::make_pair( "#size", ::HIR::VisEnt<::HIR::TypeRef> { ::HIR::Publicity::new_none(), ::HIR::CoreType::Usize } )); // - Alignment of data - vtc.fields.push_back(::std::make_pair( "#align", ::HIR::VisEnt<::HIR::TypeRef> { false, ::HIR::CoreType::Usize } )); + vtc.fields.push_back(::std::make_pair( "#align", ::HIR::VisEnt<::HIR::TypeRef> { ::HIR::Publicity::new_none(), ::HIR::CoreType::Usize } )); // - Add methods if( ! vtc.add_ents_from_trait(tr, trait_path) ) { diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 762adf5a..1fd44698 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -156,9 +156,9 @@ struct Context const ::HIR::SimplePath m_lang_Box; - Context(const ::HIR::Crate& crate, const ::HIR::GenericParams* impl_params, const ::HIR::GenericParams* item_params): + Context(const ::HIR::Crate& crate, const ::HIR::GenericParams* impl_params, const ::HIR::GenericParams* item_params, const ::HIR::SimplePath& mod_path): m_crate(crate), - m_resolve(m_ivars, crate, impl_params, item_params) + m_resolve(m_ivars, crate, impl_params, item_params, mod_path) ,next_rule_idx( 0 ) ,m_lang_Box( crate.get_lang_item_path_opt("owned_box") ) { @@ -8062,7 +8062,8 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR: TRACE_FUNCTION; auto root_ptr = expr.into_unique(); - Context context { ms.m_crate, ms.m_impl_generics, ms.m_item_generics }; + assert(!ms.m_mod_paths.empty()); + Context context { ms.m_crate, ms.m_impl_generics, ms.m_item_generics, ms.m_mod_paths.back() }; for( auto& arg : args ) { context.handle_pattern( Span(), arg.first, arg.second ); diff --git a/src/hir_typeck/expr_visit.cpp b/src/hir_typeck/expr_visit.cpp index 1a153aaf..d713c135 100644 --- a/src/hir_typeck/expr_visit.cpp +++ b/src/hir_typeck/expr_visit.cpp @@ -36,7 +36,7 @@ namespace { public: void visit_module(::HIR::ItemPath p, ::HIR::Module& mod) override { - m_ms.push_traits(mod); + m_ms.push_traits(p, mod); ::HIR::Visitor::visit_module(p, mod); m_ms.pop_traits(mod); } @@ -58,7 +58,7 @@ namespace { auto _ = this->m_ms.set_impl_generics(impl.m_params); const auto& mod = this->m_ms.m_crate.get_mod_by_path(Span(), impl.m_src_module); - m_ms.push_traits(mod); + m_ms.push_traits(impl.m_src_module, mod); ::HIR::Visitor::visit_type_impl(impl); m_ms.pop_traits(mod); } @@ -68,7 +68,7 @@ namespace { auto _ = this->m_ms.set_impl_generics(impl.m_params); const auto& mod = this->m_ms.m_crate.get_mod_by_path(Span(), impl.m_src_module); - m_ms.push_traits(mod); + m_ms.push_traits(impl.m_src_module, mod); m_ms.m_traits.push_back( ::std::make_pair( &trait_path, &this->m_ms.m_crate.get_trait_by_path(Span(), trait_path) ) ); ::HIR::Visitor::visit_trait_impl(trait_path, impl); m_ms.m_traits.pop_back( ); @@ -80,7 +80,7 @@ namespace { auto _ = this->m_ms.set_impl_generics(impl.m_params); const auto& mod = this->m_ms.m_crate.get_mod_by_path(Span(), impl.m_src_module); - m_ms.push_traits(mod); + m_ms.push_traits(impl.m_src_module, mod); ::HIR::Visitor::visit_marker_impl(trait_path, impl); m_ms.pop_traits(mod); } diff --git a/src/hir_typeck/expr_visit.hpp b/src/hir_typeck/expr_visit.hpp index 21a775dc..9388b1dd 100644 --- a/src/hir_typeck/expr_visit.hpp +++ b/src/hir_typeck/expr_visit.hpp @@ -5,6 +5,7 @@ * hir_typeck/expr_visit.hpp * - Helpers for the HIR typecheck expression visiting */ +#include namespace typeck { struct ModuleState @@ -15,6 +16,7 @@ namespace typeck { ::HIR::GenericParams* m_item_generics; ::std::vector< ::std::pair< const ::HIR::SimplePath*, const ::HIR::Trait* > > m_traits; + ::std::vector m_mod_paths; ModuleState(const ::HIR::Crate& crate): m_crate(crate), @@ -44,8 +46,9 @@ namespace typeck { return NullOnDrop< ::HIR::GenericParams>(m_item_generics); } - void push_traits(const ::HIR::Module& mod) { + void push_traits(::HIR::ItemPath p, const ::HIR::Module& mod) { auto sp = Span(); + m_mod_paths.push_back( p.get_simple_path() ); DEBUG("Module has " << mod.m_traits.size() << " in-scope traits"); // - Push a NULL entry to prevent parent module import lists being searched m_traits.push_back( ::std::make_pair(nullptr, nullptr) ); @@ -59,6 +62,7 @@ namespace typeck { for(unsigned int i = 0; i < mod.m_traits.size(); i ++ ) m_traits.pop_back(); m_traits.pop_back(); + m_mod_paths.pop_back(); } }; } diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index f94cdf26..0ebb9c07 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -4334,8 +4334,8 @@ bool TraitResolution::find_field(const Span& sp, const ::HIR::TypeRef& ty, const (Tuple, for( unsigned int i = 0; i < se.size(); i ++ ) { - // TODO: Privacy - if( FMT(i) == name ) { + DEBUG(i << ": " << se[i].publicity); + if( se[i].publicity.is_visible(this->m_vis_path) && FMT(i) == name ) { field_ty = monomorphise_type_with(sp, se[i].ent, monomorph); return true; } @@ -4344,8 +4344,8 @@ bool TraitResolution::find_field(const Span& sp, const ::HIR::TypeRef& ty, const (Named, for( const auto& fld : se ) { - // TODO: Privacy - if( fld.first == name ) { + DEBUG(fld.first << ": " << fld.second.publicity << ", " << this->m_vis_path); + if( fld.second.publicity.is_visible(this->m_vis_path) && fld.first == name ) { field_ty = monomorphise_type_with(sp, fld.second.ent, monomorph); return true; } @@ -4379,7 +4379,7 @@ bool TraitResolution::find_field(const Span& sp, const ::HIR::TypeRef& ty, const for( const auto& fld : unm.m_variants ) { // TODO: Privacy - if( fld.first == name ) { + if( fld.second.publicity.is_visible(this->m_vis_path) && fld.first == name ) { field_ty = monomorphise_type_with(sp, fld.second.ent, monomorph); return true; } diff --git a/src/hir_typeck/helpers.hpp b/src/hir_typeck/helpers.hpp index 651a36c8..dd9a1581 100644 --- a/src/hir_typeck/helpers.hpp +++ b/src/hir_typeck/helpers.hpp @@ -150,17 +150,19 @@ class TraitResolution const ::HIR::Crate& m_crate; const ::HIR::GenericParams* m_impl_params; const ::HIR::GenericParams* m_item_params; + const ::HIR::SimplePath& m_vis_path; ::std::map< ::HIR::TypeRef, ::HIR::TypeRef> m_type_equalities; ::HIR::SimplePath m_lang_Box; mutable ::std::vector< ::HIR::TypeRef> m_eat_active_stack; public: - TraitResolution(const HMTypeInferrence& ivars, const ::HIR::Crate& crate, const ::HIR::GenericParams* impl_params, const ::HIR::GenericParams* item_params): + TraitResolution(const HMTypeInferrence& ivars, const ::HIR::Crate& crate, const ::HIR::GenericParams* impl_params, const ::HIR::GenericParams* item_params, const ::HIR::SimplePath& vis_path): m_ivars(ivars), m_crate(crate), m_impl_params( impl_params ), m_item_params( item_params ) + ,m_vis_path(vis_path) { prep_indexes(); m_lang_Box = crate.get_lang_item_path_opt("owned_box"); diff --git a/src/resolve/index.cpp b/src/resolve/index.cpp index f010b420..f38219ef 100644 --- a/src/resolve/index.cpp +++ b/src/resolve/index.cpp @@ -286,7 +286,7 @@ void Resolve_Index_Module_Wildcard__glob_in_hir_mod(const Span& sp, const AST::C { for(const auto& it : hmod.m_mod_items) { const auto& ve = *it.second; - if( ve.is_public ) { + if( ve.publicity.is_global() ) { const auto* vep = &ve.ent; AST::Path p; if( vep->is_Import() ) { @@ -346,7 +346,7 @@ void Resolve_Index_Module_Wildcard__glob_in_hir_mod(const Span& sp, const AST::C } for(const auto& it : hmod.m_value_items) { const auto& ve = *it.second; - if( ve.is_public ) { + if( ve.publicity.is_global() ) { AST::Path p; const auto* vep = &ve.ent; if( ve.ent.is_Import() ) { diff --git a/src/trans/enumerate.cpp b/src/trans/enumerate.cpp index e1e2bbd5..afdbd626 100644 --- a/src/trans/enumerate.cpp +++ b/src/trans/enumerate.cpp @@ -152,14 +152,14 @@ namespace { const bool EMIT_ALL = true; for(auto& vi : mod.m_value_items) { - Trans_Enumerate_ValItem(state, vi.second->ent, EMIT_ALL || (is_visible && vi.second->is_public), [&](){ return mod_path + vi.first; }); + Trans_Enumerate_ValItem(state, vi.second->ent, EMIT_ALL || (is_visible && vi.second->publicity.is_global()), [&](){ return mod_path + vi.first; }); } for(auto& ti : mod.m_mod_items) { if(auto* e = ti.second->ent.opt_Module() ) { - Trans_Enumerate_Public_Mod(state, *e, mod_path + ti.first, ti.second->is_public); + Trans_Enumerate_Public_Mod(state, *e, mod_path + ti.first, ti.second->publicity.is_global()); } } } -- cgit v1.2.3 From 967a76859749ecb602cd2c343e28888514f827bd Mon Sep 17 00:00:00 2001 From: John Hodge Date: Thu, 25 Apr 2019 13:56:11 +0800 Subject: MIR - Reduce size of LValue::Static by putting the HIR::Path behind a pointer --- src/hir/deserialise.cpp | 2 +- src/hir/serialise.cpp | 2 +- src/hir_conv/bind.cpp | 2 +- src/hir_conv/constant_evaluation.cpp | 4 +-- src/mir/dump.cpp | 2 +- src/mir/from_hir.cpp | 2 +- src/mir/helpers.cpp | 2 +- src/mir/mir.cpp | 4 +-- src/mir/mir.hpp | 58 +++++++++++++++++++++++++++++++++++- src/mir/mir_builder.cpp | 8 ++--- src/mir/optimise.cpp | 2 +- src/trans/codegen_c.cpp | 2 +- src/trans/codegen_mmir.cpp | 2 +- src/trans/enumerate.cpp | 4 +-- src/trans/monomorphise.cpp | 2 +- 15 files changed, 77 insertions(+), 21 deletions(-) diff --git a/src/hir/deserialise.cpp b/src/hir/deserialise.cpp index 9933255f..cd25a3cb 100644 --- a/src/hir/deserialise.cpp +++ b/src/hir/deserialise.cpp @@ -423,7 +423,7 @@ _(Return, {}) _(Argument, { static_cast(m_in.read_count()) } ) _(Local, static_cast(m_in.read_count()) ) - _(Static, deserialise_path() ) + _(Static, box$(deserialise_path()) ) _(Field, { box$( deserialise_mir_lvalue() ), static_cast(m_in.read_count()) diff --git a/src/hir/serialise.cpp b/src/hir/serialise.cpp index dd81596f..e90cf995 100644 --- a/src/hir/serialise.cpp +++ b/src/hir/serialise.cpp @@ -689,7 +689,7 @@ m_out.write_count(e); ), (Static, - serialise_path(e); + serialise_path(*e); ), (Field, serialise(e.val); diff --git a/src/hir_conv/bind.cpp b/src/hir_conv/bind.cpp index a3b0041b..940b2cab 100644 --- a/src/hir_conv/bind.cpp +++ b/src/hir_conv/bind.cpp @@ -712,7 +712,7 @@ namespace { (Argument, ), (Static, - upper_visitor.visit_path(e, ::HIR::Visitor::PathContext::VALUE); + upper_visitor.visit_path(*e, ::HIR::Visitor::PathContext::VALUE); ), (Field, H::visit_lvalue(upper_visitor, *e.val); diff --git a/src/hir_conv/constant_evaluation.cpp b/src/hir_conv/constant_evaluation.cpp index 6049056c..6838e186 100644 --- a/src/hir_conv/constant_evaluation.cpp +++ b/src/hir_conv/constant_evaluation.cpp @@ -319,7 +319,7 @@ namespace { return args[e.idx]; ), (Static, - MIR_TODO(state, "LValue::Static - " << e); + MIR_TODO(state, "LValue::Static - " << *e); ), (Field, auto& val = get_lval(*e.val); @@ -495,7 +495,7 @@ namespace { } else if( const auto* p = e.val.opt_Static() ) { // Borrow of a static, emit BorrowPath with the same path - val = ::HIR::Literal::make_BorrowPath( p->clone() ); + val = ::HIR::Literal::make_BorrowPath( (*p)->clone() ); } else { auto inner_val = local_state.read_lval(e.val); diff --git a/src/mir/dump.cpp b/src/mir/dump.cpp index 90b81d5d..ffce8abb 100644 --- a/src/mir/dump.cpp +++ b/src/mir/dump.cpp @@ -187,7 +187,7 @@ namespace { os << "_$" << e; ), (Static, - os << e; + os << *e; ), (Field, os << "("; diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index a2d0c790..912b8c78 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -2195,7 +2195,7 @@ namespace { m_builder.set_result( node.span(), mv$(tmp) ); ), (Static, - m_builder.set_result( node.span(), ::MIR::LValue::make_Static(node.m_path.clone()) ); + m_builder.set_result( node.span(), ::MIR::LValue::make_Static(box$(node.m_path.clone())) ); ), (StructConstant, // TODO: Why is this still a PathValue? diff --git a/src/mir/helpers.cpp b/src/mir/helpers.cpp index 38380fed..38388aed 100644 --- a/src/mir/helpers.cpp +++ b/src/mir/helpers.cpp @@ -82,7 +82,7 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c return m_fcn.locals.at(e); ), (Static, - return get_static_type(tmp, e); + return get_static_type(tmp, *e); ), (Field, const auto& ty = this->get_lvalue_type(tmp, *e.val); diff --git a/src/mir/mir.cpp b/src/mir/mir.cpp index ee6c1a6c..657e695d 100644 --- a/src/mir/mir.cpp +++ b/src/mir/mir.cpp @@ -104,7 +104,7 @@ namespace MIR { os << "Local(" << e << ")"; ), (Static, - os << "Static(" << e << ")"; + os << "Static(" << *e << ")"; ), (Field, os << "Field(" << e.field_index << ", " << *e.val << ")"; @@ -543,7 +543,7 @@ namespace MIR { (Return, return LValue(e); ), (Argument, return LValue(e); ), (Local, return LValue(e); ), - (Static, return LValue(e.clone()); ), + (Static, return LValue(box$(e->clone())); ), (Field, return LValue::make_Field({ box$( e.val->clone() ), e.field_index diff --git a/src/mir/mir.hpp b/src/mir/mir.hpp index 31eb9cd7..6969225d 100644 --- a/src/mir/mir.hpp +++ b/src/mir/mir.hpp @@ -17,6 +17,62 @@ namespace MIR { typedef unsigned int RegionId; typedef unsigned int BasicBlockId; +#if 0 +// TODO: Store LValues as: +// - A packed root value (one word, using the low bits as an enum descriminator) +// - A list of (inner to outer) wrappers +struct LValue +{ + class Storage + { + uintptr_t val; + public: + ~Storage() + { + if( is_Static() ) { + delete reinterpret_cast<::HIR::Path*>(val & ~3u); + val = 0; + } + } + bool is_Argument() const { return val != (MAX_ARG << 2) && (val & 3) == 0; } + bool is_Return() const { return val == (MAX_ARG << 2); } + bool is_Local() const { return (val & 3) == 1; } + bool is_Static() const { return (val & 3) == 2; } + + const ::HIR::Path& as_Static() const { assert(is_Static()); return *reinterpret_cast(val & ~3u); } + }; + class Wrapper + { + uintptr_t val; + public: + bool is_Deref() const { return (val & 3) == 0; } + // Stores the field index + bool is_Field() const { return (val & 3) == 1; } + // Stores the variant index + bool is_Downcast() const { return (val & 3) == 2; } + // Stores a Local index + bool is_Index() const { return (val & 3) == 3; } + + const unsigned as_Field() const { assert(is_Field()); return (val >> 2); } + const unsigned as_Index() const { assert(is_Index()); return (val >> 2); } + }; + + Storage m_root; + ::std::vector m_wrappers; + + LValue clone() const; + + class Ref + { + LValue& r; + size_t wrapper_idx; + public:: + LValue clone() const; + void replace(LValue x) const; + }; +}; +#endif + // "LVALUE" - Assignable values TAGGED_UNION_EX(LValue, (), Return, ( // Function return @@ -26,7 +82,7 @@ TAGGED_UNION_EX(LValue, (), Return, ( // Variable/Temporary (Local, unsigned int), // `static` or `static mut` - (Static, ::HIR::Path), + (Static, ::std::unique_ptr<::HIR::Path>), // Field access (tuple, struct, tuple struct, enum field, ...) // NOTE: Also used to index an array/slice by a compile-time known index (e.g. in destructuring) (Field, struct { diff --git a/src/mir/mir_builder.cpp b/src/mir/mir_builder.cpp index ac1b7650..81816535 100644 --- a/src/mir/mir_builder.cpp +++ b/src/mir/mir_builder.cpp @@ -1622,20 +1622,20 @@ void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std:: cb( m_output.locals.at(e) ); ), (Static, - TU_MATCHA( (e.m_data), (pe), + TU_MATCHA( (e->m_data), (pe), (Generic, ASSERT_BUG(sp, pe.m_params.m_types.empty(), "Path params on static"); const auto& s = m_resolve.m_crate.get_static_by_path(sp, pe.m_path); cb( s.m_type ); ), (UfcsKnown, - TODO(sp, "Static - UfcsKnown - " << e); + TODO(sp, "Static - UfcsKnown - " << *e); ), (UfcsUnknown, - BUG(sp, "Encountered UfcsUnknown in Static - " << e); + BUG(sp, "Encountered UfcsUnknown in Static - " << *e); ), (UfcsInherent, - TODO(sp, "Static - UfcsInherent - " << e); + TODO(sp, "Static - UfcsInherent - " << *e); ) ) ), diff --git a/src/mir/optimise.cpp b/src/mir/optimise.cpp index 67a5d4a4..b7e63deb 100644 --- a/src/mir/optimise.cpp +++ b/src/mir/optimise.cpp @@ -1159,7 +1159,7 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool return ::MIR::LValue::make_Local(this->var_base + se); ), (Static, - return this->monomorph( se ); + return box$(this->monomorph( *se )); ), (Deref, return ::MIR::LValue::make_Deref({ box$(this->clone_lval(*se.val)) }); diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 98d0d3de..373a36a8 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -5522,7 +5522,7 @@ namespace { m_of << "var" << e; ), (Static, - m_of << Trans_Mangle(e); + m_of << Trans_Mangle(*e); ), (Field, ::HIR::TypeRef tmp; diff --git a/src/trans/codegen_mmir.cpp b/src/trans/codegen_mmir.cpp index b2c5282a..4867cf6f 100644 --- a/src/trans/codegen_mmir.cpp +++ b/src/trans/codegen_mmir.cpp @@ -52,7 +52,7 @@ namespace os << "arg" << e.idx; break; TU_ARM(x.e, Static, e) - os << e; + os << *e; break; TU_ARM(x.e, Deref, e) os << "*" << fmt(*e.val); diff --git a/src/trans/enumerate.cpp b/src/trans/enumerate.cpp index afdbd626..da11386c 100644 --- a/src/trans/enumerate.cpp +++ b/src/trans/enumerate.cpp @@ -735,7 +735,7 @@ void Trans_Enumerate_Types(EnumState& state) ), (Static, if( tmp_ty_ptr ) { - const auto& path = e; + const auto& path = *e; TU_MATCHA( (path.m_data), (pe), (Generic, ASSERT_BUG(Span(), pe.m_params.m_types.empty(), "Path params on static - " << path); @@ -1495,7 +1495,7 @@ void Trans_Enumerate_FillFrom_MIR_LValue(EnumState& state, const ::MIR::LValue& (Local, ), (Static, - Trans_Enumerate_FillFrom_Path(state, e, pp); + Trans_Enumerate_FillFrom_Path(state, *e, pp); ), (Field, Trans_Enumerate_FillFrom_MIR_LValue(state, *e.val, pp); diff --git a/src/trans/monomorphise.cpp b/src/trans/monomorphise.cpp index 3b958fec..0a0b43b5 100644 --- a/src/trans/monomorphise.cpp +++ b/src/trans/monomorphise.cpp @@ -19,7 +19,7 @@ namespace { (Argument, return e; ), (Local, return e; ), (Static, - return params.monomorph(resolve, e); + return box$(params.monomorph(resolve, *e)); ), (Field, return ::MIR::LValue::make_Field({ -- cgit v1.2.3 From f8e6e964ffdac258780087d90899e7d3ad34b947 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Thu, 25 Apr 2019 14:41:00 +0800 Subject: Typecheck Expressions - Mark a change when `!` assigned --- src/hir_typeck/expr_cs.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 1fd44698..b453cf9d 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -6996,6 +6996,7 @@ namespace { DEBUG("- Diverge with no source types, force setting to !"); DEBUG("Set IVar " << i << " = !"); context.m_ivars.get_type(ty_l_ivar) = ::HIR::TypeRef::new_diverge(); + context.m_ivars.mark_change(); return true; } } -- cgit v1.2.3 From a6ca64bf6645e8e3bac089d370f9dc2a0b6e7b6e Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 26 Apr 2019 16:02:11 +0800 Subject: Typecheck Expressions - Strong disable match ergonomics downstream ivars, hack for ivar_poss match ergonomics --- src/hir_typeck/expr_cs.cpp | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index b453cf9d..913c3fc1 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -4410,7 +4410,8 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T { if( pat.m_binding.is_valid() ) { const auto& pb = pat.m_binding; - context.equate_types_from_shadow(sp, context.get_var(sp, pb.m_slot)); + //context.equate_types_from_shadow(sp, context.get_var(sp, pb.m_slot)); + context.equate_types_shadow_strong(sp, context.get_var(sp, pb.m_slot)); } TU_MATCHA( (pat.m_data), (e), (Any, @@ -7854,6 +7855,31 @@ namespace { } DEBUG("possible_tys = " << possible_tys); + // Find a CD option that can deref to a `--` option + for(const auto& e : possible_tys) + { + if( e.is_pointer && e.can_deref ) + { + ::HIR::TypeRef tmp; + const auto* dty = context.m_resolve.autoderef(sp, *e.ty, tmp); + if( dty && !dty->m_data.is_Infer() ) + { + for(const auto& e2 : possible_tys) + { + if( !e2.is_pointer && !e2.can_deref ) + { + if( context.m_ivars.types_equal(*dty, *e2.ty) ) + { + DEBUG("Coerce source can deref once to an unsize destination, picking source " << *e.ty); + context.equate_types(sp, ty_l, *e.ty); + return true; + } + } + } + } + } + } + // If there's only one option (or one real option w/ ivars, if in fallback mode) - equate it //if( possible_tys.size() == 1 && (n_ivars == 0 || !honour_disable) ) if( possible_tys.size() == 1 && n_ivars == 0 ) -- cgit v1.2.3 From 451bfeabc8e427818dfabc12cc54dbfad0f964fb Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 28 Apr 2019 10:55:31 +0800 Subject: Typecheck Expressions - Better handling of `!`, and match ergonomics --- src/hir_typeck/expr_cs.cpp | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 913c3fc1..721891c7 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -2049,7 +2049,7 @@ namespace { const auto& ty = this->context.get_type(rty); // TODO: Search the entire type for `!`? (What about pointers to it? or Option/Result?) // - A correct search will search for unconditional (ignoring enums with a non-! variant) non-rawptr instances of ! in the type - return ty.m_data.is_Diverge();// || (ty.m_data.is_Infer() && ty.m_data.as_Infer().ty_class == ::HIR::InferClass::Diverge); + return ty.m_data.is_Diverge(); }; assert( !node.m_nodes.empty() ); @@ -2066,6 +2066,7 @@ namespace { diverges = false; break; default: + this->context.equate_types_from_shadow(node.span(), node.m_res_type); return ; } ) @@ -3114,7 +3115,7 @@ namespace { void visit_node_ptr(::HIR::ExprNodeP& node_ptr) override { auto& node = *node_ptr; const char* node_ty = typeid(node).name(); - TRACE_FUNCTION_FR(&node << " " << &node << " " << node_ty << " : " << node.m_res_type, node_ty); + TRACE_FUNCTION_FR(&node_ptr << " " << &node << " " << node_ty << " : " << node.m_res_type, &node << " " << node_ty); this->check_type_resolved_top(node.span(), node.m_res_type); DEBUG(node_ty << " : = " << node.m_res_type); ::HIR::ExprVisitorDef::visit_node_ptr(node_ptr); @@ -3165,6 +3166,15 @@ namespace { { check_types_equal(node.span(), node.m_res_type, node.m_value_node->m_res_type); } + // If the last node diverges (yields `!`) then this block can yield `!` (or anything) + else if( ! node.m_nodes.empty() && node.m_nodes.back()->m_res_type == ::HIR::TypeRef::new_diverge() ) + { + } + else + { + // Non-diverging (empty, or with a non-diverging last node) blocks must yield `()` + check_types_equal(node.span(), node.m_res_type, ::HIR::TypeRef::new_unit()); + } } void visit(::HIR::ExprNode_Let& node) override { @@ -3379,9 +3389,9 @@ namespace { void check_types_equal(const Span& sp, const ::HIR::TypeRef& l, const ::HIR::TypeRef& r) const { DEBUG(sp << " - " << l << " == " << r); - if( /*l.m_data.is_Diverge() ||*/ r.m_data.is_Diverge() ) { - // Diverge, matches everything. - // TODO: Is this always true? + if( r.m_data.is_Diverge() ) { + // Diverge on the right is always valid + // - NOT on the left, because `!` can become everything, but nothing can become `!` } else if( l != r ) { ERROR(sp, E0000, "Type mismatch - " << l << " != " << r); @@ -6894,7 +6904,15 @@ namespace { DEBUG(i << ": Literal " << ty_l); return false; } - if( ! ivar_ent.has_rules() ) { + if( ! ivar_ent.has_rules() ) + { + if( ty_l.m_data.as_Infer().ty_class == ::HIR::InferClass::Diverge ) + { + DEBUG("Set IVar " << i << " = ! (no rules, and is diverge-class ivar)"); + context.m_ivars.get_type(ty_l_ivar) = ::HIR::TypeRef::new_diverge(); + context.m_ivars.mark_change(); + return true; + } // No rules, don't do anything (and don't print) DEBUG(i << ": No rules"); return false; @@ -8186,6 +8204,10 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR: } if( rule.name != "" ) { rule.left_ty = context.m_resolve.expand_associated_types(rule.span, mv$(rule.left_ty)); + // HACK: If the left type is `!`, remove the type bound + //if( rule.left_ty.m_data.is_Diverge() ) { + // rule.name = ""; + //} } rule.impl_ty = context.m_resolve.expand_associated_types(rule.span, mv$(rule.impl_ty)); @@ -8254,7 +8276,7 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR: { if( check_ivar_poss(context, i, context.possible_ivar_vals[i]) ) { static Span sp; - assert( context.possible_ivar_vals[i].has_rules() ); + //assert( context.possible_ivar_vals[i].has_rules() ); // Disable all metioned ivars in the possibilities for(const auto& ty : context.possible_ivar_vals[i].types_coerce_to) context.equate_types_from_shadow(sp,ty); -- cgit v1.2.3 From 9e5d8a66034e95217e00702647fdc6621862c9ae Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 28 Apr 2019 11:03:42 +0800 Subject: MIR Optimise - Fix (and detect) a recursive inline, remove drops of GC'd locals, disable a really expensive pass --- src/mir/optimise.cpp | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/src/mir/optimise.cpp b/src/mir/optimise.cpp index b7e63deb..7c284546 100644 --- a/src/mir/optimise.cpp +++ b/src/mir/optimise.cpp @@ -191,7 +191,7 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path #endif // >> Move common statements (assignments) across gotos. - change_happened |= MIR_Optimise_CommonStatements(state, fcn); + //change_happened |= MIR_Optimise_CommonStatements(state, fcn); // >> Combine Duplicate Blocks change_happened |= MIR_Optimise_UnifyBlocks(state, fcn); @@ -859,12 +859,31 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool { bool inline_happened = false; TRACE_FUNCTION_FR("", inline_happened); + struct InlineEvent { + ::HIR::Path path; + ::std::vector bb_list; + InlineEvent(::HIR::Path p) + :path(::std::move(p)) + { + } + bool has_bb(size_t i) const { + return ::std::find(this->bb_list.begin(), this->bb_list.end(), i) != this->bb_list.end(); + } + void add_range(size_t start, size_t count) { + for(size_t j = 0; j < count; j++) + { + this->bb_list.push_back(start + j); + } + } + }; + ::std::vector inlined_functions; struct H { static bool can_inline(const ::HIR::Path& path, const ::MIR::Function& fcn, bool minimal) { // TODO: If the function is marked as `inline(always)`, then inline it regardless of the contents + // TODO: Take a monomorph helper so recursion can be detected if( minimal ) { return false; @@ -888,6 +907,7 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool return false; // Detect and avoid simple recursion. // - This won't detect mutual recursion - that also needs prevention. + // TODO: This is the pre-monomorph path, but we're comparing with the post-monomorph path if( blk0_te.fcn.is_Path() && blk0_te.fcn.as_Path() == path ) return false; return true; @@ -907,6 +927,10 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool // Recursion, don't inline. if( te.fcn.is_Path() && te.fcn.as_Path() == path ) return false; + // HACK: Only allow if the wrapped function is an intrinsic + // - Works around the TODO about monomorphed paths above + if(!te.fcn.is_Intrinsic()) + return false; } } return true; @@ -1272,6 +1296,15 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool if( ! te->fcn.is_Path() ) continue ; const auto& path = te->fcn.as_Path(); + DEBUG(state << fcn.blocks[i].terminator); + + for(const auto& e : inlined_functions) + { + if( path == e.path && e.has_bb(i) ) + { + MIR_BUG(state, "Recursive inline of " << path); + } + } Cloner cloner { state.sp, state.m_resolve, *te }; const auto* called_mir = get_called_mir(state, list, path, cloner.params); @@ -1292,7 +1325,6 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool DEBUG("Can't inline " << path); continue ; } - DEBUG(state << fcn.blocks[i].terminator); TRACE_FUNCTION_F("Inline " << path); // Allocate a temporary for the return value @@ -1350,6 +1382,17 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool } cloner.const_assignments.clear(); + // Record the inline event + for(auto& e : inlined_functions) + { + if( e.has_bb(i) ) + { + e.add_range(cloner.bb_base, new_blocks.size()); + } + } + inlined_functions.push_back(InlineEvent(path.clone())); + inlined_functions.back().add_range(cloner.bb_base, new_blocks.size()); + // Apply DEBUG("- Append new blocks"); fcn.blocks.reserve( fcn.blocks.size() + new_blocks.size() ); @@ -1359,6 +1402,10 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool } fcn.blocks[i].terminator = ::MIR::Terminator::make_Goto( cloner.bb_base ); inline_happened = true; + + // TODO: Store the inlined path along with the start and end BBs, and then use that to detect recursive + // inlining + // - Recursive inlining should be an immediate panic. } } return inline_happened; @@ -3605,6 +3652,14 @@ bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn continue ; } } + + // HACK: Remove drop if it's of an unused value (TODO: only if it's conditional?) + if( se->slot.is_Local() && local_rewrite_table[se->slot.as_Local()] == ~0u ) + { + DEBUG(state << "Remove " << stmt << " - Dropping non-set value"); + to_remove_statements[stmt_idx] = true; + continue ; + } } visit_mir_lvalues_mut(stmt, lvalue_cb); -- cgit v1.2.3 From 2aaec20f9f4f8fc002086cb1117126dd6ac53b22 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 28 Apr 2019 11:05:00 +0800 Subject: MIR Gen - Support `match` in a `match` guard arm --- src/mir/from_hir.hpp | 6 +++--- src/mir/mir.hpp | 3 +++ src/mir/mir_builder.cpp | 51 +++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 51 insertions(+), 9 deletions(-) diff --git a/src/mir/from_hir.hpp b/src/mir/from_hir.hpp index 0dcbd65b..194fd0e0 100644 --- a/src/mir/from_hir.hpp +++ b/src/mir/from_hir.hpp @@ -70,8 +70,8 @@ TAGGED_UNION_EX(VarState, (), Invalid, ( (), (), ( VarState clone() const; - bool operator==(VarState& x) const; - bool operator!=(VarState& x) const { return !(*this == x); } + bool operator==(const VarState& x) const; + bool operator!=(const VarState& x) const { return !(*this == x); } ) ); extern ::std::ostream& operator<<(::std::ostream& os, const VarState& x); @@ -110,7 +110,7 @@ TAGGED_UNION(ScopeType, Owning, }), // State which should end up with no mutation of variable states (Freeze, struct { - //::std::map changed_slots; + ::std::map changed_slots; //::std::map changed_args; }) ); diff --git a/src/mir/mir.hpp b/src/mir/mir.hpp index 6969225d..7100d4aa 100644 --- a/src/mir/mir.hpp +++ b/src/mir/mir.hpp @@ -159,6 +159,9 @@ TAGGED_UNION_EX(Constant, (), Int, ( }), (Bytes, ::std::vector< ::std::uint8_t>), // Byte string (StaticString, ::std::string), // String + // TODO: Should these ::HIR::Path structures be behind pointers? + // - HIR::Path is ~11 words long, without it MIR::Constant is 4 instead of 12 + // - MIR::Param is quite common, potential large space saving. (Const, struct { ::HIR::Path p; }), // `const` (ItemAddr, ::HIR::Path) // address of a value ), (), (), ( diff --git a/src/mir/mir_builder.cpp b/src/mir/mir_builder.cpp index 81816535..8d534314 100644 --- a/src/mir/mir_builder.cpp +++ b/src/mir/mir_builder.cpp @@ -1554,7 +1554,6 @@ void MirBuilder::complete_scope(ScopeDef& sd) (Split, ), (Freeze, - //DEBUG("Freeze"); ) ) @@ -1607,6 +1606,28 @@ void MirBuilder::complete_scope(ScopeDef& sd) ASSERT_BUG(sd.span, e.end_state_valid, ""); H::apply_end_state(sd.span, *this, e.end_state); } + else if( const auto* e = sd.data.opt_Freeze() ) + { + TRACE_FUNCTION_F("Freeze"); + for(auto& ent : e->changed_slots) + { + auto& vs = this->get_slot_state_mut(sd.span, ent.first, SlotType::Local); + auto lv = ::MIR::LValue::make_Local(ent.first); + DEBUG(lv << " " << vs << " => " << ent.second); + if( vs != ent.second ) + { + if( vs.is_Valid() ) { + ERROR(sd.span, E0000, "Value went from " << vs << " => " << ent.second << " over freeze"); + } + else if( !this->lvalue_is_copy(sd.span, lv) ) { + ERROR(sd.span, E0000, "Non-Copy value went from " << vs << " => " << ent.second << " over freeze"); + } + else { + // It's a Copy value, and it wasn't originally fully Valid - allowable + } + } + } + } } void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::function cb) const @@ -1919,20 +1940,38 @@ VarState& MirBuilder::get_slot_state_mut(const Span& sp, unsigned int idx, SlotT } } } - else if( scope_def.data.is_Freeze() ) + // Freeze is used for `match` guards + // - These are only allowed to modify the (known `bool`) condition variable + // TODO: Some guards have more complex pieces of code, with self-contained scopes, allowable? + // - Those should already have defined their own scope? + // - OR, allow mutations here but ONLY if it's of a Copy type, and force it uninit at the end of the scope + else if( auto* e = scope_def.data.opt_Freeze() ) { + // If modified variable is the guard's result variable, allow it. + if( type != SlotType::Local ) { + DEBUG("Mutating state of arg" << idx); + ERROR(sp, E0000, "Attempting to move/initialise a value where not allowed"); + } if( type == SlotType::Local && idx == m_if_cond_lval.as_Local() ) { + // The guard condition variable is allowed to be mutated, and falls through to the upper scope } else { - // NOTE: This is only used in match conditions - DEBUG("Mutating state of ?" << idx); - ERROR(sp, E0000, "Attempting to move/initialise a value where not allowed"); + DEBUG("Mutating state of local" << idx); + auto& states = e->changed_slots; + if( states.count(idx) == 0 ) + { + auto state = get_slot_state(sp, idx, type).clone(); + states.insert(::std::make_pair( idx, mv$(state) )); + } + ret = &states[idx]; + break; // Stop searching } } else { + // Unknown scope type? } } if( ret ) @@ -2259,7 +2298,7 @@ VarState VarState::clone() const ) throw ""; } -bool VarState::operator==(VarState& x) const +bool VarState::operator==(const VarState& x) const { if( this->tag() != x.tag() ) return false; -- cgit v1.2.3 From 406fe84b2c663e5b1a31448baefe09b847cb635c Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 28 Apr 2019 15:23:37 +0800 Subject: Trans Monomorph - Associated constants left as Defer --- src/hir/hir.hpp | 3 +++ src/hir_conv/constant_evaluation.cpp | 51 ++++++++++++++++++------------------ src/trans/codegen_c.cpp | 17 ++++++++++-- src/trans/enumerate.cpp | 39 ++++++++++++++++++++------- src/trans/monomorphise.cpp | 30 +++++++++++++++++++-- src/trans/trans_list.cpp | 15 +++++++++++ src/trans/trans_list.hpp | 1 + 7 files changed, 116 insertions(+), 40 deletions(-) diff --git a/src/hir/hir.hpp b/src/hir/hir.hpp index f0844580..6c8385c4 100644 --- a/src/hir/hir.hpp +++ b/src/hir/hir.hpp @@ -173,6 +173,9 @@ public: TypeRef m_type; ExprPtr m_value; Literal m_value_res; + + // A cache of monomorphised versions when the `const` depends on generics for its value + mutable ::std::map< ::HIR::Path, Literal> m_monomorph_cache; }; class Function { diff --git a/src/hir_conv/constant_evaluation.cpp b/src/hir_conv/constant_evaluation.cpp index 6838e186..6067b32f 100644 --- a/src/hir_conv/constant_evaluation.cpp +++ b/src/hir_conv/constant_evaluation.cpp @@ -16,12 +16,15 @@ #include #include +#include "constant_evaluation.hpp" #include // For handling monomorph of MIR in provided associated constants #define CHECK_DEFER(var) do { if( var.is_Defer() ) { m_rv = ::HIR::Literal::make_Defer({}); return ; } } while(0) namespace { - struct NewvalState { + struct NewvalState + : public HIR::Evaluator::Newval + { const ::HIR::Module& mod; const ::HIR::ItemPath& mod_path; ::std::string name_prefix; @@ -35,7 +38,7 @@ namespace { { } - ::HIR::SimplePath new_static(::HIR::TypeRef type, ::HIR::Literal value) + virtual ::HIR::Path new_static(::HIR::TypeRef type, ::HIR::Literal value) override { auto name = FMT(name_prefix << next_item_idx); next_item_idx ++; @@ -51,23 +54,6 @@ namespace { return rv; } }; - struct Evaluator - { - const Span& root_span; - StaticTraitResolve resolve; - NewvalState nvs; - - Evaluator(const Span& sp, const ::HIR::Crate& crate, NewvalState nvs): - root_span(sp), - resolve(crate), - nvs( ::std::move(nvs) ) - { - } - - ::HIR::Literal evaluate_constant(const ::HIR::ItemPath& ip, const ::HIR::ExprPtr& expr, ::HIR::TypeRef exp, MonomorphState ms={}); - - ::HIR::Literal evaluate_constant_mir(const ::HIR::ItemPath& ip, const ::MIR::Function& fcn, MonomorphState ms, ::HIR::TypeRef exp, ::std::vector< ::HIR::Literal> args); - }; ::HIR::Literal clone_literal(const ::HIR::Literal& v) { @@ -276,6 +262,9 @@ namespace { TODO(sp, "Could not find function for " << path << " - " << rv.tag_str()); } } +} // namespace + +namespace HIR { ::HIR::Literal Evaluator::evaluate_constant_mir(const ::HIR::ItemPath& ip, const ::MIR::Function& fcn, MonomorphState ms, ::HIR::TypeRef exp, ::std::vector< ::HIR::Literal> args) { @@ -417,7 +406,8 @@ namespace { auto& item = const_cast<::HIR::Constant&>(c); // Challenge: Adding items to the module might invalidate an iterator. ::HIR::ItemPath mod_ip { item.m_value.m_state->m_mod_path }; - auto eval = Evaluator { item.m_value.span(), resolve.m_crate, NewvalState { item.m_value.m_state->m_module, mod_ip, FMT(&c << "$") } }; + auto nvs = NewvalState { item.m_value.m_state->m_module, mod_ip, FMT(&c << "$") }; + auto eval = ::HIR::Evaluator { item.m_value.span(), resolve.m_crate, nvs }; DEBUG("- Evaluate " << p); DEBUG("- " << ::HIR::ItemPath(p)); item.m_value_res = eval.evaluate_constant(::HIR::ItemPath(p), item.m_value, item.m_type.clone()); @@ -875,6 +865,9 @@ namespace { BUG(this->root_span, "Attempting to evaluate constant expression with no associated code"); } } +} // namespace HIR + +namespace { void check_lit_type(const Span& sp, const ::HIR::TypeRef& type, ::HIR::Literal& lit) { @@ -1028,7 +1021,8 @@ namespace { }); const auto& template_const = vi.second.as_Constant(); if( template_const.m_value_res.is_Defer() ) { - auto eval = Evaluator { sp, m_crate, NewvalState { *m_mod, *m_mod_path, FMT("impl" << &impl << "$" << vi.first << "$") } }; + auto nvs = NewvalState { *m_mod, *m_mod_path, FMT("impl" << &impl << "$" << vi.first << "$") }; + auto eval = ::HIR::Evaluator { sp, m_crate, nvs }; ::HIR::ExprPtr ep; Trans_Params tp(sp); tp.self_type = ms.self_ty->clone(); @@ -1094,7 +1088,8 @@ namespace { const auto& expr_ptr = *e.size; auto ty_name = FMT("ty_" << &ty << "$"); - auto eval = Evaluator { expr_ptr->span(), m_crate, NewvalState { *m_mod, *m_mod_path, ty_name } }; + auto nvs = NewvalState { *m_mod, *m_mod_path, ty_name }; + auto eval = ::HIR::Evaluator { expr_ptr->span(), m_crate, nvs }; auto val = eval.evaluate_constant(::HIR::ItemPath(*m_mod_path, ty_name.c_str()), expr_ptr, ::HIR::CoreType::Usize); if( !val.is_Integer() ) ERROR(expr_ptr->span(), E0000, "Array size isn't an integer"); @@ -1110,7 +1105,8 @@ namespace { // NOTE: Consteval needed here for MIR match generation to work if( item.m_value || item.m_value.m_mir ) { - auto eval = Evaluator { item.m_value.span(), m_crate, NewvalState { *m_mod, *m_mod_path, FMT(p.get_name() << "$") } }; + auto nvs = NewvalState { *m_mod, *m_mod_path, FMT(p.get_name() << "$") }; + auto eval = ::HIR::Evaluator { item.m_value.span(), m_crate, nvs }; item.m_value_res = eval.evaluate_constant(p, item.m_value, item.m_type.clone(), m_monomorph_state.clone()); check_lit_type(item.m_value.span(), item.m_type, item.m_value_res); @@ -1124,7 +1120,8 @@ namespace { if( item.m_value ) { - auto eval = Evaluator { item.m_value->span(), m_crate, NewvalState { *m_mod, *m_mod_path, FMT(p.get_name() << "$") } }; + auto nvs = NewvalState { *m_mod, *m_mod_path, FMT(p.get_name() << "$") }; + auto eval = ::HIR::Evaluator { item.m_value->span(), m_crate, nvs }; item.m_value_res = eval.evaluate_constant(p, item.m_value, item.m_type.clone()); check_lit_type(item.m_value->span(), item.m_type, item.m_value_res); @@ -1142,7 +1139,8 @@ namespace { { if( var.expr ) { - auto eval = Evaluator { var.expr->span(), m_crate, NewvalState { *m_mod, *m_mod_path, FMT(p.get_name() << "$" << var.name << "$") } }; + auto nvs = NewvalState { *m_mod, *m_mod_path, FMT(p.get_name() << "$" << var.name << "$") }; + auto eval = ::HIR::Evaluator { var.expr->span(), m_crate, nvs }; auto val = eval.evaluate_constant(p, var.expr, ty.clone()); DEBUG("enum variant: " << p << "::" << var.name << " = " << val); i = val.as_Integer(); @@ -1178,7 +1176,8 @@ namespace { void visit(::HIR::ExprNode_ArraySized& node) override { assert( node.m_size ); auto name = FMT("array_" << &node << "$"); - auto eval = Evaluator { node.span(), m_exp.m_crate, NewvalState { *m_exp.m_mod, *m_exp.m_mod_path, name } }; + auto nvs = NewvalState { *m_exp.m_mod, *m_exp.m_mod_path, name }; + auto eval = ::HIR::Evaluator { node.span(), m_exp.m_crate, nvs }; auto val = eval.evaluate_constant( ::HIR::ItemPath(*m_exp.m_mod_path, name.c_str()), node.m_size, ::HIR::CoreType::Usize ); if( !val.is_Integer() ) ERROR(node.span(), E0000, "Array size isn't an integer"); diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 373a36a8..08b4f2de 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -5288,8 +5288,21 @@ namespace { auto v = m_resolve.get_value(m_mir_res->sp, path, params); if( const auto* e = v.opt_Constant() ) { - ty = params.monomorph(m_mir_res->sp, (*e)->m_type); - return (*e)->m_value_res; + const auto& hir_const = **e; + ty = params.monomorph(m_mir_res->sp, hir_const.m_type); + if( hir_const.m_value_res.is_Defer() ) + { + // Do some form of lookup of a pre-cached evaluated monomorphised constant + // - Maybe on the `Constant` entry there can be a list of pre-monomorphised values + auto it = hir_const.m_monomorph_cache.find(path); + if( it == hir_const.m_monomorph_cache.end() ) + { + MIR_BUG(*m_mir_res, "Constant with Defer literal and no cached monomorphisation - " << path); + // TODO: Can do the consteval here? + } + return it->second; + } + return hir_const.m_value_res; } else { diff --git a/src/trans/enumerate.cpp b/src/trans/enumerate.cpp index da11386c..00b938ff 100644 --- a/src/trans/enumerate.cpp +++ b/src/trans/enumerate.cpp @@ -903,6 +903,10 @@ void Trans_Enumerate_Types(EnumState& state) return blank; } + static void visit_const(TypeVisitor& tv, const Trans_Params& pp, const ::HIR::Function& fcn, const ::MIR::Constant& p) + { + } + static void visit_param(TypeVisitor& tv, const Trans_Params& pp, const ::HIR::Function& fcn, const ::MIR::Param& p) { TU_MATCHA( (p), (e), @@ -910,6 +914,7 @@ void Trans_Enumerate_Types(EnumState& state) H::visit_lvalue(tv, pp, fcn, e); ), (Constant, + H::visit_const(tv, pp, fcn, e); ) ) } @@ -937,6 +942,7 @@ void Trans_Enumerate_Types(EnumState& state) H::visit_lvalue(tv,pp,fcn, re); ), (Constant, + H::visit_const(tv,pp,fcn, re); ), (SizedArray, H::visit_param(tv,pp,fcn, re.val); @@ -1182,14 +1188,14 @@ namespace { return true; } } - //{ - // auto it = impl.m_constants.find(e.item); - // if( it != impl.m_constants.end() ) - // { - // rv = EntPtr { &it->second.data }; - // return true; - // } - //} + { + auto it = impl.m_constants.find(pe->item); + if( it != impl.m_constants.end() ) + { + rv = EntPtr { &it->second.data }; + return true; + } + } return false; }); return rv; @@ -1481,7 +1487,19 @@ void Trans_Enumerate_FillFrom_Path(EnumState& state, const ::HIR::Path& path, co } } TU_ARMA(Constant, e) { - Trans_Enumerate_FillFrom_Literal(state, e->m_value_res, sub_pp); + if( e->m_value_res.is_Defer() ) + { + if( auto* slot = state.rv.add_const(mv$(path_mono)) ) + { + Trans_Enumerate_FillFrom_MIR(state, *e->m_value.m_mir, sub_pp); + slot->ptr = e; + slot->pp = ::std::move(sub_pp); + } + } + else + { + Trans_Enumerate_FillFrom_Literal(state, e->m_value_res, sub_pp); + } } } } @@ -1522,7 +1540,8 @@ void Trans_Enumerate_FillFrom_MIR_Constant(EnumState& state, const ::MIR::Consta (Bytes, ), (StaticString, ), // String (Const, - //Trans_Enumerate_FillFrom_Path(state, ce.p, pp); + // - Check if this constant has a value of Defer + Trans_Enumerate_FillFrom_Path(state, ce.p, pp); ), (ItemAddr, Trans_Enumerate_FillFrom_Path(state, ce, pp); diff --git a/src/trans/monomorphise.cpp b/src/trans/monomorphise.cpp index 0a0b43b5..cf101443 100644 --- a/src/trans/monomorphise.cpp +++ b/src/trans/monomorphise.cpp @@ -10,6 +10,7 @@ #include #include #include // Needed for post-monomorph checks and optimisations +#include namespace { ::MIR::LValue monomorph_LValue(const ::StaticTraitResolve& resolve, const Trans_Params& params, const ::MIR::LValue& tpl) @@ -361,8 +362,8 @@ void Trans_Monomorphise_List(const ::HIR::Crate& crate, TransList& list) for(const auto& a : fcn.m_args) args.push_back(::std::make_pair( ::HIR::Pattern{}, pp.monomorph(resolve, a.second) )); - ::std::string s = FMT(path); - ::HIR::ItemPath ip(s); + //::std::string s = FMT(path); + ::HIR::ItemPath ip(path); MIR_Validate(resolve, ip, *mir, args, ret_type); MIR_Cleanup(resolve, ip, *mir, args, ret_type); MIR_Optimise(resolve, ip, *mir, args, ret_type); @@ -373,5 +374,30 @@ void Trans_Monomorphise_List(const ::HIR::Crate& crate, TransList& list) fcn_ent.second->monomorphised.code = ::std::move(mir); } } + + // Also do constants and statics (stored in where?) + for(auto& ent : list.m_constants) + { + const auto& path = ent.first; + const auto& pp = ent.second->pp; + const auto& c = *ent.second->ptr; + TRACE_FUNCTION_FR(path, path); + auto ty = pp.monomorph(resolve, c.m_type); + // 1. Evaluate the constant + struct Nvs: public ::HIR::Evaluator::Newval + { + ::HIR::Path new_static(::HIR::TypeRef type, ::HIR::Literal value) override { + TODO(Span(), "Create new static in monomorph pass - " << value << " : " << type); + } + } nvs; + auto eval = ::HIR::Evaluator { pp.sp, crate, nvs }; + MonomorphState ms; + ms.self_ty = &pp.self_type; + ms.pp_impl = &pp.pp_impl; + ms.pp_method = &pp.pp_method; + auto new_lit = eval.evaluate_constant(path, c.m_value, ::std::move(ty), ::std::move(ms)); + // 2. Store evaluated HIR::Literal in c.m_monomorph_cache + c.m_monomorph_cache.insert(::std::make_pair( path.clone(), ::std::move(new_lit) )); + } } diff --git a/src/trans/trans_list.cpp b/src/trans/trans_list.cpp index 04e1e9a1..54ae8011 100644 --- a/src/trans/trans_list.cpp +++ b/src/trans/trans_list.cpp @@ -38,6 +38,21 @@ TransList_Static* TransList::add_static(::HIR::Path p) return nullptr; } } +TransList_Const* TransList::add_const(::HIR::Path p) +{ + auto rv = m_constants.insert( ::std::make_pair(mv$(p), nullptr) ); + if( rv.second ) + { + DEBUG("Const " << rv.first->first); + assert( !rv.first->second ); + rv.first->second.reset( new TransList_Const {} ); + return &*rv.first->second; + } + else + { + return nullptr; + } +} t_cb_generic Trans_Params::get_cb() const { diff --git a/src/trans/trans_list.hpp b/src/trans/trans_list.hpp index b58a241d..df550925 100644 --- a/src/trans/trans_list.hpp +++ b/src/trans/trans_list.hpp @@ -95,6 +95,7 @@ public: TransList_Function* add_function(::HIR::Path p); TransList_Static* add_static(::HIR::Path p); + TransList_Const* add_const(::HIR::Path p); bool add_vtable(::HIR::Path p, Trans_Params pp) { return m_vtables.insert( ::std::make_pair( mv$(p), mv$(pp) ) ).second; } -- cgit v1.2.3 From 52a948b6b934b3ac8c14f3d52e21fe0acf803378 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 3 May 2019 20:39:21 +0800 Subject: HIR Typecheck - Tweaks to validation code to allow pre-expand checks --- src/hir_typeck/common.hpp | 3 ++ src/hir_typeck/expr_check.cpp | 122 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 123 insertions(+), 2 deletions(-) diff --git a/src/hir_typeck/common.hpp b/src/hir_typeck/common.hpp index 4de874a8..9d662100 100644 --- a/src/hir_typeck/common.hpp +++ b/src/hir_typeck/common.hpp @@ -138,3 +138,6 @@ static inline t_cb_generic monomorphise_type_get_cb(const Span& sp, const ::HIR: } extern void check_type_class_primitive(const Span& sp, const ::HIR::TypeRef& type, ::HIR::InferClass ic, ::HIR::CoreType ct); + +class StaticTraitResolve; +extern void Typecheck_Expressions_ValidateOne(const StaticTraitResolve& resolve, const ::std::vector<::std::pair< ::HIR::Pattern, ::HIR::TypeRef>>& args, const ::HIR::TypeRef& ret_ty, const ::HIR::ExprPtr& code); diff --git a/src/hir_typeck/expr_check.cpp b/src/hir_typeck/expr_check.cpp index bc3b7f3d..0d3bc8ab 100644 --- a/src/hir_typeck/expr_check.cpp +++ b/src/hir_typeck/expr_check.cpp @@ -22,14 +22,18 @@ namespace { const ::HIR::TypeRef& ret_type; ::std::vector< const ::HIR::TypeRef*> closure_ret_types; ::std::vector m_loops; + //const ::HIR::ExprPtr* m_cur_expr; ::HIR::SimplePath m_lang_Index; public: + bool expand_erased_types; + ExprVisitor_Validate(const StaticTraitResolve& res, const t_args& args, const ::HIR::TypeRef& ret_type): m_resolve(res), //m_args(args), ret_type(ret_type) + ,expand_erased_types(true) { m_lang_Index = m_resolve.m_crate.get_lang_item_path_opt("index"); } @@ -131,6 +135,7 @@ namespace { TRACE_FUNCTION_F(&node << " let " << node.m_pattern << ": " << node.m_type); if(node.m_value) { + check_pattern(node.m_pattern, node.m_value->m_res_type); check_types_equal(node.span(), node.m_type, node.m_value->m_res_type); node.m_value->visit(*this); } @@ -141,6 +146,10 @@ namespace { node.m_value->visit(*this); for(auto& arm : node.m_arms) { + for(const auto& pat : arm.m_patterns) + { + check_pattern(pat, node.m_value->m_res_type); + } check_types_equal(node.span(), node.m_res_type, arm.m_code->m_res_type); arm.m_code->visit( *this ); } @@ -149,9 +158,11 @@ namespace { { TRACE_FUNCTION_F(&node << " if ... { ... } else { ... }"); node.m_cond->visit( *this ); + node.m_true->visit( *this ); check_types_equal(node.span(), node.m_res_type, node.m_true->m_res_type); if( node.m_false ) { + node.m_false->visit( *this ); check_types_equal(node.span(), node.m_res_type, node.m_false->m_res_type); } } @@ -377,7 +388,12 @@ namespace { const auto& src_ty = node.m_value->m_res_type; const auto& dst_ty = node.m_res_type; - if( src_ty == dst_ty ) + if( src_ty.m_data.is_Array() ) + { + ASSERT_BUG(sp, dst_ty.m_data.is_Slice(), ""); + ASSERT_BUG(sp, node.m_usage == ::HIR::ValueUsage::Unknown, ""); + } + else if( src_ty == dst_ty ) { } else if( src_ty.m_data.is_Borrow() && dst_ty.m_data.is_Borrow() ) @@ -760,7 +776,7 @@ namespace { rv = monomorph_cb(tpl).clone(); return true; } - else if( tpl.m_data.is_ErasedType() ) { + else if( this->expand_erased_types && tpl.m_data.is_ErasedType() ) { const auto& e = tpl.m_data.as_ErasedType(); ASSERT_BUG(sp, e.m_index < fcn_ptr->m_code.m_erased_types.size(), ""); @@ -852,6 +868,9 @@ namespace { } check_types_equal(node.span(), node.m_res_type, *e.m_rettype); ) + else if( node.m_trait_used == ::HIR::ExprNode_CallValue::TraitUsed::Unknown ) + { + } else { // 1. Look up the encoded trait @@ -1077,6 +1096,15 @@ namespace { } void check_types_equal(const Span& sp, const ::HIR::TypeRef& l, const ::HIR::TypeRef& r) const { + // TODO: Recurse when an erased type is encountered + //if( const auto* e = l.m_data.opt_ErasedType() ) + //{ + // return check_types_equal(sp, m_cur_expr->m_erased_types.at(e->m_index), r); + //} + //if( const auto* e = r.m_data.opt_ErasedType() ) + //{ + // return check_types_equal(sp, l, m_cur_expr->m_erased_types.at(e->m_index)); + //} //DEBUG(sp << " - " << l << " == " << r); if( /*l.m_data.is_Diverge() ||*/ r.m_data.is_Diverge() ) { // Diverge, matches everything. @@ -1125,6 +1153,89 @@ namespace { ERROR(sp, E0000, "Cannot find an impl of " << trait << params << " for " << ity); } } + void check_pattern(const ::HIR::Pattern& pat, const ::HIR::TypeRef& ty) const + { + Span sp; + TU_MATCH_HDRA( (pat.m_data), { ) + TU_ARMA(Any, pe) { + // Don't care + } + TU_ARMA(Box, pe) { + // TODO: Assert that `ty` is an owned_box + } + TU_ARMA(Ref, pe) { + // TODO: Assert that `ty` is a &-ptr + } + TU_ARMA(Tuple, pe) { + // TODO: Check for a matching tuple size + } + TU_ARMA(SplitTuple, pe) { + // TODO: Check for a matching tuple size + } + TU_ARMA(StructValue, pe) { + // TODO: Check that the type matches the struct + } + TU_ARMA(StructTuple, pe) { + // TODO: Destructure + } + TU_ARMA(Struct, pe) { + // TODO: Destructure + } + + TU_ARMA(Value, pe) { + this->check_pattern_value(sp, pe.val, ty); + } + TU_ARMA(Range, pe) { + this->check_pattern_value(sp, pe.start, ty); + this->check_pattern_value(sp, pe.end, ty); + } + TU_ARMA(EnumValue, e) { + // TODO: Check type + } + TU_ARMA(EnumTuple, e) { + // TODO: Destructure + } + TU_ARMA(EnumStruct, e) { + // TODO: Destructure + } + TU_ARMA(Slice, e) { + // TODO: Check that the type is a Slice or Array + // - Array must match size + } + TU_ARMA(SplitSlice, e) { + // TODO: Check that the type is a Slice or Array + // - Array must have compatible size + } + } + } + void check_pattern_value(const Span& sp, const ::HIR::Pattern::Value& pv, const ::HIR::TypeRef& ty) const + { + TU_MATCH_HDRA( (pv), { ) + TU_ARMA(Integer, e) { + if( e.type == ::HIR::CoreType::Str ) { + } + else { + check_types_equal(sp, ty, e.type); + } + } + TU_ARMA(Float, e) { + if( e.type == ::HIR::CoreType::Str ) { + } + else { + check_types_equal(sp, ty, e.type); + } + } + TU_ARMA(String, e) { + check_types_equal(sp, ty, ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, ::HIR::CoreType::Str)); + } + TU_ARMA(ByteString, e) { + check_types_equal(sp, ty, ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, ::HIR::TypeRef::new_slice(::HIR::CoreType::U8))); + } + TU_ARMA(Named, e) { + // TODO: Get type of the value and check equality + } + } + } const ::HIR::SimplePath& get_lang_item_path(const Span& sp, const char* name) const { @@ -1239,6 +1350,13 @@ namespace { }; } +void Typecheck_Expressions_ValidateOne(const StaticTraitResolve& resolve, const ::std::vector<::std::pair< ::HIR::Pattern, ::HIR::TypeRef>>& args, const ::HIR::TypeRef& ret_ty, const ::HIR::ExprPtr& code) +{ + ExprVisitor_Validate ev(resolve, args, ret_ty); + ev.expand_erased_types = false; // TODO: Make this an argument, we don't want to do this too early + ev.visit_root( const_cast<::HIR::ExprPtr&>(code) ); +} + void Typecheck_Expressions_Validate(::HIR::Crate& crate) { OuterVisitor ov(crate); -- cgit v1.2.3 From fb51e6006dbdb67977438e2c73b901856e23da91 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 3 May 2019 20:50:13 +0800 Subject: HIR Typecheck - Handle closure types in static typecheck --- src/hir_typeck/static.cpp | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/hir_typeck/static.cpp b/src/hir_typeck/static.cpp index 1dabb2c2..c71e71d7 100644 --- a/src/hir_typeck/static.cpp +++ b/src/hir_typeck/static.cpp @@ -7,6 +7,7 @@ */ #include "static.hpp" #include +#include void StaticTraitResolve::prep_indexes() { @@ -163,6 +164,47 @@ bool StaticTraitResolve::find_impl( return found_cb( ImplRef(type.clone(), trait_params->clone(), mv$(assoc)), false ); } ) + if(const auto* e = type.m_data.opt_Closure()) + { + if( trait_path == m_lang_Fn || trait_path == m_lang_FnMut || trait_path == m_lang_FnOnce ) + { + if( trait_params ) + { + const auto& des_arg_tys = trait_params->m_types.at(0).m_data.as_Tuple(); + if( des_arg_tys.size() != e->m_arg_types.size() ) { + return false; + } + for(unsigned int i = 0; i < des_arg_tys.size(); i ++) + { + if( des_arg_tys[i] != e->m_arg_types[i] ) { + return false; + } + } + } + else + { + trait_params = &null_params; + } + switch( e->node->m_class ) + { + case ::HIR::ExprNode_Closure::Class::Unknown: + break; + case ::HIR::ExprNode_Closure::Class::NoCapture: + break; + case ::HIR::ExprNode_Closure::Class::Once: + if( trait_path == m_lang_FnMut ) + return false; + case ::HIR::ExprNode_Closure::Class::Mut: + if( trait_path == m_lang_Fn ) + return false; + case ::HIR::ExprNode_Closure::Class::Shared: + break; + } + ::std::map< ::std::string, ::HIR::TypeRef> assoc; + assoc.insert( ::std::make_pair("Output", e->m_rettype->clone()) ); + return found_cb( ImplRef(type.clone(), trait_params->clone(), mv$(assoc)), false ); + } + } // ---- // TraitObject traits and supertraits -- cgit v1.2.3 From 1f407a88dabad32956f6936c1fa52de0c1b20285 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 3 May 2019 20:55:01 +0800 Subject: HIR Typecheck - Check expressions after typecheck (finds bugs faster) --- src/hir_typeck/expr_cs.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 721891c7..c3e85ae5 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -11,6 +11,7 @@ #include #include // std::find_if +#include #include "helpers.hpp" #include "expr_visit.hpp" @@ -4132,7 +4133,8 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T } } - // If there's no dereferences done, then + // If there's no dereferences done, then add a possible unsize type + // TODO: If the pattern is a String or ByteString value, then permit a single deref if( n_deref == 0 ) { const ::HIR::TypeRef& possible_type = get_possible_type(context, pattern); @@ -8543,5 +8545,18 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR: ExprVisitor_Apply visitor { context }; visitor.visit_node_ptr( expr ); } + + { + StaticTraitResolve static_resolve(ms.m_crate); + if( ms.m_impl_generics ) + { + static_resolve.set_impl_generics_raw(*ms.m_impl_generics); + } + if( ms.m_item_generics ) + { + static_resolve.set_item_generics_raw(*ms.m_item_generics); + } + Typecheck_Expressions_ValidateOne(static_resolve, args, result_type, expr); + } } -- cgit v1.2.3 From 788767f740979632cfeedeb1ac9b5d4f988ac623 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 3 May 2019 20:55:25 +0800 Subject: Lower MIR - (minor) Replace TU_MATCH with TU_MATCH_HDR --- src/mir/from_hir_match.cpp | 55 ++++++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/src/mir/from_hir_match.cpp b/src/mir/from_hir_match.cpp index 32c97682..e3ddce30 100644 --- a/src/mir/from_hir_match.cpp +++ b/src/mir/from_hir_match.cpp @@ -2819,40 +2819,37 @@ void MatchGenGrouped::gen_dispatch(const ::std::vector& rules, s // Matching over a path can only happen with an enum. // TODO: What about `box` destructures? // - They're handled via hidden derefs - if( !te.binding.is_Enum() ) { - TU_MATCHA( (te.binding), (pbe), - (Unbound, - BUG(sp, "Encounterd unbound path - " << te.path); - ), - (Opaque, - BUG(sp, "Attempting to match over opaque type - " << ty); - ), - (Struct, - const auto& str_data = pbe->m_data; - TU_MATCHA( (str_data), (sd), - (Unit, - BUG(sp, "Attempting to match over unit type - " << ty); - ), - (Tuple, - TODO(sp, "Matching on tuple-like struct?"); - ), - (Named, - TODO(sp, "Matching on struct?"); - ) - ) - ), - (Union, - TODO(sp, "Match over Union"); + TU_MATCH_HDR( (te.binding), { ) + TU_ARM(te.binding, Unbound, pbe) { + BUG(sp, "Encounterd unbound path - " << te.path); + } + TU_ARM(te.binding, Opaque, pbe) { + BUG(sp, "Attempting to match over opaque type - " << ty); + } + TU_ARM(te.binding, Struct, pbe) { + const auto& str_data = pbe->m_data; + TU_MATCHA( (str_data), (sd), + (Unit, + BUG(sp, "Attempting to match over unit type - " << ty); ), - (ExternType, - TODO(sp, "Match over ExternType - " << ty); + (Tuple, + TODO(sp, "Matching on tuple-like struct?"); ), - (Enum, + (Named, + TODO(sp, "Matching on struct? - " << ty); ) ) + } + TU_ARM(te.binding, Union, pbe) { + TODO(sp, "Match over Union"); + } + TU_ARM(te.binding, ExternType, pbe) { + TODO(sp, "Match over ExternType - " << ty); + } + TU_ARM(te.binding, Enum, pbe) { + this->gen_dispatch__enum(mv$(ty), mv$(val), rules, ofs, arm_targets, def_blk); + } } - - this->gen_dispatch__enum(mv$(ty), mv$(val), rules, ofs, arm_targets, def_blk); ), (Generic, BUG(sp, "Attempting to match a generic"); -- cgit v1.2.3 From 771c9385a5d7213cb12c1d7b969553b3402c498b Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 4 May 2019 17:11:12 +0800 Subject: HIR Typecheck - Expected type for string patterns --- src/hir_typeck/expr_cs.cpp | 98 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 87 insertions(+), 11 deletions(-) diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index c3e85ae5..a8e80a56 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -3870,6 +3870,7 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T struct H2 { static bool has_ref_or_borrow(const Span& sp, const ::HIR::Pattern& pat) { // TODO: Turns out that this isn't valid. See libsyntax 1.29 + // - ref `rustc-1.29.0-src/src/libsyntax/print/pprust.rs` 2911, `&Option` matched with `Some(ref foo)` //if( pat.m_binding.is_valid() && pat.m_binding.m_type != ::HIR::PatternBinding::Type::Move ) { // return true; //} @@ -3998,6 +3999,39 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T } return true; } + ::HIR::TypeRef get_possible_type_val(Context& context, ::HIR::Pattern::Value& pv) const + { + TU_MATCH_HDR( (pv), {) + TU_ARM(pv, Integer, ve) { + if( ve.type == ::HIR::CoreType::Str ) { + return ::HIR::TypeRef::new_infer(context.m_ivars.new_ivar(), ::HIR::InferClass::Integer); + } + return ve.type; + } + TU_ARM(pv, Float, ve) { + if( ve.type == ::HIR::CoreType::Str ) { + return ::HIR::TypeRef::new_infer(context.m_ivars.new_ivar(), ::HIR::InferClass::Float); + } + return ve.type; + } + TU_ARM(pv, String, ve) { + return ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, ::HIR::CoreType::Str); + } + TU_ARM(pv, ByteString, ve) { + // TODO: ByteString patterns can match either &[u8] or &[u8; N] + //return ::HIR::TypeRef::new_borrow( + // ::HIR::BorrowType::Shared, + // ::HIR::TypeRef::new_slice(::HIR::CoreType::U8) + // ); + return ::HIR::TypeRef(); + } + TU_ARM(pv, Named, ve) { + // TODO: Look up the path and get the type + return ::HIR::TypeRef(); + } + } + throw ""; + } const ::HIR::TypeRef& get_possible_type(Context& context, ::HIR::Pattern& pattern) const { if( m_possible_type == ::HIR::TypeRef() ) @@ -4010,13 +4044,20 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T // No type information. } TU_ARM(pattern.m_data, Value, pe) { - // TODO: Get type info + possible_type = get_possible_type_val(context, pe.val); } TU_ARM(pattern.m_data, Range, pe) { - // TODO: Get type info (same as Value) + possible_type = get_possible_type_val(context, pe.start); + if( possible_type == ::HIR::TypeRef() ) { + possible_type = get_possible_type_val(context, pe.end); + } + else { + // TODO: Check that the type from .end matches .start + } } TU_ARM(pattern.m_data, Box, pe) { - // TODO: Get type info (Box<_>) + // TODO: Get type info (Box<_>) ? + // - Is this possible? Shouldn't a box pattern disable ergonomics? } TU_ARM(pattern.m_data, Ref, pe) { BUG(sp, "Match ergonomics - & pattern"); @@ -4082,20 +4123,44 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T { pattern.m_binding.m_type = binding_mode; } + unsigned n_deref = 0; + const auto* type_p = &type; + ::HIR::TypeRef tmp; + const ::HIR::TypeRef* binding_type = nullptr; switch(pattern.m_binding.m_type) { case ::HIR::PatternBinding::Type::Move: - context.equate_types(sp, context.get_var(sp, pattern.m_binding.m_slot), type); + binding_type = &type; break; case ::HIR::PatternBinding::Type::MutRef: - context.equate_types(sp, context.get_var(sp, pattern.m_binding.m_slot), ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Unique, type.clone())); + // NOTE: Needs to deref and borrow to get just `&mut T` (where T isn't a &mut T) + //while( TU_TEST1(type_p->m_data, Borrow, .type >= ::HIR::BorrowType::Unique) ) + //{ + // n_deref ++; + // type_p = &context.m_ivars.get_type(*type_p->m_data.as_Borrow().inner); + //} + DEBUG(n_deref << " from " << type << " to " << *type_p); + binding_type = &(tmp = ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Unique, type_p->clone())); break; case ::HIR::PatternBinding::Type::Ref: - context.equate_types(sp, context.get_var(sp, pattern.m_binding.m_slot), ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, type.clone())); + // NOTE: Needs to deref and borrow to get just `&mut T` (where T isn't a &mut T) + //while( type_p->m_data.is_Borrow() ) + //{ + // n_deref ++; + // type_p = &context.m_ivars.get_type(*type_p->m_data.as_Borrow().inner); + //} + DEBUG(n_deref << " from " << type << " to " << *type_p); + binding_type = &(tmp = ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, type_p->clone())); break; default: TODO(sp, "Assign variable type using mode " << (int)binding_mode << " and " << type); } + if( n_deref > 0 ) { + TODO(sp, "Handle autoderef of ref bindings in match ergonomics"); + } + assert(binding_type); + context.equate_types(sp, context.get_var(sp, pattern.m_binding.m_slot), *binding_type); + //pattern.m_binding.n_deref = n_deref; } // For `_` patterns, there's nothing to match, so they just succeed with no derefs @@ -4134,12 +4199,23 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T } // If there's no dereferences done, then add a possible unsize type - // TODO: If the pattern is a String or ByteString value, then permit a single deref - if( n_deref == 0 ) + const ::HIR::TypeRef& possible_type = get_possible_type(context, pattern); + if( possible_type != ::HIR::TypeRef() ) { - const ::HIR::TypeRef& possible_type = get_possible_type(context, pattern); - if( possible_type != ::HIR::TypeRef() ) + DEBUG("n_deref = " << n_deref << ", possible_type = " << possible_type); + const ::HIR::TypeRef* possible_type_p = &possible_type; + // Unwrap borrows as many times as we've already dereferenced + for(size_t i = 0; i < n_deref && possible_type_p; i ++) { + if( const auto* te = possible_type_p->m_data.opt_Borrow() ) { + possible_type_p = &*te->inner; + } + else { + possible_type_p = nullptr; + } + } + if( possible_type_p ) { + const auto& possible_type = *possible_type_p; if( const auto* te = ty_p->m_data.opt_Infer() ) { context.possible_equate_type_unsize_to(te->index, possible_type); @@ -4161,7 +4237,7 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T } } - // TODO: Visit all inner bindings and disable coercion fallbacks on them. + // Visit all inner bindings and disable coercion fallbacks on them. MatchErgonomicsRevisit::disable_possibilities_on_bindings(sp, context, pattern); return false; } -- cgit v1.2.3 From 8a74857d5a6323a46757f12078b46718464a006d Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 4 May 2019 17:36:07 +0800 Subject: Match Ergonomics - Auto-deref in `ref` patterns to get `&T` --- src/hir/pattern.hpp | 8 ++++++-- src/hir_typeck/expr_cs.cpp | 25 +++++++++++-------------- src/mir/check.cpp | 6 ++++-- src/mir/from_hir.cpp | 5 +++++ 4 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/hir/pattern.hpp b/src/hir/pattern.hpp index cd6c7422..d16fd942 100644 --- a/src/hir/pattern.hpp +++ b/src/hir/pattern.hpp @@ -32,19 +32,23 @@ struct PatternBinding ::std::string m_name; unsigned int m_slot; + unsigned m_implicit_deref_count = 0; + bool is_valid() const { return m_name != ""; } PatternBinding(): m_mutable(false), m_type(Type::Move), m_name(""), - m_slot(0) + m_slot(0), + m_implicit_deref_count(0) {} PatternBinding(bool mut, Type type, ::std::string name, unsigned int slot): m_mutable(mut), m_type(type), m_name( mv$(name) ), - m_slot( slot ) + m_slot( slot ), + m_implicit_deref_count(0) {} }; diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index a8e80a56..0b6b0089 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -4134,33 +4134,30 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T break; case ::HIR::PatternBinding::Type::MutRef: // NOTE: Needs to deref and borrow to get just `&mut T` (where T isn't a &mut T) - //while( TU_TEST1(type_p->m_data, Borrow, .type >= ::HIR::BorrowType::Unique) ) - //{ - // n_deref ++; - // type_p = &context.m_ivars.get_type(*type_p->m_data.as_Borrow().inner); - //} + while( TU_TEST1(type_p->m_data, Borrow, .type >= ::HIR::BorrowType::Unique) ) + { + n_deref ++; + type_p = &context.m_ivars.get_type(*type_p->m_data.as_Borrow().inner); + } DEBUG(n_deref << " from " << type << " to " << *type_p); binding_type = &(tmp = ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Unique, type_p->clone())); break; case ::HIR::PatternBinding::Type::Ref: // NOTE: Needs to deref and borrow to get just `&mut T` (where T isn't a &mut T) - //while( type_p->m_data.is_Borrow() ) - //{ - // n_deref ++; - // type_p = &context.m_ivars.get_type(*type_p->m_data.as_Borrow().inner); - //} + while( type_p->m_data.is_Borrow() ) + { + n_deref ++; + type_p = &context.m_ivars.get_type(*type_p->m_data.as_Borrow().inner); + } DEBUG(n_deref << " from " << type << " to " << *type_p); binding_type = &(tmp = ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, type_p->clone())); break; default: TODO(sp, "Assign variable type using mode " << (int)binding_mode << " and " << type); } - if( n_deref > 0 ) { - TODO(sp, "Handle autoderef of ref bindings in match ergonomics"); - } assert(binding_type); context.equate_types(sp, context.get_var(sp, pattern.m_binding.m_slot), *binding_type); - //pattern.m_binding.n_deref = n_deref; + pattern.m_binding.m_implicit_deref_count = n_deref; } // For `_` patterns, there's nothing to match, so they just succeed with no derefs diff --git a/src/mir/check.cpp b/src/mir/check.cpp index b2d86590..b5abdb0a 100644 --- a/src/mir/check.cpp +++ b/src/mir/check.cpp @@ -686,10 +686,12 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path // TODO: Check that the input type is Copy ), (Borrow, - // TODO: Check return type + ::HIR::TypeRef tmp; + check_types( dst_ty, ::HIR::TypeRef::new_borrow(e.type, state.get_lvalue_type(tmp, e.val).clone()) ); ), (Cast, - // TODO: Check return type + // Check return type + check_types( dst_ty, e.type ); // TODO: Check suitability of source type (COMPLEX) ), (BinOp, diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index 912b8c78..8d51bf55 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -174,6 +174,11 @@ namespace { destructure_from_ex(sp, pat, lval.clone(), 3); } + for(size_t i = 0; i < pat.m_binding.m_implicit_deref_count; i ++) + { + lval = ::MIR::LValue::make_Deref({ box$(lval) }); + } + switch( pat.m_binding.m_type ) { case ::HIR::PatternBinding::Type::Move: -- cgit v1.2.3 From e475d337864918773d3e7784c645976e8acee663 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 4 May 2019 19:11:39 +0800 Subject: Typecheck Expressions - Handle SpliceSlice patterns in match ergonomics, disable `ref` autoderef --- src/hir_typeck/expr_cs.cpp | 41 ++++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 0b6b0089..f971cca7 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -4134,21 +4134,21 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T break; case ::HIR::PatternBinding::Type::MutRef: // NOTE: Needs to deref and borrow to get just `&mut T` (where T isn't a &mut T) - while( TU_TEST1(type_p->m_data, Borrow, .type >= ::HIR::BorrowType::Unique) ) - { - n_deref ++; - type_p = &context.m_ivars.get_type(*type_p->m_data.as_Borrow().inner); - } + //while( TU_TEST1(type_p->m_data, Borrow, .type >= ::HIR::BorrowType::Unique) ) + //{ + // n_deref ++; + // type_p = &context.m_ivars.get_type(*type_p->m_data.as_Borrow().inner); + //} DEBUG(n_deref << " from " << type << " to " << *type_p); binding_type = &(tmp = ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Unique, type_p->clone())); break; case ::HIR::PatternBinding::Type::Ref: // NOTE: Needs to deref and borrow to get just `&mut T` (where T isn't a &mut T) - while( type_p->m_data.is_Borrow() ) - { - n_deref ++; - type_p = &context.m_ivars.get_type(*type_p->m_data.as_Borrow().inner); - } + //while( type_p->m_data.is_Borrow() ) + //{ + // n_deref ++; + // type_p = &context.m_ivars.get_type(*type_p->m_data.as_Borrow().inner); + //} DEBUG(n_deref << " from " << type << " to " << *type_p); binding_type = &(tmp = ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, type_p->clone())); break; @@ -4350,7 +4350,22 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T rv |= this->revisit_inner(context, sub, *slice_inner, binding_mode); } TU_ARM(pattern.m_data, SplitSlice, pe) { - TODO(sp, "Match ergonomics - split-slice pattern"); + const ::HIR::TypeRef* slice_inner; + TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Slice, te, + slice_inner = &*te.inner; + ) + else TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Array, te, + slice_inner = &*te.inner; + ) + else { + ERROR(sp, E0000, "Matching a non-array/slice with a slice pattern - " << ty); + } + rv = true; + for(auto& sub : pe.leading) + rv |= this->revisit_inner(context, sub, *slice_inner, binding_mode); + // TODO: Extra bind + for(auto& sub : pe.trailing) + rv |= this->revisit_inner(context, sub, *slice_inner, binding_mode); } TU_ARM(pattern.m_data, StructValue, e) { context.add_ivars_params( e.path.m_params ); @@ -4598,6 +4613,10 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T (SplitSlice, for(auto& sub : e.leading) create_bindings(sp, context, sub); + // TODO: extra_bind + if( e.extra_bind.is_valid() ) { + TODO(sp, "Handle split slice binding binding in match ergonomics"); + } for(auto& sub : e.trailing) create_bindings(sp, context, sub); ), -- cgit v1.2.3 From a67c91329da4e2840ee4089e5c7854f68bb8afda Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 5 May 2019 10:39:25 +0800 Subject: Typecheck Expressions - (Disabled) inclusion of a coercion point on match values --- src/hir_typeck/expr_cs.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index f971cca7..a8fa2870 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -812,8 +812,8 @@ namespace { { TRACE_FUNCTION_F(&node << " match ..."); +#if 1 const auto& val_type = node.m_value->m_res_type; - { auto _ = this->push_inner_coerce_scoped(true); this->context.add_ivars(node.m_value->m_res_type); @@ -821,6 +821,15 @@ namespace { // TODO: If a coercion point (and ivar for the value) is placed here, it will allow `match &string { "..." ... }` node.m_value->visit( *this ); } +#else + auto val_type = this->context.m_ivars.new_ivar_tr(); + { + auto _ = this->push_inner_coerce_scoped(true); + this->context.add_ivars(node.m_value->m_res_type); + node.m_value->visit( *this ); + this->context.equate_types_coerce( node.span(), val_type, node.m_value ); + } +#endif for(auto& arm : node.m_arms) { -- cgit v1.2.3 From 4c4a7b88914861b644ec56738ced8cfc179f93f9 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 5 May 2019 12:42:57 +0800 Subject: MIR - Wrap HIR::Path-s in MIR::Constant in unique_ptr --- src/hir/deserialise.cpp | 4 +-- src/hir/expr_ptr.cpp | 13 ++++--- src/hir/serialise.cpp | 4 +-- src/hir_conv/bind.cpp | 47 ++++++++++--------------- src/hir_conv/constant_evaluation.cpp | 6 ++-- src/mir/cleanup.cpp | 18 +++++----- src/mir/dump.cpp | 4 +-- src/mir/from_hir.cpp | 20 ++++++----- src/mir/helpers.cpp | 10 +++--- src/mir/mir.cpp | 12 +++---- src/mir/mir.hpp | 67 ++++++++++++++++++++++++++++++------ src/mir/optimise.cpp | 4 +-- src/trans/codegen_c.cpp | 8 ++--- src/trans/codegen_mmir.cpp | 2 +- src/trans/enumerate.cpp | 4 +-- src/trans/monomorphise.cpp | 6 ++-- 16 files changed, 135 insertions(+), 94 deletions(-) diff --git a/src/hir/deserialise.cpp b/src/hir/deserialise.cpp index cd25a3cb..c5350b55 100644 --- a/src/hir/deserialise.cpp +++ b/src/hir/deserialise.cpp @@ -532,8 +532,8 @@ return ::MIR::Constant::make_Bytes( mv$(bytes) ); } _(StaticString, m_in.read_string() ) - _(Const, { deserialise_path() } ) - _(ItemAddr, deserialise_path() ) + _(Const, { box$(deserialise_path()) } ) + _(ItemAddr, box$(deserialise_path()) ) #undef _ default: BUG(Span(), "Bad tag for MIR::Const - " << tag); diff --git a/src/hir/expr_ptr.cpp b/src/hir/expr_ptr.cpp index 0c219e0f..7f493a0d 100644 --- a/src/hir/expr_ptr.cpp +++ b/src/hir/expr_ptr.cpp @@ -91,11 +91,14 @@ void HIR::ExprPtr::set_mir(::MIR::FunctionPointer mir) assert( !this->m_mir ); m_mir = ::std::move(mir); // Reset the HIR tree to be a placeholder node (thus freeing the backing memory) - //if( node ) - //{ - // auto sp = node->span(); - // node = ExprPtrInner(::std::unique_ptr(new ::HIR::ExprNode_Tuple(sp, {}))); - //} + if( false && node ) + { + auto sp = node->span(); + node = ExprPtrInner(::std::unique_ptr(new ::HIR::ExprNode_Loop( + sp, "", + ::std::unique_ptr(new ::HIR::ExprNode_Tuple(sp, {})) + ))); + } } diff --git a/src/hir/serialise.cpp b/src/hir/serialise.cpp index e90cf995..2c72c801 100644 --- a/src/hir/serialise.cpp +++ b/src/hir/serialise.cpp @@ -795,10 +795,10 @@ m_out.write_string(e); ), (Const, - serialise_path(e.p); + serialise_path(*e.p); ), (ItemAddr, - serialise_path(e); + serialise_path(*e); ) ) } diff --git a/src/hir_conv/bind.cpp b/src/hir_conv/bind.cpp index 940b2cab..84854315 100644 --- a/src/hir_conv/bind.cpp +++ b/src/hir_conv/bind.cpp @@ -729,25 +729,29 @@ namespace { ) ) } + static void visit_constant(Visitor& upper_visitor, ::MIR::Constant& e) + { + TU_MATCHA( (e), (ce), + (Int, ), + (Uint,), + (Float, ), + (Bool, ), + (Bytes, ), + (StaticString, ), // String + (Const, + upper_visitor.visit_path(*ce.p, ::HIR::Visitor::PathContext::VALUE); + ), + (ItemAddr, + upper_visitor.visit_path(*ce, ::HIR::Visitor::PathContext::VALUE); + ) + ) + } static void visit_param(Visitor& upper_visitor, ::MIR::Param& p) { TU_MATCHA( (p), (e), (LValue, H::visit_lvalue(upper_visitor, e);), (Constant, - TU_MATCHA( (e), (ce), - (Int, ), - (Uint,), - (Float, ), - (Bool, ), - (Bytes, ), - (StaticString, ), // String - (Const, - upper_visitor.visit_path(ce.p, ::HIR::Visitor::PathContext::VALUE); - ), - (ItemAddr, - upper_visitor.visit_path(ce, ::HIR::Visitor::PathContext::VALUE); - ) - ) + H::visit_constant(upper_visitor, e); ) ) } @@ -765,20 +769,7 @@ namespace { H::visit_lvalue(*this, e); ), (Constant, - TU_MATCHA( (e), (ce), - (Int, ), - (Uint,), - (Float, ), - (Bool, ), - (Bytes, ), - (StaticString, ), // String - (Const, - this->visit_path(ce.p, ::HIR::Visitor::PathContext::VALUE); - ), - (ItemAddr, - this->visit_path(ce, ::HIR::Visitor::PathContext::VALUE); - ) - ) + H::visit_constant(*this, e); ), (SizedArray, H::visit_param(*this, e.val); diff --git a/src/hir_conv/constant_evaluation.cpp b/src/hir_conv/constant_evaluation.cpp index 6067b32f..0ccb6e6f 100644 --- a/src/hir_conv/constant_evaluation.cpp +++ b/src/hir_conv/constant_evaluation.cpp @@ -390,11 +390,11 @@ namespace HIR { TU_ARM(c, StaticString, e2) return ::HIR::Literal(e2); TU_ARM(c, Const, e2) { - auto p = ms.monomorph(state.sp, e2.p); + auto p = ms.monomorph(state.sp, *e2.p); // If there's any mention of generics in this path, then return Literal::Defer if( visit_path_tys_with(p, [&](const auto& ty)->bool { return ty.m_data.is_Generic(); }) ) { - DEBUG("Return Literal::Defer for constant " << e2.p << " which references a generic parameter"); + DEBUG("Return Literal::Defer for constant " << *e2.p << " which references a generic parameter"); return ::HIR::Literal::make_Defer({}); } MonomorphState const_ms; @@ -417,7 +417,7 @@ namespace HIR { return clone_literal( c.m_value_res ); } TU_ARM(c, ItemAddr, e2) - return ::HIR::Literal::make_BorrowPath( ms.monomorph(state.sp, e2) ); + return ::HIR::Literal::make_BorrowPath( ms.monomorph(state.sp, *e2) ); } throw ""; }; diff --git a/src/mir/cleanup.cpp b/src/mir/cleanup.cpp index fdc0f3d4..dd5332b6 100644 --- a/src/mir/cleanup.cpp +++ b/src/mir/cleanup.cpp @@ -216,7 +216,7 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const MIR::TypeResolve& state, con if( path == ::HIR::GenericPath() ) MIR_TODO(state, "Literal of type " << ty << " - " << lit); DEBUG("Unknown type " << ty << ", but a path was provided - Return ItemAddr " << path); - return ::MIR::Constant( mv$(path) ); + return ::MIR::Constant::make_ItemAddr( box$(path) ); ), (Tuple, MIR_ASSERT(state, lit.is_List(), "Non-list literal for Tuple - " << lit); @@ -378,7 +378,7 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const MIR::TypeResolve& state, con if( const auto* pp = lit.opt_BorrowPath() ) { const auto& path = *pp; - auto ptr_val = ::MIR::Constant::make_ItemAddr(path.clone()); + auto ptr_val = ::MIR::Constant::make_ItemAddr(box$(path.clone())); // TODO: Get the metadata type (for !Sized wrapper types) if( te.inner->m_data.is_Slice() ) { @@ -397,7 +397,7 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const MIR::TypeResolve& state, con auto vtable_path = ::HIR::Path(&ty == &tmp ? mv$(tmp) : ty.clone(), tep->m_trait.m_path.clone(), "vtable#"); - auto vtable_val = ::MIR::Param( ::MIR::Constant::make_ItemAddr(mv$(vtable_path)) ); + auto vtable_val = ::MIR::Param( ::MIR::Constant::make_ItemAddr(box$(vtable_path)) ); return ::MIR::RValue::make_MakeDst({ ::MIR::Param(mv$(ptr_val)), mv$(vtable_val) }); } @@ -458,7 +458,7 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const MIR::TypeResolve& state, con (Function, //MIR_TODO(state, "Const function pointer " << lit << " w/ type " << ty); MIR_ASSERT(state, lit.is_BorrowPath(), ""); - return ::MIR::Constant::make_ItemAddr( lit.as_BorrowPath().clone() ); + return ::MIR::Constant::make_ItemAddr( box$( lit.as_BorrowPath().clone() ) ); ) ) } @@ -703,7 +703,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator& MIR_ASSERT(state, state.m_resolve.type_is_sized(state.sp, src_ty), "Attempting to get vtable for unsized type - " << src_ty); ::HIR::Path vtable { src_ty.clone(), trait_path.m_path.clone(), "vtable#" }; - out_meta_val = ::MIR::Constant::make_ItemAddr(mv$(vtable)); + out_meta_val = ::MIR::Constant::make_ItemAddr(box$(vtable)); } } return true; @@ -1092,18 +1092,18 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, TU_IFLET( ::MIR::Constant, e, Const, ce, // 1. Find the constant ::HIR::TypeRef ty; - const auto* lit_ptr = MIR_Cleanup_GetConstant(state, ce.p, ty); + const auto* lit_ptr = MIR_Cleanup_GetConstant(state, *ce.p, ty); if( lit_ptr && !lit_ptr->is_Defer() ) { - DEBUG("Replace constant " << ce.p << " with " << *lit_ptr); - se.src = MIR_Cleanup_LiteralToRValue(state, mutator, *lit_ptr, mv$(ty), mv$(ce.p)); + DEBUG("Replace constant " << *ce.p << " with " << *lit_ptr); + se.src = MIR_Cleanup_LiteralToRValue(state, mutator, *lit_ptr, mv$(ty), mv$(*ce.p)); if( auto* p = se.src.opt_Constant() ) { MIR_Cleanup_Constant(state, mutator, *p); } } else { - DEBUG("No replacement for constant " << ce.p); + DEBUG("No replacement for constant " << *ce.p); } ) ) diff --git a/src/mir/dump.cpp b/src/mir/dump.cpp index ffce8abb..b02c1e5b 100644 --- a/src/mir/dump.cpp +++ b/src/mir/dump.cpp @@ -244,10 +244,10 @@ namespace { os << "\"" << ce << "\""; ), (Const, - os << ce.p; + os << *ce.p; ), (ItemAddr, - os << "addr " << ce; + os << "addr " << *ce; ) ) } diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index 8d51bf55..b8549f8a 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -162,6 +162,7 @@ namespace { void destructure_from_ex(const Span& sp, const ::HIR::Pattern& pat, ::MIR::LValue lval, int allow_refutable=0) // 1 : yes, 2 : disallow binding { + TRACE_FUNCTION_F(pat << ", allow_refutable=" << allow_refutable); if( allow_refutable != 3 && pat.m_binding.is_valid() ) { if( allow_refutable == 2 ) { BUG(sp, "Binding when not expected"); @@ -425,9 +426,10 @@ namespace { // 2. Obtain pointer to element ::HIR::BorrowType bt = H::get_borrow_type(sp, e.extra_bind); ::MIR::LValue ptr_val = m_builder.lvalue_or_temp(sp, - ::HIR::TypeRef::new_pointer( bt, inner_type.clone() ), + ::HIR::TypeRef::new_borrow( bt, inner_type.clone() ), ::MIR::RValue::make_Borrow({ 0, bt, ::MIR::LValue::make_Field({ box$(lval.clone()), static_cast(e.leading.size()) }) }) ); + // TODO: Cast to raw pointer? Or keep as a borrow? // Construct fat pointer m_builder.push_stmt_assign( sp, m_builder.get_variable(sp, e.extra_bind.m_slot), ::MIR::RValue::make_MakeDst({ mv$(ptr_val), mv$(len_val) }) ); @@ -2185,7 +2187,7 @@ namespace { // TODO: Ideally, the creation of the wrapper function would happen somewhere before trans? auto tmp = m_builder.new_temporary( node.m_res_type ); - m_builder.push_stmt_assign( sp, tmp.clone(), ::MIR::Constant::make_ItemAddr(node.m_path.clone()) ); + m_builder.push_stmt_assign( sp, tmp.clone(), ::MIR::Constant::make_ItemAddr(box$(node.m_path.clone())) ); m_builder.set_result( sp, mv$(tmp) ); return ; } @@ -2196,7 +2198,7 @@ namespace { ), (Constant, auto tmp = m_builder.new_temporary( e.m_type ); - m_builder.push_stmt_assign( sp, tmp.clone(), ::MIR::Constant::make_Const({node.m_path.clone()}) ); + m_builder.push_stmt_assign( sp, tmp.clone(), ::MIR::Constant::make_Const({box$(node.m_path.clone())}) ); m_builder.set_result( node.span(), mv$(tmp) ); ), (Static, @@ -2245,13 +2247,13 @@ namespace { fcn_ty_data.m_arg_types.push_back( monomorphise_type_with(sp, arg.second, monomorph_cb) ); } auto tmp = m_builder.new_temporary( ::HIR::TypeRef( mv$(fcn_ty_data) ) ); - m_builder.push_stmt_assign( sp, tmp.clone(), ::MIR::Constant::make_ItemAddr(node.m_path.clone()) ); + m_builder.push_stmt_assign( sp, tmp.clone(), ::MIR::Constant::make_ItemAddr(box$(node.m_path.clone())) ); m_builder.set_result( sp, mv$(tmp) ); ), (StructConstructor, // TODO: Ideally, the creation of the wrapper function would happen somewhere before this? auto tmp = m_builder.new_temporary( node.m_res_type ); - m_builder.push_stmt_assign( sp, tmp.clone(), ::MIR::Constant::make_ItemAddr(node.m_path.clone()) ); + m_builder.push_stmt_assign( sp, tmp.clone(), ::MIR::Constant::make_ItemAddr(box$(node.m_path.clone())) ); m_builder.set_result( sp, mv$(tmp) ); ) ) @@ -2263,13 +2265,13 @@ namespace { ASSERT_BUG(sp, it != tr.m_values.end(), "Cannot find trait item for " << node.m_path); TU_MATCHA( (it->second), (e), (Constant, - m_builder.set_result( sp, ::MIR::Constant::make_Const({node.m_path.clone()}) ); + m_builder.set_result( sp, ::MIR::Constant::make_Const({box$(node.m_path.clone())}) ); ), (Static, TODO(sp, "Associated statics (non-rustc) - " << node.m_path); ), (Function, - m_builder.set_result( sp, ::MIR::Constant::make_ItemAddr(node.m_path.clone()) ); + m_builder.set_result( sp, ::MIR::Constant::make_ItemAddr(box$(node.m_path.clone())) ); ) ) ), @@ -2285,7 +2287,7 @@ namespace { { auto it = impl.m_methods.find(pe.item); if( it != impl.m_methods.end() ) { - m_builder.set_result( sp, ::MIR::Constant::make_ItemAddr(node.m_path.clone()) ); + m_builder.set_result( sp, ::MIR::Constant::make_ItemAddr(box$(node.m_path.clone())) ); return true; } } @@ -2293,7 +2295,7 @@ namespace { { auto it = impl.m_constants.find(pe.item); if( it != impl.m_constants.end() ) { - m_builder.set_result( sp, ::MIR::Constant::make_Const({node.m_path.clone()}) ); + m_builder.set_result( sp, ::MIR::Constant::make_Const({box$(node.m_path.clone())}) ); return true; } } diff --git a/src/mir/helpers.cpp b/src/mir/helpers.cpp index 38388aed..1453acb3 100644 --- a/src/mir/helpers.cpp +++ b/src/mir/helpers.cpp @@ -270,7 +270,7 @@ const ::HIR::TypeRef& MIR::TypeResolve::get_param_type(::HIR::TypeRef& tmp, cons ), (Const, MonomorphState p; - auto v = m_resolve.get_value(this->sp, e.p, p, /*signature_only=*/true); + auto v = m_resolve.get_value(this->sp, *e.p, p, /*signature_only=*/true); if( const auto* ve = v.opt_Constant() ) { const auto& ty = (*ve)->m_type; if( monomorphise_type_needed(ty) ) { @@ -282,12 +282,12 @@ const ::HIR::TypeRef& MIR::TypeResolve::get_param_type(::HIR::TypeRef& tmp, cons return ty.clone(); } else { - MIR_BUG(*this, "get_const_type - Not a constant " << e.p); + MIR_BUG(*this, "get_const_type - Not a constant " << *e.p); } ), (ItemAddr, MonomorphState p; - auto v = m_resolve.get_value(this->sp, e, p, /*signature_only=*/true); + auto v = m_resolve.get_value(this->sp, *e, p, /*signature_only=*/true); TU_MATCHA( (v), (ve), (NotFound, MIR_BUG(*this, "get_const_type - ItemAddr points to unknown value - " << c); @@ -325,7 +325,7 @@ const ::HIR::TypeRef& MIR::TypeResolve::get_param_type(::HIR::TypeRef& tmp, cons ::HIR::FunctionType ft; ft.is_unsafe = false; ft.m_abi = ABI_RUST; - auto enum_path = e.clone(); + auto enum_path = e->clone(); enum_path.m_data.as_Generic().m_path.m_components.pop_back(); ft.m_rettype = box$( ::HIR::TypeRef::new_path(mv$(enum_path), ve.e) ); ft.m_arg_types.reserve(str_data.size()); @@ -348,7 +348,7 @@ const ::HIR::TypeRef& MIR::TypeResolve::get_param_type(::HIR::TypeRef& tmp, cons ::HIR::FunctionType ft; ft.is_unsafe = false; ft.m_abi = ABI_RUST; - ft.m_rettype = box$( ::HIR::TypeRef::new_path( ::HIR::GenericPath(*ve.p, e.m_data.as_Generic().m_params.clone()), &str) ); + ft.m_rettype = box$( ::HIR::TypeRef::new_path( ::HIR::GenericPath(*ve.p, e->m_data.as_Generic().m_params.clone()), &str) ); ft.m_arg_types.reserve(str_data.size()); for(const auto& fld : str_data) ft.m_arg_types.push_back( p.monomorph(this->sp, fld.ent) ); diff --git a/src/mir/mir.cpp b/src/mir/mir.cpp index 657e695d..638b8e46 100644 --- a/src/mir/mir.cpp +++ b/src/mir/mir.cpp @@ -44,10 +44,10 @@ namespace MIR { os << "\"" << FmtEscaped(e) << "\""; ), (Const, - os << e.p; + os << *e.p; ), (ItemAddr, - os << "&" << e; + os << "&" << *e; ) ) return os; @@ -82,10 +82,10 @@ namespace MIR { return ::ord(ae, be); ), (Const, - return ::ord(ae.p, be.p); + return ::ord(*ae.p, *be.p); ), (ItemAddr, - return ::ord(ae, be); + return ::ord(*ae, *be); ) ) throw ""; @@ -571,8 +571,8 @@ namespace MIR { (Bool, return ::MIR::Constant(e2); ), (Bytes, return ::MIR::Constant(e2); ), (StaticString, return ::MIR::Constant(e2); ), - (Const, return ::MIR::Constant::make_Const({e2.p.clone()}); ), - (ItemAddr, return ::MIR::Constant(e2.clone()); ) + (Const, return ::MIR::Constant::make_Const({box$(e2.p->clone())}); ), + (ItemAddr, return ::MIR::Constant(box$(e2->clone())); ) ) throw ""; } diff --git a/src/mir/mir.hpp b/src/mir/mir.hpp index 7100d4aa..c24aac51 100644 --- a/src/mir/mir.hpp +++ b/src/mir/mir.hpp @@ -26,7 +26,21 @@ struct LValue class Storage { uintptr_t val; + static uintptr_t MAX_ARG = (1 << 30) - 1; // max value of 30 bits public: + Storage(const Storage&) = delete; + Storage& operator=(const Storage&) = delete; + Storage(Storage&& x) + :val(x.val) + { + x.val = 0; + } + Storage& operator=(Storage&& x) + { + this->~Storage(); + this->val = x.val; + x.val = 0; + } ~Storage() { if( is_Static() ) { @@ -34,32 +48,64 @@ struct LValue val = 0; } } + + static Storage new_Return() { return Storage { MAX_ARG << 2 }; } + static Storage new_Argument(unsigned idx) { assert(idx < MAX_ARG); return Storage { idx << 2 }; ) + static Storage new_Local(unsigned idx) { assert(idx <= MAX_ARG); return Storage { (idx << 2) | 1 } }; + static Storage new_Static(::HIR::Path p) { + ::HIR::Path* ptr = new ::HIR::Path(::std::move(p)); + return Storage { static_cast(ptr) | 2; } + } + + bool is_Return() const { return val == (MAX_ARG << 2) /*&& (val & 3) == 0*/; } bool is_Argument() const { return val != (MAX_ARG << 2) && (val & 3) == 0; } - bool is_Return() const { return val == (MAX_ARG << 2); } - bool is_Local() const { return (val & 3) == 1; } - bool is_Static() const { return (val & 3) == 2; } + bool is_Local() const { return (val & 3) == 1; } + bool is_Static() const { return (val & 3) == 2; } + // No as_Return + unsigned as_Argument() const { assert(is_Argument()); return val >> 2; } + unsigned as_Local() const { assert(is_Local()); return val >> 2; } const ::HIR::Path& as_Static() const { assert(is_Static()); return *reinterpret_cast(val & ~3u); } }; class Wrapper { uintptr_t val; public: - bool is_Deref() const { return (val & 3) == 0; } + static Wrapper new_Deref() { return Wrapper { 0 }; } + static Wrapepr new_Field (unsigned idx) { return Wrapper { (idx << 2) | 1 }; } + static Wrapepr new_Downcast(unsigned idx) { return Wrapper { (idx << 2) | 2 }; } + static Wrapepr new_Index (unsigned idx) { return Wrapper { (idx << 2) | 3 }; } + + bool is_Deref () const { return (val & 3) == 0; } // Stores the field index - bool is_Field() const { return (val & 3) == 1; } + bool is_Field () const { return (val & 3) == 1; } // Stores the variant index bool is_Downcast() const { return (val & 3) == 2; } // Stores a Local index - bool is_Index() const { return (val & 3) == 3; } + bool is_Index () const { return (val & 3) == 3; } + // no as_Deref() const unsigned as_Field() const { assert(is_Field()); return (val >> 2); } + const unsigned as_Downcast() const { assert(is_Downcast()); return (val >> 2); } + // TODO: Should this return a LValue? const unsigned as_Index() const { assert(is_Index()); return (val >> 2); } }; Storage m_root; ::std::vector m_wrappers; + static LValue new_Return() { return LValue { Storage::new_Return(), {} }; } + static LValue new_Argument(unsigned idx) { return LValue { Storage::new_Argument(idx), {} }; } + static LValue new_Local(unsigned idx) { return LValue { Storage::new_Local(idx), {} }; } + static LValue new_Static(::HIR::Path p) { return LValue { Storage::new_Static(::std::move(p)), {} }; } + + static LValue new_Deref(LValue lv) { lv.m_wrappers.push_back(Wrapper::new_Deref()); } + static LValue new_Field(LValue lv, unsigned idx) { lv.m_wrappers.push_back(Wrapper::new_Field(idx)); } + static LValue new_Downcast(LValue lv, unsigned idx) { lv.m_wrappers.push_back(Wrapper::new_Downcast(idx)); } + static LValue new_Index(LValue lv, unsigned local_idx) { lv.m_wrappers.push_back(Wrapper::new_Index(local_idx)); } + + LValue monomorphise(const MonomorphState& ms, unsigned local_offset=0); + //LValue monomorphise(const TransParams& ms, unsigned local_offset=0); LValue clone() const; class Ref @@ -159,11 +205,10 @@ TAGGED_UNION_EX(Constant, (), Int, ( }), (Bytes, ::std::vector< ::std::uint8_t>), // Byte string (StaticString, ::std::string), // String - // TODO: Should these ::HIR::Path structures be behind pointers? - // - HIR::Path is ~11 words long, without it MIR::Constant is 4 instead of 12 - // - MIR::Param is quite common, potential large space saving. - (Const, struct { ::HIR::Path p; }), // `const` - (ItemAddr, ::HIR::Path) // address of a value + // NOTE: These are behind pointers to save inline space (HIR::Path is ~11 + // words, compared to 4 for MIR::Constant without it) + (Const, struct { ::std::unique_ptr<::HIR::Path> p; }), // `const` + (ItemAddr, ::std::unique_ptr<::HIR::Path>) // address of a value ), (), (), ( friend ::std::ostream& operator<<(::std::ostream& os, const Constant& v); ::Ordering ord(const Constant& b) const; diff --git a/src/mir/optimise.cpp b/src/mir/optimise.cpp index 7c284546..a45b1c05 100644 --- a/src/mir/optimise.cpp +++ b/src/mir/optimise.cpp @@ -1213,10 +1213,10 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool (Bytes, return ::MIR::Constant(ce);), (StaticString, return ::MIR::Constant(ce);), (Const, - return ::MIR::Constant::make_Const({ this->monomorph(ce.p) }); + return ::MIR::Constant::make_Const({ box$(this->monomorph(*ce.p)) }); ), (ItemAddr, - return ::MIR::Constant::make_ItemAddr(this->monomorph(ce)); + return ::MIR::Constant::make_ItemAddr(box$(this->monomorph(*ce))); ) ) throw ""; diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 08b4f2de..d238a523 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -5743,7 +5743,7 @@ namespace { (Const, // TODO: This should have been eliminated? ("MIR Cleanup" should have removed all inline Const references) ::HIR::TypeRef ty; - const auto& lit = get_literal_for_const(c.p, ty); + const auto& lit = get_literal_for_const(*c.p, ty); if(lit.is_Integer() || lit.is_Float()) { emit_literal(ty, lit, {}); @@ -5764,7 +5764,7 @@ namespace { } ), (ItemAddr, - TU_MATCHA( (c.m_data), (pe), + TU_MATCHA( (c->m_data), (pe), (Generic, if( pe.m_path.m_components.size() > 1 && m_crate.get_typeitem_by_path(sp, pe.m_path, false, true).is_Enum() ) ; @@ -5781,7 +5781,7 @@ namespace { } ), (UfcsUnknown, - MIR_BUG(*m_mir_res, "UfcsUnknown in trans " << c); + MIR_BUG(*m_mir_res, "UfcsUnknown in trans " << *c); ), (UfcsInherent, // TODO: If the target is a function, don't emit the & @@ -5792,7 +5792,7 @@ namespace { m_of << "&"; ) ) - m_of << Trans_Mangle(c); + m_of << Trans_Mangle(*c); ) ) } diff --git a/src/trans/codegen_mmir.cpp b/src/trans/codegen_mmir.cpp index 4867cf6f..51b8aac3 100644 --- a/src/trans/codegen_mmir.cpp +++ b/src/trans/codegen_mmir.cpp @@ -104,7 +104,7 @@ namespace os << " " << v.t; } break; TU_ARM(e, ItemAddr, v) { - os << "ADDROF " << v; + os << "ADDROF " << *v; } break; default: os << e; diff --git a/src/trans/enumerate.cpp b/src/trans/enumerate.cpp index 00b938ff..934f40a2 100644 --- a/src/trans/enumerate.cpp +++ b/src/trans/enumerate.cpp @@ -1541,10 +1541,10 @@ void Trans_Enumerate_FillFrom_MIR_Constant(EnumState& state, const ::MIR::Consta (StaticString, ), // String (Const, // - Check if this constant has a value of Defer - Trans_Enumerate_FillFrom_Path(state, ce.p, pp); + Trans_Enumerate_FillFrom_Path(state, *ce.p, pp); ), (ItemAddr, - Trans_Enumerate_FillFrom_Path(state, ce, pp); + Trans_Enumerate_FillFrom_Path(state, *ce, pp); ) ) } diff --git a/src/trans/monomorphise.cpp b/src/trans/monomorphise.cpp index cf101443..50924e2f 100644 --- a/src/trans/monomorphise.cpp +++ b/src/trans/monomorphise.cpp @@ -71,15 +71,15 @@ namespace { ), (Const, return ::MIR::Constant::make_Const({ - params.monomorph(resolve, ce.p) + box$(params.monomorph(resolve, *ce.p)) }); ), (ItemAddr, - auto p = params.monomorph(resolve, ce); + auto p = params.monomorph(resolve, *ce); // TODO: If this is a pointer to a function on a trait object, replace with the address loaded from the vtable. // - Requires creating a new temporary for the vtable pointer. // - Also requires knowing what the receiver is. - return ::MIR::Constant( mv$(p) ); + return ::MIR::Constant( box$(p) ); ) ) throw ""; -- cgit v1.2.3 From 1f432b862329d71eaaf53110edb1c4a31e390f2c Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 5 May 2019 17:05:03 +0800 Subject: Typecheck Expressions - Permanently enable match ergonomics --- src/hir_typeck/expr_cs.cpp | 117 ++++++++++++++++++++------------------------- 1 file changed, 53 insertions(+), 64 deletions(-) diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index a8fa2870..b9cfb0b2 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -812,24 +812,18 @@ namespace { { TRACE_FUNCTION_F(&node << " match ..."); -#if 1 - const auto& val_type = node.m_value->m_res_type; - { - auto _ = this->push_inner_coerce_scoped(true); - this->context.add_ivars(node.m_value->m_res_type); - - // TODO: If a coercion point (and ivar for the value) is placed here, it will allow `match &string { "..." ... }` - node.m_value->visit( *this ); - } -#else auto val_type = this->context.m_ivars.new_ivar_tr(); + { auto _ = this->push_inner_coerce_scoped(true); this->context.add_ivars(node.m_value->m_res_type); + node.m_value->visit( *this ); - this->context.equate_types_coerce( node.span(), val_type, node.m_value ); + // TODO: If a coercion point (and ivar for the value) is placed here, it will allow `match &string { "..." ... }` + // - But, this can break some parts of inferrence + this->context.equate_types( node.span(), val_type, node.m_value->m_res_type ); + //this->context.equate_types_coerce( node.span(), val_type, node.m_value ); } -#endif for(auto& arm : node.m_arms) { @@ -3961,7 +3955,7 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T // NOTE: Even if the top-level is a binding, and even if the top-level type is fully known, match ergonomics // still applies. - if( TARGETVER_1_29 && ! H2::has_ref_or_borrow(sp, pat) ) { + if( TARGETVER_1_29 ) { //&& ! H2::has_ref_or_borrow(sp, pat) ) { // There's not a `&` or `ref` in the pattern, and we're targeting 1.29 // - Run the match ergonomics handler // TODO: Default binding mode can be overridden back to "move" with `mut` @@ -4132,8 +4126,6 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T { pattern.m_binding.m_type = binding_mode; } - unsigned n_deref = 0; - const auto* type_p = &type; ::HIR::TypeRef tmp; const ::HIR::TypeRef* binding_type = nullptr; switch(pattern.m_binding.m_type) @@ -4143,30 +4135,17 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T break; case ::HIR::PatternBinding::Type::MutRef: // NOTE: Needs to deref and borrow to get just `&mut T` (where T isn't a &mut T) - //while( TU_TEST1(type_p->m_data, Borrow, .type >= ::HIR::BorrowType::Unique) ) - //{ - // n_deref ++; - // type_p = &context.m_ivars.get_type(*type_p->m_data.as_Borrow().inner); - //} - DEBUG(n_deref << " from " << type << " to " << *type_p); - binding_type = &(tmp = ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Unique, type_p->clone())); + binding_type = &(tmp = ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Unique, type.clone())); break; case ::HIR::PatternBinding::Type::Ref: // NOTE: Needs to deref and borrow to get just `&mut T` (where T isn't a &mut T) - //while( type_p->m_data.is_Borrow() ) - //{ - // n_deref ++; - // type_p = &context.m_ivars.get_type(*type_p->m_data.as_Borrow().inner); - //} - DEBUG(n_deref << " from " << type << " to " << *type_p); - binding_type = &(tmp = ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, type_p->clone())); + binding_type = &(tmp = ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, type.clone())); break; default: TODO(sp, "Assign variable type using mode " << (int)binding_mode << " and " << type); } assert(binding_type); context.equate_types(sp, context.get_var(sp, pattern.m_binding.m_slot), *binding_type); - pattern.m_binding.m_implicit_deref_count = n_deref; } // For `_` patterns, there's nothing to match, so they just succeed with no derefs @@ -4175,6 +4154,16 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T return true; } + if( auto* pe = pattern.m_data.opt_Ref() ) + { + // Require a &-ptr (hard requirement), then visit sub-pattern + auto inner_ty = context.m_ivars.new_ivar_tr(); + auto new_ty = ::HIR::TypeRef::new_borrow( pe->type, inner_ty.clone() ); + context.equate_types(sp, type, new_ty); + + return this->revisit_inner( context, *pe->sub, inner_ty, binding_mode ); + } + // If the type is a borrow, then count derefs required for the borrow // - If the first non-borrow inner is an ivar, return false unsigned n_deref = 0; @@ -4590,68 +4579,68 @@ void Context::handle_pattern(const Span& sp, ::HIR::Pattern& pat, const ::HIR::T // - I'll leave the option open, MIR generation should handle cases where there's multiple borrows // or moves. } - TU_MATCHA( (pat.m_data), (e), - (Any, - ), - (Value, - ), - (Range, - ), - (Box, + TU_MATCH_HDRA( (pat.m_data), { ) + TU_ARMA(Any, e) { + } + TU_ARMA(Value, e) { + } + TU_ARMA(Range, e) { + } + TU_ARMA(Box, e) { create_bindings(sp, context, *e.sub); - ), - (Ref, + } + TU_ARMA(Ref, e) { create_bindings(sp, context, *e.sub); - ), - (Tuple, + } + TU_ARMA(Tuple, e) { for(auto& subpat : e.sub_patterns) create_bindings(sp, context, subpat); - ), - (SplitTuple, + } + TU_ARMA(SplitTuple, e) { for(auto& subpat : e.leading) { create_bindings(sp, context, subpat); } for(auto& subpat : e.trailing) { create_bindings(sp, context, subpat); } - ), - (Slice, + } + TU_ARMA(Slice, e) { for(auto& sub : e.sub_patterns) create_bindings(sp, context, sub); - ), - (SplitSlice, + } + TU_ARMA(SplitSlice, e) { for(auto& sub : e.leading) create_bindings(sp, context, sub); - // TODO: extra_bind if( e.extra_bind.is_valid() ) { - TODO(sp, "Handle split slice binding binding in match ergonomics"); + const auto& pb = e.extra_bind; + context.add_var( sp, pb.m_slot, pb.m_name, context.m_ivars.new_ivar_tr() ); } for(auto& sub : e.trailing) create_bindings(sp, context, sub); - ), + } // - Enums/Structs - (StructValue, - ), - (StructTuple, + TU_ARMA(StructValue, e) { + } + TU_ARMA(StructTuple, e) { for(auto& subpat : e.sub_patterns) create_bindings(sp, context, subpat); - ), - (Struct, + } + TU_ARMA(Struct, e) { for(auto& field_pat : e.sub_patterns) create_bindings(sp, context, field_pat.second); - ), - (EnumValue, - ), - (EnumTuple, + } + TU_ARMA(EnumValue, e) { + } + TU_ARMA(EnumTuple, e) { for(auto& subpat : e.sub_patterns) create_bindings(sp, context, subpat); - ), - (EnumStruct, + } + TU_ARMA(EnumStruct, e) { for(auto& field_pat : e.sub_patterns) create_bindings(sp, context, field_pat.second); - ) - ) + } + } } }; // - Create variables, assigning new ivars for all of them. -- cgit v1.2.3 From 6cc802dfbd44a6f1f76cc5ae76227f1f54cf9f75 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 5 May 2019 17:37:04 +0800 Subject: MMIR - Fix a TODO around pointers to strings --- src/trans/codegen_mmir.cpp | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/src/trans/codegen_mmir.cpp b/src/trans/codegen_mmir.cpp index 51b8aac3..032e6afa 100644 --- a/src/trans/codegen_mmir.cpp +++ b/src/trans/codegen_mmir.cpp @@ -648,6 +648,13 @@ namespace size_t len; const ::HIR::Path* p; ::std::string bytes; + + static Reloc new_named(size_t ofs, size_t len, const ::HIR::Path* p) { + return Reloc { ofs, len, p, "" }; + } + static Reloc new_bytes(size_t ofs, size_t len, ::std::string bytes) { + return Reloc { ofs, len, nullptr, ::std::move(bytes) }; + } }; void emit_str_byte(uint8_t b) { if( b == 0 ) { @@ -842,7 +849,7 @@ namespace const auto& s = lit.as_String(); putsize(0); putsize(s.size()); - out_relocations.push_back(Reloc { base_ofs, 8, nullptr, s }); + out_relocations.push_back(Reloc::new_bytes(base_ofs, 8, s)); break; } // fall @@ -851,35 +858,41 @@ namespace size_t ity_size, ity_align; Target_GetSizeAndAlignOf(sp, m_resolve, ity, ity_size, ity_align); bool is_unsized = (ity_size == SIZE_MAX); - if( lit.is_BorrowPath() ) - { + + TU_MATCH_HDRA( (lit), { ) + TU_ARMA(BorrowPath, le) { putsize(0); - out_relocations.push_back(Reloc { base_ofs, 8, &lit.as_BorrowPath(), "" }); + out_relocations.push_back(Reloc::new_named(base_ofs, 8, &le)); if( is_unsized ) { // TODO: Get the size of the pointed-to array // OR: Find out the source item type and the target trait. putsize(0); } - break; - } - else if( lit.is_Integer() ) - { - ASSERT_BUG(sp, lit.as_Integer() == 0, "Pointer from integer not 0"); + } + TU_ARMA(Integer, le) { + ASSERT_BUG(sp, le == 0, "Pointer from integer not 0"); ASSERT_BUG(sp, ty.m_data.is_Pointer(), "Borrow from integer"); putsize(0); if( is_unsized ) { putsize(0); } - break; + } + TU_ARMA(String, le) { + const auto& s = lit.as_String(); + putsize(0); + putsize(s.size()); + out_relocations.push_back(Reloc::new_bytes(base_ofs, 8, s)); + } + break; default: + TODO(sp, "Emit a pointer - " << ty << " from literal " << lit); } - TODO(sp, "Pointers - " << ty << " w/ " << lit); } break; case ::HIR::TypeRef::Data::TAG_Function: ASSERT_BUG(sp, lit.is_BorrowPath(), ty << " not Literal::BorrowPath - " << lit); putsize(0); - out_relocations.push_back(Reloc { base_ofs, 8, &lit.as_BorrowPath(), "" }); + out_relocations.push_back(Reloc::new_named(base_ofs, 8, &lit.as_BorrowPath())); break; TU_ARM(ty.m_data, Array, te) { // What about byte strings? -- cgit v1.2.3 From 7a5cd835703fdfac0634b975392f915e0230c2a7 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 5 May 2019 20:12:58 +0800 Subject: parse/expand/resolve - `macro` macros use their own module as the resolve root --- src/ast/ast.cpp | 3 +++ src/ast/ast.hpp | 1 + src/expand/mod.cpp | 3 +++ src/hir/from_ast.cpp | 2 ++ src/ident.cpp | 5 ++++- src/include/ident.hpp | 20 ++++++++++++++++++- src/macro_rules/eval.cpp | 1 + src/macro_rules/macro_rules.hpp | 4 ++++ src/macro_rules/parse.cpp | 20 +++++++++++-------- src/parse/paths.cpp | 1 + src/parse/root.cpp | 43 +++++++++++++++++++++-------------------- src/resolve/absolute.cpp | 27 ++++++++++++++++++++++++++ src/resolve/index.cpp | 4 ++++ 13 files changed, 103 insertions(+), 31 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 9893e87f..03257fc6 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -315,6 +315,9 @@ Item Item::clone() const (MacroInv, TODO(this->span, "Clone on Item::MacroInv"); ), + (Macro, + TODO(this->span, "Clone on Item::Macro"); + ), (Use, return AST::Item(e.clone()); ), diff --git a/src/ast/ast.hpp b/src/ast/ast.hpp index 43a0e027..f6f97fce 100644 --- a/src/ast/ast.hpp +++ b/src/ast/ast.hpp @@ -607,6 +607,7 @@ TAGGED_UNION_EX(Item, (), None, (Impl, Impl), (NegImpl, ImplDef), + (Macro, MacroRulesPtr), (Module, Module), (Crate, struct { ::std::string name; diff --git a/src/expand/mod.cpp b/src/expand/mod.cpp index fd851c89..bc51e1ff 100644 --- a/src/expand/mod.cpp +++ b/src/expand/mod.cpp @@ -1113,6 +1113,9 @@ void Expand_Mod(::AST::Crate& crate, LList modstack, ::AST:: } dat.as_MacroInv() = mv$(mi_owned); } + TU_ARMA(Macro, e) { + mod.add_macro(i.is_pub, i.name, mv$(e)); + } TU_ARMA(Use, e) { // No inner expand. } diff --git a/src/hir/from_ast.cpp b/src/hir/from_ast.cpp index af6bc9cb..2393cadd 100644 --- a/src/hir/from_ast.cpp +++ b/src/hir/from_ast.cpp @@ -1433,6 +1433,8 @@ void _add_mod_val_item(::HIR::Module& mod, ::std::string name, ::HIR::Publicity TU_MATCH(::AST::Item, (item.data), (e), (None, ), + (Macro, + ), (MacroInv, // Valid. //BUG(sp, "Stray macro invocation in " << path); diff --git a/src/ident.cpp b/src/ident.cpp index da029e21..63fe57ed 100644 --- a/src/ident.cpp +++ b/src/ident.cpp @@ -34,7 +34,10 @@ bool Ident::Hygiene::is_visible(const Hygiene& src) const } ::std::ostream& operator<<(::std::ostream& os, const Ident::Hygiene& x) { - os << "{" << x.contexts << "}"; + os << "{" << x.contexts; + if( x.search_module ) + os << " " << x.search_module->ents; + os << "}"; return os; } diff --git a/src/include/ident.hpp b/src/include/ident.hpp index b9a6dec5..ec42c582 100644 --- a/src/include/ident.hpp +++ b/src/include/ident.hpp @@ -8,14 +8,21 @@ #pragma once #include #include +#include struct Ident { + struct ModPath + { + //::std::vector ents; + ::std::vector<::std::string> ents; + }; class Hygiene { static unsigned g_next_scope; ::std::vector contexts; + ::std::shared_ptr search_module; Hygiene(unsigned int index): contexts({index}) @@ -32,6 +39,7 @@ struct Ident static Hygiene new_scope_chained(const Hygiene& parent) { Hygiene rv; + rv.search_module = parent.search_module; rv.contexts.reserve( parent.contexts.size() + 1 ); rv.contexts.insert( rv.contexts.begin(), parent.contexts.begin(), parent.contexts.end() ); rv.contexts.push_back( ++g_next_scope ); @@ -45,12 +53,22 @@ struct Ident return rv; } + bool has_mod_path() const { + return this->search_module != 0; + } + const ModPath& mod_path() const { + return *this->search_module; + } + void set_mod_path(ModPath p) { + this->search_module.reset( new ModPath(::std::move(p)) ); + } + Hygiene(Hygiene&& x) = default; Hygiene(const Hygiene& x) = default; Hygiene& operator=(Hygiene&& x) = default; Hygiene& operator=(const Hygiene& x) = default; - // Returns true if an ident with hygine `souce` can see an ident with this hygine + // Returns true if an ident with hygine `source` can see an ident with this hygine bool is_visible(const Hygiene& source) const; //bool operator==(const Hygiene& x) const { return scope_index == x.scope_index; } //bool operator!=(const Hygiene& x) const { return scope_index != x.scope_index; } diff --git a/src/macro_rules/eval.cpp b/src/macro_rules/eval.cpp index 9caff7b8..c40eb810 100644 --- a/src/macro_rules/eval.cpp +++ b/src/macro_rules/eval.cpp @@ -502,6 +502,7 @@ InterpolatedFragment Macro_HandlePatternCap(TokenStream& lex, MacroPatEnt::Type ::std::unique_ptr Macro_InvokeRules(const char *name, const MacroRules& rules, const Span& sp, TokenTree input, AST::Module& mod) { TRACE_FUNCTION_F("'" << name << "', " << input); + DEBUG("rules.m_hygiene = " << rules.m_hygiene); ParameterMappings bound_tts; unsigned int rule_index = Macro_InvokeRules_MatchPattern(sp, rules, mv$(input), mod, bound_tts); diff --git a/src/macro_rules/macro_rules.hpp b/src/macro_rules/macro_rules.hpp index 02b302d8..9e408fd5 100644 --- a/src/macro_rules/macro_rules.hpp +++ b/src/macro_rules/macro_rules.hpp @@ -181,4 +181,8 @@ public: extern ::std::unique_ptr Macro_InvokeRules(const char *name, const MacroRules& rules, const Span& sp, TokenTree input, AST::Module& mod); extern MacroRulesPtr Parse_MacroRules(TokenStream& lex); +extern ::std::vector Parse_MacroRules_Pat(TokenStream& lex, enum eTokenType open, enum eTokenType close, ::std::vector< ::std::string>& names); +extern ::std::vector Parse_MacroRules_Cont(TokenStream& lex, enum eTokenType open, enum eTokenType close, const ::std::vector< ::std::string>& var_names, ::std::map* var_set_ptr=nullptr); +extern MacroRulesArm Parse_MacroRules_MakeArm(Span pat_sp, ::std::vector pattern, ::std::vector contents); + #endif // MACROS_HPP_INCLUDED diff --git a/src/macro_rules/parse.cpp b/src/macro_rules/parse.cpp index 98163998..4bd8a577 100644 --- a/src/macro_rules/parse.cpp +++ b/src/macro_rules/parse.cpp @@ -40,6 +40,7 @@ public: int depth = 0; while( GET_TOK(tok, lex) != close || depth > 0 ) { + DEBUG("tok = " << tok); if( tok.type() == open ) { depth ++; @@ -142,7 +143,7 @@ public: TokenStream& lex, enum eTokenType open, enum eTokenType close, const ::std::vector< ::std::string>& var_names, - ::std::map* var_set_ptr=nullptr + ::std::map* var_set_ptr/*=nullptr*/ ) { TRACE_FUNCTION; @@ -310,6 +311,15 @@ void enumerate_names(const ::std::vector& pats, ::std::vector< ::st } } +MacroRulesArm Parse_MacroRules_MakeArm(Span pat_sp, ::std::vector pattern, ::std::vector contents) +{ + // - Convert the rule into an instruction stream + auto rule_sequence = macro_pattern_to_simple(pat_sp, pattern); + auto arm = MacroRulesArm( mv$(rule_sequence), mv$(contents) ); + enumerate_names(pattern, arm.m_param_names); + return arm; +} + /// Parse an entire macro_rules! block into a format that exec.cpp can use MacroRulesPtr Parse_MacroRules(TokenStream& lex) { @@ -336,13 +346,7 @@ MacroRulesPtr Parse_MacroRules(TokenStream& lex) // Re-parse the patterns into a unified form for(auto& rule : rules) { - // TODO: Transform the pattern into a DFA or similar here (seekable instruction stream?) - - auto rule_sequence = macro_pattern_to_simple(rule.m_pat_span, rule.m_pattern); - MacroRulesArm arm = MacroRulesArm( mv$(rule_sequence), mv$(rule.m_contents) ); - enumerate_names(rule.m_pattern, arm.m_param_names); - - rule_arms.push_back( mv$(arm) ); + rule_arms.push_back( Parse_MacroRules_MakeArm(rule.m_pat_span, mv$(rule.m_pattern), mv$(rule.m_contents)) ); } auto rv = new MacroRules( ); diff --git a/src/parse/paths.cpp b/src/parse/paths.cpp index cb704f85..5c99e049 100644 --- a/src/parse/paths.cpp +++ b/src/parse/paths.cpp @@ -103,6 +103,7 @@ AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generi // TODO: TOK_INTERPOLATED_IDENT? GET_CHECK_TOK(tok, lex, TOK_IDENT); auto hygine = lex.getHygiene(); + DEBUG("hygine = " << hygine); PUTBACK(tok, lex); return AST::Path(AST::Path::TagRelative(), mv$(hygine), Parse_PathNodes(lex, generic_mode)); } diff --git a/src/parse/root.cpp b/src/parse/root.cpp index c055c190..b0c37a21 100644 --- a/src/parse/root.cpp +++ b/src/parse/root.cpp @@ -20,6 +20,7 @@ #include "lex.hpp" // New file lexer #include #include +#include template Spanned get_spanned(TokenStream& lex, ::std::function f) { @@ -1931,31 +1932,31 @@ namespace { GET_TOK(tok, lex); throw ParseError::Unexpected(lex, tok); } + DEBUG("name = " << name); - //::std::vector< ::std::string> names; - //auto arm_pat = Parse_MacroRules_Pat(lex, TOK_PAREN_OPEN, TOK_PAREN_CLOSE, names); - auto args_tt = Parse_TT(lex, false); - if( lex.lookahead(0) != TOK_BRACE_OPEN ) + ::std::vector< ::std::string> names; + auto ps = lex.start_span(); + GET_CHECK_TOK(tok, lex, TOK_PAREN_OPEN); + auto arm_pat = Parse_MacroRules_Pat(lex, TOK_PAREN_OPEN, TOK_PAREN_CLOSE, names); + auto pat_span = lex.end_span(ps); + GET_CHECK_TOK(tok, lex, TOK_BRACE_OPEN); + // TODO: Pass a flag that annotates all idents with the current module? + auto body = Parse_MacroRules_Cont(lex, TOK_BRACE_OPEN, TOK_BRACE_CLOSE, names); + + auto mr = new MacroRules( ); + mr->m_hygiene = lex.getHygiene(); { - GET_TOK(tok, lex); - throw ParseError::Unexpected(lex, tok); + Ident::ModPath mp; + for(const auto& node : mod_path.nodes()) + { + mp.ents.push_back(node.name()); + } + mr->m_hygiene.set_mod_path(::std::move(mp)); } - //auto body = Parse_MacroRules_Cont(lex, TOK_BRACE_OPEN, TOK_BRACE_CLOSE, names); - auto body_tt = Parse_TT(lex, false); - - // TODO: Invoke the macro_rules parsers here - // - Could also do the same level of parsing when `macro_rules! foo {` is seen (i.e. parse macros at parse - // time, instead of during expand). - // - That would simplify some of the expand logic... + mr->m_rules.push_back(Parse_MacroRules_MakeArm(pat_span, ::std::move(arm_pat), ::std::move(body))); - // Lazy option: create a TT - ::std::vector out; - out.push_back(mv$(args_tt)); - out.push_back(TokenTree( Token(TOK_FATARROW) )); - out.push_back(mv$(body_tt)); - - item_name = ""; - item_data = ::AST::Item( AST::MacroInvocation(lex.end_span(ps), "macro_rules", name, TokenTree({}, mv$(out))) ); + item_name = name; + item_data = ::AST::Item( MacroRulesPtr(mr) ); } else { diff --git a/src/resolve/absolute.cpp b/src/resolve/absolute.cpp index 95e01d18..c2dedfcb 100644 --- a/src/resolve/absolute.cpp +++ b/src/resolve/absolute.cpp @@ -424,6 +424,29 @@ namespace } AST::Path lookup_opt(const ::std::string& name, const Ident::Hygiene& src_context, LookupMode mode) const { DEBUG("name=" << name <<", src_context=" << src_context); + // NOTE: src_context may provide a module to search + if( src_context.has_mod_path() ) + { + DEBUG(src_context.mod_path().ents); + const AST::Module* mod = &m_crate.root_module(); + for(const auto& node : src_context.mod_path().ents) + { + const AST::Module* next = nullptr; + for(const auto& i : mod->items()) + { + if( i.name == node ) { + next = &i.data.as_Module(); + break; + } + } + assert(next); + mod = next; + } + ::AST::Path rv; + if( this->lookup_in_mod(*mod, name, mode, rv) ) { + return rv; + } + } for(auto it = m_name_context.rbegin(); it != m_name_context.rend(); ++ it) { TU_MATCH(Ent, (*it), (e), @@ -2012,6 +2035,7 @@ void Resolve_Absolute_ImplItems(Context& item_context, ::AST::NamedList< ::AST: (ExternBlock, BUG(i.data.span, "Resolve_Absolute_ImplItems - " << i.data.tag_str());), (Impl, BUG(i.data.span, "Resolve_Absolute_ImplItems - " << i.data.tag_str());), (NegImpl, BUG(i.data.span, "Resolve_Absolute_ImplItems - " << i.data.tag_str());), + (Macro, BUG(i.data.span, "Resolve_Absolute_ImplItems - " << i.data.tag_str());), (Use, BUG(i.data.span, "Resolve_Absolute_ImplItems - Use");), (Module, BUG(i.data.span, "Resolve_Absolute_ImplItems - Module");), (Crate , BUG(i.data.span, "Resolve_Absolute_ImplItems - Crate");), @@ -2056,6 +2080,7 @@ void Resolve_Absolute_ImplItems(Context& item_context, ::std::vector< ::AST::Im (Impl , BUG(i.data->span, "Resolve_Absolute_ImplItems - " << i.data->tag_str());), (NegImpl, BUG(i.data->span, "Resolve_Absolute_ImplItems - " << i.data->tag_str());), (ExternBlock, BUG(i.data->span, "Resolve_Absolute_ImplItems - " << i.data->tag_str());), + (Macro , BUG(i.data->span, "Resolve_Absolute_ImplItems - " << i.data->tag_str());), (Use , BUG(i.data->span, "Resolve_Absolute_ImplItems - " << i.data->tag_str());), (Module, BUG(i.data->span, "Resolve_Absolute_ImplItems - " << i.data->tag_str());), (Crate , BUG(i.data->span, "Resolve_Absolute_ImplItems - " << i.data->tag_str());), @@ -2221,6 +2246,8 @@ void Resolve_Absolute_Mod( Context item_context, ::AST::Module& mod ) ), (Use, ), + (Macro, + ), (ExternBlock, for(auto& i2 : e.items()) { diff --git a/src/resolve/index.cpp b/src/resolve/index.cpp index f38219ef..43182faf 100644 --- a/src/resolve/index.cpp +++ b/src/resolve/index.cpp @@ -121,6 +121,10 @@ void Resolve_Index_Module_Base(const AST::Crate& crate, AST::Module& mod) (NegImpl, ), + (Macro, + // TODO: Add to a macro list + ), + (Use, // Skip for now ), -- cgit v1.2.3 From 203862df03f8ee9f49ab704063bd28523f13ba2d Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 5 May 2019 21:56:49 +0800 Subject: LoadCrates - Search for crates with matching names (instead of needing a perfect filename match) --- src/ast/crate.cpp | 64 +++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 50 insertions(+), 14 deletions(-) diff --git a/src/ast/crate.cpp b/src/ast/crate.cpp index 69db669e..5717cbdb 100644 --- a/src/ast/crate.cpp +++ b/src/ast/crate.cpp @@ -12,6 +12,7 @@ #include // HIR::Crate #include // HIR_Deserialise #include +#include ::std::vector<::std::string> AST::g_crate_load_dirs = { }; ::std::map<::std::string, ::std::string> AST::g_crate_overrides; @@ -121,31 +122,66 @@ void Crate::load_externs() ERROR(sp, E0000, "Unable to open crate '" << name << "' at path " << path); } } - else + else if( basename != "" ) { // Search a list of load paths for the crate for(const auto& p : g_crate_load_dirs) { - if( basename == "" ) - { - path = p + "/lib" + name + ".hir"; - // TODO: Search for `p+"/lib"+name+"-*.hir" (which would match e.g. libnum-0.11.hir) - } - else - { - path = p + "/" + basename; - } + path = p + "/" + basename; if( ::std::ifstream(path).good() ) { break ; } } if( !::std::ifstream(path).good() ) { - if( basename.empty() ) - ERROR(sp, E0000, "Unable to locate crate '" << name << "' in search directories"); - else - ERROR(sp, E0000, "Unable to locate crate '" << name << "' with filename " << basename << " in search directories"); + ERROR(sp, E0000, "Unable to locate crate '" << name << "' with filename " << basename << " in search directories"); + } + } + else + { + ::std::vector<::std::string> paths; + auto name_prefix = "lib"+name+"-"; + // Search a list of load paths for the crate + for(const auto& p : g_crate_load_dirs) + { + + path = p + "/lib" + name + ".hir"; + // TODO: Search for `p+"/lib"+name+"-*.hir" (which would match e.g. libnum-0.11.hir) + if( ::std::ifstream(path).good() ) { + paths.push_back(path); + } + path = ""; + + auto dp = opendir(p.c_str()); + if( !dp ) { + continue ; + } + struct dirent *ent; + while( (ent = readdir(dp)) != nullptr && path == "" ) + { + // AND the start is "lib"+name + size_t len = strlen(ent->d_name); + if( len <= 4 || strcmp(ent->d_name + len - 4, ".hir") != 0 ) + continue ; + + DEBUG(ent->d_name << " vs " << name_prefix); + // Check if the entry ends with .hir + if( strncmp(name_prefix.c_str(), ent->d_name, name_prefix.size()) != 0 ) + continue ; + + paths.push_back( p + "/" + ent->d_name ); + } + closedir(dp); + if( paths.size() > 0 ) + break; + } + if( paths.size() > 1 ) { + ERROR(sp, E0000, "Multiple options for crate '" << name << "' in search directories - " << paths); + } + if( paths.size() == 0 || !::std::ifstream(paths.front()).good() ) { + ERROR(sp, E0000, "Unable to locate crate '" << name << "' in search directories"); } + path = paths.front(); } // NOTE: Creating `ExternCrate` loads the crate from the specified path -- cgit v1.2.3 From 92afcb37de80802d91164d9f1cd307c6964d1811 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 5 May 2019 21:58:06 +0800 Subject: HIR Expand Closures - Run on constants --- src/hir/from_ast_expr.cpp | 6 ++++ src/hir_expand/closures.cpp | 71 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 75 insertions(+), 2 deletions(-) diff --git a/src/hir/from_ast_expr.cpp b/src/hir/from_ast_expr.cpp index 7d676bf8..fdb2b867 100644 --- a/src/hir/from_ast_expr.cpp +++ b/src/hir/from_ast_expr.cpp @@ -227,6 +227,12 @@ struct LowerHIR_ExprNode_Visitor: mv$( args ) ) ); ), + (Static, + m_rv.reset( new ::HIR::ExprNode_CallValue( v.span(), + ::HIR::ExprNodeP(new ::HIR::ExprNode_PathValue( v.span(), LowerHIR_Path(v.span(), v.m_path), ::HIR::ExprNode_PathValue::STATIC )), + mv$(args) + ) ); + ), //(TypeAlias, // TODO(v.span(), "CallPath -> TupleVariant TypeAlias"); // ), diff --git a/src/hir_expand/closures.cpp b/src/hir_expand/closures.cpp index d7d476e5..ace154ff 100644 --- a/src/hir_expand/closures.cpp +++ b/src/hir_expand/closures.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include "main_bindings.hpp" namespace { @@ -1357,9 +1358,75 @@ namespace { }; } -void HIR_Expand_Closures_Expr(const ::HIR::Crate& crate, ::HIR::ExprPtr& exp) +void HIR_Expand_Closures_Expr(const ::HIR::Crate& crate_ro, ::HIR::ExprPtr& exp) { - // TODO: + Span sp; + auto& crate = const_cast<::HIR::Crate&>(crate_ro); + TRACE_FUNCTION; + + StaticTraitResolve resolve { crate }; + assert(exp); + if(exp.m_state->m_impl_generics) resolve.set_impl_generics(*exp.m_state->m_impl_generics); + if(exp.m_state->m_item_generics) resolve.set_item_generics(*exp.m_state->m_item_generics); + + const ::HIR::TypeRef* self_type = nullptr; // TODO: Need to be able to get this? + + static int closure_count = 0; + out_impls_t new_trait_impls; + new_type_cb_t new_type_cb = [&](auto s)->::HIR::SimplePath { + auto name = FMT("closure#C_" << closure_count); + closure_count += 1; + auto boxed = box$(( ::HIR::VisEnt< ::HIR::TypeItem> { ::HIR::Publicity::new_none(), ::HIR::TypeItem( mv$(s) ) } )); + crate.m_root_module.m_mod_items.insert( ::std::make_pair(name, mv$(boxed)) ); + return ::HIR::SimplePath(crate.m_crate_name, {}) + name; + }; + + { + ExprVisitor_Extract ev(resolve, self_type, exp.m_bindings, new_trait_impls, new_type_cb); + ev.visit_root( *exp ); + } + + { + ExprVisitor_Fixup fixup(crate, nullptr, [](const auto& x)->const auto&{ return x; }); + fixup.visit_root( exp ); + } + + for(auto& impl : new_trait_impls) + { + for( auto& m : impl.second.m_methods ) + { + m.second.data.m_code.m_state = ::HIR::ExprStatePtr(*exp.m_state); + m.second.data.m_code.m_state->stage = ::HIR::ExprState::Stage::Typecheck; + } + impl.second.m_src_module = exp.m_state->m_mod_path; + switch(impl.first) + { + case ::HIR::ExprNode_Closure::Class::Once: + crate.m_trait_impls.insert( ::std::make_pair(crate.get_lang_item_path(sp, "fn_once"), mv$(impl.second)) ); + break; + case ::HIR::ExprNode_Closure::Class::Mut: + crate.m_trait_impls.insert( ::std::make_pair(crate.get_lang_item_path(sp, "fn_mut" ), mv$(impl.second)) ); + break; + case ::HIR::ExprNode_Closure::Class::Shared: + crate.m_trait_impls.insert( ::std::make_pair(crate.get_lang_item_path(sp, "fn" ), mv$(impl.second)) ); + break; + case ::HIR::ExprNode_Closure::Class::NoCapture: + assert(impl.second.m_methods.size() == 1); + assert(impl.second.m_types.empty()); + assert(impl.second.m_constants.empty()); + crate.m_type_impls.push_back( ::HIR::TypeImpl { + mv$(impl.second.m_params), + mv$(impl.second.m_type), + make_map1(impl.second.m_methods.begin()->first, ::HIR::TypeImpl::VisImplEnt< ::HIR::Function> { ::HIR::Publicity::new_global(), false, mv$(impl.second.m_methods.begin()->second.data) }), + {}, + mv$(impl.second.m_src_module) + } ); + break; + case ::HIR::ExprNode_Closure::Class::Unknown: + BUG(Span(), "Encountered Unkown closure type in new impls"); + break; + } + } } void HIR_Expand_Closures(::HIR::Crate& crate) -- cgit v1.2.3 From 54ca77e36c85934706d1f1bd387228182ef09950 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Mon, 6 May 2019 21:07:46 +0800 Subject: Codegen C - Mark llvm.* shims as static --- src/trans/codegen_c.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index d238a523..fe8bf881 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -2274,7 +2274,9 @@ namespace { } else if( item.m_linkage.name.rfind("llvm.", 0) == 0 ) { + m_of << "static "; emit_function_header(p, item, params); + // TODO: Hand off to compiler-specific intrinsics m_of << " { abort(); }\n"; m_mir_res = nullptr; return ; -- cgit v1.2.3 From 4c4dd6e0120877b6a535cef62ee06795b07456d2 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Thu, 9 May 2019 22:57:28 +0800 Subject: MIR Optimise - Work around De-Temporary bug that was mis-optimising Vec::retain --- src/mir/optimise.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/mir/optimise.cpp b/src/mir/optimise.cpp index a45b1c05..b1be20a4 100644 --- a/src/mir/optimise.cpp +++ b/src/mir/optimise.cpp @@ -1411,6 +1411,12 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool return inline_happened; } +// TODO: New pass that removes useless borrows +// ``` +// _$1 = & _$0; +// (*_$1).1 = 0x0; +// ``` + // -------------------------------------------------------------------- // Replaces uses of stack slots with what they were assigned with (when // possible) @@ -1424,6 +1430,7 @@ bool MIR_Optimise_DeTemporary(::MIR::TypeResolve& state, ::MIR::Function& fcn) { auto& bb = fcn.blocks[bb_idx]; ::std::map local_assignments; // Local number -> statement index + // TODO: Keep track of what variables would invalidate a local (and compound on assignment) ::std::vector statements_to_remove; // List of statements that have to be removed // ----- Helper closures ----- @@ -1457,6 +1464,7 @@ bool MIR_Optimise_DeTemporary(::MIR::TypeResolve& state, ::MIR::Function& fcn) case ValUsage::Write: // Mutated? It's invalidated case ValUsage::Move: // Moved? Now invalid visit_mir_lvalues(src_rvalue, [&](const auto& s_lv, auto /*s_vu*/) { + //DEBUG(" " << s_lv << " ?= " << lv); if( s_lv == lv ) { DEBUG(state << "> Invalidates source of Local(" << it->first << ") - " << src_rvalue); @@ -1556,6 +1564,12 @@ bool MIR_Optimise_DeTemporary(::MIR::TypeResolve& state, ::MIR::Function& fcn) { DEBUG(state << "> Don't record, self-referrential"); } + else if( visit_mir_lvalue(stmt.as_Assign().src.as_Use(), ValUsage::Read, [&](const auto& lv, auto /*vu*/) { + return lv.is_Deref(); + }) ) + { + DEBUG(state << "> Don't record, dereference"); + } else { local_assignments.insert(::std::make_pair( stmt.as_Assign().dst.as_Local(), stmt_idx )); -- cgit v1.2.3 From fae820af151c81a40bc6b4568a199ed54e9a2ff7 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 11 May 2019 11:18:43 +0800 Subject: dump_hirfile - Extend to dump function MIR --- tools/dump_hirfile/Makefile | 2 +- tools/dump_hirfile/main.cpp | 157 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 153 insertions(+), 6 deletions(-) diff --git a/tools/dump_hirfile/Makefile b/tools/dump_hirfile/Makefile index 10fb8e81..c0ae0513 100644 --- a/tools/dump_hirfile/Makefile +++ b/tools/dump_hirfile/Makefile @@ -17,7 +17,7 @@ OBJS += hir/crate_ptr.o hir/generic_params.o hir/path.o hir/pattern.o hir/expr_p OBJS += hir/expr.o # Why is this needed? OBJS += parse/token.o parse/tokentree.o parse/tokenstream.o OBJS += ast/ast.o ast/expr.o ast/path.o ast/types.o ast/pattern.o -OBJS += mir/mir.o mir/mir_ptr.o +OBJS += mir/mir.o mir/mir_ptr.o mir/dump.o hir/visitor.o OBJS += macro_rules/mod.o LINKFLAGS := -g -lpthread -lz diff --git a/tools/dump_hirfile/main.cpp b/tools/dump_hirfile/main.cpp index df3e48df..98a92f7b 100644 --- a/tools/dump_hirfile/main.cpp +++ b/tools/dump_hirfile/main.cpp @@ -1,6 +1,9 @@ #include +#include #include #include +#include +#include // MIR_Dump_Fcn int g_debug_indent_level = 0; @@ -11,14 +14,37 @@ struct Args ::std::string infile; }; +struct Dumper +{ + struct Filters { + struct Types { + bool macros = false; + bool functions = false; + bool statics = false; + bool types = false; + } types; + bool public_only = false; + } filters; + + void dump_crate(const char* name, const ::HIR::Crate& crate) const; + void dump_module(::HIR::ItemPath ip, const ::HIR::Publicity& pub, const ::HIR::Module& mod) const; + void dump_function(::HIR::ItemPath ip, const ::HIR::Publicity& pub, const ::HIR::Function& fcn, int indent=0) const; +}; + int main(int argc, const char* argv[]) { Args args(argc, argv); + Dumper dumper; - auto hir = HIR_Deserialise(args.infile, ""); + dumper.filters.types.functions = true; + auto hir = HIR_Deserialise(args.infile, ""); + dumper.dump_crate("", *hir); +} +void Dumper::dump_crate(const char* name, const ::HIR::Crate& crate) const +{ // Dump macros - for(const auto& mac : hir->m_exported_macros) + for(const auto& mac : crate.m_exported_macros) { ::std::cout << "macro_rules! " << mac.first << "{" << std::endl; for(const auto& arm : mac.second->m_rules) @@ -53,13 +79,134 @@ int main(int argc, const char* argv[]) } } } - ::std::cout << " ) => {" << ::std::endl; - // TODO... - ::std::cout << " }" << ::std::endl; + ::std::cout << " ) => {\n"; + // TODO: Macro expansion + ::std::cout << " }\n"; + } + ::std::cout << "}\n"; + ::std::cout << ::std::endl; + } + + this->dump_module(::HIR::ItemPath(name), ::HIR::Publicity::new_global(), crate.m_root_module); + + for(const auto& i : crate.m_trait_impls) + { + auto root_ip = ::HIR::ItemPath(i.second.m_type, i.first, i.second.m_trait_args); + ::std::cout << "impl" << i.second.m_params.fmt_args() << " " << i.first << i.second.m_trait_args << " for " << i.second.m_type << "\n"; + ::std::cout << " where" << i.second.m_params.fmt_bounds() << "\n"; + ::std::cout << "{" << ::std::endl; + if( this->filters.types.functions ) + { + for(const auto& m : i.second.m_methods) + { + this->dump_function(root_ip + m.first.c_str(), ::HIR::Publicity::new_global(), m.second.data, 1); + } + } + ::std::cout << "}" << ::std::endl; + } + + for(const auto& i : crate.m_type_impls) + { + auto root_ip = ::HIR::ItemPath(i.m_type); + ::std::cout << "impl" << i.m_params.fmt_args() << " " << i.m_type << "\n"; + ::std::cout << " where" << i.m_params.fmt_bounds() << "\n"; + ::std::cout << "{" << ::std::endl; + if( this->filters.types.functions ) + { + for(const auto& m : i.m_methods) + { + this->dump_function(root_ip + m.first.c_str(), ::HIR::Publicity::new_global(), m.second.data, 1); + } } ::std::cout << "}" << ::std::endl; + } +} +void Dumper::dump_module(::HIR::ItemPath ip, const ::HIR::Publicity& pub, const ::HIR::Module& mod) const +{ + if( !filters.public_only && !pub.is_global() ) + { + return ; + } + for(const auto& i : mod.m_mod_items) + { + auto sub_ip = ip + i.first.c_str(); + //::std::cout << "// " << i.second->ent.tagstr() << " " << sub_ip << "\n"; + TU_MATCH_HDRA( (i.second->ent), {) + TU_ARMA(Module, e) { + this->dump_module(sub_ip, i.second->publicity, e); + } + TU_ARMA(Import, e) { + //this->dump_mod_import(sub_ip, e); + } + TU_ARMA(TypeAlias, e) { + //this->dump_type_alias(sub_ip, e); + } + TU_ARMA(ExternType, e) { + //this->dump_ext_type(sub_ip, e); + } + TU_ARMA(Enum, e) { + //this->dump_enum(sub_ip, e); + } + TU_ARMA(Struct, e) { + //this->dump_enum(sub_ip, e); + } + TU_ARMA(Union, e) { + //this->dump_enum(sub_ip, e); + } + TU_ARMA(Trait, e) { + //this->dump_enum(sub_ip, e); + } + } + } + for(const auto& i : mod.m_value_items) + { + auto sub_ip = ip + i.first.c_str(); + //::std::cout << "// " << i.second->ent.tagstr() << " " << sub_ip << "\n"; + TU_MATCH_HDRA( (i.second->ent), {) + TU_ARMA(Import, e) { + //this->dump_val_import(sub_ip, e); + } + TU_ARMA(Constant, e) { + //this->dump_constant(sub_ip, e); + } + TU_ARMA(Static, e) { + //this->dump_constant(sub_ip, e); + } + TU_ARMA(StructConstant, e) { + //this->dump_constant(sub_ip, e); + } + TU_ARMA(StructConstructor, e) { + //this->dump_constant(sub_ip, e); + } + TU_ARMA(Function, e) { + this->dump_function(sub_ip, i.second->publicity, e); + } + } + } +} +void Dumper::dump_function(::HIR::ItemPath ip, const ::HIR::Publicity& pub, const ::HIR::Function& fcn, int nindent/*=0*/) const +{ + auto indent = RepeatLitStr { " ", nindent }; + if( !this->filters.types.functions ) { + return ; + } + if( !filters.public_only && !pub.is_global() ) { + return ; + } + ::std::cout << indent << "fn " << ip << fcn.m_params.fmt_args() << "("; + ::std::cout << " )"; + if( fcn.m_code.m_mir ) + { + ::std::cout << "\n"; + ::std::cout << indent << "{\n"; + MIR_Dump_Fcn(::std::cout, *fcn.m_code.m_mir, nindent+1); + ::std::cout << indent << "}\n"; ::std::cout << ::std::endl; } + else + { + ::std::cout << ";" << ::std::endl; + } } bool debug_enabled() -- cgit v1.2.3 From 20ecad6f1d3b70b199486876dc804c4850cf5fdb Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 11 May 2019 17:40:06 +0800 Subject: Typecheck Expressions - Fix bug in ivar counting, work around failure in librustc --- src/hir_typeck/expr_cs.cpp | 104 ++++++++++++++++++++++++++++++++------------- 1 file changed, 74 insertions(+), 30 deletions(-) diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index b9cfb0b2..cda8edd0 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -6943,6 +6943,7 @@ namespace { None, // No fallback, only make safe decisions Assume, // Picks an option, even if there's non source/destination types IgnoreWeakDisable, // Ignores the weaker disable flags + FinalOption, }; ::std::ostream& operator<<(::std::ostream& os, IvarPossFallbackType t) { switch(t) @@ -6950,6 +6951,7 @@ namespace { case IvarPossFallbackType::None: os << ""; break; case IvarPossFallbackType::Assume: os << " weak"; break; case IvarPossFallbackType::IgnoreWeakDisable: os << " unblock"; break; + case IvarPossFallbackType::FinalOption: os << " final"; break; } return os; } @@ -6965,10 +6967,17 @@ namespace { DEBUG(i << ": forced unknown"); return false; } - if( fallback_ty != IvarPossFallbackType::IgnoreWeakDisable && (ivar_ent.force_no_to || ivar_ent.force_no_from) ) + if( ivar_ent.force_no_to || ivar_ent.force_no_from ) { - DEBUG(i << ": coercion blocked"); - return false; + switch(fallback_ty) + { + case IvarPossFallbackType::IgnoreWeakDisable: + case IvarPossFallbackType::FinalOption: + break; + default: + DEBUG(i << ": coercion blocked"); + return false; + } } ::HIR::TypeRef ty_l_ivar; @@ -7044,7 +7053,8 @@ namespace { ::std::vector possible_tys; static ::HIR::TypeRef null_placeholder; - if( honour_disable && ivar_ent.force_no_from ) // TODO: This can't happen, there's an early return above. + bool add_placeholders = (fallback_ty < IvarPossFallbackType::IgnoreWeakDisable); + if( add_placeholders && ivar_ent.force_no_from ) // TODO: This can't happen, there's an early return above. { possible_tys.push_back(PossibleType { false, true, &null_placeholder }); } @@ -7056,7 +7066,7 @@ namespace { { possible_tys.push_back(PossibleType { false, true, &new_ty }); } - if( honour_disable && ivar_ent.force_no_to ) // TODO: This can't happen, there's an early return above. + if( add_placeholders && ivar_ent.force_no_to ) // TODO: This can't happen, there's an early return above. { possible_tys.push_back(PossibleType { false, false, &null_placeholder }); } @@ -7126,10 +7136,17 @@ namespace { //} // TODO: This shouldn't just return, instead the above null placeholders should be tested - if( fallback_ty != IvarPossFallbackType::IgnoreWeakDisable && (ivar_ent.force_no_to || ivar_ent.force_no_from) ) + if( ivar_ent.force_no_to || ivar_ent.force_no_from ) { - DEBUG(i << ": coercion blocked"); - return false; + switch(fallback_ty) + { + case IvarPossFallbackType::IgnoreWeakDisable: + case IvarPossFallbackType::FinalOption: + break; + default: + DEBUG(i << ": coercion blocked"); + return false; + } } // Filter out ivars @@ -7138,26 +7155,31 @@ namespace { size_t n_src_ivars; size_t n_dst_ivars; { - auto new_end = ::std::remove_if(possible_tys.begin(), possible_tys.end(), [](const PossibleType& ent) { + n_src_ivars = 0; + n_dst_ivars = 0; + auto new_end = ::std::remove_if(possible_tys.begin(), possible_tys.end(), [&](const PossibleType& ent) { // TODO: Should this remove Unbound associated types too? - return ent.ty->m_data.is_Infer(); + if( ent.ty->m_data.is_Infer() ) + { + if( ent.can_deref ) + { + n_src_ivars += 1; + } + else + { + n_dst_ivars += 1; + } + return true; + } + else + { + return false; + } }); n_ivars = possible_tys.end() - new_end; - n_src_ivars = 0; - n_dst_ivars = 0; - for(auto it = new_end; it != possible_tys.end(); ++it) - { - if( it->can_deref ) - { - n_src_ivars += 1; - } - else - { - n_dst_ivars += 1; - } - } possible_tys.erase(new_end, possible_tys.end()); } + DEBUG(n_ivars << " ivars (" << n_src_ivars << " src, " << n_dst_ivars << " dst)"); (void)n_ivars; // === If there's no source ivars, find the least permissive source === @@ -7167,7 +7189,7 @@ namespace { // 2. Look for an option that uses that pointer type, and contains an unsized type (that isn't a trait // object with markers) // 3. Assign to that known most-permissive option - // Do the oposite for the destination types (least permissive pointer, pick any Sized type) + // TODO: Do the oposite for the destination types (least permissive pointer, pick any Sized type) if( n_src_ivars == 0 || fallback_ty == IvarPossFallbackType::Assume ) { static const ::HIR::TypeRef::Data::Tag tag_ordering[] = { @@ -7963,7 +7985,7 @@ namespace { } it = (remove_option ? possible_tys.erase(it) : it + 1); } - DEBUG("possible_tys = " << possible_tys); + DEBUG("possible_tys = " << possible_tys << " (" << n_src_ivars << " src ivars, " << n_dst_ivars << " dst ivars)"); // Find a CD option that can deref to a `--` option for(const auto& e : possible_tys) @@ -8012,9 +8034,17 @@ namespace { { auto it = ::std::find_if(possible_tys.begin(), possible_tys.end(), [](const PossibleType& pt){ return !pt.can_deref; }); const auto& new_ty = *it->ty; - DEBUG("Picking " << new_ty << " as the only target [" << possible_tys << "]"); - context.equate_types(sp, ty_l, new_ty); - return true; + if( it->is_pointer ) + { + DEBUG("Picking " << new_ty << " as the only target [" << possible_tys << "]"); + context.equate_types(sp, ty_l, new_ty); + return true; + } + else + { + // HACK: Work around failure in librustc + DEBUG("Would pick " << new_ty << " as the only target, but it's an unsize"); + } } // If there's multiple possiblilties, we're in fallback mode, AND there's no ivars in the list if( possible_tys.size() > 0 && !honour_disable && n_ivars == 0 ) @@ -8171,13 +8201,13 @@ namespace { context.equate_types(sp, ty_l, *good_types.front()); return true; } - else if( good_types.size() > 0 && !honour_disable ) + else if( good_types.size() > 0 && fallback_ty == IvarPossFallbackType::FinalOption ) { auto typ_is_borrow = [&](const ::HIR::TypeRef* typ) { return typ->m_data.is_Borrow(); }; // NOTE: We want to select from sets of primitives and generics (which can be interchangable) if( ::std::all_of(good_types.begin(), good_types.end(), typ_is_borrow) == ::std::any_of(good_types.begin(), good_types.end(), typ_is_borrow) ) { - DEBUG("Picking " << *good_types.front() << " as first of " << good_types.size() << " options"); + DEBUG("Picking " << *good_types.front() << " as first of " << good_types.size() << " options [" << FMT_CB(ss, for(auto e:good_types) ss << *e << ",";) << "]"); context.equate_types(sp, ty_l, *good_types.front()); return true; } @@ -8535,6 +8565,20 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR: } #endif } // `if peek_changed` (ivar possibilities #2) +#if 1 + if( !context.m_ivars.peek_changed() ) + { + // Check the possible equations + DEBUG("--- IVar possibilities (final fallback)"); + for(unsigned int i = context.possible_ivar_vals.size(); i --; ) // NOTE: Ordering is a hack for libgit2 + //for(unsigned int i = 0; i < context.possible_ivar_vals.size(); i ++ ) + { + if( check_ivar_poss(context, i, context.possible_ivar_vals[i], IvarPossFallbackType::FinalOption) ) { + break; + } + } + } +#endif #if 1 if( !context.m_ivars.peek_changed() ) -- cgit v1.2.3 From 1345b89c88d32fed62df16e492e18bcf7ded477c Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 11 May 2019 20:35:31 +0800 Subject: HIR Const Eval - Use cached monomorphsed values in consteval, evaluate in reverse --- src/hir_conv/constant_evaluation.cpp | 6 ++++++ src/trans/monomorphise.cpp | 4 +++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/hir_conv/constant_evaluation.cpp b/src/hir_conv/constant_evaluation.cpp index 0ccb6e6f..22909cdc 100644 --- a/src/hir_conv/constant_evaluation.cpp +++ b/src/hir_conv/constant_evaluation.cpp @@ -414,6 +414,12 @@ namespace HIR { //check_lit_type(item.m_value->span(), item.m_type, item.m_value_res); } + auto it = c.m_monomorph_cache.find(*e2.p); + if( it != c.m_monomorph_cache.end() ) + { + MIR_ASSERT(state, !it->second.is_Defer(), "Cached literal for " << *e2.p << " is Defer"); + return clone_literal( it->second ); + } return clone_literal( c.m_value_res ); } TU_ARM(c, ItemAddr, e2) diff --git a/src/trans/monomorphise.cpp b/src/trans/monomorphise.cpp index 50924e2f..6c331d9c 100644 --- a/src/trans/monomorphise.cpp +++ b/src/trans/monomorphise.cpp @@ -376,7 +376,8 @@ void Trans_Monomorphise_List(const ::HIR::Crate& crate, TransList& list) } // Also do constants and statics (stored in where?) - for(auto& ent : list.m_constants) + // - NOTE: Done in reverse order, because consteval needs used constants to be evaluated + for(auto& ent : reverse(list.m_constants)) { const auto& path = ent.first; const auto& pp = ent.second->pp; @@ -396,6 +397,7 @@ void Trans_Monomorphise_List(const ::HIR::Crate& crate, TransList& list) ms.pp_impl = &pp.pp_impl; ms.pp_method = &pp.pp_method; auto new_lit = eval.evaluate_constant(path, c.m_value, ::std::move(ty), ::std::move(ms)); + ASSERT_BUG(Span(), !new_lit.is_Defer(), "Result of evaluating " << path << " was still Defer"); // 2. Store evaluated HIR::Literal in c.m_monomorph_cache c.m_monomorph_cache.insert(::std::make_pair( path.clone(), ::std::move(new_lit) )); } -- cgit v1.2.3 From 65fa34c0f38bc1511ff2fee7efc4744d66b15a46 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 12 May 2019 17:09:58 +0800 Subject: minicargo - dependency file support, planning for dylibs --- tools/minicargo/build.cpp | 141 +++++++++++++++++++++++++++++++++++++++++-- tools/minicargo/manifest.cpp | 21 ++++++- tools/minicargo/manifest.h | 9 +++ 3 files changed, 165 insertions(+), 6 deletions(-) diff --git a/tools/minicargo/build.cpp b/tools/minicargo/build.cpp index 7b2027d4..2bf32ac8 100644 --- a/tools/minicargo/build.cpp +++ b/tools/minicargo/build.cpp @@ -24,6 +24,7 @@ extern int _putenv_s(const char*, const char*); #include #include #include // stringstream +#include // ifstream #include // setenv #ifndef DISABLE_MULTITHREAD # include @@ -51,8 +52,10 @@ extern int _putenv_s(const char*, const char*); #ifdef _WIN32 # define EXESUF ".exe" +# define DLLSUF ".dll" #else # define EXESUF "" +# define DLLSUF ".so" #endif #include // tools/common/target_detect.h #define HOST_TARGET DEFAULT_TARGET_NAME @@ -612,6 +615,8 @@ Builder::Builder(BuildOptions opts, size_t total_targets): if(crate_type) { *crate_type = target.m_is_proc_macro ? "proc-macro" : "rlib"; } + // TODO: Support dylibs (e.g. if target.m_crate_types is just dylib, + // emit a dylib) outfile /= ::format("lib", target.m_name, crate_suffix, ".hir"); break; case PackageTarget::Type::Bin: @@ -619,6 +624,7 @@ Builder::Builder(BuildOptions opts, size_t total_targets): *crate_type = "bin"; outfile /= ::format(target.m_name, EXESUF); break; + break; default: throw ::std::runtime_error("Unknown target type being built"); } @@ -627,11 +633,115 @@ Builder::Builder(BuildOptions opts, size_t total_targets): return outfile; } +namespace { + ::std::map< ::std::string, ::std::vector > load_depfile(const helpers::path& depfile_path) + { + ::std::map< ::std::string, ::std::vector > rv; + ::std::ifstream ifp(depfile_path); + if( ifp.good() ) + { + // Load space-separated (backslash-escaped) paths + struct Lexer { + ::std::ifstream ifp; + char m_c; + + Lexer(::std::ifstream ifp) + :ifp(::std::move(ifp)) + ,m_c(0) + { + nextc(); + } + + bool nextc() { + int v = ifp.get(); + if( v == EOF ) { + m_c = '\0'; + return false; + } + else { + m_c = (char)v; + return true; + } + } + ::std::string get_token() { + auto t = get_token_int(); + DEBUG("get_token '" << t << "'"); + return t; + } + ::std::string get_token_int() { + if( ifp.eof() ) + return ""; + while( m_c == ' ' ) + { + if( !nextc() ) + return ""; + } + if( m_c == '\n' ) { + nextc(); + return "\n"; + } + if( m_c == '\t' ) { + nextc(); + return "\t"; + } + ::std::string rv; + do { + if( m_c == '\\' ) + { + nextc(); + if( m_c == ' ' ) { + rv += m_c; + } + else if( m_c == ':' ) { + rv += m_c; + } + // HACK: Only spaces are escaped this way? + else { + rv += '\\'; + rv += m_c; + } + } + else + { + rv += m_c; + } + } while( nextc() && m_c != ' ' && m_c != ':' && m_c != '\n' ); + return rv; + } + } lexer(::std::move(ifp)); + + // Look for ":" []* "\n" + do { + auto t = lexer.get_token(); + if( t == "" ) + break; + if( t == "\n" ) + continue ; + + auto v = rv.insert(::std::make_pair(t, ::std::vector())); + auto& list = v.first->second; + auto target = t; + t = lexer.get_token(); + assert(t == ":"); + + do { + t = lexer.get_token(); + if( t == "\n" || t == "" ) + break ; + list.push_back(t); + } while(1); + } while(1); + } + return rv; + } +} + bool Builder::build_target(const PackageManifest& manifest, const PackageTarget& target, bool is_for_host, size_t index) const { const char* crate_type; ::std::string crate_suffix; auto outfile = this->get_crate_path(manifest, target, is_for_host, &crate_type, &crate_suffix); + auto depfile = outfile + ".d"; size_t this_target_idx = (index != ~0u ? m_targets_built++ : ~0u); @@ -655,10 +765,30 @@ bool Builder::build_target(const PackageManifest& manifest, const PackageTarget& DEBUG("Building " << outfile << " - Older than mrustc ( " << ts_result << " < " << Timestamp::for_file(m_compiler_path) << ")"); } else { - // TODO: Check dependencies. (from depfile) - // Don't rebuild (no need to) - DEBUG("Not building " << outfile << " - not out of date"); - return true; + // Check dependencies. (from depfile) + auto depfile_ents = load_depfile(depfile); + auto it = depfile_ents.find(outfile); + bool has_new_file = false; + if( it != depfile_ents.end() ) + { + for(const auto& f : it->second) + { + auto dep_ts = Timestamp::for_file(f); + if( ts_result < dep_ts ) + { + has_new_file = true; + DEBUG("Rebuilding " << outfile << ", older than " << f); + break; + } + } + } + + if( !has_new_file ) + { + // Don't rebuild (no need to) + DEBUG("Not building " << outfile << " - not out of date"); + return true; + } } for(const auto& cmd : manifest.build_script_output().pre_build_commands) @@ -682,8 +812,10 @@ bool Builder::build_target(const PackageManifest& manifest, const PackageTarget& } StringList args; args.push_back(::helpers::path(manifest.manifest_path()).parent() / ::helpers::path(target.m_path)); + args.push_back("-o"); args.push_back(outfile); args.push_back("--crate-name"); args.push_back(target.m_name.c_str()); args.push_back("--crate-type"); args.push_back(crate_type); + args.push_back("-C"); args.push_back(format("emit-depfile=",depfile)); if( !crate_suffix.empty() ) { args.push_back("--crate-tag"); args.push_back(crate_suffix.c_str() + 1); } @@ -709,7 +841,6 @@ bool Builder::build_target(const PackageManifest& manifest, const PackageTarget& args.push_back("-C"); args.push_back("codegen-type=monomir"); } - args.push_back("-o"); args.push_back(outfile); args.push_back("-L"); args.push_back(this->get_output_dir(is_for_host).str()); for(const auto& dir : manifest.build_script_output().rustc_link_search) { args.push_back("-L"); args.push_back(dir.second.c_str()); diff --git a/tools/minicargo/manifest.cpp b/tools/minicargo/manifest.cpp index 8f49c538..be2e1c77 100644 --- a/tools/minicargo/manifest.cpp +++ b/tools/minicargo/manifest.cpp @@ -434,7 +434,26 @@ namespace } else if( key == "crate-type" ) { - // TODO: Support crate types + //assert_kv_size(kv, base_idx + 1); + //assert_type(kv, base_idx + 1); + assert(kv.path.size() == base_idx + 1); + if( !target.m_crate_types.empty() ) { + // TODO: Error, multiple instances + } + for(const auto& sv : kv.value.m_sub_values) + { + const auto& s = sv.as_string(); + if(s == "rlib") { + target.m_crate_types.push_back(PackageTarget::CrateType::rlib); + } + else if(s == "dylib") { + target.m_crate_types.push_back(PackageTarget::CrateType::dylib); + } + // TODO: Other crate types + else { + throw ::std::runtime_error(format("Unknown crate type - ", s)); + } + } } else if( key == "required-features" ) { diff --git a/tools/minicargo/manifest.h b/tools/minicargo/manifest.h index be19a7b1..54374dc2 100644 --- a/tools/minicargo/manifest.h +++ b/tools/minicargo/manifest.h @@ -190,6 +190,14 @@ struct PackageTarget Bench, Example, }; + enum class CrateType + { + dylib, + rlib, + staticlib, + cdylib, + proc_macro, + }; Type m_type; ::std::string m_name; @@ -202,6 +210,7 @@ struct PackageTarget bool m_is_proc_macro = false; bool m_is_own_harness = false; + ::std::vector m_crate_types; ::std::vector<::std::string> m_required_features; PackageTarget(Type ty): -- cgit v1.2.3 From ba97fac504233fb85bd033b3dbfba3ebfa675b15 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 12 May 2019 17:26:39 +0800 Subject: main - Slight tweak to dependency file output --- src/main.cpp | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index c0f2df9b..1fea95ff 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -399,17 +399,15 @@ int main(int argc, char *argv[]) } }); + /// Emit the dependency files if( params.emit_depfile != "" ) { - ::std::ofstream of { params.emit_depfile }; - of << params.outfile << ":"; // - Iterate all loaded files for modules - struct H { - ::std::ofstream& of; - H(::std::ofstream& of): of(of) {} + struct PathEnumerator { + ::std::vector<::std::string> out; void visit_module(::AST::Module& mod) { if( mod.m_file_info.path != "!" && mod.m_file_info.path.back() != '/' ) { - of << " " << mod.m_file_info.path; + out.push_back( mod.m_file_info.path ); } // TODO: Should we check anon modules? //for(auto& amod : mod.anon_mods()) { @@ -422,7 +420,19 @@ int main(int argc, char *argv[]) } } }; - H(of).visit_module(crate.m_root_module); + PathEnumerator pe; + pe.visit_module(crate.m_root_module); + + ::std::ofstream of { params.emit_depfile }; + // TODO: Escape spaces and colons in these paths + of << params.outfile << ":"; + for(const auto& mod_path : pe.out) + { + of << " " << mod_path; + } + of << ::std::endl; + + of << params.outfile << ":"; // - Iterate all loaded crates files for(const auto& ec : crate.m_extern_crates) { @@ -464,6 +474,13 @@ int main(int argc, char *argv[]) }); // Deallocate the original crate crate = ::AST::Crate(); + if( params.debug.dump_hir ) + { + CompilePhaseV("Dump HIR", [&]() { + ::std::ofstream os (FMT(params.outfile << "_2_hir.rs")); + HIR_Dump( os, *hir_crate ); + }); + } // Replace type aliases (`type`) into the actual type // - Also inserts defaults in trait impls -- cgit v1.2.3 From 64933e013b3b9cf11f479a07cbe674de4f56ab7b Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 12 May 2019 22:15:53 +0800 Subject: Codegen C - (minor) Commenting and extra assertions --- src/trans/codegen_c.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index fe8bf881..b229db8b 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -615,9 +615,12 @@ namespace { emit_box_drop_glue( mv$(e.first), *e.second ); } - // TODO: Define this function in MIR. + // TODO: Support dynamic libraries too + // - No main, but has the rest. + // - Well... for cdylibs that's the case, for rdylibs it's not if( is_executable ) { + // TODO: Define this function in MIR? m_of << "int main(int argc, const char* argv[]) {\n"; auto c_start_path = m_resolve.m_crate.get_lang_item_path_opt("mrustc-start"); if( c_start_path == ::HIR::SimplePath() ) @@ -789,7 +792,7 @@ namespace { args.push_back("-g"); } args.push_back("-o"); - args.push_back(m_outfile_path.c_str()); + args.push_back(m_outfile_path .c_str()); args.push_back(m_outfile_path_c.c_str()); if( is_executable ) { @@ -5302,6 +5305,7 @@ namespace { MIR_BUG(*m_mir_res, "Constant with Defer literal and no cached monomorphisation - " << path); // TODO: Can do the consteval here? } + MIR_ASSERT(*m_mir_res, !it->second.is_Defer(), "get_literal_for_const - Cached literal was Defer - " << path); return it->second; } return hir_const.m_value_res; @@ -5349,7 +5353,7 @@ namespace { void assign_from_literal(::std::function emit_dst, const ::HIR::TypeRef& ty, const ::HIR::Literal& lit) { - //TRACE_FUNCTION_F("ty=" << ty << ", lit=" << lit); + TRACE_FUNCTION_F("ty=" << ty << ", lit=" << lit); Span sp; ::HIR::TypeRef tmp; auto monomorph_with = [&](const ::HIR::PathParams& pp, const ::HIR::TypeRef& ty)->const ::HIR::TypeRef& { -- cgit v1.2.3 From cee20b8f3ab7fd6eca9fddff712b899064d0536b Mon Sep 17 00:00:00 2001 From: John Hodge Date: Tue, 14 May 2019 20:49:40 +0800 Subject: Trans Enumerate - Cache paths used by function --- src/mir/mir.hpp | 16 ++++++ src/mir/optimise.cpp | 4 +- src/trans/enumerate.cpp | 145 +++++++++++++++++++++++++++++++++--------------- 3 files changed, 119 insertions(+), 46 deletions(-) diff --git a/src/mir/mir.hpp b/src/mir/mir.hpp index c24aac51..ebef039a 100644 --- a/src/mir/mir.hpp +++ b/src/mir/mir.hpp @@ -402,6 +402,19 @@ struct BasicBlock }; +struct EnumCache; // Defined in trans/enumerate.cpp +class EnumCachePtr +{ + const EnumCache* p; +public: + EnumCachePtr(const EnumCache* p=nullptr): p(p) {} + ~EnumCachePtr(); + EnumCachePtr(EnumCachePtr&& x): p(x.p) { x.p = nullptr; } + EnumCachePtr& operator=(EnumCachePtr&& x) { this->~EnumCachePtr(); p = x.p; x.p = nullptr; return *this; } + operator bool() { return p; } + const EnumCache& operator*() const { return *p; } + const EnumCache* operator->() const { return p; } +}; class Function { public: @@ -410,6 +423,9 @@ public: ::std::vector drop_flags; ::std::vector blocks; + + // Cache filled/used by enumerate + mutable EnumCachePtr trans_enum_state; }; }; diff --git a/src/mir/optimise.cpp b/src/mir/optimise.cpp index b1be20a4..440f65db 100644 --- a/src/mir/optimise.cpp +++ b/src/mir/optimise.cpp @@ -3921,7 +3921,9 @@ void MIR_OptimiseCrate_Inlining(const ::HIR::Crate& crate, TransList& list) else if( hir_fcn.m_code ) { auto& mir = hir_fcn.m_code.get_mir_or_error_mut(Span()); - did_inline_on_pass |= MIR_OptimiseInline(resolve, ip, mir, hir_fcn.m_args, hir_fcn.m_return, list); + bool did_opt = MIR_OptimiseInline(resolve, ip, mir, hir_fcn.m_args, hir_fcn.m_return, list); + mir.trans_enum_state = ::MIR::EnumCachePtr(); // Clear MIR enum cache + did_inline_on_pass |= did_opt; } else { diff --git a/src/trans/enumerate.cpp b/src/trans/enumerate.cpp index 934f40a2..4567c0e7 100644 --- a/src/trans/enumerate.cpp +++ b/src/trans/enumerate.cpp @@ -51,7 +51,7 @@ void Trans_Enumerate_FillFrom(EnumState& state, const ::HIR::Function& function, void Trans_Enumerate_FillFrom(EnumState& state, const ::HIR::Static& stat, TransList_Static& stat_out, Trans_Params pp={}); void Trans_Enumerate_FillFrom_VTable (EnumState& state, ::HIR::Path vtable_path, const Trans_Params& pp); void Trans_Enumerate_FillFrom_Literal(EnumState& state, const ::HIR::Literal& lit, const Trans_Params& pp); -void Trans_Enumerate_FillFrom_MIR(EnumState& state, const ::MIR::Function& code, const Trans_Params& pp); +void Trans_Enumerate_FillFrom_MIR(MIR::EnumCache& state, const ::MIR::Function& code); /// Enumerate trans items starting from `::main` (binary crate) TransList Trans_Enumerate_Main(const ::HIR::Crate& crate) @@ -336,6 +336,7 @@ TransList Trans_Enumerate_Public(::HIR::Crate& crate) return rv; } +#if 0 void Trans_Enumerate_Cleanup(const ::HIR::Crate& crate, TransList& list) { EnumState state { crate }; @@ -381,6 +382,7 @@ void Trans_Enumerate_Cleanup(const ::HIR::Crate& crate, TransList& list) ASSERT_BUG(Span(), it != list.m_functions.end(), "Enumerate Error - New function appeared after monomorphisation - " << e.first); } } +#endif /// Common post-processing void Trans_Enumerate_CommonPost_Run(EnumState& state) @@ -1346,6 +1348,48 @@ namespace { } } +namespace MIR { + struct EnumCache + { + ::std::vector paths; + ::std::vector typeids; + EnumCache() + { + } + void insert_path(const ::HIR::Path& new_path) + { + for(const auto* p : this->paths) + if( *p == new_path ) + return ; + this->paths.push_back(&new_path); + } + void insert_typeid(const ::HIR::TypeRef& new_ty) + { + for(const auto* p : this->typeids) + if( *p == new_ty ) + return ; + this->typeids.push_back(&new_ty); + } + + void apply(EnumState& state, const Trans_Params& pp) const + { + for(const auto* ty_p : this->typeids) + { + state.rv.m_typeids.insert( pp.monomorph(state.crate, *ty_p) ); + } + for(const auto& path : this->paths) + { + Trans_Enumerate_FillFrom_Path(state, *path, pp); + } + } + }; + EnumCachePtr::~EnumCachePtr() + { + delete this->p; + this->p = nullptr; + } +} + void Trans_Enumerate_FillFrom_Path(EnumState& state, const ::HIR::Path& path, const Trans_Params& pp) { TRACE_FUNCTION_F(path); @@ -1491,7 +1535,9 @@ void Trans_Enumerate_FillFrom_Path(EnumState& state, const ::HIR::Path& path, co { if( auto* slot = state.rv.add_const(mv$(path_mono)) ) { - Trans_Enumerate_FillFrom_MIR(state, *e->m_value.m_mir, sub_pp); + MIR::EnumCache es; + Trans_Enumerate_FillFrom_MIR(es, *e->m_value.m_mir); + es.apply(state, sub_pp); slot->ptr = e; slot->pp = ::std::move(sub_pp); } @@ -1503,7 +1549,8 @@ void Trans_Enumerate_FillFrom_Path(EnumState& state, const ::HIR::Path& path, co } } } -void Trans_Enumerate_FillFrom_MIR_LValue(EnumState& state, const ::MIR::LValue& lv, const Trans_Params& pp) + +void Trans_Enumerate_FillFrom_MIR_LValue(MIR::EnumCache& state, const ::MIR::LValue& lv) { TU_MATCHA( (lv), (e), (Return, @@ -1513,24 +1560,24 @@ void Trans_Enumerate_FillFrom_MIR_LValue(EnumState& state, const ::MIR::LValue& (Local, ), (Static, - Trans_Enumerate_FillFrom_Path(state, *e, pp); + state.insert_path(*e); ), (Field, - Trans_Enumerate_FillFrom_MIR_LValue(state, *e.val, pp); + Trans_Enumerate_FillFrom_MIR_LValue(state, *e.val); ), (Deref, - Trans_Enumerate_FillFrom_MIR_LValue(state, *e.val, pp); + Trans_Enumerate_FillFrom_MIR_LValue(state, *e.val); ), (Index, - Trans_Enumerate_FillFrom_MIR_LValue(state, *e.val, pp); - Trans_Enumerate_FillFrom_MIR_LValue(state, *e.idx, pp); + Trans_Enumerate_FillFrom_MIR_LValue(state, *e.val); + Trans_Enumerate_FillFrom_MIR_LValue(state, *e.idx); ), (Downcast, - Trans_Enumerate_FillFrom_MIR_LValue(state, *e.val, pp); + Trans_Enumerate_FillFrom_MIR_LValue(state, *e.val); ) ) } -void Trans_Enumerate_FillFrom_MIR_Constant(EnumState& state, const ::MIR::Constant& c, const Trans_Params& pp) +void Trans_Enumerate_FillFrom_MIR_Constant(MIR::EnumCache& state, const ::MIR::Constant& c) { TU_MATCHA( (c), (ce), (Int, ), @@ -1541,21 +1588,21 @@ void Trans_Enumerate_FillFrom_MIR_Constant(EnumState& state, const ::MIR::Consta (StaticString, ), // String (Const, // - Check if this constant has a value of Defer - Trans_Enumerate_FillFrom_Path(state, *ce.p, pp); + state.insert_path(*ce.p); ), (ItemAddr, - Trans_Enumerate_FillFrom_Path(state, *ce, pp); + state.insert_path(*ce); ) ) } -void Trans_Enumerate_FillFrom_MIR_Param(EnumState& state, const ::MIR::Param& p, const Trans_Params& pp) +void Trans_Enumerate_FillFrom_MIR_Param(MIR::EnumCache& state, const ::MIR::Param& p) { TU_MATCHA( (p), (e), - (LValue, Trans_Enumerate_FillFrom_MIR_LValue(state, e, pp); ), - (Constant, Trans_Enumerate_FillFrom_MIR_Constant(state, e, pp); ) + (LValue, Trans_Enumerate_FillFrom_MIR_LValue(state, e); ), + (Constant, Trans_Enumerate_FillFrom_MIR_Constant(state, e); ) ) } -void Trans_Enumerate_FillFrom_MIR(EnumState& state, const ::MIR::Function& code, const Trans_Params& pp) +void Trans_Enumerate_FillFrom_MIR(MIR::EnumCache& state, const ::MIR::Function& code) { for(const auto& bb : code.blocks) { @@ -1564,63 +1611,63 @@ void Trans_Enumerate_FillFrom_MIR(EnumState& state, const ::MIR::Function& code, TU_MATCHA((stmt), (se), (Assign, DEBUG("- " << se.dst << " = " << se.src); - Trans_Enumerate_FillFrom_MIR_LValue(state, se.dst, pp); + Trans_Enumerate_FillFrom_MIR_LValue(state, se.dst); TU_MATCHA( (se.src), (e), (Use, - Trans_Enumerate_FillFrom_MIR_LValue(state, e, pp); + Trans_Enumerate_FillFrom_MIR_LValue(state, e); ), (Constant, - Trans_Enumerate_FillFrom_MIR_Constant(state, e, pp); + Trans_Enumerate_FillFrom_MIR_Constant(state, e); ), (SizedArray, - Trans_Enumerate_FillFrom_MIR_Param(state, e.val, pp); + Trans_Enumerate_FillFrom_MIR_Param(state, e.val); ), (Borrow, - Trans_Enumerate_FillFrom_MIR_LValue(state, e.val, pp); + Trans_Enumerate_FillFrom_MIR_LValue(state, e.val); ), (Cast, - Trans_Enumerate_FillFrom_MIR_LValue(state, e.val, pp); + Trans_Enumerate_FillFrom_MIR_LValue(state, e.val); ), (BinOp, - Trans_Enumerate_FillFrom_MIR_Param(state, e.val_l, pp); - Trans_Enumerate_FillFrom_MIR_Param(state, e.val_r, pp); + Trans_Enumerate_FillFrom_MIR_Param(state, e.val_l); + Trans_Enumerate_FillFrom_MIR_Param(state, e.val_r); ), (UniOp, - Trans_Enumerate_FillFrom_MIR_LValue(state, e.val, pp); + Trans_Enumerate_FillFrom_MIR_LValue(state, e.val); ), (DstMeta, - Trans_Enumerate_FillFrom_MIR_LValue(state, e.val, pp); + Trans_Enumerate_FillFrom_MIR_LValue(state, e.val); ), (DstPtr, - Trans_Enumerate_FillFrom_MIR_LValue(state, e.val, pp); + Trans_Enumerate_FillFrom_MIR_LValue(state, e.val); ), (MakeDst, - Trans_Enumerate_FillFrom_MIR_Param(state, e.ptr_val, pp); - Trans_Enumerate_FillFrom_MIR_Param(state, e.meta_val, pp); + Trans_Enumerate_FillFrom_MIR_Param(state, e.ptr_val); + Trans_Enumerate_FillFrom_MIR_Param(state, e.meta_val); ), (Tuple, for(const auto& val : e.vals) - Trans_Enumerate_FillFrom_MIR_Param(state, val, pp); + Trans_Enumerate_FillFrom_MIR_Param(state, val); ), (Array, for(const auto& val : e.vals) - Trans_Enumerate_FillFrom_MIR_Param(state, val, pp); + Trans_Enumerate_FillFrom_MIR_Param(state, val); ), (Variant, - Trans_Enumerate_FillFrom_MIR_Param(state, e.val, pp); + Trans_Enumerate_FillFrom_MIR_Param(state, e.val); ), (Struct, for(const auto& val : e.vals) - Trans_Enumerate_FillFrom_MIR_Param(state, val, pp); + Trans_Enumerate_FillFrom_MIR_Param(state, val); ) ) ), (Asm, DEBUG("- asm! ..."); for(const auto& v : se.inputs) - Trans_Enumerate_FillFrom_MIR_LValue(state, v.second, pp); + Trans_Enumerate_FillFrom_MIR_LValue(state, v.second); for(const auto& v : se.outputs) - Trans_Enumerate_FillFrom_MIR_LValue(state, v.second, pp); + Trans_Enumerate_FillFrom_MIR_LValue(state, v.second); ), (SetDropFlag, ), @@ -1628,7 +1675,7 @@ void Trans_Enumerate_FillFrom_MIR(EnumState& state, const ::MIR::Function& code, ), (Drop, DEBUG("- DROP " << se.slot); - Trans_Enumerate_FillFrom_MIR_LValue(state, se.slot, pp); + Trans_Enumerate_FillFrom_MIR_LValue(state, se.slot); // TODO: Ensure that the drop glue for this type is generated ) ) @@ -1641,32 +1688,32 @@ void Trans_Enumerate_FillFrom_MIR(EnumState& state, const ::MIR::Function& code, (Goto, ), (Panic, ), (If, - Trans_Enumerate_FillFrom_MIR_LValue(state, e.cond, pp); + Trans_Enumerate_FillFrom_MIR_LValue(state, e.cond); ), (Switch, - Trans_Enumerate_FillFrom_MIR_LValue(state, e.val, pp); + Trans_Enumerate_FillFrom_MIR_LValue(state, e.val); ), (SwitchValue, - Trans_Enumerate_FillFrom_MIR_LValue(state, e.val, pp); + Trans_Enumerate_FillFrom_MIR_LValue(state, e.val); ), (Call, - Trans_Enumerate_FillFrom_MIR_LValue(state, e.ret_val, pp); + Trans_Enumerate_FillFrom_MIR_LValue(state, e.ret_val); TU_MATCHA( (e.fcn), (e2), (Value, - Trans_Enumerate_FillFrom_MIR_LValue(state, e2, pp); + Trans_Enumerate_FillFrom_MIR_LValue(state, e2); ), (Path, - Trans_Enumerate_FillFrom_Path(state, e2, pp); + state.insert_path(e2); ), (Intrinsic, if( e2.name == "type_id" ) { // Add ::#type_id to the enumerate list - state.rv.m_typeids.insert( pp.monomorph(state.crate, e2.params.m_types.at(0)) ); + state.insert_typeid(e2.params.m_types.at(0)); } ) ) for(const auto& arg : e.args) - Trans_Enumerate_FillFrom_MIR_Param(state, arg, pp); + Trans_Enumerate_FillFrom_MIR_Param(state, arg); ) ) } @@ -1765,7 +1812,15 @@ void Trans_Enumerate_FillFrom(EnumState& state, const ::HIR::Function& function, TRACE_FUNCTION_F("Function pp=" << pp.pp_method<<"+"<apply(state, pp); } else { -- cgit v1.2.3 From b9f65d3234026d231b889abded407c4ae1e34286 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Wed, 15 May 2019 19:16:38 +0800 Subject: standalone_miri - Fix for MIR changes, fiddling with FFI --- tools/standalone_miri/main.cpp | 4 +-- tools/standalone_miri/mir.cpp | 11 ++++-- tools/standalone_miri/miri.cpp | 38 ++++++++++---------- tools/standalone_miri/module_tree.cpp | 4 +-- tools/standalone_miri/value.cpp | 4 +-- tools/standalone_miri/value.hpp | 68 +++++++++++++++++++++++++++++++---- 6 files changed, 95 insertions(+), 34 deletions(-) diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp index deed08be..ed9b9267 100644 --- a/tools/standalone_miri/main.cpp +++ b/tools/standalone_miri/main.cpp @@ -74,11 +74,11 @@ int main(int argc, const char* argv[]) // Create argc/argv based on input arguments auto argv_alloc = Allocation::new_alloc((1 + opts.args.size()) * POINTER_SIZE); argv_alloc->write_usize(0 * POINTER_SIZE, 0); - argv_alloc->relocations.push_back({ 0 * POINTER_SIZE, RelocationPtr::new_ffi(FFIPointer { "", (void*)(opts.infile.c_str()), opts.infile.size() + 1 }) }); + argv_alloc->relocations.push_back({ 0 * POINTER_SIZE, RelocationPtr::new_ffi(FFIPointer::new_const_bytes(opts.infile.c_str(), opts.infile.size() + 1)) }); for(size_t i = 0; i < opts.args.size(); i ++) { argv_alloc->write_usize((1 + i) * POINTER_SIZE, 0); - argv_alloc->relocations.push_back({ (1 + i) * POINTER_SIZE, RelocationPtr::new_ffi({ "", (void*)(opts.args[0]), ::std::strlen(opts.args[0]) + 1 }) }); + argv_alloc->relocations.push_back({ (1 + i) * POINTER_SIZE, RelocationPtr::new_ffi(FFIPointer::new_const_bytes(opts.args[0], ::std::strlen(opts.args[0]) + 1)) }); } // Construct argc/argv values diff --git a/tools/standalone_miri/mir.cpp b/tools/standalone_miri/mir.cpp index a0601823..f1b4841e 100644 --- a/tools/standalone_miri/mir.cpp +++ b/tools/standalone_miri/mir.cpp @@ -62,10 +62,10 @@ namespace MIR { os << "\"" << e << "\""; ), (Const, - os << e.p; + os << *e.p; ), (ItemAddr, - os << "&" << e; + os << "&" << *e; ) ) return os; @@ -83,7 +83,7 @@ namespace MIR { os << "Local(" << e << ")"; ), (Static, - os << "Static(" << e << ")"; + os << "Static(" << *e << ")"; ), (Field, os << "Field(" << e.field_index << ", " << *e.val << ")"; @@ -296,5 +296,10 @@ namespace MIR { ) return os; } + + EnumCachePtr::~EnumCachePtr() + { + assert(!this->p); + } } diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index 8231f2c5..d5bcb024 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -273,7 +273,7 @@ struct MirHelpers return ValueRef(this->frame.args.at(e.idx)); } break; TU_ARM(lv, Static, e) { - /*const*/ auto& s = this->thread.m_modtree.get_static(e); + /*const*/ auto& s = this->thread.m_modtree.get_static(*e); ty = s.ty; return ValueRef(s.val); } break; @@ -482,15 +482,15 @@ struct MirHelpers // --> Accessor TU_ARM(c, ItemAddr, ce) { // Create a value with a special backing allocation of zero size that references the specified item. - if( /*const auto* fn =*/ this->thread.m_modtree.get_function_opt(ce) ) { + if( /*const auto* fn =*/ this->thread.m_modtree.get_function_opt(*ce) ) { ty = ::HIR::TypeRef(RawType::Function); - return Value::new_fnptr(ce); + return Value::new_fnptr(*ce); } - if( const auto* s = this->thread.m_modtree.get_static_opt(ce) ) { + if( const auto* s = this->thread.m_modtree.get_static_opt(*ce) ) { ty = s->ty.wrapped(TypeWrapper::Ty::Borrow, 0); return Value::new_pointer(ty, 0, RelocationPtr::new_alloc(s->val.allocation)); } - LOG_ERROR("Constant::ItemAddr - " << ce << " - not found"); + LOG_ERROR("Constant::ItemAddr - " << *ce << " - not found"); } break; } throw ""; @@ -1031,19 +1031,20 @@ bool InterpreterThread::step_one(Value& out_thread_result) LOG_ASSERT(ty_r.get_wrapper() == nullptr, "Bitwise operator with non-primitive - " << ty_r); size_t max_bits = ty_r.get_size() * 8; uint8_t shift; - auto check_cast = [&](auto v){ LOG_ASSERT(0 <= v && v <= max_bits, "Shift out of range - " << v); return static_cast(v); }; + auto check_cast_u = [&](auto v){ LOG_ASSERT(0 <= v && v <= max_bits, "Shift out of range - " << v); return static_cast(v); }; + auto check_cast_s = [&](auto v){ LOG_ASSERT(v <= static_cast(max_bits), "Shift out of range - " << v); return static_cast(v); }; switch(ty_r.inner_type) { - case RawType::U64: shift = check_cast(v_r.read_u64(0)); break; - case RawType::U32: shift = check_cast(v_r.read_u32(0)); break; - case RawType::U16: shift = check_cast(v_r.read_u16(0)); break; - case RawType::U8 : shift = check_cast(v_r.read_u8 (0)); break; - case RawType::I64: shift = check_cast(v_r.read_i64(0)); break; - case RawType::I32: shift = check_cast(v_r.read_i32(0)); break; - case RawType::I16: shift = check_cast(v_r.read_i16(0)); break; - case RawType::I8 : shift = check_cast(v_r.read_i8 (0)); break; - case RawType::USize: shift = check_cast(v_r.read_usize(0)); break; - case RawType::ISize: shift = check_cast(v_r.read_isize(0)); break; + case RawType::U64: shift = check_cast_u(v_r.read_u64(0)); break; + case RawType::U32: shift = check_cast_u(v_r.read_u32(0)); break; + case RawType::U16: shift = check_cast_u(v_r.read_u16(0)); break; + case RawType::U8 : shift = check_cast_u(v_r.read_u8 (0)); break; + case RawType::I64: shift = check_cast_s(v_r.read_i64(0)); break; + case RawType::I32: shift = check_cast_s(v_r.read_i32(0)); break; + case RawType::I16: shift = check_cast_s(v_r.read_i16(0)); break; + case RawType::I8 : shift = check_cast_s(v_r.read_i8 (0)); break; + case RawType::USize: shift = check_cast_u(v_r.read_usize(0)); break; + case RawType::ISize: shift = check_cast_s(v_r.read_isize(0)); break; default: LOG_TODO("BinOp shift rhs unknown type - " << se.src << " w/ " << ty_r); } @@ -2213,9 +2214,8 @@ bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, con LOG_FATAL("Attempt to copy* a function"); break; case RelocationPtr::Ty::FfiPointer: - LOG_ASSERT(src_ofs <= src_alloc.ffi().size, ""); - LOG_ASSERT(byte_count <= src_alloc.ffi().size, ""); - LOG_ASSERT(src_ofs + byte_count <= src_alloc.ffi().size, ""); + LOG_ASSERT(src_alloc.ffi().layout, ""); + LOG_ASSERT(src_alloc.ffi().layout->is_valid_read(src_ofs, byte_count), ""); dst_alloc.alloc().write_bytes(dst_ofs, reinterpret_cast(src_alloc.ffi().ptr_value) + src_ofs, byte_count); break; } diff --git a/tools/standalone_miri/module_tree.cpp b/tools/standalone_miri/module_tree.cpp index eb6b6b9e..984662fe 100644 --- a/tools/standalone_miri/module_tree.cpp +++ b/tools/standalone_miri/module_tree.cpp @@ -379,7 +379,7 @@ bool Parser::parse_one() else if( lex.next() == "::" || lex.next() == '<' ) { auto path = p.parse_path(); - lv = ::MIR::LValue( ::std::move(path) ); + lv = ::MIR::LValue( ::std::make_unique(::std::move(path)) ); } else { LOG_ERROR(lex << "Unexpected token in LValue - " << lex.next()); @@ -464,7 +464,7 @@ bool Parser::parse_one() else if( p.lex.consume_if("ADDROF") ) { auto path = p.parse_path(); - return ::MIR::Constant::make_ItemAddr({ ::std::move(path) }); + return ::MIR::Constant::make_ItemAddr({ ::std::make_unique(::std::move(path)) }); } else { LOG_BUG(p.lex << "BUG? " << p.lex.next()); diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp index 849d3a64..9007eb5c 100644 --- a/tools/standalone_miri/value.cpp +++ b/tools/standalone_miri/value.cpp @@ -167,7 +167,7 @@ size_t RelocationPtr::get_size() const os << "\"" << x.str() << "\""; break; case RelocationPtr::Ty::FfiPointer: - os << "FFI " << x.ffi().source_function << " " << x.ffi().ptr_value; + os << "FFI " << x.ffi().tag_name << " " << x.ffi().ptr_value; break; } } @@ -237,7 +237,7 @@ void* ValueCommonRead::read_pointer_unsafe(size_t rd_ofs, size_t req_valid, size //if( req_valid ) // LOG_FATAL("Can't request valid data from a FFI pointer"); // TODO: Have an idea of mutability and available size from FFI - out_size = f.size - ofs; + out_size = f.get_size() - ofs; out_is_mut = false; return reinterpret_cast(reloc.ffi().ptr_value) + ofs; } diff --git a/tools/standalone_miri/value.hpp b/tools/standalone_miri/value.hpp index b057b3c4..377361ce 100644 --- a/tools/standalone_miri/value.hpp +++ b/tools/standalone_miri/value.hpp @@ -21,11 +21,67 @@ class Allocation; struct Value; struct ValueRef; +struct FfiLayout +{ + struct Range { + size_t len; + bool is_valid; + bool is_writable; + }; + ::std::vector ranges; + + size_t get_size() const { + size_t rv = 0; + for(const auto& r : ranges) + rv += r.len; + return rv; + } + bool is_valid_read(size_t o, size_t s) { + for(const auto& r : ranges) + { + if( o < r.len ) { + if( !r.is_valid ) + return false; + if( o + s <= r.len ) + { + s = 0; + break; + } + s -= (r.len - o); + o = 0; + } + else { + o -= r.len; + } + } + if( s > 0 ) + { + return false; + } + return true; + } +}; struct FFIPointer { - const char* source_function; + // FFI pointers require the following: + // - A tag indicating where they're valid/from + // - A data format (e.g. size of allocation, internal data format) + // - If the data format is unspecified (null) then it's a void pointer + // - An actual pointer + + // Pointer value, returned by the FFI void* ptr_value; - size_t size; + // Tag name, used for validty checking by FFI hooks + const char* tag_name; + ::std::shared_ptr layout; + + static FFIPointer new_const_bytes(const void* s, size_t size) { + return FFIPointer { const_cast(s), "", ::std::shared_ptr() }; + }; + + size_t get_size() const { + return (layout ? layout->get_size() : 0); + } }; class AllocationHandle @@ -83,7 +139,7 @@ public: RelocationPtr(const RelocationPtr& x); ~RelocationPtr(); static RelocationPtr new_alloc(AllocationHandle h); - static RelocationPtr new_fcn(::HIR::Path p); + static RelocationPtr new_fcn(::HIR::Path p); // TODO: What if it's a FFI function? Could be encoded in here. static RelocationPtr new_string(const ::std::string* s); // NOTE: The string must have a stable pointer static RelocationPtr new_ffi(FFIPointer info); @@ -331,9 +387,9 @@ struct ValueRef: assert(ofs+size <= m_alloc.str().size()); break; case RelocationPtr::Ty::FfiPointer: - assert(ofs < m_alloc.ffi().size); - assert(size <= m_alloc.ffi().size); - assert(ofs+size <= m_alloc.ffi().size); + assert(ofs < m_alloc.ffi().get_size()); + assert(size <= m_alloc.ffi().get_size()); + assert(ofs+size <= m_alloc.ffi().get_size()); break; default: throw "TODO"; -- cgit v1.2.3 From 311b406bf90a8244a39a8eff933c7fce45b9c7f2 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Wed, 15 May 2019 20:35:44 +0800 Subject: standalone_miri - Fiddling for 1.29 support (not working yet) --- tools/standalone_miri/miri.cpp | 36 +++++++++++++++++++++++++++++++++--- tools/standalone_miri/value.cpp | 32 ++++++++++++++++++++++++++++++++ tools/standalone_miri/value.hpp | 30 +++++------------------------- 3 files changed, 70 insertions(+), 28 deletions(-) diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index d5bcb024..4bba4da4 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -1553,7 +1553,9 @@ bool InterpreterThread::call_path(Value& ret, const ::HIR::Path& path, ::std::ve } // - No guard page needed - if( path == ::HIR::SimplePath { "std", {"sys", "imp", "thread", "guard", "init" } } ) + if( path == ::HIR::SimplePath { "std", {"sys", "imp", "thread", "guard", "init" } } + || path == ::HIR::SimplePath { "std", {"sys", "unix", "thread", "guard", "init" } } + ) { ret = Value::with_size(16, false); ret.write_u64(0, 0); @@ -1599,7 +1601,7 @@ extern "C" { #endif bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, const ::std::string& abi, ::std::vector args) { - if( link_name == "__rust_allocate" ) + if( link_name == "__rust_allocate" || link_name == "__rust_alloc" ) { auto size = args.at(0).read_usize(0); auto align = args.at(1).read_usize(0); @@ -1609,7 +1611,7 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c // TODO: Use the alignment when making an allocation? rv = Value::new_pointer(rty, 0, RelocationPtr::new_alloc(Allocation::new_alloc(size))); } - else if( link_name == "__rust_reallocate" ) + else if( link_name == "__rust_reallocate" || link_name == "__rust_realloc" ) { LOG_ASSERT(args.at(0).allocation, "__rust_reallocate first argument doesn't have an allocation"); auto alloc_ptr = args.at(0).get_relocation(0); @@ -1757,6 +1759,10 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c rv = Value::new_usize(val); } + else if( link_name == "pthread_self" ) + { + rv = Value::new_i32(0); + } else if( link_name == "pthread_mutex_init" || link_name == "pthread_mutex_lock" || link_name == "pthread_mutex_unlock" || link_name == "pthread_mutex_destroy" ) { rv = Value::new_i32(0); @@ -1773,6 +1779,10 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c { rv = Value::new_i32(0); } + else if( link_name == "pthread_attr_init" || link_name == "pthread_attr_destroy" || link_name == "pthread_getattr_np" ) + { + rv = Value::new_i32(0); + } else if( link_name == "pthread_cond_init" || link_name == "pthread_cond_destroy" ) { rv = Value::new_i32(0); @@ -1820,6 +1830,14 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c rv = Value(::HIR::TypeRef(RawType::USize)); rv.write_usize(0, 1); } + else if( link_name == "sigaction" ) + { + rv = Value::new_i32(-1); + } + else if( link_name == "sigaltstack" ) // POSIX: Set alternate signal stack + { + rv = Value::new_i32(-1); + } // - `void *memchr(const void *s, int c, size_t n);` else if( link_name == "memchr" ) { @@ -2177,6 +2195,18 @@ bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, con auto lhs = PrimitiveValueVirt::from_value(ty, args.at(0)); auto rhs = PrimitiveValueVirt::from_value(ty, args.at(1)); lhs.get().subtract( rhs.get() ); + // TODO: Overflowing part + + rv = Value(ty); + lhs.get().write_to_value(rv, 0); + } + else if( name == "overflowing_add" ) + { + const auto& ty = ty_params.tys.at(0); + + auto lhs = PrimitiveValueVirt::from_value(ty, args.at(0)); + auto rhs = PrimitiveValueVirt::from_value(ty, args.at(1)); + lhs.get().add( rhs.get() ); rv = Value(ty); lhs.get().write_to_value(rv, 0); diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp index 9007eb5c..0b3aa988 100644 --- a/tools/standalone_miri/value.cpp +++ b/tools/standalone_miri/value.cpp @@ -13,6 +13,38 @@ #include #include "debug.hpp" +FfiLayout FfiLayout::new_const_bytes(size_t s) +{ + return FfiLayout { + { Range {s, true, false} } + }; +} +bool FfiLayout::is_valid_read(size_t o, size_t s) const +{ + for(const auto& r : ranges) + { + if( o < r.len ) { + if( !r.is_valid ) + return false; + if( o + s <= r.len ) + { + s = 0; + break; + } + s -= (r.len - o); + o = 0; + } + else { + o -= r.len; + } + } + if( s > 0 ) + { + return false; + } + return true; +} + AllocationHandle Allocation::new_alloc(size_t size) { Allocation* rv = new Allocation(); diff --git a/tools/standalone_miri/value.hpp b/tools/standalone_miri/value.hpp index 377361ce..e45759a7 100644 --- a/tools/standalone_miri/value.hpp +++ b/tools/standalone_miri/value.hpp @@ -30,36 +30,15 @@ struct FfiLayout }; ::std::vector ranges; + static FfiLayout new_const_bytes(size_t s); + size_t get_size() const { size_t rv = 0; for(const auto& r : ranges) rv += r.len; return rv; } - bool is_valid_read(size_t o, size_t s) { - for(const auto& r : ranges) - { - if( o < r.len ) { - if( !r.is_valid ) - return false; - if( o + s <= r.len ) - { - s = 0; - break; - } - s -= (r.len - o); - o = 0; - } - else { - o -= r.len; - } - } - if( s > 0 ) - { - return false; - } - return true; - } + bool is_valid_read(size_t o, size_t s) const; }; struct FFIPointer { @@ -76,7 +55,7 @@ struct FFIPointer ::std::shared_ptr layout; static FFIPointer new_const_bytes(const void* s, size_t size) { - return FFIPointer { const_cast(s), "", ::std::shared_ptr() }; + return FFIPointer { const_cast(s), "", ::std::make_shared(FfiLayout::new_const_bytes(size)) }; }; size_t get_size() const { @@ -268,6 +247,7 @@ class Allocation: // TODO: Read-only flag? bool is_freed = false; public: + virtual ~Allocation() {} static AllocationHandle new_alloc(size_t size); const uint8_t* data_ptr() const { return reinterpret_cast(this->data.data()); } -- cgit v1.2.3 From 894950e87dc8c7631fe38cdfe47170ce1f94c062 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Wed, 15 May 2019 20:36:11 +0800 Subject: Scripts - Extend log_get_last_function with more start-of-function signatures --- scripts/log_get_last_function.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/log_get_last_function.py b/scripts/log_get_last_function.py index 7a148639..eb9f8e94 100644 --- a/scripts/log_get_last_function.py +++ b/scripts/log_get_last_function.py @@ -11,7 +11,7 @@ def main(): fcn_lines = [] found_fcn = False for line in args.logfile: - if 'visit_function: ' in line: + if 'visit_function: ' in line or 'Trans_Monomorphise_List: ' in line or 'Trans_Codegen: FUNCTION CODE' in line: if found_fcn: break fcn_lines = [] -- cgit v1.2.3 From 0f59ded4389202468dd5bcb420724395afbfe1f7 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Wed, 15 May 2019 21:19:57 +0800 Subject: Expand - Track include!/include_str!/include_bytes! files for dependencies --- src/ast/crate.hpp | 3 ++- src/expand/include.cpp | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/ast/crate.hpp b/src/ast/crate.hpp index 11fba9c0..79cb9cd7 100644 --- a/src/ast/crate.hpp +++ b/src/ast/crate.hpp @@ -57,7 +57,8 @@ public: bool m_test_harness = false; ::std::vector m_tests; - //::std::vector<::std::string> m_extra_files; + /// Files loaded using things like include! and include_str! + mutable ::std::vector<::std::string> m_extra_files; // Procedural macros! ::std::vector m_proc_macros; diff --git a/src/expand/include.cpp b/src/expand/include.cpp index 59f33d47..8078d5d0 100644 --- a/src/expand/include.cpp +++ b/src/expand/include.cpp @@ -12,6 +12,7 @@ #include #include // Lexer (new files) #include +#include namespace { @@ -75,6 +76,7 @@ class CIncludeExpander: GET_CHECK_TOK(tok, lex, TOK_EOF); ::std::string file_path = get_path_relative_to(mod.m_file_info.path, mv$(path)); + crate.m_extra_files.push_back(file_path); try { return box$( Lexer(file_path) ); @@ -101,6 +103,7 @@ class CIncludeBytesExpander: GET_CHECK_TOK(tok, lex, TOK_EOF); ::std::string file_path = get_path_relative_to(mod.m_file_info.path, mv$(path)); + crate.m_extra_files.push_back(file_path); ::std::ifstream is(file_path); if( !is.good() ) { @@ -130,6 +133,7 @@ class CIncludeStrExpander: GET_CHECK_TOK(tok, lex, TOK_EOF); ::std::string file_path = get_path_relative_to(mod.m_file_info.path, mv$(path)); + crate.m_extra_files.push_back(file_path); ::std::ifstream is(file_path); if( !is.good() ) { -- cgit v1.2.3 From c4b5f0abb1b67e7f691c105841ce6e37fe2b0432 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Wed, 15 May 2019 21:44:05 +0800 Subject: Updates to TODO list --- Notes/todo.txt | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/Notes/todo.txt b/Notes/todo.txt index 7041c8b9..edc0074e 100644 --- a/Notes/todo.txt +++ b/Notes/todo.txt @@ -18,12 +18,28 @@ TODO: - Refactor parse to use a consume model lexer - Optimise optimise (and typecheck) - Complete structed C codegen +- Switch MIR to be SSA (or have a SSA form) +- MIR restructure specified in MIR-PackedLValue.txt + - Designed to remove pointer chasing when doing MIR analyis (and save space) ## Smaller changes - Only generate destructors if needed (removes C warnings) - Cache specialisation tree - Dependency files from mrustc - Partally done, not complete +- Replace all std::string-s with RcString (saves memory) + - Also use a string interning pool to de-duplicate identical strings (which + will be common) + - Copies of strings are relatively common (path copies) +- Delete HIR after MIR generation +- Use a more space-efficient (and readable) MIR LValue debug output + - e.g. `_0**.1#2` for Downcast(2, Field(1, Deref(Deref(Local(0))))) + - Will simplify reading of debug, and reduce the size of required debug + output + - Trailing dereference might be confusing with multiply operator? +- Cache referenced items for each function in `Trans Enumerate` + - Should reduce the impact of large generic functions being walked every + time they're used with a new type set. ## Optimisations @@ -32,4 +48,9 @@ TODO: - Dead assignment removal (Delete ` = Use()` - Tuple destructure removal - Spot `#1 = (...,)`, `#2 = (#1).n` where #1 is Write-once, borrow-none +- Remove useless borrows (remove write-once &T lvalues if they're never used by + value - only used via deref) + + -- cgit v1.2.3 From 7aa0e40f91ecc7b8c6be6044e9314529cb7a4cfd Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 18 May 2019 13:46:40 +0800 Subject: Forgotten header --- src/hir_conv/constant_evaluation.hpp | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 src/hir_conv/constant_evaluation.hpp diff --git a/src/hir_conv/constant_evaluation.hpp b/src/hir_conv/constant_evaluation.hpp new file mode 100644 index 00000000..dff6e73e --- /dev/null +++ b/src/hir_conv/constant_evaluation.hpp @@ -0,0 +1,33 @@ +/* + */ +#include + +namespace HIR { + + +struct Evaluator +{ + class Newval + { + public: + virtual ::HIR::Path new_static(::HIR::TypeRef type, ::HIR::Literal value) = 0; + }; + + const Span& root_span; + StaticTraitResolve resolve; + Newval& nvs; + + Evaluator(const Span& sp, const ::HIR::Crate& crate, Newval& nvs): + root_span(sp), + resolve(crate), + nvs( nvs ) + { + } + + ::HIR::Literal evaluate_constant(const ::HIR::ItemPath& ip, const ::HIR::ExprPtr& expr, ::HIR::TypeRef exp, MonomorphState ms={}); + + ::HIR::Literal evaluate_constant_mir(const ::HIR::ItemPath& ip, const ::MIR::Function& fcn, MonomorphState ms, ::HIR::TypeRef exp, ::std::vector< ::HIR::Literal> args); +}; + +} // namespace HIR + -- cgit v1.2.3 From acf5e74ebb31aa26ea94ca5f0e636573794e6753 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 18 May 2019 15:59:37 +0800 Subject: patches - Avoid need for dylib support --- rustc-1.29.0-src.patch | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/rustc-1.29.0-src.patch b/rustc-1.29.0-src.patch index df6ef8f5..69f831ff 100644 --- a/rustc-1.29.0-src.patch +++ b/rustc-1.29.0-src.patch @@ -23,3 +23,18 @@ + let rv = unsafe { ::intrinsics::mrustc_slice_len(self) }; + rv } +--- src/librustc_driver/Cargo.toml ++++ src/librustc_driver/Cargo.toml +@@ -39,1 +39,2 @@ + syntax_pos = { path = "../libsyntax_pos" } ++rustc_codegen_llvm = { path = "../librustc_codegen_llvm" } +--- src/librustc_driver/lib.rs ++++ src/librustc_driver/lib.rs +@@ -63,2 +63,3 @@ + extern crate syntax_pos; ++extern crate rustc_codegen_llvm; + +@@ -259,2 +260,3 @@ + let backend = match &codegen_name[..] { ++ "llvm" => rustc_codegen_llvm::__rustc_codegen_backend, + "metadata_only" => { -- cgit v1.2.3 From ce2ad230390cb1ea23aaa33a206909bc11523e1d Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 18 May 2019 16:00:56 +0800 Subject: main - dylib crate type on command line --- src/main.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main.cpp b/src/main.cpp index 1fea95ff..5ffc195a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1046,6 +1046,9 @@ ProgramParams::ProgramParams(int argc, char *argv[]) if( strcmp(type_str, "rlib") == 0 ) { this->crate_type = ::AST::Crate::Type::RustLib; } + else if( strcmp(type_str, "dylib") == 0 ) { + this->crate_type = ::AST::Crate::Type::RustDylib; + } else if( strcmp(type_str, "bin") == 0 ) { this->crate_type = ::AST::Crate::Type::Executable; } -- cgit v1.2.3 From a2b3ce762d7bf4955f59d4827d5d3dded75307ce Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 18 May 2019 16:01:33 +0800 Subject: minicargo - Very rough planning for dylibs --- tools/minicargo/build.cpp | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/tools/minicargo/build.cpp b/tools/minicargo/build.cpp index 2bf32ac8..145a1c1e 100644 --- a/tools/minicargo/build.cpp +++ b/tools/minicargo/build.cpp @@ -612,19 +612,35 @@ Builder::Builder(BuildOptions opts, size_t total_targets): switch(target.m_type) { case PackageTarget::Type::Lib: - if(crate_type) { - *crate_type = target.m_is_proc_macro ? "proc-macro" : "rlib"; + switch( target.m_crate_types.size() > 0 + ? target.m_crate_types.front() + : (target.m_is_proc_macro + ? PackageTarget::CrateType::proc_macro + : PackageTarget::CrateType::rlib + ) + ) + { + case PackageTarget::CrateType::proc_macro: + if(crate_type) *crate_type = "proc-macro"; + outfile /= ::format("lib", target.m_name, crate_suffix, ".hir"); // TODO: .rlib instead + break; + case PackageTarget::CrateType::dylib: + //if(crate_type) *crate_type = "dylib"; + //outfile /= ::format("lib", target.m_name, crate_suffix, DLLSUF); + //break; + case PackageTarget::CrateType::rlib: + if(crate_type) *crate_type = "rlib"; + outfile /= ::format("lib", target.m_name, crate_suffix, ".hir"); // TODO: .rlib instead + break; + default: + throw ""; } - // TODO: Support dylibs (e.g. if target.m_crate_types is just dylib, - // emit a dylib) - outfile /= ::format("lib", target.m_name, crate_suffix, ".hir"); break; case PackageTarget::Type::Bin: if(crate_type) *crate_type = "bin"; outfile /= ::format(target.m_name, EXESUF); break; - break; default: throw ::std::runtime_error("Unknown target type being built"); } -- cgit v1.2.3 From 278efd923cb06f2c3f9719db54f775ed2a29062e Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 18 May 2019 16:34:37 +0800 Subject: minicargo.mk - Tweaks --- minicargo.mk | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/minicargo.mk b/minicargo.mk index 70b4c058..14773e60 100644 --- a/minicargo.mk +++ b/minicargo.mk @@ -16,7 +16,7 @@ PARLEVEL ?= 1 MINICARGO_FLAGS ?= ifneq ($(MMIR),) - OUTDIR_SUF := -mmir + OUTDIR_SUF := $(OUTDIR_SUF)-mmir MINICARGO_FLAGS += -Z emit-mmir endif ifneq ($(PARLEVEL),1) @@ -27,6 +27,10 @@ OUTDIR := output$(OUTDIR_SUF)/ MRUSTC := bin/mrustc MINICARGO := tools/bin/minicargo +RUSTC_OUT_BIN := rustc +ifeq ($(RUSTC_VERSION),1.29.0) + RUSTC_OUT_BIN := rustc_binary +endif ifeq ($(RUSTC_CHANNEL),nightly) RUSTCSRC := rustc-nightly-src/ else @@ -88,7 +92,8 @@ RUSTC_ENV_VARS += CFG_LIBDIR_RELATIVE=lib $(OUTDIR)rustc: $(MRUSTC) $(MINICARGO) LIBS $(LLVM_CONFIG) mkdir -p $(OUTDIR)rustc-build $(RUSTC_ENV_VARS) $(MINICARGO) $(RUSTCSRC)src/rustc --vendor-dir $(RUSTCSRC)src/vendor --output-dir $(OUTDIR)rustc-build -L $(OUTDIR) $(MINICARGO_FLAGS) - cp $(OUTDIR)rustc-build/rustc $(OUTDIR) +# $(RUSTC_ENV_VARS) $(MINICARGO) $(RUSTCSRC)src/librustc_codegen_llvm --vendor-dir $(RUSTCSRC)src/vendor --output-dir $(OUTDIR)rustc-build -L $(OUTDIR) $(MINICARGO_FLAGS) + cp $(OUTDIR)rustc-build/$(RUSTC_OUT_BIN) $@ $(OUTDIR)cargo: $(MRUSTC) LIBS mkdir -p $(OUTDIR)cargo-build $(MINICARGO) $(RUSTCSRC)src/tools/cargo --vendor-dir $(RUSTCSRC)src/vendor --output-dir $(OUTDIR)cargo-build -L $(OUTDIR) $(MINICARGO_FLAGS) -- cgit v1.2.3 From 8183bf1f7ffa47cd966bdc7872ca36875d9d83a1 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 18 May 2019 16:35:39 +0800 Subject: Makefile - Ensure that patch changes cause a rustc update --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 8da0e1be..41d6bb7c 100644 --- a/Makefile +++ b/Makefile @@ -283,7 +283,7 @@ output$(OUTDIR_SUF)/rust/test_run-pass_hello_out.txt: output$(OUTDIR_SUF)/rust/t # # TEST: Rust standard library and the "hello, world" run-pass test # -test: output$(OUTDIR_SUF)/libstd.hir output$(OUTDIR_SUF)/rust/test_run-pass_hello_out.txt $(BIN) +test: RUSTCSRC output$(OUTDIR_SUF)/libstd.hir output$(OUTDIR_SUF)/rust/test_run-pass_hello_out.txt $(BIN) # # TEST: Attempt to compile rust_os (Tifflin) from ../rust_os -- cgit v1.2.3 From dab5cf5462d8fce6d6fcaa1343df8f5f3b763b8a Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 18 May 2019 17:38:05 +0800 Subject: HIR - Fix privacy error for items in non-library crate root --- src/ast/dump.cpp | 2 +- src/hir/hir.cpp | 39 +++++++++++++++++++++++++++++++++++++++ src/hir/hir.hpp | 37 +++---------------------------------- 3 files changed, 43 insertions(+), 35 deletions(-) diff --git a/src/ast/dump.cpp b/src/ast/dump.cpp index f0bdfa11..00848fb5 100644 --- a/src/ast/dump.cpp +++ b/src/ast/dump.cpp @@ -1042,7 +1042,7 @@ void RustPrinter::handle_struct(const AST::Struct& s) (Tuple, m_os << "("; for( const auto& i : e.ents ) - m_os << i.m_type << ", "; + m_os << (i.m_is_public ? "pub " : "") << i.m_type << ", "; m_os << ")\n"; print_bounds(s.params()); m_os << indent() << ";\n"; diff --git a/src/hir/hir.cpp b/src/hir/hir.cpp index 4b9aef10..2a8ac8bf 100644 --- a/src/hir/hir.cpp +++ b/src/hir/hir.cpp @@ -17,6 +17,20 @@ #include namespace HIR { + ::std::ostream& operator<<(::std::ostream& os, const Publicity& x) + { + if( !x.vis_path ) { + os << "pub"; + } + else if( *x.vis_path == *Publicity::none_path ) { + os << "priv"; + } + else { + os << "pub(" << *x.vis_path << ")"; + } + return os; + } + ::std::ostream& operator<<(::std::ostream& os, const ::HIR::Literal& v) { TU_MATCH(::HIR::Literal, (v), (e), @@ -110,6 +124,31 @@ namespace HIR { } } +::std::shared_ptr<::HIR::SimplePath> HIR::Publicity::none_path = ::std::make_shared(::HIR::SimplePath{"#", {}}); + +bool HIR::Publicity::is_visible(const ::HIR::SimplePath& p) const +{ + // No path = global public + if( !vis_path ) + return true; + // Empty simple path = full private + if( *vis_path == *none_path ) { + return false; + } + // Crate names must match + if(p.m_crate_name != vis_path->m_crate_name) + return false; + // `p` must be a child of vis_path + if(p.m_components.size() < vis_path->m_components.size()) + return false; + for(size_t i = 0; i < vis_path->m_components.size(); i ++) + { + if(p.m_components[i] != vis_path->m_components[i]) + return false; + } + return true; +} + size_t HIR::Enum::find_variant(const ::std::string& name) const { if( m_data.is_Value() ) diff --git a/src/hir/hir.hpp b/src/hir/hir.hpp index 6c8385c4..cc66a9e7 100644 --- a/src/hir/hir.hpp +++ b/src/hir/hir.hpp @@ -43,6 +43,7 @@ class ItemPath; class Publicity { + static ::std::shared_ptr<::HIR::SimplePath> none_path; ::std::shared_ptr<::HIR::SimplePath> vis_path; Publicity(::std::shared_ptr<::HIR::SimplePath> p) @@ -55,7 +56,6 @@ public: return Publicity({}); } static Publicity new_none() { - static ::std::shared_ptr<::HIR::SimplePath> none_path = ::std::make_shared(); return Publicity(none_path); } static Publicity new_priv(::HIR::SimplePath p) { @@ -65,40 +65,9 @@ public: bool is_global() const { return !vis_path; } - bool is_visible(const ::HIR::SimplePath& p) const { - // No path = global public - if( !vis_path ) - return true; - // Empty simple path = full private - if( *vis_path == ::HIR::SimplePath() ) { - return false; - } - // Crate names must match - if(p.m_crate_name != vis_path->m_crate_name) - return false; - // `p` must be a child of vis_path - if(p.m_components.size() < vis_path->m_components.size()) - return false; - for(size_t i = 0; i < vis_path->m_components.size(); i ++) - { - if(p.m_components[i] != vis_path->m_components[i]) - return false; - } - return true; - } + bool is_visible(const ::HIR::SimplePath& p) const; - friend ::std::ostream& operator<<(::std::ostream& os, const Publicity& x) { - if( !x.vis_path ) { - os << "pub"; - } - else if( *x.vis_path == ::HIR::SimplePath() ) { - os << "priv"; - } - else { - os << "pub(" << *x.vis_path << ")"; - } - return os; - } + friend ::std::ostream& operator<<(::std::ostream& os, const Publicity& x); }; template -- cgit v1.2.3 From b48167dec0c1c05b463991a8db5a8db70a5ae604 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 19 May 2019 22:15:02 +0800 Subject: All - Switch to using interned (de-duplicated) RcString-s instead of std::string for paths/identifiers --- src/ast/ast.cpp | 26 ++-- src/ast/ast.hpp | 59 ++++---- src/ast/attrs.hpp | 10 +- src/ast/crate.cpp | 23 +-- src/ast/crate.hpp | 18 +-- src/ast/dump.cpp | 4 +- src/ast/expr.hpp | 24 +-- src/ast/generics.hpp | 6 +- src/ast/item.hpp | 4 +- src/ast/macro.hpp | 10 +- src/ast/path.cpp | 4 +- src/ast/path.hpp | 39 ++--- src/ast/pattern.cpp | 2 +- src/ast/pattern.hpp | 4 +- src/ast/types.cpp | 7 +- src/ast/types.hpp | 11 +- src/coretypes.hpp | 2 +- src/expand/asm.cpp | 4 +- src/expand/assert.cpp | 8 +- src/expand/cfg.cpp | 12 +- src/expand/concat.cpp | 4 +- src/expand/derive.cpp | 276 ++++++++++++++++++----------------- src/expand/env.cpp | 20 +-- src/expand/file_line.cpp | 14 +- src/expand/format_args.cpp | 63 ++++---- src/expand/include.cpp | 15 +- src/expand/macro_rules.cpp | 15 +- src/expand/mod.cpp | 19 ++- src/expand/proc_macro.cpp | 16 +- src/expand/proc_macro.hpp | 8 +- src/expand/rustc_diagnostics.cpp | 14 +- src/expand/stringify.cpp | 2 +- src/expand/test.cpp | 2 +- src/expand/test_harness.cpp | 4 +- src/hir/crate_post_load.cpp | 2 +- src/hir/deserialise.cpp | 139 +++++++++++++----- src/hir/expr.hpp | 26 ++-- src/hir/from_ast.cpp | 55 +++---- src/hir/from_ast.hpp | 2 +- src/hir/from_ast_expr.cpp | 8 +- src/hir/generic_params.cpp | 2 +- src/hir/generic_params.hpp | 16 +- src/hir/hir.cpp | 2 +- src/hir/hir.hpp | 52 +++---- src/hir/hir_ops.cpp | 14 +- src/hir/item_path.hpp | 11 +- src/hir/main_bindings.hpp | 2 +- src/hir/path.cpp | 6 +- src/hir/path.hpp | 26 ++-- src/hir/pattern.cpp | 5 +- src/hir/pattern.hpp | 8 +- src/hir/serialise.cpp | 51 ++++++- src/hir/serialise_lowlevel.cpp | 56 ++++++- src/hir/serialise_lowlevel.hpp | 29 +++- src/hir/type.hpp | 8 +- src/hir_conv/constant_evaluation.cpp | 2 +- src/hir_expand/closures.cpp | 26 ++-- src/hir_expand/vtable.cpp | 11 +- src/hir_typeck/expr_check.cpp | 4 +- src/hir_typeck/expr_cs.cpp | 19 +-- src/hir_typeck/helpers.cpp | 49 +++---- src/hir_typeck/helpers.hpp | 14 +- src/hir_typeck/impl_ref.hpp | 8 +- src/hir_typeck/outer.cpp | 5 +- src/hir_typeck/static.cpp | 22 +-- src/hir_typeck/static.hpp | 4 +- src/include/ident.hpp | 12 +- src/include/rc_string.hpp | 81 +++++++--- src/include/synext_macro.hpp | 5 +- src/macro_rules/eval.cpp | 14 +- src/macro_rules/macro_rules.hpp | 12 +- src/macro_rules/parse.cpp | 14 +- src/main.cpp | 4 +- src/mir/check.cpp | 7 +- src/mir/cleanup.cpp | 6 +- src/mir/from_hir.cpp | 10 +- src/mir/mir.hpp | 4 +- src/parse/common.hpp | 2 +- src/parse/expr.cpp | 44 +++--- src/parse/lex.cpp | 14 +- src/parse/paths.cpp | 10 +- src/parse/pattern.cpp | 12 +- src/parse/root.cpp | 139 +++++++++--------- src/parse/token.cpp | 13 +- src/parse/token.hpp | 4 + src/parse/tokenstream.cpp | 4 +- src/parse/types.cpp | 9 +- src/rc_string.cpp | 113 ++++++++++++-- src/resolve/absolute.cpp | 26 ++-- src/resolve/index.cpp | 10 +- src/resolve/use.cpp | 19 ++- src/trans/auto_impls.cpp | 2 +- src/trans/codegen_c.cpp | 11 +- src/trans/codegen_mmir.cpp | 7 +- src/trans/enumerate.cpp | 10 +- src/trans/mangling.cpp | 15 +- 96 files changed, 1202 insertions(+), 864 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 03257fc6..f1a68680 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -107,16 +107,16 @@ Function Function::clone() const return rv; } -void Trait::add_type(::std::string name, AttributeList attrs, TypeRef type) { +void Trait::add_type(RcString name, AttributeList attrs, TypeRef type) { m_items.push_back( Named(mv$(name), Item::make_Type({TypeAlias(GenericParams(), mv$(type))}), true) ); m_items.back().data.attrs = mv$(attrs); } -void Trait::add_function(::std::string name, AttributeList attrs, Function fcn) { +void Trait::add_function(RcString name, AttributeList attrs, Function fcn) { DEBUG("trait fn " << name); m_items.push_back( Named(mv$(name), Item::make_Function({mv$(fcn)}), true) ); m_items.back().data.attrs = mv$(attrs); } -void Trait::add_static(::std::string name, AttributeList attrs, Static v) { +void Trait::add_static(RcString name, AttributeList attrs, Static v) { m_items.push_back( Named(mv$(name), Item::make_Static({mv$(v)}), true) ); m_items.back().data.attrs = mv$(attrs); } @@ -126,7 +126,7 @@ void Trait::set_is_marker() { bool Trait::is_marker() const { return m_is_marker; } -bool Trait::has_named_item(const ::std::string& name, bool& out_is_fcn) const +bool Trait::has_named_item(const RcString& name, bool& out_is_fcn) const { for( const auto& i : m_items ) { @@ -208,16 +208,16 @@ Union Union::clone() const return os << "impl<" << impl.m_params << "> " << impl.m_trait.ent << " for " << impl.m_type << ""; } -void Impl::add_function(bool is_public, bool is_specialisable, ::std::string name, Function fcn) +void Impl::add_function(bool is_public, bool is_specialisable, RcString name, Function fcn) { DEBUG("impl fn " << name); m_items.push_back( ImplItem { is_public, is_specialisable, mv$(name), box$( Item::make_Function(mv$(fcn)) ) } ); } -void Impl::add_type(bool is_public, bool is_specialisable, ::std::string name, TypeRef type) +void Impl::add_type(bool is_public, bool is_specialisable, RcString name, TypeRef type) { m_items.push_back( ImplItem { is_public, is_specialisable, mv$(name), box$( Item::make_Type(TypeAlias(GenericParams(), mv$(type))) ) } ); } -void Impl::add_static(bool is_public, bool is_specialisable, ::std::string name, Static v) +void Impl::add_static(bool is_public, bool is_specialisable, RcString name, Static v) { m_items.push_back( ImplItem { is_public, is_specialisable, mv$(name), box$( Item::make_Static(mv$(v)) ) } ); } @@ -225,7 +225,7 @@ void Impl::add_macro_invocation(MacroInvocation item) { m_items.push_back( ImplItem { false, false, "", box$( Item::make_MacroInv(mv$(item)) ) } ); } -bool Impl::has_named_item(const ::std::string& name) const +bool Impl::has_named_item(const RcString& name) const { for( const auto& it : this->items() ) { @@ -271,7 +271,7 @@ ExternBlock ExternBlock::clone() const } ::std::shared_ptr Module::add_anon() { - auto rv = ::std::shared_ptr( new Module(m_my_path + FMT("#" << m_anon_modules.size())) ); + auto rv = ::std::shared_ptr( new Module(m_my_path + RcString::new_interned(FMT("#" << m_anon_modules.size()))) ); DEBUG("New anon " << rv->m_my_path); rv->m_file_info = m_file_info; @@ -289,20 +289,20 @@ void Module::add_item( Named named_item ) { DEBUG(m_my_path << "::" << i.name << " = " << i.data.tag_str() << ", attrs = " << i.data.attrs); } } -void Module::add_item(bool is_pub, ::std::string name, Item it, AttributeList attrs) { +void Module::add_item(bool is_pub, RcString name, Item it, AttributeList attrs) { it.attrs = mv$(attrs); add_item( Named( mv$(name), mv$(it), is_pub ) ); } -void Module::add_ext_crate(bool is_public, ::std::string ext_name, ::std::string imp_name, AttributeList attrs) { +void Module::add_ext_crate(bool is_public, RcString ext_name, RcString imp_name, AttributeList attrs) { this->add_item( is_public, imp_name, Item::make_Crate({mv$(ext_name)}), mv$(attrs) ); } void Module::add_macro_invocation(MacroInvocation item) { this->add_item( false, "", Item( mv$(item) ), ::AST::AttributeList {} ); } -void Module::add_macro(bool is_exported, ::std::string name, MacroRulesPtr macro) { +void Module::add_macro(bool is_exported, RcString name, MacroRulesPtr macro) { m_macros.push_back( Named( mv$(name), mv$(macro), is_exported ) ); } -void Module::add_macro_import(::std::string name, const MacroRules& mr) { +void Module::add_macro_import(RcString name, const MacroRules& mr) { m_macro_import_res.push_back( Named( mv$(name), &mr, false ) ); } diff --git a/src/ast/ast.hpp b/src/ast/ast.hpp index f6f97fce..bfef9cff 100644 --- a/src/ast/ast.hpp +++ b/src/ast/ast.hpp @@ -58,12 +58,12 @@ struct StructItem { ::AST::AttributeList m_attrs; bool m_is_public; - ::std::string m_name; + RcString m_name; TypeRef m_type; //StructItem() {} - StructItem(::AST::AttributeList attrs, bool is_pub, ::std::string name, TypeRef ty): + StructItem(::AST::AttributeList attrs, bool is_pub, RcString name, TypeRef ty): m_attrs( mv$(attrs) ), m_is_public(is_pub), m_name( mv$(name) ), @@ -222,16 +222,16 @@ public: const NamedList& items() const { return m_items; } NamedList& items() { return m_items; } - void add_type(::std::string name, AttributeList attrs, TypeRef type); - void add_function(::std::string name, AttributeList attrs, Function fcn); - void add_static(::std::string name, AttributeList attrs, Static v); + void add_type(RcString name, AttributeList attrs, TypeRef type); + void add_function(RcString name, AttributeList attrs, Function fcn); + void add_static(RcString name, AttributeList attrs, Static v); void set_is_marker(); bool is_marker() const; void set_is_unsafe() { m_is_unsafe = true; } bool is_unsafe() const { return m_is_unsafe; } - bool has_named_item(const ::std::string& name, bool& out_is_fcn) const; + bool has_named_item(const RcString& name, bool& out_is_fcn) const; Trait clone() const; }; @@ -257,28 +257,28 @@ TAGGED_UNION_EX(EnumVariantData, (), Value, struct EnumVariant { AttributeList m_attrs; - ::std::string m_name; + RcString m_name; EnumVariantData m_data; EnumVariant() { } - EnumVariant(AttributeList attrs, ::std::string name, Expr&& value): + EnumVariant(AttributeList attrs, RcString name, Expr&& value): m_attrs( mv$(attrs) ), m_name( mv$(name) ), m_data( EnumVariantData::make_Value({mv$(value)}) ) { } - EnumVariant(AttributeList attrs, ::std::string name, ::std::vector sub_types): + EnumVariant(AttributeList attrs, RcString name, ::std::vector sub_types): m_attrs( mv$(attrs) ), m_name( ::std::move(name) ), m_data( EnumVariantData::make_Tuple( {mv$(sub_types)} ) ) { } - EnumVariant(AttributeList attrs, ::std::string name, ::std::vector fields): + EnumVariant(AttributeList attrs, RcString name, ::std::vector fields): m_attrs( mv$(attrs) ), m_name( ::std::move(name) ), m_data( EnumVariantData::make_Struct( {mv$(fields)} ) ) @@ -425,7 +425,7 @@ public: struct ImplItem { bool is_pub; // Ignored for trait impls bool is_specialisable; - ::std::string name; + RcString name; ::std::unique_ptr data; }; @@ -445,9 +445,9 @@ public: {} Impl& operator=(Impl&&) = default; - void add_function(bool is_public, bool is_specialisable, ::std::string name, Function fcn); - void add_type(bool is_public, bool is_specialisable, ::std::string name, TypeRef type); - void add_static(bool is_public, bool is_specialisable, ::std::string name, Static v); + void add_function(bool is_public, bool is_specialisable, RcString name, Function fcn); + void add_type(bool is_public, bool is_specialisable, RcString name, TypeRef type); + void add_static(bool is_public, bool is_specialisable, RcString name, Static v); void add_macro_invocation( MacroInvocation inv ); const ImplDef& def() const { return m_def; } @@ -455,7 +455,7 @@ public: const ::std::vector& items() const { return m_items; } ::std::vector& items() { return m_items; } - bool has_named_item(const ::std::string& name) const; + bool has_named_item(const RcString& name) const; friend ::std::ostream& operator<<(::std::ostream& os, const Impl& impl); @@ -468,7 +468,7 @@ struct UseItem struct Ent { Span sp; // Span covering just the path (final component) ::AST::Path path; - ::std::string name; // If "", this is a glob/wildcard use + RcString name; // If "", this is a glob/wildcard use }; ::std::vector entries; @@ -533,23 +533,23 @@ public: }; // TODO: Document difference between namespace and Type - ::std::unordered_map< ::std::string, IndexEnt > m_namespace_items; - ::std::unordered_map< ::std::string, IndexEnt > m_type_items; - ::std::unordered_map< ::std::string, IndexEnt > m_value_items; + ::std::unordered_map< RcString, IndexEnt > m_namespace_items; + ::std::unordered_map< RcString, IndexEnt > m_type_items; + ::std::unordered_map< RcString, IndexEnt > m_value_items; // List of macros imported from other modules (via #[macro_use], includes proc macros) // - First value is an absolute path to the macro (including crate name) struct MacroImport { bool is_pub; - ::std::string name; // Can be different, if `use foo as bar` is used - ::std::vector<::std::string> path; // includes the crate name + RcString name; // Can be different, if `use foo as bar` is used + ::std::vector path; // includes the crate name const MacroRules* macro_ptr; }; ::std::vector m_macro_imports; struct Import { bool is_pub; - ::std::string name; + RcString name; ::AST::Path path; // If `name` is "", then this is a module/enum to glob }; ::std::vector m_item_imports; @@ -562,19 +562,19 @@ public: } bool is_anon() const { - return m_my_path.nodes().size() > 0 && m_my_path.nodes().back().name()[0] == '#'; + return m_my_path.nodes().size() > 0 && m_my_path.nodes().back().name().c_str()[0] == '#'; } /// Create an anon module (for use inside expressions) ::std::shared_ptr add_anon(); void add_item(Named item); - void add_item(bool is_pub, ::std::string name, Item it, AttributeList attrs); - void add_ext_crate(bool is_public, ::std::string ext_name, ::std::string imp_name, AttributeList attrs); + void add_item(bool is_pub, RcString name, Item it, AttributeList attrs); + void add_ext_crate(bool is_public, RcString ext_name, RcString imp_name, AttributeList attrs); void add_macro_invocation(MacroInvocation item); - void add_macro(bool is_exported, ::std::string name, MacroRulesPtr macro); - void add_macro_import(::std::string name, const MacroRules& mr); + void add_macro(bool is_exported, RcString name, MacroRulesPtr macro); + void add_macro_import(RcString name, const MacroRules& mr); @@ -590,9 +590,6 @@ public: NamedList& macros() { return m_macros; } const NamedList& macros() const { return m_macros; } const ::std::vector > macro_imports_res() const { return m_macro_import_res; } - -private: - void resolve_macro_import(const Crate& crate, const ::std::string& modname, const ::std::string& macro_name); }; TAGGED_UNION_EX(Item, (), None, @@ -610,7 +607,7 @@ TAGGED_UNION_EX(Item, (), None, (Macro, MacroRulesPtr), (Module, Module), (Crate, struct { - ::std::string name; + RcString name; }), (Type, TypeAlias), diff --git a/src/ast/attrs.hpp b/src/ast/attrs.hpp index a15b4175..04328130 100644 --- a/src/ast/attrs.hpp +++ b/src/ast/attrs.hpp @@ -74,24 +74,24 @@ TAGGED_UNION(AttributeData, None, class Attribute { Span m_span; - ::std::string m_name; + RcString m_name; AttributeData m_data; mutable bool m_is_used; // TODO: Parse as a TT then expand? public: - Attribute(Span sp, ::std::string name): + Attribute(Span sp, RcString name): m_span(::std::move(sp)), m_name(name), m_data( AttributeData::make_None({}) ) { } - Attribute(Span sp, ::std::string name, ::std::string str_val): + Attribute(Span sp, RcString name, ::std::string str_val): m_span(::std::move(sp)), m_name(name), m_data( AttributeData::make_String({mv$(str_val)}) ) { } - Attribute(Span sp, ::std::string name, ::std::vector items): + Attribute(Span sp, RcString name, ::std::vector items): m_span(::std::move(sp)), m_name(name), m_data( AttributeData::make_List({mv$(items)}) ) @@ -123,7 +123,7 @@ public: bool is_used() const { return m_is_used; } const Span& span() const { return m_span; } - const ::std::string& name() const { return m_name; } + const RcString& name() const { return m_name; } const AttributeData& data() const { return m_data; } // Legacy accessors/checkers diff --git a/src/ast/crate.cpp b/src/ast/crate.cpp index 5717cbdb..c9856781 100644 --- a/src/ast/crate.cpp +++ b/src/ast/crate.cpp @@ -64,7 +64,7 @@ void Crate::load_externs() TU_IFLET(AST::Item, it.data, Crate, c, if( check_item_cfg(it.data.attrs) ) { - c.name = load_extern_crate( it.data.span, c.name ); + c.name = load_extern_crate( it.data.span, c.name.c_str() ); } ) } @@ -109,12 +109,12 @@ void Crate::load_externs() } // TODO: Handle disambiguating crates with the same name (e.g. libc in std and crates.io libc) // - Crates recorded in rlibs should specify a hash/tag that's passed in to this function. -::std::string Crate::load_extern_crate(Span sp, const ::std::string& name, const ::std::string& basename/*=""*/) +RcString Crate::load_extern_crate(Span sp, const RcString& name, const ::std::string& basename/*=""*/) { DEBUG("Loading crate '" << name << "'"); ::std::string path; - auto it = g_crate_overrides.find(name); + auto it = g_crate_overrides.find(name.c_str()); if(basename == "" && it != g_crate_overrides.end()) { path = it->second; @@ -140,18 +140,19 @@ void Crate::load_externs() else { ::std::vector<::std::string> paths; - auto name_prefix = "lib"+name+"-"; + auto direct_filename = FMT("lib" << name.c_str() << ".hir"); + auto name_prefix = FMT("lib" << name.c_str() << "-"); // Search a list of load paths for the crate for(const auto& p : g_crate_load_dirs) { - path = p + "/lib" + name + ".hir"; - // TODO: Search for `p+"/lib"+name+"-*.hir" (which would match e.g. libnum-0.11.hir) + path = p + "/" + direct_filename; if( ::std::ifstream(path).good() ) { paths.push_back(path); } path = ""; + // Search for `p+"/lib"+name+"-*.hir" (which would match e.g. libnum-0.11.hir) auto dp = opendir(p.c_str()); if( !dp ) { continue ; @@ -187,7 +188,7 @@ void Crate::load_externs() // NOTE: Creating `ExternCrate` loads the crate from the specified path auto ec = ExternCrate { name, path }; auto real_name = ec.m_hir->m_crate_name; - assert(!real_name.empty()); + assert(real_name != ""); auto res = m_extern_crates.insert(::std::make_pair( real_name, mv$(ec) )); if( !res.second ) { // Crate already loaded? @@ -214,26 +215,26 @@ void Crate::load_externs() return real_name; } -ExternCrate::ExternCrate(const ::std::string& name, const ::std::string& path): +ExternCrate::ExternCrate(const RcString& name, const ::std::string& path): m_name(name), m_short_name(name), m_filename(path) { TRACE_FUNCTION_F("name=" << name << ", path='" << path << "'"); - m_hir = HIR_Deserialise(path, name); + m_hir = HIR_Deserialise(path); m_hir->post_load_update(name); m_name = m_hir->m_crate_name; } -void ExternCrate::with_all_macros(::std::function cb) const +void ExternCrate::with_all_macros(::std::function cb) const { for(const auto& m : m_hir->m_exported_macros) { cb(m.first, *m.second); } } -const MacroRules* ExternCrate::find_macro_rules(const ::std::string& name) const +const MacroRules* ExternCrate::find_macro_rules(const RcString& name) const { auto i = m_hir->m_exported_macros.find(name); if(i != m_hir->m_exported_macros.end()) diff --git a/src/ast/crate.hpp b/src/ast/crate.hpp index 79cb9cd7..c4e1d5df 100644 --- a/src/ast/crate.hpp +++ b/src/ast/crate.hpp @@ -36,7 +36,7 @@ public: class ProcMacroDef { public: - ::std::string name; + RcString name; ::AST::Path path; ::std::vector<::std::string> attributes; }; @@ -49,9 +49,9 @@ public: ::std::map< ::std::string, ::AST::Path> m_lang_items; public: Module m_root_module; - ::std::map< ::std::string, ExternCrate> m_extern_crates; + ::std::map< RcString, ExternCrate> m_extern_crates; // Mapping filled by searching for (?visible) macros with is_pub=true - ::std::map< ::std::string, const MacroRules*> m_exported_macros; + ::std::map< RcString, const MacroRules*> m_exported_macros; // List of tests (populated in expand if --test is passed) bool m_test_harness = false; @@ -91,27 +91,27 @@ public: /// Load the named crate and returns the crate's unique name /// If the parameter `file` is non-empty, only that particular filename will be loaded (from any of the search paths) - ::std::string load_extern_crate(Span sp, const ::std::string& name, const ::std::string& file=""); + RcString load_extern_crate(Span sp, const RcString& name, const ::std::string& file=""); }; /// Representation of an imported crate class ExternCrate { public: - ::std::string m_name; - ::std::string m_short_name; + RcString m_name; + RcString m_short_name; ::std::string m_filename; ::HIR::CratePtr m_hir; - ExternCrate(const ::std::string& name, const ::std::string& path); + ExternCrate(const RcString& name, const ::std::string& path); ExternCrate(ExternCrate&&) = default; ExternCrate& operator=(ExternCrate&&) = default; ExternCrate(const ExternCrate&) = delete; ExternCrate& operator=(const ExternCrate& ) = delete; - void with_all_macros(::std::function cb) const; - const MacroRules* find_macro_rules(const ::std::string& name) const; + void with_all_macros(::std::function cb) const; + const MacroRules* find_macro_rules(const RcString& name) const; }; extern ::std::vector<::std::string> g_crate_load_dirs; diff --git a/src/ast/dump.cpp b/src/ast/dump.cpp index 00848fb5..9fb34099 100644 --- a/src/ast/dump.cpp +++ b/src/ast/dump.cpp @@ -36,7 +36,7 @@ public: void handle_enum(const AST::Enum& s); void handle_trait(const AST::Trait& s); - void handle_function(bool is_pub, const ::std::string& name, const AST::Function& f); + void handle_function(bool is_pub, const RcString& name, const AST::Function& f); virtual bool is_const() const override { return true; } virtual void visit(AST::ExprNode_Block& n) override { @@ -1133,7 +1133,7 @@ void RustPrinter::handle_trait(const AST::Trait& s) m_os << "\n"; } -void RustPrinter::handle_function(bool is_pub, const ::std::string& name, const AST::Function& f) +void RustPrinter::handle_function(bool is_pub, const RcString& name, const AST::Function& f) { m_os << indent(); m_os << (is_pub ? "pub " : ""); diff --git a/src/ast/expr.hpp b/src/ast/expr.hpp index 7675b29a..a9c82efa 100644 --- a/src/ast/expr.hpp +++ b/src/ast/expr.hpp @@ -90,11 +90,11 @@ struct ExprNode_Try: struct ExprNode_Macro: public ExprNode { - ::std::string m_name; - ::std::string m_ident; + RcString m_name; + RcString m_ident; ::TokenTree m_tokens; - ExprNode_Macro(::std::string name, ::std::string ident, ::TokenTree&& tokens): + ExprNode_Macro(RcString name, RcString ident, ::TokenTree&& tokens): m_name(name), m_ident(ident), m_tokens( move(tokens) ) @@ -140,10 +140,10 @@ struct ExprNode_Flow: CONTINUE, BREAK, } m_type; - ::std::string m_target; + RcString m_target; unique_ptr m_value; - ExprNode_Flow(Type type, ::std::string target, unique_ptr&& value): + ExprNode_Flow(Type type, RcString target, unique_ptr&& value): m_type(type), m_target( move(target) ), m_value( move(value) ) @@ -245,24 +245,24 @@ struct ExprNode_Loop: WHILELET, FOR, } m_type; - ::std::string m_label; + RcString m_label; AST::Pattern m_pattern; unique_ptr m_cond; // if NULL, loop is a 'loop' unique_ptr m_code; ExprNode_Loop(): m_type(LOOP) {} - ExprNode_Loop(::std::string label, unique_ptr code): + ExprNode_Loop(RcString label, unique_ptr code): m_type(LOOP), m_label( ::std::move(label) ), m_code( ::std::move(code) ) {} - ExprNode_Loop(::std::string label, unique_ptr cond, unique_ptr code): + ExprNode_Loop(RcString label, unique_ptr cond, unique_ptr code): m_type(WHILE), m_label( ::std::move(label) ), m_cond( ::std::move(cond) ), m_code( ::std::move(code) ) {} - ExprNode_Loop(::std::string label, Type type, AST::Pattern pattern, unique_ptr val, unique_ptr code): + ExprNode_Loop(RcString label, Type type, AST::Pattern pattern, unique_ptr val, unique_ptr code): m_type(type), m_label( ::std::move(label) ), m_pattern( ::std::move(pattern) ), @@ -430,7 +430,7 @@ struct ExprNode_StructLiteral: { struct Ent { AttributeList attrs; - ::std::string name; + RcString name; unique_ptr value; }; typedef ::std::vector t_values; @@ -493,9 +493,9 @@ struct ExprNode_Field: public ExprNode { ::std::unique_ptr m_obj; - ::std::string m_name; + RcString m_name; - ExprNode_Field(::std::unique_ptr&& obj, ::std::string name): + ExprNode_Field(::std::unique_ptr&& obj, RcString name): m_obj( ::std::move(obj) ), m_name( ::std::move(name) ) { diff --git a/src/ast/generics.hpp b/src/ast/generics.hpp index c222044c..bfc7080b 100644 --- a/src/ast/generics.hpp +++ b/src/ast/generics.hpp @@ -17,7 +17,7 @@ class TypeParam ::AST::AttributeList m_attrs; Span m_span; // TODO: use an Ident? - ::std::string m_name; + RcString m_name; ::TypeRef m_default; public: TypeParam(TypeParam&& x) = default; @@ -30,7 +30,7 @@ public: { } - TypeParam(Span sp, ::AST::AttributeList attrs, ::std::string name): + TypeParam(Span sp, ::AST::AttributeList attrs, RcString name): m_attrs( ::std::move(attrs) ), m_span( ::std::move(sp) ), m_name( ::std::move(name) ), @@ -44,7 +44,7 @@ public: const ::AST::AttributeList& attrs() const { return m_attrs; } const Span& span() const { return m_span; } - const ::std::string& name() const { return m_name; } + const RcString& name() const { return m_name; } const TypeRef& get_default() const { return m_default; } TypeRef& get_default() { return m_default; } diff --git a/src/ast/item.hpp b/src/ast/item.hpp index 0074ce9a..ee83a8db 100644 --- a/src/ast/item.hpp +++ b/src/ast/item.hpp @@ -15,7 +15,7 @@ namespace AST { template struct Named { - ::std::string name; + RcString name; T data; bool is_pub; @@ -25,7 +25,7 @@ struct Named Named(Named&&) = default; Named(const Named&) = default; Named& operator=(Named&&) = default; - Named(::std::string name, T data, bool is_pub): + Named(RcString name, T data, bool is_pub): name( ::std::move(name) ), data( ::std::move(data) ), is_pub( is_pub ) diff --git a/src/ast/macro.hpp b/src/ast/macro.hpp index 5b2223ce..e94de8f1 100644 --- a/src/ast/macro.hpp +++ b/src/ast/macro.hpp @@ -18,8 +18,8 @@ class MacroInvocation { Span m_span; - ::std::string m_macro_name; - ::std::string m_ident; + RcString m_macro_name; + RcString m_ident; TokenTree m_input; public: MacroInvocation(MacroInvocation&&) = default; @@ -31,7 +31,7 @@ public: { } - MacroInvocation(Span span, ::std::string macro, ::std::string ident, TokenTree input): + MacroInvocation(Span span, RcString macro, RcString ident, TokenTree input): m_span( mv$(span) ), m_macro_name( mv$(macro) ), m_ident( mv$(ident) ), @@ -48,9 +48,9 @@ public: } const Span& span() const { return m_span; } - const ::std::string& name() const { return m_macro_name; } + const RcString& name() const { return m_macro_name; } - const ::std::string& input_ident() const { return m_ident; } + const RcString& input_ident() const { return m_ident; } const TokenTree& input_tt() const { return m_input; } TokenTree& input_tt() { return m_input; } diff --git a/src/ast/path.cpp b/src/ast/path.cpp index d156f465..830e7372 100644 --- a/src/ast/path.cpp +++ b/src/ast/path.cpp @@ -148,7 +148,7 @@ Ordering PathParams::ord(const PathParams& x) const } // --- AST::PathNode -PathNode::PathNode(::std::string name, PathParams args): +PathNode::PathNode(RcString name, PathParams args): m_name( mv$(name) ), m_params( mv$(args) ) { @@ -256,7 +256,7 @@ void Path::bind_variable(unsigned int slot) { m_bindings.value = PathBinding_Value::make_Variable({slot}); } -void Path::bind_enum_var(const Enum& ent, const ::std::string& name) +void Path::bind_enum_var(const Enum& ent, const RcString& name) { auto it = ::std::find_if(ent.variants().begin(), ent.variants().end(), [&](const auto& x) { return x.m_name == name; }); if( it == ent.variants().end() ) diff --git a/src/ast/path.hpp b/src/ast/path.hpp index faa1ffe6..c611c819 100644 --- a/src/ast/path.hpp +++ b/src/ast/path.hpp @@ -127,15 +127,15 @@ TAGGED_UNION_EX(PathBinding_Macro, (), Unbound, ( }), (ProcMacroDerive, struct { const ExternCrate* crate_; - ::std::string mac_name; + RcString mac_name; }), (ProcMacroAttribute, struct { const ExternCrate* crate_; - ::std::string mac_name; + RcString mac_name; }), (ProcMacro, struct { const ExternCrate* crate_; - ::std::string mac_name; + RcString mac_name; }), (MacroRules, struct { const ExternCrate* crate_; // Can be NULL @@ -157,12 +157,12 @@ struct PathParams { ::std::vector< LifetimeRef > m_lifetimes; ::std::vector< TypeRef > m_types; - ::std::vector< ::std::pair< ::std::string, TypeRef> > m_assoc; + ::std::vector< ::std::pair< RcString, TypeRef> > m_assoc; PathParams(PathParams&& x) = default; PathParams(const PathParams& x); PathParams() {} - PathParams(::std::vector lfts, ::std::vector tys, ::std::vector<::std::pair<::std::string,TypeRef>> a): + PathParams(::std::vector lfts, ::std::vector tys, ::std::vector<::std::pair> a): m_lifetimes(mv$(lfts)), m_types(mv$(tys)), m_assoc(mv$(a)) @@ -182,12 +182,12 @@ struct PathParams class PathNode { - ::std::string m_name; + RcString m_name; PathParams m_params; public: PathNode() {} - PathNode(::std::string name, PathParams args = {}); - const ::std::string& name() const { return m_name; } + PathNode(RcString name, PathParams args = {}); + const RcString& name() const { return m_name; } const ::AST::PathParams& args() const { return m_params; } ::AST::PathParams& args() { return m_params; } @@ -205,7 +205,7 @@ public: TAGGED_UNION(Class, Invalid, (Invalid, struct {}), (Local, struct { // Variable / Type param (resolved) - ::std::string name; + RcString name; } ), (Relative, struct { // General relative Ident::Hygiene hygiene; @@ -219,7 +219,7 @@ public: ::std::vector nodes; } ), (Absolute, struct { // Absolute - ::std::string crate; + RcString crate; ::std::vector nodes; } ), (UFCS, struct { // Type-relative @@ -267,7 +267,7 @@ public: Path& operator=(const AST::Path&) = delete; // ABSOLUTE - Path(::std::string crate, ::std::vector nodes): + Path(RcString crate, ::std::vector nodes): m_class( Class::make_Absolute({ mv$(crate), mv$(nodes)}) ) {} @@ -278,10 +278,10 @@ public: // VARIABLE struct TagLocal {}; - Path(TagLocal, ::std::string name): + Path(TagLocal, RcString name): m_class( Class::make_Local({ mv$(name) }) ) {} - Path(::std::string name): + Path(RcString name): m_class( Class::make_Local({ mv$(name) }) ) {} @@ -301,14 +301,6 @@ public: m_class( Class::make_Super({ count, mv$(nodes) }) ) {} - //void set_crate(::std::string crate) { - // if( m_crate == "" ) { - // m_crate = crate; - // DEBUG("crate set to " << m_crate); - // } - //} - - Class::Tag class_tag() const { return m_class.tag(); } @@ -318,7 +310,7 @@ public: tmp.nodes().push_back( mv$(pn) ); return tmp; } - Path operator+(const ::std::string& s) const { + Path operator+(const RcString& s) const { Path tmp = Path(*this); tmp.append(PathNode(s, {})); return tmp; @@ -370,7 +362,6 @@ public: ) throw ::std::runtime_error("Path::nodes() fell off"); } - //const ::std::string& crate() const { return m_crate; } bool is_parent_of(const Path& x) const; @@ -407,7 +398,7 @@ private: void check_param_counts(const GenericParams& params, bool expect_params, PathNode& node); public: - void bind_enum_var(const Enum& ent, const ::std::string& name); + void bind_enum_var(const Enum& ent, const RcString& name); void bind_function(const Function& ent) { m_bindings.value = PathBinding_Value::make_Function({&ent}); } diff --git a/src/ast/pattern.cpp b/src/ast/pattern.cpp index 72087d95..e13662fe 100644 --- a/src/ast/pattern.cpp +++ b/src/ast/pattern.cpp @@ -223,7 +223,7 @@ AST::Pattern AST::Pattern::clone() const rv.m_data = Data::make_StructTuple({ ::AST::Path(e.path), H::clone_tup(e.tup_pat) }); ), (Struct, - ::std::vector< ::std::pair< ::std::string, Pattern> > sps; + ::std::vector< ::std::pair< RcString, Pattern> > sps; for(const auto& sp : e.sub_patterns) sps.push_back( ::std::make_pair(sp.first, sp.second.clone()) ); rv.m_data = Data::make_Struct({ ::AST::Path(e.path), mv$(sps) }); diff --git a/src/ast/pattern.hpp b/src/ast/pattern.hpp index 40cfa927..81c1126a 100644 --- a/src/ast/pattern.hpp +++ b/src/ast/pattern.hpp @@ -88,7 +88,7 @@ public: (Value, struct { Value start; Value end; } ), (Tuple, TuplePat ), (StructTuple, struct { Path path; TuplePat tup_pat; } ), - (Struct, struct { Path path; ::std::vector< ::std::pair< ::std::string, Pattern> > sub_patterns; bool is_exhaustive; } ), + (Struct, struct { Path path; ::std::vector< ::std::pair< RcString, Pattern> > sub_patterns; bool is_exhaustive; } ), (Slice, struct { ::std::vector sub_pats; }), (SplitSlice, struct { ::std::vector leading; PatternBinding extra_bind; ::std::vector trailing; } ) ); @@ -171,7 +171,7 @@ public: {} struct TagStruct {}; - Pattern(TagStruct, Span sp, Path path, ::std::vector< ::std::pair< ::std::string,Pattern> > sub_patterns, bool is_exhaustive): + Pattern(TagStruct, Span sp, Path path, ::std::vector< ::std::pair< RcString,Pattern> > sub_patterns, bool is_exhaustive): m_span( mv$(sp) ), m_data( Data::make_Struct( { ::std::move(path), ::std::move(sub_patterns), is_exhaustive } ) ) {} diff --git a/src/ast/types.cpp b/src/ast/types.cpp index f9103b37..496cf694 100644 --- a/src/ast/types.cpp +++ b/src/ast/types.cpp @@ -40,13 +40,14 @@ static const struct { {"usize", CORETYPE_UINT}, }; -enum eCoreType coretype_fromstring(const ::std::string& name) +enum eCoreType coretype_fromstring(const char* name) { for(unsigned int i = 0; i < sizeof(CORETYPES)/sizeof(CORETYPES[0]); i ++) { - if( name < CORETYPES[i].name ) + int cmp = strcmp(name, CORETYPES[i].name); + if( cmp < 0 ) break; - if( name == CORETYPES[i].name ) + if( cmp == 0 ) return CORETYPES[i].type; } return CORETYPE_INVAL; diff --git a/src/ast/types.hpp b/src/ast/types.hpp index 0b0f205e..15cb1383 100644 --- a/src/ast/types.hpp +++ b/src/ast/types.hpp @@ -73,6 +73,7 @@ namespace AST { bool is_infer() const { return m_binding == BINDING_INFER; } const Ident& name() const { return m_name; } + uint16_t binding() const { return m_binding; } Ordering ord(const LifetimeRef& x) const { return ::ord(m_name.name, x.m_name.name); } bool operator==(const LifetimeRef& x) const { return ord(x) == OrdEqual; } bool operator!=(const LifetimeRef& x) const { return ord(x) != OrdEqual; } @@ -97,7 +98,7 @@ public: struct TypeArgRef { - ::std::string name; + RcString name; unsigned int level; const AST::GenericParams* params; }; @@ -165,7 +166,7 @@ TAGGED_UNION(TypeData, None, ::std::shared_ptr size; }), (Generic, struct { - ::std::string name; + RcString name; unsigned int index; }), (Path, struct { @@ -276,11 +277,11 @@ public: {} struct TagArg {}; - TypeRef(TagArg, Span sp, ::std::string name, unsigned int binding = ~0u): + TypeRef(TagArg, Span sp, RcString name, unsigned int binding = ~0u): m_span( mv$(sp) ), m_data(TypeData::make_Generic({ name, binding })) {} - TypeRef(Span sp, ::std::string name, unsigned int binding = ~0u): + TypeRef(Span sp, RcString name, unsigned int binding = ~0u): TypeRef(TagArg(), mv$(sp), mv$(name), binding) {} @@ -314,7 +315,7 @@ public: AST::Path& path() { return m_data.as_Path().path; } bool is_type_param() const { return m_data.is_Generic(); } - const ::std::string& type_param() const { return m_data.as_Generic().name; } + const RcString& type_param() const { return m_data.as_Generic().name; } bool is_reference() const { return m_data.is_Borrow(); } bool is_pointer() const { return m_data.is_Pointer(); } diff --git a/src/coretypes.hpp b/src/coretypes.hpp index 7665f5ba..692473e5 100644 --- a/src/coretypes.hpp +++ b/src/coretypes.hpp @@ -24,7 +24,7 @@ enum eCoreType CORETYPE_F64, }; -extern enum eCoreType coretype_fromstring(const ::std::string& name); +extern enum eCoreType coretype_fromstring(const char* name); extern const char* coretype_name(const eCoreType ct); #endif // CORETYPES_HPP_INCLUDED diff --git a/src/expand/asm.cpp b/src/expand/asm.cpp index d895c32d..f8b3984d 100644 --- a/src/expand/asm.cpp +++ b/src/expand/asm.cpp @@ -35,12 +35,10 @@ namespace class CAsmExpander: public ExpandProcMacro { - ::std::unique_ptr expand(const Span& sp, const ::AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override + ::std::unique_ptr expand(const Span& sp, const ::AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override { Token tok; auto lex = TTStream(sp, tt); - if( ident != "" ) - ERROR(sp, E0000, "asm! doesn't take an ident"); auto template_text = get_string(sp, lex, crate, mod); ::std::vector<::AST::ExprNode_Asm::ValRef> outputs; diff --git a/src/expand/assert.cpp b/src/expand/assert.cpp index 5bb23bde..ffba7b98 100644 --- a/src/expand/assert.cpp +++ b/src/expand/assert.cpp @@ -15,14 +15,12 @@ class CExpander_assert: public ExpandProcMacro { - ::std::unique_ptr expand(const Span& sp, const ::AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override + ::std::unique_ptr expand(const Span& sp, const ::AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override { Token tok; auto lex = TTStream(sp, tt); lex.parse_state().module = &mod; - if( ident != "" ) - ERROR(sp, E0000, "format_args! doesn't take an ident"); // assertion condition auto n = Parse_Expr0(lex); @@ -39,7 +37,7 @@ class CExpander_assert: toks.push_back( Token(InterpolatedFragment(InterpolatedFragment::EXPR, n.release())) ); toks.push_back( Token(TOK_BRACE_OPEN) ); // User-provided message - toks.push_back( Token(TOK_IDENT, "panic") ); + toks.push_back( Token(TOK_IDENT, RcString::new_interned("panic")) ); toks.push_back( Token(TOK_EXCLAM) ); toks.push_back( Token(TOK_PAREN_OPEN) ); while(lex.lookahead(0) != TOK_EOF ) @@ -63,7 +61,7 @@ class CExpander_assert: toks.push_back( Token(TOK_BRACE_OPEN) ); // Auto-generated message - toks.push_back( Token(TOK_IDENT, "panic") ); + toks.push_back( Token(TOK_IDENT, RcString::new_interned("panic")) ); toks.push_back( Token(TOK_EXCLAM) ); toks.push_back( Token(TOK_PAREN_OPEN) ); toks.push_back( Token(TOK_STRING, ss.str()) ); diff --git a/src/expand/cfg.cpp b/src/expand/cfg.cpp index 773a38c4..7e922779 100644 --- a/src/expand/cfg.cpp +++ b/src/expand/cfg.cpp @@ -60,7 +60,7 @@ bool check_cfg(const Span& sp, const ::AST::Attribute& mi) { } else if( mi.has_string() ) { // Equaliy - auto its = g_cfg_values.equal_range(mi.name()); + auto its = g_cfg_values.equal_range(mi.name().c_str()); for(auto it = its.first; it != its.second; ++it) { DEBUG(""<second<<"' == '"< expand(const Span& sp, const ::AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override + ::std::unique_ptr expand(const Span& sp, const ::AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override { - if( ident != "" ) { - ERROR(sp, E0000, "cfg! doesn't take an identifier"); - } - auto lex = TTStream(sp, tt); auto attrs = Parse_MetaItem(lex); DEBUG("cfg!() - " << attrs); diff --git a/src/expand/concat.cpp b/src/expand/concat.cpp index 29a066df..bd741e2f 100644 --- a/src/expand/concat.cpp +++ b/src/expand/concat.cpp @@ -16,13 +16,11 @@ class CConcatExpander: public ExpandProcMacro { - ::std::unique_ptr expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override + ::std::unique_ptr expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override { Token tok; auto lex = TTStream(sp, tt); - if( ident != "" ) - ERROR(sp, E0000, "format_args! doesn't take an ident"); ::std::string rv; do { diff --git a/src/expand/derive.cpp b/src/expand/derive.cpp index dddd82b6..6dea3028 100644 --- a/src/expand/derive.cpp +++ b/src/expand/derive.cpp @@ -58,6 +58,15 @@ static inline ::std::vector vec$(T v1, T v2, T v3, T v4, T v5) { tmp.push_back( mv$(v5) ); return mv$(tmp); } +static AST::Path get_path(const RcString& core_name, ::std::string c1, ::std::string c2) +{ + return AST::Path(core_name, { AST::PathNode(RcString::new_interned(c1), {}), AST::PathNode(RcString::new_interned(c2), {}) }); +} +static AST::Path get_path(const RcString& core_name, ::std::string c1, ::std::string c2, ::std::string c3) +{ + return AST::Path(core_name, { AST::PathNode(RcString::new_interned(c1), {}), AST::PathNode(RcString::new_interned(c2), {}), AST::PathNode(RcString::new_interned(c3), {}) }); +} + static inline AST::ExprNodeP mk_exprnodep(AST::ExprNode* en){ return AST::ExprNodeP(en); } //#define NEWNODE(type, ...) mk_exprnodep(new type(__VA_ARGS__)) @@ -65,7 +74,7 @@ static inline AST::ExprNodeP mk_exprnodep(AST::ExprNode* en){ return AST::ExprNo struct DeriveOpts { - ::std::string core_name; + RcString core_name; const ::std::vector<::AST::Attribute>& derive_items; }; @@ -288,7 +297,7 @@ class Deriver_Debug: // throw CompileError::Todo("derive(Debug) - _try"); //} - AST::Impl make_ret(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector types_to_bound, AST::ExprNodeP node) const + AST::Impl make_ret(Span sp, const RcString& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector types_to_bound, AST::ExprNodeP node) const { const AST::Path debug_trait = AST::Path(core_name, { AST::PathNode("fmt", {}), AST::PathNode("Debug", {}) }); TypeRef f_type(TypeRef::TagReference(), sp, AST::LifetimeRef(), true, @@ -319,7 +328,7 @@ public: AST::Impl handle_item(Span sp, const DeriveOpts& opts, const AST::GenericParams& p, const TypeRef& type, const AST::Struct& str) const override { - const ::std::string& name = type.path().nodes().back().name(); + ::std::string name = type.path().nodes().back().name().c_str(); // Generate code for Debug AST::ExprNodeP node; @@ -342,7 +351,7 @@ public: node = NEWNODE(CallMethod, mv$(node), AST::PathNode("field",{}), vec$( - NEWNODE(String, fld.m_name), + NEWNODE(String, fld.m_name.c_str()), NEWNODE(UniOp, AST::ExprNode_UniOp::REF, NEWNODE(UniOp, AST::ExprNode_UniOp::REF, NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), @@ -368,7 +377,7 @@ public: NEWNODE(UniOp, AST::ExprNode_UniOp::REF, NEWNODE(UniOp, AST::ExprNode_UniOp::REF, NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), - FMT(idx) + RcString::new_interned(FMT(idx)) ) )) ) @@ -396,7 +405,7 @@ public: code = NEWNODE(CallMethod, NEWNODE(NamedValue, AST::Path("f")), AST::PathNode("write_str",{}), - vec$( NEWNODE(String, v.m_name) ) + vec$( NEWNODE(String, v.m_name.c_str()) ) ); pat_a = AST::Pattern(AST::Pattern::TagValue(), sp, AST::Pattern::Value::make_Named(base_path + v.m_name)); ), @@ -407,12 +416,12 @@ public: node = NEWNODE(NamedValue, AST::Path("f")); node = NEWNODE(CallMethod, mv$(node), AST::PathNode("debug_tuple",{}), - vec$( NEWNODE(String, v.m_name) ) + vec$( NEWNODE(String, v.m_name.c_str()) ) ); for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ ) { - auto name_a = FMT("a" << idx); + auto name_a = RcString::new_interned(FMT("a" << idx)); pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) ); node = NEWNODE(CallMethod, @@ -427,24 +436,24 @@ public: pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_a)); ), (Struct, - ::std::vector< ::std::pair > pats_a; + ::std::vector< ::std::pair > pats_a; AST::ExprNodeP node; node = NEWNODE(NamedValue, AST::Path("f")); node = NEWNODE(CallMethod, mv$(node), AST::PathNode("debug_struct",{}), - vec$( NEWNODE(String, v.m_name) ) + vec$( NEWNODE(String, v.m_name.c_str()) ) ); for( const auto& fld : e.m_fields ) { - auto name_a = FMT("a" << fld.m_name); + auto name_a = RcString::new_interned(FMT("a" << fld.m_name)); pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF)) ); node = NEWNODE(CallMethod, mv$(node), AST::PathNode("field",{}), vec$( - NEWNODE(String, fld.m_name), + NEWNODE(String, fld.m_name.c_str()), NEWNODE(NamedValue, AST::Path(name_a)) ) ); @@ -476,7 +485,7 @@ public: class Deriver_PartialEq: public Deriver { - AST::Impl make_ret(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector types_to_bound, AST::ExprNodeP node) const + AST::Impl make_ret(Span sp, const RcString& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector types_to_bound, AST::ExprNodeP node) const { const AST::Path trait_path(core_name, { AST::PathNode("cmp", {}), AST::PathNode("PartialEq", {}) }); @@ -498,7 +507,7 @@ class Deriver_PartialEq: rv.add_function(false, false, "eq", mv$(fcn)); return mv$(rv); } - AST::ExprNodeP compare_and_ret(Span sp, const ::std::string& core_name, AST::ExprNodeP v1, AST::ExprNodeP v2) const + AST::ExprNodeP compare_and_ret(Span sp, const RcString& core_name, AST::ExprNodeP v1, AST::ExprNodeP v2) const { return NEWNODE(If, NEWNODE(BinOp, AST::ExprNode_BinOp::CMPNEQU, mv$(v1), mv$(v2)), @@ -528,7 +537,7 @@ public: (Tuple, for( unsigned int idx = 0; idx < e.ents.size(); idx ++ ) { - auto fld_name = FMT(idx); + auto fld_name = RcString::new_interned(FMT(idx)); nodes.push_back(this->compare_and_ret( sp, opts.core_name, NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), fld_name), NEWNODE(Field, NEWNODE(NamedValue, AST::Path("v" )), fld_name) @@ -566,8 +575,8 @@ public: for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ ) { - auto name_a = FMT("a" << idx); - auto name_b = FMT("b" << idx); + auto name_a = RcString::new_interned(FMT("a" << idx)); + auto name_b = RcString::new_interned(FMT("b" << idx)); pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) ); pats_b.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_b, ::AST::PatternBinding::Type::REF) ); nodes.push_back(this->compare_and_ret(sp, opts.core_name, @@ -582,14 +591,14 @@ public: code = NEWNODE(Block, mv$(nodes)); ), (Struct, - ::std::vector< ::std::pair > pats_a; - ::std::vector< ::std::pair > pats_b; + ::std::vector< ::std::pair > pats_a; + ::std::vector< ::std::pair > pats_b; ::std::vector nodes; for( const auto& fld : e.m_fields ) { - auto name_a = FMT("a" << fld.m_name); - auto name_b = FMT("b" << fld.m_name); + auto name_a = RcString::new_interned(FMT("a" << fld.m_name)); + auto name_b = RcString::new_interned(FMT("b" << fld.m_name)); pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF)) ); pats_b.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_b, ::AST::PatternBinding::Type::REF)) ); nodes.push_back(this->compare_and_ret(sp, opts.core_name, @@ -642,16 +651,7 @@ public: class Deriver_PartialOrd: public Deriver { - AST::Path get_path(const ::std::string core_name, ::std::string c1, ::std::string c2) const - { - return AST::Path(core_name, { AST::PathNode(c1, {}), AST::PathNode(c2, {}) }); - } - AST::Path get_path(const ::std::string core_name, ::std::string c1, ::std::string c2, ::std::string c3) const - { - return AST::Path(core_name, { AST::PathNode(c1, {}), AST::PathNode(c2, {}), AST::PathNode(c3, {}) }); - } - - AST::Impl make_ret(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector types_to_bound, AST::ExprNodeP node) const + AST::Impl make_ret(Span sp, const RcString& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector types_to_bound, AST::ExprNodeP node) const { const AST::Path trait_path(core_name, { AST::PathNode("cmp", {}), AST::PathNode("PartialOrd", {}) }); const AST::Path path_ordering(core_name, { AST::PathNode("cmp", {}), AST::PathNode("Ordering", {}) }); @@ -678,10 +678,10 @@ class Deriver_PartialOrd: return mv$(rv); } - AST::ExprNodeP make_compare_and_ret(Span sp, const ::std::string& core_name, AST::ExprNodeP v1, AST::ExprNodeP v2) const + AST::ExprNodeP make_compare_and_ret(Span sp, const RcString& core_name, AST::ExprNodeP v1, AST::ExprNodeP v2) const { return NEWNODE(Match, - NEWNODE(CallPath, this->get_path(core_name, "cmp", "PartialOrd", "partial_cmp"), + NEWNODE(CallPath, get_path(core_name, "cmp", "PartialOrd", "partial_cmp"), ::make_vec2( NEWNODE(UniOp, AST::ExprNode_UniOp::REF, mv$(v1)), NEWNODE(UniOp, AST::ExprNode_UniOp::REF, mv$(v2)) @@ -689,13 +689,13 @@ class Deriver_PartialOrd: ), ::make_vec3( ::AST::ExprNode_Match_Arm( - ::make_vec1( AST::Pattern(AST::Pattern::TagValue(), sp, this->get_path(core_name, "option", "Option", "None")) ), + ::make_vec1( AST::Pattern(AST::Pattern::TagValue(), sp, get_path(core_name, "option", "Option", "None")) ), nullptr, - NEWNODE(Flow, AST::ExprNode_Flow::RETURN, "", NEWNODE(NamedValue, this->get_path(core_name, "option", "Option", "None"))) + NEWNODE(Flow, AST::ExprNode_Flow::RETURN, "", NEWNODE(NamedValue, get_path(core_name, "option", "Option", "None"))) ), ::AST::ExprNode_Match_Arm( - ::make_vec1( AST::Pattern(AST::Pattern::TagNamedTuple(), sp, this->get_path(core_name, "option", "Option", "Some"), - ::make_vec1( AST::Pattern(AST::Pattern::TagValue(), sp, this->get_path(core_name, "cmp", "Ordering", "Equal")) ) + ::make_vec1( AST::Pattern(AST::Pattern::TagNamedTuple(), sp, get_path(core_name, "option", "Option", "Some"), + ::make_vec1( AST::Pattern(AST::Pattern::TagValue(), sp, get_path(core_name, "cmp", "Ordering", "Equal")) ) ) ), nullptr, NEWNODE(Tuple, ::std::vector()) @@ -708,10 +708,10 @@ class Deriver_PartialOrd: ) ); } - AST::ExprNodeP make_ret_equal(const ::std::string& core_name) const + AST::ExprNodeP make_ret_equal(const RcString& core_name) const { - return NEWNODE(CallPath, this->get_path(core_name, "option", "Option", "Some"), - ::make_vec1( NEWNODE(NamedValue, this->get_path(core_name, "cmp", "Ordering", "Equal")) ) + return NEWNODE(CallPath, get_path(core_name, "option", "Option", "Some"), + ::make_vec1( NEWNODE(NamedValue, get_path(core_name, "cmp", "Ordering", "Equal")) ) ); } public: @@ -736,7 +736,7 @@ public: (Tuple, for( unsigned int idx = 0; idx < e.ents.size(); idx ++ ) { - auto fld_name = FMT(idx); + auto fld_name = RcString::new_interned(FMT(idx)); nodes.push_back(this->make_compare_and_ret( sp, opts.core_name, NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), fld_name), NEWNODE(Field, NEWNODE(NamedValue, AST::Path("v" )), fld_name) @@ -774,8 +774,8 @@ public: for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ ) { - auto name_a = FMT("a" << idx); - auto name_b = FMT("b" << idx); + auto name_a = RcString::new_interned(FMT("a" << idx)); + auto name_b = RcString::new_interned(FMT("b" << idx)); pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) ); pats_b.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_b, ::AST::PatternBinding::Type::REF) ); @@ -791,14 +791,14 @@ public: code = NEWNODE(Block, mv$(nodes)); ), (Struct, - ::std::vector< ::std::pair > pats_a; - ::std::vector< ::std::pair > pats_b; + ::std::vector< ::std::pair > pats_a; + ::std::vector< ::std::pair > pats_b; ::std::vector nodes; for( const auto& fld : e.m_fields ) { - auto name_a = FMT("a" << fld.m_name); - auto name_b = FMT("b" << fld.m_name); + auto name_a = RcString::new_interned(FMT("a" << fld.m_name)); + auto name_b = RcString::new_interned(FMT("b" << fld.m_name)); pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF)) ); pats_b.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_b, ::AST::PatternBinding::Type::REF)) ); @@ -834,10 +834,10 @@ public: // - Requires a way of emitting said intrinsic into the AST // - LAZY WAY - hard-code ::"core"::intrinsics::discriminant_value { - auto code = NEWNODE(CallPath, this->get_path(opts.core_name, "cmp", "PartialOrd", "partial_cmp"), + auto code = NEWNODE(CallPath, get_path(opts.core_name, "cmp", "PartialOrd", "partial_cmp"), ::make_vec2( - NEWNODE(UniOp, AST::ExprNode_UniOp::REF, NEWNODE(CallPath, this->get_path(opts.core_name, "intrinsics", "discriminant_value"), make_vec1( NEWNODE(NamedValue, AST::Path("self")) )) ), - NEWNODE(UniOp, AST::ExprNode_UniOp::REF, NEWNODE(CallPath, this->get_path(opts.core_name, "intrinsics", "discriminant_value"), make_vec1( NEWNODE(NamedValue, AST::Path("v")) )) ) + NEWNODE(UniOp, AST::ExprNode_UniOp::REF, NEWNODE(CallPath, get_path(opts.core_name, "intrinsics", "discriminant_value"), make_vec1( NEWNODE(NamedValue, AST::Path("self")) )) ), + NEWNODE(UniOp, AST::ExprNode_UniOp::REF, NEWNODE(CallPath, get_path(opts.core_name, "intrinsics", "discriminant_value"), make_vec1( NEWNODE(NamedValue, AST::Path("v")) )) ) ) ); ::std::vector< AST::Pattern> pats = make_vec1( AST::Pattern() ); @@ -862,11 +862,11 @@ public: class Deriver_Eq: public Deriver { - AST::Path get_trait_path(const ::std::string& core_name) const { + AST::Path get_trait_path(const RcString& core_name) const { return AST::Path(core_name, { AST::PathNode("cmp", {}), AST::PathNode("Eq", {}) }); } - AST::Impl make_ret(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector types_to_bound, AST::ExprNodeP node) const + AST::Impl make_ret(Span sp, const RcString& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector types_to_bound, AST::ExprNodeP node) const { const AST::Path trait_path = this->get_trait_path(core_name); @@ -894,6 +894,9 @@ class Deriver_Eq: ); } AST::ExprNodeP field(const ::std::string& name) const { + return NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), RcString::new_interned(name)); + } + AST::ExprNodeP field(const RcString& name) const { return NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), name); } @@ -949,7 +952,7 @@ public: for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ ) { - auto name_a = FMT("a" << idx); + auto name_a = RcString::new_interned(FMT("a" << idx)); pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) ); nodes.push_back( this->assert_is_eq(assert_method_path, NEWNODE(NamedValue, AST::Path(name_a))) ); } @@ -958,12 +961,12 @@ public: code = NEWNODE(Block, mv$(nodes)); ), (Struct, - ::std::vector< ::std::pair > pats_a; + ::std::vector< ::std::pair > pats_a; ::std::vector nodes; for( const auto& fld : e.m_fields ) { - auto name_a = FMT("a" << fld.m_name); + auto name_a = RcString::new_interned(FMT("a" << fld.m_name)); pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF)) ); nodes.push_back( this->assert_is_eq(assert_method_path, NEWNODE(NamedValue, AST::Path(name_a))) ); } @@ -1007,16 +1010,7 @@ public: class Deriver_Ord: public Deriver { - AST::Path get_path(const ::std::string core_name, ::std::string c1, ::std::string c2) const - { - return AST::Path(core_name, { AST::PathNode(c1, {}), AST::PathNode(c2, {}) }); - } - AST::Path get_path(const ::std::string core_name, ::std::string c1, ::std::string c2, ::std::string c3) const - { - return AST::Path(core_name, { AST::PathNode(c1, {}), AST::PathNode(c2, {}), AST::PathNode(c3, {}) }); - } - - AST::Impl make_ret(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector types_to_bound, AST::ExprNodeP node) const + AST::Impl make_ret(Span sp, const RcString& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector types_to_bound, AST::ExprNodeP node) const { const AST::Path trait_path(core_name, { AST::PathNode("cmp", {}), AST::PathNode("Ord", {}) }); const AST::Path path_ordering(core_name, { AST::PathNode("cmp", {}), AST::PathNode("Ordering", {}) }); @@ -1040,10 +1034,10 @@ class Deriver_Ord: return mv$(rv); } - AST::ExprNodeP make_compare_and_ret(Span sp, const ::std::string& core_name, AST::ExprNodeP v1, AST::ExprNodeP v2) const + AST::ExprNodeP make_compare_and_ret(Span sp, const RcString& core_name, AST::ExprNodeP v1, AST::ExprNodeP v2) const { return NEWNODE(Match, - NEWNODE(CallPath, this->get_path(core_name, "cmp", "Ord", "cmp"), + NEWNODE(CallPath, get_path(core_name, "cmp", "Ord", "cmp"), // TODO: Optional Ref? ::make_vec2( NEWNODE(UniOp, AST::ExprNode_UniOp::REF, mv$(v1)), @@ -1052,7 +1046,7 @@ class Deriver_Ord: ), ::make_vec2( ::AST::ExprNode_Match_Arm( - ::make_vec1( AST::Pattern(AST::Pattern::TagValue(), sp, this->get_path(core_name, "cmp", "Ordering", "Equal")) ), + ::make_vec1( AST::Pattern(AST::Pattern::TagValue(), sp, get_path(core_name, "cmp", "Ordering", "Equal")) ), nullptr, NEWNODE(Tuple, ::std::vector()) ), @@ -1064,9 +1058,9 @@ class Deriver_Ord: ) ); } - AST::ExprNodeP make_ret_equal(const ::std::string& core_name) const + AST::ExprNodeP make_ret_equal(const RcString& core_name) const { - return NEWNODE(NamedValue, this->get_path(core_name, "cmp", "Ordering", "Equal")); + return NEWNODE(NamedValue, get_path(core_name, "cmp", "Ordering", "Equal")); } public: const char* trait_name() const override { return "Ord"; } @@ -1090,7 +1084,7 @@ public: (Tuple, for( unsigned int idx = 0; idx < e.ents.size(); idx ++ ) { - auto fld_name = FMT(idx); + auto fld_name = RcString::new_interned(FMT(idx)); nodes.push_back(this->make_compare_and_ret( sp, opts.core_name, NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), fld_name), NEWNODE(Field, NEWNODE(NamedValue, AST::Path("v" )), fld_name) @@ -1128,8 +1122,8 @@ public: for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ ) { - auto name_a = FMT("a" << idx); - auto name_b = FMT("b" << idx); + auto name_a = RcString::new_interned(FMT("a" << idx)); + auto name_b = RcString::new_interned(FMT("b" << idx)); pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) ); pats_b.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_b, ::AST::PatternBinding::Type::REF) ); @@ -1145,14 +1139,14 @@ public: code = NEWNODE(Block, mv$(nodes)); ), (Struct, - ::std::vector< ::std::pair > pats_a; - ::std::vector< ::std::pair > pats_b; + ::std::vector< ::std::pair > pats_a; + ::std::vector< ::std::pair > pats_b; ::std::vector nodes; for( const auto& fld : e.m_fields ) { - auto name_a = FMT("a" << fld.m_name); - auto name_b = FMT("b" << fld.m_name); + auto name_a = RcString::new_interned(FMT("a" << fld.m_name)); + auto name_b = RcString::new_interned(FMT("b" << fld.m_name)); pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF)) ); pats_b.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_b, ::AST::PatternBinding::Type::REF)) ); @@ -1186,10 +1180,10 @@ public: { - auto code = NEWNODE(CallPath, this->get_path(opts.core_name, "cmp", "Ord", "cmp"), + auto code = NEWNODE(CallPath, get_path(opts.core_name, "cmp", "Ord", "cmp"), ::make_vec2( - NEWNODE(UniOp, AST::ExprNode_UniOp::REF, NEWNODE(CallPath, this->get_path(opts.core_name, "intrinsics", "discriminant_value"), make_vec1( NEWNODE(NamedValue, AST::Path("self")) )) ), - NEWNODE(UniOp, AST::ExprNode_UniOp::REF, NEWNODE(CallPath, this->get_path(opts.core_name, "intrinsics", "discriminant_value"), make_vec1( NEWNODE(NamedValue, AST::Path("v")) )) ) + NEWNODE(UniOp, AST::ExprNode_UniOp::REF, NEWNODE(CallPath, get_path(opts.core_name, "intrinsics", "discriminant_value"), make_vec1( NEWNODE(NamedValue, AST::Path("self")) )) ), + NEWNODE(UniOp, AST::ExprNode_UniOp::REF, NEWNODE(CallPath, get_path(opts.core_name, "intrinsics", "discriminant_value"), make_vec1( NEWNODE(NamedValue, AST::Path("v")) )) ) ) ); ::std::vector< AST::Pattern> pats = make_vec1( AST::Pattern() ); @@ -1214,14 +1208,14 @@ public: class Deriver_Clone: public Deriver { - AST::Path get_trait_path(const ::std::string& core_name) const { + AST::Path get_trait_path(const RcString& core_name) const { return AST::Path(core_name, { AST::PathNode("clone", {}), AST::PathNode("Clone", {}) }); } - AST::Path get_method_path(const ::std::string& core_name) const { + AST::Path get_method_path(const RcString& core_name) const { return get_trait_path(core_name) + "clone"; } - AST::Impl make_ret(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector types_to_bound, AST::ExprNodeP node) const + AST::Impl make_ret(Span sp, const RcString& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector types_to_bound, AST::ExprNodeP node) const { const AST::Path trait_path = this->get_trait_path(core_name); @@ -1242,22 +1236,25 @@ class Deriver_Clone: rv.add_function(false, false, "clone", mv$(fcn)); return mv$(rv); } - AST::ExprNodeP clone_val_ref(const ::std::string& core_name, AST::ExprNodeP val) const { + AST::ExprNodeP clone_val_ref(const RcString& core_name, AST::ExprNodeP val) const { // TODO: Hack for zero-sized arrays? (Not a 1.19 feature) return NEWNODE(CallPath, this->get_method_path(core_name), vec$( NEWNODE(UniOp, AST::ExprNode_UniOp::REF, mv$(val) ) ) ); } - AST::ExprNodeP clone_val_direct(const ::std::string& core_name, AST::ExprNodeP val) const { + AST::ExprNodeP clone_val_direct(const RcString& core_name, AST::ExprNodeP val) const { return NEWNODE(CallPath, this->get_method_path(core_name), vec$( mv$(val) ) ); } - AST::ExprNodeP field(const ::std::string& name) const { + AST::ExprNodeP field(const RcString& name) const { return NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), name); } + AST::ExprNodeP field(const ::std::string& name) const { + return NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), RcString::new_interned(name)); + } public: const char* trait_name() const override { return "Clone"; } @@ -1314,7 +1311,7 @@ public: for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ ) { - auto name_a = FMT("a" << idx); + auto name_a = RcString::new_interned(FMT("a" << idx)); pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) ); nodes.push_back( this->clone_val_direct(opts.core_name, NEWNODE(NamedValue, AST::Path(name_a))) ); } @@ -1323,12 +1320,12 @@ public: code = NEWNODE(CallPath, base_path + v.m_name, mv$(nodes)); ), (Struct, - ::std::vector< ::std::pair > pats_a; + ::std::vector< ::std::pair > pats_a; ::AST::ExprNode_StructLiteral::t_values vals; for( const auto& fld : e.m_fields ) { - auto name_a = FMT("a" << fld.m_name); + auto name_a = RcString::new_interned(FMT("a" << fld.m_name)); pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF)) ); vals.push_back({ {}, fld.m_name, this->clone_val_direct(opts.core_name, NEWNODE(NamedValue, AST::Path(name_a))) }); } @@ -1383,11 +1380,11 @@ private: class Deriver_Copy: public Deriver { - AST::Path get_trait_path(const ::std::string& core_name) const { + AST::Path get_trait_path(const RcString& core_name) const { return AST::Path(core_name, { AST::PathNode("marker", {}), AST::PathNode("Copy", {}) }); } - AST::Impl make_ret(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector types_to_bound, AST::ExprNodeP node) const + AST::Impl make_ret(Span sp, const RcString& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector types_to_bound, AST::ExprNodeP node) const { const AST::Path trait_path = this->get_trait_path(core_name); @@ -1418,14 +1415,14 @@ public: class Deriver_Default: public Deriver { - AST::Path get_trait_path(const ::std::string& core_name) const { + AST::Path get_trait_path(const RcString& core_name) const { return AST::Path(core_name, { AST::PathNode("default", {}), AST::PathNode("Default", {}) }); } - AST::Path get_method_path(const ::std::string& core_name) const { + AST::Path get_method_path(const RcString& core_name) const { return AST::Path(AST::Path::TagUfcs(), ::TypeRef(Span()), get_trait_path(core_name), { AST::PathNode("default", {}) } ); } - AST::Impl make_ret(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector types_to_bound, AST::ExprNodeP node) const + AST::Impl make_ret(Span sp, const RcString& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector types_to_bound, AST::ExprNodeP node) const { const AST::Path trait_path = this->get_trait_path(core_name); @@ -1444,7 +1441,7 @@ class Deriver_Default: rv.add_function(false, false, "default", mv$(fcn)); return mv$(rv); } - AST::ExprNodeP default_call(const ::std::string& core_name) const { + AST::ExprNodeP default_call(const RcString& core_name) const { return NEWNODE(CallPath, this->get_method_path(core_name), {} @@ -1493,17 +1490,17 @@ public: class Deriver_Hash: public Deriver { - AST::Path get_trait_path(const ::std::string& core_name) const { + AST::Path get_trait_path(const RcString& core_name) const { return AST::Path(core_name, { AST::PathNode("hash", {}), AST::PathNode("Hash", {}) }); } - AST::Path get_trait_path_Hasher(const ::std::string& core_name) const { + AST::Path get_trait_path_Hasher(const RcString& core_name) const { return AST::Path(core_name, { AST::PathNode("hash", {}), AST::PathNode("Hasher", {}) }); } - AST::Path get_method_path(const ::std::string& core_name) const { + AST::Path get_method_path(const RcString& core_name) const { return get_trait_path(core_name) + "hash"; } - AST::Impl make_ret(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector types_to_bound, AST::ExprNodeP node) const + AST::Impl make_ret(Span sp, const RcString& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector types_to_bound, AST::ExprNodeP node) const { const AST::Path trait_path = this->get_trait_path(core_name); @@ -1530,18 +1527,21 @@ class Deriver_Hash: rv.add_function(false, false, "hash", mv$(fcn)); return mv$(rv); } - AST::ExprNodeP hash_val_ref(const ::std::string& core_name, AST::ExprNodeP val) const { + AST::ExprNodeP hash_val_ref(const RcString& core_name, AST::ExprNodeP val) const { return this->hash_val_direct(core_name, NEWNODE(UniOp, AST::ExprNode_UniOp::REF, mv$(val)) ); } - AST::ExprNodeP hash_val_direct(const ::std::string& core_name, AST::ExprNodeP val) const { + AST::ExprNodeP hash_val_direct(const RcString& core_name, AST::ExprNodeP val) const { return NEWNODE(CallPath, this->get_method_path(core_name), vec$( mv$(val), NEWNODE(NamedValue, AST::Path("state")) ) ); } - AST::ExprNodeP field(const ::std::string& name) const { + AST::ExprNodeP field(const RcString& name) const { return NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), name); } + AST::ExprNodeP field(const std::string& name) const { + return NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), RcString::new_interned(name)); + } public: const char* trait_name() const override { return "Hash"; } @@ -1596,7 +1596,7 @@ public: for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ ) { - auto name_a = FMT("a" << idx); + auto name_a = RcString::new_interned(FMT("a" << idx)); pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) ); nodes.push_back( this->hash_val_direct(opts.core_name, NEWNODE(NamedValue, AST::Path(name_a))) ); } @@ -1605,13 +1605,13 @@ public: code = NEWNODE(Block, mv$(nodes)); ), (Struct, - ::std::vector< ::std::pair > pats_a; + ::std::vector< ::std::pair > pats_a; ::std::vector< AST::ExprNodeP > nodes; nodes.push_back( mv$(var_idx_hash) ); for( const auto& fld : e.m_fields ) { - auto name_a = FMT("a" << fld.m_name); + auto name_a = RcString::new_interned(FMT("a" << fld.m_name)); pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF)) ); nodes.push_back( this->hash_val_direct(opts.core_name, NEWNODE(NamedValue, AST::Path(name_a))) ); } @@ -1652,7 +1652,7 @@ class Deriver_RustcEncodable: return get_trait_path() + "encode"; } - AST::Impl make_ret(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector types_to_bound, AST::ExprNodeP node) const + AST::Impl make_ret(Span sp, const RcString& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector types_to_bound, AST::ExprNodeP node) const { const AST::Path trait_path = this->get_trait_path(); @@ -1689,9 +1689,12 @@ class Deriver_RustcEncodable: AST::ExprNodeP enc_val_ref(AST::ExprNodeP val) const { return this->enc_val_direct(NEWNODE(UniOp, AST::ExprNode_UniOp::REF, mv$(val)) ); } - AST::ExprNodeP field(const ::std::string& name) const { + AST::ExprNodeP field(const RcString& name) const { return NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), name); } + AST::ExprNodeP field(::std::string name) const { + return NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), RcString::new_interned(name)); + } AST::ExprNodeP enc_closure(Span sp, AST::ExprNodeP code) const { return NEWNODE(Closure, @@ -1699,7 +1702,7 @@ class Deriver_RustcEncodable: mv$(code), false ); } - AST::ExprNodeP get_val_ok(const ::std::string& core_name) const { + AST::ExprNodeP get_val_ok(const RcString& core_name) const { return NEWNODE(CallPath, AST::Path(core_name, {AST::PathNode("result",{}), AST::PathNode("Result",{}), AST::PathNode("Ok",{})}), vec$( NEWNODE(Tuple, {})) ); } @@ -1708,7 +1711,7 @@ public: AST::Impl handle_item(Span sp, const DeriveOpts& opts, const AST::GenericParams& p, const TypeRef& type, const AST::Struct& str) const override { - const ::std::string& struct_name = type.m_data.as_Path().path.nodes().back().name(); + ::std::string struct_name = type.m_data.as_Path().path.nodes().back().name().c_str(); ::std::vector nodes; TU_MATCH(AST::StructData, (str.m_data), (e), @@ -1720,7 +1723,12 @@ public: { nodes.push_back( NEWNODE(CallPath, this->get_trait_path_Encoder() + "emit_struct_field", - vec$( NEWNODE(NamedValue, AST::Path("s")), NEWNODE(String, fld.m_name), NEWNODE(Integer, idx, CORETYPE_UINT), this->enc_closure( sp, this->enc_val_ref(this->field(fld.m_name)) ) ) + vec$( + NEWNODE(NamedValue, AST::Path("s")), + NEWNODE(String, fld.m_name.c_str()), + NEWNODE(Integer, idx, CORETYPE_UINT), + this->enc_closure( sp, this->enc_val_ref(this->field(fld.m_name)) ) + ) ) ); idx ++; } @@ -1778,7 +1786,7 @@ public: code = NEWNODE(CallPath, this->get_trait_path_Encoder() + "emit_enum_variant", vec$( NEWNODE(NamedValue, AST::Path("s")), - NEWNODE(String, v.m_name), + NEWNODE(String, v.m_name.c_str()), NEWNODE(Integer, var_idx, CORETYPE_UINT), NEWNODE(Integer, 0, CORETYPE_UINT), this->enc_closure(sp, this->get_val_ok(opts.core_name)) @@ -1792,7 +1800,7 @@ public: for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ ) { - auto name_a = FMT("a" << idx); + auto name_a = RcString::new_interned(FMT("a" << idx)); pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) ); nodes.push_back( NEWNODE(CallPath, this->get_trait_path_Encoder() + "emit_enum_variant_arg", vec$( @@ -1807,7 +1815,7 @@ public: code = NEWNODE(CallPath, this->get_trait_path_Encoder() + "emit_enum_variant", vec$( NEWNODE(NamedValue, AST::Path("s")), - NEWNODE(String, v.m_name), + NEWNODE(String, v.m_name.c_str()), NEWNODE(Integer, var_idx, CORETYPE_UINT), NEWNODE(Integer, e.m_sub_types.size(), CORETYPE_UINT), this->enc_closure(sp, NEWNODE(Block, mv$(nodes))) @@ -1816,19 +1824,19 @@ public: pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_a)); ), (Struct, - ::std::vector< ::std::pair > pats_a; + ::std::vector< ::std::pair > pats_a; ::std::vector< AST::ExprNodeP > nodes; unsigned int idx = 0; for( const auto& fld : e.m_fields ) { - auto name_a = Ident( FMT("a" << fld.m_name) ); + auto name_a = Ident( RcString::new_interned(FMT("a" << fld.m_name)) ); pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, Ident(name_a), ::AST::PatternBinding::Type::REF)) ); nodes.push_back( NEWNODE(CallPath, this->get_trait_path_Encoder() + "emit_enum_struct_variant_field", vec$( NEWNODE(NamedValue, AST::Path("s")), - NEWNODE(String, fld.m_name), + NEWNODE(String, fld.m_name.c_str()), NEWNODE(Integer, idx, CORETYPE_UINT), this->enc_closure(sp, this->enc_val_direct(NEWNODE(NamedValue, AST::Path(name_a.name)))) ) @@ -1841,7 +1849,7 @@ public: code = NEWNODE(CallPath, this->get_trait_path_Encoder() + "emit_enum_struct_variant", vec$( NEWNODE(NamedValue, AST::Path("s")), - NEWNODE(String, v.m_name), + NEWNODE(String, v.m_name.c_str()), NEWNODE(Integer, var_idx, CORETYPE_UINT), NEWNODE(Integer, e.m_fields.size(), CORETYPE_UINT), this->enc_closure(sp, NEWNODE(Block, mv$(nodes))) @@ -1862,7 +1870,7 @@ public: auto node_match = NEWNODE(Match, NEWNODE(NamedValue, AST::Path("self")), mv$(arms)); - const ::std::string& enum_name = type.m_data.as_Path().path.nodes().back().name(); + ::std::string enum_name = type.m_data.as_Path().path.nodes().back().name().c_str(); auto node = NEWNODE(CallPath, this->get_trait_path_Encoder() + "emit_enum", vec$( NEWNODE(NamedValue, AST::Path("s")), NEWNODE(String, enum_name), this->enc_closure(sp, mv$(node_match)) ) ); @@ -1885,11 +1893,11 @@ class Deriver_RustcDecodable: return get_trait_path() + "decode"; } - AST::Impl make_ret(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector types_to_bound, AST::ExprNodeP node) const + AST::Impl make_ret(Span sp, const RcString& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector types_to_bound, AST::ExprNodeP node) const { const AST::Path trait_path = this->get_trait_path(); - AST::Path result_path = AST::Path(core_name, { AST::PathNode("result", {}), AST::PathNode("Result", {}) }); + AST::Path result_path = AST::Path(core_name, { AST::PathNode(RcString::new_interned("result"), {}), AST::PathNode(RcString::new_interned("Result"), {}) }); result_path.nodes()[1].args().m_types.push_back( TypeRef(sp, "Self", 0xFFFF) ); result_path.nodes()[1].args().m_types.push_back( TypeRef(sp, AST::Path(AST::Path::TagUfcs(), TypeRef(sp, "D", 0x100|0), this->get_trait_path_Decoder(), { AST::PathNode("Error",{}) })) ); @@ -1920,7 +1928,7 @@ class Deriver_RustcDecodable: return NEWNODE(CallPath, this->get_method_path(), vec$( NEWNODE(NamedValue, AST::Path("d")) )); } AST::ExprNodeP field(const ::std::string& name) const { - return NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), name); + return NEWNODE(Field, NEWNODE(NamedValue, AST::Path(RcString::new_interned("self"))), RcString::new_interned(name)); } AST::ExprNodeP dec_closure(Span sp, AST::ExprNodeP code) const { @@ -1929,8 +1937,8 @@ class Deriver_RustcDecodable: mv$(code), false ); } - AST::ExprNodeP get_val_err_str(const ::std::string& core_name, ::std::string err_str) const { - return NEWNODE(CallPath, AST::Path(core_name, {AST::PathNode("result",{}), AST::PathNode("Result",{}), AST::PathNode("Err",{})}), vec$( + AST::ExprNodeP get_val_err_str(const RcString& core_name, ::std::string err_str) const { + return NEWNODE(CallPath, get_path(core_name, "result", "Result", "Err"), vec$( NEWNODE(CallMethod, NEWNODE(NamedValue, AST::Path("d")), AST::PathNode("error"), @@ -1938,10 +1946,10 @@ class Deriver_RustcDecodable: ) ) ); } - AST::ExprNodeP get_val_ok(const ::std::string& core_name, AST::ExprNodeP inner) const { - return NEWNODE(CallPath, AST::Path(core_name, {AST::PathNode("result",{}), AST::PathNode("Result",{}), AST::PathNode("Ok",{})}), vec$( mv$(inner) ) ); + AST::ExprNodeP get_val_ok(const RcString& core_name, AST::ExprNodeP inner) const { + return NEWNODE(CallPath, get_path(core_name, "result", "Result", "Ok"), vec$( mv$(inner) ) ); } - AST::ExprNodeP get_val_ok_unit(const ::std::string& core_name) const { + AST::ExprNodeP get_val_ok_unit(const RcString& core_name) const { return get_val_ok(core_name, NEWNODE(Tuple, {})); } @@ -1951,7 +1959,7 @@ public: AST::Impl handle_item(Span sp, const DeriveOpts& opts, const AST::GenericParams& p, const TypeRef& type, const AST::Struct& str) const override { AST::Path base_path = type.m_data.as_Path().path; - const ::std::string& struct_name = type.m_data.as_Path().path.nodes().back().name(); + ::std::string struct_name = type.m_data.as_Path().path.nodes().back().name().c_str(); AST::ExprNodeP node_v; TU_MATCH(AST::StructData, (str.m_data), (e), @@ -1964,7 +1972,7 @@ public: { vals.push_back({ {}, fld.m_name, NEWNODE(UniOp, ::AST::ExprNode_UniOp::QMARK, NEWNODE(CallPath, this->get_trait_path_Decoder() + "read_struct_field", - vec$( NEWNODE(NamedValue, AST::Path("d")), NEWNODE(String, fld.m_name), NEWNODE(Integer, idx, CORETYPE_UINT), this->dec_closure( sp, this->dec_val() ) ) + vec$( NEWNODE(NamedValue, AST::Path("d")), NEWNODE(String, fld.m_name.c_str()), NEWNODE(Integer, idx, CORETYPE_UINT), this->dec_closure( sp, this->dec_val() ) ) )) }); idx ++; } @@ -2053,7 +2061,7 @@ public: vals.push_back({ {}, fld.m_name, NEWNODE(UniOp, ::AST::ExprNode_UniOp::QMARK, NEWNODE(CallPath, this->get_trait_path_Decoder() + "read_enum_struct_variant_field", vec$( NEWNODE(NamedValue, AST::Path("d")), - NEWNODE(String, fld.m_name), + NEWNODE(String, fld.m_name.c_str()), NEWNODE(Integer, idx, CORETYPE_UINT), this->dec_closure(sp, this->dec_val()) ) @@ -2073,7 +2081,7 @@ public: nullptr, this->get_val_ok(opts.core_name, mv$(code)) )); - var_name_strs.push_back( NEWNODE(String, v.m_name) ); + var_name_strs.push_back( NEWNODE(String, v.m_name.c_str()) ); } // Default arm @@ -2095,7 +2103,7 @@ public: mv$(node_match), false ); - const ::std::string& enum_name = type.m_data.as_Path().path.nodes().back().name(); + ::std::string enum_name = type.m_data.as_Path().path.nodes().back().name().c_str(); auto node_rev = NEWNODE(CallPath, this->get_trait_path_Decoder() + "read_enum_variant", vec$( @@ -2117,7 +2125,7 @@ public: // -------------------------------------------------------------------- // Select and dispatch the correct derive() handler // -------------------------------------------------------------------- -static const Deriver* find_impl(const ::std::string& trait_name) +static const Deriver* find_impl(const RcString& trait_name) { #define _(obj) if(trait_name == obj.trait_name()) return &obj; _(g_derive_debug) @@ -2158,7 +2166,7 @@ static void derive_item(const Span& sp, const AST::Crate& crate, AST::Module& mo attr.items() }; - ::std::vector< ::std::string> missing_handlers; + ::std::vector< RcString> missing_handlers; for( const auto& trait : attr.items() ) { DEBUG("- " << trait.name()); @@ -2182,7 +2190,7 @@ static void derive_item(const Span& sp, const AST::Crate& crate, AST::Module& mo } else { // proc_macro - Invoke the handler. - auto lex = ProcMacro_Invoke(sp, crate, mac_path.path, path.nodes().back().name(), item); + auto lex = ProcMacro_Invoke(sp, crate, mac_path.path, path.nodes().back().name().c_str(), item); if( lex ) { Parse_ModRoot_Items(*lex, mod); diff --git a/src/expand/env.cpp b/src/expand/env.cpp index f4577ef1..825c895a 100644 --- a/src/expand/env.cpp +++ b/src/expand/env.cpp @@ -34,48 +34,44 @@ namespace { class CExpanderEnv: public ExpandProcMacro { - ::std::unique_ptr expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override + ::std::unique_ptr expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override { - if( ident != "" ) - ERROR(sp, E0000, "env! doesn't take an ident"); ::std::string varname = get_string(sp, crate, mod, tt); const char* var_val_cstr = getenv(varname.c_str()); if( !var_val_cstr ) { ERROR(sp, E0000, "Environment variable '" << varname << "' not defined"); } - return box$( TTStreamO(sp, TokenTree(Token(TOK_STRING, var_val_cstr))) ); + return box$( TTStreamO(sp, TokenTree(Token(TOK_STRING, ::std::string(var_val_cstr)))) ); } }; class CExpanderOptionEnv: public ExpandProcMacro { - ::std::unique_ptr expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override + ::std::unique_ptr expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override { - if( ident != "" ) - ERROR(sp, E0000, "option_env! doesn't take an ident"); ::std::string varname = get_string(sp, crate, mod, tt); const char* var_val_cstr = getenv(varname.c_str()); if( !var_val_cstr ) { ::std::vector< TokenTree> rv; rv.reserve(7); - rv.push_back( Token(TOK_IDENT, "None") ); + rv.push_back( Token(TOK_IDENT, RcString::new_interned("None")) ); rv.push_back( Token(TOK_DOUBLE_COLON) ); rv.push_back( Token(TOK_LT) ); rv.push_back( Token(TOK_AMP) ); - rv.push_back( Token(TOK_LIFETIME, "static") ); - rv.push_back( Token(TOK_IDENT, "str") ); + rv.push_back( Token(TOK_LIFETIME, RcString::new_interned("static")) ); + rv.push_back( Token(TOK_IDENT, RcString::new_interned("str")) ); rv.push_back( Token(TOK_GT) ); return box$( TTStreamO(sp, TokenTree( {}, mv$(rv) )) ); } else { ::std::vector< TokenTree> rv; rv.reserve(4); - rv.push_back( Token(TOK_IDENT, "Some") ); + rv.push_back( Token(TOK_IDENT, RcString::new_interned("Some")) ); rv.push_back( Token(TOK_PAREN_OPEN) ); - rv.push_back( Token(TOK_STRING, var_val_cstr) ); + rv.push_back( Token(TOK_STRING, ::std::string(var_val_cstr)) ); rv.push_back( Token(TOK_PAREN_CLOSE) ); return box$( TTStreamO(sp, TokenTree( {}, mv$(rv) )) ); } diff --git a/src/expand/file_line.cpp b/src/expand/file_line.cpp index 2bf85ffd..09d3e6b2 100644 --- a/src/expand/file_line.cpp +++ b/src/expand/file_line.cpp @@ -23,16 +23,16 @@ namespace { class CExpanderFile: public ExpandProcMacro { - ::std::unique_ptr expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override + ::std::unique_ptr expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override { - return box$( TTStreamO(sp, TokenTree(Token(TOK_STRING, get_top_span(sp).filename.c_str()))) ); + return box$( TTStreamO(sp, TokenTree(Token(TOK_STRING, ::std::string(get_top_span(sp).filename.c_str())))) ); } }; class CExpanderLine: public ExpandProcMacro { - ::std::unique_ptr expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override + ::std::unique_ptr expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override { return box$( TTStreamO(sp, TokenTree(Token((uint64_t)get_top_span(sp).start_line, CORETYPE_U32))) ); } @@ -41,7 +41,7 @@ class CExpanderLine: class CExpanderColumn: public ExpandProcMacro { - ::std::unique_ptr expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override + ::std::unique_ptr expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override { return box$( TTStreamO(sp, TokenTree(Token((uint64_t)get_top_span(sp).start_ofs, CORETYPE_U32))) ); } @@ -49,7 +49,7 @@ class CExpanderColumn: class CExpanderUnstableColumn: public ExpandProcMacro { - ::std::unique_ptr expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override + ::std::unique_ptr expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override { return box$( TTStreamO(sp, TokenTree(Token((uint64_t)get_top_span(sp).start_ofs, CORETYPE_U32))) ); } @@ -58,13 +58,13 @@ class CExpanderUnstableColumn: class CExpanderModulePath: public ExpandProcMacro { - ::std::unique_ptr expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override + ::std::unique_ptr expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override { ::std::string path_str; for(const auto& comp : mod.path().nodes()) { if( &comp != &mod.path().nodes().front() ) path_str += "::"; - path_str += comp.name(); + path_str += comp.name().c_str(); } return box$( TTStreamO(sp, TokenTree( Token(TOK_STRING, mv$(path_str)) )) ); } diff --git a/src/expand/format_args.cpp b/src/expand/format_args.cpp index d79fd9d5..7f33eb6d 100644 --- a/src/expand/format_args.cpp +++ b/src/expand/format_args.cpp @@ -189,11 +189,11 @@ namespace { ::std::tuple< ::std::vector, ::std::string> parse_format_string( const Span& sp, const ::std::string& format_string, - const ::std::map< ::std::string,unsigned int>& named, + const ::std::map& named, unsigned int n_free ) { - unsigned int n_named = named.size(); + //unsigned int n_named = named.size(); unsigned int next_free = 0; ::std::vector frags; @@ -256,7 +256,7 @@ namespace { while( isalnum(*s) || *s == '_' || (*s < 0 || *s > 127) ) { s ++; } - ::std::string ident { start, s }; + auto ident = RcString(start, s - start); auto it = named.find(ident); if( it == named.end() ) ERROR(sp, E0000, "Named argument '"<& toks, const AST::Crate& crate, ::std::initializer_list il) { switch(crate.m_load_std) @@ -472,17 +475,17 @@ namespace { break; case ::AST::Crate::LOAD_CORE: toks.push_back( TokenTree(TOK_DOUBLE_COLON) ); - toks.push_back( Token(TOK_IDENT, "core") ); + toks.push_back( ident("core") ); break; case ::AST::Crate::LOAD_STD: toks.push_back( TokenTree(TOK_DOUBLE_COLON) ); - toks.push_back( Token(TOK_IDENT, "std") ); + toks.push_back( ident("std") ); break; } for(auto ent : il) { toks.push_back( TokenTree(TOK_DOUBLE_COLON) ); - toks.push_back( Token(TOK_IDENT, ent) ); + toks.push_back( ident(ent) ); } } void push_toks(::std::vector& toks, Token t1) { @@ -519,7 +522,7 @@ namespace { const auto& format_string_sp = format_string_np->span(); const auto& format_string = format_string_np->m_value; - ::std::map< ::std::string, unsigned int> named_args_index; + ::std::map named_args_index; ::std::vector named_args; ::std::vector free_args; @@ -535,7 +538,7 @@ namespace { if( lex.lookahead(0) == TOK_IDENT && lex.lookahead(1) == TOK_EQUAL ) { GET_CHECK_TOK(tok, lex, TOK_IDENT); - auto name = mv$(tok.str()); + auto name = tok.istr(); GET_CHECK_TOK(tok, lex, TOK_EQUAL); @@ -600,7 +603,7 @@ namespace { toks.push_back( TokenTree(TOK_PAREN_OPEN) ); for(unsigned int i = 0; i < free_args.size() + named_args.size(); i ++ ) { - toks.push_back( Token(TOK_IDENT, FMT("a" << i)) ); + toks.push_back( ident(FMT("a" << i).c_str()) ); toks.push_back( TokenTree(TOK_COMMA) ); } toks.push_back( TokenTree(TOK_PAREN_CLOSE) ); @@ -612,13 +615,13 @@ namespace { // - Contains N+1 entries, where N is the number of fragments { toks.push_back( TokenTree(TOK_RWORD_STATIC) ); - toks.push_back( Token(TOK_IDENT, "FRAGMENTS") ); + toks.push_back( ident("FRAGMENTS") ); toks.push_back( TokenTree(TOK_COLON) ); toks.push_back( TokenTree(TOK_SQUARE_OPEN) ); toks.push_back( Token(TOK_AMP) ); - toks.push_back( Token(TOK_LIFETIME, "static") ); - toks.push_back( Token(TOK_IDENT, "str") ); + toks.push_back( Token(TOK_LIFETIME, RcString::new_interned("static")) ); + toks.push_back( ident("str") ); toks.push_back( Token(TOK_SEMICOLON) ); toks.push_back( Token(static_cast(fragments.size() + 1), CORETYPE_UINT) ); toks.push_back( TokenTree(TOK_SQUARE_CLOSE) ); @@ -644,7 +647,7 @@ namespace { toks.push_back( TokenTree(TOK_PAREN_OPEN) ); { toks.push_back( TokenTree(TOK_AMP) ); - toks.push_back( Token(TOK_IDENT, "FRAGMENTS") ); + toks.push_back( ident("FRAGMENTS") ); toks.push_back( TokenTree(TOK_COMMA) ); toks.push_back( TokenTree(TOK_AMP) ); @@ -653,7 +656,7 @@ namespace { { push_path(toks, crate, {"fmt", "ArgumentV1", "new"}); toks.push_back( Token(TOK_PAREN_OPEN) ); - toks.push_back( Token(TOK_IDENT, FMT("a" << frag.arg_index)) ); + toks.push_back( ident( FMT("a" << frag.arg_index).c_str() ) ); toks.push_back( TokenTree(TOK_COMMA) ); @@ -678,7 +681,7 @@ namespace { toks.push_back( TokenTree(TOK_PAREN_OPEN) ); { toks.push_back( TokenTree(TOK_AMP) ); - toks.push_back( Token(TOK_IDENT, "FRAGMENTS") ); + toks.push_back( ident("FRAGMENTS") ); toks.push_back( TokenTree(TOK_COMMA) ); // TODO: Fragments to format @@ -689,7 +692,7 @@ namespace { { push_path(toks, crate, {"fmt", "ArgumentV1", "new"}); toks.push_back( Token(TOK_PAREN_OPEN) ); - toks.push_back( Token(TOK_IDENT, FMT("a" << frag.arg_index)) ); + toks.push_back( ident(FMT("a" << frag.arg_index).c_str()) ); toks.push_back( TokenTree(TOK_COMMA) ); @@ -707,17 +710,17 @@ namespace { push_path(toks, crate, {"fmt", "rt", "v1", "Argument"}); toks.push_back( TokenTree(TOK_BRACE_OPEN) ); - push_toks(toks, Token(TOK_IDENT, "position"), TOK_COLON ); + push_toks(toks, ident("position"), TOK_COLON ); push_path(toks, crate, {"fmt", "rt", "v1", "Position", "Next"}); push_toks(toks, TOK_COMMA); - push_toks(toks, Token(TOK_IDENT, "format"), TOK_COLON ); + push_toks(toks, ident("format"), TOK_COLON ); push_path(toks, crate, {"fmt", "rt", "v1", "FormatSpec"}); toks.push_back( TokenTree(TOK_BRACE_OPEN) ); { - push_toks(toks, Token(TOK_IDENT, "fill"), TOK_COLON, Token(uint64_t(frag.args.align_char), CORETYPE_CHAR), TOK_COMMA ); + push_toks(toks, ident("fill"), TOK_COLON, Token(uint64_t(frag.args.align_char), CORETYPE_CHAR), TOK_COMMA ); - push_toks(toks, Token(TOK_IDENT, "align"), TOK_COLON); + push_toks(toks, ident("align"), TOK_COLON); const char* align_var_name = nullptr; switch( frag.args.align ) { @@ -729,19 +732,19 @@ namespace { push_path(toks, crate, {"fmt", "rt", "v1", "Alignment", align_var_name}); push_toks(toks, TOK_COMMA); - push_toks(toks, Token(TOK_IDENT, "flags"), TOK_COLON); + push_toks(toks, ident("flags"), TOK_COLON); uint64_t flags = 0; if(frag.args.alternate) flags |= 1 << 2; push_toks(toks, Token(uint64_t(flags), CORETYPE_U32)); push_toks(toks, TOK_COMMA); - push_toks(toks, Token(TOK_IDENT, "precision"), TOK_COLON ); + push_toks(toks, ident("precision"), TOK_COLON ); if( frag.args.prec_is_arg || frag.args.prec != 0 ) { push_path(toks, crate, {"fmt", "rt", "v1", "Count", "Is"}); push_toks(toks, TOK_PAREN_OPEN); if( frag.args.prec_is_arg ) { - push_toks(toks, TOK_STAR, Token(TOK_IDENT, FMT("a" << frag.args.prec)) ); + push_toks(toks, TOK_STAR, ident(FMT("a" << frag.args.prec).c_str()) ); } else { push_toks(toks, Token(uint64_t(frag.args.prec), CORETYPE_UINT) ); @@ -753,12 +756,12 @@ namespace { } toks.push_back( TokenTree(TOK_COMMA) ); - push_toks(toks, Token(TOK_IDENT, "width"), TOK_COLON ); + push_toks(toks, ident("width"), TOK_COLON ); if( frag.args.width_is_arg || frag.args.width != 0 ) { push_path(toks, crate, {"fmt", "rt", "v1", "Count", "Is"}); push_toks(toks, TOK_PAREN_OPEN); if( frag.args.width_is_arg ) { - push_toks(toks, TOK_STAR, Token(TOK_IDENT, FMT("a" << frag.args.width)) ); + push_toks(toks, TOK_STAR, ident(FMT("a" << frag.args.width).c_str()) ); } else { push_toks(toks, Token(uint64_t(frag.args.width), CORETYPE_UINT) ); @@ -791,14 +794,12 @@ namespace { class CFormatArgsExpander: public ExpandProcMacro { - ::std::unique_ptr expand(const Span& sp, const ::AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override + ::std::unique_ptr expand(const Span& sp, const ::AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override { Token tok; auto lex = TTStream(sp, tt); lex.parse_state().module = &mod; - if( ident != "" ) - ERROR(sp, E0000, "format_args! doesn't take an ident"); return expand_format_args(sp, crate, lex, /*add_newline=*/false); } @@ -807,14 +808,12 @@ class CFormatArgsExpander: class CFormatArgsNlExpander: public ExpandProcMacro { - ::std::unique_ptr expand(const Span& sp, const ::AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override + ::std::unique_ptr expand(const Span& sp, const ::AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override { Token tok; auto lex = TTStream(sp, tt); lex.parse_state().module = &mod; - if( ident != "" ) - ERROR(sp, E0000, "format_args_nl! doesn't take an ident"); return expand_format_args(sp, crate, lex, /*add_newline=*/true); } diff --git a/src/expand/include.cpp b/src/expand/include.cpp index 8078d5d0..14a7bc7b 100644 --- a/src/expand/include.cpp +++ b/src/expand/include.cpp @@ -64,11 +64,8 @@ namespace { class CIncludeExpander: public ExpandProcMacro { - ::std::unique_ptr expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override + ::std::unique_ptr expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override { - if( ident != "" ) - ERROR(sp, E0000, "include! doesn't take an ident"); - Token tok; auto lex = TTStream(sp, tt); @@ -91,11 +88,8 @@ class CIncludeExpander: class CIncludeBytesExpander: public ExpandProcMacro { - ::std::unique_ptr expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override + ::std::unique_ptr expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override { - if( ident != "" ) - ERROR(sp, E0000, "include_bytes! doesn't take an ident"); - Token tok; auto lex = TTStream(sp, tt); @@ -121,11 +115,8 @@ class CIncludeBytesExpander: class CIncludeStrExpander: public ExpandProcMacro { - ::std::unique_ptr expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override + ::std::unique_ptr expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override { - if( ident != "" ) - ERROR(sp, E0000, "include_str! doesn't take an ident"); - Token tok; auto lex = TTStream(sp, tt); diff --git a/src/expand/macro_rules.cpp b/src/expand/macro_rules.cpp index 3bacfcf7..88b7fc88 100644 --- a/src/expand/macro_rules.cpp +++ b/src/expand/macro_rules.cpp @@ -21,11 +21,12 @@ class CMacroRulesExpander: public ExpandProcMacro { - ::std::unique_ptr expand(const Span& sp, const ::AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override + ::std::unique_ptr expand(const Span& sp, const ::AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override + { + ERROR(sp, E0000, "macro_rules! requires an identifier" ); + } + ::std::unique_ptr expand_ident(const Span& sp, const ::AST::Crate& crate, const RcString& ident, const TokenTree& tt, AST::Module& mod) override { - if( ident == "" ) - ERROR(sp, E0000, "macro_rules! requires an identifier" ); - DEBUG("Parsing macro_rules! " << ident); TTStream lex(sp, tt); auto mac = Parse_MacroRules(lex); @@ -48,7 +49,7 @@ class CMacroUseHandler: // Just ignore ) else TU_IFLET( ::AST::Item, i, Crate, ec_name, - const auto& ec = crate.m_extern_crates.at(ec_name.name); + const auto& ec = crate.m_extern_crates.at(ec_name.name.c_str()); if( mi.has_sub_items() ) { TODO(sp, "Named import from extern crate"); @@ -61,7 +62,7 @@ class CMacroUseHandler: }); for(const auto& p : ec.m_hir->m_proc_macros) { - mod.m_macro_imports.push_back({ false, p.path.m_components.back(), p.path.m_components, nullptr }); + mod.m_macro_imports.push_back(AST::Module::MacroImport{ false, p.path.m_components.back(), p.path.m_components, nullptr }); mod.m_macro_imports.back().path.insert( mod.m_macro_imports.back().path.begin(), p.path.m_crate_name ); } } @@ -153,7 +154,7 @@ class CMacroReexportHandler: } const auto& crate_name = i.as_Crate().name; - auto& ext_crate = *crate.m_extern_crates.at(crate_name).m_hir; + auto& ext_crate = *crate.m_extern_crates.at(crate_name.c_str()).m_hir; if( mi.has_sub_items() ) { diff --git a/src/expand/mod.cpp b/src/expand/mod.cpp index bc51e1ff..e3cef375 100644 --- a/src/expand/mod.cpp +++ b/src/expand/mod.cpp @@ -56,7 +56,7 @@ void ExpandDecorator::unexpected(const Span& sp, const AST::Attribute& mi, const void Expand_Attr(const Span& sp, const ::AST::Attribute& a, AttrStage stage, ::std::function f) { for( auto& d : g_decorators ) { - if( d.first == a.name() ) { + if( a.name() == d.first ) { DEBUG("#[" << d.first << "] " << (int)d.second->stage() << "-" << (int)stage); if( d.second->stage() == stage ) { f(sp, *d.second, a); @@ -94,7 +94,7 @@ void Expand_Attrs(::AST::AttributeList& attrs, AttrStage stage, ::AST::Crate& c ::std::unique_ptr Expand_Macro_Inner( const ::AST::Crate& crate, LList modstack, ::AST::Module& mod, - Span mi_span, const ::std::string& name, const ::std::string& input_ident, TokenTree& input_tt + Span mi_span, const RcString& name, const RcString& input_ident, TokenTree& input_tt ) { if( name == "" ) { @@ -105,7 +105,10 @@ void Expand_Attrs(::AST::AttributeList& attrs, AttrStage stage, ::AST::Crate& c { if( name == m.first ) { - auto e = m.second->expand(mi_span, crate, input_ident, input_tt, mod); + auto e = input_ident == "" + ? m.second->expand(mi_span, crate, input_tt, mod) + : m.second->expand_ident(mi_span, crate, input_ident, input_tt, mod) + ; return e; } } @@ -152,7 +155,7 @@ void Expand_Attrs(::AST::AttributeList& attrs, AttrStage stage, ::AST::Crate& c } ::std::unique_ptr Expand_Macro( const ::AST::Crate& crate, LList modstack, ::AST::Module& mod, - Span mi_span, const ::std::string& name, const ::std::string& input_ident, TokenTree& input_tt + Span mi_span, const RcString& name, const RcString& input_ident, TokenTree& input_tt ) { auto rv = Expand_Macro_Inner(crate, modstack, mod, mi_span, name, input_ident, input_tt); @@ -348,7 +351,7 @@ struct CExpandExpr: ::std::unique_ptr<::AST::ExprNode> replacement; // Stack of `try { ... }` blocks (the string is the loop label for the desugaring) - ::std::vector< ::std::string> m_try_stack; + ::std::vector m_try_stack; unsigned m_try_index = 0; AST::ExprNode_Block* current_block = nullptr; @@ -559,7 +562,7 @@ struct CExpandExpr: // } // ``` // NOTE: MIR lowering and HIR typecheck need to know to skip these (OR resolve should handle naming all loop blocks) - m_try_stack.push_back(FMT("#try" << m_try_index++)); + m_try_stack.push_back(RcString::new_interned(FMT("#try" << m_try_index++))); this->visit_nodelete(node, node.m_inner); auto loop_name = mv$(m_try_stack.back()); m_try_stack.pop_back(); @@ -858,7 +861,7 @@ struct CExpandExpr: nullptr, ::AST::ExprNodeP(new ::AST::ExprNode_Flow( (m_try_stack.empty() ? ::AST::ExprNode_Flow::RETURN : ::AST::ExprNode_Flow::BREAK), // NOTE: uses `break 'tryblock` instead of return if in a try block. - (m_try_stack.empty() ? "" : m_try_stack.back()), + (m_try_stack.empty() ? RcString("") : m_try_stack.back()), ::AST::ExprNodeP(new ::AST::ExprNode_CallPath( ::AST::Path(path_Try_from_error), ::make_vec1( @@ -1415,7 +1418,7 @@ void Expand(::AST::Crate& crate) for( auto& a : crate.m_attrs.m_items ) { for( auto& d : g_decorators ) { - if( d.first == a.name() && d.second->stage() == AttrStage::Pre ) { + if( a.name() == d.first && d.second->stage() == AttrStage::Pre ) { //d.second->handle(a, crate, ::AST::Path(), crate.m_root_module, crate.m_root_module); } } diff --git a/src/expand/proc_macro.cpp b/src/expand/proc_macro.cpp index f0f28f5a..24cd41d9 100644 --- a/src/expand/proc_macro.cpp +++ b/src/expand/proc_macro.cpp @@ -49,13 +49,13 @@ public: { if( attr.items()[i].name() == "attributes") { for(const auto& si : attr.items()[i].items()) { - attributes.push_back( si.name() ); + attributes.push_back( si.name().c_str() ); } } } // TODO: Store attributes for later use. - crate.m_proc_macros.push_back(AST::ProcMacroDef { FMT("derive#" << trait_name), path, mv$(attributes) }); + crate.m_proc_macros.push_back(AST::ProcMacroDef { RcString::new_interned(FMT("derive#" << trait_name)), path, mv$(attributes) }); } }; @@ -100,7 +100,7 @@ void Expand_ProcMacro(::AST::Crate& crate) { ::AST::ExprNode_StructLiteral::t_values desc_vals; // `name: "foo",` - desc_vals.push_back({ {}, "name", NEWNODE(_String, desc.name) }); + desc_vals.push_back({ {}, "name", NEWNODE(_String, desc.name.c_str()) }); // `handler`: ::foo desc_vals.push_back({ {}, "handler", NEWNODE(_NamedValue, AST::Path(desc.path)) }); @@ -211,7 +211,7 @@ public: void send_float(eCoreType ct, double v); //void send_fragment(); - bool attr_is_used(const ::std::string& n) const { + bool attr_is_used(const RcString& n) const { return ::std::find(m_proc_macro_desc.attributes.begin(), m_proc_macro_desc.attributes.end(), n) != m_proc_macro_desc.attributes.end(); } @@ -229,7 +229,7 @@ private: uint64_t recv_v128u(); }; -ProcMacroInv ProcMacro_Invoke_int(const Span& sp, const ::AST::Crate& crate, const ::std::vector<::std::string>& mac_path) +ProcMacroInv ProcMacro_Invoke_int(const Span& sp, const ::AST::Crate& crate, const ::std::vector& mac_path) { // 1. Locate macro in HIR list const auto& crate_name = mac_path.front(); @@ -745,7 +745,7 @@ namespace { } }; } -::std::unique_ptr ProcMacro_Invoke(const Span& sp, const ::AST::Crate& crate, const ::std::vector<::std::string>& mac_path, const ::std::string& item_name, const ::AST::Struct& i) +::std::unique_ptr ProcMacro_Invoke(const Span& sp, const ::AST::Crate& crate, const ::std::vector& mac_path, const ::std::string& item_name, const ::AST::Struct& i) { // 1. Create ProcMacroInv instance auto pmi = ProcMacro_Invoke_int(sp, crate, mac_path); @@ -757,7 +757,7 @@ namespace { // 3. Return boxed invocation instance return box$(pmi); } -::std::unique_ptr ProcMacro_Invoke(const Span& sp, const ::AST::Crate& crate, const ::std::vector<::std::string>& mac_path, const ::std::string& item_name, const ::AST::Enum& i) +::std::unique_ptr ProcMacro_Invoke(const Span& sp, const ::AST::Crate& crate, const ::std::vector& mac_path, const ::std::string& item_name, const ::AST::Enum& i) { // 1. Create ProcMacroInv instance auto pmi = ProcMacro_Invoke_int(sp, crate, mac_path); @@ -769,7 +769,7 @@ namespace { // 3. Return boxed invocation instance return box$(pmi); } -::std::unique_ptr ProcMacro_Invoke(const Span& sp, const ::AST::Crate& crate, const ::std::vector<::std::string>& mac_path, const ::std::string& item_name, const ::AST::Union& i) +::std::unique_ptr ProcMacro_Invoke(const Span& sp, const ::AST::Crate& crate, const ::std::vector& mac_path, const ::std::string& item_name, const ::AST::Union& i) { // 1. Create ProcMacroInv instance auto pmi = ProcMacro_Invoke_int(sp, crate, mac_path); diff --git a/src/expand/proc_macro.hpp b/src/expand/proc_macro.hpp index 8c5b71c7..e66bf037 100644 --- a/src/expand/proc_macro.hpp +++ b/src/expand/proc_macro.hpp @@ -8,8 +8,8 @@ #pragma once #include -extern ::std::unique_ptr ProcMacro_Invoke(const Span& sp, const ::AST::Crate& crate, const ::std::vector<::std::string>& mac_path, const ::std::string& name, const ::AST::Struct& i); -extern ::std::unique_ptr ProcMacro_Invoke(const Span& sp, const ::AST::Crate& crate, const ::std::vector<::std::string>& mac_path, const ::std::string& name, const ::AST::Enum& i); -extern ::std::unique_ptr ProcMacro_Invoke(const Span& sp, const ::AST::Crate& crate, const ::std::vector<::std::string>& mac_path, const ::std::string& name, const ::AST::Union& i); -//extern ::std::unique_ptr ProcMacro_Invoke(const Span& sp, const ::AST::Crate& crate, const ::std::vector<::std::string>& mac_path, const TokenStream& tt); +extern ::std::unique_ptr ProcMacro_Invoke(const Span& sp, const ::AST::Crate& crate, const ::std::vector& mac_path, const ::std::string& name, const ::AST::Struct& i); +extern ::std::unique_ptr ProcMacro_Invoke(const Span& sp, const ::AST::Crate& crate, const ::std::vector& mac_path, const ::std::string& name, const ::AST::Enum& i); +extern ::std::unique_ptr ProcMacro_Invoke(const Span& sp, const ::AST::Crate& crate, const ::std::vector& mac_path, const ::std::string& name, const ::AST::Union& i); +//extern ::std::unique_ptr ProcMacro_Invoke(const Span& sp, const ::AST::Crate& crate, const ::std::vector& mac_path, const TokenStream& tt); diff --git a/src/expand/rustc_diagnostics.cpp b/src/expand/rustc_diagnostics.cpp index 0e95bb7c..b36bf586 100644 --- a/src/expand/rustc_diagnostics.cpp +++ b/src/expand/rustc_diagnostics.cpp @@ -13,7 +13,7 @@ class CExpanderRegisterDiagnostic: public ExpandProcMacro { - ::std::unique_ptr expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override + ::std::unique_ptr expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override { return box$( TTStreamO(sp, TokenTree()) ); } @@ -21,7 +21,7 @@ class CExpanderRegisterDiagnostic: class CExpanderDiagnosticUsed: public ExpandProcMacro { - ::std::unique_ptr expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override + ::std::unique_ptr expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override { return box$( TTStreamO(sp, TokenTree()) ); } @@ -29,10 +29,8 @@ class CExpanderDiagnosticUsed: class CExpanderBuildDiagnosticArray: public ExpandProcMacro { - ::std::unique_ptr expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override + ::std::unique_ptr expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override { - if( ident != "" ) - ERROR(sp, E0000, "__build_diagnostic_array! doesn't take an ident"); auto lex = TTStream(sp, tt); Token tok; @@ -41,7 +39,7 @@ class CExpanderBuildDiagnosticArray: //auto crate_name = mv$(tok.str()); GET_CHECK_TOK(tok, lex, TOK_COMMA); GET_CHECK_TOK(tok, lex, TOK_IDENT); - auto item_name = mv$(tok.str()); + auto item_name = tok.istr(); GET_CHECK_TOK(tok, lex, TOK_EOF); ::std::vector toks; @@ -51,9 +49,9 @@ class CExpanderBuildDiagnosticArray: toks.push_back( TOK_COLON ); toks.push_back( TOK_SQUARE_OPEN ); toks.push_back( TOK_PAREN_OPEN ); - toks.push_back( TOK_AMP ); toks.push_back( Token(TOK_LIFETIME, "static") ); toks.push_back( Token(TOK_IDENT, "str") ); + toks.push_back( TOK_AMP ); toks.push_back( Token(TOK_LIFETIME, RcString::new_interned("static")) ); toks.push_back( Token(TOK_IDENT, RcString::new_interned("str")) ); toks.push_back( TOK_COMMA ); - toks.push_back( TOK_AMP ); toks.push_back( Token(TOK_LIFETIME, "static") ); toks.push_back( Token(TOK_IDENT, "str") ); + toks.push_back( TOK_AMP ); toks.push_back( Token(TOK_LIFETIME, RcString::new_interned("static")) ); toks.push_back( Token(TOK_IDENT, RcString::new_interned("str")) ); toks.push_back( TOK_PAREN_CLOSE ); toks.push_back( TOK_SEMICOLON ); toks.push_back( Token(static_cast(0), CORETYPE_UINT) ); diff --git a/src/expand/stringify.cpp b/src/expand/stringify.cpp index f552ffd4..561177ef 100644 --- a/src/expand/stringify.cpp +++ b/src/expand/stringify.cpp @@ -12,7 +12,7 @@ class CExpander: public ExpandProcMacro { - ::std::unique_ptr expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override + ::std::unique_ptr expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) override { Token tok; ::std::string rv; diff --git a/src/expand/test.cpp b/src/expand/test.cpp index 9497c692..ac536228 100644 --- a/src/expand/test.cpp +++ b/src/expand/test.cpp @@ -25,7 +25,7 @@ class CTestHandler: for(const auto& node : path.nodes()) { td.name += "::"; - td.name += node.name(); + td.name += node.name().c_str(); } td.path = ::AST::Path(path); diff --git a/src/expand/test_harness.cpp b/src/expand/test_harness.cpp index f720cac7..36b60632 100644 --- a/src/expand/test_harness.cpp +++ b/src/expand/test_harness.cpp @@ -89,10 +89,10 @@ void Expand_TestHarness(::AST::Crate& crate) auto desc_expr = NEWNODE(_StructLiteral, ::AST::Path("test", { ::AST::PathNode("TestDesc")}), nullptr, mv$(desc_vals)); ::AST::ExprNode_StructLiteral::t_values descandfn_vals; - descandfn_vals.push_back({ {}, ::std::string("desc"), mv$(desc_expr) }); + descandfn_vals.push_back({ {}, RcString::new_interned("desc"), mv$(desc_expr) }); auto test_type_var_name = test.is_benchmark ? "StaticBenchFn" : "StaticTestFn"; - descandfn_vals.push_back({ {}, ::std::string("testfn"), NEWNODE(_CallPath, + descandfn_vals.push_back({ {}, RcString::new_interned("testfn"), NEWNODE(_CallPath, ::AST::Path("test", { ::AST::PathNode(test_type_var_name) }), ::make_vec1( NEWNODE(_NamedValue, AST::Path(test.path)) ) ) }); diff --git a/src/hir/crate_post_load.cpp b/src/hir/crate_post_load.cpp index 81c5b029..a0733987 100644 --- a/src/hir/crate_post_load.cpp +++ b/src/hir/crate_post_load.cpp @@ -9,7 +9,7 @@ #include // Used to update the crate name -void HIR::Crate::post_load_update(const ::std::string& name) +void HIR::Crate::post_load_update(const RcString& name) { // TODO: Do a pass across m_hir that // 1. Updates all absolute paths with the crate name diff --git a/src/hir/deserialise.cpp b/src/hir/deserialise.cpp index c5350b55..56671a04 100644 --- a/src/hir/deserialise.cpp +++ b/src/hir/deserialise.cpp @@ -22,13 +22,14 @@ class HirDeserialiser { - ::std::string m_crate_name; + RcString m_crate_name; ::HIR::serialise::Reader& m_in; public: HirDeserialiser(::HIR::serialise::Reader& in): m_in(in) {} + RcString read_istring() { return m_in.read_istring(); } ::std::string read_string() { return m_in.read_string(); } bool read_bool() { return m_in.read_bool(); } size_t deserialise_count() { return m_in.read_count(); } @@ -78,6 +79,51 @@ return rv; } + template + ::std::map< RcString,V> deserialise_istrmap() + { + TRACE_FUNCTION_F("<" << typeid(V).name() << ">"); + size_t n = m_in.read_count(); + ::std::map< RcString, V> rv; + //rv.reserve(n); + for(size_t i = 0; i < n; i ++) + { + auto s = m_in.read_istring(); + rv.insert( ::std::make_pair( mv$(s), D::des(*this) ) ); + } + return rv; + } + template + ::std::unordered_map< RcString,V> deserialise_istrumap() + { + TRACE_FUNCTION_F("<" << typeid(V).name() << ">"); + size_t n = m_in.read_count(); + ::std::unordered_map rv; + //rv.reserve(n); + for(size_t i = 0; i < n; i ++) + { + auto s = m_in.read_istring(); + DEBUG("- " << s); + rv.insert( ::std::make_pair( mv$(s), D::des(*this) ) ); + } + return rv; + } + template + ::std::unordered_multimap deserialise_istrummap() + { + TRACE_FUNCTION_F("<" << typeid(V).name() << ">"); + size_t n = m_in.read_count(); + ::std::unordered_multimap rv; + //rv.reserve(n); + for(size_t i = 0; i < n; i ++) + { + auto s = m_in.read_istring(); + DEBUG("- " << s); + rv.insert( ::std::make_pair( mv$(s), D::des(*this) ) ); + } + return rv; + } + template ::std::vector deserialise_vec() { @@ -117,6 +163,7 @@ } + ::HIR::LifetimeDef deserialise_lifetimedef(); ::HIR::LifetimeRef deserialise_lifetimeref(); ::HIR::TypeRef deserialise_type(); ::HIR::SimplePath deserialise_simplepath(); @@ -137,7 +184,7 @@ { ::HIR::ProcMacro pm; TRACE_FUNCTION_FR("", "ProcMacro { " << pm.name << ", " << pm.path << ", [" << pm.attributes << "]}"); - pm.name = m_in.read_string(); + pm.name = m_in.read_istring(); pm.path = deserialise_simplepath(); pm.attributes = deserialise_vec< ::std::string>(); DEBUG("pm = ProcMacro { " << pm.name << ", " << pm.path << ", [" << pm.attributes << "]}"); @@ -155,7 +202,7 @@ size_t method_count = m_in.read_count(); for(size_t i = 0; i < method_count; i ++) { - auto name = m_in.read_string(); + auto name = m_in.read_istring(); rv.m_methods.insert( ::std::make_pair( mv$(name), ::HIR::TypeImpl::VisImplEnt< ::HIR::Function> { deserialise_pub(), m_in.read_bool(), deserialise_function() } ) ); @@ -163,7 +210,7 @@ size_t const_count = m_in.read_count(); for(size_t i = 0; i < const_count; i ++) { - auto name = m_in.read_string(); + auto name = m_in.read_istring(); rv.m_constants.insert( ::std::make_pair( mv$(name), ::HIR::TypeImpl::VisImplEnt< ::HIR::Constant> { deserialise_pub(), m_in.read_bool(), deserialise_constant() } ) ); @@ -184,7 +231,7 @@ size_t method_count = m_in.read_count(); for(size_t i = 0; i < method_count; i ++) { - auto name = m_in.read_string(); + auto name = m_in.read_istring(); auto is_spec = m_in.read_bool(); rv.m_methods.insert( ::std::make_pair( mv$(name), ::HIR::TraitImpl::ImplEnt< ::HIR::Function> { is_spec, deserialise_function() @@ -193,7 +240,7 @@ size_t const_count = m_in.read_count(); for(size_t i = 0; i < const_count; i ++) { - auto name = m_in.read_string(); + auto name = m_in.read_istring(); auto is_spec = m_in.read_bool(); rv.m_constants.insert( ::std::make_pair( mv$(name), ::HIR::TraitImpl::ImplEnt< ::HIR::Constant> { is_spec, deserialise_constant() @@ -202,7 +249,7 @@ size_t static_count = m_in.read_count(); for(size_t i = 0; i < static_count; i ++) { - auto name = m_in.read_string(); + auto name = m_in.read_istring(); auto is_spec = m_in.read_bool(); rv.m_statics.insert( ::std::make_pair( mv$(name), ::HIR::TraitImpl::ImplEnt< ::HIR::Static> { is_spec, deserialise_static() @@ -211,7 +258,7 @@ size_t type_count = m_in.read_count(); for(size_t i = 0; i < type_count; i ++) { - auto name = m_in.read_string(); + auto name = m_in.read_istring(); auto is_spec = m_in.read_bool(); rv.m_types.insert( ::std::make_pair( mv$(name), ::HIR::TraitImpl::ImplEnt< ::HIR::TypeRef> { is_spec, deserialise_type() @@ -240,10 +287,10 @@ // NOTE: This is set after loading. //rv.m_exported = true; rv.m_rules = deserialise_vec_c< ::MacroRulesArm>( [&](){ return deserialise_macrorulesarm(); }); - rv.m_source_crate = m_in.read_string(); + rv.m_source_crate = m_in.read_istring(); if(rv.m_source_crate == "") { - assert(!m_crate_name.empty()); + assert(m_crate_name != ""); rv.m_source_crate = m_crate_name; } return rv; @@ -288,7 +335,7 @@ } } ::MacroPatEnt deserialise_macropatent() { - auto s = m_in.read_string(); + auto s = m_in.read_istring(); auto n = static_cast(m_in.read_count()); auto type = static_cast< ::MacroPatEnt::Type>(m_in.read_tag()); ::MacroPatEnt rv { mv$(s), mv$(n), mv$(type) }; @@ -320,7 +367,7 @@ } ::MacroRulesArm deserialise_macrorulesarm() { ::MacroRulesArm rv; - rv.m_param_names = deserialise_vec< ::std::string>(); + rv.m_param_names = deserialise_vec(); rv.m_pattern = deserialise_vec_c< ::SimplePatEnt>( [&](){ return deserialise_simplepatent(); } ); rv.m_contents = deserialise_vec_c< ::MacroExpansionEnt>( [&](){ return deserialise_macroexpansionent(); } ); return rv; @@ -366,6 +413,8 @@ return ::Token::Data::make_None({}); case ::Token::Data::TAG_String: return ::Token::Data::make_String( m_in.read_string() ); + case ::Token::Data::TAG_IString: + return ::Token::Data::make_IString( m_in.read_istring() ); case ::Token::Data::TAG_Integer: { auto dty = static_cast(m_in.read_tag()); return ::Token::Data::make_Integer({ dty, m_in.read_u64c() }); @@ -723,7 +772,7 @@ { return ::HIR::AssociatedType { m_in.read_bool(), - "", // TODO: Better lifetime type + deserialise_lifetimeref(), deserialise_vec< ::HIR::TraitPath>(), deserialise_type() }; @@ -737,6 +786,9 @@ DEF_D( ::std::string, return d.read_string(); ); template<> + DEF_D( RcString, + return d.read_istring(); ); + template<> DEF_D( bool, return d.read_bool(); ); @@ -754,6 +806,8 @@ DEF_D( ::HIR::VisEnt, return d.deserialise_visent(); ) + template<> DEF_D( ::HIR::LifetimeDef, return d.deserialise_lifetimedef(); ) + template<> DEF_D( ::HIR::LifetimeRef, return d.deserialise_lifetimeref(); ) template<> DEF_D( ::HIR::TypeRef, return d.deserialise_type(); ) template<> DEF_D( ::HIR::SimplePath, return d.deserialise_simplepath(); ) template<> DEF_D( ::HIR::GenericPath, return d.deserialise_genericpath(); ) @@ -784,6 +838,12 @@ template<> DEF_D( ::HIR::ExternLibrary, return d.deserialise_extlib(); ) + ::HIR::LifetimeDef HirDeserialiser::deserialise_lifetimedef() + { + ::HIR::LifetimeDef rv; + rv.m_name = m_in.read_istring(); + return rv; + } ::HIR::LifetimeRef HirDeserialiser::deserialise_lifetimeref() { ::HIR::LifetimeRef rv; @@ -808,7 +868,7 @@ {} }) _(Generic, { - m_in.read_string(), + m_in.read_istring(), m_in.read_u16() }) _(TraitObject, { @@ -859,11 +919,11 @@ { TRACE_FUNCTION; // HACK! If the read crate name is empty, replace it with the name we're loaded with - auto crate_name = m_in.read_string(); - auto components = deserialise_vec< ::std::string>(); + auto crate_name = m_in.read_istring(); + auto components = deserialise_vec< RcString>(); if( crate_name == "" && components.size() > 0) { - assert(!m_crate_name.empty()); + assert(m_crate_name != ""); crate_name = m_crate_name; } return ::HIR::SimplePath { @@ -889,7 +949,7 @@ ::HIR::TraitPath HirDeserialiser::deserialise_traitpath() { auto gpath = deserialise_genericpath(); - auto tys = deserialise_strmap< ::HIR::TypeRef>(); + auto tys = deserialise_istrmap< ::HIR::TypeRef>(); return ::HIR::TraitPath { mv$(gpath), {}, mv$(tys) }; } ::HIR::Path HirDeserialiser::deserialise_path() @@ -904,7 +964,7 @@ DEBUG("Inherent"); return ::HIR::Path( ::HIR::Path::Data::Data_UfcsInherent { box$( deserialise_type() ), - m_in.read_string(), + m_in.read_istring(), deserialise_pathparams(), deserialise_pathparams() } ); @@ -913,7 +973,7 @@ return ::HIR::Path( ::HIR::Path::Data::Data_UfcsKnown { box$( deserialise_type() ), deserialise_genericpath(), - m_in.read_string(), + m_in.read_istring(), deserialise_pathparams() } ); default: @@ -926,7 +986,7 @@ TRACE_FUNCTION; ::HIR::GenericParams params; params.m_types = deserialise_vec< ::HIR::TypeParamDef>(); - params.m_lifetimes = deserialise_vec< ::std::string>(); + params.m_lifetimes = deserialise_vec< ::HIR::LifetimeDef>(); params.m_bounds = deserialise_vec< ::HIR::GenericBound>(); DEBUG("params = " << params.fmt_args() << ", " << params.fmt_bounds()); return params; @@ -934,7 +994,7 @@ ::HIR::TypeParamDef HirDeserialiser::deserialise_typaramdef() { auto rv = ::HIR::TypeParamDef { - m_in.read_string(), + m_in.read_istring(), deserialise_type(), m_in.read_bool() }; @@ -991,7 +1051,7 @@ } ::HIR::Enum::DataVariant HirDeserialiser::deserialise_enumdatavariant() { - auto name = m_in.read_string(); + auto name = m_in.read_istring(); DEBUG("Enum::DataVariant " << name); return ::HIR::Enum::DataVariant { mv$(name), @@ -1001,7 +1061,7 @@ } ::HIR::Enum::ValueVariant HirDeserialiser::deserialise_enumvaluevariant() { - auto name = m_in.read_string(); + auto name = m_in.read_istring(); DEBUG("Enum::ValueVariant " << name); return ::HIR::Enum::ValueVariant { mv$(name), @@ -1014,7 +1074,7 @@ TRACE_FUNCTION; auto params = deserialise_genericparams(); auto repr = static_cast< ::HIR::Union::Repr>( m_in.read_tag() ); - auto variants = deserialise_vec< ::std::pair< ::std::string, ::HIR::VisEnt< ::HIR::TypeRef> > >(); + auto variants = deserialise_vec< ::std::pair< RcString, ::HIR::VisEnt< ::HIR::TypeRef> > >(); auto markings = deserialise_markings(); return ::HIR::Union { @@ -1041,7 +1101,7 @@ break; case ::HIR::Struct::Data::TAG_Named: DEBUG("Named"); - data = ::HIR::Struct::Data( deserialise_vec< ::std::pair< ::std::string, ::HIR::VisEnt< ::HIR::TypeRef> > >() ); + data = ::HIR::Struct::Data( deserialise_vec< ::std::pair< RcString, ::HIR::VisEnt< ::HIR::TypeRef> > >() ); break; default: BUG(Span(), "Bad tag for HIR::Struct::Data - " << tag); @@ -1061,15 +1121,16 @@ ::HIR::Trait rv { deserialise_genericparams(), - "", // TODO: Better type for lifetime + ::HIR::LifetimeRef(), // TODO: Better type for lifetime {} }; rv.m_is_marker = m_in.read_bool(); - rv.m_types = deserialise_strumap< ::HIR::AssociatedType>(); - rv.m_values = deserialise_strumap< ::HIR::TraitValueItem>(); - rv.m_value_indexes = deserialise_strummap< ::std::pair >(); - rv.m_type_indexes = deserialise_strumap< unsigned int>(); + rv.m_types = deserialise_istrumap< ::HIR::AssociatedType>(); + rv.m_values = deserialise_istrumap< ::HIR::TraitValueItem>(); + rv.m_value_indexes = deserialise_istrummap< ::std::pair >(); + rv.m_type_indexes = deserialise_istrumap< unsigned int>(); rv.m_all_parent_traits = deserialise_vec< ::HIR::TraitPath>(); + rv.m_vtable_path = deserialise_simplepath(); return rv; } @@ -1225,7 +1286,7 @@ _(Value, deserialise_mir_lvalue() ) _(Path, deserialise_path() ) _(Intrinsic, { - m_in.read_string(), + m_in.read_istring(), deserialise_pathparams() }) #undef _ @@ -1241,8 +1302,8 @@ ::HIR::Module rv; // m_traits doesn't need to be serialised - rv.m_value_items = deserialise_strumap< ::std::unique_ptr< ::HIR::VisEnt< ::HIR::ValueItem> > >(); - rv.m_mod_items = deserialise_strumap< ::std::unique_ptr< ::HIR::VisEnt< ::HIR::TypeItem> > >(); + rv.m_value_items = deserialise_istrumap< ::std::unique_ptr< ::HIR::VisEnt< ::HIR::ValueItem> > >(); + rv.m_mod_items = deserialise_istrumap< ::std::unique_ptr< ::HIR::VisEnt< ::HIR::TypeItem> > >(); return rv; } @@ -1256,8 +1317,8 @@ { ::HIR::Crate rv; - this->m_crate_name = m_in.read_string(); - assert(!this->m_crate_name.empty() && "Empty crate name loaded from metadata"); + this->m_crate_name = m_in.read_istring(); + assert(this->m_crate_name != "" && "Empty crate name loaded from metadata"); rv.m_crate_name = this->m_crate_name; rv.m_root_module = deserialise_module(); @@ -1280,14 +1341,14 @@ } } - rv.m_exported_macros = deserialise_strumap< ::MacroRulesPtr>(); + rv.m_exported_macros = deserialise_istrumap< ::MacroRulesPtr>(); rv.m_lang_items = deserialise_strumap< ::HIR::SimplePath>(); { size_t n = m_in.read_count(); for(size_t i = 0; i < n; i ++) { - auto ext_crate_name = m_in.read_string(); + auto ext_crate_name = m_in.read_istring(); auto ext_crate_file = m_in.read_string(); auto ext_crate = ::HIR::ExternCrate {}; ext_crate.m_basename = ext_crate_file; @@ -1304,7 +1365,7 @@ } //} -::HIR::CratePtr HIR_Deserialise(const ::std::string& filename, const ::std::string& loaded_name) +::HIR::CratePtr HIR_Deserialise(const ::std::string& filename) { try { diff --git a/src/hir/expr.hpp b/src/hir/expr.hpp index 140ba817..d099ecb4 100644 --- a/src/hir/expr.hpp +++ b/src/hir/expr.hpp @@ -133,11 +133,11 @@ struct ExprNode_Return: struct ExprNode_Loop: public ExprNode { - ::std::string m_label; + RcString m_label; ::HIR::ExprNodeP m_code; bool m_diverges = false; - ExprNode_Loop(Span sp, ::std::string label, ::HIR::ExprNodeP code): + ExprNode_Loop(Span sp, RcString label, ::HIR::ExprNodeP code): //ExprNode(mv$(sp), ::HIR::TypeRef::new_unit()), ExprNode(mv$(sp), ::HIR::TypeRef()), m_label( mv$(label) ), @@ -149,11 +149,11 @@ struct ExprNode_Loop: struct ExprNode_LoopControl: public ExprNode { - ::std::string m_label; + RcString m_label; bool m_continue; ::HIR::ExprNodeP m_value; - ExprNode_LoopControl(Span sp, ::std::string label, bool cont, ::HIR::ExprNodeP value={}): + ExprNode_LoopControl(Span sp, RcString label, bool cont, ::HIR::ExprNodeP value={}): ExprNode(mv$(sp), ::HIR::TypeRef::new_diverge()), m_label( mv$(label) ), m_continue( cont ), @@ -539,7 +539,7 @@ struct ExprNode_CallMethod: public ExprNode { ::HIR::ExprNodeP m_value; - ::std::string m_method; + RcString m_method; ::HIR::PathParams m_params; ::std::vector< ::HIR::ExprNodeP> m_args; @@ -553,7 +553,7 @@ struct ExprNode_CallMethod: // - A pool of ivars to use for searching for trait impls ::std::vector m_trait_param_ivars; - ExprNode_CallMethod(Span sp, ::HIR::ExprNodeP val, ::std::string method_name, ::HIR::PathParams params, ::std::vector< ::HIR::ExprNodeP> args): + ExprNode_CallMethod(Span sp, ::HIR::ExprNodeP val, RcString method_name, ::HIR::PathParams params, ::std::vector< ::HIR::ExprNodeP> args): ExprNode( mv$(sp) ), m_value( mv$(val) ), m_method( mv$(method_name) ), @@ -570,9 +570,9 @@ struct ExprNode_Field: public ExprNode { ::HIR::ExprNodeP m_value; - ::std::string m_field; + RcString m_field; - ExprNode_Field(Span sp, ::HIR::ExprNodeP val, ::std::string field): + ExprNode_Field(Span sp, ::HIR::ExprNodeP val, RcString field): ExprNode(mv$(sp)), m_value( mv$(val) ), m_field( mv$(field) ) @@ -677,10 +677,10 @@ struct ExprNode_PathValue: struct ExprNode_Variable: public ExprNode { - ::std::string m_name; + RcString m_name; unsigned int m_slot; - ExprNode_Variable(Span sp, ::std::string name, unsigned int slot): + ExprNode_Variable(Span sp, RcString name, unsigned int slot): ExprNode(mv$(sp)), m_name( mv$(name) ), m_slot( slot ) @@ -692,7 +692,7 @@ struct ExprNode_Variable: struct ExprNode_StructLiteral: public ExprNode { - typedef ::std::vector< ::std::pair< ::std::string, ExprNodeP > > t_values; + typedef ::std::vector< ::std::pair< RcString, ExprNodeP > > t_values; ::HIR::Path m_path; bool m_is_struct; @@ -719,12 +719,12 @@ struct ExprNode_UnionLiteral: public ExprNode { ::HIR::GenericPath m_path; - ::std::string m_variant_name; + RcString m_variant_name; ::HIR::ExprNodeP m_value; unsigned int m_variant_index = ~0; - ExprNode_UnionLiteral(Span sp, ::HIR::GenericPath path, ::std::string name, ::HIR::ExprNodeP value): + ExprNode_UnionLiteral(Span sp, ::HIR::GenericPath path, RcString name, ::HIR::ExprNodeP value): ExprNode( mv$(sp) ), m_path( mv$(path) ), m_variant_name( mv$(name) ), diff --git a/src/hir/from_ast.cpp b/src/hir/from_ast.cpp index 2393cadd..84980818 100644 --- a/src/hir/from_ast.cpp +++ b/src/hir/from_ast.cpp @@ -23,15 +23,18 @@ ::HIR::TraitPath LowerHIR_TraitPath(const Span& sp, const ::AST::Path& path); ::HIR::SimplePath path_Sized; -::std::string g_core_crate; -::std::string g_crate_name; +RcString g_core_crate; +RcString g_crate_name; ::HIR::Crate* g_crate_ptr = nullptr; const ::AST::Crate* g_ast_crate_ptr; // -------------------------------------------------------------------- -::std::string LowerHIR_LifetimeRef(const ::AST::LifetimeRef& r) +HIR::LifetimeRef LowerHIR_LifetimeRef(const ::AST::LifetimeRef& r) { - return r.name().name; + return HIR::LifetimeRef { + // TODO: names? + r.binding() + }; } ::HIR::GenericParams LowerHIR_GenericParams(const ::AST::GenericParams& gp, bool* self_is_sized) @@ -48,7 +51,7 @@ const ::AST::Crate* g_ast_crate_ptr; if( gp.lft_params().size() > 0 ) { for(const auto& lft_def : gp.lft_params()) - rv.m_lifetimes.push_back( lft_def.name().name ); + rv.m_lifetimes.push_back( HIR::LifetimeDef { lft_def.name().name } ); } if( gp.bounds().size() > 0 ) { @@ -316,7 +319,7 @@ const ::AST::Crate* g_ast_crate_ptr; } } TU_ARMA(Struct, e) { - ::std::vector< ::std::pair< ::std::string, ::HIR::Pattern> > sub_patterns; + ::std::vector< ::std::pair< RcString, ::HIR::Pattern> > sub_patterns; for(const auto& sp : e.sub_patterns) sub_patterns.push_back( ::std::make_pair(sp.first, LowerHIR_Pattern(sp.second)) ); @@ -968,7 +971,7 @@ namespace { return rv; } -::HIR::Enum LowerHIR_Enum(::HIR::ItemPath path, const ::AST::Enum& ent, const ::AST::AttributeList& attrs, ::std::function push_struct) +::HIR::Enum LowerHIR_Enum(::HIR::ItemPath path, const ::AST::Enum& ent, const ::AST::AttributeList& attrs, ::std::function push_struct) { // 1. Figure out what sort of enum this is (value or data) bool has_value = false; @@ -1081,7 +1084,7 @@ namespace { throw ""; } - auto ty_name = FMT(path.name << "#" << var.m_name); + auto ty_name = RcString::new_interned(FMT(path.name << "#" << var.m_name)); push_struct( ty_name, ::HIR::Struct { @@ -1156,14 +1159,14 @@ namespace { bool trait_reqires_sized = false; auto params = LowerHIR_GenericParams(f.params(), &trait_reqires_sized); - ::std::string lifetime; + ::HIR::LifetimeRef lifetime; ::std::vector< ::HIR::TraitPath> supertraits; for(const auto& st : f.supertraits()) { if( st.ent.path.is_valid() ) { supertraits.push_back( LowerHIR_TraitPath(st.sp, st.ent.path) ); } else { - lifetime = "static"; + lifetime = ::HIR::LifetimeRef::new_static(); } } ::HIR::Trait rv { @@ -1201,7 +1204,7 @@ namespace { (Type, bool is_sized = true; ::std::vector< ::HIR::TraitPath> trait_bounds; - ::std::string lifetime_bound; + ::HIR::LifetimeRef lifetime_bound; auto gps = LowerHIR_GenericParams(i.params(), &is_sized); for(auto& b : gps.m_bounds) @@ -1385,10 +1388,10 @@ namespace { }; } -void _add_mod_ns_item(::HIR::Module& mod, ::std::string name, ::HIR::Publicity is_pub, ::HIR::TypeItem ti) { +void _add_mod_ns_item(::HIR::Module& mod, RcString name, ::HIR::Publicity is_pub, ::HIR::TypeItem ti) { mod.m_mod_items.insert( ::std::make_pair( mv$(name), ::make_unique_ptr(::HIR::VisEnt< ::HIR::TypeItem> { is_pub, mv$(ti) }) ) ); } -void _add_mod_val_item(::HIR::Module& mod, ::std::string name, ::HIR::Publicity is_pub, ::HIR::ValueItem ti) { +void _add_mod_val_item(::HIR::Module& mod, RcString name, ::HIR::Publicity is_pub, ::HIR::ValueItem ti) { mod.m_value_items.insert( ::std::make_pair( mv$(name), ::make_unique_ptr(::HIR::VisEnt< ::HIR::ValueItem> { is_pub, mv$(ti) }) ) ); } @@ -1418,7 +1421,7 @@ void _add_mod_val_item(::HIR::Module& mod, ::std::string name, ::HIR::Publicity if( submod_ptr ) { auto& submod = *submod_ptr; - ::std::string name = FMT("#" << i); + auto name = RcString::new_interned(FMT("#" << i)); auto item_path = ::HIR::ItemPath(path, name.c_str()); auto ti = ::HIR::TypeItem::make_Module( LowerHIR_Module(submod, item_path, mod.m_traits) ); _add_mod_ns_item( mod, mv$(name), get_pub(false), mv$(ti) ); @@ -1534,7 +1537,7 @@ void _add_mod_val_item(::HIR::Module& mod, ::std::string name, ::HIR::Publicity // If there's no code, demangle the name (TODO: By ABI) and set linkage. if( linkage.name == "" && ! e.value().is_valid() ) { - linkage.name = item.name; + linkage.name = item.name.c_str(); } _add_mod_val_item(mod, item.name, get_pub(item.is_pub), ::HIR::ValueItem::make_Static(::HIR::Static { @@ -1633,9 +1636,9 @@ void LowerHIR_Module_Impls(const ::AST::Module& ast_mod, ::HIR::Crate& hir_crat ::HIR::ItemPath path(type, trait_name, trait_args); DEBUG(path); - ::std::map< ::std::string, ::HIR::TraitImpl::ImplEnt< ::HIR::Function> > methods; - ::std::map< ::std::string, ::HIR::TraitImpl::ImplEnt< ::HIR::Constant> > constants; - ::std::map< ::std::string, ::HIR::TraitImpl::ImplEnt< ::HIR::TypeRef> > types; + ::std::map< RcString, ::HIR::TraitImpl::ImplEnt< ::HIR::Function> > methods; + ::std::map< RcString, ::HIR::TraitImpl::ImplEnt< ::HIR::Constant> > constants; + ::std::map< RcString, ::HIR::TraitImpl::ImplEnt< ::HIR::TypeRef> > types; for(const auto& item : impl.items()) { @@ -1711,8 +1714,8 @@ void LowerHIR_Module_Impls(const ::AST::Module& ast_mod, ::HIR::Crate& hir_crat auto priv_path = ::HIR::Publicity::new_priv( LowerHIR_SimplePath(Span(), ast_mod.path()) ); // TODO: Does this need to consume anon modules? auto get_pub = [&](bool is_pub){ return is_pub ? ::HIR::Publicity::new_global() : priv_path; }; - ::std::map< ::std::string, ::HIR::TypeImpl::VisImplEnt< ::HIR::Function> > methods; - ::std::map< ::std::string, ::HIR::TypeImpl::VisImplEnt< ::HIR::Constant> > constants; + ::std::map< RcString, ::HIR::TypeImpl::VisImplEnt< ::HIR::Function> > methods; + ::std::map< RcString, ::HIR::TypeImpl::VisImplEnt< ::HIR::Constant> > constants; for(const auto& item : impl.items()) { @@ -1809,18 +1812,20 @@ public: if(crate.m_crate_type != ::AST::Crate::Type::Executable) { - rv.m_crate_name = crate.m_crate_name; if(crate.m_crate_name_suffix != "") { - rv.m_crate_name += "-"; - rv.m_crate_name += crate.m_crate_name_suffix; + rv.m_crate_name = RcString::new_interned(FMT(crate.m_crate_name + "-" + crate.m_crate_name_suffix)); + } + else + { + rv.m_crate_name = RcString::new_interned(crate.m_crate_name); } } g_crate_ptr = &rv; g_ast_crate_ptr = &crate; g_crate_name = rv.m_crate_name; - g_core_crate = (crate.m_load_std == ::AST::Crate::LOAD_NONE ? rv.m_crate_name : "core"); + g_core_crate = (crate.m_load_std == ::AST::Crate::LOAD_NONE ? rv.m_crate_name : RcString::new_interned("core")); auto& macros = rv.m_exported_macros; // - Extract exported macros @@ -1896,7 +1901,7 @@ public: for(const auto& ent : crate.m_proc_macros) { // Register under an invalid simplepath - rv.m_proc_macros.push_back( ::HIR::ProcMacro { ent.name, ::HIR::SimplePath("", { ent.name}), ent.attributes } ); + rv.m_proc_macros.push_back( ::HIR::ProcMacro { ent.name, ::HIR::SimplePath(RcString(""), { ent.name }), ent.attributes } ); } } else diff --git a/src/hir/from_ast.hpp b/src/hir/from_ast.hpp index 4625f479..3eeaaa48 100644 --- a/src/hir/from_ast.hpp +++ b/src/hir/from_ast.hpp @@ -16,5 +16,5 @@ extern ::HIR::SimplePath LowerHIR_SimplePath(const Span& sp, const ::AST::Pat extern ::HIR::TypeRef LowerHIR_Type(const ::TypeRef& ty); extern ::HIR::Pattern LowerHIR_Pattern(const ::AST::Pattern& pat); -extern ::std::string g_core_crate; +extern RcString g_core_crate; extern ::HIR::Crate* g_crate_ptr; diff --git a/src/hir/from_ast_expr.cpp b/src/hir/from_ast_expr.cpp index fdb2b867..baca8d75 100644 --- a/src/hir/from_ast_expr.cpp +++ b/src/hir/from_ast_expr.cpp @@ -332,16 +332,16 @@ struct LowerHIR_ExprNode_Visitor: break; } - // TODO: Iterate the constructed loop and determine if there are any `break` statements pointing to it + // Iterate the constructed loop and determine if there are any `break` statements pointing to it { struct LoopVisitor: public ::HIR::ExprVisitorDef { - const ::std::string& top_label; + const RcString& top_label; bool top_is_broken; - ::std::vector< const ::std::string*> name_stack; + ::std::vector< const RcString*> name_stack; - LoopVisitor(const ::std::string& top_label): + LoopVisitor(const RcString& top_label): top_label(top_label), top_is_broken(false), name_stack() diff --git a/src/hir/generic_params.cpp b/src/hir/generic_params.cpp index 381277fc..3f6559a7 100644 --- a/src/hir/generic_params.cpp +++ b/src/hir/generic_params.cpp @@ -33,7 +33,7 @@ namespace HIR { { os << "<"; for(const auto& lft : x.gp.m_lifetimes) { - os << "'" << lft << ","; + os << "'" << lft.m_name << ","; } for(const auto& typ : x.gp.m_types) { os << typ.m_name; diff --git a/src/hir/generic_params.hpp b/src/hir/generic_params.hpp index ef83bda7..afa1c682 100644 --- a/src/hir/generic_params.hpp +++ b/src/hir/generic_params.hpp @@ -15,19 +15,23 @@ namespace HIR { struct TypeParamDef { - ::std::string m_name; + RcString m_name; ::HIR::TypeRef m_default; bool m_is_sized; }; +struct LifetimeDef +{ + RcString m_name; +}; TAGGED_UNION(GenericBound, Lifetime, (Lifetime, struct { - ::std::string test; - ::std::string valid_for; + LifetimeRef test; + LifetimeRef valid_for; }), (TypeLifetime, struct { ::HIR::TypeRef type; - ::std::string valid_for; + LifetimeRef valid_for; }), (TraitBound, struct { ::HIR::TypeRef type; @@ -47,8 +51,8 @@ extern ::std::ostream& operator<<(::std::ostream& os, const GenericBound& x); class GenericParams { public: - ::std::vector m_types; - ::std::vector< ::std::string> m_lifetimes; + ::std::vector m_types; + ::std::vector m_lifetimes; ::std::vector m_bounds; diff --git a/src/hir/hir.cpp b/src/hir/hir.cpp index 2a8ac8bf..88b1cb8c 100644 --- a/src/hir/hir.cpp +++ b/src/hir/hir.cpp @@ -149,7 +149,7 @@ bool HIR::Publicity::is_visible(const ::HIR::SimplePath& p) const return true; } -size_t HIR::Enum::find_variant(const ::std::string& name) const +size_t HIR::Enum::find_variant(const RcString& name) const { if( m_data.is_Value() ) { diff --git a/src/hir/hir.hpp b/src/hir/hir.hpp index cc66a9e7..3f045dd2 100644 --- a/src/hir/hir.hpp +++ b/src/hir/hir.hpp @@ -192,7 +192,7 @@ struct TypeAlias }; typedef ::std::vector< VisEnt<::HIR::TypeRef> > t_tuple_fields; -typedef ::std::vector< ::std::pair< ::std::string, VisEnt<::HIR::TypeRef> > > t_struct_fields; +typedef ::std::vector< ::std::pair< RcString, VisEnt<::HIR::TypeRef> > > t_struct_fields; /// Cache of the state of various language traits on an enum/struct struct TraitMarkings @@ -258,7 +258,7 @@ class Enum { public: struct DataVariant { - ::std::string name; + RcString name; bool is_struct; // Indicates that the variant does not show up in the value namespace ::HIR::TypeRef type; }; @@ -269,7 +269,7 @@ public: Usize, U8, U16, U32, U64, }; struct ValueVariant { - ::std::string name; + RcString name; ::HIR::ExprPtr expr; // TODO: Signed. uint64_t val; @@ -290,7 +290,7 @@ public: size_t num_variants() const { return (m_data.is_Data() ? m_data.as_Data().size() : m_data.as_Value().variants.size()); } - size_t find_variant(const ::std::string& ) const; + size_t find_variant(const RcString& ) const; /// Returns true if this enum is a C-like enum (has values only) bool is_value() const; @@ -343,7 +343,7 @@ public: struct AssociatedType { bool is_sized; - ::std::string m_lifetime_bound; + LifetimeRef m_lifetime_bound; ::std::vector< ::HIR::TraitPath> m_trait_bounds; ::HIR::TypeRef m_default; }; @@ -356,23 +356,25 @@ class Trait { public: GenericParams m_params; - ::std::string m_lifetime; + LifetimeRef m_lifetime; ::std::vector< ::HIR::TraitPath > m_parent_traits; bool m_is_marker; // aka OIBIT - ::std::unordered_map< ::std::string, AssociatedType > m_types; - ::std::unordered_map< ::std::string, TraitValueItem > m_values; + ::std::unordered_map< RcString, AssociatedType > m_types; + ::std::unordered_map< RcString, TraitValueItem > m_values; // Indexes into the vtable for each present method and value - ::std::unordered_multimap< ::std::string, ::std::pair > m_value_indexes; + ::std::unordered_multimap< RcString, ::std::pair > m_value_indexes; // Indexes in the vtable parameter list for each associated type - ::std::unordered_map< ::std::string, unsigned int > m_type_indexes; + ::std::unordered_map< RcString, unsigned int > m_type_indexes; // Flattend set of parent traits (monomorphised and associated types fixed) ::std::vector< ::HIR::TraitPath > m_all_parent_traits; + // VTable path + ::HIR::SimplePath m_vtable_path; - Trait( GenericParams gps, ::std::string lifetime, ::std::vector< ::HIR::TraitPath> parents): + Trait( GenericParams gps, LifetimeRef lifetime, ::std::vector< ::HIR::TraitPath> parents): m_params( mv$(gps) ), m_lifetime( mv$(lifetime) ), m_parent_traits( mv$(parents) ), @@ -387,11 +389,11 @@ public: ::std::vector< ::HIR::SimplePath> m_traits; // Contains all values and functions (including type constructors) - ::std::unordered_map< ::std::string, ::std::unique_ptr> > m_value_items; + ::std::unordered_map< RcString, ::std::unique_ptr> > m_value_items; // Contains types, traits, and modules - ::std::unordered_map< ::std::string, ::std::unique_ptr> > m_mod_items; + ::std::unordered_map< RcString, ::std::unique_ptr> > m_mod_items; - ::std::vector< ::std::pair<::std::string, Static> > m_inline_statics; + ::std::vector< ::std::pair > m_inline_statics; Module() {} Module(const Module&) = delete; @@ -436,8 +438,8 @@ public: ::HIR::GenericParams m_params; ::HIR::TypeRef m_type; - ::std::map< ::std::string, VisImplEnt< ::HIR::Function> > m_methods; - ::std::map< ::std::string, VisImplEnt< ::HIR::Constant> > m_constants; + ::std::map< RcString, VisImplEnt< ::HIR::Function> > m_methods; + ::std::map< RcString, VisImplEnt< ::HIR::Constant> > m_constants; ::HIR::SimplePath m_src_module; @@ -460,11 +462,11 @@ public: ::HIR::PathParams m_trait_args; ::HIR::TypeRef m_type; - ::std::map< ::std::string, ImplEnt< ::HIR::Function> > m_methods; - ::std::map< ::std::string, ImplEnt< ::HIR::Constant> > m_constants; - ::std::map< ::std::string, ImplEnt< ::HIR::Static> > m_statics; + ::std::map< RcString, ImplEnt< ::HIR::Function> > m_methods; + ::std::map< RcString, ImplEnt< ::HIR::Constant> > m_constants; + ::std::map< RcString, ImplEnt< ::HIR::Static> > m_statics; - ::std::map< ::std::string, ImplEnt< ::HIR::TypeRef> > m_types; + ::std::map< RcString, ImplEnt< ::HIR::TypeRef> > m_types; ::HIR::SimplePath m_src_module; @@ -512,7 +514,7 @@ class ProcMacro { public: // Name of the macro - ::std::string name; + RcString name; // Path to the handler ::HIR::SimplePath path; // A list of attributes to hand to the handler @@ -521,7 +523,7 @@ public: class Crate { public: - ::std::string m_crate_name; + RcString m_crate_name; Module m_root_module; @@ -532,7 +534,7 @@ public: ::std::multimap< ::HIR::SimplePath, ::HIR::MarkerImpl > m_marker_impls; /// Macros exported by this crate - ::std::unordered_map< ::std::string, ::MacroRulesPtr > m_exported_macros; + ::std::unordered_map< RcString, ::MacroRulesPtr > m_exported_macros; /// Procedural macros presented ::std::vector< ::HIR::ProcMacro> m_proc_macros; @@ -540,7 +542,7 @@ public: ::std::unordered_map< ::std::string, ::HIR::SimplePath> m_lang_items; /// Referenced crates - ::std::unordered_map< ::std::string, ExternCrate> m_ext_crates; + ::std::unordered_map< RcString, ExternCrate> m_ext_crates; /// Referenced system libraries ::std::vector m_ext_libs; /// Extra paths for the linker @@ -548,7 +550,7 @@ public: /// Method called to populate runtime state after deserialisation /// See hir/crate_post_load.cpp - void post_load_update(const ::std::string& loaded_name); + void post_load_update(const RcString& loaded_name); const ::HIR::SimplePath& get_lang_item_path(const Span& sp, const char* name) const; const ::HIR::SimplePath& get_lang_item_path_opt(const char* name) const; diff --git a/src/hir/hir_ops.cpp b/src/hir/hir_ops.cpp index 89e48c80..32c70a72 100644 --- a/src/hir/hir_ops.cpp +++ b/src/hir/hir_ops.cpp @@ -825,6 +825,7 @@ bool ::HIR::TraitImpl::overlaps_with(const Crate& crate, const ::HIR::TraitImpl& static Span sp; for(const auto& tb : id.m_params.m_bounds) { + DEBUG(tb); if(tb.is_TraitBound()) { ::HIR::TypeRef tmp_ty; @@ -851,7 +852,7 @@ bool ::HIR::TraitImpl::overlaps_with(const Crate& crate, const ::HIR::TraitImpl& } } else if( TU_TEST1(ty.m_data, Path, .binding.is_Opaque()) ) { - TODO(Span(), "Check bound " << ty << " : " << trait << " in source bounds or trait bounds"); + TODO(sp, "Check bound " << ty << " : " << trait << " in source bounds or trait bounds"); } else { // Search the crate for an impl @@ -889,9 +890,14 @@ bool ::HIR::TraitImpl::overlaps_with(const Crate& crate, const ::HIR::TraitImpl& // 4. Check ATY bounds on the trait path for(const auto& atyb : trait.m_type_bounds) { - const auto& aty = ti.m_types.at(atyb.first); - if( !aty.data.match_test_generics(sp, atyb.second, cb_ident, cb_match) ) - return false; + if( ti.m_types.count(atyb.first) == 0 ) { + DEBUG("Associated type '" << atyb.first << "' not in trait impl, assuming good"); + } + else { + const auto& aty = ti.m_types.at(atyb.first); + if( !aty.data.match_test_generics(sp, atyb.second, cb_ident, cb_match) ) + return false; + } } // All those pass? It's good. return true; diff --git a/src/hir/item_path.hpp b/src/hir/item_path.hpp index d93df9e8..290bf23b 100644 --- a/src/hir/item_path.hpp +++ b/src/hir/item_path.hpp @@ -54,12 +54,12 @@ public: } else if( parent ) { assert(name); - return parent->get_simple_path() + name; + return parent->get_simple_path() + RcString::new_interned(name); } else { assert(!name); assert(crate_name); - return ::HIR::SimplePath(crate_name); + return ::HIR::SimplePath(RcString::new_interned(crate_name)); } } ::HIR::Path get_full_path() const { @@ -76,11 +76,11 @@ public: else if( parent->trait ) { assert(parent->ty); assert(parent->trait_params); - return ::HIR::Path( parent->ty->clone(), ::HIR::GenericPath(parent->trait->clone(), parent->trait_params->clone()), ::std::string(name) ); + return ::HIR::Path( parent->ty->clone(), ::HIR::GenericPath(parent->trait->clone(), parent->trait_params->clone()), RcString::new_interned(name) ); } else { assert(parent->ty); - return ::HIR::Path( parent->ty->clone(), ::std::string(name) ); + return ::HIR::Path( parent->ty->clone(), RcString::new_interned(name) ); } } const char* get_name() const { @@ -95,6 +95,9 @@ public: ItemPath operator+(const ::std::string& name) const { return ItemPath(*this, name.c_str()); } + ItemPath operator+(const RcString& name) const { + return ItemPath(*this, name.c_str()); + } bool operator==(const ::HIR::SimplePath& sp) const { if( sp.m_crate_name != "" ) return false; diff --git a/src/hir/main_bindings.hpp b/src/hir/main_bindings.hpp index 622d8e2e..89896df0 100644 --- a/src/hir/main_bindings.hpp +++ b/src/hir/main_bindings.hpp @@ -18,4 +18,4 @@ namespace AST { extern void HIR_Dump(::std::ostream& sink, const ::HIR::Crate& crate); extern ::HIR::CratePtr LowerHIR_FromAST(::AST::Crate crate); extern void HIR_Serialise(const ::std::string& filename, const ::HIR::Crate& crate); -extern ::HIR::CratePtr HIR_Deserialise(const ::std::string& filename, const ::std::string& loaded_name); +extern ::HIR::CratePtr HIR_Deserialise(const ::std::string& filename); diff --git a/src/hir/path.cpp b/src/hir/path.cpp index e6dab41f..a867c245 100644 --- a/src/hir/path.cpp +++ b/src/hir/path.cpp @@ -8,7 +8,7 @@ #include #include -::HIR::SimplePath HIR::SimplePath::operator+(const ::std::string& s) const +::HIR::SimplePath HIR::SimplePath::operator+(const RcString& s) const { ::HIR::SimplePath ret(m_crate_name); ret.m_components = m_components; @@ -193,11 +193,11 @@ bool ::HIR::TraitPath::operator==(const ::HIR::TraitPath& x) const m_data( ::HIR::Path::Data::make_Generic(::HIR::GenericPath(mv$(sp))) ) { } -::HIR::Path::Path(TypeRef ty, ::std::string item, PathParams item_params): +::HIR::Path::Path(TypeRef ty, RcString item, PathParams item_params): m_data(Data::make_UfcsInherent({ box$(ty), mv$(item), mv$(item_params) })) { } -::HIR::Path::Path(TypeRef ty, GenericPath trait, ::std::string item, PathParams item_params): +::HIR::Path::Path(TypeRef ty, GenericPath trait, RcString item, PathParams item_params): m_data( Data::make_UfcsKnown({ box$(mv$(ty)), mv$(trait), mv$(item), mv$(item_params) }) ) { } diff --git a/src/hir/path.hpp b/src/hir/path.hpp index f2bec6ee..86fe725e 100644 --- a/src/hir/path.hpp +++ b/src/hir/path.hpp @@ -25,7 +25,7 @@ enum Compare { }; typedef ::std::function t_cb_resolve_type; -typedef ::std::function< ::HIR::Compare(unsigned int, const ::std::string&, const ::HIR::TypeRef&) > t_cb_match_generics; +typedef ::std::function< ::HIR::Compare(unsigned int, const RcString&, const ::HIR::TypeRef&) > t_cb_match_generics; static inline ::std::ostream& operator<<(::std::ostream& os, const Compare& x) { switch(x) @@ -54,18 +54,18 @@ static inline Compare& operator &=(Compare& x, const Compare& y) { /// Simple path - Absolute with no generic parameters struct SimplePath { - ::std::string m_crate_name; - ::std::vector< ::std::string> m_components; + RcString m_crate_name; + ::std::vector< RcString> m_components; SimplePath(): m_crate_name("") { } - SimplePath(::std::string crate): + SimplePath(RcString crate): m_crate_name( mv$(crate) ) { } - SimplePath(::std::string crate, ::std::vector< ::std::string> components): + SimplePath(RcString crate, ::std::vector< RcString> components): m_crate_name( mv$(crate) ), m_components( mv$(components) ) { @@ -73,7 +73,7 @@ struct SimplePath SimplePath clone() const; - SimplePath operator+(const ::std::string& s) const; + SimplePath operator+(const RcString& s) const; bool operator==(const SimplePath& x) const { return m_crate_name == x.m_crate_name && m_components == x.m_components; } @@ -158,9 +158,9 @@ class TraitPath { public: GenericPath m_path; - ::std::vector< ::std::string> m_hrls; + ::std::vector< RcString> m_hrls; // TODO: Each bound should list its origin trait - ::std::map< ::std::string, ::HIR::TypeRef> m_type_bounds; + ::std::map< RcString, ::HIR::TypeRef> m_type_bounds; const ::HIR::Trait* m_trait_ptr; @@ -190,20 +190,20 @@ public: (Generic, GenericPath), (UfcsInherent, struct { ::std::unique_ptr type; - ::std::string item; + RcString item; PathParams params; PathParams impl_params; }), (UfcsKnown, struct { ::std::unique_ptr type; GenericPath trait; - ::std::string item; + RcString item; PathParams params; }), (UfcsUnknown, struct { ::std::unique_ptr type; //GenericPath ??; - ::std::string item; + RcString item; PathParams params; }) ); @@ -216,8 +216,8 @@ public: Path(GenericPath _); Path(SimplePath _); - Path(TypeRef ty, ::std::string item, PathParams item_params=PathParams()); - Path(TypeRef ty, GenericPath trait, ::std::string item, PathParams item_params=PathParams()); + Path(TypeRef ty, RcString item, PathParams item_params=PathParams()); + Path(TypeRef ty, GenericPath trait, RcString item, PathParams item_params=PathParams()); Path clone() const; Compare compare_with_placeholders(const Span& sp, const Path& x, t_cb_resolve_type resolve_placeholder) const; diff --git a/src/hir/pattern.cpp b/src/hir/pattern.cpp index d25b25e7..063ed1b3 100644 --- a/src/hir/pattern.cpp +++ b/src/hir/pattern.cpp @@ -154,8 +154,9 @@ namespace { rv.push_back( pat.clone() ); return rv; } - ::std::vector< ::std::pair< ::std::string, ::HIR::Pattern> > clone_pat_fields(const ::std::vector< ::std::pair< ::std::string, ::HIR::Pattern> >& pats) { - ::std::vector< ::std::pair< ::std::string, ::HIR::Pattern> > rv; + typedef ::std::vector< ::std::pair< RcString, ::HIR::Pattern> > pat_fields_t; + pat_fields_t clone_pat_fields(const pat_fields_t& pats) { + pat_fields_t rv; rv.reserve( pats.size() ); for(const auto& field : pats) rv.push_back( ::std::make_pair(field.first, field.second.clone()) ); diff --git a/src/hir/pattern.hpp b/src/hir/pattern.hpp index d16fd942..136bd587 100644 --- a/src/hir/pattern.hpp +++ b/src/hir/pattern.hpp @@ -29,7 +29,7 @@ struct PatternBinding bool m_mutable; Type m_type; - ::std::string m_name; + RcString m_name; unsigned int m_slot; unsigned m_implicit_deref_count = 0; @@ -43,7 +43,7 @@ struct PatternBinding m_slot(0), m_implicit_deref_count(0) {} - PatternBinding(bool mut, Type type, ::std::string name, unsigned int slot): + PatternBinding(bool mut, Type type, RcString name, unsigned int slot): m_mutable(mut), m_type(type), m_name( mv$(name) ), @@ -104,7 +104,7 @@ struct Pattern (Struct, struct { GenericPath path; const Struct* binding; - ::std::vector< ::std::pair< ::std::string, Pattern> > sub_patterns; + ::std::vector< ::std::pair > sub_patterns; bool is_exhaustive; bool is_wildcard() const { @@ -129,7 +129,7 @@ struct Pattern GenericPath path; const Enum* binding_ptr; unsigned binding_idx; - ::std::vector< ::std::pair< ::std::string, Pattern> > sub_patterns; + ::std::vector< ::std::pair > sub_patterns; bool is_exhaustive; } ), (Slice, struct { diff --git a/src/hir/serialise.cpp b/src/hir/serialise.cpp index 2c72c801..c15630d9 100644 --- a/src/hir/serialise.cpp +++ b/src/hir/serialise.cpp @@ -20,6 +20,15 @@ m_out( out ) {} + template + void serialise_strmap(const ::std::map& map) + { + m_out.write_count(map.size()); + for(const auto& v : map) { + m_out.write_string(v.first); + serialise(v.second); + } + } template void serialise_strmap(const ::std::map< ::std::string,V>& map) { @@ -30,6 +39,16 @@ } } template + void serialise_strmap(const ::std::unordered_map& map) + { + m_out.write_count(map.size()); + for(const auto& v : map) { + DEBUG("- " << v.first); + m_out.write_string(v.first); + serialise(v.second); + } + } + template void serialise_strmap(const ::std::unordered_map< ::std::string,V>& map) { m_out.write_count(map.size()); @@ -40,6 +59,16 @@ } } template + void serialise_strmap(const ::std::unordered_multimap& map) + { + m_out.write_count(map.size()); + for(const auto& v : map) { + DEBUG("- " << v.first); + m_out.write_string(v.first); + serialise(v.second); + } + } + template void serialise_strmap(const ::std::unordered_multimap< ::std::string,V>& map) { m_out.write_count(map.size()); @@ -73,6 +102,11 @@ serialise(e.second); } template + void serialise(const ::std::pair< RcString, T>& e) { + m_out.write_string(e.first); + serialise(e.second); + } + template void serialise(const ::std::pair& e) { m_out.write_count(e.first); serialise(e.second); @@ -86,6 +120,10 @@ void serialise(uint64_t v) { m_out.write_u64c(v); }; void serialise(int64_t v) { m_out.write_i64c(v); }; + void serialise(const ::HIR::LifetimeDef& ld) + { + m_out.write_string(ld.m_name); + } void serialise(const ::HIR::LifetimeRef& lr) { m_out.write_count(lr.binding); @@ -392,6 +430,9 @@ void serialise(const ::std::string& v) { m_out.write_string(v); } + void serialise(const RcString& v) { + m_out.write_string(v); + } void serialise(const ::MacroRulesPtr& mac) { @@ -488,6 +529,9 @@ TU_ARM(td, String, e) { m_out.write_string(e); } break; + TU_ARM(td, IString, e) { + m_out.write_string(e); + } break; TU_ARM(td, Integer, e) { m_out.write_tag(e.m_datatype); m_out.write_u64c(e.m_intval); @@ -1041,6 +1085,7 @@ serialise_strmap( item.m_value_indexes ); serialise_strmap( item.m_type_indexes ); serialise_vec( item.m_all_parent_traits ); + serialise( item.m_vtable_path ); } void serialise(const ::HIR::TraitValueItem& tvi) { @@ -1063,7 +1108,7 @@ void serialise(const ::HIR::AssociatedType& at) { m_out.write_bool(at.is_sized); - //m_out.write_string(at.m_lifetime_bound); // TODO: better type for lifetime + serialise(at.m_lifetime_bound); serialise_vec(at.m_trait_bounds); serialise_type(at.m_default); } @@ -1072,8 +1117,10 @@ void HIR_Serialise(const ::std::string& filename, const ::HIR::Crate& crate) { - ::HIR::serialise::Writer out { filename }; + ::HIR::serialise::Writer out; HirSerialiser s { out }; s.serialise_crate(crate); + out.open(filename); + s.serialise_crate(crate); } diff --git a/src/hir/serialise_lowlevel.cpp b/src/hir/serialise_lowlevel.cpp index e69ff848..5c4b0df2 100644 --- a/src/hir/serialise_lowlevel.cpp +++ b/src/hir/serialise_lowlevel.cpp @@ -11,6 +11,7 @@ #include #include // memcpy #include +#include namespace HIR { namespace serialise { @@ -29,17 +30,58 @@ public: void write(const void* buf, size_t len); }; -Writer::Writer(const ::std::string& filename): - m_inner( new WriterInner(filename) ) +Writer::Writer(): + m_inner(nullptr) { } Writer::~Writer() { delete m_inner, m_inner = nullptr; } +void Writer::open(const ::std::string& filename) +{ + // 1. Sort strings by frequency + ::std::vector<::std::pair> sorted; + sorted.reserve(m_istring_cache.size()); + for(const auto& e : m_istring_cache) + sorted.push_back( e ); + // 2. Write out string table + ::std::sort(sorted.begin(), sorted.end(), [](const auto& a, const auto& b){ return a.second > b.second; }); + + m_inner = new WriterInner(filename); + // 3. Reset m_istring_cache to use the same value + this->write_count(sorted.size()); + for(size_t i = 0; i < sorted.size(); i ++) + { + const auto& s = sorted[i].first; + this->write_string(s.size(), s.c_str()); + DEBUG(i << " = " << m_istring_cache[s] << " '" << s << "'"); + m_istring_cache[s] = i; + } + for(const auto& e : m_istring_cache) + { + assert(e.second < sorted.size()); + } +} void Writer::write(const void* buf, size_t len) { - m_inner->write(buf, len); + if( m_inner ) { + m_inner->write(buf, len); + } + else { + // No-op, pre caching + } +} +void Writer::write_string(const RcString& v) +{ + if( m_inner ) { + // Emit ID from the cache + this->write_count( m_istring_cache.at(v) ); + } + else { + // Find/add in cache + m_istring_cache.insert(::std::make_pair(v, 0)).first->second += 1; + } } @@ -189,6 +231,14 @@ Reader::Reader(const ::std::string& filename): m_buffer(1024), m_pos(0) { + size_t n_strings = read_count(); + m_strings.reserve(n_strings); + DEBUG("n_strings = " << n_strings); + for(size_t i = 0; i < n_strings; i ++) + { + auto s = read_string(); + m_strings.push_back( RcString::new_interned(s) ); + } } Reader::~Reader() { diff --git a/src/hir/serialise_lowlevel.hpp b/src/hir/serialise_lowlevel.hpp index a35b8e98..b3633d54 100644 --- a/src/hir/serialise_lowlevel.hpp +++ b/src/hir/serialise_lowlevel.hpp @@ -9,8 +9,10 @@ #include #include +#include #include #include +#include namespace HIR { namespace serialise { @@ -21,12 +23,14 @@ class ReaderInner; class Writer { WriterInner* m_inner; + ::std::map m_istring_cache; public: - Writer(const ::std::string& path); + Writer(); Writer(const Writer&) = delete; Writer(Writer&&) = delete; ~Writer(); + void open(const ::std::string& filename); void write(const void* data, size_t count); void write_u8(uint8_t v) { @@ -114,16 +118,20 @@ public: write_u16( static_cast(c) ); } } - void write_string(const ::std::string& v) { - if(v.size() < 128) { - write_u8( static_cast(v.size()) ); + void write_string(const RcString& v); + void write_string(size_t len, const char* s) { + if(len < 128) { + write_u8( static_cast(len) ); } else { - assert(v.size() < (1u<<(16+7))); - write_u8( static_cast(128 + (v.size() >> 16)) ); - write_u16( static_cast(v.size() & 0xFFFF) ); + assert(len < (1u<<(16+7))); + write_u8( static_cast(128 + (len >> 16)) ); + write_u16( static_cast(len & 0xFFFF) ); } - this->write(v.data(), v.size()); + this->write(s, len); + } + void write_string(const ::std::string& v) { + write_string(v.size(), v.c_str()); } void write_bool(bool v) { write_u8(v ? 0xFF : 0x00); @@ -148,6 +156,7 @@ class Reader ReaderInner* m_inner; ReadBuffer m_buffer; size_t m_pos; + ::std::vector m_strings; public: Reader(const ::std::string& path); Reader(const Writer&) = delete; @@ -251,6 +260,10 @@ public: return ~0u; } } + RcString read_istring() { + size_t idx = read_count(); + return m_strings.at(idx); + } ::std::string read_string() { size_t len = read_u8(); if( len < 128 ) { diff --git a/src/hir/type.hpp b/src/hir/type.hpp index 2fc1179d..38196a55 100644 --- a/src/hir/type.hpp +++ b/src/hir/type.hpp @@ -88,6 +88,7 @@ struct LifetimeRef static const uint32_t UNKNOWN = 0; static const uint32_t STATIC = 0xFFFF; + //RcString name; // Values below 2^16 are parameters/static, values above are per-function region IDs allocated during region inferrence. uint32_t binding = UNKNOWN; @@ -97,6 +98,9 @@ struct LifetimeRef return rv; } + Ordering ord(const LifetimeRef& x) const { + return ::ord(binding, x.binding); + } bool operator==(const LifetimeRef& x) const { return binding == x.binding; } @@ -191,7 +195,7 @@ public: TypePathBinding binding; }), (Generic, struct { - ::std::string name; + RcString name; // 0xFFFF = Self, 0-255 = Type/Trait, 256-511 = Method, 512-767 = Placeholder unsigned int binding; @@ -254,7 +258,7 @@ public: TypeRef(::std::vector< ::HIR::TypeRef> sts): m_data( Data::make_Tuple(mv$(sts)) ) {} - TypeRef(::std::string name, unsigned int slot): + TypeRef(RcString name, unsigned int slot): m_data( Data::make_Generic({ mv$(name), slot }) ) {} TypeRef(::HIR::TypeRef::Data x): diff --git a/src/hir_conv/constant_evaluation.cpp b/src/hir_conv/constant_evaluation.cpp index 22909cdc..b97a6ae0 100644 --- a/src/hir_conv/constant_evaluation.cpp +++ b/src/hir_conv/constant_evaluation.cpp @@ -40,7 +40,7 @@ namespace { virtual ::HIR::Path new_static(::HIR::TypeRef type, ::HIR::Literal value) override { - auto name = FMT(name_prefix << next_item_idx); + auto name = RcString::new_interned(FMT(name_prefix << next_item_idx)); next_item_idx ++; DEBUG("mod_path = " << mod_path); auto rv = mod_path.get_simple_path() + name.c_str(); diff --git a/src/hir_expand/closures.cpp b/src/hir_expand/closures.cpp index ace154ff..94f272f8 100644 --- a/src/hir_expand/closures.cpp +++ b/src/hir_expand/closures.cpp @@ -147,7 +147,7 @@ namespace { { m_replacement = NEWNODE(node.m_res_type.clone(), Field, node.span(), get_self(node.span()), - FMT(binding_it - m_captures.begin()) + RcString::new_interned(FMT(binding_it - m_captures.begin())) ); if( binding_it->second != ::HIR::ValueUsage::Move ) { auto bt = (binding_it->second == ::HIR::ValueUsage::Mutate ? ::HIR::BorrowType::Unique : ::HIR::BorrowType::Shared); @@ -355,7 +355,7 @@ namespace { return ::HIR::TraitImpl { mv$(params), {}, mv$(closure_type), make_map1( - ::std::string("call_free"), ::HIR::TraitImpl::ImplEnt< ::HIR::Function> { false, ::HIR::Function { + RcString::new_interned("call_free"), ::HIR::TraitImpl::ImplEnt< ::HIR::Function> { false, ::HIR::Function { false, ::HIR::Linkage {}, ::HIR::Function::Receiver::Free, ABI_RUST, false, false, @@ -385,7 +385,7 @@ namespace { return ::HIR::TraitImpl { mv$(params), mv$(trait_params), mv$(closure_type), make_map1( - ::std::string("call_once"), ::HIR::TraitImpl::ImplEnt< ::HIR::Function> { false, ::HIR::Function { + RcString::new_interned("call_once"), ::HIR::TraitImpl::ImplEnt< ::HIR::Function> { false, ::HIR::Function { false, ::HIR::Linkage {}, ::HIR::Function::Receiver::Value, ABI_RUST, false, false, @@ -404,7 +404,7 @@ namespace { {}, {}, make_map1( - ::std::string("Output"), ::HIR::TraitImpl::ImplEnt< ::HIR::TypeRef> { false, mv$(ret_ty) } + RcString::new_interned("Output"), ::HIR::TraitImpl::ImplEnt< ::HIR::TypeRef> { false, mv$(ret_ty) } ), ::HIR::SimplePath() }; @@ -423,7 +423,7 @@ namespace { return ::HIR::TraitImpl { mv$(params), mv$(trait_params), mv$(closure_type), make_map1( - ::std::string("call_mut"), ::HIR::TraitImpl::ImplEnt< ::HIR::Function> { false, ::HIR::Function { + RcString::new_interned("call_mut"), ::HIR::TraitImpl::ImplEnt< ::HIR::Function> { false, ::HIR::Function { false, ::HIR::Linkage {}, ::HIR::Function::Receiver::BorrowUnique, ABI_RUST, false, false, @@ -459,7 +459,7 @@ namespace { return ::HIR::TraitImpl { mv$(params), mv$(trait_params), mv$(closure_type), make_map1( - ::std::string("call"), ::HIR::TraitImpl::ImplEnt< ::HIR::Function> { false, ::HIR::Function { + RcString::new_interned("call"), ::HIR::TraitImpl::ImplEnt< ::HIR::Function> { false, ::HIR::Function { false, ::HIR::Linkage {}, ::HIR::Function::Receiver::BorrowShared, ABI_RUST, false, false, @@ -801,11 +801,11 @@ namespace { for(size_t i = 0; i < args_tup_inner.size(); i ++) { const auto& ty = args_tup_inner[i]; - dispatch_args.push_back( NEWNODE(ty.clone(), Field, sp, NEWNODE(args_ty.clone(), Variable, sp, "arg", 1), FMT(i)) ); + dispatch_args.push_back( NEWNODE(ty.clone(), Field, sp, NEWNODE(args_ty.clone(), Variable, sp, RcString::new_interned("arg"), 1), RcString::new_interned(FMT(i))) ); dispatch_node_args_cache.push_back( ty.clone() ); } dispatch_node_args_cache.push_back( ret_type.clone() ); - auto path = ::HIR::Path(closure_type.clone(), "call_free"); + auto path = ::HIR::Path(closure_type.clone(), RcString::new_interned("call_free")); path.m_data.as_UfcsInherent().impl_params = closure_type.m_data.as_Path().path.m_data.as_Generic().m_params.clone(); HIR::ExprNodeP dispatch_node = NEWNODE(ret_type.clone(), CallPath, sp, mv$(path), @@ -814,7 +814,7 @@ namespace { dynamic_cast<::HIR::ExprNode_CallPath&>(*dispatch_node).m_cache.m_arg_types = mv$(dispatch_node_args_cache); auto args_arg = ::std::make_pair( - ::HIR::Pattern { {false, ::HIR::PatternBinding::Type::Move, "args", 1}, {} }, + ::HIR::Pattern { {false, ::HIR::PatternBinding::Type::Move, RcString::new_interned("args"), 1}, {} }, args_ty.clone() ); HIR::TraitImpl fcn; @@ -863,9 +863,9 @@ namespace { // - FnOnce { auto dispatch_node = NEWNODE(ret_type.clone(), CallPath, sp, - ::HIR::Path(closure_type.clone(), ::HIR::GenericPath(lang_Fn, trait_params.clone()), "call"), + ::HIR::Path(closure_type.clone(), ::HIR::GenericPath(lang_Fn, trait_params.clone()), RcString::new_interned("call")), make_vec2( - NEWNODE(method_self_ty.clone(), Borrow, sp, ::HIR::BorrowType::Shared, NEWNODE(closure_type.clone(), Variable, sp, "self", 0)), + NEWNODE(method_self_ty.clone(), Borrow, sp, ::HIR::BorrowType::Shared, NEWNODE(closure_type.clone(), Variable, sp, RcString::new_interned("self"), 0)), NEWNODE(args_ty.clone(), Variable, sp, "arg", 1) ) ); @@ -1181,7 +1181,7 @@ namespace { ::HIR::SimplePath root_mod_path(crate.m_crate_name,{}); m_cur_mod_path = &root_mod_path; m_new_type = [&](auto s)->auto { - auto name = FMT("closure#I_" << closure_count); + auto name = RcString::new_interned(FMT("closure#I_" << closure_count)); closure_count += 1; auto boxed = box$(( ::HIR::VisEnt< ::HIR::TypeItem> { ::HIR::Publicity::new_none(), ::HIR::TypeItem( mv$(s) ) } )); crate.m_root_module.m_mod_items.insert( ::std::make_pair(name, mv$(boxed)) ); @@ -1374,7 +1374,7 @@ void HIR_Expand_Closures_Expr(const ::HIR::Crate& crate_ro, ::HIR::ExprPtr& exp) static int closure_count = 0; out_impls_t new_trait_impls; new_type_cb_t new_type_cb = [&](auto s)->::HIR::SimplePath { - auto name = FMT("closure#C_" << closure_count); + auto name = RcString::new_interned(FMT("closure#C_" << closure_count)); closure_count += 1; auto boxed = box$(( ::HIR::VisEnt< ::HIR::TypeItem> { ::HIR::Publicity::new_none(), ::HIR::TypeItem( mv$(s) ) } )); crate.m_root_module.m_mod_items.insert( ::std::make_pair(name, mv$(boxed)) ); diff --git a/src/hir_expand/vtable.cpp b/src/hir_expand/vtable.cpp index 2b3dcfb4..cd7b3413 100644 --- a/src/hir_expand/vtable.cpp +++ b/src/hir_expand/vtable.cpp @@ -17,7 +17,7 @@ namespace { { const ::HIR::Crate& m_crate; //StaticTraitResolve m_resolve; - ::std::function<::HIR::SimplePath(bool, ::std::string, ::HIR::Struct)> m_new_type; + ::std::function<::HIR::SimplePath(bool, RcString, ::HIR::Struct)> m_new_type; ::HIR::SimplePath m_lang_Sized; public: OuterVisitor(const ::HIR::Crate& crate): @@ -72,7 +72,7 @@ namespace { //TODO(Span(), "Handle conflicting associated types - '" << ty.first << "'"); } else { - params.m_types.push_back( ::HIR::TypeParamDef { "a#"+ty.first, {}, ty.second.is_sized } ); + params.m_types.push_back( ::HIR::TypeParamDef { RcString::new_interned(FMT("a#" << ty.first)), {}, ty.second.is_sized } ); } i ++; } @@ -98,14 +98,14 @@ namespace { auto clone_cb = [&](const auto& t, auto& o) { if(t.m_data.is_Path() && t.m_data.as_Path().path.m_data.is_UfcsKnown()) { const auto& pe = t.m_data.as_Path().path.m_data.as_UfcsKnown(); - bool is_self = (*pe.type == ::HIR::TypeRef("Self", 0xFFFF)); + bool is_self = (*pe.type == ::HIR::TypeRef(RcString::new_interned("Self"), 0xFFFF)); auto it = trait_ptr->m_type_indexes.find(pe.item); bool has_item = (it != trait_ptr->m_type_indexes.end()); // TODO: Check the trait against m_type_indexes if( is_self /*&& pe.trait == trait_path*/ && has_item ) { DEBUG("[clone_cb] t=" << t << " -> " << it->second); // Replace with a new type param, need to know the index of it - o = ::HIR::TypeRef("a#"+pe.item, it->second); + o = ::HIR::TypeRef( RcString::new_interned(FMT("a#" << pe.item)), it->second); return true; } else { @@ -231,12 +231,13 @@ namespace { } } // TODO: Would like to have access to the publicity marker - auto item_path = m_new_type(true, FMT(p.get_name() << "#vtable"), ::HIR::Struct { + auto item_path = m_new_type(true, RcString::new_interned(FMT(p.get_name() << "#vtable")), ::HIR::Struct { mv$(args), ::HIR::Struct::Repr::Rust, ::HIR::Struct::Data(mv$(fields)), {} }); + tr.m_vtable_path = item_path; DEBUG("Vtable structure created - " << item_path); ::HIR::GenericPath path( mv$(item_path), mv$(params) ); diff --git a/src/hir_typeck/expr_check.cpp b/src/hir_typeck/expr_check.cpp index 0d3bc8ab..aa26ae1f 100644 --- a/src/hir_typeck/expr_check.cpp +++ b/src/hir_typeck/expr_check.cpp @@ -832,7 +832,7 @@ namespace { // TODO: Either - Don't include the above impl bound, or change the below trait to the one that has that type for( const auto& assoc : be.trait.m_type_bounds ) { ::HIR::GenericPath type_trait_path; - bool has_ty = m_resolve.trait_contains_type(sp, real_trait, *be.trait.m_trait_ptr, assoc.first, type_trait_path); + bool has_ty = m_resolve.trait_contains_type(sp, real_trait, *be.trait.m_trait_ptr, assoc.first.c_str(), type_trait_path); ASSERT_BUG(sp, has_ty, "Type " << assoc.first << " not found in chain of " << real_trait); auto other_ty = monomorphise_type_with(sp, assoc.second, cache.m_monomorph_cb, true); @@ -934,7 +934,7 @@ namespace { const auto& sp = node.span(); const auto& str_ty = node.m_value->m_res_type; - bool is_index = ( '0' <= node.m_field[0] && node.m_field[0] <= '9' ); + bool is_index = ( '0' <= node.m_field.c_str()[0] && node.m_field.c_str()[0] <= '9' ); if( str_ty.m_data.is_Tuple() ) { ASSERT_BUG(sp, is_index, "Non-index _Field on tuple"); diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index cda8edd0..ecaae208 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -53,7 +53,7 @@ struct Context struct Binding { - ::std::string name; + RcString name; ::HIR::TypeRef ty; //unsigned int ivar; }; @@ -79,7 +79,7 @@ struct Context ::HIR::SimplePath trait; ::HIR::PathParams params; ::HIR::TypeRef impl_ty; - ::std::string name; // if "", no type is used (and left is ignored) - Just does trait selection + RcString name; // if "", no type is used (and left is ignored) - Just does trait selection // HACK: operators are special - the result when both types are primitives is ALWAYS the lefthand side bool is_operator; @@ -252,7 +252,7 @@ struct Context void handle_pattern_direct_inner(const Span& sp, ::HIR::Pattern& pat, const ::HIR::TypeRef& type); void add_binding_inner(const Span& sp, const ::HIR::PatternBinding& pb, ::HIR::TypeRef type); - void add_var(const Span& sp, unsigned int index, const ::std::string& name, ::HIR::TypeRef type); + void add_var(const Span& sp, unsigned int index, const RcString& name, ::HIR::TypeRef type); const ::HIR::TypeRef& get_var(const Span& sp, unsigned int idx) const; // - Add a revisit entry @@ -304,7 +304,7 @@ namespace { ::HIR::GenericPath type_trait_path; ASSERT_BUG(sp, be.trait.m_trait_ptr, "Trait pointer not set in " << be.trait.m_path); // TODO: Store the source trait for this bound in the the bound list? - if( !context.m_resolve.trait_contains_type(sp, real_trait, *be.trait.m_trait_ptr, assoc.first, type_trait_path) ) + if( !context.m_resolve.trait_contains_type(sp, real_trait, *be.trait.m_trait_ptr, assoc.first.c_str(), type_trait_path) ) BUG(sp, "Couldn't find associated type " << assoc.first << " in trait " << real_trait); auto other_ty = monomorphise_type_with(sp, assoc.second, monomorph_cb, true); @@ -1480,7 +1480,7 @@ namespace { } // - Search in-scope trait list for traits that provide a method of this name - const ::std::string& method_name = node.m_method; + const RcString& method_name = node.m_method; ::HIR::t_trait_list possible_traits; unsigned int max_num_params = 0; for(const auto& trait_ref : ::reverse(m_traits)) @@ -2772,7 +2772,7 @@ namespace { // - If running in a mode after stablise (before defaults), fall // back to trait if the inherent is still ambigious. ::std::vector<::std::pair> possible_methods; - unsigned int deref_count = this->context.m_resolve.autoderef_find_method(node.span(), node.m_traits, node.m_trait_param_ivars, ty, node.m_method, possible_methods); + unsigned int deref_count = this->context.m_resolve.autoderef_find_method(node.span(), node.m_traits, node.m_trait_param_ivars, ty, node.m_method.c_str(), possible_methods); try_again: if( deref_count != ~0u ) { @@ -3003,6 +3003,7 @@ namespace { const auto* current_ty = &node.m_value->m_res_type; ::std::vector< ::HIR::TypeRef> deref_res_types; + // TODO: autoderef_find_field? do { const auto& ty = this->context.m_ivars.get_type(*current_ty); if( ty.m_data.is_Infer() ) { @@ -3013,7 +3014,7 @@ namespace { DEBUG("Hit unbound path, returning early"); return ; } - if( this->context.m_resolve.find_field(node.span(), ty, field_name, out_type) ) { + if( this->context.m_resolve.find_field(node.span(), ty, field_name.c_str(), out_type) ) { this->context.equate_types(node.span(), node.m_res_type, out_type); break; } @@ -5439,7 +5440,7 @@ void Context::possible_equate_type_disable_strong(const Span& sp, unsigned int i ent.force_disable = true; } -void Context::add_var(const Span& sp, unsigned int index, const ::std::string& name, ::HIR::TypeRef type) { +void Context::add_var(const Span& sp, unsigned int index, const RcString& name, ::HIR::TypeRef type) { DEBUG("(" << index << " " << name << " : " << type << ")"); assert(index != ~0u); if( m_bindings.size() <= index ) @@ -6923,7 +6924,7 @@ namespace { DEBUG("Check <" << t << ">::" << node.m_method); ::std::vector<::std::pair> possible_methods; - unsigned int deref_count = context.m_resolve.autoderef_find_method(node.span(), node.m_traits, node.m_trait_param_ivars, t, node.m_method, possible_methods); + unsigned int deref_count = context.m_resolve.autoderef_find_method(node.span(), node.m_traits, node.m_trait_param_ivars, t, node.m_method.c_str(), possible_methods); DEBUG("> deref_count = " << deref_count << ", " << possible_methods); if( !t.m_data.is_Infer() && possible_methods.empty() ) { diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index 0ebb9c07..629b8bba 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -960,7 +960,7 @@ void TraitResolution::prep_indexes() // Locate the source trait ::HIR::GenericPath source_trait_path; - bool rv = this->trait_contains_type(sp, be.trait.m_path, m_crate.get_trait_by_path(sp, be.trait.m_path.m_path), tb.first, source_trait_path); + bool rv = this->trait_contains_type(sp, be.trait.m_path, m_crate.get_trait_by_path(sp, be.trait.m_path.m_path), tb.first.c_str(), source_trait_path); ASSERT_BUG(sp, rv, "Can't find `" << tb.first << "` in " << be.trait.m_path); auto ty_l = ::HIR::TypeRef( ::HIR::Path( be.type.clone(), mv$(source_trait_path), tb.first ) ); @@ -1005,7 +1005,7 @@ void TraitResolution::prep_indexes() // Find the source trait for this associated type ::HIR::GenericPath source_trait_path; - bool rv = this->trait_contains_type(sp, trait_mono.m_path, itrait, tb.first, source_trait_path); + bool rv = this->trait_contains_type(sp, trait_mono.m_path, itrait, tb.first.c_str(), source_trait_path); ASSERT_BUG(sp, rv, "Can't find `" << tb.first << "` in " << trait_mono.m_path); auto ty_l = ::HIR::TypeRef( ::HIR::Path( ty_a.clone(), mv$(source_trait_path), tb.first ) ); @@ -1091,7 +1091,7 @@ bool TraitResolution::iterate_aty_bounds(const Span& sp, const ::HIR::Path::Data { ::HIR::GenericPath trait_path; DEBUG("Checking ATY bounds on " << pe.trait << " :: " << pe.item); - if( !this->trait_contains_type(sp, pe.trait, this->m_crate.get_trait_by_path(sp, pe.trait.m_path), pe.item, trait_path) ) + if( !this->trait_contains_type(sp, pe.trait, this->m_crate.get_trait_by_path(sp, pe.trait.m_path), pe.item.c_str(), trait_path) ) BUG(sp, "Cannot find associated type " << pe.item << " anywhere in trait " << pe.trait); DEBUG("trait_path=" << trait_path); const auto& trait_ref = m_crate.get_trait_by_path(sp, trait_path.m_path); @@ -1133,7 +1133,7 @@ bool TraitResolution::find_trait_impls_magic(const Span& sp, ) const { static ::HIR::PathParams null_params; - static ::std::map< ::std::string, ::HIR::TypeRef> null_assoc; + static ::std::map null_assoc; const auto& lang_Sized = this->m_crate.get_lang_item_path(sp, "sized"); const auto& lang_Copy = this->m_crate.get_lang_item_path(sp, "copy"); @@ -1235,7 +1235,7 @@ bool TraitResolution::find_trait_impls(const Span& sp, ) const { static ::HIR::PathParams null_params; - static ::std::map< ::std::string, ::HIR::TypeRef> null_assoc; + static ::std::map null_assoc; const auto& type = this->m_ivars.get_type(ty); TRACE_FUNCTION_F("trait = " << trait << params << ", type = " << type); @@ -1295,7 +1295,7 @@ bool TraitResolution::find_trait_impls(const Span& sp, ::HIR::PathParams pp; pp.m_types.push_back( ::HIR::TypeRef(mv$(args)) ); - ::std::map< ::std::string, ::HIR::TypeRef> types; + ::std::map types; types.insert( ::std::make_pair( "Output", e.m_rettype->clone() ) ); return callback( ImplRef(type.clone(), mv$(pp), mv$(types)), cmp ); } @@ -1337,7 +1337,7 @@ bool TraitResolution::find_trait_impls(const Span& sp, ::HIR::PathParams pp; pp.m_types.push_back( ::HIR::TypeRef(mv$(args)) ); - ::std::map< ::std::string, ::HIR::TypeRef> types; + ::std::map types; types.insert( ::std::make_pair( "Output", e.m_rettype->clone() ) ); return callback( ImplRef(type.clone(), mv$(pp), mv$(types)), cmp ); } @@ -1362,7 +1362,7 @@ bool TraitResolution::find_trait_impls(const Span& sp, { ::HIR::PathParams pp; pp.m_types.push_back( mv$(ty_usize) ); - ::std::map< ::std::string, ::HIR::TypeRef> types; + ::std::map types; types.insert( ::std::make_pair( "Output", e.inner->clone() ) ); return callback( ImplRef(type.clone(), mv$(pp), mv$(types)), cmp ); } @@ -1402,8 +1402,7 @@ bool TraitResolution::find_trait_impls(const Span& sp, if( trait == mt.m_path ) { auto cmp = compare_pp(sp, mt.m_params, params); if( cmp != ::HIR::Compare::Unequal ) { - static ::std::map< ::std::string, ::HIR::TypeRef> types; - return callback( ImplRef(&type, &mt.m_params, &types), cmp ); + return callback( ImplRef(&type, &mt.m_params, &null_assoc), cmp ); } } } @@ -1417,7 +1416,7 @@ bool TraitResolution::find_trait_impls(const Span& sp, auto cmp = this->compare_pp(sp, i_params, params); if( cmp != ::HIR::Compare::Unequal ) { // Invoke callback with a proper ImplRef - ::std::map< ::std::string, ::HIR::TypeRef> assoc_clone; + ::std::map assoc_clone; for(const auto& e : i_assoc) assoc_clone.insert( ::std::make_pair(e.first, e.second.clone()) ); auto ir = ImplRef(i_ty.clone(), i_params.clone(), mv$(assoc_clone)); @@ -1454,7 +1453,7 @@ bool TraitResolution::find_trait_impls(const Span& sp, auto cmp = this->compare_pp(sp, i_params, params); if( cmp != ::HIR::Compare::Unequal ) { // Invoke callback with a proper ImplRef - ::std::map< ::std::string, ::HIR::TypeRef> assoc_clone; + ::std::map assoc_clone; for(const auto& e : i_assoc) assoc_clone.insert( ::std::make_pair(e.first, e.second.clone()) ); auto ir = ImplRef(i_ty.clone(), i_params.clone(), mv$(assoc_clone)); @@ -1498,7 +1497,7 @@ bool TraitResolution::find_trait_impls(const Span& sp, ::HIR::PathParams params_mono_o; const auto& b_params_mono = (monomorphise_pathparams_needed(b_params) ? params_mono_o = monomorphise_path_params_with(sp, b_params, monomorph_cb, false) : b_params); // TODO: Monormophise and EAT associated types - ::std::map< ::std::string, ::HIR::TypeRef> b_atys; + ::std::map b_atys; for(const auto& aty : bound.m_type_bounds) b_atys.insert(::std::make_pair( aty.first, monomorphise_type_with(sp, aty.second, monomorph_cb) )); @@ -2080,7 +2079,7 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp, // - Does simplification of complex associated types // ::HIR::GenericPath trait_path; - if( !this->trait_contains_type(sp, pe_inner.trait, this->m_crate.get_trait_by_path(sp, pe_inner.trait.m_path), pe_inner.item, trait_path) ) + if( !this->trait_contains_type(sp, pe_inner.trait, this->m_crate.get_trait_by_path(sp, pe_inner.trait.m_path), pe_inner.item.c_str(), trait_path) ) BUG(sp, "Cannot find associated type " << pe_inner.item << " anywhere in trait " << pe_inner.trait); const auto& trait_ptr = this->m_crate.get_trait_by_path(sp, trait_path.m_path); const auto& assoc_ty = trait_ptr.m_types.at(pe_inner.item); @@ -2150,7 +2149,7 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp, // TODO: Search for the actual trait containing this associated type ::HIR::GenericPath trait_path; //if( !this->trait_contains_type(sp, pe.trait, this->m_crate.get_trait_by_path(sp, pe.trait.m_path), *pe.type, pe.item, trait_path) ) - if( !this->trait_contains_type(sp, pe.trait, this->m_crate.get_trait_by_path(sp, pe.trait.m_path), pe.item, trait_path) ) + if( !this->trait_contains_type(sp, pe.trait, this->m_crate.get_trait_by_path(sp, pe.trait.m_path), pe.item.c_str(), trait_path) ) BUG(sp, "Cannot find associated type " << pe.item << " anywhere in trait " << pe.trait); //pe.trait = mv$(trait_path); @@ -2350,7 +2349,7 @@ bool TraitResolution::find_trait_impls_bound(const Span& sp, const ::HIR::Simple type, [&](const auto& ty, const auto& b_params, const auto& assoc) { // TODO: Avoid duplicating this map every time - ::std::map< ::std::string,::HIR::TypeRef> assoc2; + ::std::map< RcString,::HIR::TypeRef> assoc2; for(const auto& i : assoc) { assoc2.insert( ::std::make_pair(i.first, i.second.clone()) ); } @@ -2447,7 +2446,7 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, { // TODO: Have a global cache of impls that don't reference either generics or ivars - static ::std::map< ::std::string, ::HIR::TypeRef> null_assoc; + static ::std::map null_assoc; TRACE_FUNCTION_F(trait << FMT_CB(ss, if(params_ptr) { ss << *params_ptr; } else { ss << ""; }) << " for " << type); // Handle auto traits (aka OIBITs) @@ -2832,7 +2831,7 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, // TODO: Some impl blocks have type params used as part of type bounds. // - A rough idea is to have monomorph return a third class of generic for params that are not yet bound. // - compare_with_placeholders gets called on both ivars and generics, so that can be used to replace it once known. - ::std::string placeholder_name = FMT("impl_?_" << &impl_params); + auto placeholder_name = RcString::new_interned(FMT("impl_?_" << &impl_params)); for(unsigned int i = 0; i < impl_params.size(); i ++ ) { if( !impl_params[i] ) { if( placeholders.size() == 0 ) @@ -3061,7 +3060,7 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, } namespace { - bool trait_contains_method_inner(const ::HIR::Trait& trait_ptr, const ::std::string& name, const ::HIR::Function*& out_fcn_ptr) + bool trait_contains_method_inner(const ::HIR::Trait& trait_ptr, const char* name, const ::HIR::Function*& out_fcn_ptr) { auto it = trait_ptr.m_values.find(name); if( it != trait_ptr.m_values.end() ) @@ -3076,7 +3075,7 @@ namespace { } } -const ::HIR::Function* TraitResolution::trait_contains_method(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const ::HIR::TypeRef& self, const ::std::string& name, ::HIR::GenericPath& out_path) const +const ::HIR::Function* TraitResolution::trait_contains_method(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const ::HIR::TypeRef& self, const char* name, ::HIR::GenericPath& out_path) const { TRACE_FUNCTION_FR("trait_path=" << trait_path << ",name=" << name, out_path); const ::HIR::Function* rv = nullptr; @@ -3101,7 +3100,7 @@ const ::HIR::Function* TraitResolution::trait_contains_method(const Span& sp, co } return nullptr; } -bool TraitResolution::trait_contains_type(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const ::std::string& name, ::HIR::GenericPath& out_path) const +bool TraitResolution::trait_contains_type(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const char* name, ::HIR::GenericPath& out_path) const { TRACE_FUNCTION_FR(trait_path << " has " << name, out_path); @@ -3698,7 +3697,7 @@ const ::HIR::TypeRef* TraitResolution::autoderef(const Span& sp, const ::HIR::Ty } unsigned int TraitResolution::autoderef_find_method(const Span& sp, - const HIR::t_trait_list& traits, const ::std::vector& ivars, const ::HIR::TypeRef& top_ty, const ::std::string& method_name, + const HIR::t_trait_list& traits, const ::std::vector& ivars, const ::HIR::TypeRef& top_ty, const char* method_name, /* Out -> */::std::vector<::std::pair>& possibilities ) const { @@ -3906,7 +3905,7 @@ const ::HIR::TypeRef* TraitResolution::check_method_receiver(const Span& sp, con } bool TraitResolution::find_method(const Span& sp, - const HIR::t_trait_list& traits, const ::std::vector& ivars, const ::HIR::TypeRef& ty, const ::std::string& method_name, MethodAccess access, + const HIR::t_trait_list& traits, const ::std::vector& ivars, const ::HIR::TypeRef& ty, const char* method_name, MethodAccess access, AutoderefBorrow borrow_type, /* Out -> */::std::vector<::std::pair>& possibilities ) const { @@ -4259,7 +4258,7 @@ bool TraitResolution::find_method(const Span& sp, return rv; } -unsigned int TraitResolution::autoderef_find_field(const Span& sp, const ::HIR::TypeRef& top_ty, const ::std::string& field_name, /* Out -> */::HIR::TypeRef& field_type) const +unsigned int TraitResolution::autoderef_find_field(const Span& sp, const ::HIR::TypeRef& top_ty, const char* field_name, /* Out -> */::HIR::TypeRef& field_type) const { unsigned int deref_count = 0; ::HIR::TypeRef tmp_type; // Temporary type used for handling Deref @@ -4299,7 +4298,7 @@ unsigned int TraitResolution::autoderef_find_field(const Span& sp, const ::HIR:: this->m_ivars.dump(); TODO(sp, "Error when no field could be found, but type is known - (: " << top_ty << ")." << field_name); } -bool TraitResolution::find_field(const Span& sp, const ::HIR::TypeRef& ty, const ::std::string& name, /* Out -> */::HIR::TypeRef& field_ty) const +bool TraitResolution::find_field(const Span& sp, const ::HIR::TypeRef& ty, const char* name, /* Out -> */::HIR::TypeRef& field_ty) const { TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Path, e, TU_MATCH(::HIR::TypeRef::TypePathBinding, (e.binding), (be), diff --git a/src/hir_typeck/helpers.hpp b/src/hir_typeck/helpers.hpp index dd9a1581..00befd63 100644 --- a/src/hir_typeck/helpers.hpp +++ b/src/hir_typeck/helpers.hpp @@ -207,7 +207,7 @@ public: bool iterate_bounds_traits(const Span& sp, ::std::function cb) const; bool iterate_aty_bounds(const Span& sp, const ::HIR::Path::Data::Data_UfcsKnown& pe, ::std::function cb) const; - typedef ::std::function&)> t_cb_trait_impl; + typedef ::std::function&)> t_cb_trait_impl; typedef ::std::function t_cb_trait_impl_r; /// Searches for a trait impl that matches the provided trait name and type @@ -250,17 +250,17 @@ public: /// Locate the named method by applying auto-dereferencing. /// \return Number of times deref was applied (or ~0 if _ was hit) unsigned int autoderef_find_method(const Span& sp, - const HIR::t_trait_list& traits, const ::std::vector& ivars, const ::HIR::TypeRef& top_ty, const ::std::string& method_name, + const HIR::t_trait_list& traits, const ::std::vector& ivars, const ::HIR::TypeRef& top_ty, const char* method_name, /* Out -> */::std::vector<::std::pair>& possibilities ) const; /// Locate the named field by applying auto-dereferencing. /// \return Number of times deref was applied (or ~0 if _ was hit) - unsigned int autoderef_find_field(const Span& sp, const ::HIR::TypeRef& top_ty, const ::std::string& name, /* Out -> */::HIR::TypeRef& field_type) const; + unsigned int autoderef_find_field(const Span& sp, const ::HIR::TypeRef& top_ty, const char* name, /* Out -> */::HIR::TypeRef& field_type) const; /// Apply an automatic dereference const ::HIR::TypeRef* autoderef(const Span& sp, const ::HIR::TypeRef& ty, ::HIR::TypeRef& tmp_type) const; - bool find_field(const Span& sp, const ::HIR::TypeRef& ty, const ::std::string& name, /* Out -> */::HIR::TypeRef& field_type) const; + bool find_field(const Span& sp, const ::HIR::TypeRef& ty, const char* name, /* Out -> */::HIR::TypeRef& field_type) const; enum class MethodAccess { Shared, @@ -279,13 +279,13 @@ public: }; friend ::std::ostream& operator<<(::std::ostream& os, const AllowedReceivers& x); bool find_method(const Span& sp, - const HIR::t_trait_list& traits, const ::std::vector& ivars, const ::HIR::TypeRef& ty, const ::std::string& method_name, MethodAccess access, + const HIR::t_trait_list& traits, const ::std::vector& ivars, const ::HIR::TypeRef& ty, const char* method_name, MethodAccess access, AutoderefBorrow borrow_type, /* Out -> */::std::vector<::std::pair>& possibilities ) const; /// Locates a named method in a trait, and returns the path of the trait that contains it (with fixed parameters) - const ::HIR::Function* trait_contains_method(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const ::HIR::TypeRef& self, const ::std::string& name, ::HIR::GenericPath& out_path) const; - bool trait_contains_type(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const ::std::string& name, ::HIR::GenericPath& out_path) const; + const ::HIR::Function* trait_contains_method(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const ::HIR::TypeRef& self, const char* name, ::HIR::GenericPath& out_path) const; + bool trait_contains_type(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const char* name, ::HIR::GenericPath& out_path) const; ::HIR::Compare type_is_sized(const Span& sp, const ::HIR::TypeRef& ty) const; ::HIR::Compare type_is_copy(const Span& sp, const ::HIR::TypeRef& ty) const; diff --git a/src/hir_typeck/impl_ref.hpp b/src/hir_typeck/impl_ref.hpp index 84d0b404..c67c8a81 100644 --- a/src/hir_typeck/impl_ref.hpp +++ b/src/hir_typeck/impl_ref.hpp @@ -27,12 +27,12 @@ struct ImplRef (BoundedPtr, struct { const ::HIR::TypeRef* type; const ::HIR::PathParams* trait_args; - const ::std::map< ::std::string, ::HIR::TypeRef>* assoc; + const ::std::map< RcString, ::HIR::TypeRef>* assoc; }), (Bounded, struct { ::HIR::TypeRef type; ::HIR::PathParams trait_args; - ::std::map< ::std::string, ::HIR::TypeRef> assoc; + ::std::map< RcString, ::HIR::TypeRef> assoc; }) ); @@ -45,10 +45,10 @@ struct ImplRef m_data(Data::make_TraitImpl({ mv$(params), mv$(params_ph), &trait, &impl })) {} - ImplRef(const ::HIR::TypeRef* type, const ::HIR::PathParams* args, const ::std::map< ::std::string, ::HIR::TypeRef>* assoc): + ImplRef(const ::HIR::TypeRef* type, const ::HIR::PathParams* args, const ::std::map< RcString, ::HIR::TypeRef>* assoc): m_data(Data::make_BoundedPtr({ type, mv$(args), mv$(assoc) })) {} - ImplRef(::HIR::TypeRef type, ::HIR::PathParams args, ::std::map< ::std::string, ::HIR::TypeRef> assoc): + ImplRef(::HIR::TypeRef type, ::HIR::PathParams args, ::std::map< RcString, ::HIR::TypeRef> assoc): m_data(Data::make_Bounded({ mv$(type), mv$(args), mv$(assoc) })) {} diff --git a/src/hir_typeck/outer.cpp b/src/hir_typeck/outer.cpp index 6a8e8b35..c2b216d4 100644 --- a/src/hir_typeck/outer.cpp +++ b/src/hir_typeck/outer.cpp @@ -322,8 +322,9 @@ namespace { else if( m_fcn_ptr ) { size_t idx = m_fcn_ptr->m_params.m_types.size(); - auto new_ty = ::HIR::TypeRef( FMT("impl$" << idx), 256 + idx ); - m_fcn_ptr->m_params.m_types.push_back({ FMT("impl$" << idx), ::HIR::TypeRef(), true }); + auto name = RcString::new_interned(FMT("impl$" << idx)); + auto new_ty = ::HIR::TypeRef( name, 256 + idx ); + m_fcn_ptr->m_params.m_types.push_back({ name, ::HIR::TypeRef(), true }); for( const auto& trait : e.m_traits ) { m_fcn_ptr->m_params.m_bounds.push_back(::HIR::GenericBound::make_TraitBound({ diff --git a/src/hir_typeck/static.cpp b/src/hir_typeck/static.cpp index c71e71d7..0c0f1859 100644 --- a/src/hir_typeck/static.cpp +++ b/src/hir_typeck/static.cpp @@ -97,7 +97,7 @@ bool StaticTraitResolve::find_impl( auto cb_ident = [](const ::HIR::TypeRef&ty)->const ::HIR::TypeRef& { return ty; }; static ::HIR::PathParams null_params; - static ::std::map< ::std::string, ::HIR::TypeRef> null_assoc; + static ::std::map null_assoc; if( !dont_handoff_to_specialised ) { if( trait_path == m_lang_Copy ) { @@ -159,7 +159,7 @@ bool StaticTraitResolve::find_impl( { trait_params = &null_params; } - ::std::map< ::std::string, ::HIR::TypeRef> assoc; + ::std::map< RcString, ::HIR::TypeRef> assoc; assoc.insert( ::std::make_pair("Output", e.m_rettype->clone()) ); return found_cb( ImplRef(type.clone(), trait_params->clone(), mv$(assoc)), false ); } @@ -200,7 +200,7 @@ bool StaticTraitResolve::find_impl( case ::HIR::ExprNode_Closure::Class::Shared: break; } - ::std::map< ::std::string, ::HIR::TypeRef> assoc; + ::std::map< RcString, ::HIR::TypeRef> assoc; assoc.insert( ::std::make_pair("Output", e->m_rettype->clone()) ); return found_cb( ImplRef(type.clone(), trait_params->clone(), mv$(assoc)), false ); } @@ -223,7 +223,7 @@ bool StaticTraitResolve::find_impl( if( trait_path == mt.m_path ) { if( !trait_params || mt.m_params == *trait_params ) { - static ::std::map< ::std::string, ::HIR::TypeRef> types; + static ::std::map< RcString, ::HIR::TypeRef> types; return found_cb( ImplRef(&type, &mt.m_params, &types), false ); } } @@ -235,7 +235,7 @@ bool StaticTraitResolve::find_impl( bool is_supertrait = trait_params && this->find_named_trait_in_trait(sp, trait_path,*trait_params, *e.m_trait.m_trait_ptr, e.m_trait.m_path.m_path,e.m_trait.m_path.m_params, type, [&](const auto& i_params, const auto& i_assoc) { // Invoke callback with a proper ImplRef - ::std::map< ::std::string, ::HIR::TypeRef> assoc_clone; + ::std::map< RcString, ::HIR::TypeRef> assoc_clone; for(const auto& e : i_assoc) assoc_clone.insert( ::std::make_pair(e.first, e.second.clone()) ); // HACK! Just add all the associated type bounds (only inserted if not already present) @@ -265,7 +265,7 @@ bool StaticTraitResolve::find_impl( bool is_supertrait = trait_params && this->find_named_trait_in_trait(sp, trait_path,*trait_params, *trait.m_trait_ptr, trait.m_path.m_path,trait.m_path.m_params, type, [&](const auto& i_params, const auto& i_assoc) { // Invoke callback with a proper ImplRef - ::std::map< ::std::string, ::HIR::TypeRef> assoc_clone; + ::std::map< RcString, ::HIR::TypeRef> assoc_clone; for(const auto& e : i_assoc) assoc_clone.insert( ::std::make_pair(e.first, e.second.clone()) ); // HACK! Just add all the associated type bounds (only inserted if not already present) @@ -312,7 +312,7 @@ bool StaticTraitResolve::find_impl( { if( &b_params_mono == ¶ms_mono_o || ::std::any_of(bound.m_type_bounds.begin(), bound.m_type_bounds.end(), [&](const auto& x){ return monomorphise_type_needed(x.second); }) ) { - ::std::map< ::std::string, ::HIR::TypeRef> atys; + ::std::map< RcString, ::HIR::TypeRef> atys; if( ! bound.m_type_bounds.empty() ) { for(const auto& tb : bound.m_type_bounds) @@ -722,7 +722,7 @@ bool StaticTraitResolve::find_impl__check_crate_raw( const ::HIR::TypeRef& exp = assoc_bound.second; ::HIR::GenericPath aty_src_trait; - trait_contains_type(sp, b_tp_mono.m_path, *e.trait.m_trait_ptr, aty_name, aty_src_trait); + trait_contains_type(sp, b_tp_mono.m_path, *e.trait.m_trait_ptr, aty_name.c_str(), aty_src_trait); bool rv = false; if( b_ty_mono.m_data.is_Generic() && (b_ty_mono.m_data.as_Generic().binding >> 8) == 2 ) { @@ -1241,7 +1241,7 @@ bool StaticTraitResolve::expand_associated_types__UfcsKnown(const Span& sp, ::HI // - Search for the actual trait containing this associated type ::HIR::GenericPath trait_path; - if( !this->trait_contains_type(sp, e2.trait, this->m_crate.get_trait_by_path(sp, e2.trait.m_path), e2.item, trait_path) ) + if( !this->trait_contains_type(sp, e2.trait, this->m_crate.get_trait_by_path(sp, e2.trait.m_path), e2.item.c_str(), trait_path) ) BUG(sp, "Cannot find associated type " << e2.item << " anywhere in trait " << e2.trait); //e2.trait = mv$(trait_path); @@ -1382,7 +1382,7 @@ bool StaticTraitResolve::find_named_trait_in_trait(const Span& sp, const ::HIR::SimplePath& des, const ::HIR::PathParams& des_params, const ::HIR::Trait& trait_ptr, const ::HIR::SimplePath& trait_path, const ::HIR::PathParams& pp, const ::HIR::TypeRef& target_type, - ::std::function)> callback + ::std::function)> callback ) const { TRACE_FUNCTION_F(des << des_params << " from " << trait_path << pp); @@ -1423,7 +1423,7 @@ bool StaticTraitResolve::find_named_trait_in_trait(const Span& sp, return false; } -bool StaticTraitResolve::trait_contains_type(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const ::std::string& name, ::HIR::GenericPath& out_path) const +bool StaticTraitResolve::trait_contains_type(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const char* name, ::HIR::GenericPath& out_path) const { TRACE_FUNCTION_FR("name="<~RcString(); m_ptr = x.m_ptr; - m_len = x.m_len; if( m_ptr ) *m_ptr += 1; } return *this; @@ -62,27 +60,76 @@ public: { this->~RcString(); m_ptr = x.m_ptr; - m_len = x.m_len; x.m_ptr = nullptr; - x.m_len = 0; } return *this; } + const char* begin() const { return c_str(); } + const char* end() const { return c_str() + size(); } + size_t size() const { return m_ptr ? m_ptr[1] : 0; } const char* c_str() const { - if( m_len > 0 ) + if( m_ptr ) { - return reinterpret_cast(m_ptr + 1); + return reinterpret_cast(m_ptr + 2); } else { return ""; } } - bool operator==(const RcString& s) const { return *this == s.c_str(); } + + char back() const { + assert(size() > 0 ); + return *(c_str() + size() - 1); + } + + Ordering ord(const RcString& s) const; + bool operator==(const RcString& s) const { + if(s.size() != this->size()) + return false; + return this->ord(s) == OrdEqual; + } + bool operator!=(const RcString& s) const { + if(s.size() != this->size()) + return true; + return this->ord(s) != OrdEqual; + } + bool operator<(const RcString& s) const { return this->ord(s) == OrdLess; } + bool operator>(const RcString& s) const { return this->ord(s) == OrdGreater; } + + Ordering ord(const std::string& s) const; + bool operator==(const std::string& s) const { return this->ord(s) == OrdEqual; } + bool operator!=(const std::string& s) const { return this->ord(s) != OrdEqual; } + bool operator<(const std::string& s) const { return this->ord(s) == OrdLess; } + bool operator>(const std::string& s) const { return this->ord(s) == OrdGreater; } bool operator==(const char* s) const; - friend ::std::ostream& operator<<(::std::ostream& os, const RcString& x) { - return os << x.c_str(); + bool operator!=(const char* s) const { return !(*this == s); } + friend ::std::ostream& operator<<(::std::ostream& os, const RcString& x); + + friend bool operator==(const char* a, const RcString& b) { + return b == a; + } + friend bool operator!=(const char* a, const RcString& b) { + return b != a; + } + + int compare(size_t o, size_t l, const char* s) const { + assert(o <= this->size()); + return memcmp(this->c_str() + o, s, l); } }; + +namespace std { + static inline bool operator==(const string& a, const ::RcString& b) { + return b == a; + } + static inline bool operator!=(const string& a, const ::RcString& b) { + return b != a; + } + template<> struct hash + { + size_t operator()(const RcString& s) const noexcept; + }; +} diff --git a/src/include/synext_macro.hpp b/src/include/synext_macro.hpp index d414ceb0..e62a6126 100644 --- a/src/include/synext_macro.hpp +++ b/src/include/synext_macro.hpp @@ -27,7 +27,10 @@ class TokenStream; class ExpandProcMacro { public: - virtual ::std::unique_ptr expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) = 0; + virtual ::std::unique_ptr expand(const Span& sp, const AST::Crate& crate, const TokenTree& tt, AST::Module& mod) = 0; + virtual ::std::unique_ptr expand_ident(const Span& sp, const AST::Crate& crate, const RcString& ident, const TokenTree& tt, AST::Module& mod) { + ERROR(sp, E0000, "macro doesn't take an identifier"); + } }; struct MacroDef; diff --git a/src/macro_rules/eval.cpp b/src/macro_rules/eval.cpp index c40eb810..2d1b6bb1 100644 --- a/src/macro_rules/eval.cpp +++ b/src/macro_rules/eval.cpp @@ -405,7 +405,7 @@ class MacroExpander: { const RcString m_macro_filename; - const ::std::string m_crate_name; + const RcString m_crate_name; ::std::shared_ptr m_invocation_span; ParameterMappings m_mappings; @@ -418,7 +418,7 @@ class MacroExpander: public: MacroExpander(const MacroExpander& x) = delete; - MacroExpander(const ::std::string& macro_name, const Span& sp, const Ident::Hygiene& parent_hygiene, const ::std::vector& contents, ParameterMappings mappings, ::std::string crate_name): + MacroExpander(const ::std::string& macro_name, const Span& sp, const Ident::Hygiene& parent_hygiene, const ::std::vector& contents, ParameterMappings mappings, RcString crate_name): m_macro_filename( FMT("Macro:" << macro_name) ), m_crate_name( mv$(crate_name) ), m_invocation_span( new Span(sp) ), @@ -841,7 +841,7 @@ namespace case TOK_SQUARE_OPEN: return consume_tt(lex); case TOK_IDENT: - if( TARGETVER_1_29 && lex.next_tok().str() == "dyn" ) + if( TARGETVER_1_29 && lex.next_tok().istr() == "dyn" ) lex.consume(); case TOK_RWORD_SUPER: case TOK_RWORD_SELF: @@ -1345,7 +1345,7 @@ namespace return true; // Macro invocation // TODO: What about `union!` as a macro? Needs to be handled below - if( (lex.next() == TOK_IDENT && lex.next_tok().str() != "union") + if( (lex.next() == TOK_IDENT && lex.next_tok().istr() != "union") || lex.next() == TOK_RWORD_SELF || lex.next() == TOK_RWORD_SUPER || lex.next() == TOK_DOUBLE_COLON @@ -1481,7 +1481,7 @@ namespace return false; return consume_tt(lex); case TOK_IDENT: - if( lex.next_tok().str() == "union" ) + if( lex.next_tok().istr() == "union" ) { lex.consume(); if( lex.next() == TOK_EXCLAM ) @@ -1506,7 +1506,7 @@ namespace return consume_tt(lex); } } - else if( lex.next_tok().str() == "auto" ) + else if( lex.next_tok().istr() == "auto" ) { lex.consume(); if( lex.consume_if(TOK_RWORD_TRAIT) ) @@ -1960,7 +1960,7 @@ Token MacroExpander::realGetToken() DEBUG("Crate name hack"); if( m_crate_name != "" ) { - m_next_token = Token(TOK_STRING, m_crate_name); + m_next_token = Token(TOK_STRING, ::std::string(m_crate_name.c_str())); return Token(TOK_DOUBLE_COLON); } break; diff --git a/src/macro_rules/macro_rules.hpp b/src/macro_rules/macro_rules.hpp index 9e408fd5..05b1e065 100644 --- a/src/macro_rules/macro_rules.hpp +++ b/src/macro_rules/macro_rules.hpp @@ -41,7 +41,7 @@ extern ::std::ostream& operator<<(::std::ostream& os, const MacroExpansionEnt& x /// Matching pattern entry struct MacroPatEnt { - ::std::string name; + RcString name; unsigned int name_index = 0; // TODO: Include a point span for the token? Token tok; @@ -77,7 +77,7 @@ struct MacroPatEnt { } - MacroPatEnt(::std::string name, unsigned int name_index, Type type): + MacroPatEnt(RcString name, unsigned int name_index, Type type): name( mv$(name) ), name_index( name_index ), tok(), @@ -134,7 +134,7 @@ extern::std::ostream& operator<<(::std::ostream& os, const SimplePatEnt& x); struct MacroRulesArm { /// Names for the parameters - ::std::vector< ::std::string> m_param_names; + ::std::vector m_param_names; /// Patterns ::std::vector m_pattern; @@ -164,7 +164,7 @@ public: /// Crate that defined this macro /// - Populated on deserialise if not already set - ::std::string m_source_crate; + RcString m_source_crate; Ident::Hygiene m_hygiene; @@ -181,8 +181,8 @@ public: extern ::std::unique_ptr Macro_InvokeRules(const char *name, const MacroRules& rules, const Span& sp, TokenTree input, AST::Module& mod); extern MacroRulesPtr Parse_MacroRules(TokenStream& lex); -extern ::std::vector Parse_MacroRules_Pat(TokenStream& lex, enum eTokenType open, enum eTokenType close, ::std::vector< ::std::string>& names); -extern ::std::vector Parse_MacroRules_Cont(TokenStream& lex, enum eTokenType open, enum eTokenType close, const ::std::vector< ::std::string>& var_names, ::std::map* var_set_ptr=nullptr); +extern ::std::vector Parse_MacroRules_Pat(TokenStream& lex, enum eTokenType open, enum eTokenType close, ::std::vector& names); +extern ::std::vector Parse_MacroRules_Cont(TokenStream& lex, enum eTokenType open, enum eTokenType close, const ::std::vector& var_names, ::std::map* var_set_ptr=nullptr); extern MacroRulesArm Parse_MacroRules_MakeArm(Span pat_sp, ::std::vector pattern, ::std::vector contents); #endif // MACROS_HPP_INCLUDED diff --git a/src/macro_rules/parse.cpp b/src/macro_rules/parse.cpp index 4bd8a577..97e1f8f9 100644 --- a/src/macro_rules/parse.cpp +++ b/src/macro_rules/parse.cpp @@ -30,7 +30,7 @@ public: }; /// Parse the pattern of a macro_rules! arm -::std::vector Parse_MacroRules_Pat(TokenStream& lex, enum eTokenType open, enum eTokenType close, ::std::vector< ::std::string>& names) +::std::vector Parse_MacroRules_Pat(TokenStream& lex, enum eTokenType open, enum eTokenType close, ::std::vector& names) { TRACE_FUNCTION; Token tok; @@ -60,10 +60,10 @@ public: // TODO: Allow any reserved word case TOK_RWORD_PUB ... TOK_RWORD_UNSIZED: case TOK_IDENT: { - ::std::string name = tok.type() == TOK_IDENT ? mv$(tok.str()) : FMT(tok); + auto name = tok.type() == TOK_IDENT ? tok.istr() : RcString::new_interned(FMT(tok)); GET_CHECK_TOK(tok, lex, TOK_COLON); GET_CHECK_TOK(tok, lex, TOK_IDENT); - ::std::string type = mv$(tok.str()); + RcString type = tok.istr(); unsigned int idx = ::std::find( names.begin(), names.end(), name ) - names.begin(); if( idx == names.size() ) @@ -142,7 +142,7 @@ public: ::std::vector Parse_MacroRules_Cont( TokenStream& lex, enum eTokenType open, enum eTokenType close, - const ::std::vector< ::std::string>& var_names, + const ::std::vector& var_names, ::std::map* var_set_ptr/*=nullptr*/ ) { @@ -221,7 +221,7 @@ public: else if( tok.type() == TOK_IDENT || tok.type() >= TOK_RWORD_PUB ) { // Look up the named parameter in the list of param names for this arm - auto name = tok.type() == TOK_IDENT ? tok.str() : FMT(tok); + auto name = tok.type() == TOK_IDENT ? tok.istr() : RcString::new_interned(FMT(tok)); unsigned int idx = ::std::find(var_names.begin(), var_names.end(), name) - var_names.begin(); if( idx == var_names.size() ) { // TODO: `error-chain`'s quick_error macro has an arm which refers to an undefined metavar. @@ -269,7 +269,7 @@ MacroRule Parse_MacroRules_Var(TokenStream& lex) throw ParseError::Unexpected(lex, tok); } // - Pattern entries - ::std::vector< ::std::string> names; + ::std::vector names; { auto ps = lex.start_span(); rule.m_pattern = Parse_MacroRules_Pat(lex, tok.type(), close, names); @@ -294,7 +294,7 @@ MacroRule Parse_MacroRules_Var(TokenStream& lex) } // TODO: Also count the number of times each variable is used? -void enumerate_names(const ::std::vector& pats, ::std::vector< ::std::string>& names) +void enumerate_names(const ::std::vector& pats, ::std::vector& names) { for( const auto& pat : pats ) { diff --git a/src/main.cpp b/src/main.cpp index 5ffc195a..28d34da4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -351,9 +351,9 @@ int main(int argc, char *argv[]) if( crate.m_crate_type == ::AST::Crate::Type::Executable || params.test_harness || crate.m_crate_type == ::AST::Crate::Type::ProcMacro ) { bool allocator_crate_loaded = false; - ::std::string alloc_crate_name; + RcString alloc_crate_name; bool panic_runtime_loaded = false; - ::std::string panic_crate_name; + RcString panic_crate_name; bool panic_runtime_needed = false; for(const auto& ec : crate.m_extern_crates) { diff --git a/src/mir/check.cpp b/src/mir/check.cpp index b5abdb0a..0b032bbc 100644 --- a/src/mir/check.cpp +++ b/src/mir/check.cpp @@ -19,7 +19,6 @@ namespace { if( const auto* tep = unsized_ty.m_data.opt_TraitObject() ) { const auto& trait_path = tep->m_trait; - const auto& trait = *tep->m_trait.m_trait_ptr; if( trait_path.m_path.m_path == ::HIR::SimplePath() ) { @@ -27,8 +26,10 @@ namespace { } else { - auto vtable_ty_spath = trait_path.m_path.m_path; - vtable_ty_spath.m_components.back() += "#vtable"; + const auto& trait = *tep->m_trait.m_trait_ptr; + + const auto& vtable_ty_spath = trait.m_vtable_path; + MIR_ASSERT(state, vtable_ty_spath != ::HIR::SimplePath(), "Trait with no vtable - " << trait_path); const auto& vtable_ref = state.m_resolve.m_crate.get_struct_by_path(state.sp, vtable_ty_spath); // Copy the param set from the trait in the trait object ::HIR::PathParams vtable_params = trait_path.m_path.m_params.clone(); diff --git a/src/mir/cleanup.cpp b/src/mir/cleanup.cpp index dd5332b6..5d32d0c8 100644 --- a/src/mir/cleanup.cpp +++ b/src/mir/cleanup.cpp @@ -75,8 +75,7 @@ namespace { { const auto& trait = *te.m_trait.m_trait_ptr; - auto vtable_ty_spath = te.m_trait.m_path.m_path; - vtable_ty_spath.m_components.back() += "#vtable"; + const auto& vtable_ty_spath = trait.m_vtable_path; const auto& vtable_ref = resolve.m_crate.get_struct_by_path(sp, vtable_ty_spath); // Copy the param set from the trait in the trait object ::HIR::PathParams vtable_params = te.m_trait.m_path.m_params.clone(); @@ -676,8 +675,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator& const auto& trait = *de.m_trait.m_trait_ptr; // Obtain vtable type `::"path"::to::Trait#vtable` - auto vtable_ty_spath = trait_path.m_path.m_path; - vtable_ty_spath.m_components.back() += "#vtable"; + const auto& vtable_ty_spath = trait.m_vtable_path; const auto& vtable_ref = state.m_crate.get_struct_by_path(state.sp, vtable_ty_spath); // Copy the param set from the trait in the trait object ::HIR::PathParams vtable_params = trait_path.m_path.m_params.clone(); diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index b8549f8a..9e749811 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -51,7 +51,7 @@ namespace { struct LoopDesc { ScopeHandle scope; - ::std::string label; + RcString label; unsigned int cur; unsigned int next; ::MIR::LValue res_value; @@ -679,7 +679,7 @@ namespace { target_block = &*it; } else { - if( target_block->label != "" && target_block->label[0] == '#' ) { + if( target_block->label != "" && target_block->label.c_str()[0] == '#' ) { TODO(node.span(), "Break within try block, want to break parent loop instead"); } } @@ -1952,7 +1952,7 @@ namespace { { m_builder.end_block(::MIR::Terminator::make_Call({ next_block, panic_block, - res.clone(), ::MIR::CallTarget::make_Intrinsic({ "platform:"+gpath.m_path.m_components.back(), gpath.m_params.clone() }), + res.clone(), ::MIR::CallTarget::make_Intrinsic({ RcString(FMT("platform:" << gpath.m_path.m_components.back())), gpath.m_params.clone() }), mv$(values) })); } @@ -2054,8 +2054,8 @@ namespace { const auto& val_ty = node.m_value->m_res_type; unsigned int idx; - if( '0' <= node.m_field[0] && node.m_field[0] <= '9' ) { - ::std::stringstream(node.m_field) >> idx; + if( ::std::isdigit(node.m_field.c_str()[0]) ) { + ::std::stringstream(node.m_field.c_str()) >> idx; m_builder.set_result( node.span(), ::MIR::LValue::make_Field({ box$(val), idx }) ); } else if( const auto* bep = val_ty.m_data.as_Path().binding.opt_Struct() ) { diff --git a/src/mir/mir.hpp b/src/mir/mir.hpp index ebef039a..63acf89d 100644 --- a/src/mir/mir.hpp +++ b/src/mir/mir.hpp @@ -311,7 +311,7 @@ TAGGED_UNION(CallTarget, Intrinsic, (Value, LValue), (Path, ::HIR::Path), (Intrinsic, struct { - ::std::string name; + RcString name; ::HIR::PathParams params; }) ); @@ -419,7 +419,7 @@ class Function { public: ::std::vector< ::HIR::TypeRef> locals; - //::std::vector< ::std::string> local_names; + //::std::vector< RcString> local_names; ::std::vector drop_flags; ::std::vector blocks; diff --git a/src/parse/common.hpp b/src/parse/common.hpp index 6ee0d3f4..d4a1d59a 100644 --- a/src/parse/common.hpp +++ b/src/parse/common.hpp @@ -46,7 +46,7 @@ extern ::AST::HigherRankedBounds Parse_HRB_Opt(TokenStream& lex); extern AST::AttributeList Parse_ItemAttrs(TokenStream& lex); extern void Parse_ParentAttrs(TokenStream& lex, AST::AttributeList& out); extern AST::Attribute Parse_MetaItem(TokenStream& lex); -extern ::AST::MacroInvocation Parse_MacroInvocation(ProtoSpan ps, ::std::string name, TokenStream& lex); +extern ::AST::MacroInvocation Parse_MacroInvocation(ProtoSpan ps, RcString name, TokenStream& lex); extern TypeRef Parse_Type(TokenStream& lex, bool allow_trait_list = true); extern AST::Pattern Parse_Pattern(TokenStream& lex, bool is_refutable); diff --git a/src/parse/expr.cpp b/src/parse/expr.cpp index 6cc94d74..2735c39e 100644 --- a/src/parse/expr.cpp +++ b/src/parse/expr.cpp @@ -32,8 +32,8 @@ ExprNodeP Parse_ExprBlockLine_Stmt(TokenStream& lex, bool& has_semicolon); ExprNodeP Parse_Stmt_Let(TokenStream& lex); ExprNodeP Parse_Expr0(TokenStream& lex); ExprNodeP Parse_IfStmt(TokenStream& lex); -ExprNodeP Parse_WhileStmt(TokenStream& lex, ::std::string lifetime); -ExprNodeP Parse_ForStmt(TokenStream& lex, ::std::string lifetime); +ExprNodeP Parse_WhileStmt(TokenStream& lex, RcString lifetime); +ExprNodeP Parse_ForStmt(TokenStream& lex, RcString lifetime); ExprNodeP Parse_Expr_Match(TokenStream& lex); ExprNodeP Parse_Expr1(TokenStream& lex); ExprNodeP Parse_ExprMacro(TokenStream& lex, AST::Path tok); @@ -108,7 +108,7 @@ ExprNodeP Parse_ExprBlockLine_WithItems(TokenStream& lex, ::std::shared_ptrgetc(); } this->ungetc(); - return Token(TOK_LIFETIME, str); + return Token(TOK_LIFETIME, RcString::new_interned(str)); } else { throw ParseError::Todo("Lex Fail - Expected ' after character constant"); @@ -728,7 +728,7 @@ Token Lexer::getTokenInt() str += ch; } } - return Token(TOK_STRING, str); + return Token(TOK_STRING, mv$(str)); } default: assert(!"bugcheck"); @@ -806,7 +806,7 @@ Token Lexer::getTokenInt_RawString(bool is_byte) } } } - return Token(is_byte ? TOK_BYTESTRING : TOK_STRING, val); + return Token(is_byte ? TOK_BYTESTRING : TOK_STRING, mv$(val)); } Token Lexer::getTokenInt_Identifier(Codepoint leader, Codepoint leader2) { @@ -826,7 +826,7 @@ Token Lexer::getTokenInt_Identifier(Codepoint leader, Codepoint leader2) if( str < RWORDS[i].chars ) break; if( str == RWORDS[i].chars ) return Token((enum eTokenType)RWORDS[i].type); } - return Token(TOK_IDENT, mv$(str)); + return Token(TOK_IDENT, RcString::new_interned(str)); } // Takes the VERY lazy way of reading the float into a string then passing to strtod diff --git a/src/parse/paths.cpp b/src/parse/paths.cpp index 5c99e049..8bfd20de 100644 --- a/src/parse/paths.cpp +++ b/src/parse/paths.cpp @@ -90,7 +90,7 @@ AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generi return AST::Path("", Parse_PathNodes(lex, generic_mode)); } else if( GET_TOK(tok, lex) == TOK_STRING ) { - ::std::string cratename = tok.str(); + auto cratename = RcString::new_interned(tok.str()); GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON); return AST::Path(cratename, Parse_PathNodes(lex, generic_mode)); } @@ -122,7 +122,7 @@ AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generi ::AST::PathParams params; CHECK_TOK(tok, TOK_IDENT); - auto component = mv$( tok.str() ); + auto component = mv$( tok.istr() ); GET_TOK(tok, lex); if( generic_mode == PATH_GENERIC_TYPE ) @@ -166,7 +166,7 @@ AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generi params = ::AST::PathParams { {}, ::make_vec1( TypeRef(TypeRef::TagTuple(), lex.end_span(ps), mv$(args)) ), - ::make_vec1( ::std::make_pair( ::std::string("Output"), mv$(ret_type) ) ) + ::make_vec1( ::std::make_pair( RcString::new_interned("Output"), mv$(ret_type) ) ) }; GET_TOK(tok, lex); @@ -210,7 +210,7 @@ AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generi ::std::vector types; ::std::vector lifetimes; - ::std::vector< ::std::pair< ::std::string, TypeRef > > assoc_bounds; + ::std::vector< ::std::pair< RcString, TypeRef > > assoc_bounds; do { if( LOOK_AHEAD(lex) == TOK_GT || LOOK_AHEAD(lex) == TOK_DOUBLE_GT || LOOK_AHEAD(lex) == TOK_GTE || LOOK_AHEAD(lex) == TOK_DOUBLE_GT_EQUAL ) { @@ -225,7 +225,7 @@ AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generi case TOK_IDENT: if( LOOK_AHEAD(lex) == TOK_EQUAL ) { - ::std::string name = mv$(tok.str()); + auto name = tok.istr(); GET_CHECK_TOK(tok, lex, TOK_EQUAL); assoc_bounds.push_back( ::std::make_pair( mv$(name), Parse_Type(lex,false) ) ); break; diff --git a/src/parse/pattern.cpp b/src/parse/pattern.cpp index 239bac80..37b78123 100644 --- a/src/parse/pattern.cpp +++ b/src/parse/pattern.cpp @@ -46,7 +46,7 @@ AST::Pattern Parse_Pattern(TokenStream& lex, bool is_refutable) if( tok.type() == TOK_IDENT && lex.lookahead(0) == TOK_EXCLAM ) { lex.getToken(); - return AST::Pattern( AST::Pattern::TagMacro(), lex.end_span(ps), box$(Parse_MacroInvocation(ps, tok.str(), lex))); + return AST::Pattern( AST::Pattern::TagMacro(), lex.end_span(ps), box$(Parse_MacroInvocation(ps, tok.istr(), lex))); } if( tok.type() == TOK_INTERPOLATED_PATTERN ) { @@ -87,7 +87,7 @@ AST::Pattern Parse_Pattern(TokenStream& lex, bool is_refutable) if( expect_bind ) { CHECK_TOK(tok, TOK_IDENT); - auto bind_name = Ident(lex.getHygiene(), mv$(tok.str())); + auto bind_name = lex.get_ident(mv$(tok)); // If there's no '@' after it, it's a name binding only (_ pattern) if( GET_TOK(tok, lex) != TOK_AT ) { @@ -117,12 +117,12 @@ AST::Pattern Parse_Pattern(TokenStream& lex, bool is_refutable) break; // Known binding `ident @` case TOK_AT: - binding = AST::PatternBinding( Ident(lex.getHygiene(), mv$(tok.str())), bind_type/*MOVE*/, is_mut/*false*/ ); + binding = AST::PatternBinding( lex.get_ident(mv$(tok)), bind_type/*MOVE*/, is_mut/*false*/ ); GET_TOK(tok, lex); // '@' GET_TOK(tok, lex); // Match lex.putback() below break; default: { // Maybe bind - Ident name = Ident(lex.getHygiene(), mv$(tok.str())); + auto name = lex.get_ident(mv$(tok)); // if the pattern can be refuted (i.e this could be an enum variant), return MaybeBind if( is_refutable ) { assert(bind_type == ::AST::PatternBinding::Type::MOVE); @@ -459,7 +459,7 @@ AST::Pattern Parse_PatternStruct(TokenStream& lex, ProtoSpan ps, AST::Path path, } bool is_exhaustive = true; - ::std::vector< ::std::pair< ::std::string, AST::Pattern> > subpats; + ::std::vector< ::std::pair< RcString, AST::Pattern> > subpats; do { GET_TOK(tok, lex); DEBUG("tok = " << tok); @@ -500,7 +500,7 @@ AST::Pattern Parse_PatternStruct(TokenStream& lex, ProtoSpan ps, AST::Path path, CHECK_TOK(tok, TOK_IDENT); auto field_ident = lex.get_ident(mv$(tok)); - ::std::string field_name; + RcString field_name; GET_TOK(tok, lex); AST::Pattern pat; diff --git a/src/parse/root.cpp b/src/parse/root.cpp index b0c37a21..677dbe26 100644 --- a/src/parse/root.cpp +++ b/src/parse/root.cpp @@ -21,6 +21,7 @@ #include #include #include +#include template Spanned get_spanned(TokenStream& lex, ::std::function f) { @@ -36,7 +37,7 @@ Spanned get_spanned(TokenStream& lex, ::std::function f) { // Check the next two tokens #define LOOKAHEAD2(lex, tok1, tok2) ((lex).lookahead(0) == (tok1) && (lex).lookahead(1) == (tok2)) -::std::string dirname(::std::string input) { +::helpers::path dirname(::std::string input) { while( input.size() > 0 && input.back() != '/' && input.back() != '\\' ) { input.pop_back(); } @@ -110,12 +111,12 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv) GET_CHECK_TOK(tok, lex, TOK_IDENT); case TOK_RWORD_IN: GET_CHECK_TOK(tok, lex, TOK_IDENT); - path.nodes().push_back( AST::PathNode(tok.str()) ); + path.nodes().push_back( AST::PathNode(tok.istr()) ); while( LOOK_AHEAD(lex) == TOK_DOUBLE_COLON ) { GET_TOK(tok, lex); GET_CHECK_TOK(tok, lex, TOK_IDENT); - path.nodes().push_back( AST::PathNode(tok.str()) ); + path.nodes().push_back( AST::PathNode(tok.istr()) ); } break; default: @@ -149,7 +150,7 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv) switch(GET_TOK(tok, lex)) { case TOK_LIFETIME: - rv.m_lifetimes.push_back(::AST::LifetimeParam(lex.point_span(), ::std::move(attrs), Ident(lex.getHygiene(), tok.str()))); + rv.m_lifetimes.push_back(::AST::LifetimeParam(lex.point_span(), ::std::move(attrs), lex.get_ident(mv$(tok)))); break; default: throw ParseError::Unexpected(lex, tok, Token(TOK_LIFETIME)); @@ -175,7 +176,7 @@ namespace { AST::LifetimeRef get_LifetimeRef(TokenStream& lex, Token tok) { CHECK_TOK(tok, TOK_LIFETIME); - return AST::LifetimeRef(/*lex.point_span(), */Ident(lex.getHygiene(), mv$(tok.str()))); + return AST::LifetimeRef(/*lex.point_span(), */lex.get_ident(mv$(tok))); } } /// Parse type parameters in a definition @@ -242,7 +243,7 @@ AST::GenericParams Parse_GenericParams(TokenStream& lex) GET_TOK(tok, lex); if( tok.type() == TOK_IDENT ) { - ::std::string param_name = mv$(tok.str()); + auto param_name = tok.istr(); ret.add_ty_param( AST::TypeParam( lex.point_span(), ::std::move(attrs), param_name ) ); auto param_ty = TypeRef(lex.point_span(), param_name); @@ -260,7 +261,7 @@ AST::GenericParams Parse_GenericParams(TokenStream& lex) } else if( tok.type() == TOK_LIFETIME ) { - auto param_name = tok.str(); + auto param_name = tok.istr(); auto ref = get_LifetimeRef(lex, mv$(tok)); ret.add_lft_param(::AST::LifetimeParam(lex.point_span(), ::std::move(attrs), Ident(lex.getHygiene(), param_name) )); if( GET_TOK(tok, lex) == TOK_COLON ) @@ -621,7 +622,7 @@ AST::Struct Parse_Struct(TokenStream& lex, const AST::AttributeList& meta_items) bool is_pub = Parse_Publicity(lex); GET_CHECK_TOK(tok, lex, TOK_IDENT); - auto name = mv$(tok.str()); + auto name = tok.istr(); GET_CHECK_TOK(tok, lex, TOK_COLON); TypeRef type = Parse_Type(lex); @@ -658,7 +659,7 @@ AST::Named Parse_Trait_Item(TokenStream& lex) GET_TOK(tok, lex); bool is_specialisable = false; - if( tok.type() == TOK_IDENT && tok.str() == "default" ) { + if( tok.type() == TOK_IDENT && tok.istr() == "default" ) { is_specialisable = true; GET_TOK(tok, lex); } @@ -669,13 +670,13 @@ AST::Named Parse_Trait_Item(TokenStream& lex) bool fn_is_unsafe = false; ::std::string abi = ABI_RUST; - ::std::string name; + RcString name; ::AST::Item rv; switch(tok.type()) { case TOK_RWORD_STATIC: { GET_CHECK_TOK(tok, lex, TOK_IDENT); - name = mv$(tok.str()); + name = tok.istr(); GET_CHECK_TOK(tok, lex, TOK_COLON); auto ty = Parse_Type(lex); GET_CHECK_TOK(tok, lex, TOK_SEMICOLON); @@ -691,7 +692,7 @@ AST::Named Parse_Trait_Item(TokenStream& lex) break; } case TOK_RWORD_CONST: { GET_CHECK_TOK(tok, lex, TOK_IDENT); - name = mv$(tok.str()); + name = tok.istr(); GET_CHECK_TOK(tok, lex, TOK_COLON); auto ty = Parse_Type(lex); @@ -708,7 +709,7 @@ AST::Named Parse_Trait_Item(TokenStream& lex) case TOK_RWORD_TYPE: { auto atype_params = ::AST::GenericParams { }; GET_CHECK_TOK(tok, lex, TOK_IDENT); - name = mv$(tok.str()); + name = tok.istr(); if( GET_TOK(tok, lex) == TOK_COLON ) { // Bounded associated type @@ -746,7 +747,7 @@ AST::Named Parse_Trait_Item(TokenStream& lex) CHECK_TOK(tok, TOK_RWORD_FN); case TOK_RWORD_FN: { GET_CHECK_TOK(tok, lex, TOK_IDENT); - name = mv$(tok.str()); + name = tok.istr(); // Self allowed, prototype-form allowed (optional names and no code) auto fcn = Parse_FunctionDef(lex, abi, true, true, fn_is_unsafe, fn_is_const); if( GET_TOK(tok, lex) == TOK_BRACE_OPEN ) @@ -863,7 +864,7 @@ AST::Enum Parse_EnumDef(TokenStream& lex, const AST::AttributeList& meta_items) SET_ATTRS(lex, item_attrs); GET_CHECK_TOK(tok, lex, TOK_IDENT); - ::std::string name = mv$(tok.str()); + auto name = tok.istr(); // Tuple-like variants if( GET_TOK(tok, lex) == TOK_PAREN_OPEN ) { @@ -901,7 +902,7 @@ AST::Enum Parse_EnumDef(TokenStream& lex, const AST::AttributeList& meta_items) auto field_attrs = Parse_ItemAttrs(lex); GET_CHECK_TOK(tok, lex, TOK_IDENT); - auto name = mv$(tok.str()); + auto name = tok.istr(); GET_CHECK_TOK(tok, lex, TOK_COLON); auto ty = Parse_Type(lex); fields.push_back( ::AST::StructItem(mv$(field_attrs), true, mv$(name), mv$(ty)) ); @@ -966,7 +967,7 @@ AST::Enum Parse_EnumDef(TokenStream& lex, const AST::AttributeList& meta_items) bool is_pub = Parse_Publicity(lex); GET_CHECK_TOK(tok, lex, TOK_IDENT); - auto name = mv$(tok.str()); + auto name = tok.istr(); GET_CHECK_TOK(tok, lex, TOK_COLON); auto ty = Parse_Type(lex); @@ -1029,7 +1030,7 @@ AST::Attribute Parse_MetaItem(TokenStream& lex) throw ParseError::Unexpected(lex, tok, {TOK_IDENT, TOK_INTEGER}); } - ::std::string name = mv$(tok.str()); + auto name = tok.istr(); switch(GET_TOK(tok, lex)) { case TOK_EQUAL: @@ -1199,7 +1200,7 @@ void Parse_Impl_Item(TokenStream& lex, AST::Impl& impl) GET_TOK(tok, lex); bool is_specialisable = false; - if( tok.type() == TOK_IDENT && tok.str() == "default" ) { + if( tok.type() == TOK_IDENT && tok.istr() == "default" ) { is_specialisable = true; GET_TOK(tok, lex); } @@ -1211,7 +1212,7 @@ void Parse_Impl_Item(TokenStream& lex, AST::Impl& impl) { case TOK_RWORD_TYPE: { GET_CHECK_TOK(tok, lex, TOK_IDENT); - auto name = mv$(tok.str()); + auto name = tok.istr(); GET_CHECK_TOK(tok, lex, TOK_EQUAL); impl.add_type(is_public, is_specialisable, name, Parse_Type(lex)); GET_CHECK_TOK(tok, lex, TOK_SEMICOLON); @@ -1226,7 +1227,7 @@ void Parse_Impl_Item(TokenStream& lex, AST::Impl& impl) if( tok.type() != TOK_RWORD_FN && tok.type() != TOK_RWORD_UNSAFE && !fn_is_unsafe ) { CHECK_TOK(tok, TOK_IDENT); - auto name = mv$(tok.str()); + auto name = tok.istr(); GET_CHECK_TOK(tok, lex, TOK_COLON); auto ty = Parse_Type(lex); GET_CHECK_TOK(tok, lex, TOK_EQUAL); @@ -1261,7 +1262,7 @@ void Parse_Impl_Item(TokenStream& lex, AST::Impl& impl) case TOK_RWORD_FN: { GET_CHECK_TOK(tok, lex, TOK_IDENT); // TODO: Hygine on function names? - Not in impl blocks? - ::std::string name = mv$(tok.str()); + auto name = tok.istr(); DEBUG("Function " << name); // - Self allowed, can't be prototype-form auto fcn = Parse_FunctionDefWithCode(lex, abi, true, fn_is_unsafe, fn_is_const); @@ -1298,7 +1299,7 @@ AST::ExternBlock Parse_ExternBlock(TokenStream& lex, ::std::string abi, ::AST::A { case TOK_RWORD_FN: { GET_CHECK_TOK(tok, lex, TOK_IDENT); - auto name = mv$(tok.str()); + auto name = tok.istr(); // parse function as prototype // - no self, is prototype, is unsafe and not const auto i = ::AST::Item( Parse_FunctionDef(lex, abi, false, true, true,false) ); @@ -1316,7 +1317,7 @@ AST::ExternBlock Parse_ExternBlock(TokenStream& lex, ::std::string abi, ::AST::A else PUTBACK(tok, lex); GET_CHECK_TOK(tok, lex, TOK_IDENT); - auto name = mv$(tok.str()); + auto name = tok.istr(); GET_CHECK_TOK(tok, lex, TOK_COLON); auto type = Parse_Type(lex); GET_CHECK_TOK(tok, lex, TOK_SEMICOLON); @@ -1328,7 +1329,7 @@ AST::ExternBlock Parse_ExternBlock(TokenStream& lex, ::std::string abi, ::AST::A break; } case TOK_RWORD_TYPE: { GET_CHECK_TOK(tok, lex, TOK_IDENT); - auto name = mv$(tok.str()); + auto name = tok.istr(); GET_CHECK_TOK(tok, lex, TOK_SEMICOLON); auto sp = lex.end_span(ps); //TODO(sp, "Extern type"); @@ -1355,7 +1356,7 @@ void Parse_Use_Inner(TokenStream& lex, ::std::vector& entries switch( GET_TOK(tok, lex) ) { case TOK_IDENT: - path.append( AST::PathNode( mv$(tok.str()), {}) ); + path.append( AST::PathNode( tok.istr(), {}) ); break; case TOK_BRACE_OPEN: // Can't be an empty list @@ -1376,7 +1377,7 @@ void Parse_Use_Inner(TokenStream& lex, ::std::vector& entries if( LOOK_AHEAD(lex) == TOK_RWORD_AS ) { GET_TOK(tok, lex); GET_CHECK_TOK(tok, lex, TOK_IDENT); - name = mv$(tok.str()); + name = tok.istr(); } entries.push_back({ lex.point_span(), AST::Path(path), ::std::move(name) }); } @@ -1399,13 +1400,13 @@ void Parse_Use_Inner(TokenStream& lex, ::std::vector& entries } } while( GET_TOK(tok, lex) == TOK_DOUBLE_COLON ); - ::std::string name; + RcString name; // NOTE: The above loop has to run once, so the last token HAS to have been an ident if( tok.type() == TOK_RWORD_AS ) { GET_CHECK_TOK(tok, lex, TOK_IDENT); - name = mv$(tok.str()); + name = tok.istr(); } else { @@ -1455,7 +1456,7 @@ void Parse_Use_Inner(TokenStream& lex, ::std::vector& entries if( LOOK_AHEAD(lex) == TOK_STRING ) { GET_CHECK_TOK(tok, lex, TOK_STRING); - path = ::AST::Path(tok.str(), {}); + path = ::AST::Path(RcString::new_interned(tok.str()), {}); } else { @@ -1478,12 +1479,12 @@ void Parse_Use_Inner(TokenStream& lex, ::std::vector& entries } -::AST::MacroInvocation Parse_MacroInvocation(ProtoSpan span_start, ::std::string name, TokenStream& lex) +::AST::MacroInvocation Parse_MacroInvocation(ProtoSpan span_start, RcString name, TokenStream& lex) { Token tok; - ::std::string ident; + RcString ident; if( GET_TOK(tok, lex) == TOK_IDENT ) { - ident = mv$(tok.str()); + ident = tok.istr(); } else { PUTBACK(tok, lex); @@ -1648,7 +1649,7 @@ namespace { auto ps = lex.start_span(); - ::std::string item_name; + RcString item_name; ::AST::Item item_data; { @@ -1684,7 +1685,7 @@ namespace { // `extern "" fn ...` case TOK_RWORD_FN: { GET_CHECK_TOK(tok, lex, TOK_IDENT); - item_name = mv$(tok.str()); + item_name = tok.istr(); item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, abi, false, false,false) ); break; } // `extern "ABI" {` @@ -1699,7 +1700,7 @@ namespace { // `extern fn ...` case TOK_RWORD_FN: GET_CHECK_TOK(tok, lex, TOK_IDENT); - item_name = mv$(tok.str()); + item_name = tok.istr(); item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, "C", false, false,false) ); break; @@ -1718,20 +1719,20 @@ namespace { // `extern crate "crate-name" as crate_name;` // NOTE: rustc doesn't allow this, keep in mrustc for for reparse support case TOK_STRING: - item_data = ::AST::Item::make_Crate({ tok.str() }); + item_data = ::AST::Item::make_Crate({ RcString::new_interned(tok.str()) }); GET_CHECK_TOK(tok, lex, TOK_RWORD_AS); GET_CHECK_TOK(tok, lex, TOK_IDENT); - item_name = mv$(tok.str()); + item_name = tok.istr(); break; // `extern crate crate_name;` // `extern crate crate_name as other_name;` case TOK_IDENT: - item_name = mv$(tok.str()); + item_name = tok.istr(); if(GET_TOK(tok, lex) == TOK_RWORD_AS) { item_data = ::AST::Item::make_Crate({ mv$(item_name) }); GET_CHECK_TOK(tok, lex, TOK_IDENT); - item_name = mv$(tok.str()); + item_name = tok.istr(); } else { PUTBACK(tok, lex); @@ -1754,7 +1755,7 @@ namespace { switch( GET_TOK(tok, lex) ) { case TOK_IDENT: { - item_name = mv$(tok.str()); + item_name = tok.istr(); GET_CHECK_TOK(tok, lex, TOK_COLON); TypeRef type = Parse_Type(lex); @@ -1766,12 +1767,12 @@ namespace { case TOK_RWORD_UNSAFE: GET_CHECK_TOK(tok, lex, TOK_RWORD_FN); GET_CHECK_TOK(tok, lex, TOK_IDENT); - item_name = mv$(tok.str()); + item_name = tok.istr(); item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, ABI_RUST, false, true,true/*unsafe,const*/) ); break; case TOK_RWORD_FN: GET_CHECK_TOK(tok, lex, TOK_IDENT); - item_name = mv$(tok.str()); + item_name = tok.istr(); // - self not allowed, not prototype item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, ABI_RUST, false, false,true/*unsafe,const*/) ); break; @@ -1788,7 +1789,7 @@ namespace { GET_TOK(tok, lex); } CHECK_TOK(tok, TOK_IDENT); - item_name = mv$(tok.str()); + item_name = tok.istr(); GET_CHECK_TOK(tok, lex, TOK_COLON); TypeRef type = Parse_Type(lex); @@ -1818,20 +1819,20 @@ namespace { } GET_CHECK_TOK(tok, lex, TOK_RWORD_FN); GET_CHECK_TOK(tok, lex, TOK_IDENT); - item_name = mv$(tok.str()); + item_name = tok.istr(); item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, abi, false, true,false/*unsafe,const*/) ); break; } // `unsafe fn` case TOK_RWORD_FN: GET_CHECK_TOK(tok, lex, TOK_IDENT); - item_name = mv$(tok.str()); + item_name = tok.istr(); // - self not allowed, not prototype item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, ABI_RUST, false, true,false/*unsafe,const*/) ); break; // `unsafe trait` case TOK_RWORD_TRAIT: { GET_CHECK_TOK(tok, lex, TOK_IDENT); - item_name = mv$(tok.str()); + item_name = tok.istr(); auto tr = Parse_TraitDef(lex, meta_items); tr.set_is_unsafe(); item_data = ::AST::Item( ::std::move(tr) ); @@ -1852,10 +1853,10 @@ namespace { } // `unsafe auto trait` case TOK_IDENT: - if( TARGETVER_1_29 && tok.str() == "auto" ) { + if( TARGETVER_1_29 && tok.istr() == "auto" ) { GET_CHECK_TOK(tok, lex, TOK_RWORD_TRAIT); GET_CHECK_TOK(tok, lex, TOK_IDENT); - item_name = mv$(tok.str()); + item_name = tok.istr(); auto tr = Parse_TraitDef(lex, meta_items); tr.set_is_unsafe(); tr.set_is_marker(); @@ -1870,40 +1871,40 @@ namespace { // `fn` case TOK_RWORD_FN: GET_CHECK_TOK(tok, lex, TOK_IDENT); - item_name = mv$(tok.str()); + item_name = tok.istr(); // - self not allowed, not prototype item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, ABI_RUST, false, false,false/*unsafe,const*/) ); break; // `type` case TOK_RWORD_TYPE: GET_CHECK_TOK(tok, lex, TOK_IDENT); - item_name = mv$(tok.str()); + item_name = tok.istr(); item_data = ::AST::Item( Parse_TypeAlias(lex) ); break; // `struct` case TOK_RWORD_STRUCT: GET_CHECK_TOK(tok, lex, TOK_IDENT); - item_name = mv$(tok.str()); + item_name = tok.istr(); item_data = ::AST::Item( Parse_Struct(lex, meta_items) ); break; // `enum` case TOK_RWORD_ENUM: GET_CHECK_TOK(tok, lex, TOK_IDENT); - item_name = mv$(tok.str()); + item_name = tok.istr(); item_data = ::AST::Item( Parse_EnumDef(lex, meta_items) ); break; // Contextual keywords case TOK_IDENT: - if( tok.str() == "union" ) { + if( tok.istr() == "union" ) { GET_CHECK_TOK(tok, lex, TOK_IDENT); - item_name = mv$(tok.str()); + item_name = tok.istr(); item_data = ::AST::Item( Parse_Union(lex, meta_items) ); } // `auto trait` - else if( TARGETVER_1_29 && tok.str() == "auto" ) { + else if( TARGETVER_1_29 && tok.istr() == "auto" ) { GET_CHECK_TOK(tok, lex, TOK_RWORD_TRAIT); GET_CHECK_TOK(tok, lex, TOK_IDENT); - item_name = mv$(tok.str()); + item_name = tok.istr(); auto tr = Parse_TraitDef(lex, meta_items); tr.set_is_marker(); item_data = ::AST::Item( ::std::move(tr) ); @@ -1918,7 +1919,7 @@ namespace { // `trait` case TOK_RWORD_TRAIT: GET_CHECK_TOK(tok, lex, TOK_IDENT); - item_name = mv$(tok.str()); + item_name = tok.istr(); item_data = ::AST::Item( Parse_TraitDef(lex, meta_items) ); break; @@ -1926,7 +1927,7 @@ namespace { if( TARGETVER_1_29 ) { GET_CHECK_TOK(tok, lex, TOK_IDENT); - auto name = tok.str(); + auto name = tok.istr(); if( lex.lookahead(0) != TOK_PAREN_OPEN ) { GET_TOK(tok, lex); @@ -1934,7 +1935,7 @@ namespace { } DEBUG("name = " << name); - ::std::vector< ::std::string> names; + ::std::vector names; auto ps = lex.start_span(); GET_CHECK_TOK(tok, lex, TOK_PAREN_OPEN); auto arm_pat = Parse_MacroRules_Pat(lex, TOK_PAREN_OPEN, TOK_PAREN_CLOSE, names); @@ -1966,7 +1967,7 @@ namespace { case TOK_RWORD_MOD: { GET_CHECK_TOK(tok, lex, TOK_IDENT); - auto name = mv$(tok.str()); + auto name = tok.istr(); DEBUG("Sub module '" << name << "'"); AST::Module submod( mod_path + name ); @@ -1992,7 +1993,7 @@ namespace { //submod.m_file_info = get_submod_file(lex.end_span(ps), mod_fileinfo, name, path_attr, LOOK_AHEAD(lex) == TOK_SEMICOLON, H::check_item_cfg(meta_items)); - ::std::string sub_path; + ::helpers::path sub_path; bool sub_file_controls_dir = true; if( mod_fileinfo.path == "-" ) { if( path_attr.size() ) { @@ -2002,15 +2003,15 @@ namespace { } else if( path_attr.size() > 0 ) { - sub_path = dirname(mod_fileinfo.path) + path_attr; + sub_path = dirname(mod_fileinfo.path) / path_attr.c_str(); } else if( mod_fileinfo.controls_dir ) { - sub_path = dirname(mod_fileinfo.path) + name; + sub_path = dirname(mod_fileinfo.path) / name.c_str(); } else { - sub_path = dirname(mod_fileinfo.path) + mod_path.nodes().back().name() + "/" + name; + sub_path = dirname(mod_fileinfo.path) / mod_path.nodes().back().name().c_str() / name.c_str(); //sub_path = mod_fileinfo.path; sub_file_controls_dir = false; } @@ -2022,14 +2023,14 @@ namespace { switch( GET_TOK(tok, lex) ) { case TOK_BRACE_OPEN: - submod.m_file_info.path = sub_path + "/"; + submod.m_file_info.path = sub_path.str() + "/"; // TODO: If cfg fails, just eat the TT until a matching #[cfg]? // - Or, mark the file infor as not being valid (so child modules don't try to load) Parse_ModRoot(lex, submod, meta_items); GET_CHECK_TOK(tok, lex, TOK_BRACE_CLOSE); break; case TOK_SEMICOLON: - if( sub_path == "-" ) { + if( sub_path.str() == "-" ) { ERROR(lex.point_span(), E0000, "Cannot load module from file when reading stdin"); } else if( !H::check_item_cfg(meta_items) ) { @@ -2042,7 +2043,7 @@ namespace { { // TODO: Also search for curmod/submod.rs //::std::string newpath_file = (mod_path.nodes().size() > 1 ? dirname(mod_fileinfo.path) + mod_path.nodes()[mod_path.nodes().size()-2].name() + "/" + name + ".rs" : ""); - ::std::string newpath_file = (mod_path.nodes().size() >= 1 ? dirname(mod_fileinfo.path) + mod_path.nodes()[mod_path.nodes().size()-1].name() + "/" + name + ".rs" : ""); + ::std::string newpath_file = (mod_path.nodes().size() >= 1 ? dirname(mod_fileinfo.path) / mod_path.nodes()[mod_path.nodes().size()-1].name().c_str() / name.c_str() + ".rs" : ""); DEBUG("newpath_file = '" << newpath_file << "' " << mod_fileinfo.path << " " << mod_path); ::std::ifstream ifs_file(newpath_file); if( ifs_file.is_open() ) @@ -2061,7 +2062,7 @@ namespace { } else { - ::std::string newpath_dir = sub_path + "/"; + ::std::string newpath_dir = sub_path.str() + "/"; ::std::string newpath_file = path_attr.size() > 0 ? sub_path : sub_path + ".rs"; DEBUG("newpath_dir = '" << newpath_dir << "', newpath_file = '" << newpath_file << "'"); ::std::ifstream ifs_dir (newpath_dir + "mod.rs"); diff --git a/src/parse/token.cpp b/src/parse/token.cpp index d8a68d88..73ae7d93 100644 --- a/src/parse/token.cpp +++ b/src/parse/token.cpp @@ -52,6 +52,11 @@ Token::Token(enum eTokenType type): m_type(type) { } +Token::Token(enum eTokenType type, RcString str): + m_type(type), + m_data(Data::make_IString(mv$(str))) +{ +} Token::Token(enum eTokenType type, ::std::string str): m_type(type), m_data(Data::make_String(mv$(str))) @@ -163,6 +168,7 @@ Token::Token(const Token& t): assert( t.m_data.tag() != Data::TAGDEAD ); TU_MATCH(Data, (t.m_data), (e), (None, ), + (IString, m_data = Data::make_IString(e); ), (String, m_data = Data::make_String(e); ), (Integer, m_data = Data::make_Integer(e);), (Float, m_data = Data::make_Float(e);), @@ -178,6 +184,9 @@ Token Token::clone() const TU_MATCH(Data, (m_data), (e), (None, ), + (IString, + rv.m_data = Data::make_IString(e); + ), (String, rv.m_data = Data::make_String(e); ), @@ -333,8 +342,8 @@ struct EscapedString { case TOK_INTERPOLATED_IDENT: return "/*:ident*/"; case TOK_INTERPOLATED_VIS: return "/*:vis*/"; // Value tokens - case TOK_IDENT: return m_data.as_String(); - case TOK_LIFETIME: return "'" + m_data.as_String(); + case TOK_IDENT: return m_data.as_IString().c_str(); + case TOK_LIFETIME: return FMT("'" << m_data.as_IString().c_str()); case TOK_INTEGER: if( m_data.as_Integer().m_datatype == CORETYPE_ANY ) { return FMT(m_data.as_Integer().m_intval); diff --git a/src/parse/token.hpp b/src/parse/token.hpp index d5e7a6db..0d9a8015 100644 --- a/src/parse/token.hpp +++ b/src/parse/token.hpp @@ -64,6 +64,7 @@ class Token TAGGED_UNION(Data, None, (None, struct {}), + (IString, RcString), (String, ::std::string), (Integer, struct { enum eCoreType m_datatype; @@ -108,6 +109,7 @@ public: Token(enum eTokenType type); Token(enum eTokenType type, ::std::string str); + Token(enum eTokenType type, RcString str); Token(uint64_t val, enum eCoreType datatype); Token(double val, enum eCoreType datatype); Token(const InterpolatedFragment& ); @@ -115,6 +117,7 @@ public: Token(TagTakeIP, InterpolatedFragment ); enum eTokenType type() const { return m_type; } + const RcString& istr() const { return m_data.as_IString(); } ::std::string& str() { return m_data.as_String(); } const ::std::string& str() const { return m_data.as_String(); } enum eCoreType datatype() const { TU_MATCH_DEF(Data, (m_data), (e), (assert(!"Getting datatype of invalid token type");), (Integer, return e.m_datatype;), (Float, return e.m_datatype;)) throw ""; } @@ -135,6 +138,7 @@ public: return false; TU_MATCH(Data, (m_data, r.m_data), (e, re), (None, return true;), + (IString, return e == re; ), (String, return e == re; ), (Integer, return e.m_datatype == re.m_datatype && e.m_intval == re.m_intval;), (Float, return e.m_datatype == re.m_datatype && e.m_floatval == re.m_floatval;), diff --git a/src/parse/tokenstream.cpp b/src/parse/tokenstream.cpp index 611df2ff..957bc673 100644 --- a/src/parse/tokenstream.cpp +++ b/src/parse/tokenstream.cpp @@ -138,11 +138,11 @@ Span TokenStream::point_span() const Ident TokenStream::get_ident(Token tok) const { if(tok.type() == TOK_IDENT) { - return Ident(getHygiene(), tok.str()); + return Ident(getHygiene(), tok.istr()); } else if(tok.type() == TOK_LIFETIME) { // TODO: Maybe only when it's explicitly asked for? - return Ident(getHygiene(), tok.str()); + return Ident(getHygiene(), tok.istr()); } else if( tok.type() == TOK_INTERPOLATED_IDENT ) { TODO(getPosition(), "get_ident from TOK_INTERPOLATED_IDENT"); diff --git a/src/parse/types.cpp b/src/parse/types.cpp index d261c403..979a8045 100644 --- a/src/parse/types.cpp +++ b/src/parse/types.cpp @@ -83,9 +83,9 @@ TypeRef Parse_Type_Int(TokenStream& lex, bool allow_trait_list) { lex.getToken(); // TODO: path macros - return TypeRef(TypeRef::TagMacro(), Parse_MacroInvocation(ps, mv$(tok.str()), lex)); + return TypeRef(TypeRef::TagMacro(), Parse_MacroInvocation(ps, tok.istr(), lex)); } - if( TARGETVER_1_29 && tok.str() == "dyn" ) + if( TARGETVER_1_29 && tok.istr() == "dyn" ) { if( lex.lookahead(0) == TOK_PAREN_OPEN ) { GET_TOK(tok, lex); @@ -283,16 +283,17 @@ TypeRef Parse_Type_Path(TokenStream& lex, ::AST::HigherRankedBounds hrbs, bool a auto ps = lex.start_span(); + auto path = Parse_Path(lex, PATH_GENERIC_TYPE); if( hrbs.empty() && !allow_trait_list ) { - return TypeRef(TypeRef::TagPath(), lex.end_span(ps), Parse_Path(lex, PATH_GENERIC_TYPE)); + return TypeRef(TypeRef::TagPath(), lex.end_span(ps), mv$(path)); } else { ::std::vector traits; ::std::vector lifetimes; - traits.push_back(Type_TraitPath { mv$(hrbs), Parse_Path(lex, PATH_GENERIC_TYPE) }); + traits.push_back(Type_TraitPath { mv$(hrbs), mv$(path) }); if( allow_trait_list ) { diff --git a/src/rc_string.cpp b/src/rc_string.cpp index 46f36923..0d7e253a 100644 --- a/src/rc_string.cpp +++ b/src/rc_string.cpp @@ -7,17 +7,18 @@ */ #include #include +#include #include RcString::RcString(const char* s, unsigned int len): - m_ptr(nullptr), - m_len(len) + m_ptr(nullptr) { if( len > 0 ) { - m_ptr = new unsigned int[1 + (len+1 + sizeof(unsigned int)-1) / sizeof(unsigned int)]; - *m_ptr = 1; - char* data_mut = reinterpret_cast(m_ptr + 1); + m_ptr = new unsigned int[2 + (len+1 + sizeof(unsigned int)-1) / sizeof(unsigned int)]; + m_ptr[0] = 1; + m_ptr[1] = len; + char* data_mut = reinterpret_cast(m_ptr + 2); for(unsigned int j = 0; j < len; j ++ ) data_mut[j] = s[j]; data_mut[len] = '\0'; @@ -36,14 +37,104 @@ RcString::~RcString() } } } +Ordering RcString::ord(const RcString& x) const +{ + if( m_ptr == x.m_ptr ) + return OrdEqual; + // Both can't be empty/null + if( m_ptr == nullptr ) + return OrdLess; + if( x.m_ptr == nullptr ) + return OrdGreater; + + assert(x.size() > 0); + assert(this->size() > 0); + + auto xp = x.c_str(); + auto tp = this->c_str(); + for(size_t i = 0; i < ::std::min(this->size(), x.size()); i ++) + { + if( *xp != *tp ) + return ::ord((unsigned)*xp, (unsigned)*tp); + xp ++; + tp ++; + } + return ::ord((unsigned)this->size(), (unsigned)x.size()); +} +Ordering RcString::ord(const std::string& x) const +{ + if( m_ptr == nullptr && x.size() == 0 ) + return OrdEqual; + // Both can't be empty/null + if( m_ptr == nullptr ) + return OrdLess; + if( x.empty() ) + return OrdGreater; + + assert(x.size() > 0); + assert(this->size() > 0); + + auto xp = x.c_str(); + auto tp = this->c_str(); + for(size_t i = 0; i < ::std::min(this->size(), x.size()); i ++) + { + if( *xp != *tp ) + return ::ord((unsigned)*xp, (unsigned)*tp); + xp ++; + tp ++; + } + return ::ord((unsigned)this->size(), (unsigned)x.size()); +} bool RcString::operator==(const char* s) const { - if( m_len == 0 ) + if( m_ptr == nullptr ) return *s == '\0'; - auto m = this->c_str(); - do { - if( *m != *s ) + const char* ts = this->c_str(); + const char* end = ts + this->size(); + // Loop while not at the end of either + while(s && ts != end) + { + if( *s != *ts ) return false; - } while( *m++ != '\0' && *s++ != '\0' ); - return true; + s ++; + ts ++; + } + // Only equal if we're at the end of both strings + return *s == '\0' && ts == end; +} + +::std::ostream& operator<<(::std::ostream& os, const RcString& x) +{ + for(size_t i = 0; i < x.size(); i ++) + { + os << x.c_str()[i]; + } + return os; +} + + +::std::set RcString_interned_strings; + +RcString RcString::new_interned(const ::std::string& s) +{ +#if 0 + auto it = RcString_interned_strings.find(s); + if( it == RcString_interned_strings.end() ) + { + it = RcString_interned_strings.insert(RcString(s)).first; + } + return *it; +#else + return *RcString_interned_strings.insert(RcString(s)).first; +#endif +} + +size_t std::hash::operator()(const RcString& s) const noexcept +{ + size_t h = 5381; + for(auto c : s) { + h = h * 33 + (unsigned)c; + } + return h; + //return hash(s.c_str(), s.size()); } diff --git a/src/resolve/absolute.cpp b/src/resolve/absolute.cpp index c2dedfcb..d26bb699 100644 --- a/src/resolve/absolute.cpp +++ b/src/resolve/absolute.cpp @@ -41,7 +41,7 @@ namespace template struct Named { - ::std::string name; + RcString name; Val value; }; template @@ -300,7 +300,7 @@ namespace } return ""; } - AST::Path lookup(const Span& sp, const ::std::string& name, const Ident::Hygiene& src_context, LookupMode mode) const { + AST::Path lookup(const Span& sp, const RcString& name, const Ident::Hygiene& src_context, LookupMode mode) const { auto rv = this->lookup_opt(name, src_context, mode); if( !rv.is_valid() ) { switch(mode) @@ -314,7 +314,7 @@ namespace } return rv; } - static bool lookup_in_mod(const ::AST::Module& mod, const ::std::string& name, LookupMode mode, ::AST::Path& path) { + static bool lookup_in_mod(const ::AST::Module& mod, const RcString& name, LookupMode mode, ::AST::Path& path) { switch(mode) { case LookupMode::Namespace: @@ -422,7 +422,7 @@ namespace } return false; } - AST::Path lookup_opt(const ::std::string& name, const Ident::Hygiene& src_context, LookupMode mode) const { + AST::Path lookup_opt(const RcString& name, const Ident::Hygiene& src_context, LookupMode mode) const { DEBUG("name=" << name <<", src_context=" << src_context); // NOTE: src_context may provide a module to search if( src_context.has_mod_path() ) @@ -513,7 +513,7 @@ namespace case LookupMode::Namespace: case LookupMode::Type: { // Look up primitive types - auto ct = coretype_fromstring(name); + auto ct = coretype_fromstring(name.c_str()); if( ct != CORETYPE_INVAL ) { return ::AST::Path( ::AST::Path::TagUfcs(), TypeRef(Span("-",0,0,0,0), ct), ::AST::Path(), ::std::vector< ::AST::PathNode>() ); @@ -538,7 +538,7 @@ namespace return AST::Path(); } - unsigned int lookup_local(const Span& sp, const ::std::string name, LookupMode mode) { + unsigned int lookup_local(const Span& sp, const RcString name, LookupMode mode) { for(auto it = m_name_context.rbegin(); it != m_name_context.rend(); ++ it) { TU_MATCH(Ent, (*it), (e), @@ -732,7 +732,7 @@ void Resolve_Absolute_Path_BindUFCS(Context& context, const Span& sp, Context::L } namespace { - AST::Path split_into_crate(const Span& sp, AST::Path path, unsigned int start, const ::std::string& crate_name) + AST::Path split_into_crate(const Span& sp, AST::Path path, unsigned int start, const RcString& crate_name) { auto& nodes = path.nodes(); AST::Path np = AST::Path(crate_name, {}); @@ -1146,7 +1146,7 @@ void Resolve_Absolute_Path_BindAbsolute(Context& context, const Span& sp, Contex { auto& n = path_abs.nodes[i]; - if( n.name()[0] == '#' ) { + if( n.name().c_str()[0] == '#' ) { if( ! n.args().is_empty() ) { ERROR(sp, E0000, "Type parameters were not expected here"); } @@ -1157,7 +1157,7 @@ void Resolve_Absolute_Path_BindAbsolute(Context& context, const Span& sp, Contex char c; unsigned int idx; - ::std::stringstream ss( n.name() ); + ::std::stringstream ss( n.name().c_str() ); ss >> c; ss >> idx; assert( idx < mod->anon_mods().size() ); @@ -1367,7 +1367,7 @@ void Resolve_Absolute_Path(/*const*/ Context& context, const Span& sp, Context:: // HACK: If this is a primitive name, and resolved to a module. // - If the next component isn't found in the located module // > Instead use the type name. - if( ! p.m_class.is_Local() && coretype_fromstring(e.nodes[0].name()) != CORETYPE_INVAL ) { + if( ! p.m_class.is_Local() && coretype_fromstring(e.nodes[0].name().c_str()) != CORETYPE_INVAL ) { if( const auto* pep = p.m_bindings.type.opt_Module() ) { const auto& pe = *pep; bool found = false; @@ -1421,7 +1421,7 @@ void Resolve_Absolute_Path(/*const*/ Context& context, const Span& sp, Context:: } if( !found ) { - auto ct = coretype_fromstring(e.nodes[0].name()); + auto ct = coretype_fromstring(e.nodes[0].name().c_str()); p = ::AST::Path( ::AST::Path::TagUfcs(), TypeRef(Span("-",0,0,0,0), ct), ::AST::Path(), ::std::vector< ::AST::PathNode>() ); } @@ -1467,7 +1467,7 @@ void Resolve_Absolute_Path(/*const*/ Context& context, const Span& sp, Context:: const auto& mp_nodes = context.m_mod.path().nodes(); // Ignore any leading anon modules unsigned int start_len = mp_nodes.size(); - while( start_len > 0 && mp_nodes[start_len-1].name()[0] == '#' ) + while( start_len > 0 && mp_nodes[start_len-1].name().c_str()[0] == '#' ) start_len --; // - Create a new path @@ -1491,7 +1491,7 @@ void Resolve_Absolute_Path(/*const*/ Context& context, const Span& sp, Context:: assert( e.count >= 1 ); // TODO: The first super should ignore any anon modules. unsigned int start_len = e.count > mp_nodes.size() ? 0 : mp_nodes.size() - e.count; - while( start_len > 0 && mp_nodes[start_len-1].name()[0] == '#' ) + while( start_len > 0 && mp_nodes[start_len-1].name().c_str()[0] == '#' ) start_len --; // - Create a new path diff --git a/src/resolve/index.cpp b/src/resolve/index.cpp index 43182faf..45fb58f5 100644 --- a/src/resolve/index.cpp +++ b/src/resolve/index.cpp @@ -32,7 +32,7 @@ void Resolve_Index_Module_Wildcard__use_stmt(AST::Crate& crate, AST::Module& dst } throw ""; } -::std::unordered_map< ::std::string, ::AST::Module::IndexEnt >& get_mod_index(::AST::Module& mod, IndexName location) { +::std::unordered_map< RcString, ::AST::Module::IndexEnt >& get_mod_index(::AST::Module& mod, IndexName location) { switch(location) { case IndexName::Namespace: @@ -57,7 +57,7 @@ namespace { } } // namespace -void _add_item(const Span& sp, AST::Module& mod, IndexName location, const ::std::string& name, bool is_pub, ::AST::Path ir, bool error_on_collision=true) +void _add_item(const Span& sp, AST::Module& mod, IndexName location, const RcString& name, bool is_pub, ::AST::Path ir, bool error_on_collision=true) { ASSERT_BUG(sp, ir.m_bindings.has_binding(), ""); auto& list = get_mod_index(mod, location); @@ -90,12 +90,12 @@ void _add_item(const Span& sp, AST::Module& mod, IndexName location, const ::std assert(rec.second); } } -void _add_item_type(const Span& sp, AST::Module& mod, const ::std::string& name, bool is_pub, ::AST::Path ir, bool error_on_collision=true) +void _add_item_type(const Span& sp, AST::Module& mod, const RcString& name, bool is_pub, ::AST::Path ir, bool error_on_collision=true) { _add_item(sp, mod, IndexName::Namespace, name, is_pub, ::AST::Path(ir), error_on_collision); _add_item(sp, mod, IndexName::Type, name, is_pub, mv$(ir), error_on_collision); } -void _add_item_value(const Span& sp, AST::Module& mod, const ::std::string& name, bool is_pub, ::AST::Path ir, bool error_on_collision=true) +void _add_item_value(const Span& sp, AST::Module& mod, const RcString& name, bool is_pub, ::AST::Path ir, bool error_on_collision=true) { _add_item(sp, mod, IndexName::Value, name, is_pub, mv$(ir), error_on_collision); } @@ -237,7 +237,7 @@ void Resolve_Index_Module_Base(const AST::Crate& crate, AST::Module& mod) DEBUG(i_data.name << " - Not a macro"); } TU_ARMA(MacroRules, e) { - ::std::vector<::std::string> path; + ::std::vector path; path.push_back( i_data.path.m_class.as_Absolute().crate ); for(const auto& node : i_data.path.m_class.as_Absolute().nodes ) path.push_back( node.name() ); diff --git a/src/resolve/use.cpp b/src/resolve/use.cpp index 95e6d2c1..cde9cd5f 100644 --- a/src/resolve/use.cpp +++ b/src/resolve/use.cpp @@ -51,7 +51,7 @@ void Resolve_Use(::AST::Crate& crate) // How can this happen? DEBUG("Relative " << path); // EVIL HACK: If the current module is an anon module, refer to the parent - if( base_path.nodes().size() > 0 && base_path.nodes().back().name()[0] == '#' ) { + if( base_path.nodes().size() > 0 && base_path.nodes().back().name().c_str()[0] == '#' ) { AST::Path np("", {}); for( unsigned int i = 0; i < base_path.nodes().size() - 1; i ++ ) np.nodes().push_back( base_path.nodes()[i] ); @@ -65,7 +65,7 @@ void Resolve_Use(::AST::Crate& crate) (Self, DEBUG("Self " << path); // EVIL HACK: If the current module is an anon module, refer to the parent - if( base_path.nodes().size() > 0 && base_path.nodes().back().name()[0] == '#' ) { + if( base_path.nodes().size() > 0 && base_path.nodes().back().name().c_str()[0] == '#' ) { AST::Path np("", {}); for( unsigned int i = 0; i < base_path.nodes().size() - 1; i ++ ) np.nodes().push_back( base_path.nodes()[i] ); @@ -86,7 +86,7 @@ void Resolve_Use(::AST::Crate& crate) // TODO: Do this in a cleaner manner. unsigned int n_anon = 0; // Skip any anon modules in the way (i.e. if the current module is an anon, go to the parent) - while( base_path.nodes().size() > n_anon && base_path.nodes()[ base_path.nodes().size()-1-n_anon ].name()[0] == '#' ) + while( base_path.nodes().size() > n_anon && base_path.nodes()[ base_path.nodes().size()-1-n_anon ].name().c_str()[0] == '#' ) n_anon ++; for( unsigned int i = 0; i < base_path.nodes().size() - e.count - n_anon; i ++ ) np.nodes().push_back( base_path.nodes()[i] ); @@ -252,13 +252,13 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path ::AST::Path::Bindings Resolve_Use_GetBinding_Mod( const Span& span, const ::AST::Crate& crate, const ::AST::Path& source_mod_path, const ::AST::Module& mod, - const ::std::string& des_item_name, + const RcString& des_item_name, ::std::span< const ::AST::Module* > parent_modules ) { ::AST::Path::Bindings rv; // If the desired item is an anon module (starts with #) then parse and index - if( des_item_name.size() > 0 && des_item_name[0] == '#' ) { + if( des_item_name.size() > 0 && des_item_name.c_str()[0] == '#' ) { unsigned int idx = 0; if( ::std::sscanf(des_item_name.c_str(), "#%u", &idx) != 1 ) { BUG(span, "Invalid anon path segment '" << des_item_name << "'"); @@ -283,6 +283,9 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path (MacroInv, BUG(span, "Hit MacroInv in use resolution"); ), + (Macro, + //rv.macro = ::AST::PathBinding_Macro::make_MacroRules({nullptr, e.get()}); + ), (Use, continue; // Skip for now ), @@ -479,7 +482,7 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path return rv; } - if( mod.path().nodes().size() > 0 && mod.path().nodes().back().name()[0] == '#' ) { + if( mod.path().nodes().size() > 0 && mod.path().nodes().back().name().c_str()[0] == '#' ) { assert( parent_modules.size() > 0 ); return Resolve_Use_GetBinding_Mod(span, crate, source_mod_path, *parent_modules.back(), des_item_name, parent_modules.subspan(0, parent_modules.size()-1)); } @@ -754,8 +757,8 @@ namespace { if( path.m_class.is_Absolute() && path.m_class.as_Absolute().crate != "" ) { const auto& path_abs = path.m_class.as_Absolute(); - ASSERT_BUG(span, crate.m_extern_crates.count(path_abs.crate), "Crate '" << path_abs.crate << "' not loaded"); - return Resolve_Use_GetBinding__ext(span, crate, path, crate.m_extern_crates.at( path_abs.crate ), 0); + ASSERT_BUG(span, crate.m_extern_crates.count(path_abs.crate.c_str()), "Crate '" << path_abs.crate << "' not loaded"); + return Resolve_Use_GetBinding__ext(span, crate, path, crate.m_extern_crates.at( path_abs.crate.c_str() ), 0); } ::AST::Path::Bindings rv; diff --git a/src/trans/auto_impls.cpp b/src/trans/auto_impls.cpp index ec4b8a42..07a52857 100644 --- a/src/trans/auto_impls.cpp +++ b/src/trans/auto_impls.cpp @@ -199,7 +199,7 @@ void Trans_AutoImpl_Clone(State& state, ::HIR::TypeRef ty) // Impl ::HIR::TraitImpl impl; impl.m_type = mv$(ty); - impl.m_methods.insert(::std::make_pair( ::std::string("clone"), ::HIR::TraitImpl::ImplEnt< ::HIR::Function> { false, ::std::move(fcn) } )); + impl.m_methods.insert(::std::make_pair( RcString::new_interned("clone"), ::HIR::TraitImpl::ImplEnt< ::HIR::Function> { false, ::std::move(fcn) } )); // Add impl to the crate state.crate.m_trait_impls.insert(::std::make_pair( state.lang_Clone, ::std::move(impl) )); diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index b229db8b..09b63f44 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -2187,8 +2187,7 @@ namespace { } { - auto vtable_sp = trait_path.m_path; - vtable_sp.m_components.back() += "#vtable"; + const auto& vtable_sp = trait.m_vtable_path; auto vtable_params = trait_path.m_params.clone(); for(const auto& ty : trait.m_type_indexes) { auto aty = ::HIR::TypeRef( ::HIR::Path( type.clone(), trait_path.clone(), ty.first ) ); @@ -4055,7 +4054,7 @@ namespace { } } - void emit_intrinsic_call(const ::std::string& name, const ::HIR::PathParams& params, const ::MIR::Terminator::Data_Call& e) + void emit_intrinsic_call(const RcString& name, const ::HIR::PathParams& params, const ::MIR::Terminator::Data_Call& e) { const auto& mir_res = *m_mir_res; enum class Ordering @@ -4088,7 +4087,7 @@ namespace { } throw ""; }; - auto get_atomic_ordering = [&](const ::std::string& name, size_t prefix_len)->Ordering { + auto get_atomic_ordering = [&](const RcString& name, size_t prefix_len)->Ordering { if( name.size() < prefix_len ) { return Ordering::SeqCst; @@ -5024,7 +5023,7 @@ namespace { || name == "atomic_min" || name.compare(0, 7+3+1, "atomic_min_") == 0 ) { auto ordering = get_atomic_ordering(name, 7+3+1); const auto& ty = params.m_types.at(0); - const char* op = (name[7+1] == 'a' ? "imax" : "imin"); // m'a'x vs m'i'n + const char* op = (name.c_str()[7+1] == 'a' ? "imax" : "imin"); // m'a'x vs m'i'n emit_lvalue(e.ret_val); m_of << " = __mrustc_atomicloop" << get_prim_size(ty) << "("; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", " << get_atomic_ty_gcc(ordering) << ", __mrustc_op_" << op << get_prim_size(ty); m_of << ")"; @@ -5033,7 +5032,7 @@ namespace { || name == "atomic_umin" || name.compare(0, 7+4+1, "atomic_umin_") == 0 ) { auto ordering = get_atomic_ordering(name, 7+4+1); const auto& ty = params.m_types.at(0); - const char* op = (name[7+2] == 'a' ? "umax" : "umin"); // m'a'x vs m'i'n + const char* op = (name.c_str()[7+2] == 'a' ? "umax" : "umin"); // m'a'x vs m'i'n emit_lvalue(e.ret_val); m_of << " = __mrustc_atomicloop" << get_prim_size(ty) << "("; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", " << get_atomic_ty_gcc(ordering) << ", __mrustc_op_" << op << get_prim_size(ty); m_of << ")"; diff --git a/src/trans/codegen_mmir.cpp b/src/trans/codegen_mmir.cpp index 032e6afa..50d36a8a 100644 --- a/src/trans/codegen_mmir.cpp +++ b/src/trans/codegen_mmir.cpp @@ -328,9 +328,9 @@ namespace const auto& te = t.m_data.as_TraitObject(); //auto vtp = t.m_data.as_TraitObject().m_trait.m_path; - auto vtable_gp = te.m_trait.m_path.clone(); - vtable_gp.m_path.m_components.back() += "#vtable"; const auto& trait = resolve.m_crate.get_trait_by_path(sp, te.m_trait.m_path.m_path); + auto vtable_gp = ::HIR::GenericPath(trait.m_vtable_path); + vtable_gp.m_params = te.m_trait.m_path.m_params.clone(); vtable_gp.m_params.m_types.resize( vtable_gp.m_params.m_types.size() + trait.m_type_indexes.size() ); for(const auto& ty : trait.m_type_indexes) { auto aty = te.m_trait.m_type_bounds.at(ty.first).clone(); @@ -948,8 +948,7 @@ namespace ::HIR::TypeRef vtable_ty; { - auto vtable_sp = trait_path.m_path; - vtable_sp.m_components.back() += "#vtable"; + const auto& vtable_sp = trait.m_vtable_path; auto vtable_params = trait_path.m_params.clone(); for(const auto& ty : trait.m_type_indexes) { auto aty = ::HIR::TypeRef( ::HIR::Path( type.clone(), trait_path.clone(), ty.first ) ); diff --git a/src/trans/enumerate.cpp b/src/trans/enumerate.cpp index 4567c0e7..a2ecb408 100644 --- a/src/trans/enumerate.cpp +++ b/src/trans/enumerate.cpp @@ -592,8 +592,7 @@ namespace { const auto& trait = *te.m_trait.m_trait_ptr; ASSERT_BUG(Span(), ! te.m_trait.m_path.m_path.m_components.empty(), "TODO: Data trait is empty, what can be done?"); - auto vtable_ty_spath = te.m_trait.m_path.m_path; - vtable_ty_spath.m_components.back() += "#vtable"; + const auto& vtable_ty_spath = trait.m_vtable_path; const auto& vtable_ref = m_crate.get_struct_by_path(sp, vtable_ty_spath); // Copy the param set from the trait in the trait object ::HIR::PathParams vtable_params = te.m_trait.m_path.m_params.clone(); @@ -1039,8 +1038,7 @@ void Trans_Enumerate_Types(EnumState& state) const auto& gpath = ent.first.m_data.as_UfcsKnown().trait; const auto& trait = state.crate.get_trait_by_path(sp, gpath.m_path); - auto vtable_ty_spath = gpath.m_path; - vtable_ty_spath.m_components.back() += "#vtable"; + const auto& vtable_ty_spath = trait.m_vtable_path; const auto& vtable_ref = state.crate.get_struct_by_path(sp, vtable_ty_spath); // Copy the param set from the trait in the trait object ::HIR::PathParams vtable_params = gpath.m_params.clone(); @@ -1775,7 +1773,7 @@ namespace { TU_IFLET( ::HIR::ValueItem, vi.second->ent, Function, i, if( i.m_code.m_mir && i.m_linkage.name != "" && i.m_linkage.name == name ) { - out_path = (mod_path + vi.first.c_str()).get_simple_path(); + out_path = (mod_path + vi.first).get_simple_path(); return &i; } ) @@ -1784,7 +1782,7 @@ namespace { for(const auto& ti : mod.m_mod_items) { TU_IFLET( ::HIR::TypeItem, ti.second->ent, Module, i, - if( auto rv = find_function_by_link_name(i, mod_path + ti.first.c_str(), name, out_path) ) + if( auto rv = find_function_by_link_name(i, mod_path + ti.first, name, out_path) ) return rv; ) } diff --git a/src/trans/mangling.cpp b/src/trans/mangling.cpp index 741d13dd..5d7584ed 100644 --- a/src/trans/mangling.cpp +++ b/src/trans/mangling.cpp @@ -22,18 +22,27 @@ #include namespace { - ::std::string escape_str(const ::std::string& s) { + ::std::string escape_str(const char* s, size_t len) { ::std::string output; - output.reserve(s.size() + 1); - for(auto v : s) + output.reserve(len + 1); + for(auto vp = s; vp != s + len; vp ++) + { + auto v= *vp; if( v == '#' ) output += "$H"; else if( v == '-' ) output += "_"; else output += v; + } return output; } + ::std::string escape_str(const RcString& s) { + return escape_str(s.c_str(), s.size()); + } + ::std::string escape_str(const ::std::string& s) { + return escape_str(s.c_str(), s.size()); + } ::FmtLambda emit_params(const ::HIR::PathParams& params) { return FMT_CB(ss, -- cgit v1.2.3 From 84a9e0b722ac2b56a958720330592bc9e5ed7633 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Tue, 21 May 2019 18:58:23 +0800 Subject: rc_string - Use memcmp/strcmp (faster) --- src/include/rc_string.hpp | 16 ++++++++--- src/rc_string.cpp | 71 +++++++++++++---------------------------------- 2 files changed, 31 insertions(+), 56 deletions(-) diff --git a/src/include/rc_string.hpp b/src/include/rc_string.hpp index 94b6d9e7..2177e614 100644 --- a/src/include/rc_string.hpp +++ b/src/include/rc_string.hpp @@ -85,7 +85,12 @@ public: return *(c_str() + size() - 1); } - Ordering ord(const RcString& s) const; + Ordering ord(const char* s, size_t l) const; + Ordering ord(const RcString& s) const { + if( m_ptr == s.m_ptr ) + return OrdEqual; + return ord(s.c_str(), s.size()); + } bool operator==(const RcString& s) const { if(s.size() != this->size()) return false; @@ -99,13 +104,16 @@ public: bool operator<(const RcString& s) const { return this->ord(s) == OrdLess; } bool operator>(const RcString& s) const { return this->ord(s) == OrdGreater; } - Ordering ord(const std::string& s) const; + Ordering ord(const std::string& s) const { return ord(s.data(), s.size()); } bool operator==(const std::string& s) const { return this->ord(s) == OrdEqual; } bool operator!=(const std::string& s) const { return this->ord(s) != OrdEqual; } bool operator<(const std::string& s) const { return this->ord(s) == OrdLess; } bool operator>(const std::string& s) const { return this->ord(s) == OrdGreater; } - bool operator==(const char* s) const; - bool operator!=(const char* s) const { return !(*this == s); } + + Ordering ord(const char* s) const; + bool operator==(const char* s) const { return this->ord(s) == OrdEqual; } + bool operator!=(const char* s) const { return this->ord(s) != OrdEqual; } + friend ::std::ostream& operator<<(::std::ostream& os, const RcString& x); friend bool operator==(const char* a, const RcString& b) { diff --git a/src/rc_string.cpp b/src/rc_string.cpp index 0d7e253a..123b4254 100644 --- a/src/rc_string.cpp +++ b/src/rc_string.cpp @@ -37,70 +37,35 @@ RcString::~RcString() } } } -Ordering RcString::ord(const RcString& x) const +Ordering RcString::ord(const char* s, size_t len) const { - if( m_ptr == x.m_ptr ) - return OrdEqual; - // Both can't be empty/null if( m_ptr == nullptr ) - return OrdLess; - if( x.m_ptr == nullptr ) + return (len == 0 ? OrdEqual : OrdLess); + if( len == 0 ) return OrdGreater; - assert(x.size() > 0); assert(this->size() > 0); + assert(len > 0); - auto xp = x.c_str(); - auto tp = this->c_str(); - for(size_t i = 0; i < ::std::min(this->size(), x.size()); i ++) - { - if( *xp != *tp ) - return ::ord((unsigned)*xp, (unsigned)*tp); - xp ++; - tp ++; - } - return ::ord((unsigned)this->size(), (unsigned)x.size()); + int cmp = memcmp(this->c_str(), s, ::std::min(len, this->size())); + if(cmp == 0) + return ::ord(this->size(), len); + return ::ord(cmp, 0); } -Ordering RcString::ord(const std::string& x) const +Ordering RcString::ord(const char* s) const { - if( m_ptr == nullptr && x.size() == 0 ) - return OrdEqual; - // Both can't be empty/null if( m_ptr == nullptr ) - return OrdLess; - if( x.empty() ) - return OrdGreater; - - assert(x.size() > 0); - assert(this->size() > 0); + return (*s == '\0' ? OrdEqual : OrdLess); - auto xp = x.c_str(); - auto tp = this->c_str(); - for(size_t i = 0; i < ::std::min(this->size(), x.size()); i ++) - { - if( *xp != *tp ) - return ::ord((unsigned)*xp, (unsigned)*tp); - xp ++; - tp ++; - } - return ::ord((unsigned)this->size(), (unsigned)x.size()); -} -bool RcString::operator==(const char* s) const -{ - if( m_ptr == nullptr ) - return *s == '\0'; - const char* ts = this->c_str(); - const char* end = ts + this->size(); - // Loop while not at the end of either - while(s && ts != end) + int cmp = strncmp(this->c_str(), s, this->size()); + if( cmp == 0 ) { - if( *s != *ts ) - return false; - s ++; - ts ++; + if( s[this->size()] == '\0' ) + return OrdEqual; + else + return OrdLess; } - // Only equal if we're at the end of both strings - return *s == '\0' && ts == end; + return ::ord(cmp, 0); } ::std::ostream& operator<<(::std::ostream& os, const RcString& x) @@ -125,12 +90,14 @@ RcString RcString::new_interned(const ::std::string& s) } return *it; #else + // TODO: interning flag, so comparisons can just be a pointer comparison return *RcString_interned_strings.insert(RcString(s)).first; #endif } size_t std::hash::operator()(const RcString& s) const noexcept { + // http://www.cse.yorku.ca/~oz/hash.html "djb2" size_t h = 5381; for(auto c : s) { h = h * 33 + (unsigned)c; -- cgit v1.2.3 From 865235c09f8e5ccf9cc7714428dc64036a9e3ea9 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 24 May 2019 22:39:06 +0800 Subject: Expand derive - Code cleanup --- src/expand/derive.cpp | 417 +++++++++++++++++++++------------------------- src/include/rc_string.hpp | 2 +- src/rc_string.cpp | 16 ++ 3 files changed, 207 insertions(+), 228 deletions(-) diff --git a/src/expand/derive.cpp b/src/expand/derive.cpp index 6dea3028..cc3b3cd0 100644 --- a/src/expand/derive.cpp +++ b/src/expand/derive.cpp @@ -58,20 +58,95 @@ static inline ::std::vector vec$(T v1, T v2, T v3, T v4, T v5) { tmp.push_back( mv$(v5) ); return mv$(tmp); } -static AST::Path get_path(const RcString& core_name, ::std::string c1, ::std::string c2) +static AST::Path get_path(const RcString& core_name, const char* c1, const char* c2) { return AST::Path(core_name, { AST::PathNode(RcString::new_interned(c1), {}), AST::PathNode(RcString::new_interned(c2), {}) }); } -static AST::Path get_path(const RcString& core_name, ::std::string c1, ::std::string c2, ::std::string c3) +static AST::Path get_path(const RcString& core_name, const char* c1, const char* c2, const char* c3) { return AST::Path(core_name, { AST::PathNode(RcString::new_interned(c1), {}), AST::PathNode(RcString::new_interned(c2), {}), AST::PathNode(RcString::new_interned(c3), {}) }); } - static inline AST::ExprNodeP mk_exprnodep(AST::ExprNode* en){ return AST::ExprNodeP(en); } //#define NEWNODE(type, ...) mk_exprnodep(new type(__VA_ARGS__)) #define NEWNODE(type, ...) mk_exprnodep(new AST::ExprNode_##type(__VA_ARGS__)) +static ::std::vector make_refpat_a( + const Span& sp, + ::std::vector& pats_a, + const ::std::vector& sub_types, + ::std::function cb + ) +{ + ::std::vector nodes; + for( size_t idx = 0; idx < sub_types.size(); idx ++ ) + { + auto name_a = RcString::new_interned(FMT("a" << idx)); + pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) ); + nodes.push_back( cb(idx, NEWNODE(NamedValue, AST::Path(name_a))) ); + } + return nodes; +} +static ::std::vector make_refpat_a( + const Span& sp, + ::std::vector< ::std::pair >& pats_a, + const ::std::vector& fields, + ::std::function cb + ) +{ + ::std::vector nodes; + size_t idx = 0; + for( const auto& fld : fields ) + { + auto name_a = RcString::new_interned(FMT("a" << fld.m_name)); + pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF)) ); + nodes.push_back( cb(idx, NEWNODE(NamedValue, AST::Path(name_a))) ); + idx ++; + } + return nodes; +} +static ::std::vector make_refpat_ab( + const Span& sp, + ::std::vector& pats_a, + ::std::vector& pats_b, + const ::std::vector& sub_types, + ::std::function cb + ) +{ + ::std::vector nodes; + for( size_t idx = 0; idx < sub_types.size(); idx ++ ) + { + auto name_a = RcString::new_interned(FMT("a" << idx)); + auto name_b = RcString::new_interned(FMT("b" << idx)); + pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) ); + pats_b.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_b, ::AST::PatternBinding::Type::REF) ); + nodes.push_back( cb(idx, NEWNODE(NamedValue, AST::Path(name_a)), NEWNODE(NamedValue, AST::Path(name_b))) ); + } + return nodes; +} +static ::std::vector make_refpat_ab( + const Span& sp, + ::std::vector< ::std::pair >& pats_a, + ::std::vector< ::std::pair >& pats_b, + const ::std::vector& fields, + ::std::function cb + ) +{ + ::std::vector nodes; + size_t idx = 0; + for( const auto& fld : fields ) + { + auto name_a = RcString::new_interned(FMT("a" << fld.m_name)); + auto name_b = RcString::new_interned(FMT("b" << fld.m_name)); + pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF)) ); + pats_b.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_b, ::AST::PatternBinding::Type::REF)) ); + nodes.push_back( cb(idx, NEWNODE(NamedValue, AST::Path(name_a)), NEWNODE(NamedValue, AST::Path(name_b))) ); + idx ++; + } + return nodes; +} + + struct DeriveOpts { RcString core_name; @@ -299,19 +374,18 @@ class Deriver_Debug: AST::Impl make_ret(Span sp, const RcString& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector types_to_bound, AST::ExprNodeP node) const { - const AST::Path debug_trait = AST::Path(core_name, { AST::PathNode("fmt", {}), AST::PathNode("Debug", {}) }); - TypeRef f_type(TypeRef::TagReference(), sp, AST::LifetimeRef(), true, - TypeRef(sp, AST::Path(core_name, {AST::PathNode("fmt",{}), AST::PathNode("Formatter", {})})) - ); + const AST::Path debug_trait = get_path(core_name, "fmt", "Debug"); AST::Function fcn( sp, AST::GenericParams(), ABI_RUST, false, false, false, - TypeRef(sp, AST::Path(core_name, {AST::PathNode("fmt",{}), AST::PathNode("Result",{})}) ), + TypeRef(sp, get_path(core_name, "fmt", "Result")), vec$( - ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), sp, "self"), TypeRef(TypeRef::TagReference(), sp, AST::LifetimeRef(), false, TypeRef(sp, "Self", 0xFFFF)) ), - ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), sp, "f"), mv$(f_type) ) + ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), sp, "self"), + TypeRef(TypeRef::TagReference(), sp, AST::LifetimeRef(), false, TypeRef(sp, "Self", 0xFFFF)) ), + ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), sp, "f"), + TypeRef(TypeRef::TagReference(), sp, AST::LifetimeRef(), true, TypeRef(sp, get_path(core_name, "fmt", "Formatter")) ) ) ) ); fcn.set_code( NEWNODE(Block, vec$(mv$(node))) ); @@ -346,6 +420,7 @@ public: mv$(node), AST::PathNode("debug_struct",{}), vec$( NEWNODE(String, name) ) ); + // TODO: use a block instead of chaining for( const auto& fld : e.ents ) { node = NEWNODE(CallMethod, @@ -411,55 +486,40 @@ public: ), (Tuple, ::std::vector pats_a; - AST::ExprNodeP node; - - node = NEWNODE(NamedValue, AST::Path("f")); - node = NEWNODE(CallMethod, - mv$(node), AST::PathNode("debug_tuple",{}), - vec$( NEWNODE(String, v.m_name.c_str()) ) - ); - - for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ ) - { - auto name_a = RcString::new_interned(FMT("a" << idx)); - pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) ); - node = NEWNODE(CallMethod, - mv$(node), AST::PathNode("field",{}), - vec$( - NEWNODE(NamedValue, AST::Path(name_a)) - ) - ); - } - - code = NEWNODE(CallMethod, mv$(node), AST::PathNode("finish",{}), {}); + auto s_ent = NEWNODE(NamedValue, AST::Path("s")); + auto nodes = make_refpat_a(sp, pats_a, e.m_sub_types, [&](size_t idx, auto a){ + return NEWNODE(CallMethod, s_ent->clone(), AST::PathNode("field", {}), vec$( mv$(a) )); + }); + nodes.insert(nodes.begin(), NEWNODE(LetBinding, AST::Pattern(AST::Pattern::TagBind(), sp, "s"), TypeRef(sp), + NEWNODE(CallMethod, NEWNODE(NamedValue, AST::Path("f")), AST::PathNode("debug_tuple",{}), + vec$( NEWNODE(String, v.m_name.c_str()) ) + ) + )); + nodes.push_back( NEWNODE(CallMethod, mv$(s_ent), AST::PathNode("finish",{}), {}) ); + code = NEWNODE(Block, mv$(nodes)); pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_a)); ), (Struct, ::std::vector< ::std::pair > pats_a; - AST::ExprNodeP node; - node = NEWNODE(NamedValue, AST::Path("f")); - node = NEWNODE(CallMethod, - mv$(node), AST::PathNode("debug_struct",{}), - vec$( NEWNODE(String, v.m_name.c_str()) ) - ); - - for( const auto& fld : e.m_fields ) - { - auto name_a = RcString::new_interned(FMT("a" << fld.m_name)); - pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF)) ); - - node = NEWNODE(CallMethod, - mv$(node), AST::PathNode("field",{}), - vec$( - NEWNODE(String, fld.m_name.c_str()), - NEWNODE(NamedValue, AST::Path(name_a)) + auto s_ent = NEWNODE(NamedValue, AST::Path("s")); + auto nodes = make_refpat_a(sp, pats_a, e.m_fields, [&](size_t idx, auto a){ + return NEWNODE(CallMethod, s_ent->clone(), AST::PathNode("field", {}), + vec$( + NEWNODE(String, e.m_fields[idx].m_name.c_str()), + mv$(a) + ) + ); + }); + nodes.insert(nodes.begin(), NEWNODE(LetBinding, AST::Pattern(AST::Pattern::TagBind(), sp, "s"), TypeRef(sp), + NEWNODE(CallMethod, NEWNODE(NamedValue, AST::Path("f")), AST::PathNode("debug_struct",{}), + vec$( NEWNODE(String, v.m_name.c_str()) ) ) - ); - } + )); + nodes.push_back( NEWNODE(CallMethod, mv$(s_ent), AST::PathNode("finish",{}), {}) ); - code = NEWNODE(CallMethod, mv$(node), AST::PathNode("finish",{}), {}); + code = NEWNODE(Block, mv$(nodes)); pat_a = AST::Pattern(AST::Pattern::TagStruct(), sp, base_path + v.m_name, mv$(pats_a), true); ) ) @@ -487,7 +547,7 @@ class Deriver_PartialEq: { AST::Impl make_ret(Span sp, const RcString& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector types_to_bound, AST::ExprNodeP node) const { - const AST::Path trait_path(core_name, { AST::PathNode("cmp", {}), AST::PathNode("PartialEq", {}) }); + const AST::Path trait_path = get_path(core_name, "cmp", "PartialEq"); AST::Function fcn( sp, @@ -571,21 +631,12 @@ public: (Tuple, ::std::vector pats_a; ::std::vector pats_b; - ::std::vector nodes; - - for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ ) - { - auto name_a = RcString::new_interned(FMT("a" << idx)); - auto name_b = RcString::new_interned(FMT("b" << idx)); - pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) ); - pats_b.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_b, ::AST::PatternBinding::Type::REF) ); - nodes.push_back(this->compare_and_ret(sp, opts.core_name, - NEWNODE(NamedValue, AST::Path(name_a)), - NEWNODE(NamedValue, AST::Path(name_b)) - )); - } + auto nodes = make_refpat_ab(sp, pats_a, pats_b, e.m_sub_types, [&](auto idx, auto a, auto b){ + return this->compare_and_ret(sp, opts.core_name, mv$(a), mv$(b)); + }); nodes.push_back( NEWNODE(Bool, true) ); + pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_a)); pat_b = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_b)); code = NEWNODE(Block, mv$(nodes)); @@ -593,21 +644,12 @@ public: (Struct, ::std::vector< ::std::pair > pats_a; ::std::vector< ::std::pair > pats_b; - ::std::vector nodes; - - for( const auto& fld : e.m_fields ) - { - auto name_a = RcString::new_interned(FMT("a" << fld.m_name)); - auto name_b = RcString::new_interned(FMT("b" << fld.m_name)); - pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF)) ); - pats_b.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_b, ::AST::PatternBinding::Type::REF)) ); - nodes.push_back(this->compare_and_ret(sp, opts.core_name, - NEWNODE(NamedValue, AST::Path(name_a)), - NEWNODE(NamedValue, AST::Path(name_b)) - )); - } + auto nodes = make_refpat_ab(sp, pats_a, pats_b, e.m_fields, [&](const auto& name, auto a, auto b){ + return this->compare_and_ret(sp, opts.core_name, mv$(a), mv$(b)); + }); nodes.push_back( NEWNODE(Bool, true) ); + pat_a = AST::Pattern(AST::Pattern::TagStruct(), sp, base_path + v.m_name, mv$(pats_a), true); pat_b = AST::Pattern(AST::Pattern::TagStruct(), sp, base_path + v.m_name, mv$(pats_b), true); code = NEWNODE(Block, mv$(nodes)); @@ -653,10 +695,10 @@ class Deriver_PartialOrd: { AST::Impl make_ret(Span sp, const RcString& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector types_to_bound, AST::ExprNodeP node) const { - const AST::Path trait_path(core_name, { AST::PathNode("cmp", {}), AST::PathNode("PartialOrd", {}) }); - const AST::Path path_ordering(core_name, { AST::PathNode("cmp", {}), AST::PathNode("Ordering", {}) }); + const AST::Path trait_path = get_path(core_name, "cmp", "PartialOrd"); + const AST::Path path_ordering = get_path(core_name, "cmp", "Ordering"); - AST::Path path_option_ordering(core_name, { AST::PathNode("option", {}), AST::PathNode("Option", {}) }); + AST::Path path_option_ordering = get_path(core_name, "option", "Option"); path_option_ordering.nodes().back().args().m_types.push_back( TypeRef(sp, path_ordering) ); AST::Function fcn( @@ -770,22 +812,12 @@ public: (Tuple, ::std::vector pats_a; ::std::vector pats_b; - ::std::vector nodes; - - for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ ) - { - auto name_a = RcString::new_interned(FMT("a" << idx)); - auto name_b = RcString::new_interned(FMT("b" << idx)); - pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) ); - pats_b.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_b, ::AST::PatternBinding::Type::REF) ); - - nodes.push_back(this->make_compare_and_ret( sp, opts.core_name, - NEWNODE(Deref, NEWNODE(NamedValue, AST::Path(name_a))), - NEWNODE(Deref, NEWNODE(NamedValue, AST::Path(name_b))) - )); - } + auto nodes = make_refpat_ab(sp, pats_a, pats_b, e.m_sub_types, [&](size_t , auto a, auto b){ + return this->make_compare_and_ret(sp, opts.core_name, NEWNODE(Deref, mv$(a)), NEWNODE(Deref, mv$(b))); + }); nodes.push_back( this->make_ret_equal(opts.core_name) ); + pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_a)); pat_b = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_b)); code = NEWNODE(Block, mv$(nodes)); @@ -793,22 +825,12 @@ public: (Struct, ::std::vector< ::std::pair > pats_a; ::std::vector< ::std::pair > pats_b; - ::std::vector nodes; - - for( const auto& fld : e.m_fields ) - { - auto name_a = RcString::new_interned(FMT("a" << fld.m_name)); - auto name_b = RcString::new_interned(FMT("b" << fld.m_name)); - pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF)) ); - pats_b.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_b, ::AST::PatternBinding::Type::REF)) ); - - nodes.push_back(this->make_compare_and_ret( sp, opts.core_name, - NEWNODE(Deref, NEWNODE(NamedValue, AST::Path(name_a))), - NEWNODE(Deref, NEWNODE(NamedValue, AST::Path(name_b))) - )); - } + auto nodes = make_refpat_ab(sp, pats_a, pats_b, e.m_fields, [&](size_t /*idx*/, auto a, auto b){ + return this->make_compare_and_ret(sp, opts.core_name, NEWNODE(Deref, mv$(a)), NEWNODE(Deref, mv$(b))); + }); nodes.push_back( this->make_ret_equal(opts.core_name) ); + pat_a = AST::Pattern(AST::Pattern::TagStruct(), sp, base_path + v.m_name, mv$(pats_a), true); pat_b = AST::Pattern(AST::Pattern::TagStruct(), sp, base_path + v.m_name, mv$(pats_b), true); code = NEWNODE(Block, mv$(nodes)); @@ -863,7 +885,7 @@ class Deriver_Eq: public Deriver { AST::Path get_trait_path(const RcString& core_name) const { - return AST::Path(core_name, { AST::PathNode("cmp", {}), AST::PathNode("Eq", {}) }); + return get_path(core_name, "cmp", "Eq"); } AST::Impl make_ret(Span sp, const RcString& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector types_to_bound, AST::ExprNodeP node) const @@ -948,28 +970,18 @@ public: ), (Tuple, ::std::vector pats_a; - ::std::vector nodes; - - for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ ) - { - auto name_a = RcString::new_interned(FMT("a" << idx)); - pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) ); - nodes.push_back( this->assert_is_eq(assert_method_path, NEWNODE(NamedValue, AST::Path(name_a))) ); - } + auto nodes = make_refpat_a(sp, pats_a, e.m_sub_types, [&](size_t idx, auto a){ + return this->assert_is_eq(assert_method_path, mv$(a)); + }); pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_a)); code = NEWNODE(Block, mv$(nodes)); ), (Struct, ::std::vector< ::std::pair > pats_a; - ::std::vector nodes; - - for( const auto& fld : e.m_fields ) - { - auto name_a = RcString::new_interned(FMT("a" << fld.m_name)); - pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF)) ); - nodes.push_back( this->assert_is_eq(assert_method_path, NEWNODE(NamedValue, AST::Path(name_a))) ); - } + auto nodes = make_refpat_a(sp, pats_a, e.m_fields, [&](size_t idx, auto a){ + return this->assert_is_eq(assert_method_path, mv$(a)); + }); pat_a = AST::Pattern(AST::Pattern::TagStruct(), sp, base_path + v.m_name, mv$(pats_a), true); code = NEWNODE(Block, mv$(nodes)); @@ -1012,8 +1024,8 @@ class Deriver_Ord: { AST::Impl make_ret(Span sp, const RcString& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector types_to_bound, AST::ExprNodeP node) const { - const AST::Path trait_path(core_name, { AST::PathNode("cmp", {}), AST::PathNode("Ord", {}) }); - const AST::Path path_ordering(core_name, { AST::PathNode("cmp", {}), AST::PathNode("Ordering", {}) }); + const AST::Path trait_path = get_path(core_name, "cmp", "Ord"); + const AST::Path path_ordering = get_path(core_name, "cmp", "Ordering"); AST::Function fcn( sp, @@ -1118,22 +1130,12 @@ public: (Tuple, ::std::vector pats_a; ::std::vector pats_b; - ::std::vector nodes; - - for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ ) - { - auto name_a = RcString::new_interned(FMT("a" << idx)); - auto name_b = RcString::new_interned(FMT("b" << idx)); - pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) ); - pats_b.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_b, ::AST::PatternBinding::Type::REF) ); - - nodes.push_back(this->make_compare_and_ret( sp, opts.core_name, - NEWNODE(NamedValue, AST::Path(name_a)), - NEWNODE(NamedValue, AST::Path(name_b)) - )); - } + auto nodes = make_refpat_ab(sp, pats_a, pats_b, e.m_sub_types, [&](size_t, auto a, auto b){ + return this->make_compare_and_ret(sp, opts.core_name, mv$(a), mv$(b)); + }); nodes.push_back( this->make_ret_equal(opts.core_name) ); + pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_a)); pat_b = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_b)); code = NEWNODE(Block, mv$(nodes)); @@ -1141,22 +1143,12 @@ public: (Struct, ::std::vector< ::std::pair > pats_a; ::std::vector< ::std::pair > pats_b; - ::std::vector nodes; - - for( const auto& fld : e.m_fields ) - { - auto name_a = RcString::new_interned(FMT("a" << fld.m_name)); - auto name_b = RcString::new_interned(FMT("b" << fld.m_name)); - pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF)) ); - pats_b.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_b, ::AST::PatternBinding::Type::REF)) ); - - nodes.push_back(this->make_compare_and_ret( sp, opts.core_name, - NEWNODE(NamedValue, AST::Path(name_a)), - NEWNODE(NamedValue, AST::Path(name_b)) - )); - } + auto nodes = make_refpat_ab(sp, pats_a, pats_b, e.m_fields, [&](const auto& /*name*/, auto a, auto b) { + return this->make_compare_and_ret(sp, opts.core_name, mv$(a), mv$(b)); + }); nodes.push_back( this->make_ret_equal(opts.core_name) ); + pat_a = AST::Pattern(AST::Pattern::TagStruct(), sp, base_path + v.m_name, mv$(pats_a), true); pat_b = AST::Pattern(AST::Pattern::TagStruct(), sp, base_path + v.m_name, mv$(pats_b), true); code = NEWNODE(Block, mv$(nodes)); @@ -1307,14 +1299,9 @@ public: ), (Tuple, ::std::vector pats_a; - ::std::vector nodes; - - for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ ) - { - auto name_a = RcString::new_interned(FMT("a" << idx)); - pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) ); - nodes.push_back( this->clone_val_direct(opts.core_name, NEWNODE(NamedValue, AST::Path(name_a))) ); - } + auto nodes = make_refpat_a(sp, pats_a, e.m_sub_types, [&](size_t , auto a) { + return this->clone_val_direct(opts.core_name, mv$(a)); + }); pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_a)); code = NEWNODE(CallPath, base_path + v.m_name, mv$(nodes)); @@ -1370,7 +1357,7 @@ private: for(auto& b : ret.def().params().bounds()) { auto& be = b.as_IsTrait(); - be.trait = AST::Path(opts.core_name, { AST::PathNode("marker", {}), AST::PathNode("Copy", {}) }); + be.trait = get_path(opts.core_name, "marker", "Copy"); } return ret; @@ -1381,7 +1368,7 @@ class Deriver_Copy: public Deriver { AST::Path get_trait_path(const RcString& core_name) const { - return AST::Path(core_name, { AST::PathNode("marker", {}), AST::PathNode("Copy", {}) }); + return get_path(core_name, "marker", "Copy"); } AST::Impl make_ret(Span sp, const RcString& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector types_to_bound, AST::ExprNodeP node) const @@ -1416,7 +1403,7 @@ class Deriver_Default: public Deriver { AST::Path get_trait_path(const RcString& core_name) const { - return AST::Path(core_name, { AST::PathNode("default", {}), AST::PathNode("Default", {}) }); + return get_path(core_name, "default", "Default"); } AST::Path get_method_path(const RcString& core_name) const { return AST::Path(AST::Path::TagUfcs(), ::TypeRef(Span()), get_trait_path(core_name), { AST::PathNode("default", {}) } ); @@ -1491,10 +1478,10 @@ class Deriver_Hash: public Deriver { AST::Path get_trait_path(const RcString& core_name) const { - return AST::Path(core_name, { AST::PathNode("hash", {}), AST::PathNode("Hash", {}) }); + return get_path(core_name, "hash", "Hash"); } AST::Path get_trait_path_Hasher(const RcString& core_name) const { - return AST::Path(core_name, { AST::PathNode("hash", {}), AST::PathNode("Hasher", {}) }); + return get_path(core_name, "hash", "Hasher"); } AST::Path get_method_path(const RcString& core_name) const { return get_trait_path(core_name) + "hash"; @@ -1591,30 +1578,20 @@ public: ), (Tuple, ::std::vector pats_a; - ::std::vector nodes; - nodes.push_back( mv$(var_idx_hash) ); - - for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ ) - { - auto name_a = RcString::new_interned(FMT("a" << idx)); - pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) ); - nodes.push_back( this->hash_val_direct(opts.core_name, NEWNODE(NamedValue, AST::Path(name_a))) ); - } + auto nodes = make_refpat_a(sp, pats_a, e.m_sub_types, [&](size_t , auto a) { + return this->hash_val_direct(opts.core_name, mv$(a)); + }); + nodes.insert(nodes.begin(), mv$(var_idx_hash)); pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), sp, base_path + v.m_name, mv$(pats_a)); code = NEWNODE(Block, mv$(nodes)); ), (Struct, ::std::vector< ::std::pair > pats_a; - ::std::vector< AST::ExprNodeP > nodes; - nodes.push_back( mv$(var_idx_hash) ); - - for( const auto& fld : e.m_fields ) - { - auto name_a = RcString::new_interned(FMT("a" << fld.m_name)); - pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF)) ); - nodes.push_back( this->hash_val_direct(opts.core_name, NEWNODE(NamedValue, AST::Path(name_a))) ); - } + auto nodes = make_refpat_a(sp, pats_a, e.m_fields, [&](size_t , auto a) { + return this->hash_val_direct(opts.core_name, mv$(a)); + }); + nodes.insert(nodes.begin(), mv$(var_idx_hash)); pat_a = AST::Pattern(AST::Pattern::TagStruct(), sp, base_path + v.m_name, mv$(pats_a), true); code = NEWNODE(Block, mv$(nodes)); @@ -1643,10 +1620,10 @@ class Deriver_RustcEncodable: { // NOTE: This emits paths like `::rustc_serialize::Encodable` - rustc and crates.io have subtly different crate names AST::Path get_trait_path() const { - return AST::Path("", { AST::PathNode("rustc_serialize", {}), AST::PathNode("Encodable", {}) }); + return get_path("", "rustc_serialize", "Encodable"); } AST::Path get_trait_path_Encoder() const { - return AST::Path("", { AST::PathNode("rustc_serialize", {}), AST::PathNode("Encoder", {}) }); + return get_path("", "rustc_serialize", "Encoder"); } AST::Path get_method_path() const { return get_trait_path() + "encode"; @@ -1656,7 +1633,7 @@ class Deriver_RustcEncodable: { const AST::Path trait_path = this->get_trait_path(); - AST::Path result_path = AST::Path(core_name, { AST::PathNode("result", {}), AST::PathNode("Result", {}) }); + AST::Path result_path = get_path(core_name, "result", "Result"); result_path.nodes()[1].args().m_types.push_back( TypeRef(TypeRef::TagUnit(), sp) ); result_path.nodes()[1].args().m_types.push_back(TypeRef( sp, AST::Path(AST::Path::TagUfcs(), TypeRef(sp, "S", 0x100|0), this->get_trait_path_Encoder(), { AST::PathNode("Error",{}) }) )); @@ -1703,7 +1680,7 @@ class Deriver_RustcEncodable: ); } AST::ExprNodeP get_val_ok(const RcString& core_name) const { - return NEWNODE(CallPath, AST::Path(core_name, {AST::PathNode("result",{}), AST::PathNode("Result",{}), AST::PathNode("Ok",{})}), vec$( NEWNODE(Tuple, {})) ); + return NEWNODE(CallPath, get_path(core_name, "result", "Result", "Ok"), vec$( NEWNODE(Tuple, {})) ); } public: @@ -1775,6 +1752,8 @@ public: base_path.nodes().back().args() = ::AST::PathParams(); ::std::vector arms; + auto s_ent = NEWNODE(NamedValue, AST::Path("s")); + for(unsigned int var_idx = 0; var_idx < enm.variants().size(); var_idx ++) { const auto& v = enm.variants()[var_idx]; @@ -1785,7 +1764,7 @@ public: (Value, code = NEWNODE(CallPath, this->get_trait_path_Encoder() + "emit_enum_variant", vec$( - NEWNODE(NamedValue, AST::Path("s")), + s_ent->clone(), NEWNODE(String, v.m_name.c_str()), NEWNODE(Integer, var_idx, CORETYPE_UINT), NEWNODE(Integer, 0, CORETYPE_UINT), @@ -1796,25 +1775,20 @@ public: ), (Tuple, ::std::vector pats_a; - ::std::vector nodes; - - for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ ) - { - auto name_a = RcString::new_interned(FMT("a" << idx)); - pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), sp, name_a, ::AST::PatternBinding::Type::REF) ); - nodes.push_back( NEWNODE(CallPath, this->get_trait_path_Encoder() + "emit_enum_variant_arg", + auto nodes = make_refpat_a(sp, pats_a, e.m_sub_types, [&](size_t idx, auto a){ + return NEWNODE(CallPath, this->get_trait_path_Encoder() + RcString::new_interned("emit_enum_variant_arg"), vec$( - NEWNODE(NamedValue, AST::Path("s")), + s_ent->clone(), NEWNODE(Integer, idx, CORETYPE_UINT), - this->enc_closure(sp, this->enc_val_direct(NEWNODE(NamedValue, AST::Path(name_a)))) + this->enc_closure(sp, this->enc_val_direct(mv$(a))) ) - ) ); - } + ); + }); nodes.push_back( this->get_val_ok(opts.core_name) ); code = NEWNODE(CallPath, this->get_trait_path_Encoder() + "emit_enum_variant", vec$( - NEWNODE(NamedValue, AST::Path("s")), + s_ent->clone(), NEWNODE(String, v.m_name.c_str()), NEWNODE(Integer, var_idx, CORETYPE_UINT), NEWNODE(Integer, e.m_sub_types.size(), CORETYPE_UINT), @@ -1825,30 +1799,22 @@ public: ), (Struct, ::std::vector< ::std::pair > pats_a; - ::std::vector< AST::ExprNodeP > nodes; - - unsigned int idx = 0; - for( const auto& fld : e.m_fields ) - { - auto name_a = Ident( RcString::new_interned(FMT("a" << fld.m_name)) ); - pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), sp, Ident(name_a), ::AST::PatternBinding::Type::REF)) ); - - nodes.push_back( NEWNODE(CallPath, this->get_trait_path_Encoder() + "emit_enum_struct_variant_field", + auto nodes = make_refpat_a(sp, pats_a, e.m_fields, [&](size_t idx, auto a){ + return NEWNODE(CallPath, this->get_trait_path_Encoder() + RcString::new_interned("emit_enum_variant_arg"), vec$( - NEWNODE(NamedValue, AST::Path("s")), - NEWNODE(String, fld.m_name.c_str()), + s_ent->clone(), + NEWNODE(String, e.m_fields[idx].m_name.c_str()), NEWNODE(Integer, idx, CORETYPE_UINT), - this->enc_closure(sp, this->enc_val_direct(NEWNODE(NamedValue, AST::Path(name_a.name)))) + this->enc_closure(sp, this->enc_val_direct(mv$(a))) ) - ) ); - idx ++; - } + ); + }); nodes.push_back( this->get_val_ok(opts.core_name) ); pat_a = AST::Pattern(AST::Pattern::TagStruct(), sp, base_path + v.m_name, mv$(pats_a), true); code = NEWNODE(CallPath, this->get_trait_path_Encoder() + "emit_enum_struct_variant", vec$( - NEWNODE(NamedValue, AST::Path("s")), + s_ent->clone(), NEWNODE(String, v.m_name.c_str()), NEWNODE(Integer, var_idx, CORETYPE_UINT), NEWNODE(Integer, e.m_fields.size(), CORETYPE_UINT), @@ -1872,7 +1838,7 @@ public: ::std::string enum_name = type.m_data.as_Path().path.nodes().back().name().c_str(); auto node = NEWNODE(CallPath, this->get_trait_path_Encoder() + "emit_enum", - vec$( NEWNODE(NamedValue, AST::Path("s")), NEWNODE(String, enum_name), this->enc_closure(sp, mv$(node_match)) ) + vec$( mv$(s_ent), NEWNODE(String, enum_name), this->enc_closure(sp, mv$(node_match)) ) ); return this->make_ret(sp, opts.core_name, p, type, this->get_field_bounds(enm), mv$(node)); @@ -1884,10 +1850,10 @@ class Deriver_RustcDecodable: { // NOTE: This emits paths like `::rustc_serialize::Encodable` - rustc and crates.io have subtly different crate names AST::Path get_trait_path() const { - return AST::Path("", { AST::PathNode("rustc_serialize", {}), AST::PathNode("Decodable", {}) }); + return get_path("", "rustc_serialize", "Decodable"); } AST::Path get_trait_path_Decoder() const { - return AST::Path("", { AST::PathNode("rustc_serialize", {}), AST::PathNode("Decoder", {}) }); + return get_path("", "rustc_serialize", "Decoder"); } AST::Path get_method_path() const { return get_trait_path() + "decode"; @@ -1897,7 +1863,7 @@ class Deriver_RustcDecodable: { const AST::Path trait_path = this->get_trait_path(); - AST::Path result_path = AST::Path(core_name, { AST::PathNode(RcString::new_interned("result"), {}), AST::PathNode(RcString::new_interned("Result"), {}) }); + AST::Path result_path = get_path(core_name, "result", "Result"); result_path.nodes()[1].args().m_types.push_back( TypeRef(sp, "Self", 0xFFFF) ); result_path.nodes()[1].args().m_types.push_back( TypeRef(sp, AST::Path(AST::Path::TagUfcs(), TypeRef(sp, "D", 0x100|0), this->get_trait_path_Decoder(), { AST::PathNode("Error",{}) })) ); @@ -2039,7 +2005,6 @@ public: for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ ) { - auto name_a = FMT("a" << idx); args.push_back( NEWNODE(UniOp, ::AST::ExprNode_UniOp::QMARK, NEWNODE(CallPath, this->get_trait_path_Decoder() + "read_enum_variant_arg", vec$( NEWNODE(NamedValue, AST::Path("d")), @@ -2056,8 +2021,6 @@ public: unsigned int idx = 0; for( const auto& fld : e.m_fields ) { - auto name_a = FMT("a" << fld.m_name); - vals.push_back({ {}, fld.m_name, NEWNODE(UniOp, ::AST::ExprNode_UniOp::QMARK, NEWNODE(CallPath, this->get_trait_path_Decoder() + "read_enum_struct_variant_field", vec$( NEWNODE(NamedValue, AST::Path("d")), diff --git a/src/include/rc_string.hpp b/src/include/rc_string.hpp index 2177e614..0d6ab155 100644 --- a/src/include/rc_string.hpp +++ b/src/include/rc_string.hpp @@ -29,7 +29,7 @@ public: } static RcString new_interned(const ::std::string& s); - //static new_interned(const char* s); + static RcString new_interned(const char* s); RcString(const RcString& x): m_ptr(x.m_ptr) diff --git a/src/rc_string.cpp b/src/rc_string.cpp index 123b4254..38f6b15d 100644 --- a/src/rc_string.cpp +++ b/src/rc_string.cpp @@ -91,6 +91,22 @@ RcString RcString::new_interned(const ::std::string& s) return *it; #else // TODO: interning flag, so comparisons can just be a pointer comparison + // - Only want to set this flag on the cached instance + return *RcString_interned_strings.insert(RcString(s)).first; +#endif +} +RcString RcString::new_interned(const char* s) +{ +#if 0 + auto it = RcString_interned_strings.find(s); + if( it == RcString_interned_strings.end() ) + { + it = RcString_interned_strings.insert(RcString(s)).first; + } + return *it; +#else + // TODO: interning flag, so comparisons can just be a pointer comparison + // - Only want to set this flag on the cached instance return *RcString_interned_strings.insert(RcString(s)).first; #endif } -- cgit v1.2.3 From 0d23f91b596b9bafc5779e9803c60583db969633 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 25 May 2019 08:20:26 +0800 Subject: TODO - Struck off a few items --- Notes/todo.txt | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Notes/todo.txt b/Notes/todo.txt index edc0074e..3ea2f69d 100644 --- a/Notes/todo.txt +++ b/Notes/todo.txt @@ -27,19 +27,12 @@ TODO: - Cache specialisation tree - Dependency files from mrustc - Partally done, not complete -- Replace all std::string-s with RcString (saves memory) - - Also use a string interning pool to de-duplicate identical strings (which - will be common) - - Copies of strings are relatively common (path copies) - Delete HIR after MIR generation - Use a more space-efficient (and readable) MIR LValue debug output - e.g. `_0**.1#2` for Downcast(2, Field(1, Deref(Deref(Local(0))))) - Will simplify reading of debug, and reduce the size of required debug output - Trailing dereference might be confusing with multiply operator? -- Cache referenced items for each function in `Trans Enumerate` - - Should reduce the impact of large generic functions being walked every - time they're used with a new type set. ## Optimisations -- cgit v1.2.3 From 36eb3d81c73a41895d241c4a32ec06b1952b8012 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 25 May 2019 10:16:03 +0800 Subject: MIR - Condense LValue debug format --- src/mir/mir.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/mir/mir.cpp b/src/mir/mir.cpp index 638b8e46..83f7e1f0 100644 --- a/src/mir/mir.cpp +++ b/src/mir/mir.cpp @@ -95,28 +95,28 @@ namespace MIR { { TU_MATCHA( (x), (e), (Return, - os << "Return"; + os << "retval"; ), (Argument, - os << "Argument(" << e.idx << ")"; + os << "a" << e.idx; ), (Local, - os << "Local(" << e << ")"; + os << "_" << e; ), (Static, - os << "Static(" << *e << ")"; + os << "(" << *e << ")"; ), (Field, - os << "Field(" << e.field_index << ", " << *e.val << ")"; + os << *e.val << "." << e.field_index; ), (Deref, - os << "Deref(" << *e.val << ")"; + os << *e.val << "*"; ), (Index, - os << "Index(" << *e.val << ", " << *e.idx << ")"; + os << *e.val << "[" << *e.idx << "]"; ), (Downcast, - os << "Downcast(" << e.variant_index << ", " << *e.val << ")"; + os << *e.val << "#" << e.variant_index; ) ) return os; -- cgit v1.2.3 From 599ed0a4cdaf7e05a1c8623c015a593106ea31ec Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 25 May 2019 14:24:59 +0800 Subject: Derive - Fix incorrect copy-paste during previous refactor --- src/expand/derive.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/expand/derive.cpp b/src/expand/derive.cpp index cc3b3cd0..25523fa4 100644 --- a/src/expand/derive.cpp +++ b/src/expand/derive.cpp @@ -1800,7 +1800,7 @@ public: (Struct, ::std::vector< ::std::pair > pats_a; auto nodes = make_refpat_a(sp, pats_a, e.m_fields, [&](size_t idx, auto a){ - return NEWNODE(CallPath, this->get_trait_path_Encoder() + RcString::new_interned("emit_enum_variant_arg"), + return NEWNODE(CallPath, this->get_trait_path_Encoder() + RcString::new_interned("emit_enum_struct_variant_field"), vec$( s_ent->clone(), NEWNODE(String, e.m_fields[idx].m_name.c_str()), -- cgit v1.2.3 From dab72ad78160ecd2a4d1759174cee837a5bedcbc Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 2 Jun 2019 11:55:02 +0800 Subject: MIR - Refactor LValue to reduce size and linked-list-ness (seems to have had a ~10% reduction in memory usage) --- Notes/MIR-PackedLValue.txt | 65 ++++ src/hir/deserialise.cpp | 32 +- src/hir/serialise.cpp | 41 +-- src/hir_conv/bind.cpp | 27 +- src/hir_conv/constant_evaluation.cpp | 112 +++---- src/include/tagged_union.hpp | 7 +- src/mir/check.cpp | 173 +++++----- src/mir/check_full.cpp | 230 ++++++-------- src/mir/cleanup.cpp | 82 +++-- src/mir/dump.cpp | 35 +- src/mir/from_hir.cpp | 76 ++--- src/mir/from_hir.hpp | 15 +- src/mir/from_hir_match.cpp | 112 +++---- src/mir/helpers.cpp | 135 ++++---- src/mir/helpers.hpp | 11 +- src/mir/mir.cpp | 189 ++++------- src/mir/mir.hpp | 402 ++++++++++++++++++----- src/mir/mir_builder.cpp | 597 ++++++++++++++++------------------- src/mir/optimise.cpp | 587 ++++++++++++++++++---------------- src/trans/auto_impls.cpp | 20 +- src/trans/codegen_c.cpp | 287 +++++++++-------- src/trans/codegen_mmir.cpp | 103 +++--- src/trans/enumerate.cpp | 340 ++++++-------------- src/trans/monomorphise.cpp | 40 +-- 24 files changed, 1863 insertions(+), 1855 deletions(-) create mode 100644 Notes/MIR-PackedLValue.txt diff --git a/Notes/MIR-PackedLValue.txt b/Notes/MIR-PackedLValue.txt new file mode 100644 index 00000000..ce889aee --- /dev/null +++ b/Notes/MIR-PackedLValue.txt @@ -0,0 +1,65 @@ +Problem statement: +- MIR LValues are very common, and suffer from excessive indirection when + dereferences and field accesses are present +- Many MIR analysis passes care most about the inner values +- Pointer chasing ruins cache locality + +Solution: Replace the tagged union tree with a flatteded structure + +Quirk: Indexing takes two LValues to produce one BUT one of those is of a +lesser class, so doesn't need to be treated the same. + + + +Structure proposal: +---- +A LValue is made up of: +- A root value (referencing a local, argument, static, or the return value) +- And a list of wrappers (dereference, field, downcast, index) + +Root values are encoded as a packed pointer/value and tag, with the tag stored in the low 2 bits of the pointer +- This allows a 32-bit pointer to a word to be stored, using the alignment bits as tag +- Arguments and locals are encoded with the argument/local index in the "data" bits +- Return value is encoded as argument `-1` (all 1 bits in data) +- Statics are encoded as a pointer to a `::HIR::Path` + - This adds a new pointer access and allocation vs the existing LValue structure + - HIR::Path already has a bunch of pointers in it, may not hurt that much (and may help by keeping the normal size + of the LValue down) + +Wrappers are stored as a vector of words, packed in a similar way to root values +- Dereference is stored just as an entry (could pack multiple derefs into one, but that would make handling more + difficult) +- Field/Downcast is stored with the field/variant index in the "data" bits +- Indexing is stored as a pointer to a LValue + - ALTERNATIVE: Could require that indexing always uses a local, and just store the local index + - This would vastly reduce complexity in handling the Index wrapper, BUT would add a new statement in some cases + - A quick scan of the MMIR output of libstd crates, shows that the vast majority of indexing cases are with a local + directly. + - Doing so would simplify monomorph/clone/serialise (no need to clone the wrapper list, just copy it). + - Would also improve comparison times + + + +Usecase comparisons +------ +(Using 32-bit architecture) + +NOTES: +- Existing `LValue` structure is 3 words long (1 tag, plus 2 pointers for largest variant) + - WRONG. It's actually far larger due to the ::HIR::Path embedded in it (estimate at least 8 pointers, very likely + more). That should be fixed given the number of LValue-s that exist + - Fixed now, had a slight improvement in compile times (and memory usage?) +- New structure is 4 words long (root value, plus len/cap/ptr for vector) + +- Field access via `&self` + - Old: Field(Deref(Argument(0)), 0) + - 12 + 12 + 12 = 36 bytes w/ 2 pointers + - New: LValue( Argument(0), { Deref, Field(0) } ) + - 16 + 8 = 24 bytes w/ 1 pointer + +- Array stored in `&self` (common in librand) + - `(*arg0).2[var16].0` + - Old: Field( Index(Field(Deref(Argument(0)), 2), Local(16)), 0 ) + - 12 * 5 + 12 = 72 bytes 2/ 5 pointers + - New: LValue( Argument(0), { Deref, Field(2), Index(16), Field(0) } ) + - 16 + 16 = 32 bytes w/ 1 pointer diff --git a/src/hir/deserialise.cpp b/src/hir/deserialise.cpp index 56671a04..35aeacca 100644 --- a/src/hir/deserialise.cpp +++ b/src/hir/deserialise.cpp @@ -464,32 +464,15 @@ rv = deserialise_mir_lvalue_(); return rv; } + ::MIR::LValue::Wrapper deserialise_mir_lvalue_wrapper() + { + return ::MIR::LValue::Wrapper::from_inner(m_in.read_count()); + } ::MIR::LValue deserialise_mir_lvalue_() { - switch(auto tag = m_in.read_tag()) - { - #define _(x, ...) case ::MIR::LValue::TAG_##x: return ::MIR::LValue::make_##x( __VA_ARGS__ ); - _(Return, {}) - _(Argument, { static_cast(m_in.read_count()) } ) - _(Local, static_cast(m_in.read_count()) ) - _(Static, box$(deserialise_path()) ) - _(Field, { - box$( deserialise_mir_lvalue() ), - static_cast(m_in.read_count()) - } ) - _(Deref, { box$( deserialise_mir_lvalue() ) }) - _(Index, { - box$( deserialise_mir_lvalue() ), - box$( deserialise_mir_lvalue() ) - } ) - _(Downcast, { - box$( deserialise_mir_lvalue() ), - static_cast(m_in.read_count()) - } ) - #undef _ - default: - BUG(Span(), "Bad tag for MIR::LValue - " << tag); - } + auto root_v = m_in.read_count(); + auto root = (root_v == 3 ? ::MIR::LValue::Storage::new_Static(deserialise_path()) : ::MIR::LValue::Storage::from_inner(root_v)); + return ::MIR::LValue( mv$(root), deserialise_vec<::MIR::LValue::Wrapper>() ); } ::MIR::RValue deserialise_mir_rvalue() { @@ -827,6 +810,7 @@ template<> DEF_D( ::HIR::TraitValueItem, return d.deserialise_traitvalueitem(); ) template<> DEF_D( ::MIR::Param, return d.deserialise_mir_param(); ) + template<> DEF_D( ::MIR::LValue::Wrapper, return d.deserialise_mir_lvalue_wrapper(); ) template<> DEF_D( ::MIR::LValue, return d.deserialise_mir_lvalue(); ) template<> DEF_D( ::MIR::Statement, return d.deserialise_mir_statement(); ) template<> DEF_D( ::MIR::BasicBlock, return d.deserialise_mir_basicblock(); ) diff --git a/src/hir/serialise.cpp b/src/hir/serialise.cpp index c15630d9..fc53e245 100644 --- a/src/hir/serialise.cpp +++ b/src/hir/serialise.cpp @@ -722,35 +722,18 @@ void serialise(const ::MIR::LValue& lv) { TRACE_FUNCTION_F("LValue = "<(lv.tag()) ); - TU_MATCHA( (lv), (e), - (Return, - ), - (Argument, - m_out.write_count(e.idx); - ), - (Local, - m_out.write_count(e); - ), - (Static, - serialise_path(*e); - ), - (Field, - serialise(e.val); - m_out.write_count(e.field_index); - ), - (Deref, - serialise(e.val); - ), - (Index, - serialise(e.val); - serialise(e.idx); - ), - (Downcast, - serialise(e.val); - m_out.write_count(e.variant_index); - ) - ) + if( lv.m_root.is_Static() ) { + m_out.write_count(3); + serialise_path(lv.m_root.as_Static()); + } + else { + m_out.write_count( lv.m_root.get_inner() ); + } + serialise_vec(lv.m_wrappers); + } + void serialise(const ::MIR::LValue::Wrapper& w) + { + m_out.write_count(w.get_inner()); } void serialise(const ::MIR::RValue& val) { diff --git a/src/hir_conv/bind.cpp b/src/hir_conv/bind.cpp index 84854315..e3441157 100644 --- a/src/hir_conv/bind.cpp +++ b/src/hir_conv/bind.cpp @@ -704,30 +704,9 @@ namespace { struct H { static void visit_lvalue(Visitor& upper_visitor, ::MIR::LValue& lv) { - TU_MATCHA( (lv), (e), - (Return, - ), - (Local, - ), - (Argument, - ), - (Static, - upper_visitor.visit_path(*e, ::HIR::Visitor::PathContext::VALUE); - ), - (Field, - H::visit_lvalue(upper_visitor, *e.val); - ), - (Deref, - H::visit_lvalue(upper_visitor, *e.val); - ), - (Index, - H::visit_lvalue(upper_visitor, *e.val); - H::visit_lvalue(upper_visitor, *e.idx); - ), - (Downcast, - H::visit_lvalue(upper_visitor, *e.val); - ) - ) + if( lv.m_root.is_Static() ) { + upper_visitor.visit_path(lv.m_root.as_Static(), ::HIR::Visitor::PathContext::VALUE); + } } static void visit_constant(Visitor& upper_visitor, ::MIR::Constant& e) { diff --git a/src/hir_conv/constant_evaluation.cpp b/src/hir_conv/constant_evaluation.cpp index b97a6ae0..500ac490 100644 --- a/src/hir_conv/constant_evaluation.cpp +++ b/src/hir_conv/constant_evaluation.cpp @@ -293,61 +293,66 @@ namespace HIR { ::HIR::Literal& get_lval(const ::MIR::LValue& lv) { - TU_MATCHA( (lv), (e), + ::HIR::Literal* lit_ptr; + TRACE_FUNCTION_FR(lv, *lit_ptr); + TU_MATCHA( (lv.m_root), (e), (Return, - return retval; + lit_ptr = &retval; ), (Local, - if( e >= locals.size() ) - MIR_BUG(state, "Local index out of range - " << e << " >= " << locals.size()); - return locals[e]; + MIR_ASSERT(state, e < locals.size(), "Local index out of range - " << e << " >= " << locals.size()); + lit_ptr = &locals[e]; ), (Argument, - if( e.idx >= args.size() ) - MIR_BUG(state, "Local index out of range - " << e.idx << " >= " << args.size()); - return args[e.idx]; + MIR_ASSERT(state, e < args.size(), "Argument index out of range - " << e << " >= " << args.size()); + lit_ptr = &args[e]; ), (Static, - MIR_TODO(state, "LValue::Static - " << *e); - ), - (Field, - auto& val = get_lval(*e.val); - MIR_ASSERT(state, val.is_List(), "LValue::Field on non-list literal - " << val.tag_str() << " - " << lv); - auto& vals = val.as_List(); - MIR_ASSERT(state, e.field_index < vals.size(), "LValue::Field index out of range"); - return vals[ e.field_index ]; - ), - (Deref, - auto& val = get_lval(*e.val); - TU_MATCH_DEF( ::HIR::Literal, (val), (ve), - ( - MIR_TODO(state, "LValue::Deref - " << lv << " { " << val << " }"); - ), - (BorrowData, - return *ve; - ), - (String, - // Just clone the string (hack) - // - TODO: Create a list? - return val; - ) - ) - ), - (Index, - auto& val = get_lval(*e.val); - MIR_ASSERT(state, val.is_List(), "LValue::Index on non-list literal - " << val.tag_str() << " - " << lv); - auto& idx = get_lval(*e.idx); - MIR_ASSERT(state, idx.is_Integer(), "LValue::Index with non-integer index literal - " << idx.tag_str() << " - " << lv); - auto& vals = val.as_List(); - auto idx_v = static_cast( idx.as_Integer() ); - MIR_ASSERT(state, idx_v < vals.size(), "LValue::Index index out of range"); - return vals[ idx_v ]; - ), - (Downcast, - MIR_TODO(state, "LValue::Downcast - " << lv); + MIR_TODO(state, "LValue::Static - " << e); ) ) - throw ""; + + for(const auto& w : lv.m_wrappers) + { + auto& val = *lit_ptr; + TU_MATCH_HDRA( (w), {) + TU_ARMA(Field, e) { + MIR_ASSERT(state, val.is_List(), "LValue::Field on non-list literal - " << val.tag_str() << " - " << lv); + auto& vals = val.as_List(); + MIR_ASSERT(state, e < vals.size(), "LValue::Field index out of range"); + lit_ptr = &vals[ e ]; + } + TU_ARMA(Deref, e) { + TU_MATCH_DEF( ::HIR::Literal, (val), (ve), + ( + MIR_TODO(state, "LValue::Deref - " << lv << " { " << val << " }"); + ), + (BorrowData, + lit_ptr = &*ve; + ), + (String, + // Just clone the string (hack) + // - TODO: Create a list? + lit_ptr = &val; + ) + ) + } + TU_ARMA(Index, e) { + MIR_ASSERT(state, val.is_List(), "LValue::Index on non-list literal - " << val.tag_str() << " - " << lv); + MIR_ASSERT(state, e < locals.size(), "LValue::Index index local out of range"); + auto& idx = locals[e]; + MIR_ASSERT(state, idx.is_Integer(), "LValue::Index with non-integer index literal - " << idx.tag_str() << " - " << lv); + auto& vals = val.as_List(); + auto idx_v = static_cast( idx.as_Integer() ); + MIR_ASSERT(state, idx_v < vals.size(), "LValue::Index index out of range"); + lit_ptr = &vals[ idx_v ]; + } + TU_ARMA(Downcast, e) { + MIR_TODO(state, "LValue::Downcast - " << lv); + } + } + } + return *lit_ptr; } ::HIR::Literal read_lval(const ::MIR::LValue& lv) { @@ -481,17 +486,14 @@ namespace HIR { MIR_BUG(state, "Only shared borrows are allowed in constants"); } - if( e.type != ::HIR::BorrowType::Shared ) { - MIR_BUG(state, "Only shared borrows are allowed in constants"); - } - if( const auto* p = e.val.opt_Deref() ) { - if( p->val->is_Deref() ) - MIR_TODO(state, "Undo nested deref coercion - " << *p->val); - val = local_state.read_lval(*p->val); + if( !e.val.m_wrappers.empty() && e.val.m_wrappers.back().is_Deref() ) { + //if( p->val->is_Deref() ) + // MIR_TODO(state, "Undo nested deref coercion - " << *p->val); + val = local_state.read_lval(e.val.clone_unwrapped()); } - else if( const auto* p = e.val.opt_Static() ) { + else if( e.val.m_wrappers.empty() && e.val.m_root.is_Static() ){ // Borrow of a static, emit BorrowPath with the same path - val = ::HIR::Literal::make_BorrowPath( (*p)->clone() ); + val = ::HIR::Literal::make_BorrowPath( e.val.m_root.as_Static().clone() ); } else { auto inner_val = local_state.read_lval(e.val); diff --git a/src/include/tagged_union.hpp b/src/include/tagged_union.hpp index dab7f8ea..5a3359b8 100644 --- a/src/include/tagged_union.hpp +++ b/src/include/tagged_union.hpp @@ -28,7 +28,6 @@ #define TU_CASE(mod, class, var, name,src, ...) TU_CASE_BODY(mod,class,var, TU_CASE_ITEM(src,mod,var,name) __VA_ARGS__) #define TU_CASE2(mod, class, var, n1,s1, n2,s2, ...) TU_CASE_BODY(mod,class,var, TU_CASE_ITEM(s1,mod,var,n1) TU_CASE_ITEM(s2,mod,var,n2) __VA_ARGS__) - // Argument iteration #define TU_DISP0(n) #define TU_DISP1(n, _1) n _1 @@ -105,7 +104,7 @@ */ TU_MATCH_ARMS(CLASS, VAR, NAME, __VA_ARGS__)/* */ default: {TU_EXP DEF;} break;/* */} -#define TU_MATCH_BIND1(TAG, VAR, NAME) /*MATCH_BIND*/ auto& NAME = (VAR).as_##TAG(); (void)&NAME; +#define TU_MATCH_BIND1(TAG, VAR, NAME) /*MATCH_BIND*/ decltype((VAR).as_##TAG()) NAME = (VAR).as_##TAG(); (void)&NAME; #define TU_MATCH_BIND2_(TAG, v1,v2, n1,n2) TU_MATCH_BIND1(TAG, v1, n1) TU_MATCH_BIND1(TAG, v2, n2) #define TU_MATCH_BIND2(...) TU_EXP1( TU_MATCH_BIND2_(__VA_ARGS__) ) // << Exists to cause expansion of the vars #define TU_MATCH_ARM(CLASS, VAR, NAME, TAG, ...) case CLASS::TAG_##TAG: {/* @@ -119,12 +118,12 @@ #define TU_MATCH_HDR(VARS, brace) TU_MATCH_HDR_(::std::remove_reference::type, VARS, brace) #define TU_MATCH_HDR_(CLASS, VARS, brace) switch( (TU_FIRST VARS).tag() ) brace case CLASS::TAGDEAD: assert(!"ERROR: destructed tagged union used"); // Evil hack: two for loops, the inner stops the outer after it's done. -#define TU_ARM(VAR, TAG, NAME) break; case ::std::remove_reference::type::TAG_##TAG: for(bool tu_lc = true; tu_lc; tu_lc=false) for(auto& NAME = (VAR).as_##TAG(); (void)NAME, tu_lc; tu_lc=false) +#define TU_ARM(VAR, TAG, NAME) break; case ::std::remove_reference::type::TAG_##TAG: for(bool tu_lc = true; tu_lc; tu_lc=false) for(decltype((VAR).as_##TAG()) NAME = (VAR).as_##TAG(); (void)NAME, tu_lc; tu_lc=false) #define TU_MATCH_HDRA(VARS, brace) TU_MATCH_HDRA_(::std::remove_reference::type, VARS, brace) #define TU_MATCH_HDRA_(CLASS, VARS, brace) auto& tu_match_hdr2_v = (TU_FIRST VARS); switch( tu_match_hdr2_v.tag() ) brace case CLASS::TAGDEAD: assert(!"ERROR: destructed tagged union used"); // Evil hack: two for loops, the inner stops the outer after it's done. -#define TU_ARMA(TAG, NAME) break; case ::std::remove_reference::type::TAG_##TAG: for(bool tu_lc = true; tu_lc; tu_lc=false) for(auto& NAME = tu_match_hdr2_v.as_##TAG(); (void)NAME, tu_lc; tu_lc=false) +#define TU_ARMA(TAG, NAME) break; case ::std::remove_reference::type::TAG_##TAG: for(bool tu_lc = true; tu_lc; tu_lc=false) for(decltype(tu_match_hdr2_v.as_##TAG()) NAME = tu_match_hdr2_v.as_##TAG(); (void)NAME, tu_lc; tu_lc=false) //#define TU_TEST(VAL, ...) (VAL.is_##TAG() && VAL.as_##TAG() TEST) #define TU_TEST1(VAL, TAG1, TEST) (VAL.is_##TAG1() && VAL.as_##TAG1() TEST) diff --git a/src/mir/check.cpp b/src/mir/check.cpp index 0b032bbc..6ed34563 100644 --- a/src/mir/check.cpp +++ b/src/mir/check.cpp @@ -116,6 +116,11 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn { } + explicit ValStates(const ValStates& v) = default; + ValStates(ValStates&& v) = default; + ValStates& operator=(const ValStates& v) = delete; + ValStates& operator=(ValStates&& v) = default; + void fmt(::std::ostream& os) { os << "ValStates { "; switch(ret_state) @@ -159,12 +164,13 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn return locals.empty() && args.empty(); } + // NOTE: Moves if this state is empty bool merge(unsigned bb_idx, ValStates& other) { DEBUG("bb" << bb_idx << " this=" << FMT_CB(ss,this->fmt(ss);) << ", other=" << FMT_CB(ss,other.fmt(ss);)); if( this->empty() ) { - *this = other; + *this = ValStates(other); return true; } else if( *this == other ) @@ -183,34 +189,38 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn void mark_validity(const ::MIR::TypeResolve& state, const ::MIR::LValue& lv, bool is_valid) { - TU_MATCH_DEF( ::MIR::LValue, (lv), (e), - ( - ), + if( !lv.m_wrappers.empty()) + { + return ; + } + TU_MATCHA( (lv.m_root), (e), (Return, ret_state = is_valid ? State::Valid : State::Invalid; ), (Argument, - MIR_ASSERT(state, e.idx < this->args.size(), "Argument index out of range"); - DEBUG("arg$" << e.idx << " = " << (is_valid ? "Valid" : "Invalid")); - this->args[e.idx] = is_valid ? State::Valid : State::Invalid; + MIR_ASSERT(state, e < this->args.size(), "Argument index out of range " << lv); + DEBUG("arg$" << e << " = " << (is_valid ? "Valid" : "Invalid")); + this->args[e] = is_valid ? State::Valid : State::Invalid; ), (Local, - MIR_ASSERT(state, e < this->locals.size(), "Local index out of range"); + MIR_ASSERT(state, e < this->locals.size(), "Local index out of range - " << lv); DEBUG("_" << e << " = " << (is_valid ? "Valid" : "Invalid")); this->locals[e] = is_valid ? State::Valid : State::Invalid; + ), + (Static, ) ) } void ensure_valid(const ::MIR::TypeResolve& state, const ::MIR::LValue& lv) { - TU_MATCH( ::MIR::LValue, (lv), (e), + TU_MATCHA( (lv.m_root), (e), (Return, if( this->ret_state != State::Valid ) MIR_BUG(state, "Use of non-valid lvalue - " << lv); ), (Argument, - MIR_ASSERT(state, e.idx < this->args.size(), "Arg index out of range"); - if( this->args[e.idx] != State::Valid ) + MIR_ASSERT(state, e < this->args.size(), "Arg index out of range"); + if( this->args[e] != State::Valid ) MIR_BUG(state, "Use of non-valid lvalue - " << lv); ), (Local, @@ -219,27 +229,22 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn MIR_BUG(state, "Use of non-valid lvalue - " << lv); ), (Static, - ), - (Field, - ensure_valid(state, *e.val); - ), - (Deref, - ensure_valid(state, *e.val); - ), - (Index, - ensure_valid(state, *e.val); - ensure_valid(state, *e.idx); - ), - (Downcast, - ensure_valid(state, *e.val); ) ) + + for(const auto& w : lv.m_wrappers) + { + if( w.is_Index() ) + { + if( this->locals[w.as_Index()] != State::Valid ) + MIR_BUG(state, "Use of non-valid lvalue - " << ::MIR::LValue::new_Local(w.as_Index())); + } + } } void move_val(const ::MIR::TypeResolve& state, const ::MIR::LValue& lv) { ensure_valid(state, lv); - ::HIR::TypeRef tmp; - if( ! state.m_resolve.type_is_copy( state.sp, state.get_lvalue_type(tmp, lv) ) ) + if( ! state.lvalue_is_copy(lv) ) { mark_validity(state, lv, false); } @@ -284,20 +289,29 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn ::std::vector path; ValStates state; }; + // TODO: Remove this? The path is useful, but the cloned states are really expensive + // - Option: Keep the paths, but only ever use the pre-set entry state? ::std::vector to_visit_blocks; // TODO: Check that all used locals are also set (anywhere at all) - auto add_to_visit = [&](unsigned int idx, ::std::vector src_path, auto vs) { + auto add_to_visit = [&](unsigned int idx, ::std::vector src_path, ValStates& vs, bool can_move) { for(const auto& b : to_visit_blocks) if( b.bb == idx && b.state == vs) return ; if( block_start_states.at(idx) == vs ) return ; src_path.push_back(idx); - to_visit_blocks.push_back( ToVisit { idx, mv$(src_path), mv$(vs) } ); + // TODO: Update the target block, and only visit if we've induced a change + to_visit_blocks.push_back( ToVisit { idx, mv$(src_path), (can_move ? mv$(vs) : ValStates(vs)) } ); + }; + auto add_to_visit_move = [&](unsigned int idx, ::std::vector src_path, ValStates vs) { + add_to_visit(idx, mv$(src_path), vs, true); + }; + auto add_to_visit_copy = [&](unsigned int idx, ::std::vector src_path, ValStates& vs) { + add_to_visit(idx, mv$(src_path), vs, false); }; - add_to_visit( 0, {}, ValStates { state.m_args.size(), fcn.locals.size() } ); + add_to_visit_move( 0, {}, ValStates { state.m_args.size(), fcn.locals.size() } ); while( to_visit_blocks.size() > 0 ) { auto block = to_visit_blocks.back().bb; @@ -311,7 +325,8 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn if( ! block_start_states.at(block).merge(block, val_state) ) { continue ; } - DEBUG("BB" << block << " via [" << path << "]"); + ASSERT_BUG(Span(), val_state.locals.size() == fcn.locals.size(), ""); + DEBUG("BB" << block << " via [" << path << "] " << FMT_CB(ss,val_state.fmt(ss);)); // 2. Using the newly merged state, iterate statements checking the usage and updating state. const auto& bb = fcn.blocks[block]; @@ -411,13 +426,13 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn // 3. Pass new state on to destination blocks state.set_cur_stmt_term(block); DEBUG(state << bb.terminator); - TU_MATCH(::MIR::Terminator, (bb.terminator), (e), - (Incomplete, + TU_MATCH_HDRA( (bb.terminator), { ) + TU_ARMA(Incomplete, e) { // Should be impossible here. - ), - (Return, + } + TU_ARMA(Return, e) { // Check if the return value has been set - val_state.ensure_valid( state, ::MIR::LValue::make_Return({}) ); + val_state.ensure_valid( state, ::MIR::LValue::new_Return() ); // Ensure that no other non-Copy values are valid for(unsigned int i = 0; i < val_state.locals.size(); i ++) { @@ -432,51 +447,51 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn // TODO: Error, becuase this has just been leaked } } - ), - (Diverge, + } + TU_ARMA(Diverge, e) { // TODO: Ensure that cleanup has been performed. - ), - (Goto, + } + TU_ARMA(Goto, e) { // Push block with the new state - add_to_visit( e, mv$(path), mv$(val_state) ); - ), - (Panic, + add_to_visit_move( e, mv$(path), mv$(val_state) ); + } + TU_ARMA(Panic, e) { // What should be done here? - ), - (If, + } + TU_ARMA(If, e) { // Push blocks val_state.ensure_valid( state, e.cond ); - add_to_visit( e.bb0, path, val_state ); - add_to_visit( e.bb1, mv$(path), mv$(val_state) ); - ), - (Switch, + add_to_visit_copy( e.bb0, path, val_state ); + add_to_visit_move( e.bb1, mv$(path), mv$(val_state) ); + } + TU_ARMA(Switch, e) { val_state.ensure_valid( state, e.val ); for(const auto& tgt : e.targets) { - add_to_visit( tgt, path, val_state ); + add_to_visit( tgt, path, val_state, (&tgt == &e.targets.back()) ); } - ), - (SwitchValue, + } + TU_ARMA(SwitchValue, e) { val_state.ensure_valid( state, e.val ); for(const auto& tgt : e.targets) { - add_to_visit( tgt, path, val_state ); + add_to_visit_copy( tgt, path, val_state ); + } + add_to_visit_move( e.def_target, path, mv$(val_state) ); } - add_to_visit( e.def_target, path, val_state ); - ), - (Call, + TU_ARMA(Call, e) { if( e.fcn.is_Value() ) val_state.ensure_valid( state, e.fcn.as_Value() ); for(const auto& arg : e.args) val_state.move_val( state, arg ); // Push blocks (with return valid only in one) - add_to_visit(e.panic_block, path, val_state); + add_to_visit_copy(e.panic_block, path, val_state); // TODO: If the function returns !, don't follow the ret_block val_state.mark_validity( state, e.ret_val, true ); - add_to_visit(e.ret_block, mv$(path), mv$(val_state)); - ) - ) + add_to_visit_move(e.ret_block, mv$(path), mv$(val_state)); + } + } } } @@ -838,33 +853,33 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path state.set_cur_stmt_term(bb_idx); DEBUG(state << bb.terminator); - TU_MATCH(::MIR::Terminator, (bb.terminator), (e), - (Incomplete, - ), - (Return, + TU_MATCH_HDRA( (bb.terminator), {) + TU_ARMA(Incomplete, e) { + } + TU_ARMA(Return, e) { // TODO: Check if the function can return (i.e. if its return type isn't an empty type) - ), - (Diverge, - ), - (Goto, - ), - (Panic, - ), - (If, + } + TU_ARMA(Diverge, e) { + } + TU_ARMA(Goto, e) { + } + TU_ARMA(Panic, e) { + } + TU_ARMA(If, e) { // Check that condition lvalue is a bool ::HIR::TypeRef tmp; const auto& ty = state.get_lvalue_type(tmp, e.cond); if( ty != ::HIR::CoreType::Bool ) { MIR_BUG(state, "Type mismatch in `If` - expected bool, got " << ty); } - ), - (Switch, + } + TU_ARMA(Switch, e) { // Check that the condition is an enum - ), - (SwitchValue, + } + TU_ARMA(SwitchValue, e) { // Check that the condition's type matches the values - ), - (Call, + } + TU_ARMA(Call, e) { if( e.fcn.is_Value() ) { ::HIR::TypeRef tmp; @@ -875,8 +890,8 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path } } // Typecheck arguments and return value - ) - ) + } + } } } diff --git a/src/mir/check_full.cpp b/src/mir/check_full.cpp index 24a4930a..0cc83c6f 100644 --- a/src/mir/check_full.cpp +++ b/src/mir/check_full.cpp @@ -446,68 +446,54 @@ namespace } const State& get_lvalue_state(const ::MIR::TypeResolve& mir_res, const ::MIR::LValue& lv) const { - TU_MATCHA( (lv), (e), + const State* state_p = nullptr; + TU_MATCHA( (lv.m_root), (e), (Return, - return return_value; + state_p = &return_value; ), (Argument, - return args.at(e.idx); + state_p = &args.at(e); ), (Local, - return locals.at(e); + state_p = &locals.at(e); ), (Static, static State state_of_static(true); return state_of_static; - ), - (Field, - const auto& vs = get_lvalue_state(mir_res, *e.val); - if( vs.is_composite() ) - { - const auto& states = this->get_composite(mir_res, vs); - MIR_ASSERT(mir_res, e.field_index < states.size(), "Field index out of range"); - return states[e.field_index]; - } - else - { - return vs; + ) + ) + + for(const auto& w : lv.m_wrappers) + { + if( state_p->is_composite() ) { + break; } - ), - (Deref, - const auto& vs = get_lvalue_state(mir_res, *e.val); - if( vs.is_composite() ) - { + const auto& vs = *state_p; + state_p = nullptr; + + TU_MATCHA( (w), (e), + (Field, + const auto& states = this->get_composite(mir_res, vs); + MIR_ASSERT(mir_res, e < states.size(), "Field index out of range"); + state_p = &states[e]; + ), + (Deref, MIR_TODO(mir_res, "Deref with composite state"); - } - else - { - return vs; - } - ), - (Index, - const auto& vs_v = get_lvalue_state(mir_res, *e.val); - const auto& vs_i = get_lvalue_state(mir_res, *e.idx); - MIR_ASSERT(mir_res, !vs_v.is_composite(), ""); - MIR_ASSERT(mir_res, !vs_i.is_composite(), ""); - //return State(vs_v.is_valid() && vs_i.is_valid()); - MIR_ASSERT(mir_res, vs_i.is_valid(), "Indexing with an invalidated value"); - return vs_v; - ), - (Downcast, - const auto& vs_v = get_lvalue_state(mir_res, *e.val); - if( vs_v.is_composite() ) - { - const auto& states = this->get_composite(mir_res, vs_v); - MIR_ASSERT(mir_res, states.size() == 1, "Downcast on composite of invalid size - " << StateFmt(*this, vs_v)); - return states[0]; - } - else - { - return vs_v; - } + ), + (Index, + const auto& vs_i = get_lvalue_state(mir_res, ::MIR::LValue::new_Local(e)); + MIR_ASSERT(mir_res, vs_i.is_valid(), "Indexing with an invalidated value"); + MIR_BUG(mir_res, "Indexing a composite state"); + ), + (Downcast, + const auto& states = this->get_composite(mir_res, vs); + MIR_ASSERT(mir_res, states.size() == 1, "Downcast on composite of invalid size - " << StateFmt(*this, vs)); + state_p = &states[0]; + ) ) - ) - throw ""; + assert(state_p); + } + return *state_p; } void clear_state(const ::MIR::TypeResolve& mir_res, State& s) { @@ -522,42 +508,47 @@ namespace void set_lvalue_state(const ::MIR::TypeResolve& mir_res, const ::MIR::LValue& lv, State new_vs) { TRACE_FUNCTION_F(lv << " = " << StateFmt(*this, new_vs) << " (from " << StateFmt(*this, get_lvalue_state(mir_res, lv)) << ")"); - TU_MATCHA( (lv), (e), + State* state_p = nullptr; + TU_MATCHA( (lv.m_root), (e), (Return, - this->clear_state(mir_res, return_value); - return_value = mv$(new_vs); + state_p = &return_value; ), (Argument, - auto& slot = args.at(e.idx); - this->clear_state(mir_res, slot); - slot = mv$(new_vs); + state_p = &args.at(e); ), (Local, - auto& slot = locals.at(e); - this->clear_state(mir_res, slot); - slot = mv$(new_vs); + state_p = &locals.at(e); ), (Static, - // Ignore. - ), - (Field, - const auto& cur_vs = get_lvalue_state(mir_res, *e.val); + return ; + ) + ) + + for(const auto& w : lv.m_wrappers) + { + auto& cur_vs = *state_p; + + // If this is not a composite, and it matches the new state if( !cur_vs.is_composite() && cur_vs == new_vs ) { - // Not a composite, and no state change + // Early return + return; } - else - { - ::std::vector* states_p; + + state_p = nullptr; + TU_MATCHA( (w), (e), + (Field, + // Current isn't a composite, we need to change that if( !cur_vs.is_composite() ) { ::HIR::TypeRef tmp; - const auto& ty = mir_res.get_lvalue_type(tmp, *e.val); + const auto& ty = mir_res.get_lvalue_type(tmp, lv, /*wrapper_skip_count=*/(&lv.m_wrappers.back() - &w)); unsigned int n_fields = 0; if( const auto* e = ty.m_data.opt_Tuple() ) { n_fields = e->size(); } + // TODO: Fixed-size arrays else if( ty.m_data.is_Path() && ty.m_data.as_Path().binding.is_Struct() ) { const auto& e = ty.m_data.as_Path().binding.as_Struct(); @@ -573,94 +564,59 @@ namespace ) ) } - else { + else + { MIR_BUG(mir_res, "Unknown type being accessed with Field - " << ty); } - auto new_cur_vs = this->allocate_composite(n_fields, cur_vs); - set_lvalue_state(mir_res, *e.val, State(new_cur_vs)); - states_p = &this->get_composite(mir_res, new_cur_vs); - } - else - { - states_p = &this->get_composite(mir_res, cur_vs); + cur_vs = State(this->allocate_composite(n_fields, cur_vs)); } // Get composite state and assign into it - auto& states = *states_p; - MIR_ASSERT(mir_res, e.field_index < states.size(), "Field index out of range"); - this->clear_state(mir_res, states[e.field_index]); - states[e.field_index] = mv$(new_vs); - } - ), - (Deref, - const auto& cur_vs = get_lvalue_state(mir_res, *e.val); - if( !cur_vs.is_composite() && cur_vs == new_vs ) - { - // Not a composite, and no state change - } - else - { - ::std::vector* states_p; + auto& states = this->get_composite(mir_res, cur_vs); + MIR_ASSERT(mir_res, e< states.size(), "Field index out of range"); + state_p = &states[e]; + ), + (Deref, if( !cur_vs.is_composite() ) { + // TODO: Should this check if the type is Box? //::HIR::TypeRef tmp; //const auto& ty = mir_res.get_lvalue_type(tmp, *e.val); - // TODO: Should this check if the type is Box? - auto new_cur_vs = this->allocate_composite(2, cur_vs); - set_lvalue_state(mir_res, *e.val, State(new_cur_vs)); - states_p = &this->get_composite(mir_res, new_cur_vs); - } - else - { - states_p = &this->get_composite(mir_res, cur_vs); + cur_vs = State(this->allocate_composite(2, cur_vs)); } // Get composite state and assign into it - auto& states = *states_p; + auto& states = this->get_composite(mir_res, cur_vs); MIR_ASSERT(mir_res, states.size() == 2, "Deref with invalid state list size"); - this->clear_state(mir_res, states[1]); - states[1] = mv$(new_vs); - } - ), - (Index, - const auto& vs_v = get_lvalue_state(mir_res, *e.val); - const auto& vs_i = get_lvalue_state(mir_res, *e.idx); - MIR_ASSERT(mir_res, !vs_v.is_composite(), ""); - MIR_ASSERT(mir_res, !vs_i.is_composite(), ""); + state_p = &states[1]; + ), + (Index, + const auto& vs_i = get_lvalue_state(mir_res, ::MIR::LValue::new_Local(e)); + MIR_ASSERT(mir_res, !cur_vs.is_composite(), ""); + MIR_ASSERT(mir_res, !vs_i.is_composite(), ""); - MIR_ASSERT(mir_res, vs_v.is_valid(), "Indexing an invalid value"); - MIR_ASSERT(mir_res, vs_i.is_valid(), "Indexing with an invalid index"); + MIR_ASSERT(mir_res, cur_vs.is_valid(), "Indexing an invalid value"); + MIR_ASSERT(mir_res, vs_i.is_valid(), "Indexing with an invalid index"); - // NOTE: Ignore - ), - (Downcast, - const auto& cur_vs = get_lvalue_state(mir_res, *e.val); - if( !cur_vs.is_composite() && cur_vs == new_vs ) - { - // Not a composite, and no state change - } - else - { - ::std::vector* states_p; + // NOTE: Ignore + return ; + ), + (Downcast, if( !cur_vs.is_composite() ) { - auto new_cur_vs = this->allocate_composite(1, cur_vs); - set_lvalue_state(mir_res, *e.val, State(new_cur_vs)); - states_p = &this->get_composite(mir_res, new_cur_vs); + cur_vs = State(this->allocate_composite(1, cur_vs)); } - else - { - states_p = &this->get_composite(mir_res, cur_vs); - } - // Get composite state and assign into it - auto& states = *states_p; - MIR_ASSERT(mir_res, states.size() == 1, "Downcast on composite of invalid size - " << *e.val << " - " << this->fmt_state(mir_res, *e.val)); + auto& states = this->get_composite(mir_res, cur_vs); + MIR_ASSERT(mir_res, states.size() == 1, "Downcast on composite of invalid size - " << lv << " - " << StateFmt(*this, cur_vs)); this->clear_state(mir_res, states[0]); states[0] = mv$(new_vs); - } + ) ) - ) + assert(state_p); + } + this->clear_state(mir_res, *state_p); + *state_p = mv$(new_vs); } }; @@ -939,7 +895,7 @@ void MIR_Validate_FullValState(::MIR::TypeResolve& mir_res, const ::MIR::Functio (Incomplete, ), (Return, - state.ensure_lvalue_valid(mir_res, ::MIR::LValue::make_Return({})); + state.ensure_lvalue_valid(mir_res, ::MIR::LValue::new_Return()); if( ENABLE_LEAK_DETECTOR ) { auto ensure_dropped = [&](const State& s, const ::MIR::LValue& lv) { @@ -955,10 +911,10 @@ void MIR_Validate_FullValState(::MIR::TypeResolve& mir_res, const ::MIR::Functio } }; for(unsigned i = 0; i < state.locals.size(); i ++ ) { - ensure_dropped(state.locals[i], ::MIR::LValue::make_Local(i)); + ensure_dropped(state.locals[i], ::MIR::LValue::new_Local(i)); } for(unsigned i = 0; i < state.args.size(); i ++ ) { - ensure_dropped(state.args[i], ::MIR::LValue::make_Argument({i})); + ensure_dropped(state.args[i], ::MIR::LValue::new_Argument(i)); } } ), diff --git a/src/mir/cleanup.cpp b/src/mir/cleanup.cpp index 5d32d0c8..b535c7ce 100644 --- a/src/mir/cleanup.cpp +++ b/src/mir/cleanup.cpp @@ -33,7 +33,7 @@ struct MirMutator ::MIR::LValue new_temporary(::HIR::TypeRef ty) { - auto rv = ::MIR::LValue::make_Local( static_cast(m_fcn.locals.size()) ); + auto rv = ::MIR::LValue::new_Local( static_cast(m_fcn.locals.size()) ); m_fcn.locals.push_back( mv$(ty) ); return rv; } @@ -493,12 +493,13 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const MIR::TypeResolve& state, con // Allocate a temporary for the vtable pointer itself auto vtable_lv = mutator.new_temporary( mv$(vtable_ty) ); // - Load the vtable and store it - auto ptr_lv = ::MIR::LValue::make_Deref({ box$(receiver_lvp.clone()) }); + auto ptr_lv = ::MIR::LValue::new_Deref( receiver_lvp.clone() ); MIR_Cleanup_LValue(state, mutator, ptr_lv); - auto vtable_rval = ::MIR::RValue::make_DstMeta({ mv$(*ptr_lv.as_Deref().val) }); + ptr_lv.m_wrappers.pop_back(); + auto vtable_rval = ::MIR::RValue::make_DstMeta({ mv$(ptr_lv) }); mutator.push_statement( ::MIR::Statement::make_Assign({ vtable_lv.clone(), mv$(vtable_rval) }) ); - auto fcn_lval = ::MIR::LValue::make_Field({ box$(::MIR::LValue::make_Deref({ box$(vtable_lv) })), vtable_idx }); + auto fcn_lval = ::MIR::LValue::new_Field( ::MIR::LValue::new_Deref( mv$(vtable_lv) ), vtable_idx ); ::HIR::TypeRef tmp; const auto& ty = state.get_lvalue_type(tmp, fcn_lval); @@ -526,23 +527,23 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const MIR::TypeResolve& state, con ), (Tuple, for(unsigned int i = 0; i < se.size(); i ++ ) { - auto val = (i == se.size() - 1 ? mv$(lv) : lv.clone()); + auto val = ::MIR::LValue::new_Field( (i == se.size() - 1 ? mv$(lv) : lv.clone()), i ); if( i == str.m_struct_markings.coerce_unsized_index ) { - vals.push_back( H::get_unit_ptr(state, mutator, monomorph(se[i].ent), ::MIR::LValue::make_Field({ box$(val), i }) ) ); + vals.push_back( H::get_unit_ptr(state, mutator, monomorph(se[i].ent), mv$(val)) ); } else { - vals.push_back( ::MIR::LValue::make_Field({ box$(val), i }) ); + vals.push_back( mv$(val) ); } } ), (Named, for(unsigned int i = 0; i < se.size(); i ++ ) { - auto val = (i == se.size() - 1 ? mv$(lv) : lv.clone()); + auto val = ::MIR::LValue::new_Field( (i == se.size() - 1 ? mv$(lv) : lv.clone()), i ); if( i == str.m_struct_markings.coerce_unsized_index ) { - vals.push_back( H::get_unit_ptr(state, mutator, monomorph(se[i].second.ent), ::MIR::LValue::make_Field({ box$(val), i }) ) ); + vals.push_back( H::get_unit_ptr(state, mutator, monomorph(se[i].second.ent), mv$(val) ) ); } else { - vals.push_back( ::MIR::LValue::make_Field({ box$(val), i }) ); + vals.push_back( mv$(val) ); } } ) @@ -777,7 +778,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator& auto ty_d = monomorphise_type_with(state.sp, se[i].ent, monomorph_cb_d, false); auto ty_s = monomorphise_type_with(state.sp, se[i].ent, monomorph_cb_s, false); - auto new_rval = MIR_Cleanup_CoerceUnsized(state, mutator, ty_d, ty_s, ::MIR::LValue::make_Field({ box$(value.clone()), i })); + auto new_rval = MIR_Cleanup_CoerceUnsized(state, mutator, ty_d, ty_s, ::MIR::LValue::new_Field(value.clone(), i)); auto new_lval = mutator.in_temporary( mv$(ty_d), mv$(new_rval) ); ents.push_back( mv$(new_lval) ); @@ -793,7 +794,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator& } else { - ents.push_back( ::MIR::LValue::make_Field({ box$(value.clone()), i}) ); + ents.push_back( ::MIR::LValue::new_Field(value.clone(), i) ); } } ), @@ -806,7 +807,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator& auto ty_d = monomorphise_type_with(state.sp, se[i].second.ent, monomorph_cb_d, false); auto ty_s = monomorphise_type_with(state.sp, se[i].second.ent, monomorph_cb_s, false); - auto new_rval = MIR_Cleanup_CoerceUnsized(state, mutator, ty_d, ty_s, ::MIR::LValue::make_Field({ box$(value.clone()), i })); + auto new_rval = MIR_Cleanup_CoerceUnsized(state, mutator, ty_d, ty_s, ::MIR::LValue::new_Field(value.clone(), i)); auto new_lval = mutator.new_temporary( mv$(ty_d) ); mutator.push_statement( ::MIR::Statement::make_Assign({ new_lval.clone(), mv$(new_rval) }) ); @@ -823,7 +824,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator& } else { - ents.push_back( ::MIR::LValue::make_Field({ box$(value.clone()), i}) ); + ents.push_back( ::MIR::LValue::new_Field(value.clone(), i) ); } } ) @@ -865,7 +866,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator& void MIR_Cleanup_LValue(const ::MIR::TypeResolve& state, MirMutator& mutator, ::MIR::LValue& lval) { - TU_MATCHA( (lval), (le), + TU_MATCHA( (lval.m_root), (le), (Return, ), (Argument, @@ -873,30 +874,22 @@ void MIR_Cleanup_LValue(const ::MIR::TypeResolve& state, MirMutator& mutator, :: (Local, ), (Static, - ), - (Field, - MIR_Cleanup_LValue(state, mutator, *le.val); - ), - (Deref, - MIR_Cleanup_LValue(state, mutator, *le.val); - ), - (Index, - MIR_Cleanup_LValue(state, mutator, *le.val); - MIR_Cleanup_LValue(state, mutator, *le.idx); - ), - (Downcast, - MIR_Cleanup_LValue(state, mutator, *le.val); ) ) - // If this is a deref of Box, unpack and deref the inner pointer - if( lval.is_Deref() ) + for(size_t i = 0; i < lval.m_wrappers.size(); i ++) { - auto& le = lval.as_Deref(); + if( !lval.m_wrappers[i].is_Deref() ) { + continue ; + } + + // If this is a deref of Box, unpack and deref the inner pointer ::HIR::TypeRef tmp; - const auto& ty = state.get_lvalue_type(tmp, *le.val); + const auto& ty = state.get_lvalue_type(tmp, lval, lval.m_wrappers.size() - i); if( state.m_resolve.is_type_owned_box(ty) ) { + unsigned num_injected_fld_zeros = 0; + // Handle Box by extracting it to its pointer. // - Locate (or remember) which field in Box is the pointer, and replace the inner by that field // > Dumb idea, assume it's always the first field. Keep accessing until located. @@ -924,11 +917,16 @@ void MIR_Cleanup_LValue(const ::MIR::TypeResolve& state, MirMutator& mutator, :: tmp = monomorphise_type(state.sp, str.m_params, te.path.m_data.as_Generic().m_params, *ty_tpl); typ = &tmp; - auto new_lval = ::MIR::LValue::make_Field({ mv$(le.val), 0 }); - le.val = box$(new_lval); + num_injected_fld_zeros ++; } MIR_ASSERT(state, typ->m_data.is_Pointer(), "First non-path field in Box wasn't a pointer - " << *typ); // We have reached the pointer. Good. + + // Inject all of the field zero accesses (before the deref) + while(num_injected_fld_zeros--) + { + lval.m_wrappers.insert( lval.m_wrappers.begin() + i, ::MIR::LValue::Wrapper::new_Field(0) ); + } } } } @@ -1030,9 +1028,9 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, ), (DstMeta, // HACK: Ensure that the box Deref conversion fires here. - auto v = ::MIR::LValue::make_Deref({ box$(re.val) }); - MIR_Cleanup_LValue(state, mutator, v); - re.val = mv$( *v.as_Deref().val ); + re.val.m_wrappers.push_back( ::MIR::LValue::Wrapper::new_Deref() ); + MIR_Cleanup_LValue(state, mutator, re.val); + re.val.m_wrappers.pop_back(); // If the type is an array (due to a monomorpised generic?) then replace. ::HIR::TypeRef tmp; @@ -1053,9 +1051,9 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, ), (DstPtr, // HACK: Ensure that the box Deref conversion fires here. - auto v = ::MIR::LValue::make_Deref({ box$(re.val) }); - MIR_Cleanup_LValue(state, mutator, v); - re.val = mv$( *v.as_Deref().val ); + re.val.m_wrappers.push_back( ::MIR::LValue::Wrapper::new_Deref() ); + MIR_Cleanup_LValue(state, mutator, re.val); + re.val.m_wrappers.pop_back(); ), (MakeDst, MIR_Cleanup_Param(state, mutator, re.ptr_val); @@ -1218,13 +1216,13 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, e.args.reserve( fcn_ty.m_arg_types.size() ); for(unsigned int i = 0; i < fcn_ty.m_arg_types.size(); i ++) { - e.args.push_back( ::MIR::LValue::make_Field({ box$(args_lvalue.clone()), i }) ); + e.args.push_back( ::MIR::LValue::new_Field(args_lvalue.clone(), i) ); } // If the trait is Fn/FnMut, dereference the input value. if( pe.trait.m_path == resolve.m_lang_FnOnce ) e.fcn = mv$(fcn_lvalue); else - e.fcn = ::MIR::LValue::make_Deref({ box$(fcn_lvalue) }); + e.fcn = ::MIR::LValue::new_Deref( mv$(fcn_lvalue) ); } } ) diff --git a/src/mir/dump.cpp b/src/mir/dump.cpp index b02c1e5b..69ffa850 100644 --- a/src/mir/dump.cpp +++ b/src/mir/dump.cpp @@ -176,40 +176,7 @@ namespace { #undef FMT } void fmt_val(::std::ostream& os, const ::MIR::LValue& lval) { - TU_MATCHA( (lval), (e), - (Return, - os << "RETURN"; - ), - (Argument, - os << "arg$" << e.idx; - ), - (Local, - os << "_$" << e; - ), - (Static, - os << *e; - ), - (Field, - os << "("; - fmt_val(os, *e.val); - os << ")." << e.field_index; - ), - (Deref, - os << "*"; - fmt_val(os, *e.val); - ), - (Index, - os << "("; - fmt_val(os, *e.val); - os << ")["; - fmt_val(os, *e.idx); - os << "]"; - ), - (Downcast, - fmt_val(os, *e.val); - os << " as variant" << e.variant_index; - ) - ) + os << lval; } void fmt_val(::std::ostream& os, const ::MIR::Constant& e) { TU_MATCHA( (e), (ce), diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index 9e749811..d511a32a 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -177,7 +177,7 @@ namespace { for(size_t i = 0; i < pat.m_binding.m_implicit_deref_count; i ++) { - lval = ::MIR::LValue::make_Deref({ box$(lval) }); + lval = ::MIR::LValue::new_Deref(mv$(lval)); } switch( pat.m_binding.m_type ) @@ -215,35 +215,35 @@ namespace { for(size_t i = 0; i < pat.m_implicit_deref_count; i ++) { - lval = ::MIR::LValue::make_Deref({ box$( mv$(lval) ) }); + lval = ::MIR::LValue::new_Deref(mv$(lval)); } TU_MATCH_HDRA( (pat.m_data), {) TU_ARMA(Any, e) { } TU_ARMA(Box, e) { - destructure_from_ex(sp, *e.sub, ::MIR::LValue::make_Deref({ box$( mv$(lval) ) }), allow_refutable); + destructure_from_ex(sp, *e.sub, ::MIR::LValue::new_Deref(mv$(lval)), allow_refutable); } TU_ARMA(Ref, e) { - destructure_from_ex(sp, *e.sub, ::MIR::LValue::make_Deref({ box$( mv$(lval) ) }), allow_refutable); + destructure_from_ex(sp, *e.sub, ::MIR::LValue::new_Deref(mv$(lval)), allow_refutable); } TU_ARMA(Tuple, e) { for(unsigned int i = 0; i < e.sub_patterns.size(); i ++ ) { - destructure_from_ex(sp, e.sub_patterns[i], ::MIR::LValue::make_Field({ box$( lval.clone() ), i}), allow_refutable); + destructure_from_ex(sp, e.sub_patterns[i], ::MIR::LValue::new_Field(lval.clone(), i), allow_refutable); } } TU_ARMA(SplitTuple, e) { assert(e.total_size >= e.leading.size() + e.trailing.size()); for(unsigned int i = 0; i < e.leading.size(); i ++ ) { - destructure_from_ex(sp, e.leading[i], ::MIR::LValue::make_Field({ box$( lval.clone() ), i}), allow_refutable); + destructure_from_ex(sp, e.leading[i], ::MIR::LValue::new_Field(lval.clone(), i), allow_refutable); } // TODO: Is there a binding in the middle? unsigned int ofs = e.total_size - e.trailing.size(); for(unsigned int i = 0; i < e.trailing.size(); i ++ ) { - destructure_from_ex(sp, e.trailing[i], ::MIR::LValue::make_Field({ box$( lval.clone() ), ofs+i}), allow_refutable); + destructure_from_ex(sp, e.trailing[i], ::MIR::LValue::new_Field(lval.clone(), ofs+i), allow_refutable); } } TU_ARMA(StructValue, e) { @@ -252,7 +252,7 @@ namespace { TU_ARMA(StructTuple, e) { for(unsigned int i = 0; i < e.sub_patterns.size(); i ++ ) { - destructure_from_ex(sp, e.sub_patterns[i], ::MIR::LValue::make_Field({ box$( lval.clone() ), i}), allow_refutable); + destructure_from_ex(sp, e.sub_patterns[i], ::MIR::LValue::new_Field(lval.clone(), i), allow_refutable); } } TU_ARMA(Struct, e) { @@ -264,7 +264,7 @@ namespace { for(const auto& fld_pat : e.sub_patterns) { unsigned idx = ::std::find_if( fields.begin(), fields.end(), [&](const auto&x){ return x.first == fld_pat.first; } ) - fields.begin(); - destructure_from_ex(sp, fld_pat.second, ::MIR::LValue::make_Field({ box$( lval.clone() ), idx}), allow_refutable); + destructure_from_ex(sp, fld_pat.second, ::MIR::LValue::new_Field(lval.clone(), idx), allow_refutable); } } } @@ -302,10 +302,10 @@ namespace { ERROR(sp, E0000, "Variant " << variants[i].name << " not handled"); } } - auto lval_var = ::MIR::LValue::make_Downcast({ box$(mv$(lval)), e.binding_idx }); + auto lval_var = ::MIR::LValue::new_Downcast(mv$(lval), e.binding_idx); for(unsigned int i = 0; i < e.sub_patterns.size(); i ++ ) { - destructure_from_ex(sp, e.sub_patterns[i], ::MIR::LValue::make_Field({ box$( lval_var.clone() ), i}), allow_refutable); + destructure_from_ex(sp, e.sub_patterns[i], ::MIR::LValue::new_Field(lval_var.clone(), i), allow_refutable); } } TU_ARMA(EnumStruct, e) { @@ -316,11 +316,11 @@ namespace { const auto& str = *var.type.m_data.as_Path().binding.as_Struct(); ASSERT_BUG(sp, str.m_data.is_Named(), "Struct pattern on non-Named struct - " << e.path); const auto& fields = str.m_data.as_Named(); - auto lval_var = ::MIR::LValue::make_Downcast({ box$(mv$(lval)), e.binding_idx }); + auto lval_var = ::MIR::LValue::new_Downcast(mv$(lval), e.binding_idx); for(const auto& fld_pat : e.sub_patterns) { unsigned idx = ::std::find_if( fields.begin(), fields.end(), [&](const auto&x){ return x.first == fld_pat.first; } ) - fields.begin(); - destructure_from_ex(sp, fld_pat.second, ::MIR::LValue::make_Field({ box$( lval_var.clone() ), idx}), allow_refutable); + destructure_from_ex(sp, fld_pat.second, ::MIR::LValue::new_Field(lval_var.clone(), idx), allow_refutable); } } TU_ARMA(Slice, e) { @@ -335,7 +335,7 @@ namespace { for(unsigned int i = 0; i < e.sub_patterns.size(); i ++) { const auto& subpat = e.sub_patterns[i]; - destructure_from_ex(sp, subpat, ::MIR::LValue::make_Field({ box$(lval.clone()), i }), allow_refutable ); + destructure_from_ex(sp, subpat, ::MIR::LValue::new_Field(lval.clone(), i), allow_refutable ); } } else @@ -346,7 +346,7 @@ namespace { for(unsigned int i = 0; i < e.sub_patterns.size(); i ++) { const auto& subpat = e.sub_patterns[i]; - destructure_from_ex(sp, subpat, ::MIR::LValue::make_Field({ box$(lval.clone()), i }), allow_refutable ); + destructure_from_ex(sp, subpat, ::MIR::LValue::new_Field(lval.clone(), i), allow_refutable ); } } } @@ -374,7 +374,7 @@ namespace { for(unsigned int i = 0; i < e.leading.size(); i ++) { unsigned int idx = 0 + i; - destructure_from_ex(sp, e.leading[i], ::MIR::LValue::make_Field({ box$(lval.clone()), idx }), allow_refutable ); + destructure_from_ex(sp, e.leading[i], ::MIR::LValue::new_Field(lval.clone(), idx), allow_refutable ); } if( e.extra_bind.is_valid() ) { @@ -383,7 +383,7 @@ namespace { for(unsigned int i = 0; i < e.trailing.size(); i ++) { unsigned int idx = array_size - e.trailing.size() + i; - destructure_from_ex(sp, e.trailing[i], ::MIR::LValue::make_Field({ box$(lval.clone()), idx }), allow_refutable ); + destructure_from_ex(sp, e.trailing[i], ::MIR::LValue::new_Field(lval.clone(), idx), allow_refutable ); } } else @@ -409,13 +409,13 @@ namespace { ::MIR::LValue len_lval; if( e.extra_bind.is_valid() || e.trailing.size() > 0 ) { - len_lval = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(sp, lval).clone() })); + len_lval = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(sp, lval) })); } for(unsigned int i = 0; i < e.leading.size(); i ++) { unsigned int idx = i; - destructure_from_ex(sp, e.leading[i], ::MIR::LValue::make_Field({ box$(lval.clone()), idx }), allow_refutable ); + destructure_from_ex(sp, e.leading[i], ::MIR::LValue::new_Field(lval.clone(), idx), allow_refutable ); } if( e.extra_bind.is_valid() ) { @@ -427,7 +427,7 @@ namespace { ::HIR::BorrowType bt = H::get_borrow_type(sp, e.extra_bind); ::MIR::LValue ptr_val = m_builder.lvalue_or_temp(sp, ::HIR::TypeRef::new_borrow( bt, inner_type.clone() ), - ::MIR::RValue::make_Borrow({ 0, bt, ::MIR::LValue::make_Field({ box$(lval.clone()), static_cast(e.leading.size()) }) }) + ::MIR::RValue::make_Borrow({ 0, bt, ::MIR::LValue::new_Field( lval.clone(), static_cast(e.leading.size()) ) }) ); // TODO: Cast to raw pointer? Or keep as a borrow? @@ -442,7 +442,7 @@ namespace { auto sub_val = ::MIR::Param(::MIR::Constant::make_Uint({ e.trailing.size() - i, ::HIR::CoreType::Usize })); ::MIR::LValue ofs_val = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_BinOp({ len_lval.clone(), ::MIR::eBinOp::SUB, mv$(sub_val) }) ); // Recurse with the indexed value - destructure_from_ex(sp, e.trailing[i], ::MIR::LValue::make_Index({ box$(lval.clone()), box$(ofs_val) }), allow_refutable); + destructure_from_ex(sp, e.trailing[i], ::MIR::LValue::new_Index( lval.clone(), ofs_val.m_root.as_Local() ), allow_refutable); } } } @@ -574,7 +574,7 @@ namespace { TRACE_FUNCTION_F("_Return"); this->visit_node_ptr(node.m_value); - m_builder.push_stmt_assign( node.span(), ::MIR::LValue::make_Return({}), m_builder.get_result(node.span()) ); + m_builder.push_stmt_assign( node.span(), ::MIR::LValue::new_Return(), m_builder.get_result(node.span()) ); m_builder.terminate_scope_early( node.span(), m_builder.fcn_scope() ); m_builder.end_block( ::MIR::Terminator::make_Return({}) ); } @@ -1474,7 +1474,7 @@ namespace { limit_val = ::MIR::Constant::make_Uint({ e.size_val, ::HIR::CoreType::Usize }); ), (Slice, - limit_val = ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(node.m_value->span(), value).clone() }); + limit_val = ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(node.m_value->span(), value) }); ) ) @@ -1508,7 +1508,13 @@ namespace { m_builder.set_cur_block( arm_continue ); } - m_builder.set_result( node.span(), ::MIR::LValue::make_Index({ box$(value), box$(index) }) ); + if( !index.is_Local()) + { + auto local_idx = m_builder.new_temporary(::HIR::CoreType::Usize); + m_builder.push_stmt_assign(node.span(), local_idx.clone(), mv$(index)); + index = mv$(local_idx); + } + m_builder.set_result( node.span(), ::MIR::LValue::new_Index( mv$(value), index.m_root.as_Local() ) ); } void visit(::HIR::ExprNode_Deref& node) override @@ -1591,7 +1597,7 @@ namespace { } } - m_builder.set_result( node.span(), ::MIR::LValue::make_Deref({ box$(val) }) ); + m_builder.set_result( node.span(), ::MIR::LValue::new_Deref( mv$(val) ) ); } void visit(::HIR::ExprNode_Emplace& node) override @@ -1702,7 +1708,7 @@ namespace { // 3. Get the value and assign it into `place_raw` node.m_value->visit(*this); auto val = m_builder.get_result(node.span()); - m_builder.push_stmt_assign( node.span(), ::MIR::LValue::make_Deref({ box$(place_raw.clone()) }), mv$(val) ); + m_builder.push_stmt_assign( node.span(), ::MIR::LValue::new_Deref(place_raw.clone()), mv$(val), /*drop_destination=*/false ); // 3. Return a call to `finalize` ::HIR::Path finalize_path(::HIR::GenericPath {}); @@ -1806,9 +1812,7 @@ namespace { auto place = m_builder.new_temporary( place_type ); m_builder.push_stmt_assign(node.span(), place.clone(), ::MIR::RValue::make_Cast({ mv$(place_raw), place_type.clone() })); // 3. Do a non-dropping write into the target location (i.e. just a MIR assignment) - // TODO: This should indicate that the destination shouldn't be dropped, but since drops don't happen on - // reassign currently, that's not yet an issue. - m_builder.push_stmt_assign(node.span(), ::MIR::LValue::make_Deref({box$(place.clone())}), mv$(val)); + m_builder.push_stmt_assign(node.span(), ::MIR::LValue::new_Deref(place.clone()), mv$(val), /*drop_destination=*/false); // 4. Convert the pointer into an `owned_box` auto res_type = ::HIR::TypeRef::new_path(::HIR::GenericPath(lang_owned_box, mv$(trait_params_data)), &m_builder.crate().get_struct_by_path(node.span(), lang_owned_box)); auto res = m_builder.new_temporary(res_type); @@ -2056,20 +2060,20 @@ namespace { unsigned int idx; if( ::std::isdigit(node.m_field.c_str()[0]) ) { ::std::stringstream(node.m_field.c_str()) >> idx; - m_builder.set_result( node.span(), ::MIR::LValue::make_Field({ box$(val), idx }) ); + m_builder.set_result( node.span(), ::MIR::LValue::new_Field( mv$(val), idx ) ); } else if( const auto* bep = val_ty.m_data.as_Path().binding.opt_Struct() ) { const auto& str = **bep; const auto& fields = str.m_data.as_Named(); idx = ::std::find_if( fields.begin(), fields.end(), [&](const auto& x){ return x.first == node.m_field; } ) - fields.begin(); - m_builder.set_result( node.span(), ::MIR::LValue::make_Field({ box$(val), idx }) ); + m_builder.set_result( node.span(), ::MIR::LValue::new_Field( mv$(val), idx ) ); } else if( const auto* bep = val_ty.m_data.as_Path().binding.opt_Union() ) { const auto& unm = **bep; const auto& fields = unm.m_variants; idx = ::std::find_if( fields.begin(), fields.end(), [&](const auto& x){ return x.first == node.m_field; } ) - fields.begin(); - m_builder.set_result( node.span(), ::MIR::LValue::make_Downcast({ box$(val), idx }) ); + m_builder.set_result( node.span(), ::MIR::LValue::new_Downcast( mv$(val), idx ) ); } else { BUG(node.span(), "Field access on non-union/struct - " << val_ty); @@ -2202,7 +2206,7 @@ namespace { m_builder.set_result( node.span(), mv$(tmp) ); ), (Static, - m_builder.set_result( node.span(), ::MIR::LValue::make_Static(box$(node.m_path.clone())) ); + m_builder.set_result( node.span(), ::MIR::LValue::new_Static(node.m_path.clone()) ); ), (StructConstant, // TODO: Why is this still a PathValue? @@ -2321,7 +2325,7 @@ namespace { ASSERT_BUG(sp, str.m_data.is_Named(), ""); const ::HIR::t_struct_fields& fields = str.m_data.as_Named(); - ::MIR::LValue base_val; + auto base_val = ::MIR::LValue::new_Return(); if( node.m_base_value ) { DEBUG("_StructLiteral - base"); @@ -2362,7 +2366,7 @@ namespace { if( !node.m_base_value) { ERROR(node.span(), E0000, "Field '" << fields[i].first << "' not specified"); } - values[i] = ::MIR::LValue::make_Field({ box$( base_val.clone() ), i }); + values[i] = ::MIR::LValue::new_Field( base_val.clone(), i ); } else { // Partial move support will handle dropping the rest? @@ -2545,7 +2549,7 @@ namespace { else { ev.define_vars_from(ptr->span(), arg.first); - ev.destructure_from(ptr->span(), arg.first, ::MIR::LValue::make_Argument({i})); + ev.destructure_from(ptr->span(), arg.first, ::MIR::LValue::new_Argument(i)); } i ++; } diff --git a/src/mir/from_hir.hpp b/src/mir/from_hir.hpp index 194fd0e0..a1f9a10f 100644 --- a/src/mir/from_hir.hpp +++ b/src/mir/from_hir.hpp @@ -188,13 +188,10 @@ public: // - Values ::MIR::LValue get_variable(const Span& sp, unsigned idx) const { - // DIASBLED: State tracking doesn't support arguments in loops/splits -#if 1 auto it = m_var_arg_mappings.find(idx); if(it != m_var_arg_mappings.end()) - return ::MIR::LValue::make_Argument({ it->second }); -#endif - return ::MIR::LValue::make_Local( idx ); + return ::MIR::LValue::new_Argument(it->second); + return ::MIR::LValue::new_Local(idx); } ::MIR::LValue new_temporary(const ::HIR::TypeRef& ty); ::MIR::LValue lvalue_or_temp(const Span& sp, const ::HIR::TypeRef& ty, ::MIR::RValue val); @@ -224,7 +221,7 @@ public: // - Statements // Push an assignment. NOTE: This also marks the rvalue as moved - void push_stmt_assign(const Span& sp, ::MIR::LValue dst, ::MIR::RValue val); + void push_stmt_assign(const Span& sp, ::MIR::LValue dst, ::MIR::RValue val, bool drop_destination=true); // Push a drop (likely only used by scope cleanup) void push_stmt_drop(const Span& sp, ::MIR::LValue val, unsigned int drop_flag=~0u); // Push a shallow drop (for Box) @@ -296,7 +293,7 @@ private: const VarState& get_slot_state(const Span& sp, unsigned int idx, SlotType type, unsigned int skip_count=0) const; VarState& get_slot_state_mut(const Span& sp, unsigned int idx, SlotType type); - const VarState& get_val_state(const Span& sp, const ::MIR::LValue& lv, unsigned int skip_count=0); + VarState* get_val_state_mut_p(const Span& sp, const ::MIR::LValue& lv); VarState& get_val_state_mut(const Span& sp, const ::MIR::LValue& lv); void terminate_loop_early(const Span& sp, ScopeType::Data_Loop& sd_loop); @@ -306,11 +303,11 @@ private: void complete_scope(ScopeDef& sd); public: - void with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::function cb) const; + void with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::function cb, const ::MIR::LValue::Wrapper* stop_wrapper=nullptr) const; bool lvalue_is_copy(const Span& sp, const ::MIR::LValue& lv) const; // Obtain the base fat poiner for a dst reference. Errors if it wasn't via a fat pointer - const ::MIR::LValue& get_ptr_to_dst(const Span& sp, const ::MIR::LValue& lv) const; + ::MIR::LValue get_ptr_to_dst(const Span& sp, const ::MIR::LValue& lv) const; }; class MirConverter: diff --git a/src/mir/from_hir_match.cpp b/src/mir/from_hir_match.cpp index e3ddce30..2bfb1a27 100644 --- a/src/mir/from_hir_match.cpp +++ b/src/mir/from_hir_match.cpp @@ -1732,13 +1732,13 @@ namespace { ), (Tuple, ASSERT_BUG(sp, idx < e.size(), "Tuple index out of range"); - lval = ::MIR::LValue::make_Field({ box$(lval), idx }); + lval = ::MIR::LValue::new_Field(mv$(lval), idx); cur_ty = &e[idx]; ), (Path, if( idx == FIELD_DEREF ) { // TODO: Check that the path is Box - lval = ::MIR::LValue::make_Deref({ box$(lval) }); + lval = ::MIR::LValue::new_Deref( mv$(lval) ); cur_ty = &e.path.m_data.as_Generic().m_params.m_types.at(0); break; } @@ -1773,7 +1773,7 @@ namespace { else { cur_ty = &fld.ent; } - lval = ::MIR::LValue::make_Field({ box$(lval), idx }); + lval = ::MIR::LValue::new_Field(mv$(lval), idx); ), (Named, assert( idx < fields.size() ); @@ -1785,7 +1785,7 @@ namespace { else { cur_ty = &fld.ent; } - lval = ::MIR::LValue::make_Field({ box$(lval), idx }); + lval = ::MIR::LValue::new_Field(mv$(lval), idx); ) ) ), @@ -1804,7 +1804,7 @@ namespace { else { cur_ty = &fld.second.ent; } - lval = ::MIR::LValue::make_Downcast({ box$(lval), idx }); + lval = ::MIR::LValue::new_Downcast(mv$(lval), idx); ), (Enum, auto monomorph_to_ptr = [&](const auto& ty)->const auto* { @@ -1824,7 +1824,7 @@ namespace { const auto& var = variants[idx]; cur_ty = monomorph_to_ptr(var.type); - lval = ::MIR::LValue::make_Downcast({ box$(lval), idx }); + lval = ::MIR::LValue::new_Downcast(mv$(lval), idx); ) ) ), @@ -1841,7 +1841,7 @@ namespace { assert(idx < e.size_val); cur_ty = &*e.inner; if( idx < FIELD_INDEX_MAX ) - lval = ::MIR::LValue::make_Field({ box$(lval), idx }); + lval = ::MIR::LValue::new_Field(mv$(lval), idx); else { idx -= FIELD_INDEX_MAX; idx = FIELD_INDEX_MAX - idx; @@ -1851,16 +1851,16 @@ namespace { (Slice, cur_ty = &*e.inner; if( idx < FIELD_INDEX_MAX ) - lval = ::MIR::LValue::make_Field({ box$(lval), idx }); + lval = ::MIR::LValue::new_Field(mv$(lval), idx); else { idx -= FIELD_INDEX_MAX; idx = FIELD_INDEX_MAX - idx; // 1. Create an LValue containing the size of this slice subtract `idx` - auto len_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ builder.get_ptr_to_dst(sp, lval).clone() })); + auto len_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ builder.get_ptr_to_dst(sp, lval) })); auto sub_val = ::MIR::Param(::MIR::Constant::make_Uint({ idx, ::HIR::CoreType::Usize })); auto ofs_val = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_BinOp({ mv$(len_lval), ::MIR::eBinOp::SUB, mv$(sub_val) }) ); // 2. Return _Index with that value - lval = ::MIR::LValue::make_Index({ box$(lval), box$(ofs_val) }); + lval = ::MIR::LValue::new_Index(mv$(lval), ofs_val.as_Local()); } ), (Borrow, @@ -1874,7 +1874,7 @@ namespace { cur_ty = &*e.inner; } DEBUG(i << " " << *cur_ty); - lval = ::MIR::LValue::make_Deref({ box$(lval) }); + lval = ::MIR::LValue::new_Deref(mv$(lval)); ), (Pointer, ERROR(sp, E0000, "Attempting to match over a pointer"); @@ -1978,14 +1978,14 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& DEBUG("ty = " << ity << ", val = " << val); const auto& ty = ity; - TU_MATCHA( (ty.m_data), (te), - (Infer, + TU_MATCH_HDRA( (ty.m_data), {) + TU_ARMA(Infer, _te) { BUG(sp, "Hit _ in type - " << ty); - ), - (Diverge, + } + TU_ARMA(Diverge, _te) { BUG(sp, "Matching over !"); - ), - (Primitive, + } + TU_ARMA(Primitive, te) { switch(te) { case ::HIR::CoreType::Bool: { @@ -2152,17 +2152,20 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& case ::HIR::CoreType::Str: { ASSERT_BUG(sp, rule.is_Value() && rule.as_Value().is_StaticString(), ""); const auto& v = rule.as_Value(); + ASSERT_BUG(sp, val.is_Deref(), ""); + val.m_wrappers.pop_back(); + auto str_val = mv$(val); auto succ_bb = builder.new_bb_unlinked(); auto test_val = ::MIR::Param(::MIR::Constant( v.as_StaticString() )); - auto cmp_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ mv$(*val.as_Deref().val), ::MIR::eBinOp::EQ, mv$(test_val) })); + auto cmp_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ mv$(str_val), ::MIR::eBinOp::EQ, mv$(test_val) })); builder.end_block( ::MIR::Terminator::make_If({ mv$(cmp_lval), succ_bb, fail_bb }) ); builder.set_cur_block(succ_bb); } break; } - ), - (Path, + } + TU_ARMA(Path, te) { TU_MATCHA( (te.binding), (pbe), (Unbound, BUG(sp, "Encounterd unbound path - " << te.path); @@ -2221,26 +2224,26 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& // Recurse with the new ruleset MIR_LowerHIR_Match_Simple__GeneratePattern(builder, sp, re.sub_rules.data(), re.sub_rules.size(), - var_ty_m, ::MIR::LValue::make_Downcast({ box$(val.clone()), var_idx }), rule.field_path.size()+1, + var_ty_m, ::MIR::LValue::new_Downcast(val.clone(), var_idx), rule.field_path.size()+1, fail_bb ); } ) // TypePathBinding::Enum ) - ), // Type::Data::Path - (Generic, + } // Type::Data::Path + TU_ARMA(Generic, _te) { BUG(sp, "Attempting to match a generic"); - ), - (TraitObject, + } + TU_ARMA(TraitObject, te) { BUG(sp, "Attempting to match a trait object"); - ), - (ErasedType, + } + TU_ARMA(ErasedType, te) { BUG(sp, "Attempting to match an erased type"); - ), - (Array, + } + TU_ARMA(Array, te) { TODO(sp, "Match directly on array?"); - ), - (Slice, + } + TU_ARMA(Slice, te) { ASSERT_BUG(sp, rule.is_Slice() || rule.is_SplitSlice() || (rule.is_Value() && rule.as_Value().is_Bytes()), "Can only match slice with Bytes or Slice rules - " << rule); if( rule.is_Value() ) { ASSERT_BUG(sp, *te.inner == ::HIR::CoreType::U8, "Bytes pattern on non-&[u8]"); @@ -2249,7 +2252,8 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& auto succ_bb = builder.new_bb_unlinked(); - auto inner_val = val.as_Deref().val->clone(); + ASSERT_BUG(sp, val.is_Deref(), "Slice pattern on non-Deref - " << val); + auto inner_val = val.clone_unwrapped(); auto slice_rval = ::MIR::RValue::make_MakeDst({ mv$(cloned_val), mv$(size_val) }); auto test_lval = builder.lvalue_or_temp(sp, ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, ty.clone()), mv$(slice_rval)); @@ -2262,7 +2266,7 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& // Compare length auto test_val = ::MIR::Param( ::MIR::Constant::make_Uint({ re.len, ::HIR::CoreType::Usize }) ); - auto len_val = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ builder.get_ptr_to_dst(sp, val).clone() })); + auto len_val = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ builder.get_ptr_to_dst(sp, val) })); auto cmp_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ mv$(len_val), ::MIR::eBinOp::EQ, mv$(test_val) })); auto len_succ_bb = builder.new_bb_unlinked(); @@ -2281,7 +2285,7 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& // Compare length auto test_val = ::MIR::Param( ::MIR::Constant::make_Uint({ re.min_len, ::HIR::CoreType::Usize}) ); - auto len_val = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ builder.get_ptr_to_dst(sp, val).clone() })); + auto len_val = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ builder.get_ptr_to_dst(sp, val) })); auto cmp_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ mv$(len_val), ::MIR::eBinOp::LT, mv$(test_val) })); auto len_succ_bb = builder.new_bb_unlinked(); @@ -2302,23 +2306,23 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& else { BUG(sp, "Invalid rule type for slice - " << rule); } - ), - (Tuple, + } // Type::Data::Array + TU_ARMA(Tuple, te) { TODO(sp, "Match directly on tuple?"); - ), - (Borrow, + } + TU_ARMA(Borrow, te) { TODO(sp, "Match directly on borrow?"); - ), // Type::Data::Borrow - (Pointer, + } // Type::Data::Borrow + TU_ARMA(Pointer, te) { BUG(sp, "Attempting to match a pointer - " << rule << " against " << ty); - ), - (Function, + } + TU_ARMA(Function, te) { BUG(sp, "Attempting to match a function pointer - " << rule << " against " << ty); - ), - (Closure, + } + TU_ARMA(Closure, te) { BUG(sp, "Attempting to match a closure"); - ) - ) + } + } } return 0; } @@ -3035,10 +3039,10 @@ void MatchGenGrouped::gen_dispatch__primitive(::HIR::TypeRef ty, ::MIR::LValue v } m_builder.end_block( ::MIR::Terminator::make_Goto(def_blk) ); } break; - case ::HIR::CoreType::Str: + case ::HIR::CoreType::Str: { // Remove the deref on the &str - auto oval = mv$(val); - auto val = mv$(*oval.as_Deref().val); + ASSERT_BUG(sp, !val.m_wrappers.empty() && val.m_wrappers.back().is_Deref(), "&str match on non-Deref lvalue - " << val); + val.m_wrappers.pop_back(); ::std::vector< ::MIR::BasicBlockId> targets; ::std::vector< ::std::string> values; @@ -3062,7 +3066,7 @@ void MatchGenGrouped::gen_dispatch__primitive(::HIR::TypeRef ty, ::MIR::LValue v m_builder.end_block( ::MIR::Terminator::make_SwitchValue({ mv$(val), def_blk, mv$(targets), ::MIR::SwitchValues(mv$(values)) }) ); - break; + } break; } } @@ -3100,7 +3104,7 @@ void MatchGenGrouped::gen_dispatch__enum(::HIR::TypeRef ty, ::MIR::LValue val, c void MatchGenGrouped::gen_dispatch__slice(::HIR::TypeRef ty, ::MIR::LValue val, const ::std::vector& rules, size_t ofs, const ::std::vector<::MIR::BasicBlockId>& arm_targets, ::MIR::BasicBlockId def_blk) { - auto val_len = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(sp, val).clone() })); + auto val_len = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(sp, val) })); // TODO: Re-sort the rules list to interleve Constant::Bytes and Slice @@ -3162,8 +3166,8 @@ void MatchGenGrouped::gen_dispatch__slice(::HIR::TypeRef ty, ::MIR::LValue val, m_builder.set_cur_block(succ_blk); // TODO: What if `val` isn't a Deref? - ASSERT_BUG(sp, val.is_Deref(), "TODO: Handle non-Deref matches of byte strings"); - cmp_lval_eq = this->push_compare( val.as_Deref().val->clone(), ::MIR::eBinOp::EQ, mv$(cmp_slice_val) ); + ASSERT_BUG(sp, !val.m_wrappers.empty() && val.m_wrappers.back().is_Deref(), "TODO: Handle non-Deref matches of byte strings - " << val); + cmp_lval_eq = this->push_compare( val.clone_unwrapped(), ::MIR::eBinOp::EQ, mv$(cmp_slice_val) ); m_builder.end_block( ::MIR::Terminator::make_If({ mv$(cmp_lval_eq), arm_targets[tgt_ofs], def_blk }) ); m_builder.set_cur_block(next_cmp_blk); @@ -3273,7 +3277,7 @@ void MatchGenGrouped::gen_dispatch_splitslice(const field_path_t& field_path, co ASSERT_BUG(sp, ty.m_data.is_Slice(), "SplitSlice pattern on non-slice - " << ty); // Obtain slice length - auto val_len = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(sp, val).clone() })); + auto val_len = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(sp, val) })); // 1. Check that length is sufficient for the pattern to be used // `IF len < min_len : def_blk, next diff --git a/src/mir/helpers.cpp b/src/mir/helpers.cpp index 1453acb3..6f0ef891 100644 --- a/src/mir/helpers.cpp +++ b/src/mir/helpers.cpp @@ -12,9 +12,12 @@ #include #include // ::std::find -void ::MIR::TypeResolve::fmt_pos(::std::ostream& os) const +void ::MIR::TypeResolve::fmt_pos(::std::ostream& os, bool include_path/*=false*/) const { - os << this->m_path << " BB" << this->bb_idx << "/"; + if( include_path ) { + os << this->m_path << " "; + } + os << "BB" << this->bb_idx << "/"; if( this->stmt_idx == STMT_TERM ) { os << "TERM"; } @@ -27,7 +30,7 @@ void ::MIR::TypeResolve::print_msg(const char* tag, ::std::functionget_lvalue_type(tmp, *e.val); + rv = &get_static_type(tmp, e); + ) + ) + assert(wrapper_skip_count <= val.m_wrappers.size()); + const auto* stop_wrapper = &val.m_wrappers[ val.m_wrappers.size() - wrapper_skip_count ]; + for(const auto& w : val.m_wrappers) + { + if( &w == stop_wrapper ) + break; + rv = &this->get_unwrapped_type(tmp, w, *rv); + } + return *rv; +} +const ::HIR::TypeRef& ::MIR::TypeResolve::get_unwrapped_type(::HIR::TypeRef& tmp, const ::MIR::LValue::Wrapper& w, const ::HIR::TypeRef& ty) const +{ + TU_MATCH_HDRA( (w), {) + TU_ARMA(Field, field_index) { TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te), ( MIR_BUG(*this, "Field access on unexpected type - " << ty); @@ -98,14 +115,14 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c return *te.inner; ), (Tuple, - MIR_ASSERT(*this, e.field_index < te.size(), "Field index out of range in tuple " << e.field_index << " >= " << te.size()); - return te[e.field_index]; + MIR_ASSERT(*this, field_index < te.size(), "Field index out of range in tuple " << field_index << " >= " << te.size()); + return te[field_index]; ), (Path, if( const auto* tep = te.binding.opt_Struct() ) { const auto& str = **tep; - auto monomorph = [&](const auto& ty)->const auto& { + auto maybe_monomorph = [&](const auto& ty)->const auto& { if( monomorphise_type_needed(ty) ) { tmp = monomorphise_type(sp, str.m_params, te.path.m_data.as_Generic().m_params, ty); m_resolve.expand_associated_types(sp, tmp); @@ -120,12 +137,12 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c MIR_BUG(*this, "Field on unit-like struct - " << ty); ), (Tuple, - MIR_ASSERT(*this, e.field_index < se.size(), "Field index out of range in tuple-struct " << te.path); - return monomorph(se[e.field_index].ent); + MIR_ASSERT(*this, field_index < se.size(), "Field index out of range in tuple-struct " << te.path); + return maybe_monomorph(se[field_index].ent); ), (Named, - MIR_ASSERT(*this, e.field_index < se.size(), "Field index out of range in struct " << te.path); - return monomorph(se[e.field_index].second.ent); + MIR_ASSERT(*this, field_index < se.size(), "Field index out of range in struct " << te.path); + return maybe_monomorph(se[field_index].second.ent); ) ) } @@ -142,8 +159,8 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c return t; } }; - MIR_ASSERT(*this, e.field_index < unm.m_variants.size(), "Field index out of range for union"); - return maybe_monomorph(unm.m_variants.at(e.field_index).second.ent); + MIR_ASSERT(*this, field_index < unm.m_variants.size(), "Field index out of range for union"); + return maybe_monomorph(unm.m_variants.at(field_index).second.ent); } else { @@ -151,9 +168,8 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c } ) ) - ), - (Deref, - const auto& ty = this->get_lvalue_type(tmp, *e.val); + } + TU_ARMA(Deref, _e) { TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te), ( MIR_BUG(*this, "Deref on unexpected type - " << ty); @@ -174,9 +190,8 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c return *te.inner; ) ) - ), - (Index, - const auto& ty = this->get_lvalue_type(tmp, *e.val); + } + TU_ARMA(Index, index_local) { TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te), ( MIR_BUG(*this, "Index on unexpected type - " << ty); @@ -188,9 +203,8 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c return *te.inner; ) ) - ), - (Downcast, - const auto& ty = this->get_lvalue_type(tmp, *e.val); + } + TU_ARMA(Downcast, variant_index) { TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te), ( MIR_BUG(*this, "Downcast on unexpected type - " << ty); @@ -202,8 +216,8 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c const auto& enm = *te.binding.as_Enum(); MIR_ASSERT(*this, enm.m_data.is_Data(), "Downcast on non-data enum - " << ty); const auto& variants = enm.m_data.as_Data(); - MIR_ASSERT(*this, e.variant_index < variants.size(), "Variant index out of range for " << ty); - const auto& variant = variants[e.variant_index]; + MIR_ASSERT(*this, variant_index < variants.size(), "Variant index out of range for " << ty); + const auto& variant = variants[variant_index]; const auto& var_ty = variant.type; if( monomorphise_type_needed(var_ty) ) { @@ -218,12 +232,13 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c else { const auto& unm = *te.binding.as_Union(); - MIR_ASSERT(*this, e.variant_index < unm.m_variants.size(), "Variant index out of range"); - const auto& variant = unm.m_variants[e.variant_index]; + MIR_ASSERT(*this, variant_index < unm.m_variants.size(), "Variant index out of range"); + const auto& variant = unm.m_variants[variant_index]; const auto& var_ty = variant.second.ent; + //return m_resolve.maybe_monomorph(sp, tmp, unm.m_params, te.path.m_data.as_Generic().m_params, var_ty); if( monomorphise_type_needed(var_ty) ) { - tmp = monomorphise_type(sp, unm.m_params, te.path.m_data.as_Generic().m_params, variant.second.ent); + tmp = monomorphise_type(sp, unm.m_params, te.path.m_data.as_Generic().m_params, var_ty); m_resolve.expand_associated_types(sp, tmp); return tmp; } @@ -233,8 +248,8 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c } ) ) - ) - ) + } + } throw ""; } const ::HIR::TypeRef& MIR::TypeResolve::get_param_type(::HIR::TypeRef& tmp, const ::MIR::Param& val) const @@ -383,6 +398,15 @@ namespace visit { { if( cb(lv, u) ) return true; +#if 1 + for(const auto& w : lv.m_wrappers) + { + if( w.is_Index() ) + { + cb(LValue::new_Local(w.as_Index()), ValUsage::Read); + } + } +#else TU_MATCHA( (lv), (e), (Return, ), @@ -408,6 +432,7 @@ namespace visit { return visit_mir_lvalue(*e.val, u, cb); ) ) +#endif return false; } @@ -625,32 +650,15 @@ void MIR_Helper_GetLifetimes_DetermineValueLifetime(::MIR::TypeResolve& state, c { auto assigned_lvalue = [&](size_t bb_idx, size_t stmt_idx, const ::MIR::LValue& lv) { // NOTE: Fills the first statement after running, just to ensure that any assigned value has _a_ lifetime - if( const auto* de = lv.opt_Local() ) + if( lv.m_root.is_Local() ) { - if( !mask || mask->at(*de) ) + auto de = lv.m_root.as_Local(); + if( !mask || mask->at(de) ) { - MIR_Helper_GetLifetimes_DetermineValueLifetime(state, fcn, bb_idx, stmt_idx, lv, block_offsets, slot_lifetimes[*de]); - slot_lifetimes[*de].fill(block_offsets, bb_idx, stmt_idx, stmt_idx); + MIR_Helper_GetLifetimes_DetermineValueLifetime(state, fcn, bb_idx, stmt_idx, lv, block_offsets, slot_lifetimes[de]); + slot_lifetimes[de].fill(block_offsets, bb_idx, stmt_idx, stmt_idx); } } - else - { - // Not a direct assignment of a slot. But check if a slot is mutated as part of this. - ::MIR::visit::visit_mir_lvalue(lv, ValUsage::Write, [&](const auto& ilv, ValUsage vu) { - if( const auto* de = ilv.opt_Local() ) - { - if( vu == ValUsage::Write ) - { - if( !mask || mask->at(*de) ) - { - MIR_Helper_GetLifetimes_DetermineValueLifetime(state, fcn, bb_idx, stmt_idx, lv, block_offsets, slot_lifetimes[*de]); - slot_lifetimes[*de].fill(block_offsets, bb_idx, stmt_idx, stmt_idx); - } - } - } - return false; - }); - } }; const auto& bb = fcn.blocks[bb_idx]; @@ -673,11 +681,12 @@ void MIR_Helper_GetLifetimes_DetermineValueLifetime(::MIR::TypeResolve& state, c else if( const auto* se = stmt.opt_Drop() ) { // HACK: Mark values as valid wherever there's a drop (prevents confusion by simple validator) - if( const auto* de = se->slot.opt_Local() ) + if( se->slot.m_wrappers.empty() && se->slot.m_root.is_Local() ) { - if( !mask || mask->at(*de) ) + auto de = se->slot.m_root.as_Local(); + if( !mask || mask->at(de) ) { - slot_lifetimes[*de].fill(block_offsets, bb_idx, stmt_idx,stmt_idx); + slot_lifetimes[de].fill(block_offsets, bb_idx, stmt_idx,stmt_idx); } } } diff --git a/src/mir/helpers.hpp b/src/mir/helpers.hpp index 58eee9b9..0296a1c4 100644 --- a/src/mir/helpers.hpp +++ b/src/mir/helpers.hpp @@ -104,7 +104,7 @@ public: } unsigned int get_cur_stmt_ofs() const; - void fmt_pos(::std::ostream& os) const; + void fmt_pos(::std::ostream& os, bool include_path=false) const; void print_bug(::std::function cb) const { print_msg("ERROR", cb); } @@ -116,7 +116,14 @@ public: const ::MIR::BasicBlock& get_block(::MIR::BasicBlockId id) const; const ::HIR::TypeRef& get_static_type(::HIR::TypeRef& tmp, const ::HIR::Path& path) const; - const ::HIR::TypeRef& get_lvalue_type(::HIR::TypeRef& tmp, const ::MIR::LValue& val) const; + const ::HIR::TypeRef& get_lvalue_type(::HIR::TypeRef& tmp, const ::MIR::LValue& val, unsigned wrapper_skip_count=0) const; + const ::HIR::TypeRef& get_lvalue_type(::HIR::TypeRef& tmp, const ::MIR::LValue::CRef& val) const { + return get_lvalue_type(tmp, val.lv(), val.lv().m_wrappers.size() - val.wrapper_count()); + } + const ::HIR::TypeRef& get_lvalue_type(::HIR::TypeRef& tmp, const ::MIR::LValue::MRef& val) const { + return get_lvalue_type(tmp, val.lv(), val.lv().m_wrappers.size() - val.wrapper_count()); + } + const ::HIR::TypeRef& get_unwrapped_type(::HIR::TypeRef& tmp, const ::MIR::LValue::Wrapper& w, const ::HIR::TypeRef& ty) const; const ::HIR::TypeRef& get_param_type(::HIR::TypeRef& tmp, const ::MIR::Param& val) const; ::HIR::TypeRef get_const_type(const ::MIR::Constant& c) const; diff --git a/src/mir/mir.cpp b/src/mir/mir.cpp index 83f7e1f0..8e3045d6 100644 --- a/src/mir/mir.cpp +++ b/src/mir/mir.cpp @@ -91,119 +91,86 @@ namespace MIR { throw ""; } - ::std::ostream& operator<<(::std::ostream& os, const LValue& x) + void LValue::RefCommon::fmt(::std::ostream& os) const { - TU_MATCHA( (x), (e), + TU_MATCHA( (m_lv->m_root), (e), (Return, os << "retval"; ), (Argument, - os << "a" << e.idx; + os << "a" << e; ), (Local, os << "_" << e; ), (Static, - os << "(" << *e << ")"; - ), - (Field, - os << *e.val << "." << e.field_index; - ), - (Deref, - os << *e.val << "*"; - ), - (Index, - os << *e.val << "[" << *e.idx << "]"; - ), - (Downcast, - os << *e.val << "#" << e.variant_index; + os << "(" << e << ")"; ) ) + for(size_t i = 0; i < m_wrapper_count; i ++) + { + const LValue::Wrapper& w = m_lv->m_wrappers.at(i); + TU_MATCHA( (w), (e), + (Field, + os << "." << e; + ), + (Deref, + os << "*"; + ), + (Index, + os << "[_" << e << "]"; + ), + (Downcast, + os << "#" << e; + ) + ) + } + } + + ::std::ostream& operator<<(::std::ostream& os, const LValue& x) + { + LValue::CRef(x).fmt(os); return os; } - bool operator<(const LValue& a, const LValue& b) + + Ordering LValue::Storage::ord(const LValue::Storage& x) const { - if( a.tag() != b.tag() ) - return a.tag() < b.tag(); - TU_MATCHA( (a, b), (ea, eb), - (Return, - return false; - ), - (Argument, - return ea.idx < eb.idx; - ), - (Local, - return ea < eb; - ), - (Static, - return ea < eb; - ), - (Field, - if( *ea.val != *eb.val ) - return *ea.val < *eb.val; - if( ea.field_index != eb.field_index ) - return ea.field_index < eb.field_index; - return true; - ), - (Deref, - return *ea.val < *eb.val; - ), - (Index, - if( *ea.val != *eb.val ) - return *ea.val < *eb.val; - return *ea.idx < *eb.idx; - ), - (Downcast, - if( *ea.val != *eb.val ) - return *ea.val < *eb.val; - return ea.variant_index < eb.variant_index; - ) - ) - throw ""; + if( x.is_Static() ) + { + if( this->is_Static() ) + return this->as_Static().ord( x.as_Static() ); + else + return OrdLess; + } + else + { + if( this->is_Static() ) + return OrdGreater; + } + + return ::ord(this->val, x.val); } - bool operator==(const LValue& a, const LValue& b) + Ordering LValue::ord(const LValue& x) const { - if( a.tag() != b.tag() ) - return false; - TU_MATCHA( (a, b), (ea, eb), - (Return, - return true; - ), - (Argument, - return ea.idx == eb.idx; - ), - (Local, - return ea == eb; - ), - (Static, - return ea == eb; - ), - (Field, - if( *ea.val != *eb.val ) - return false; - if( ea.field_index != eb.field_index ) - return false; - return true; - ), - (Deref, - return *ea.val == *eb.val; - ), - (Index, - if( *ea.val != *eb.val ) - return false; - if( *ea.idx != *eb.idx ) - return false; - return true; - ), - (Downcast, - if( *ea.val != *eb.val ) - return false; - if( ea.variant_index != eb.variant_index ) - return false; - return true; - ) - ) - throw ""; + auto rv = m_root.ord(x.m_root); + if( rv != OrdEqual ) + return rv; + return ::ord(m_wrappers, x.m_wrappers); + } + Ordering LValue::RefCommon::ord(const LValue::RefCommon& x) const + { + Ordering rv; + //TRACE_FUNCTION_FR(FMT_CB(ss, this->fmt(ss); ss << " ? "; x.fmt(ss);), rv); + rv = m_lv->m_root.ord(x.m_lv->m_root); + if( rv != OrdEqual ) + return rv; + for(size_t i = 0; i < ::std::min(m_wrapper_count, x.m_wrapper_count); i ++) + { + rv = m_lv->m_wrappers[i].ord(x.m_lv->m_wrappers[i]); + if( rv != OrdEqual ) + return rv; + } + return (rv = ::ord(m_wrapper_count, x.m_wrapper_count)); } ::std::ostream& operator<<(::std::ostream& os, const Param& x) @@ -537,30 +504,14 @@ namespace MIR { } } -::MIR::LValue MIR::LValue::clone() const +::MIR::LValue::Storage MIR::LValue::Storage::clone() const { - TU_MATCHA( (*this), (e), - (Return, return LValue(e); ), - (Argument, return LValue(e); ), - (Local, return LValue(e); ), - (Static, return LValue(box$(e->clone())); ), - (Field, return LValue::make_Field({ - box$( e.val->clone() ), - e.field_index - }); ), - (Deref, return LValue::make_Deref({ - box$( e.val->clone() ) - }); ), - (Index, return LValue::make_Index({ - box$( e.val->clone() ), - box$( e.idx->clone() ) - }); ), - (Downcast, return LValue::make_Downcast({ - box$( e.val->clone() ), - e.variant_index - }); ) - ) - throw ""; + if( is_Static() ) { + return new_Static(as_Static().clone()); + } + else { + return Storage(this->val); + } } ::MIR::Constant MIR::Constant::clone() const { diff --git a/src/mir/mir.hpp b/src/mir/mir.hpp index 63acf89d..f3d61dfa 100644 --- a/src/mir/mir.hpp +++ b/src/mir/mir.hpp @@ -12,21 +12,27 @@ #include // std::unique_ptr #include +class MonomorphState; + namespace MIR { typedef unsigned int RegionId; typedef unsigned int BasicBlockId; -#if 0 -// TODO: Store LValues as: +// Store LValues as: // - A packed root value (one word, using the low bits as an enum descriminator) // - A list of (inner to outer) wrappers struct LValue { class Storage { + public: + const static uintptr_t MAX_ARG = (1 << 30) - 1; // max value of 30 bits + private: + uintptr_t val; - static uintptr_t MAX_ARG = (1 << 30) - 1; // max value of 30 bits + + Storage(uintptr_t v): val(v) {} public: Storage(const Storage&) = delete; Storage& operator=(const Storage&) = delete; @@ -40,41 +46,89 @@ struct LValue this->~Storage(); this->val = x.val; x.val = 0; + return *this; } ~Storage() { if( is_Static() ) { - delete reinterpret_cast<::HIR::Path*>(val & ~3u); + delete reinterpret_cast<::HIR::Path*>(val & ~3ull); val = 0; } } - static Storage new_Return() { return Storage { MAX_ARG << 2 }; } - static Storage new_Argument(unsigned idx) { assert(idx < MAX_ARG); return Storage { idx << 2 }; ) - static Storage new_Local(unsigned idx) { assert(idx <= MAX_ARG); return Storage { (idx << 2) | 1 } }; + static Storage new_Return() { return Storage(0 << 2); } + static Storage new_Argument(unsigned idx) { assert(idx < MAX_ARG); return Storage((idx+1) << 2); } + static Storage new_Local(unsigned idx) { assert(idx <= MAX_ARG); return Storage((idx << 2) | 1); } static Storage new_Static(::HIR::Path p) { ::HIR::Path* ptr = new ::HIR::Path(::std::move(p)); - return Storage { static_cast(ptr) | 2; } + return Storage(reinterpret_cast(ptr) | 2); + } + + Storage clone() const; + + uintptr_t get_inner() const { + assert(!is_Static()); + return val; + } + static Storage from_inner(uintptr_t v) { + assert( (v & 3) < 2 ); + return Storage(v); + } + + enum Tag { + TAG_Argument, + TAG_Local, + TAG_Static, + TAG_Return, + TAGDEAD, + }; + Tag tag() const { + if(val == 0) + return TAG_Return; + return static_cast(val & 3); } - bool is_Return() const { return val == (MAX_ARG << 2) /*&& (val & 3) == 0*/; } - bool is_Argument() const { return val != (MAX_ARG << 2) && (val & 3) == 0; } + bool is_Return() const { return val == 0; } + bool is_Argument() const { return val != 0 && (val & 3) == 0; } bool is_Local() const { return (val & 3) == 1; } bool is_Static() const { return (val & 3) == 2; } - // No as_Return - unsigned as_Argument() const { assert(is_Argument()); return val >> 2; } - unsigned as_Local() const { assert(is_Local()); return val >> 2; } - const ::HIR::Path& as_Static() const { assert(is_Static()); return *reinterpret_cast(val & ~3u); } + const char as_Return () const { assert(is_Return()); return 0; } + const unsigned as_Argument() const { assert(is_Argument()); return (val >> 2) - 1; } + const unsigned as_Local () const { assert(is_Local()); return val >> 2; } + + const ::HIR::Path& as_Static() const { assert(is_Static()); return *reinterpret_cast(val & ~3llu); } + ::HIR::Path& as_Static() { assert(is_Static()); return *reinterpret_cast< ::HIR::Path*>(val & ~3llu); } + + Ordering ord(const Storage& x) const; + bool operator==(const Storage& x) const { return this->ord(x) == OrdEqual; } + bool operator!=(const Storage& x) const { return this->ord(x) != OrdEqual; } }; class Wrapper { - uintptr_t val; + uint32_t val; + Wrapper(uint32_t v): val(v) {} public: - static Wrapper new_Deref() { return Wrapper { 0 }; } - static Wrapepr new_Field (unsigned idx) { return Wrapper { (idx << 2) | 1 }; } - static Wrapepr new_Downcast(unsigned idx) { return Wrapper { (idx << 2) | 2 }; } - static Wrapepr new_Index (unsigned idx) { return Wrapper { (idx << 2) | 3 }; } + static Wrapper new_Deref() { return Wrapper( 0 ); } + static Wrapper new_Field (unsigned idx) { return Wrapper( (idx << 2) | 1 ); } + static Wrapper new_Downcast(unsigned idx) { return Wrapper( (idx << 2) | 2 ); } + static Wrapper new_Index (unsigned idx) { if(idx == ~0u) idx = Storage::MAX_ARG; return Wrapper( (idx << 2) | 3 ); } + + uint32_t get_inner() const { return val; } + static Wrapper from_inner(uint32_t v) { + return Wrapper(v); + } + + enum Tag { + TAG_Deref, + TAG_Field, + TAG_Downcast, + TAG_Index, + TAGDEAD, + }; + Tag tag() const { + return static_cast(val & 3); + } bool is_Deref () const { return (val & 3) == 0; } // Stores the field index @@ -84,79 +138,269 @@ struct LValue // Stores a Local index bool is_Index () const { return (val & 3) == 3; } - // no as_Deref() - const unsigned as_Field() const { assert(is_Field()); return (val >> 2); } + const char as_Deref () const { assert(is_Deref()); return 0; } + const unsigned as_Field () const { assert(is_Field()); return (val >> 2); } const unsigned as_Downcast() const { assert(is_Downcast()); return (val >> 2); } // TODO: Should this return a LValue? - const unsigned as_Index() const { assert(is_Index()); return (val >> 2); } + const unsigned as_Index () const { assert(is_Index()); unsigned rv = (val >> 2); return rv; } + + void inc_Field () { assert(is_Field ()); *this = Wrapper::new_Field (as_Field () + 1); } + void inc_Downcast() { assert(is_Downcast()); *this = Wrapper::new_Downcast(as_Downcast() + 1); } + + Ordering ord(const Wrapper& x) const { return ::ord(val, x.val); } }; Storage m_root; ::std::vector m_wrappers; - static LValue new_Return() { return LValue { Storage::new_Return(), {} }; } - static LValue new_Argument(unsigned idx) { return LValue { Storage::new_Argument(idx), {} }; } - static LValue new_Local(unsigned idx) { return LValue { Storage::new_Local(idx), {} }; } - static LValue new_Static(::HIR::Path p) { return LValue { Storage::new_Static(::std::move(p)), {} }; } + LValue() + :m_root( Storage::new_Return() ) + { + } + LValue(Storage root, ::std::vector wrappers) + :m_root( ::std::move(root) ) + ,m_wrappers( ::std::move(wrappers) ) + { + } + + static LValue new_Return () { return LValue(Storage::new_Return(), {}); } + static LValue new_Argument(unsigned idx ) { return LValue(Storage::new_Argument(idx), {}); } + static LValue new_Local (unsigned idx ) { return LValue(Storage::new_Local(idx), {}); } + static LValue new_Static (::HIR::Path p) { return LValue(Storage::new_Static(::std::move(p)), {}); } + + static LValue new_Deref(LValue lv) { lv.m_wrappers.push_back(Wrapper::new_Deref()); return lv; } + static LValue new_Field(LValue lv, unsigned idx) { lv.m_wrappers.push_back(Wrapper::new_Field(idx)); return lv; } + static LValue new_Downcast(LValue lv, unsigned idx) { lv.m_wrappers.push_back(Wrapper::new_Downcast(idx)); return lv; } + static LValue new_Index(LValue lv, unsigned local_idx) { lv.m_wrappers.push_back(Wrapper::new_Index(local_idx)); return lv; } - static LValue new_Deref(LValue lv) { lv.m_wrappers.push_back(Wrapper::new_Deref()); } - static LValue new_Field(LValue lv, unsigned idx) { lv.m_wrappers.push_back(Wrapper::new_Field(idx)); } - static LValue new_Downcast(LValue lv, unsigned idx) { lv.m_wrappers.push_back(Wrapper::new_Downcast(idx)); } - static LValue new_Index(LValue lv, unsigned local_idx) { lv.m_wrappers.push_back(Wrapper::new_Index(local_idx)); } + bool is_Return() const { return m_wrappers.empty() && m_root.is_Return(); } + bool is_Local () const { return m_wrappers.empty() && m_root.is_Local(); } + const unsigned as_Local() const { assert(m_wrappers.empty()); return m_root.as_Local(); } + + bool is_Deref () const { return m_wrappers.size() > 0 && m_wrappers.back().is_Deref(); } + bool is_Field () const { return m_wrappers.size() > 0 && m_wrappers.back().is_Field(); } + bool is_Downcast() const { return m_wrappers.size() > 0 && m_wrappers.back().is_Downcast(); } + const unsigned as_Field() const { assert(!m_wrappers.empty()); return m_wrappers.back().as_Field(); } + + void inc_Field () { assert(m_wrappers.size() > 0); m_wrappers.back().inc_Field (); } + void inc_Downcast() { assert(m_wrappers.size() > 0); m_wrappers.back().inc_Downcast(); } + + Ordering ord(const LValue& x) const; LValue monomorphise(const MonomorphState& ms, unsigned local_offset=0); //LValue monomorphise(const TransParams& ms, unsigned local_offset=0); - LValue clone() const; + LValue clone() const { + return LValue(m_root.clone(), m_wrappers); + } + LValue clone_wrapped(::std::vector wrappers) const { + if( this->m_wrappers.empty() ) { + return LValue(m_root.clone(), ::std::move(wrappers)); + } + else { + return clone_wrapped(wrappers.begin(), wrappers.end()); + } + } + template + LValue clone_wrapped(It begin_it, It end_it) const { + ::std::vector wrappers; + wrappers.reserve(m_wrappers.size() + ::std::distance(begin_it, end_it)); + wrappers.insert(wrappers.end(), m_wrappers.begin(), m_wrappers.end()); + wrappers.insert(wrappers.end(), begin_it, end_it); + return LValue(m_root.clone(), ::std::move(wrappers)); + } + + LValue clone_unwrapped(unsigned count=1) const { + assert(count > 0); + assert(count <= m_wrappers.size()); + return LValue(m_root.clone(), ::std::vector(m_wrappers.begin(), m_wrappers.end() - count)); + } + + /// Helper class that represents a LValue unwrapped to a certain degree + class RefCommon + { + protected: + const LValue* m_lv; + size_t m_wrapper_count; + + RefCommon(const LValue& lv, size_t wrapper_count) + :m_lv(&lv) + ,m_wrapper_count(wrapper_count) + { + assert(wrapper_count <= lv.m_wrappers.size()); + } + + public: + LValue clone() const { + return ::MIR::LValue( m_lv->m_root.clone(), ::std::vector(m_lv->m_wrappers.begin(), m_lv->m_wrappers.begin() + m_wrapper_count) ); + } + + const LValue& lv() const { return *m_lv; } + size_t wrapper_count() const { return m_wrapper_count; } + + /// Unwrap one level, returning false if already at the root + bool try_unwrap() { + if( m_wrapper_count == 0 ) { + return false; + } + else { + m_wrapper_count --; + return true; + } + } + + enum Tag { + TAGDEAD, + TAG_Return, + TAG_Argument, + TAG_Local, + TAG_Static, + TAG_Deref, + TAG_Field, + TAG_Downcast, + TAG_Index, + }; + Tag tag() const { + if( m_wrapper_count == 0 ) + { + switch(m_lv->m_root.tag()) + { + case Storage::TAGDEAD: return TAGDEAD; + case Storage::TAG_Return: return TAG_Return; + case Storage::TAG_Argument: return TAG_Argument; + case Storage::TAG_Local: return TAG_Local; + case Storage::TAG_Static: return TAG_Static; + } + } + else + { + switch(m_lv->m_wrappers[m_wrapper_count-1].tag()) + { + case Wrapper::TAGDEAD: return TAGDEAD; + case Wrapper::TAG_Deref: return TAG_Deref; + case Wrapper::TAG_Field: return TAG_Field; + case Wrapper::TAG_Downcast: return TAG_Downcast; + case Wrapper::TAG_Index: return TAG_Index; + } + } + return TAGDEAD; + } + + bool is_Local () const { return m_wrapper_count == 0 && m_lv->m_root.is_Local (); } + bool is_Return () const { return m_wrapper_count == 0 && m_lv->m_root.is_Return (); } + bool is_Argument() const { return m_wrapper_count == 0 && m_lv->m_root.is_Argument(); } + bool is_Static () const { return m_wrapper_count == 0 && m_lv->m_root.is_Static (); } + bool is_Deref () const { return m_wrapper_count >= 1 && m_lv->m_wrappers[m_wrapper_count-1].is_Deref (); } + bool is_Field () const { return m_wrapper_count >= 1 && m_lv->m_wrappers[m_wrapper_count-1].is_Field (); } + bool is_Downcast() const { return m_wrapper_count >= 1 && m_lv->m_wrappers[m_wrapper_count-1].is_Downcast(); } + bool is_Index () const { return m_wrapper_count >= 1 && m_lv->m_wrappers[m_wrapper_count-1].is_Index (); } + + const unsigned as_Local () const { assert(is_Local ()); return m_lv->m_root.as_Local (); } + const char as_Return () const { assert(is_Return ()); return m_lv->m_root.as_Return (); } + const unsigned as_Argument() const { assert(is_Argument()); return m_lv->m_root.as_Argument(); } + const HIR::Path& as_Static () const { assert(is_Static ()); return m_lv->m_root.as_Static (); } + const char as_Deref () const { assert(is_Deref ()); return m_lv->m_wrappers[m_wrapper_count-1].as_Deref (); } + const unsigned as_Field () const { assert(is_Field ()); return m_lv->m_wrappers[m_wrapper_count-1].as_Field (); } + const unsigned as_Downcast() const { assert(is_Downcast()); return m_lv->m_wrappers[m_wrapper_count-1].as_Downcast(); } + const unsigned as_Index () const { assert(is_Index ()); return m_lv->m_wrappers[m_wrapper_count-1].as_Index (); } - class Ref + void fmt(::std::ostream& os) const; + Ordering ord(const RefCommon& b) const; + }; + + class CRef: public RefCommon { - LValue& r; - size_t wrapper_idx; - public:: - LValue clone() const; - void replace(LValue x) const; + public: + CRef(const LValue& lv) + :RefCommon(lv, lv.m_wrappers.size()) + { + } + CRef(const LValue& lv, size_t wc) + :RefCommon(lv, wc) + { + } + + /// Unwrap one level + const CRef inner_ref() const { + assert(m_wrapper_count > 0); + auto rv = *this; + rv.m_wrapper_count--; + return rv; + } + + friend ::std::ostream& operator<<(::std::ostream& os, const CRef& x) { + x.fmt(os); + return os; + } + + bool operator<(const CRef& b) const { + return this->ord(b) == OrdLess; + } + bool operator==(const CRef& b) const { + return this->ord(b) == OrdEqual; + } }; + class MRef: public RefCommon + { + public: + MRef(LValue& lv) + :RefCommon(lv, lv.m_wrappers.size()) + { + } + + operator CRef() const { + return CRef(*m_lv, m_wrapper_count); + } + + MRef inner_ref() { + assert(m_wrapper_count > 0); + auto rv = *this; + rv.m_wrapper_count--; + return rv; + } + void replace(LValue x) { + auto& mut_lv = const_cast(*m_lv); + // Shortcut: No wrappers on source/destination (just assign the slot/root) + if( m_wrapper_count == 0 && x.m_wrappers.empty() ) { + mut_lv.m_root = ::std::move(x.m_root); + return ; + } + // If there's wrappers on this value (assigning over inner portion) + if( m_wrapper_count < m_lv->m_wrappers.size() ) { + // Add those wrappers to the end of the new value + x.m_wrappers.insert(x.m_wrappers.end(), m_lv->m_wrappers.begin() + m_wrapper_count, m_lv->m_wrappers.end()); + } + // Overwrite + mut_lv = ::std::move(x); + } + + friend ::std::ostream& operator<<(::std::ostream& os, const MRef& x) { + x.fmt(os); + return os; + } + }; + + Ordering ord(const LValue::CRef& x) const; + Ordering ord(const LValue::MRef& x) const; }; -#endif - -// "LVALUE" - Assignable values -TAGGED_UNION_EX(LValue, (), Return, ( - // Function return - (Return, struct{}), - // Function argument (input) - (Argument, struct { unsigned int idx; }), - // Variable/Temporary - (Local, unsigned int), - // `static` or `static mut` - (Static, ::std::unique_ptr<::HIR::Path>), - // Field access (tuple, struct, tuple struct, enum field, ...) - // NOTE: Also used to index an array/slice by a compile-time known index (e.g. in destructuring) - (Field, struct { - ::std::unique_ptr val; - unsigned int field_index; - }), - // Dereference a value - (Deref, struct { - ::std::unique_ptr val; - }), - // Index an array or slice (typeof(val) == [T; n] or [T]) - // NOTE: This is not bounds checked! - (Index, struct { - ::std::unique_ptr val; - ::std::unique_ptr idx; - }), - // Interpret an enum as a particular variant - (Downcast, struct { - ::std::unique_ptr val; - unsigned int variant_index; - }) - ), (),(), ( - LValue clone() const; - ) - ); extern ::std::ostream& operator<<(::std::ostream& os, const LValue& x); -extern bool operator<(const LValue& a, const LValue& b); -extern bool operator==(const LValue& a, const LValue& b); +static inline bool operator<(const LValue& a, const LValue::CRef& b) { + return a.ord(b) == OrdLess; +} +static inline bool operator<(const LValue& a, const LValue::MRef& b) { + return a.ord(b) == OrdLess; +} +static inline bool operator<(const LValue::CRef& a, const LValue& b) { + return b.ord(a) == OrdGreater; +} +static inline bool operator<(const LValue::MRef& a, const LValue& b) { + return b.ord(a) == OrdGreater; +} +static inline bool operator<(const LValue& a, const LValue& b) { + return a.ord(b) == OrdLess; +} +static inline bool operator==(const LValue& a, const LValue& b) { + return a.ord(b) == OrdEqual; +} static inline bool operator!=(const LValue& a, const LValue& b) { return !(a == b); } @@ -224,7 +468,7 @@ TAGGED_UNION_EX(Constant, (), Int, ( /// Parameter - A value used when a rvalue just reads (doesn't require a lvalue) /// Can be either a lvalue (memory address), or a constant -TAGGED_UNION_EX(Param, (), LValue, ( +TAGGED_UNION_EX(Param, (), Constant, ( (LValue, LValue), (Constant, Constant) ), (), (), ( @@ -237,7 +481,7 @@ TAGGED_UNION_EX(Param, (), LValue, ( ) ); -TAGGED_UNION_EX(RValue, (), Use, ( +TAGGED_UNION_EX(RValue, (), Tuple, ( (Use, LValue), (Constant, Constant), (SizedArray, struct { @@ -359,7 +603,7 @@ enum class eDropKind { SHALLOW, DEEP, }; -TAGGED_UNION(Statement, Assign, +TAGGED_UNION(Statement, Asm, // Value assigment (Assign, struct { LValue dst; diff --git a/src/mir/mir_builder.cpp b/src/mir/mir_builder.cpp index 8d534314..a064b67d 100644 --- a/src/mir/mir_builder.cpp +++ b/src/mir/mir_builder.cpp @@ -68,7 +68,7 @@ MirBuilder::~MirBuilder() { if( has_result() ) { - push_stmt_assign( sp, ::MIR::LValue::make_Return({}), get_result(sp) ); + push_stmt_assign( sp, ::MIR::LValue::new_Return(), get_result(sp) ); } terminate_scope_early(sp, fcn_scope()); @@ -176,7 +176,7 @@ void MirBuilder::define_variable(unsigned int idx) auto& tmp_scope = top_scope->data.as_Owning(); assert(tmp_scope.is_temporary); tmp_scope.slots.push_back( rv ); - return ::MIR::LValue::make_Local(rv); + return ::MIR::LValue::new_Local(rv); } ::MIR::LValue MirBuilder::lvalue_or_temp(const Span& sp, const ::HIR::TypeRef& ty, ::MIR::RValue val) { @@ -258,12 +258,10 @@ void MirBuilder::set_result(const Span& sp, ::MIR::RValue val) m_result_valid = true; } -void MirBuilder::push_stmt_assign(const Span& sp, ::MIR::LValue dst, ::MIR::RValue val) +void MirBuilder::push_stmt_assign(const Span& sp, ::MIR::LValue dst, ::MIR::RValue val, bool drop_destination/*=true*/) { DEBUG(dst << " = " << val); ASSERT_BUG(sp, m_block_active, "Pushing statement with no active block"); - ASSERT_BUG(sp, dst.tag() != ::MIR::LValue::TAGDEAD, ""); - ASSERT_BUG(sp, val.tag() != ::MIR::RValue::TAGDEAD, ""); auto moved_param = [&](const ::MIR::Param& p) { if(const auto* e = p.opt_LValue()) { @@ -344,13 +342,15 @@ void MirBuilder::push_stmt_assign(const Span& sp, ::MIR::LValue dst, ::MIR::RVal ) // Drop target if populated - mark_value_assigned(sp, dst); + if( drop_destination ) + { + mark_value_assigned(sp, dst); + } this->push_stmt( sp, ::MIR::Statement::make_Assign({ mv$(dst), mv$(val) }) ); } void MirBuilder::push_stmt_drop(const Span& sp, ::MIR::LValue val, unsigned int flag/*=~0u*/) { ASSERT_BUG(sp, m_block_active, "Pushing statement with no active block"); - ASSERT_BUG(sp, val.tag() != ::MIR::LValue::TAGDEAD, ""); if( lvalue_is_copy(sp, val) ) { // Don't emit a drop for Copy values @@ -362,7 +362,6 @@ void MirBuilder::push_stmt_drop(const Span& sp, ::MIR::LValue val, unsigned int void MirBuilder::push_stmt_drop_shallow(const Span& sp, ::MIR::LValue val, unsigned int flag/*=~0u*/) { ASSERT_BUG(sp, m_block_active, "Pushing statement with no active block"); - ASSERT_BUG(sp, val.tag() != ::MIR::LValue::TAGDEAD, ""); // TODO: Ensure that the type is a Box? @@ -400,22 +399,12 @@ void MirBuilder::push_stmt(const Span& sp, ::MIR::Statement stmt) void MirBuilder::mark_value_assigned(const Span& sp, const ::MIR::LValue& dst) { - VarState* state_p = nullptr; - // TODO: Tracking of complex asignment states (e.g. assignment of a field) - TU_MATCH_DEF(::MIR::LValue, (dst), (e), - ( - ), - (Return, - // Don't drop. - // No state tracking for the return value - ), - (Argument, - state_p = &get_slot_state_mut(sp, e.idx, SlotType::Argument); - ), - (Local, - state_p = &get_slot_state_mut(sp, e, SlotType::Local); - ) - ) + if( dst.m_root.is_Return() ) + { + ASSERT_BUG(sp, dst.m_wrappers.empty(), "Assignment to a component of the return value should be impossible."); + return ; + } + VarState* state_p = get_val_state_mut_p(sp, dst);; if( state_p ) { @@ -425,42 +414,28 @@ void MirBuilder::mark_value_assigned(const Span& sp, const ::MIR::LValue& dst) drop_value_from_state(sp, *state_p, dst.clone()); *state_p = VarState::make_Valid({}); } - // TODO: What about assigning into non-tracked locations? Should still cause a drop + else + { + // Assigning into non-tracked locations still causes a drop + drop_value_from_state(sp, VarState::make_Valid({}), dst.clone()); + } } void MirBuilder::raise_temporaries(const Span& sp, const ::MIR::LValue& val, const ScopeHandle& scope, bool to_above/*=false*/) { TRACE_FUNCTION_F(val); - TU_MATCH_DEF(::MIR::LValue, (val), (e), - ( + for(const auto& w : val.m_wrappers) + { + if( w.is_Index() ) { + // Raise index temporary + raise_temporaries(sp, ::MIR::LValue::new_Local(w.as_Index()), scope, to_above); + } + } + if( !val.m_root.is_Local() ) { // No raising of these source values? return ; - ), - // TODO: This may not be correct, because it can change the drop points and ordering - // HACK: Working around cases where values are dropped while the result is not yet used. - (Index, - raise_temporaries(sp, *e.val, scope, to_above); - raise_temporaries(sp, *e.idx, scope, to_above); - return ; - ), - (Deref, - raise_temporaries(sp, *e.val, scope, to_above); - return ; - ), - (Field, - raise_temporaries(sp, *e.val, scope, to_above); - return ; - ), - (Downcast, - raise_temporaries(sp, *e.val, scope, to_above); - return ; - ), - // Actual value types - (Local, - ) - ) - ASSERT_BUG(sp, val.is_Local(), "Hit value raising code with non-variable value - " << val); - const auto idx = val.as_Local(); + } + const auto idx = val.m_root.as_Local(); bool is_temp = (idx >= m_first_temp_idx); /* if( !is_temp ) { @@ -833,13 +808,12 @@ void MirBuilder::raise_all(const Span& sp, ScopeHandle source, const ScopeHandle } auto& src_scope_def = m_scopes.at(source.idx); -#if 1 ASSERT_BUG(sp, src_scope_def.data.is_Owning(), "Rasising scopes can only be done on temporaries (source)"); ASSERT_BUG(sp, src_scope_def.data.as_Owning().is_temporary, "Rasising scopes can only be done on temporaries (source)"); auto& src_list = src_scope_def.data.as_Owning().slots; for(auto idx : src_list) { - DEBUG("> Raising " << ::MIR::LValue::make_Local(idx)); + DEBUG("> Raising " << ::MIR::LValue::new_Local(idx)); assert(idx >= m_first_temp_idx); } @@ -910,13 +884,6 @@ void MirBuilder::raise_all(const Span& sp, ScopeHandle source, const ScopeHandle // Move all defined variables from one to the other auto& tgt_list = tgt_scope_def.data.as_Owning().slots; tgt_list.insert( tgt_list.end(), src_list.begin(), src_list.end() ); -#else - auto list = src_scope_def.data.as_Temporaries().temporaries; - for(auto idx : list) - { - this->raise_temporaries(sp, ::MIR::LValue::make_Temporary({ idx }), target); - } -#endif // Scope completed m_scope_stack.pop_back(); @@ -979,7 +946,7 @@ void MirBuilder::terminate_scope_early(const Span& sp, const ScopeHandle& scope, for(size_t i = 0; i < m_arg_states.size(); i ++) { const auto& state = get_slot_state(sp, i, SlotType::Argument); - this->drop_value_from_state(sp, state, ::MIR::LValue::make_Argument({ static_cast(i) })); + this->drop_value_from_state(sp, state, ::MIR::LValue::new_Argument(static_cast(i))); } } } @@ -1060,7 +1027,7 @@ namespace }); if( is_box ) { - merge_state(sp, builder, ::MIR::LValue::make_Deref({ box$(lv.clone()) }), *ose.inner_state, *nse.inner_state); + merge_state(sp, builder, ::MIR::LValue::new_Deref(lv.clone()), *ose.inner_state, *nse.inner_state); } else { @@ -1086,13 +1053,13 @@ namespace if( is_enum ) { for(size_t i = 0; i < ose.inner_states.size(); i ++) { - merge_state(sp, builder, ::MIR::LValue::make_Downcast({ box$(lv.clone()), static_cast(i) }), ose.inner_states[i], nse.inner_states[i]); + merge_state(sp, builder, ::MIR::LValue::new_Downcast(lv.clone(), static_cast(i)), ose.inner_states[i], nse.inner_states[i]); } } else { for(unsigned int i = 0; i < ose.inner_states.size(); i ++ ) { - merge_state(sp, builder, ::MIR::LValue::make_Field({ box$(lv.clone()), i }), ose.inner_states[i], nse.inner_states[i]); + merge_state(sp, builder, ::MIR::LValue::new_Field(lv.clone(), i), ose.inner_states[i], nse.inner_states[i]); } } } return; @@ -1168,7 +1135,7 @@ namespace }); if( is_box ) { - merge_state(sp, builder, ::MIR::LValue::make_Deref({ box$(lv.clone()) }), *ose.inner_state, *nse.inner_state); + merge_state(sp, builder, ::MIR::LValue::new_Deref(lv.clone()), *ose.inner_state, *nse.inner_state); } else { BUG(sp, "MovedOut on non-Box"); @@ -1192,19 +1159,19 @@ namespace } auto& ose = old_state.as_Partial(); if( is_enum ) { - auto ilv = ::MIR::LValue::make_Downcast({ box$(lv.clone()), 0 }); + auto ilv = ::MIR::LValue::new_Downcast(lv.clone(), 0); for(size_t i = 0; i < ose.inner_states.size(); i ++) { merge_state(sp, builder, ilv, ose.inner_states[i], nse.inner_states[i]); - ilv.as_Downcast().variant_index ++; + ilv.inc_Downcast(); } } else { - auto ilv = ::MIR::LValue::make_Field({ box$(lv.clone()), 0 }); + auto ilv = ::MIR::LValue::new_Field(lv.clone(), 0); for(unsigned int i = 0; i < ose.inner_states.size(); i ++ ) { merge_state(sp, builder, ilv, ose.inner_states[i], nse.inner_states[i]); - ilv.as_Field().field_index ++; + ilv.inc_Field(); } } } return; @@ -1268,13 +1235,13 @@ namespace if( is_enum ) { for(size_t i = 0; i < ose.inner_states.size(); i ++) { - merge_state(sp, builder, ::MIR::LValue::make_Downcast({ box$(lv.clone()), static_cast(i) }), ose.inner_states[i], nse.inner_states[i]); + merge_state(sp, builder, ::MIR::LValue::new_Downcast(lv.clone(), static_cast(i)), ose.inner_states[i], nse.inner_states[i]); } } else { for(unsigned int i = 0; i < ose.inner_states.size(); i ++ ) { - merge_state(sp, builder, ::MIR::LValue::make_Field({ box$(lv.clone()), i }), ose.inner_states[i], nse.inner_states[i]); + merge_state(sp, builder, ::MIR::LValue::new_Field(lv.clone(), i), ose.inner_states[i], nse.inner_states[i]); } } return; } @@ -1309,7 +1276,7 @@ namespace builder.push_stmt_set_dropflag_val(sp, ose.outer_flag, is_valid); } - merge_state(sp, builder, ::MIR::LValue::make_Deref({ box$(lv.clone()) }), *ose.inner_state, new_state); + merge_state(sp, builder, ::MIR::LValue::new_Deref(lv.clone()), *ose.inner_state, new_state); return ; } case VarState::TAG_Optional: { const auto& nse = new_state.as_Optional(); @@ -1334,7 +1301,7 @@ namespace builder.push_stmt_set_dropflag_other(sp, ose.outer_flag, nse); builder.push_stmt_set_dropflag_default(sp, nse); } - merge_state(sp, builder, ::MIR::LValue::make_Deref({ box$(lv.clone()) }), *ose.inner_state, new_state); + merge_state(sp, builder, ::MIR::LValue::new_Deref(lv.clone()), *ose.inner_state, new_state); return; } case VarState::TAG_MovedOut: { const auto& nse = new_state.as_MovedOut(); @@ -1342,7 +1309,7 @@ namespace { TODO(sp, "Handle mismatched flags in MovedOut"); } - merge_state(sp, builder, ::MIR::LValue::make_Deref({ box$(lv.clone()) }), *ose.inner_state, *nse.inner_state); + merge_state(sp, builder, ::MIR::LValue::new_Deref(lv.clone()), *ose.inner_state, *nse.inner_state); return; } case VarState::TAG_Partial: BUG(sp, "MovedOut->Partial not valid"); @@ -1366,13 +1333,13 @@ namespace if( is_enum ) { for(size_t i = 0; i < ose.inner_states.size(); i ++) { - merge_state(sp, builder, ::MIR::LValue::make_Downcast({ box$(lv.clone()), static_cast(i) }), ose.inner_states[i], new_state); + merge_state(sp, builder, ::MIR::LValue::new_Downcast(lv.clone(), static_cast(i)), ose.inner_states[i], new_state); } } else { for(unsigned int i = 0; i < ose.inner_states.size(); i ++ ) { - merge_state(sp, builder, ::MIR::LValue::make_Field({ box$(lv.clone()), i }), ose.inner_states[i], new_state); + merge_state(sp, builder, ::MIR::LValue::new_Field(lv.clone(), i), ose.inner_states[i], new_state); } } return ; @@ -1384,13 +1351,13 @@ namespace if( is_enum ) { for(size_t i = 0; i < ose.inner_states.size(); i ++) { - merge_state(sp, builder, ::MIR::LValue::make_Downcast({ box$(lv.clone()), static_cast(i) }), ose.inner_states[i], nse.inner_states[i]); + merge_state(sp, builder, ::MIR::LValue::new_Downcast(lv.clone(), static_cast(i)), ose.inner_states[i], nse.inner_states[i]); } } else { for(unsigned int i = 0; i < ose.inner_states.size(); i ++ ) { - merge_state(sp, builder, ::MIR::LValue::make_Field({ box$(lv.clone()), i }), ose.inner_states[i], nse.inner_states[i]); + merge_state(sp, builder, ::MIR::LValue::new_Field(lv.clone(), i), ose.inner_states[i], nse.inner_states[i]); } } } return ; @@ -1419,8 +1386,8 @@ void MirBuilder::terminate_loop_early(const Span& sp, ScopeType::Data_Loop& sd_l merge_state(sp, *this, val_cb(idx), old_state, get_slot_state(sp, idx, type)); } }; - merge_list(sd_loop.changed_slots, sd_loop.exit_state.states, ::MIR::LValue::make_Local, SlotType::Local); - merge_list(sd_loop.changed_args, sd_loop.exit_state.arg_states, [](auto v){ return ::MIR::LValue::make_Argument({v}); }, SlotType::Argument); + merge_list(sd_loop.changed_slots, sd_loop.exit_state.states, ::MIR::LValue::new_Local, SlotType::Local); + merge_list(sd_loop.changed_args, sd_loop.exit_state.arg_states, [](auto v){ return ::MIR::LValue::new_Argument(v); }, SlotType::Argument); } else { @@ -1475,7 +1442,7 @@ void MirBuilder::end_split_arm(const Span& sp, const ScopeHandle& handle, bool r auto it = states.find(idx); const auto& src_state = (it != states.end() ? it->second : get_slot_state(sp, idx, type, 1)); - auto lv = (type == SlotType::Local ? ::MIR::LValue::make_Local(idx) : ::MIR::LValue::make_Argument({idx})); + auto lv = (type == SlotType::Local ? ::MIR::LValue::new_Local(idx) : ::MIR::LValue::new_Argument(idx)); merge_state(sp, *this, mv$(lv), out_state, src_state); } }; @@ -1565,7 +1532,7 @@ void MirBuilder::complete_scope(ScopeDef& sd) auto& vs = builder.get_slot_state_mut(sp, ent.first, SlotType::Local); if( vs != ent.second ) { - DEBUG(::MIR::LValue::make_Local(ent.first) << " " << vs << " => " << ent.second); + DEBUG(::MIR::LValue::new_Local(ent.first) << " " << vs << " => " << ent.second); vs = ::std::move(ent.second); } } @@ -1574,7 +1541,7 @@ void MirBuilder::complete_scope(ScopeDef& sd) auto& vs = builder.get_slot_state_mut(sp, ent.first, SlotType::Argument); if( vs != ent.second ) { - DEBUG(::MIR::LValue::make_Argument({ent.first}) << " " << vs << " => " << ent.second); + DEBUG(::MIR::LValue::new_Argument(ent.first) << " " << vs << " => " << ent.second); vs = ::std::move(ent.second); } } @@ -1612,7 +1579,7 @@ void MirBuilder::complete_scope(ScopeDef& sd) for(auto& ent : e->changed_slots) { auto& vs = this->get_slot_state_mut(sd.span, ent.first, SlotType::Local); - auto lv = ::MIR::LValue::make_Local(ent.first); + auto lv = ::MIR::LValue::new_Local(ent.first); DEBUG(lv << " " << vs << " => " << ent.second); if( vs != ent.second ) { @@ -1630,97 +1597,96 @@ void MirBuilder::complete_scope(ScopeDef& sd) } } -void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::function cb) const +void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::function cb, const ::MIR::LValue::Wrapper* stop_wrapper/*=nullptr*/) const { - TU_MATCH(::MIR::LValue, (val), (e), + ::HIR::TypeRef tmp; + const ::HIR::TypeRef* ty_p = nullptr; + TU_MATCHA( (val.m_root), (e), (Return, TODO(sp, "Return"); ), (Argument, - cb( m_args.at(e.idx).second ); + ty_p = &m_args.at(e).second; ), (Local, - cb( m_output.locals.at(e) ); + ty_p = &m_output.locals.at(e); ), (Static, - TU_MATCHA( (e->m_data), (pe), + TU_MATCHA( (e.m_data), (pe), (Generic, ASSERT_BUG(sp, pe.m_params.m_types.empty(), "Path params on static"); const auto& s = m_resolve.m_crate.get_static_by_path(sp, pe.m_path); - cb( s.m_type ); + ty_p = &s.m_type; ), (UfcsKnown, - TODO(sp, "Static - UfcsKnown - " << *e); + TODO(sp, "Static - UfcsKnown - " << e); ), (UfcsUnknown, - BUG(sp, "Encountered UfcsUnknown in Static - " << *e); + BUG(sp, "Encountered UfcsUnknown in Static - " << e); ), (UfcsInherent, - TODO(sp, "Static - UfcsInherent - " << *e); + TODO(sp, "Static - UfcsInherent - " << e); ) ) - ), - (Field, - with_val_type(sp, *e.val, [&](const auto& ty){ + ) + ) + assert(ty_p); + for(const auto& w : val.m_wrappers) + { + if( &w == stop_wrapper ) + { + stop_wrapper = nullptr; // Reset so the below bugcheck can work + break; + } + const auto& ty = *ty_p; + ty_p = nullptr; + auto maybe_monomorph = [&](const ::HIR::GenericParams& params_def, const ::HIR::Path& p, const ::HIR::TypeRef& t)->const ::HIR::TypeRef& { + if( monomorphise_type_needed(t) ) { + tmp = monomorphise_type(sp, params_def, p.m_data.as_Generic().m_params, t); + m_resolve.expand_associated_types(sp, tmp); + return tmp; + } + else { + return t; + } + }; + TU_MATCH_HDRA( (w), {) + TU_ARMA(Field, field_index) { TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te), ( BUG(sp, "Field access on unexpected type - " << ty); ), (Array, - cb( *te.inner ); + ty_p = &*te.inner; ), (Slice, - cb( *te.inner ); + ty_p = &*te.inner; ), (Path, - ::HIR::TypeRef tmp; if( const auto* tep = te.binding.opt_Struct() ) { const auto& str = **tep; - auto maybe_monomorph = [&](const ::HIR::TypeRef& t)->const ::HIR::TypeRef& { - if( monomorphise_type_needed(t) ) { - tmp = monomorphise_type(sp, str.m_params, te.path.m_data.as_Generic().m_params, t); - m_resolve.expand_associated_types(sp, tmp); - return tmp; - } - else { - return t; - } - }; TU_MATCHA( (str.m_data), (se), (Unit, BUG(sp, "Field on unit-like struct - " << ty); ), (Tuple, - ASSERT_BUG(sp, e.field_index < se.size(), - "Field index out of range in tuple-struct " << ty << " - " << e.field_index << " > " << se.size()); - const auto& fld = se[e.field_index]; - cb( maybe_monomorph(fld.ent) ); + ASSERT_BUG(sp, field_index < se.size(), + "Field index out of range in tuple-struct " << ty << " - " << field_index << " > " << se.size()); + const auto& fld = se[field_index]; + ty_p = &maybe_monomorph(str.m_params, te.path, fld.ent); ), (Named, - ASSERT_BUG(sp, e.field_index < se.size(), - "Field index out of range in struct " << ty << " - " << e.field_index << " > " << se.size()); - const auto& fld = se[e.field_index].second; - cb( maybe_monomorph(fld.ent) ); + ASSERT_BUG(sp, field_index < se.size(), + "Field index out of range in struct " << ty << " - " << field_index << " > " << se.size()); + const auto& fld = se[field_index].second; + ty_p = &maybe_monomorph(str.m_params, te.path, fld.ent); ) ) } - else if( const auto* tep = te.binding.opt_Union() ) + else if( /*const auto* tep =*/ te.binding.opt_Union() ) { BUG(sp, "Field access on a union isn't valid, use Downcast instead - " << ty); - const auto& unm = **tep; - auto maybe_monomorph = [&](const ::HIR::TypeRef& t)->const ::HIR::TypeRef& { - if( monomorphise_type_needed(t) ) { - tmp = monomorphise_type(sp, unm.m_params, te.path.m_data.as_Generic().m_params, t); - m_resolve.expand_associated_types(sp, tmp); - return tmp; - } - else { - return t; - } - }; - ASSERT_BUG(sp, e.field_index < unm.m_variants.size(), "Field index out of range for union"); - cb( maybe_monomorph(unm.m_variants.at(e.field_index).second.ent) ); } else { @@ -1728,14 +1694,12 @@ void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std:: } ), (Tuple, - ASSERT_BUG(sp, e.field_index < te.size(), "Field index out of range in tuple " << e.field_index << " >= " << te.size()); - cb( te[e.field_index] ); + ASSERT_BUG(sp, field_index < te.size(), "Field index out of range in tuple " << field_index << " >= " << te.size()); + ty_p = &te[field_index]; ) ) - }); - ), - (Deref, - with_val_type(sp, *e.val, [&](const auto& ty){ + } + TU_ARMA(Deref, _e) { TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te), ( BUG(sp, "Deref on unexpected type - " << ty); @@ -1743,38 +1707,34 @@ void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std:: (Path, if( const auto* inner_ptr = this->is_type_owned_box(ty) ) { - cb( *inner_ptr ); + ty_p = &*inner_ptr; } else { BUG(sp, "Deref on unexpected type - " << ty); } ), (Pointer, - cb(*te.inner); + ty_p = &*te.inner; ), (Borrow, - cb(*te.inner); + ty_p = &*te.inner; ) ) - }); - ), - (Index, - with_val_type(sp, *e.val, [&](const auto& ty){ + } + TU_ARMA(Index, _index_val) { TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te), ( BUG(sp, "Index on unexpected type - " << ty); ), (Slice, - cb(*te.inner); + ty_p = &*te.inner; ), (Array, - cb(*te.inner); + ty_p = &*te.inner; ) ) - }); - ), - (Downcast, - with_val_type(sp, *e.val, [&](const auto& ty){ + } + TU_ARMA(Downcast, variant_index) { TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te), ( BUG(sp, "Downcast on unexpected type - " << ty); @@ -1785,33 +1745,19 @@ void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std:: const auto& enm = **pbe; ASSERT_BUG(sp, enm.m_data.is_Data(), "Downcast on non-data enum"); const auto& variants = enm.m_data.as_Data(); - ASSERT_BUG(sp, e.variant_index < variants.size(), "Variant index out of range"); - const auto& variant = variants[e.variant_index]; + ASSERT_BUG(sp, variant_index < variants.size(), "Variant index out of range"); + const auto& variant = variants[variant_index]; - if( monomorphise_type_needed(variant.type) ) { - auto tmp = monomorphise_type(sp, enm.m_params, te.path.m_data.as_Generic().m_params, variant.type); - m_resolve.expand_associated_types(sp, tmp); - cb(tmp); - } - else { - cb(variant.type); - } + ty_p = &maybe_monomorph(enm.m_params, te.path, variant.type); } else if( const auto* pbe = te.binding.opt_Union() ) { const auto& unm = **pbe; - ASSERT_BUG(sp, e.variant_index < unm.m_variants.size(), "Variant index out of range"); - const auto& variant = unm.m_variants.at(e.variant_index); + ASSERT_BUG(sp, variant_index < unm.m_variants.size(), "Variant index out of range"); + const auto& variant = unm.m_variants.at(variant_index); const auto& fld = variant.second; - if( monomorphise_type_needed(fld.ent) ) { - auto sty = monomorphise_type(sp, unm.m_params, te.path.m_data.as_Generic().m_params, fld.ent); - m_resolve.expand_associated_types(sp, sty); - cb(sty); - } - else { - cb(fld.ent); - } + ty_p = &maybe_monomorph(unm.m_params, te.path, fld.ent); } else { @@ -1819,9 +1765,12 @@ void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std:: } ) ) - }); - ) - ) + } + } + assert(ty_p); + } + ASSERT_BUG(sp, !stop_wrapper, "A stop wrapper was passed, but not found"); + cb(*ty_p); } bool MirBuilder::lvalue_is_copy(const Span& sp, const ::MIR::LValue& val) const @@ -1998,165 +1947,177 @@ VarState& MirBuilder::get_slot_state_mut(const Span& sp, unsigned int idx, SlotT } } -const VarState& MirBuilder::get_val_state(const Span& sp, const ::MIR::LValue& lv, unsigned int skip_count) -{ - TODO(sp, ""); -} -VarState& MirBuilder::get_val_state_mut(const Span& sp, const ::MIR::LValue& lv) +VarState* MirBuilder::get_val_state_mut_p(const Span& sp, const ::MIR::LValue& lv) { TRACE_FUNCTION_F(lv); - TU_MATCHA( (lv), (e), + VarState* vs; + TU_MATCHA( (lv.m_root), (e), (Return, BUG(sp, "Move of return value"); - return get_slot_state_mut(sp, ~0u, SlotType::Local); + vs = &get_slot_state_mut(sp, ~0u, SlotType::Local); ), (Argument, - return get_slot_state_mut(sp, e.idx, SlotType::Argument); + vs = &get_slot_state_mut(sp, e, SlotType::Argument); ), (Local, - return get_slot_state_mut(sp, e, SlotType::Local); + vs = &get_slot_state_mut(sp, e, SlotType::Local); ), (Static, - BUG(sp, "Attempting to mutate state of a static"); - ), - (Field, - auto& ivs = get_val_state_mut(sp, *e.val); - VarState tpl; - TU_MATCHA( (ivs), (ivse), - (Invalid, - //BUG(sp, "Mutating inner state of an invalidated composite - " << lv); - tpl = VarState::make_Valid({}); - ), - (MovedOut, - BUG(sp, "Field on value with MovedOut state - " << lv); - ), - (Partial, - ), - (Optional, - tpl = ivs.clone(); - ), - (Valid, - tpl = VarState::make_Valid({}); - ) + return nullptr; + //BUG(sp, "Attempting to mutate state of a static"); ) - if( !ivs.is_Partial() ) - { - size_t n_flds = 0; - with_val_type(sp, *e.val, [&](const auto& ty) { - DEBUG("ty = " << ty); - if(const auto* e = ty.m_data.opt_Path()) { - ASSERT_BUG(sp, e->binding.is_Struct(), ""); - const auto& str = *e->binding.as_Struct(); - TU_MATCHA( (str.m_data), (se), - (Unit, - BUG(sp, "Field access of unit-like struct"); - ), - (Tuple, - n_flds = se.size(); - ), - (Named, - n_flds = se.size(); - ) - ) - } - else if(const auto* e = ty.m_data.opt_Tuple()) { - n_flds = e->size(); - } - else if(const auto* e = ty.m_data.opt_Array()) { - n_flds = e->size_val; - } - else { - TODO(sp, "Determine field count for " << ty); - } - }); - ::std::vector inner_vs; inner_vs.reserve(n_flds); - for(size_t i = 0; i < n_flds; i++) - inner_vs.push_back( tpl.clone() ); - ivs = VarState::make_Partial({ mv$(inner_vs) }); - } - return ivs.as_Partial().inner_states.at(e.field_index); - ), - (Deref, - // HACK: If the dereferenced type is a Box ("owned_box") then hack in move and shallow drop - bool is_box = false; - if( this->m_lang_Box ) - { - with_val_type(sp, *e.val, [&](const auto& ty){ - DEBUG("ty = " << ty); - is_box = this->is_type_owned_box(ty); - }); - } - + ) - if( is_box ) - { - auto& ivs = get_val_state_mut(sp, *e.val); - if( ! ivs.is_MovedOut() ) + for(const auto& w : lv.m_wrappers) + { + auto& ivs = *vs; + vs = nullptr; + TU_MATCH_HDRA( (w), { ) + TU_ARMA(Field, field_index) { + VarState tpl; + TU_MATCHA( (ivs), (ivse), + (Invalid, + //BUG(sp, "Mutating inner state of an invalidated composite - " << lv); + tpl = VarState::make_Valid({}); + ), + (MovedOut, + BUG(sp, "Field on value with MovedOut state - " << lv); + ), + (Partial, + ), + (Optional, + tpl = ivs.clone(); + ), + (Valid, + tpl = VarState::make_Valid({}); + ) + ) + if( !ivs.is_Partial() ) { - ::std::vector inner; - inner.push_back(VarState::make_Valid({})); - unsigned int drop_flag = (ivs.is_Optional() ? ivs.as_Optional() : ~0u); - ivs = VarState::make_MovedOut({ box$(VarState::make_Valid({})), drop_flag }); + size_t n_flds = 0; + with_val_type(sp, lv, [&](const auto& ty) { + DEBUG("ty = " << ty); + if(const auto* e = ty.m_data.opt_Path()) { + ASSERT_BUG(sp, e->binding.is_Struct(), ""); + const auto& str = *e->binding.as_Struct(); + TU_MATCHA( (str.m_data), (se), + (Unit, + BUG(sp, "Field access of unit-like struct"); + ), + (Tuple, + n_flds = se.size(); + ), + (Named, + n_flds = se.size(); + ) + ) + } + else if(const auto* e = ty.m_data.opt_Tuple()) { + n_flds = e->size(); + } + else if(const auto* e = ty.m_data.opt_Array()) { + n_flds = e->size_val; + } + else { + TODO(sp, "Determine field count for " << ty); + } + }, &w); + ::std::vector inner_vs; inner_vs.reserve(n_flds); + for(size_t i = 0; i < n_flds; i++) + inner_vs.push_back( tpl.clone() ); + ivs = VarState::make_Partial({ mv$(inner_vs) }); + } + vs = &ivs.as_Partial().inner_states.at(field_index); + } + TU_ARMA(Deref, _e) { + // HACK: If the dereferenced type is a Box ("owned_box") then hack in move and shallow drop + bool is_box = false; + if( this->m_lang_Box ) + { + with_val_type(sp, lv, [&](const auto& ty){ + DEBUG("ty = " << ty); + is_box = this->is_type_owned_box(ty); + }, &w); } - return *ivs.as_MovedOut().inner_state; - } - else - { - BUG(sp, "Move out of deref with non-Copy values - &move? - " << lv << " : " << FMT_CB(ss, this->with_val_type(sp, lv, [&](const auto& ty){ss<