diff options
156 files changed, 9959 insertions, 9967 deletions
@@ -1,8 +1,8 @@ # MRustC - Rust Compiler # - By John Hodge (Mutabah/thePowersGang) -# +# # Makefile -# +# # - Compiles mrustc # - Downloads rustc source to test against # - Attempts to compile rust's libstd @@ -42,7 +42,6 @@ CXXFLAGS += -Wno-misleading-indentation SHELL = bash ifeq ($(DBGTPL),) - else ifeq ($(DBGTPL),gdb) DBG := echo -e "r\nbt 12\nq" | gdb --args else ifeq ($(DBGTPL),valgrind) @@ -112,7 +111,7 @@ clean: PIPECMD ?= 2>&1 | tee $@_dbg.txt | tail -n $(TAIL_COUNT) ; test $${PIPESTATUS[0]} -eq 0 -output/%.ast: samples/%.rs $(BIN) +output/%.ast: samples/%.rs $(BIN) @mkdir -p output/ $(DBG) $(BIN) $< -o $@ $(PIPECMD) diff --git a/Notes/BoxOperator.md b/Notes/BoxOperator.md index f18537da..f718ba92 100644 --- a/Notes/BoxOperator.md +++ b/Notes/BoxOperator.md @@ -22,7 +22,7 @@ struct ExprNode_Emplace Placer, Boxer, }; - + Type m_type; ExprNodeP m_place; ExprNodeP m_value; diff --git a/Notes/MacroRules.md b/Notes/MacroRules.md index 83bc703e..27aaf8e5 100644 --- a/Notes/MacroRules.md +++ b/Notes/MacroRules.md @@ -43,7 +43,6 @@ Rule Generation Algorithm - EXPECT pat - COMPLETE - LOOP -- Example Application: `vec!` --------------------------- @@ -65,7 +64,7 @@ Merging - "EXPECT `:expr`" + (2) "EXPECT `:expr`" - "EXPECT `:expr`" - "EXPECT `;`" + "IF NOT `,` BREAK" - - "IF `;` { EXPECT `;` ... } LOOP { IF + - "IF `;` { EXPECT `;` ... } LOOP { IF - TODO: This needs to break out of the loop. Problem: Generating LOOP diff --git a/Notes/Restructure.txt b/Notes/Restructure.txt index 4f00b656..70ca1bf2 100644 --- a/Notes/Restructure.txt +++ b/Notes/Restructure.txt @@ -1,10 +1,7 @@ - - 1. High-level AST (basically the code in AST form) - Elimination or otherwise disabling of #[cfg]-disabled items - Path resolution (leave UFCS unresolved for now) > Take all paths, turn into UFCS if a node points to a type - > - Root-level UFCS resoluion > Recursion limit on searching through traits - Expression-level UFCS resolution @@ -72,7 +69,7 @@ CONSTANT = INT | STATIC_STRING | ITEM<SUBSTS> // reference to an item or constant etc | <P0 as TRAIT<P1...Pn>> // projection - | CONSTANT(CONSTANT...) // + | CONSTANT(CONSTANT...) // | CAST(CONSTANT, TY) // foo as bar | Struct { (f: CONSTANT)... } // aggregates... | (CONSTANT...) // diff --git a/Notes/Typeck.txt b/Notes/Typeck.txt index 0cd7f27e..06b392c0 100644 --- a/Notes/Typeck.txt +++ b/Notes/Typeck.txt @@ -1,5 +1,4 @@ -Type inferrence - +Type inference # Type equality procedure @@ -27,7 +26,6 @@ Needs to be able to point to functions in: Maybe can use separate types for each usecase? -- <!-- vim: ft=markdown --> @@ -1,42 +1,41 @@ -
-Mutabah's Rust Compiler
-
-_In-progress_ alternative rust compiler.
-
-Intro
-===
-This project is an attempt at creating a simple rust compiler in C++, with the ultimate goal of being a separate re-implementation.
-
-The short-term goal is to compile pre-borrowchecked rust code into some intermediate form (e.g. LLVM IR, x86-64 assembly, or C code). Thankfully, (from what I have seen), the borrow checker is not needed to compile rust code (just to ensure that it's valid)
-
-Current Features
-===
-- Attribute and macro expansion
-- Resolves all paths to absolute forms
-- Converts name-resolved AST into a more compact "HIR" (simplified module and expression tree)
-- Hackily evaluates constants
- - Constant evaluation is done by using duck-typing, which is then validated by the Type Check pass
- - This is how rustc did (or still does?) const eval before MIR
-- Type inference and checking
-- Closure and operator desugaring
-- MIR generation (with partial validation pass)
-- HIR/MIR (de)serialisation, allowing for `extern crate` handling
-
-Short-Term Plans
-===
-- Parse and Typecheck all run-pass tests
-- Code generation (including picking the output format)
-
-Medium-Term Goals
-===
-- Compile rustc
-- MIR optimisations
-- Propagate lifetime annotations so that MIR can include a borrow checker
-
-
-Progress
-===
-- Compiles the following standard library crates through to emitting serialised HIR+MIR
- - `libcore`, `liballoc`, `librustc_unicode`, `libcollections`, `liblibc`, AND `libstd`
-- `librustc_driver` compiles to serialised MIR
-
+Mutabah's Rust Compiler + +_In-progress_ alternative rust compiler. + +Intro +=== +This project is an attempt at creating a simple rust compiler in C++, with the ultimate goal of being a separate re-implementation. + +The short-term goal is to compile pre-borrowchecked rust code into some intermediate form (e.g. LLVM IR, x86-64 assembly, or C code). Thankfully, (from what I have seen), the borrow checker is not needed to compile rust code (just to ensure that it's valid) + +Current Features +=== +- Attribute and macro expansion +- Resolves all paths to absolute forms +- Converts name-resolved AST into a more compact "HIR" (simplified module and expression tree) +- Hackily evaluates constants + - Constant evaluation is done by using duck-typing, which is then validated by the Type Check pass + - This is how rustc did (or still does?) const eval before MIR +- Type inference and checking +- Closure and operator desugaring +- MIR generation (with partial validation pass) +- HIR/MIR (de)serialisation, allowing for `extern crate` handling + +Short-Term Plans +=== +- Parse and Typecheck all run-pass tests +- Code generation (including picking the output format) + +Medium-Term Goals +=== +- Compile rustc +- MIR optimisations +- Propagate lifetime annotations so that MIR can include a borrow checker + + +Progress +=== +- Compiles the following standard library crates through to emitting serialised HIR+MIR + - `libcore`, `liballoc`, `librustc_unicode`, `libcollections`, `liblibc`, AND `libstd` +- `librustc_driver` compiles to serialised MIR + diff --git a/bnf/Makefile b/bnf/Makefile index 99bca9a3..4a3b3454 100644 --- a/bnf/Makefile +++ b/bnf/Makefile @@ -37,7 +37,7 @@ $(BIN): $(OBJS) g++ $(CXXFLAGS) $< -c -o $@ -MMD -MP -MF $@.dep %.o: .gen/%.cpp g++ $(CXXFLAGS) $< -c -o $@ -MMD -MP -MF $@.dep - + .gen/rust.tab.cpp: .gen/.rust.y @mkdir -p $(dir $@) @echo [BISON] $@ diff --git a/bnf/ast_types.hpp b/bnf/ast_types.hpp index 09343c71..c6674df0 100644 --- a/bnf/ast_types.hpp +++ b/bnf/ast_types.hpp @@ -56,7 +56,7 @@ public: m_key(key), m_sub_items(sub_items) {} - + const ::std::string& key() const { return m_key; } const ::std::string& string() const { assert(m_sub_items.size() == 0); return m_value; } }; @@ -70,7 +70,7 @@ public: bool has(const ::std::string& name) const { return this->has(name.c_str()); } - + const MetaItem* get_first_ptr(const char* name) const { for(const auto& e : m_ents) { if( e.key() == name) @@ -83,7 +83,7 @@ public: assert(p != 0); return *p; } - + void push_back(MetaItem a) { m_ents.push_back( ::std::move(a) ); } @@ -126,14 +126,14 @@ public: {} virtual ~Item() { } - + void set_pub() { m_is_pub = true; } void add_attrs(AttrList a) { m_attrs.append( ::std::move(a) ); } - + const AttrList& attrs() const { return m_attrs; } }; @@ -149,7 +149,7 @@ class Module: bool m_is_extern; ::std::string m_name; ItemList m_items; - + ::std::vector<::std::string> m_mod_path; ::std::string m_filename, m_base_dir; public: @@ -169,18 +169,18 @@ public: m_items = ::std::move(x.m_items); this->add_attrs( ::std::move(x.m_attrs) ); } - + bool is_external() const { return m_is_extern; } const ::std::string& name() const { return m_name; } const ::std::string& filename() const { return m_filename; } const ::std::string& base_dir() const { return m_base_dir; } const ::std::vector<::std::string>& mod_path() const { return m_mod_path; } - + void set_name(::std::string name) { assert(m_name == ""); m_name = name; } - + void set_mod_path(::std::vector<::std::string> mod_path) { m_mod_path = ::std::move(mod_path); } @@ -188,7 +188,7 @@ public: m_filename = filename; m_base_dir = base_dir; } - + ItemList& items() { return m_items; } diff --git a/bnf/lex.hpp b/bnf/lex.hpp index 4c4c6576..95241b66 100644 --- a/bnf/lex.hpp +++ b/bnf/lex.hpp @@ -6,13 +6,13 @@ struct ParserContext { ::std::string filename; ::std::string base_path; - + ::std::unique_ptr<Module> output_module; - + // semi-evil hack used to break '>>' apart into '>' '>' ::std::vector<int> next_token; - - + + ParserContext(::std::string filename): filename(filename), output_module(), @@ -30,7 +30,7 @@ struct ParserContext else { return 0; } - } + } void pushback(int tok) { assert(next_token.size() < 2); next_token.push_back( tok ); diff --git a/bnf/main.cpp b/bnf/main.cpp index 37d84985..12c30507 100644 --- a/bnf/main.cpp +++ b/bnf/main.cpp @@ -19,7 +19,7 @@ extern FILE* yyin; ::std::unique_ptr<Module> parse_module_file(::std::string filename, ::std::string base_path) { ::std::cout << "filename = " << filename << ", base_path = " << base_path << ";" << ::std::endl; - + if( filename != "-" ) { yyin = fopen(filename.c_str(), "r"); if( !yyin ) { @@ -30,7 +30,7 @@ extern FILE* yyin; ParserContext context( ::std::move(filename) ); context.base_path = ::std::move(base_path); - + yylineno = 1; int rv = yyparse(context); if( yyin != stdin ) { @@ -39,7 +39,7 @@ extern FILE* yyin; if( rv != 0 ) { exit(1); } - + assert( context.output_module.get() ); //context.output_module->set_paths( ::std::move(context.filename), ::std::move(context.base_path) ); return ::std::move(context.output_module); @@ -48,14 +48,14 @@ extern FILE* yyin; void post_process_module(Module& mod, const ::std::string& mod_filename, const ::std::string& mod_dir_path) { ::std::cout << "mod = ["<<mod.mod_path()<<"], mod_filename = " << mod_filename << ", mod_dir_path = " << mod_dir_path << ";" << ::std::endl; - + for(auto& item : mod.items()) { Module* opt_submod = dynamic_cast<Module*>(item.get()); if( !opt_submod ) continue; Module& submod = *opt_submod; printf("- Module %s\n", submod.name().c_str()); - + if( ! submod.is_external() ) { // - inline modules can be ignored.. for now if( mod_dir_path != "" ) { @@ -91,23 +91,23 @@ void post_process_module(Module& mod, const ::std::string& mod_filename, const : fclose(yyin); } } - + assert(filename.size() > 0); submod = ::std::move( *parse_module_file(filename, base_path) ); submod.set_paths( filename, base_path ); } - + auto mp = mod.mod_path(); mp.push_back(submod.name()); submod.set_mod_path(::std::move(mp)); } - + for(auto& item : mod.items()) { Module* opt_submod = dynamic_cast<Module*>(item.get()); if( !opt_submod ) continue; Module& submod = *opt_submod; - + const ::std::string& submod_fname = submod.filename(); const ::std::string& submod_dir = submod.base_dir(); post_process_module(submod, submod_fname, submod_dir); @@ -128,11 +128,11 @@ int main(int argc, char *argv[]) { ::std::string base_path = (base_filename == "-" ? ::std::string("") : get_dir_path(base_filename)); auto mod = parse_module_file(base_filename, base_path); printf("output module = %p\n", &*mod); - + post_process_module(*mod, base_filename, base_path); - + printf("Crate parsed\n"); - + return 0; } void yyerror(ParserContext& context, const char *s) { diff --git a/bnf/rust.lex b/bnf/rust.lex index d98024ae..e6a62b33 100644 --- a/bnf/rust.lex +++ b/bnf/rust.lex @@ -162,10 +162,10 @@ b?r#*\" { auto rs = handle_raw_string( (*yytext=='b' ? yytext+2 : yytext+1) ); l %% uint32_t parse_char_literal(const char *_s) { const uint8_t* s = (const uint8_t*)_s; - + assert(*s++ == '\''); uint32_t rv = 0; - + if( *s == '\\' ) { s ++; switch(*s) @@ -205,9 +205,9 @@ uint32_t parse_char_literal(const char *_s) { s ++; } assert(*s++ == '"'); - + ::std::string rv; - + for( ; *s != '"'; s ++ ) { if( *s == '\\' ) @@ -281,9 +281,9 @@ loop: num_hash ++; assert(*s == '"'); printf("handle_raw_string - num_hash=%i\n", num_hash); - + ::std::string rv; - + for(;;) { char c; @@ -303,7 +303,7 @@ loop: // Didn't find enough, append to output rv += '"'; while(i--) rv += '#'; - + } else if( c <= 0 ) { break; @@ -312,6 +312,6 @@ loop: rv += c; } } - + return rv; } @@ -20,7 +20,7 @@ %token <::std::string*> IDENT LIFETIME STRING MACRO %token <int> INTEGER CHARLIT -%token <double> FLOAT +%token <double> FLOAT %token <::std::string*> DOC_COMMENT SUPER_DOC_COMMENT %token HASHBANG %token DOUBLECOLON THINARROW FATARROW DOUBLEDOT TRIPLEDOT @@ -49,7 +49,7 @@ %type <MetaItem*> meta_item %type <MetaItems*> meta_items -%type <Item*> item macro_item vis_item unsafe_item unsafe_vis_item +%type <Item*> item macro_item vis_item unsafe_item unsafe_vis_item %type <UseSet*> use_def %type <TypeAlias*> type_def %type <Module*> module_def @@ -370,8 +370,8 @@ trait_item | RWD_const IDENT ':' type opt_assign_value ';' | opt_unsafe RWD_fn fn_def_hdr_PROTO ';' | opt_unsafe fn_qualifiers RWD_fn fn_def_hdr_PROTO ';' - | opt_unsafe RWD_fn fn_def_hdr_PROTO code - | opt_unsafe fn_qualifiers RWD_fn fn_def_hdr_PROTO code + | opt_unsafe RWD_fn fn_def_hdr_PROTO code + | opt_unsafe fn_qualifiers RWD_fn fn_def_hdr_PROTO code ; opt_assign_value: | '=' expr; @@ -434,7 +434,7 @@ dlt: DOUBLELT { context.pushback('<'); context.pushback('<'); } type_args : '<' type_exprs '>' - | '<' type_exprs DOUBLEGT { bnf_trace(context, "Double-gt terminated type expr"); context.pushback('>'); } + | '<' type_exprs DOUBLEGT { bnf_trace(context, "Double-gt terminated type expr"); context.pushback('>'); } | dlt type_args ; @@ -474,7 +474,7 @@ ufcs_path_tail : type '>' | type RWD_as trait_path '>' | type RWD_as trait_path DOUBLEGT { context.pushback('>'); } - ; + ; type_path_segs : type_path_segs DOUBLECOLON type_path_seg | type_path_seg @@ -619,7 +619,7 @@ flow_control | RWD_continue opt_lifetime {} ; block_lines - : + : | attrs expr_na | attrs MACRO tt_paren | super_attr block_lines @@ -674,7 +674,7 @@ expr_blocks : RWD_match expr_NOSTRLIT '{' match_arms '}' { } | RWD_if if_block | RWD_unsafe '{' block_contents '}' { } - | flow_control + | flow_control | loop_block ; loop_block @@ -700,7 +700,7 @@ match_arms_list | match_arms_list attrs match_arm_brace ; match_arm_last - : attrs match_arm + : attrs match_arm | attrs match_arm ',' ; match_pattern diff --git a/samples/1.rs b/samples/1.rs index 6bc434cb..320b23a8 100644 --- a/samples/1.rs +++ b/samples/1.rs @@ -1,126 +1,126 @@ -// UTF8Reader
-// - by John Hodge (thePowersGang)
-//
-//
-// Reads a stream of UTF-8 encoded codepoints from a "Reader"
-use std::io::IoResult;
-
-/// Unicode replacement character
-static BADCHAR: char = '\uFFFD';
-
-/// UTF8 reader structure
-pub struct UTF8Reader<T: Reader>
-{
- stream: T,
-}
-
-fn tochar(codepoint: u32) -> char
-{
- match ::std::char::from_u32(codepoint)
- {
- Some(c) => c,
- None => BADCHAR,
- }
-}
-
-impl<T:Reader> UTF8Reader<T>
-{
- pub fn new(reader: T) -> UTF8Reader<T>
- {
- UTF8Reader {
- stream: reader,
- }
- }
-
- /// Read a single codepoint from the stream.
- /// On an encoding error, it returns '\uFFFD' (the unicode replacement character)
- pub fn getc(&mut self) -> IoResult<char>
- {
- let ch1 = try!(self.stream.read_byte()) as u32;
- if ch1 & 0xC0 == 0x80 {
- return Ok( BADCHAR )
- }
- if ch1 & 0x80 == 0x00
- {
- // Single-byte
- Ok( tochar(ch1) )
- }
- else if ch1 & 0xE0 == 0xC0
- {
- // Two-byte sequence
- let ch2 = try!(self.stream.read_byte()) as u32;
- if ch2 & 0xC0 != 0x80 {
- return Ok( BADCHAR );
- }
-
- let ret = (ch1 & 0x1F << 6) | (ch2 & 0x3F << 0);
- Ok( tochar(ret) )
- }
- else if ch1 & 0xF0 == 0xE0
- {
- // Three-byte sequence
- let ch2 = try!(self.stream.read_byte()) as u32;
- if ch2 & 0xC0 != 0x80 {
- return Ok( BADCHAR );
- }
- let ch3 = try!(self.stream.read_byte()) as u32;
- if ch3 & 0xC0 != 0x80 {
- return Ok( BADCHAR );
- }
-
- let ret = (ch1 & 0x0F << 12) | (ch2 & 0x3F << 6) | (ch3 & 0x3F << 0);
- Ok( tochar(ret) )
- }
- else if ch1 & 0xF8 == 0xF0
- {
- // Four-byte sequence
- let ch2 = try!(self.stream.read_byte()) as u32;
- if ch2 & 0xC0 != 0x80 {
- return Ok( BADCHAR );
- }
- let ch3 = try!(self.stream.read_byte()) as u32;
- if ch3 & 0xC0 != 0x80 {
- return Ok( BADCHAR );
- }
- let ch4 = try!(self.stream.read_byte()) as u32;
- if ch4 & 0xC0 != 0x80 {
- return Ok( BADCHAR );
- }
-
- let ret = (ch1 & 0x07 << 18) | (ch2 & 0x3F << 12) | (ch3 & 0x3F << 6) | (ch4 & 0x3F << 0);
- Ok( tochar(ret) )
- }
- else
- {
- // More than four bytes is invalid
- Ok( BADCHAR )
- }
- }
-}
-
-/// Implmentation of the same interface as 'Chars' provides, returns None at the end of the stream
-impl<T:Reader> Iterator for UTF8Reader<T>
-{
- type Item = IoResult<char>;
- fn next(&mut self) -> Option<IoResult<char>>
- {
- // Get result from decoder
- match self.getc()
- {
- // - All good, return a character
- Ok(c) => Some( Ok(c) ),
- // - Error, check if it's EOF
- Err(e) => match e.kind {
- // Return 'None' on EOF (end of stream)
- ::std::io::IoError::EndOfFile => None,
- _ => Some( Err( e ) ),
- }
- }
- }
-}
-
-#[test]
-fn it_works() {
-}
-
-// vim: ft=rust
+// UTF8Reader +// - by John Hodge (thePowersGang) +// +// +// Reads a stream of UTF-8 encoded codepoints from a "Reader" +use std::io::IoResult; + +/// Unicode replacement character +static BADCHAR: char = '\uFFFD'; + +/// UTF8 reader structure +pub struct UTF8Reader<T: Reader> +{ + stream: T, +} + +fn tochar(codepoint: u32) -> char +{ + match ::std::char::from_u32(codepoint) + { + Some(c) => c, + None => BADCHAR, + } +} + +impl<T:Reader> UTF8Reader<T> +{ + pub fn new(reader: T) -> UTF8Reader<T> + { + UTF8Reader { + stream: reader, + } + } + + /// Read a single codepoint from the stream. + /// On an encoding error, it returns '\uFFFD' (the unicode replacement character) + pub fn getc(&mut self) -> IoResult<char> + { + let ch1 = try!(self.stream.read_byte()) as u32; + if ch1 & 0xC0 == 0x80 { + return Ok( BADCHAR ) + } + if ch1 & 0x80 == 0x00 + { + // Single-byte + Ok( tochar(ch1) ) + } + else if ch1 & 0xE0 == 0xC0 + { + // Two-byte sequence + let ch2 = try!(self.stream.read_byte()) as u32; + if ch2 & 0xC0 != 0x80 { + return Ok( BADCHAR ); + } + + let ret = (ch1 & 0x1F << 6) | (ch2 & 0x3F << 0); + Ok( tochar(ret) ) + } + else if ch1 & 0xF0 == 0xE0 + { + // Three-byte sequence + let ch2 = try!(self.stream.read_byte()) as u32; + if ch2 & 0xC0 != 0x80 { + return Ok( BADCHAR ); + } + let ch3 = try!(self.stream.read_byte()) as u32; + if ch3 & 0xC0 != 0x80 { + return Ok( BADCHAR ); + } + + let ret = (ch1 & 0x0F << 12) | (ch2 & 0x3F << 6) | (ch3 & 0x3F << 0); + Ok( tochar(ret) ) + } + else if ch1 & 0xF8 == 0xF0 + { + // Four-byte sequence + let ch2 = try!(self.stream.read_byte()) as u32; + if ch2 & 0xC0 != 0x80 { + return Ok( BADCHAR ); + } + let ch3 = try!(self.stream.read_byte()) as u32; + if ch3 & 0xC0 != 0x80 { + return Ok( BADCHAR ); + } + let ch4 = try!(self.stream.read_byte()) as u32; + if ch4 & 0xC0 != 0x80 { + return Ok( BADCHAR ); + } + + let ret = (ch1 & 0x07 << 18) | (ch2 & 0x3F << 12) | (ch3 & 0x3F << 6) | (ch4 & 0x3F << 0); + Ok( tochar(ret) ) + } + else + { + // More than four bytes is invalid + Ok( BADCHAR ) + } + } +} + +/// Implmentation of the same interface as 'Chars' provides, returns None at the end of the stream +impl<T:Reader> Iterator for UTF8Reader<T> +{ + type Item = IoResult<char>; + fn next(&mut self) -> Option<IoResult<char>> + { + // Get result from decoder + match self.getc() + { + // - All good, return a character + Ok(c) => Some( Ok(c) ), + // - Error, check if it's EOF + Err(e) => match e.kind { + // Return 'None' on EOF (end of stream) + ::std::io::IoError::EndOfFile => None, + _ => Some( Err( e ) ), + } + } + } +} + +#[test] +fn it_works() { +} + +// vim: ft=rust diff --git a/samples/std.rs b/samples/std.rs index 11913768..da60346f 100644 --- a/samples/std.rs +++ b/samples/std.rs @@ -53,7 +53,7 @@ pub mod io { EndOfFile, } - + pub trait Reader { fn read_byte(&mut self) -> IoResult<u8>; diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 15b8c7d7..39250a41 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1,432 +1,432 @@ -/*
- */
-#include "ast.hpp"
-#include "crate.hpp"
-#include "types.hpp"
-#include "expr.hpp"
-#include "../common.hpp"
-#include <iostream>
-#include "../parse/parseerror.hpp"
-#include <algorithm>
-#include <serialiser_texttree.hpp>
-
-namespace AST {
-
-
-namespace {
- ::std::vector<MetaItem> clone_mivec(const ::std::vector<MetaItem>& v) {
- ::std::vector<MetaItem> ri;
- ri.reserve(v.size());
- for(const auto& i : v)
- ri.push_back( i.clone() );
- return ri;
- }
-}
-
-MetaItems::~MetaItems()
-{
-}
-MetaItems MetaItems::clone() const
-{
- return MetaItems( m_span, clone_mivec(m_items) );
-}
-
-void MetaItems::push_back(MetaItem i)
-{
- m_items.push_back( ::std::move(i) );
-}
-const MetaItem* MetaItems::get(const char *name) const
-{
- for( auto& i : m_items ) {
- if(i.name() == name) {
- //i.mark_used();
- return &i;
- }
- }
- return 0;
-}
-
-MetaItem::~MetaItem()
-{
-}
-MetaItem MetaItem::clone() const
-{
- TU_MATCH(MetaItemData, (m_data), (e),
- (None,
- return MetaItem(m_name);
- ),
- (String,
- return MetaItem(m_name, e.val);
- ),
- (List,
- return MetaItem(m_name, clone_mivec(e.sub_items));
- )
- )
- throw ::std::runtime_error("MetaItem::clone - Fell off end");
-}
-
-StructItem StructItem::clone() const
-{
- return StructItem(m_attrs.clone(), m_is_public, m_name, m_type.clone());
-}
-TupleItem TupleItem::clone() const
-{
- return TupleItem(m_attrs.clone(), m_is_public, m_type.clone());
-}
-
-
-TypeAlias TypeAlias::clone() const
-{
- return TypeAlias( m_params.clone(), m_type.clone() );
-}
-Static Static::clone() const
-{
- return Static( m_class, m_type.clone(), m_value.is_valid() ? AST::Expr( m_value.node().clone() ) : AST::Expr() );
-}
-
-Function::Function(Span sp, GenericParams params, ::std::string abi, bool is_unsafe, bool is_const, bool is_variadic, TypeRef ret_type, Arglist args):
- m_span(sp),
- m_params( move(params) ),
- m_rettype( move(ret_type) ),
- m_args( move(args) ),
- m_abi( mv$(abi) ),
- m_is_const(is_const),
- m_is_unsafe(is_unsafe),
- m_is_variadic(is_variadic)
-{
-}
-Function Function::clone() const
-{
- decltype(m_args) new_args;
- for(const auto& arg : m_args)
- new_args.push_back( ::std::make_pair( arg.first.clone(), arg.second.clone() ) );
-
- auto rv = Function( m_span, m_params.clone(), m_abi, m_is_unsafe, m_is_const, m_is_variadic, m_rettype.clone(), mv$(new_args) );
- if( m_code.is_valid() )
- {
- rv.m_code = AST::Expr( m_code.node().clone() );
- }
- return rv;
-}
-
-void Trait::add_type(::std::string name, TypeRef type) {
- m_items.push_back( Named<Item>(mv$(name), Item::make_Type({TypeAlias(GenericParams(), mv$(type))}), true) );
-}
-void Trait::add_function(::std::string name, Function fcn) {
- DEBUG("trait fn " << name);
- m_items.push_back( Named<Item>(mv$(name), Item::make_Function({mv$(fcn)}), true) );
-}
-void Trait::add_static(::std::string name, Static v) {
- m_items.push_back( Named<Item>(mv$(name), Item::make_Static({mv$(v)}), true) );
-}
-void Trait::set_is_marker() {
- m_is_marker = true;
-}
-bool Trait::is_marker() const {
- return m_is_marker;
-}
-bool Trait::has_named_item(const ::std::string& name, bool& out_is_fcn) const
-{
- for( const auto& i : m_items )
- {
- if( i.name == name ) {
- out_is_fcn = i.data.is_Function();
- return true;
- }
- }
- return false;
-}
-
-Trait Trait::clone() const
-{
- auto rv = Trait(m_params.clone(), m_supertraits);
- for(const auto& item : m_items)
- {
- rv.m_items.push_back( Named<Item> { item.name, item.data.clone(), item.is_pub } );
- }
- return rv;
-}
-
-Enum Enum::clone() const
-{
- decltype(m_variants) new_variants;
- for(const auto& var : m_variants)
- {
- TU_MATCHA( (var.m_data), (e),
- (Value,
- new_variants.push_back( EnumVariant(var.m_attrs.clone(), var.m_name, e.m_value.clone()) );
- ),
- (Tuple,
- decltype(e.m_sub_types) new_st;
- for(const auto& f : e.m_sub_types)
- new_st.push_back( f.clone() );
- new_variants.push_back( EnumVariant(var.m_attrs.clone(), var.m_name, mv$(new_st)) );
- ),
- (Struct,
- decltype(e.m_fields) new_fields;
- for(const auto& f : e.m_fields)
- new_fields.push_back( f.clone() );
- new_variants.push_back( EnumVariant(var.m_attrs.clone(), var.m_name, mv$(new_fields)) );
- )
- )
- }
- return Enum(m_params.clone(), mv$(new_variants));
-}
-Struct Struct::clone() const
-{
- TU_MATCHA( (m_data), (e),
- (Tuple,
- decltype(e.ents) new_fields;
- for(const auto& f : e.ents)
- new_fields.push_back( f.clone() );
- return Struct(m_params.clone(), mv$(new_fields));
- ),
- (Struct,
- decltype(e.ents) new_fields;
- for(const auto& f : e.ents)
- new_fields.push_back( f.clone() );
- return Struct(m_params.clone(), mv$(new_fields));
- )
- )
- throw "";
-}
-
-Union Union::clone() const
-{
- decltype(m_variants) new_vars;
- for(const auto& f : m_variants)
- new_vars.push_back( f.clone() );
- return Union(m_params.clone(), mv$(new_vars));
-}
-
-::std::ostream& operator<<(::std::ostream& os, const ImplDef& impl)
-{
- 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)
-{
- 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)
-{
- 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)
-{
- m_items.push_back( ImplItem { is_public, is_specialisable, mv$(name), box$( Item::make_Static(mv$(v)) ) } );
-}
-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
-{
- for( const auto& it : this->items() )
- {
- if( it.name == name ) {
- return true;
- }
- }
- return false;
-}
-
-::std::ostream& operator<<(::std::ostream& os, const Impl& impl)
-{
- return os << impl.m_def;
-}
-
-::rust::option<char> ImplRef::find_named_item(const ::std::string& name) const
-{
- if( this->impl.has_named_item(name) ) {
- return ::rust::Some(' ');
- }
- else {
- return ::rust::None<char>();
- }
-}
-
-::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
-{
- return UseStmt(sp, path);
-}
-
-void ExternBlock::add_item(Named<Item> named_item)
-{
- ASSERT_BUG(named_item.data.span, named_item.data.is_Function() || named_item.data.is_Static(), "Incorrect item type for ExternBlock");
- m_items.push_back( mv$(named_item) );
-}
-ExternBlock ExternBlock::clone() const
-{
- TODO(Span(), "Clone an extern block");
-}
-
-::std::shared_ptr<AST::Module> Module::add_anon() {
- auto rv = ::std::shared_ptr<AST::Module>( new Module(m_my_path + FMT("#" << m_anon_modules.size())) );
- DEBUG("New anon " << rv->m_my_path);
- rv->m_file_info = m_file_info;
-
- m_anon_modules.push_back( rv );
-
- return rv;
-}
-
-void Module::add_item( Named<Item> named_item ) {
- m_items.push_back( mv$(named_item) );
- const auto& i = m_items.back();
- if( i.name == "" ) {
- }
- else {
- 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, MetaItems attrs) {
- it.attrs = mv$(attrs);
- add_item( Named<Item>( mv$(name), mv$(it), is_pub ) );
-}
-void Module::add_ext_crate(bool is_public, ::std::string ext_name, ::std::string imp_name, MetaItems 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, MetaItems 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::MetaItems {} );
-}
-void Module::add_macro(bool is_exported, ::std::string name, MacroRulesPtr macro) {
- m_macros.push_back( Named<MacroRulesPtr>( mv$(name), mv$(macro), is_exported ) );
-}
-void Module::add_macro_import(::std::string name, const MacroRules& mr) {
- m_macro_import_res.push_back( NamedNS<const MacroRules*>( mv$(name), &mr, false ) );
-}
-
-Item Item::clone() const
-{
- TU_MATCHA( (*this), (e),
- (None,
- return AST::Item(e);
- ),
- (MacroInv,
- TODO(this->span, "Clone on Item::MacroInv");
- ),
- (Use,
- return AST::Item(e.clone());
- ),
- (ExternBlock,
- TODO(this->span, "Clone on Item::" << this->tag_str());
- ),
- (Impl,
- TODO(this->span, "Clone on Item::Impl");
- ),
- (NegImpl,
- TODO(this->span, "Clone on Item::NegImpl");
- ),
- (Module,
- TODO(this->span, "Clone on Item::Module");
- ),
- (Crate,
- return AST::Item(e);
- ),
- (Type,
- return AST::Item(e.clone());
- ),
- (Struct,
- return AST::Item(e.clone());
- ),
- (Enum,
- return AST::Item(e.clone());
- ),
- (Union,
- return AST::Item(e.clone());
- ),
- (Trait,
- return AST::Item(e.clone());
- ),
-
- (Function,
- return AST::Item(e.clone());
- ),
- (Static,
- return AST::Item(e.clone());
- )
- )
- throw "";
-}
-
-
-
-::std::ostream& operator<<(::std::ostream& os, const TypeParam& tp)
-{
- //os << "TypeParam(";
- os << tp.m_name;
- os << " = ";
- os << tp.m_default;
- //os << ")";
- return os;
-}
-
-::std::ostream& operator<<(::std::ostream& os, const GenericBound& x)
-{
- TU_MATCH(GenericBound, (x), (ent),
- (Lifetime,
- os << "'" << ent.test << ": '" << ent.bound;
- ),
- (TypeLifetime,
- os << ent.type << ": '" << ent.bound;
- ),
- (IsTrait,
- if( ! ent.hrls.empty() )
- {
- os << "for<";
- for(const auto& l : ent.hrls)
- os << "'" << l;
- os << ">";
- }
- os << ent.type << ": " << ent.trait;
- ),
- (MaybeTrait,
- os << ent.type << ": ?" << ent.trait;
- ),
- (NotTrait,
- os << ent.type << ": !" << ent.trait;
- ),
- (Equality,
- os << ent.type << " = " << ent.replacement;
- )
- )
- return os;
-}
-
-
-int GenericParams::find_name(const char* name) const
-{
- for( unsigned int i = 0; i < m_type_params.size(); i ++ )
- {
- if( m_type_params[i].name() == name )
- return i;
- }
- DEBUG("Type param '" << name << "' not in list");
- return -1;
-}
-
-::std::ostream& operator<<(::std::ostream& os, const GenericParams& tps)
-{
- return os << "<" << tps.m_lifetime_params << "," << tps.m_type_params << "> where {" << tps.m_bounds << "}";
-}
-
-} // namespace AST
+/* + */ +#include "ast.hpp" +#include "crate.hpp" +#include "types.hpp" +#include "expr.hpp" +#include "../common.hpp" +#include <iostream> +#include "../parse/parseerror.hpp" +#include <algorithm> +#include <serialiser_texttree.hpp> + +namespace AST { + + +namespace { + ::std::vector<MetaItem> clone_mivec(const ::std::vector<MetaItem>& v) { + ::std::vector<MetaItem> ri; + ri.reserve(v.size()); + for(const auto& i : v) + ri.push_back( i.clone() ); + return ri; + } +} + +MetaItems::~MetaItems() +{ +} +MetaItems MetaItems::clone() const +{ + return MetaItems( m_span, clone_mivec(m_items) ); +} + +void MetaItems::push_back(MetaItem i) +{ + m_items.push_back( ::std::move(i) ); +} +const MetaItem* MetaItems::get(const char *name) const +{ + for( auto& i : m_items ) { + if(i.name() == name) { + //i.mark_used(); + return &i; + } + } + return 0; +} + +MetaItem::~MetaItem() +{ +} +MetaItem MetaItem::clone() const +{ + TU_MATCH(MetaItemData, (m_data), (e), + (None, + return MetaItem(m_name); + ), + (String, + return MetaItem(m_name, e.val); + ), + (List, + return MetaItem(m_name, clone_mivec(e.sub_items)); + ) + ) + throw ::std::runtime_error("MetaItem::clone - Fell off end"); +} + +StructItem StructItem::clone() const +{ + return StructItem(m_attrs.clone(), m_is_public, m_name, m_type.clone()); +} +TupleItem TupleItem::clone() const +{ + return TupleItem(m_attrs.clone(), m_is_public, m_type.clone()); +} + + +TypeAlias TypeAlias::clone() const +{ + return TypeAlias( m_params.clone(), m_type.clone() ); +} +Static Static::clone() const +{ + return Static( m_class, m_type.clone(), m_value.is_valid() ? AST::Expr( m_value.node().clone() ) : AST::Expr() ); +} + +Function::Function(Span sp, GenericParams params, ::std::string abi, bool is_unsafe, bool is_const, bool is_variadic, TypeRef ret_type, Arglist args): + m_span(sp), + m_params( move(params) ), + m_rettype( move(ret_type) ), + m_args( move(args) ), + m_abi( mv$(abi) ), + m_is_const(is_const), + m_is_unsafe(is_unsafe), + m_is_variadic(is_variadic) +{ +} +Function Function::clone() const +{ + decltype(m_args) new_args; + for(const auto& arg : m_args) + new_args.push_back( ::std::make_pair( arg.first.clone(), arg.second.clone() ) ); + + auto rv = Function( m_span, m_params.clone(), m_abi, m_is_unsafe, m_is_const, m_is_variadic, m_rettype.clone(), mv$(new_args) ); + if( m_code.is_valid() ) + { + rv.m_code = AST::Expr( m_code.node().clone() ); + } + return rv; +} + +void Trait::add_type(::std::string name, TypeRef type) { + m_items.push_back( Named<Item>(mv$(name), Item::make_Type({TypeAlias(GenericParams(), mv$(type))}), true) ); +} +void Trait::add_function(::std::string name, Function fcn) { + DEBUG("trait fn " << name); + m_items.push_back( Named<Item>(mv$(name), Item::make_Function({mv$(fcn)}), true) ); +} +void Trait::add_static(::std::string name, Static v) { + m_items.push_back( Named<Item>(mv$(name), Item::make_Static({mv$(v)}), true) ); +} +void Trait::set_is_marker() { + m_is_marker = true; +} +bool Trait::is_marker() const { + return m_is_marker; +} +bool Trait::has_named_item(const ::std::string& name, bool& out_is_fcn) const +{ + for( const auto& i : m_items ) + { + if( i.name == name ) { + out_is_fcn = i.data.is_Function(); + return true; + } + } + return false; +} + +Trait Trait::clone() const +{ + auto rv = Trait(m_params.clone(), m_supertraits); + for(const auto& item : m_items) + { + rv.m_items.push_back( Named<Item> { item.name, item.data.clone(), item.is_pub } ); + } + return rv; +} + +Enum Enum::clone() const +{ + decltype(m_variants) new_variants; + for(const auto& var : m_variants) + { + TU_MATCHA( (var.m_data), (e), + (Value, + new_variants.push_back( EnumVariant(var.m_attrs.clone(), var.m_name, e.m_value.clone()) ); + ), + (Tuple, + decltype(e.m_sub_types) new_st; + for(const auto& f : e.m_sub_types) + new_st.push_back( f.clone() ); + new_variants.push_back( EnumVariant(var.m_attrs.clone(), var.m_name, mv$(new_st)) ); + ), + (Struct, + decltype(e.m_fields) new_fields; + for(const auto& f : e.m_fields) + new_fields.push_back( f.clone() ); + new_variants.push_back( EnumVariant(var.m_attrs.clone(), var.m_name, mv$(new_fields)) ); + ) + ) + } + return Enum(m_params.clone(), mv$(new_variants)); +} +Struct Struct::clone() const +{ + TU_MATCHA( (m_data), (e), + (Tuple, + decltype(e.ents) new_fields; + for(const auto& f : e.ents) + new_fields.push_back( f.clone() ); + return Struct(m_params.clone(), mv$(new_fields)); + ), + (Struct, + decltype(e.ents) new_fields; + for(const auto& f : e.ents) + new_fields.push_back( f.clone() ); + return Struct(m_params.clone(), mv$(new_fields)); + ) + ) + throw ""; +} + +Union Union::clone() const +{ + decltype(m_variants) new_vars; + for(const auto& f : m_variants) + new_vars.push_back( f.clone() ); + return Union(m_params.clone(), mv$(new_vars)); +} + +::std::ostream& operator<<(::std::ostream& os, const ImplDef& impl) +{ + 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) +{ + 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) +{ + 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) +{ + m_items.push_back( ImplItem { is_public, is_specialisable, mv$(name), box$( Item::make_Static(mv$(v)) ) } ); +} +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 +{ + for( const auto& it : this->items() ) + { + if( it.name == name ) { + return true; + } + } + return false; +} + +::std::ostream& operator<<(::std::ostream& os, const Impl& impl) +{ + return os << impl.m_def; +} + +::rust::option<char> ImplRef::find_named_item(const ::std::string& name) const +{ + if( this->impl.has_named_item(name) ) { + return ::rust::Some(' '); + } + else { + return ::rust::None<char>(); + } +} + +::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 +{ + return UseStmt(sp, path); +} + +void ExternBlock::add_item(Named<Item> named_item) +{ + ASSERT_BUG(named_item.data.span, named_item.data.is_Function() || named_item.data.is_Static(), "Incorrect item type for ExternBlock"); + m_items.push_back( mv$(named_item) ); +} +ExternBlock ExternBlock::clone() const +{ + TODO(Span(), "Clone an extern block"); +} + +::std::shared_ptr<AST::Module> Module::add_anon() { + auto rv = ::std::shared_ptr<AST::Module>( new Module(m_my_path + FMT("#" << m_anon_modules.size())) ); + DEBUG("New anon " << rv->m_my_path); + rv->m_file_info = m_file_info; + + m_anon_modules.push_back( rv ); + + return rv; +} + +void Module::add_item( Named<Item> named_item ) { + m_items.push_back( mv$(named_item) ); + const auto& i = m_items.back(); + if( i.name == "" ) { + } + else { + 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, MetaItems attrs) { + it.attrs = mv$(attrs); + add_item( Named<Item>( mv$(name), mv$(it), is_pub ) ); +} +void Module::add_ext_crate(bool is_public, ::std::string ext_name, ::std::string imp_name, MetaItems 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, MetaItems 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::MetaItems {} ); +} +void Module::add_macro(bool is_exported, ::std::string name, MacroRulesPtr macro) { + m_macros.push_back( Named<MacroRulesPtr>( mv$(name), mv$(macro), is_exported ) ); +} +void Module::add_macro_import(::std::string name, const MacroRules& mr) { + m_macro_import_res.push_back( NamedNS<const MacroRules*>( mv$(name), &mr, false ) ); +} + +Item Item::clone() const +{ + TU_MATCHA( (*this), (e), + (None, + return AST::Item(e); + ), + (MacroInv, + TODO(this->span, "Clone on Item::MacroInv"); + ), + (Use, + return AST::Item(e.clone()); + ), + (ExternBlock, + TODO(this->span, "Clone on Item::" << this->tag_str()); + ), + (Impl, + TODO(this->span, "Clone on Item::Impl"); + ), + (NegImpl, + TODO(this->span, "Clone on Item::NegImpl"); + ), + (Module, + TODO(this->span, "Clone on Item::Module"); + ), + (Crate, + return AST::Item(e); + ), + (Type, + return AST::Item(e.clone()); + ), + (Struct, + return AST::Item(e.clone()); + ), + (Enum, + return AST::Item(e.clone()); + ), + (Union, + return AST::Item(e.clone()); + ), + (Trait, + return AST::Item(e.clone()); + ), + + (Function, + return AST::Item(e.clone()); + ), + (Static, + return AST::Item(e.clone()); + ) + ) + throw ""; +} + + + +::std::ostream& operator<<(::std::ostream& os, const TypeParam& tp) +{ + //os << "TypeParam("; + os << tp.m_name; + os << " = "; + os << tp.m_default; + //os << ")"; + return os; +} + +::std::ostream& operator<<(::std::ostream& os, const GenericBound& x) +{ + TU_MATCH(GenericBound, (x), (ent), + (Lifetime, + os << "'" << ent.test << ": '" << ent.bound; + ), + (TypeLifetime, + os << ent.type << ": '" << ent.bound; + ), + (IsTrait, + if( ! ent.hrls.empty() ) + { + os << "for<"; + for(const auto& l : ent.hrls) + os << "'" << l; + os << ">"; + } + os << ent.type << ": " << ent.trait; + ), + (MaybeTrait, + os << ent.type << ": ?" << ent.trait; + ), + (NotTrait, + os << ent.type << ": !" << ent.trait; + ), + (Equality, + os << ent.type << " = " << ent.replacement; + ) + ) + return os; +} + + +int GenericParams::find_name(const char* name) const +{ + for( unsigned int i = 0; i < m_type_params.size(); i ++ ) + { + if( m_type_params[i].name() == name ) + return i; + } + DEBUG("Type param '" << name << "' not in list"); + return -1; +} + +::std::ostream& operator<<(::std::ostream& os, const GenericParams& tps) +{ + return os << "<" << tps.m_lifetime_params << "," << tps.m_type_params << "> where {" << tps.m_bounds << "}"; +} + +} // namespace AST diff --git a/src/ast/ast.hpp b/src/ast/ast.hpp index 4b48aa01..b63cb2e6 100644 --- a/src/ast/ast.hpp +++ b/src/ast/ast.hpp @@ -1,642 +1,642 @@ -/*
- * MRustC - Rust Compiler
- * - By John Hodge (Mutabah/thePowersGang)
- *
- * ast/ast.hpp
- * - Core AST header
- */
-#ifndef AST_HPP_INCLUDED
-#define AST_HPP_INCLUDED
-
-#include <string>
-#include <vector>
-#include <stdexcept>
-#include "../coretypes.hpp"
-#include <memory>
-#include <map>
-#include <unordered_map>
-#include <algorithm>
-
-#include "../parse/tokentree.hpp"
-#include "types.hpp"
-#include <serialise.hpp>
-
-#include <ast/pattern.hpp>
-#include <ast/attrs.hpp>
-#include <ast/expr_ptr.hpp>
-#include <ast/item.hpp>
-#include <ast/macro.hpp> // MacroInvocation
-
-#include "generics.hpp"
-
-#include <macro_rules/macro_rules_ptr.hpp>
-
-namespace AST {
-
-class Crate;
-
-class Module;
-class Item;
-
-using ::std::unique_ptr;
-using ::std::move;
-
-enum eItemType
-{
- ITEM_TRAIT,
- ITEM_STRUCT,
- ITEM_FN,
-};
-
-struct StructItem
-{
- ::AST::MetaItems m_attrs;
- bool m_is_public;
- ::std::string m_name;
- TypeRef m_type;
-
- //StructItem() {}
-
- StructItem(::AST::MetaItems attrs, bool is_pub, ::std::string name, TypeRef ty):
- m_attrs( mv$(attrs) ),
- m_is_public(is_pub),
- m_name( mv$(name) ),
- m_type( mv$(ty) )
- {
- }
-
- friend ::std::ostream& operator<<(::std::ostream& os, const StructItem& x) {
- return os << (x.m_is_public ? "pub " : "") << x.m_name << ": " << x.m_type;
- }
-
- StructItem clone() const;
-};
-
-struct TupleItem
-{
- ::AST::MetaItems m_attrs;
- bool m_is_public;
- TypeRef m_type;
-
- //TupleItem() {}
-
- TupleItem(::AST::MetaItems attrs, bool is_pub, TypeRef ty):
- m_attrs( mv$(attrs) ),
- m_is_public(is_pub),
- m_type( mv$(ty) )
- {
- }
-
- friend ::std::ostream& operator<<(::std::ostream& os, const TupleItem& x) {
- return os << (x.m_is_public ? "pub " : "") << x.m_type;
- }
-
- TupleItem clone() const;
-};
-
-class TypeAlias
-{
- GenericParams m_params;
- TypeRef m_type;
-public:
- //TypeAlias() {}
- TypeAlias(GenericParams params, TypeRef type):
- m_params( move(params) ),
- m_type( move(type) )
- {}
-
- const GenericParams& params() const { return m_params; }
- const TypeRef& type() const { return m_type; }
-
- GenericParams& params() { return m_params; }
- TypeRef& type() { return m_type; }
-
- TypeAlias clone() const;
-};
-
-class Static
-{
-public:
- enum Class
- {
- CONST,
- STATIC,
- MUT,
- };
-private:
- Class m_class;
- TypeRef m_type;
- Expr m_value;
-public:
- //Static():
- // m_class(CONST)
- //{}
- Static(Class s_class, TypeRef type, Expr value):
- m_class(s_class),
- m_type( move(type) ),
- m_value( move(value) )
- {}
-
- const Class& s_class() const { return m_class; }
- const TypeRef& type() const { return m_type; }
- const Expr& value() const { return m_value; }
-
- TypeRef& type() { return m_type; }
- Expr& value() { return m_value; }
-
- Static clone() const;
-};
-
-class Function
-{
-public:
- typedef ::std::vector< ::std::pair<AST::Pattern,TypeRef> > Arglist;
-
-private:
- Span m_span;
- //::std::string m_lifetime;
- GenericParams m_params;
- Expr m_code;
- TypeRef m_rettype;
- Arglist m_args;
-
- // TODO: ABI, const, and unsafe
- ::std::string m_abi;
- bool m_is_const;
- bool m_is_unsafe;
- bool m_is_variadic; // extern only
-public:
- Function(const Function&) = delete;
- Function& operator=(const Function&) = delete;
- Function(Function&&) = default;
- Function& operator=(Function&&) = default;
-
- //Function() {}
- Function(Span sp, GenericParams params, ::std::string abi, bool is_unsafe, bool is_const, bool is_variadic, TypeRef ret_type, Arglist args);
-
- void set_code(Expr code) { m_code = ::std::move(code); }
-
- const ::std::string& abi() const { return m_abi; };
- bool is_const() const { return m_is_const; }
- bool is_unsafe() const { return m_is_unsafe; }
- bool is_variadic() const { return m_is_variadic; }
-
- const GenericParams& params() const { return m_params; }
- GenericParams& params() { return m_params; }
- const Expr& code() const { return m_code; }
- Expr& code() { return m_code; }
- const TypeRef& rettype() const { return m_rettype; }
- TypeRef& rettype() { return m_rettype; }
- const Arglist& args() const { return m_args; }
- Arglist& args() { return m_args; }
-
- Function clone() const;
-};
-
-class Trait
-{
- GenericParams m_params;
- ::std::vector< Spanned<AST::Path> > m_supertraits;
-
- bool m_is_marker;
- NamedList<Item> m_items;
-public:
- Trait():
- m_is_marker(false)
- {}
- Trait(GenericParams params, ::std::vector< Spanned<Path> > supertraits):
- m_params( mv$(params) ),
- m_supertraits( mv$(supertraits) ),
- m_is_marker(false)
- {
- }
-
- const GenericParams& params() const { return m_params; }
- GenericParams& params() { return m_params; }
- const ::std::vector<Spanned<Path> >& supertraits() const { return m_supertraits; }
- ::std::vector<Spanned<Path> >& supertraits() { return m_supertraits; }
-
- const NamedList<Item>& items() const { return m_items; }
- NamedList<Item>& items() { return m_items; }
-
- void add_type(::std::string name, TypeRef type);
- void add_function(::std::string name, Function fcn);
- void add_static(::std::string name, Static v);
-
- void set_is_marker();
- bool is_marker() const;
-
- bool has_named_item(const ::std::string& name, bool& out_is_fcn) const;
-
- Trait clone() const;
-};
-
-TAGGED_UNION_EX(EnumVariantData, (), Value,
- (
- (Value, struct {
- ::AST::Expr m_value;
- }),
- (Tuple, struct {
- ::std::vector<TypeRef> m_sub_types;
- }),
- (Struct, struct {
- ::std::vector<StructItem> m_fields;
- })
- ),
- (), (),
- (
- public:
- )
- );
-
-struct EnumVariant
-{
- MetaItems m_attrs;
- ::std::string m_name;
- EnumVariantData m_data;
-
- EnumVariant()
- {
- }
-
- EnumVariant(MetaItems attrs, ::std::string name, Expr&& value):
- m_attrs( mv$(attrs) ),
- m_name( mv$(name) ),
- m_data( EnumVariantData::make_Value({mv$(value)}) )
- {
- }
-
- EnumVariant(MetaItems attrs, ::std::string name, ::std::vector<TypeRef> sub_types):
- m_attrs( mv$(attrs) ),
- m_name( ::std::move(name) ),
- m_data( EnumVariantData::make_Tuple( {mv$(sub_types)} ) )
- {
- }
-
- EnumVariant(MetaItems attrs, ::std::string name, ::std::vector<StructItem> fields):
- m_attrs( mv$(attrs) ),
- m_name( ::std::move(name) ),
- m_data( EnumVariantData::make_Struct( {mv$(fields)} ) )
- {
- }
-
- friend ::std::ostream& operator<<(::std::ostream& os, const EnumVariant& x)
- {
- os << "EnumVariant(" << x.m_name;
- TU_MATCH(EnumVariantData, (x.m_data), (e),
- (Value,
- os << " = " << e.m_value;
- ),
- (Tuple,
- os << "(" << e.m_sub_types << ")";
- ),
- (Struct,
- os << " { " << e.m_fields << " }";
- )
- )
- return os << ")";
- }
-};
-
-class Enum
-{
- GenericParams m_params;
- ::std::vector<EnumVariant> m_variants;
-public:
- Enum() {}
- Enum( GenericParams params, ::std::vector<EnumVariant> variants ):
- m_params( move(params) ),
- m_variants( move(variants) )
- {}
-
- const GenericParams& params() const { return m_params; }
- GenericParams& params() { return m_params; }
- const ::std::vector<EnumVariant>& variants() const { return m_variants; }
- ::std::vector<EnumVariant>& variants() { return m_variants; }
-
- Enum clone() const;
-};
-
-TAGGED_UNION_EX(StructData, (), Struct,
- (
- (Tuple, struct {
- ::std::vector<TupleItem> ents;
- }),
- (Struct, struct {
- ::std::vector<StructItem> ents;
- })
- ),
- (),(),
- (
- public:
- )
- );
-
-class Struct
-{
- GenericParams m_params;
-public:
- StructData m_data;
-
- Struct() {}
- Struct( GenericParams params, ::std::vector<StructItem> fields ):
- m_params( move(params) ),
- m_data( StructData::make_Struct({mv$(fields)}) )
- {}
- Struct( GenericParams params, ::std::vector<TupleItem> fields ):
- m_params( move(params) ),
- m_data( StructData::make_Tuple({mv$(fields)}) )
- {}
-
- const GenericParams& params() const { return m_params; }
- GenericParams& params() { return m_params; }
-
- Struct clone() const;
-};
-
-class Union
-{
-public:
- GenericParams m_params;
- ::std::vector<StructItem> m_variants;
-
- Union( GenericParams params, ::std::vector<StructItem> fields ):
- m_params( move(params) ),
- m_variants( mv$(fields) )
- {}
-
- Union clone() const;
-};
-
-class ImplDef
-{
- Span m_span;
- MetaItems m_attrs;
- GenericParams m_params;
- Spanned<Path> m_trait;
- TypeRef m_type;
-public:
- //ImplDef() {}
- ImplDef(ImplDef&&) /*noexcept*/ = default;
- ImplDef(Span sp, MetaItems attrs, GenericParams params, Spanned<Path> trait_type, TypeRef impl_type):
- m_span( mv$(sp) ),
- m_attrs( mv$(attrs) ),
- m_params( mv$(params) ),
- m_trait( mv$(trait_type) ),
- m_type( mv$(impl_type) )
- {}
- ImplDef& operator=(ImplDef&&) = default;
-
- // Accessors
- const Span& span() const { return m_span; }
- const MetaItems& attrs() const { return m_attrs; }
- MetaItems& attrs() { return m_attrs; }
-
- const GenericParams& params() const { return m_params; }
- GenericParams& params() { return m_params; }
- const Spanned<Path>& trait() const { return m_trait; }
- Spanned<Path>& trait() { return m_trait; }
- const TypeRef& type() const { return m_type; }
- TypeRef& type() { return m_type; }
-
-
- friend ::std::ostream& operator<<(::std::ostream& os, const ImplDef& impl);
-};
-
-class Impl
-{
-public:
- struct ImplItem {
- bool is_pub; // Ignored for trait impls
- bool is_specialisable;
- ::std::string name;
-
- ::std::unique_ptr<Item> data;
- };
-
-private:
- ImplDef m_def;
- Span m_span;
-
- ::std::vector< ImplItem > m_items;
- //NamedList<TypeRef> m_types;
- //NamedList<Function> m_functions;
- //NamedList<Static> m_statics;
-
-public:
- //Impl() {}
- Impl(Impl&&) /*noexcept*/ = default;
- Impl(ImplDef def):
- m_def( mv$(def) )
- {}
- 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_macro_invocation( MacroInvocation inv );
-
- const ImplDef& def() const { return m_def; }
- ImplDef& def() { return m_def; }
- const ::std::vector<ImplItem>& items() const { return m_items; }
- ::std::vector<ImplItem>& items() { return m_items; }
-
- bool has_named_item(const ::std::string& name) const;
-
- friend ::std::ostream& operator<<(::std::ostream& os, const Impl& impl);
-
-private:
-};
-
-struct UseStmt
-{
- Span sp;
- ::AST::Path path;
- ::AST::PathBinding alt_binding;
-
- UseStmt()
- {}
- UseStmt(Span sp, Path p):
- sp(sp),
- path(p)
- {
- }
-
- UseStmt clone() const;
-
- friend ::std::ostream& operator<<(::std::ostream& os, const UseStmt& x);
-};
-
-class ExternBlock
-{
- ::std::string m_abi;
- ::std::vector< Named<Item>> m_items;
-public:
- ExternBlock(::std::string abi):
- m_abi( mv$(abi) )
- {}
-
- const ::std::string& abi() const { return m_abi; }
-
- void add_item(Named<Item> named_item);
-
- // NOTE: Only Function and Static are valid.
- ::std::vector<Named<Item>>& items() { return m_items; }
- const ::std::vector<Named<Item>>& items() const { return m_items; }
-
- ExternBlock clone() const;
-};
-
-/// Representation of a parsed (and being converted) function
-class Module
-{
- ::AST::Path m_my_path;
-
- // Module-level items
- /// General items
- ::std::vector<Named<Item>> m_items;
-
- // --- Runtime caches and state ---
- ::std::vector< ::std::shared_ptr<Module> > m_anon_modules;
-
- ::std::vector< NamedNS<const MacroRules*> > m_macro_import_res; // Vec of imported macros (not serialised)
- ::std::vector< Named<MacroRulesPtr> > m_macros;
-
-public:
- struct FileInfo
- {
- bool controls_dir = false;
- ::std::string path = "!";
- };
-
- FileInfo m_file_info;
-
- bool m_insert_prelude = true; // Set to false by `#[no_prelude]` handler
- char m_index_populated = 0; // 0 = no, 1 = partial, 2 = complete
- struct IndexEnt {
- bool is_pub; // Used as part of glob import checking
- bool is_import; // Set if this item has a path that isn't `mod->path() + name`
- ::AST::Path path;
- };
-
- // 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;
-
-public:
- Module() {}
- Module(::AST::Path path):
- m_my_path( mv$(path) )
- {
- }
-
- bool is_anon() const {
- return m_my_path.nodes().size() > 0 && m_my_path.nodes().back().name()[0] == '#';
- }
-
- /// Create an anon module (for use inside expressions)
- ::std::shared_ptr<AST::Module> add_anon();
-
- void add_item(Named<Item> item);
- void add_item(bool is_pub, ::std::string name, Item it, MetaItems attrs);
- void add_ext_crate(bool is_public, ::std::string ext_name, ::std::string imp_name, MetaItems attrs);
- void add_alias(bool is_public, UseStmt path, ::std::string name, MetaItems 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);
-
-
-
- const ::AST::Path& path() const { return m_my_path; }
-
- ::std::vector<Named<Item>>& items() { return m_items; }
- const ::std::vector<Named<Item>>& items() const { return m_items; }
-
- ::std::vector< ::std::shared_ptr<Module> >& anon_mods() { return m_anon_modules; }
- const ::std::vector< ::std::shared_ptr<Module> >& anon_mods() const { return m_anon_modules; }
-
-
- NamedList<MacroRulesPtr>& macros() { return m_macros; }
- const NamedList<MacroRulesPtr>& macros() const { return m_macros; }
- const ::std::vector<NamedNS<const MacroRules*> > 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,
- (
- (None, struct {} ),
- (MacroInv, MacroInvocation),
- (Use, UseStmt),
-
- // Nameless items
- (ExternBlock, ExternBlock),
- (Impl, Impl),
- (NegImpl, ImplDef),
-
- (Module, Module),
- (Crate, struct {
- ::std::string name;
- }),
-
- (Type, TypeAlias),
- (Struct, Struct),
- (Enum, Enum),
- (Union, Union),
- (Trait, Trait),
-
- (Function, Function),
- (Static, Static)
- ),
-
- (, attrs(mv$(x.attrs))), (attrs = mv$(x.attrs);),
- (
- public:
- MetaItems attrs;
- Span span;
-
- Item clone() const;
- )
- );
-
-
-struct ImplRef
-{
- const Impl& impl;
- ::std::vector<TypeRef> params;
-
- ImplRef(const Impl& impl, ::std::vector<TypeRef> params):
- impl(impl),
- params( mv$(params) )
- {}
-
- ::rust::option<char> find_named_item(const ::std::string& name) const;
-};
-
-} // namespace AST
-
-class GenericResolveClosure
-{
- const ::AST::GenericParams& m_params;
- const ::std::vector<TypeRef>& m_args;
-public:
- GenericResolveClosure(const AST::GenericParams& params, const ::std::vector<TypeRef>& args):
- m_params(params),
- m_args(args)
- {}
- const TypeRef& operator()(const char *argname) {
- for(unsigned int i = 0; i < m_params.ty_params().size(); i ++)
- {
- if( m_params.ty_params()[i].name() == argname ) {
- return m_args.at(i);
- }
- }
- throw ::std::runtime_error("BUGCHECK - Unknown arg in field type");
- }
-};
-
-
-#endif // AST_HPP_INCLUDED
+/* + * MRustC - Rust Compiler + * - By John Hodge (Mutabah/thePowersGang) + * + * ast/ast.hpp + * - Core AST header + */ +#ifndef AST_HPP_INCLUDED +#define AST_HPP_INCLUDED + +#include <string> +#include <vector> +#include <stdexcept> +#include "../coretypes.hpp" +#include <memory> +#include <map> +#include <unordered_map> +#include <algorithm> + +#include "../parse/tokentree.hpp" +#include "types.hpp" +#include <serialise.hpp> + +#include <ast/pattern.hpp> +#include <ast/attrs.hpp> +#include <ast/expr_ptr.hpp> +#include <ast/item.hpp> +#include <ast/macro.hpp> // MacroInvocation + +#include "generics.hpp" + +#include <macro_rules/macro_rules_ptr.hpp> + +namespace AST { + +class Crate; + +class Module; +class Item; + +using ::std::unique_ptr; +using ::std::move; + +enum eItemType +{ + ITEM_TRAIT, + ITEM_STRUCT, + ITEM_FN, +}; + +struct StructItem +{ + ::AST::MetaItems m_attrs; + bool m_is_public; + ::std::string m_name; + TypeRef m_type; + + //StructItem() {} + + StructItem(::AST::MetaItems attrs, bool is_pub, ::std::string name, TypeRef ty): + m_attrs( mv$(attrs) ), + m_is_public(is_pub), + m_name( mv$(name) ), + m_type( mv$(ty) ) + { + } + + friend ::std::ostream& operator<<(::std::ostream& os, const StructItem& x) { + return os << (x.m_is_public ? "pub " : "") << x.m_name << ": " << x.m_type; + } + + StructItem clone() const; +}; + +struct TupleItem +{ + ::AST::MetaItems m_attrs; + bool m_is_public; + TypeRef m_type; + + //TupleItem() {} + + TupleItem(::AST::MetaItems attrs, bool is_pub, TypeRef ty): + m_attrs( mv$(attrs) ), + m_is_public(is_pub), + m_type( mv$(ty) ) + { + } + + friend ::std::ostream& operator<<(::std::ostream& os, const TupleItem& x) { + return os << (x.m_is_public ? "pub " : "") << x.m_type; + } + + TupleItem clone() const; +}; + +class TypeAlias +{ + GenericParams m_params; + TypeRef m_type; +public: + //TypeAlias() {} + TypeAlias(GenericParams params, TypeRef type): + m_params( move(params) ), + m_type( move(type) ) + {} + + const GenericParams& params() const { return m_params; } + const TypeRef& type() const { return m_type; } + + GenericParams& params() { return m_params; } + TypeRef& type() { return m_type; } + + TypeAlias clone() const; +}; + +class Static +{ +public: + enum Class + { + CONST, + STATIC, + MUT, + }; +private: + Class m_class; + TypeRef m_type; + Expr m_value; +public: + //Static(): + // m_class(CONST) + //{} + Static(Class s_class, TypeRef type, Expr value): + m_class(s_class), + m_type( move(type) ), + m_value( move(value) ) + {} + + const Class& s_class() const { return m_class; } + const TypeRef& type() const { return m_type; } + const Expr& value() const { return m_value; } + + TypeRef& type() { return m_type; } + Expr& value() { return m_value; } + + Static clone() const; +}; + +class Function +{ +public: + typedef ::std::vector< ::std::pair<AST::Pattern,TypeRef> > Arglist; + +private: + Span m_span; + //::std::string m_lifetime; + GenericParams m_params; + Expr m_code; + TypeRef m_rettype; + Arglist m_args; + + // TODO: ABI, const, and unsafe + ::std::string m_abi; + bool m_is_const; + bool m_is_unsafe; + bool m_is_variadic; // extern only +public: + Function(const Function&) = delete; + Function& operator=(const Function&) = delete; + Function(Function&&) = default; + Function& operator=(Function&&) = default; + + //Function() {} + Function(Span sp, GenericParams params, ::std::string abi, bool is_unsafe, bool is_const, bool is_variadic, TypeRef ret_type, Arglist args); + + void set_code(Expr code) { m_code = ::std::move(code); } + + const ::std::string& abi() const { return m_abi; }; + bool is_const() const { return m_is_const; } + bool is_unsafe() const { return m_is_unsafe; } + bool is_variadic() const { return m_is_variadic; } + + const GenericParams& params() const { return m_params; } + GenericParams& params() { return m_params; } + const Expr& code() const { return m_code; } + Expr& code() { return m_code; } + const TypeRef& rettype() const { return m_rettype; } + TypeRef& rettype() { return m_rettype; } + const Arglist& args() const { return m_args; } + Arglist& args() { return m_args; } + + Function clone() const; +}; + +class Trait +{ + GenericParams m_params; + ::std::vector< Spanned<AST::Path> > m_supertraits; + + bool m_is_marker; + NamedList<Item> m_items; +public: + Trait(): + m_is_marker(false) + {} + Trait(GenericParams params, ::std::vector< Spanned<Path> > supertraits): + m_params( mv$(params) ), + m_supertraits( mv$(supertraits) ), + m_is_marker(false) + { + } + + const GenericParams& params() const { return m_params; } + GenericParams& params() { return m_params; } + const ::std::vector<Spanned<Path> >& supertraits() const { return m_supertraits; } + ::std::vector<Spanned<Path> >& supertraits() { return m_supertraits; } + + const NamedList<Item>& items() const { return m_items; } + NamedList<Item>& items() { return m_items; } + + void add_type(::std::string name, TypeRef type); + void add_function(::std::string name, Function fcn); + void add_static(::std::string name, Static v); + + void set_is_marker(); + bool is_marker() const; + + bool has_named_item(const ::std::string& name, bool& out_is_fcn) const; + + Trait clone() const; +}; + +TAGGED_UNION_EX(EnumVariantData, (), Value, + ( + (Value, struct { + ::AST::Expr m_value; + }), + (Tuple, struct { + ::std::vector<TypeRef> m_sub_types; + }), + (Struct, struct { + ::std::vector<StructItem> m_fields; + }) + ), + (), (), + ( + public: + ) + ); + +struct EnumVariant +{ + MetaItems m_attrs; + ::std::string m_name; + EnumVariantData m_data; + + EnumVariant() + { + } + + EnumVariant(MetaItems attrs, ::std::string name, Expr&& value): + m_attrs( mv$(attrs) ), + m_name( mv$(name) ), + m_data( EnumVariantData::make_Value({mv$(value)}) ) + { + } + + EnumVariant(MetaItems attrs, ::std::string name, ::std::vector<TypeRef> sub_types): + m_attrs( mv$(attrs) ), + m_name( ::std::move(name) ), + m_data( EnumVariantData::make_Tuple( {mv$(sub_types)} ) ) + { + } + + EnumVariant(MetaItems attrs, ::std::string name, ::std::vector<StructItem> fields): + m_attrs( mv$(attrs) ), + m_name( ::std::move(name) ), + m_data( EnumVariantData::make_Struct( {mv$(fields)} ) ) + { + } + + friend ::std::ostream& operator<<(::std::ostream& os, const EnumVariant& x) + { + os << "EnumVariant(" << x.m_name; + TU_MATCH(EnumVariantData, (x.m_data), (e), + (Value, + os << " = " << e.m_value; + ), + (Tuple, + os << "(" << e.m_sub_types << ")"; + ), + (Struct, + os << " { " << e.m_fields << " }"; + ) + ) + return os << ")"; + } +}; + +class Enum +{ + GenericParams m_params; + ::std::vector<EnumVariant> m_variants; +public: + Enum() {} + Enum( GenericParams params, ::std::vector<EnumVariant> variants ): + m_params( move(params) ), + m_variants( move(variants) ) + {} + + const GenericParams& params() const { return m_params; } + GenericParams& params() { return m_params; } + const ::std::vector<EnumVariant>& variants() const { return m_variants; } + ::std::vector<EnumVariant>& variants() { return m_variants; } + + Enum clone() const; +}; + +TAGGED_UNION_EX(StructData, (), Struct, + ( + (Tuple, struct { + ::std::vector<TupleItem> ents; + }), + (Struct, struct { + ::std::vector<StructItem> ents; + }) + ), + (),(), + ( + public: + ) + ); + +class Struct +{ + GenericParams m_params; +public: + StructData m_data; + + Struct() {} + Struct( GenericParams params, ::std::vector<StructItem> fields ): + m_params( move(params) ), + m_data( StructData::make_Struct({mv$(fields)}) ) + {} + Struct( GenericParams params, ::std::vector<TupleItem> fields ): + m_params( move(params) ), + m_data( StructData::make_Tuple({mv$(fields)}) ) + {} + + const GenericParams& params() const { return m_params; } + GenericParams& params() { return m_params; } + + Struct clone() const; +}; + +class Union +{ +public: + GenericParams m_params; + ::std::vector<StructItem> m_variants; + + Union( GenericParams params, ::std::vector<StructItem> fields ): + m_params( move(params) ), + m_variants( mv$(fields) ) + {} + + Union clone() const; +}; + +class ImplDef +{ + Span m_span; + MetaItems m_attrs; + GenericParams m_params; + Spanned<Path> m_trait; + TypeRef m_type; +public: + //ImplDef() {} + ImplDef(ImplDef&&) /*noexcept*/ = default; + ImplDef(Span sp, MetaItems attrs, GenericParams params, Spanned<Path> trait_type, TypeRef impl_type): + m_span( mv$(sp) ), + m_attrs( mv$(attrs) ), + m_params( mv$(params) ), + m_trait( mv$(trait_type) ), + m_type( mv$(impl_type) ) + {} + ImplDef& operator=(ImplDef&&) = default; + + // Accessors + const Span& span() const { return m_span; } + const MetaItems& attrs() const { return m_attrs; } + MetaItems& attrs() { return m_attrs; } + + const GenericParams& params() const { return m_params; } + GenericParams& params() { return m_params; } + const Spanned<Path>& trait() const { return m_trait; } + Spanned<Path>& trait() { return m_trait; } + const TypeRef& type() const { return m_type; } + TypeRef& type() { return m_type; } + + + friend ::std::ostream& operator<<(::std::ostream& os, const ImplDef& impl); +}; + +class Impl +{ +public: + struct ImplItem { + bool is_pub; // Ignored for trait impls + bool is_specialisable; + ::std::string name; + + ::std::unique_ptr<Item> data; + }; + +private: + ImplDef m_def; + Span m_span; + + ::std::vector< ImplItem > m_items; + //NamedList<TypeRef> m_types; + //NamedList<Function> m_functions; + //NamedList<Static> m_statics; + +public: + //Impl() {} + Impl(Impl&&) /*noexcept*/ = default; + Impl(ImplDef def): + m_def( mv$(def) ) + {} + 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_macro_invocation( MacroInvocation inv ); + + const ImplDef& def() const { return m_def; } + ImplDef& def() { return m_def; } + const ::std::vector<ImplItem>& items() const { return m_items; } + ::std::vector<ImplItem>& items() { return m_items; } + + bool has_named_item(const ::std::string& name) const; + + friend ::std::ostream& operator<<(::std::ostream& os, const Impl& impl); + +private: +}; + +struct UseStmt +{ + Span sp; + ::AST::Path path; + ::AST::PathBinding alt_binding; + + UseStmt() + {} + UseStmt(Span sp, Path p): + sp(sp), + path(p) + { + } + + UseStmt clone() const; + + friend ::std::ostream& operator<<(::std::ostream& os, const UseStmt& x); +}; + +class ExternBlock +{ + ::std::string m_abi; + ::std::vector< Named<Item>> m_items; +public: + ExternBlock(::std::string abi): + m_abi( mv$(abi) ) + {} + + const ::std::string& abi() const { return m_abi; } + + void add_item(Named<Item> named_item); + + // NOTE: Only Function and Static are valid. + ::std::vector<Named<Item>>& items() { return m_items; } + const ::std::vector<Named<Item>>& items() const { return m_items; } + + ExternBlock clone() const; +}; + +/// Representation of a parsed (and being converted) function +class Module +{ + ::AST::Path m_my_path; + + // Module-level items + /// General items + ::std::vector<Named<Item>> m_items; + + // --- Runtime caches and state --- + ::std::vector< ::std::shared_ptr<Module> > m_anon_modules; + + ::std::vector< NamedNS<const MacroRules*> > m_macro_import_res; // Vec of imported macros (not serialised) + ::std::vector< Named<MacroRulesPtr> > m_macros; + +public: + struct FileInfo + { + bool controls_dir = false; + ::std::string path = "!"; + }; + + FileInfo m_file_info; + + bool m_insert_prelude = true; // Set to false by `#[no_prelude]` handler + char m_index_populated = 0; // 0 = no, 1 = partial, 2 = complete + struct IndexEnt { + bool is_pub; // Used as part of glob import checking + bool is_import; // Set if this item has a path that isn't `mod->path() + name` + ::AST::Path path; + }; + + // 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; + +public: + Module() {} + Module(::AST::Path path): + m_my_path( mv$(path) ) + { + } + + bool is_anon() const { + return m_my_path.nodes().size() > 0 && m_my_path.nodes().back().name()[0] == '#'; + } + + /// Create an anon module (for use inside expressions) + ::std::shared_ptr<AST::Module> add_anon(); + + void add_item(Named<Item> item); + void add_item(bool is_pub, ::std::string name, Item it, MetaItems attrs); + void add_ext_crate(bool is_public, ::std::string ext_name, ::std::string imp_name, MetaItems attrs); + void add_alias(bool is_public, UseStmt path, ::std::string name, MetaItems 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); + + + + const ::AST::Path& path() const { return m_my_path; } + + ::std::vector<Named<Item>>& items() { return m_items; } + const ::std::vector<Named<Item>>& items() const { return m_items; } + + ::std::vector< ::std::shared_ptr<Module> >& anon_mods() { return m_anon_modules; } + const ::std::vector< ::std::shared_ptr<Module> >& anon_mods() const { return m_anon_modules; } + + + NamedList<MacroRulesPtr>& macros() { return m_macros; } + const NamedList<MacroRulesPtr>& macros() const { return m_macros; } + const ::std::vector<NamedNS<const MacroRules*> > 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, + ( + (None, struct {} ), + (MacroInv, MacroInvocation), + (Use, UseStmt), + + // Nameless items + (ExternBlock, ExternBlock), + (Impl, Impl), + (NegImpl, ImplDef), + + (Module, Module), + (Crate, struct { + ::std::string name; + }), + + (Type, TypeAlias), + (Struct, Struct), + (Enum, Enum), + (Union, Union), + (Trait, Trait), + + (Function, Function), + (Static, Static) + ), + + (, attrs(mv$(x.attrs))), (attrs = mv$(x.attrs);), + ( + public: + MetaItems attrs; + Span span; + + Item clone() const; + ) + ); + + +struct ImplRef +{ + const Impl& impl; + ::std::vector<TypeRef> params; + + ImplRef(const Impl& impl, ::std::vector<TypeRef> params): + impl(impl), + params( mv$(params) ) + {} + + ::rust::option<char> find_named_item(const ::std::string& name) const; +}; + +} // namespace AST + +class GenericResolveClosure +{ + const ::AST::GenericParams& m_params; + const ::std::vector<TypeRef>& m_args; +public: + GenericResolveClosure(const AST::GenericParams& params, const ::std::vector<TypeRef>& args): + m_params(params), + m_args(args) + {} + const TypeRef& operator()(const char *argname) { + for(unsigned int i = 0; i < m_params.ty_params().size(); i ++) + { + if( m_params.ty_params()[i].name() == argname ) { + return m_args.at(i); + } + } + throw ::std::runtime_error("BUGCHECK - Unknown arg in field type"); + } +}; + + +#endif // AST_HPP_INCLUDED diff --git a/src/ast/attrs.hpp b/src/ast/attrs.hpp index 372d888a..28bfec96 100644 --- a/src/ast/attrs.hpp +++ b/src/ast/attrs.hpp @@ -12,7 +12,7 @@ class MetaItems public: Span m_span; ::std::vector<MetaItem> m_items; - + virtual ~MetaItems(); MetaItems() {} MetaItems(MetaItems&&) = default; @@ -23,17 +23,17 @@ public: m_items( mv$(items) ) { } - + void push_back(MetaItem i); - + MetaItems clone() const; - + MetaItem* get(const char *name) { return const_cast<MetaItem*>( const_cast<const MetaItems*>(this)->get(name)); } const MetaItem* get(const char *name) const; bool has(const char *name) const { return get(name) != 0; } - + friend ::std::ostream& operator<<(::std::ostream& os, const MetaItems& x) { return os << "[" << x.m_items << "]"; } @@ -74,21 +74,21 @@ public: m_data( MetaItemData::make_List({mv$(items)}) ) { } - + MetaItem clone() const; - + void mark_used() {} const ::std::string& name() const { return m_name; } - + bool has_noarg() const { return m_data.is_None(); } - + bool has_string() const { return m_data.is_String(); } const ::std::string& string() const { return m_data.as_String().val; } - + bool has_sub_items() const { return m_data.is_List(); } const ::std::vector<MetaItem>& items() const { return m_data.as_List().sub_items; } ::std::vector<MetaItem>& items() { return m_data.as_List().sub_items; } - + friend ::std::ostream& operator<<(::std::ostream& os, const MetaItem& x) { os << x.m_name; TU_MATCH(MetaItemData, (x.m_data), (e), diff --git a/src/ast/crate.cpp b/src/ast/crate.cpp index b18ca662..58a08980 100644 --- a/src/ast/crate.cpp +++ b/src/ast/crate.cpp @@ -61,13 +61,13 @@ void Crate::load_externs() } }; iterate_module(m_root_module, cb); - + // Check for no_std or no_core, and load libstd/libcore // - Duplicates some of the logic in "Expand", but also helps keep crate loading separate to most of expand // NOTE: Not all crates are loaded here, any crates loaded by macro invocations will be done during expand. bool no_std = false; bool no_core = false; - + for( const auto& a : this->m_attrs.m_items ) { if( a.name() == "no_std" ) @@ -105,7 +105,7 @@ void Crate::load_extern_crate(Span sp, const ::std::string& name) ::std::string path; for(const auto& p : paths){ path = p + "lib" + name + ".hir"; - + if( ::std::ifstream(path).good() ) { break ; } @@ -113,10 +113,10 @@ void Crate::load_extern_crate(Span sp, const ::std::string& name) if( !::std::ifstream(path).good() ) { ERROR(sp, E0000, "Unable to locate crate '" << name << "'"); } - + auto res = m_extern_crates.insert(::std::make_pair( name, ExternCrate { name, path } )); auto crate_ext_list = mv$( res.first->second.m_hir->m_ext_crates ); - + // Load referenced crates for( const auto& ext : crate_ext_list ) { @@ -132,7 +132,7 @@ ExternCrate::ExternCrate(const ::std::string& name, const ::std::string& path): { TRACE_FUNCTION_F("name=" << name << ", path='" << path << "'"); m_hir = HIR_Deserialise(path, name); - + m_hir->post_load_update(name); } diff --git a/src/ast/crate.hpp b/src/ast/crate.hpp index 31076c02..c51dacf5 100644 --- a/src/ast/crate.hpp +++ b/src/ast/crate.hpp @@ -14,14 +14,14 @@ class Crate { public: ::AST::MetaItems m_attrs; - + ::std::map< ::std::string, ::AST::Path> m_lang_items; public: Module m_root_module; ::std::map< ::std::string, ExternCrate> m_extern_crates; // Mapping filled by searching for (?visible) macros with is_pub=true ::std::map< ::std::string, const MacroRules*> m_exported_macros; - + enum class Type { Unknown, RustLib, @@ -37,15 +37,15 @@ public: ::std::string m_crate_name; AST::Path m_prelude_path; - + Crate(); const Module& root_module() const { return m_root_module; } Module& root_module() { return m_root_module; } - + /// Load referenced crates void load_externs(); - + void load_extern_crate(Span sp, const ::std::string& name); }; @@ -55,14 +55,14 @@ class ExternCrate public: ::std::string m_name; ::HIR::CratePtr m_hir; - + ExternCrate(const ::std::string& 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<void(const ::std::string& , const MacroRules&)> cb) const; const MacroRules* find_macro_rules(const ::std::string& name) const; }; diff --git a/src/ast/dump.cpp b/src/ast/dump.cpp index 4773a845..07343de4 100644 --- a/src/ast/dump.cpp +++ b/src/ast/dump.cpp @@ -1,7 +1,7 @@ /* * MRustC - Mutabah's Rust Compiler * - By John Hodge (Mutabah/thePowersGang) - * + * * ast/dump.cpp * - Dumps the AST of a crate as rust code (annotated) */ @@ -30,7 +30,7 @@ public: m_indent_level(0), m_expr_root(false) {} - + void handle_module(const AST::Module& mod); void handle_struct(const AST::Struct& s); void handle_enum(const AST::Enum& s); @@ -170,7 +170,7 @@ public: virtual void visit(AST::ExprNode_Loop& n) override { bool expr_root = m_expr_root; m_expr_root = false; - + switch(n.m_type) { case AST::ExprNode_Loop::LOOP: @@ -193,7 +193,7 @@ public: AST::NodeVisitor::visit(n.m_cond); break; } - + if( expr_root ) { m_os << "\n"; @@ -211,7 +211,7 @@ public: m_expr_root = false; m_os << "match "; AST::NodeVisitor::visit(n.m_val); - + if(expr_root) { m_os << "\n"; @@ -222,7 +222,7 @@ public: m_os << " {\n"; inc_indent(); } - + for( auto& arm : n.m_arms ) { m_os << indent(); @@ -245,7 +245,7 @@ public: dec_indent(); m_os << ",\n"; } - + if(expr_root) { m_os << indent() << "}"; @@ -261,7 +261,7 @@ public: m_expr_root = false; m_os << "if "; AST::NodeVisitor::visit(n.m_cond); - + visit_if_common(expr_root, n.m_true, n.m_false); } virtual void visit(AST::ExprNode_IfLet& n) override { @@ -271,7 +271,7 @@ public: print_pattern(n.m_pattern, true); m_os << " = "; AST::NodeVisitor::visit(n.m_value); - + visit_if_common(expr_root, n.m_true, n.m_false); } void visit_if_common(bool expr_root, const ::std::unique_ptr<AST::ExprNode>& tv, const ::std::unique_ptr<AST::ExprNode>& fv) @@ -392,7 +392,7 @@ public: m_expr_root = false; m_os << "b\"" << n.m_value << "\""; } - + virtual void visit(AST::ExprNode_StructLiteral& n) override { m_expr_root = false; m_os << n.m_path << " {\n"; @@ -533,7 +533,7 @@ public: case AST::ExprNode_UniOp::REFMUT: m_os << "&mut "; break; case AST::ExprNode_UniOp::QMARK: break; } - + if( IS(*n.m_value, AST::ExprNode_BinOp) ) m_os << "("; AST::NodeVisitor::visit(n.m_value); @@ -553,14 +553,14 @@ private: AST::NodeVisitor::visit(node); m_os << ")"; } - + void print_attrs(const AST::MetaItems& attrs); void print_params(const AST::GenericParams& params); void print_bounds(const AST::GenericParams& params); void print_pattern_tuple(const AST::Pattern::TuplePat& v, bool is_refutable); void print_pattern(const AST::Pattern& p, bool is_refutable); void print_type(const TypeRef& t); - + void inc_indent(); RepeatLitStr indent(); void dec_indent(); @@ -584,7 +584,7 @@ void RustPrinter::print_attrs(const AST::MetaItems& attrs) void RustPrinter::handle_module(const AST::Module& mod) { bool need_nl = true; - + for( const auto& i : mod.items() ) { if( !i.data.is_Use() ) continue ; @@ -608,12 +608,12 @@ void RustPrinter::handle_module(const AST::Module& mod) m_os << ";\n"; } need_nl = true; - + for( const auto& item : mod.items() ) { if( !item.data.is_Module() ) continue ; const auto& e = item.data.as_Module(); - + m_os << "\n"; m_os << indent() << (item.is_pub ? "pub " : "") << "mod " << item.name << "\n"; m_os << indent() << "{\n"; @@ -623,12 +623,12 @@ void RustPrinter::handle_module(const AST::Module& mod) m_os << indent() << "}\n"; m_os << "\n"; } - + for( const auto& item : mod.items() ) { if( !item.data.is_Type() ) continue ; const auto& e = item.data.as_Type(); - + if(need_nl) { m_os << "\n"; need_nl = false; @@ -641,45 +641,45 @@ void RustPrinter::handle_module(const AST::Module& mod) m_os << ";\n"; } need_nl = true; - + for( const auto& item : mod.items() ) { if( !item.data.is_Struct() ) continue ; const auto& e = item.data.as_Struct(); - + m_os << "\n"; print_attrs(item.data.attrs); m_os << indent() << (item.is_pub ? "pub " : "") << "struct " << item.name; handle_struct(e); } - + for( const auto& item : mod.items() ) { if( !item.data.is_Enum() ) continue ; const auto& e = item.data.as_Enum(); - + m_os << "\n"; print_attrs(item.data.attrs); m_os << indent() << (item.is_pub ? "pub " : "") << "enum " << item.name; handle_enum(e); } - + for( const auto& item : mod.items() ) { if( !item.data.is_Trait() ) continue ; const auto& e = item.data.as_Trait(); - + m_os << "\n"; print_attrs(item.data.attrs); m_os << indent() << (item.is_pub ? "pub " : "") << "trait " << item.name; handle_trait(e); } - + for( const auto& item : mod.items() ) { if( !item.data.is_Static() ) continue ; const auto& e = item.data.as_Static(); - + if(need_nl) { m_os << "\n"; need_nl = false; @@ -696,12 +696,12 @@ void RustPrinter::handle_module(const AST::Module& mod) e.value().visit_nodes(*this); m_os << ";\n"; } - + for( const auto& item : mod.items() ) { if( !item.data.is_Function() ) continue ; const auto& e = item.data.as_Function(); - + m_os << "\n"; print_attrs(item.data.attrs); handle_function(item.is_pub, item.name, e); @@ -711,7 +711,7 @@ void RustPrinter::handle_module(const AST::Module& mod) { if( !item.data.is_Impl() ) continue ; const auto& i = item.data.as_Impl(); - + m_os << "\n"; m_os << indent() << "impl"; print_params(i.def().params()); @@ -720,7 +720,7 @@ void RustPrinter::handle_module(const AST::Module& mod) m_os << " " << i.def().trait().ent << " for"; } m_os << " " << i.def().type() << "\n"; - + print_bounds(i.def().params()); m_os << indent() << "{\n"; inc_indent(); @@ -796,13 +796,13 @@ void RustPrinter::print_bounds(const AST::GenericParams& params) m_os << indent() << "where\n"; inc_indent(); bool is_first = true; - + for( const auto& b : params.bounds() ) { if( !is_first ) m_os << ",\n"; is_first = false; - + m_os << indent(); TU_MATCH(AST::GenericBound, (b), (ent), (Lifetime, @@ -829,7 +829,7 @@ void RustPrinter::print_bounds(const AST::GenericParams& params) ) } m_os << "\n"; - + dec_indent(); } } @@ -934,7 +934,7 @@ void RustPrinter::print_pattern(const AST::Pattern& p, bool is_refutable) m_os << v.leading; m_os << ", "; } - + if(v.extra_bind.is_valid()) { const auto& b = v.extra_bind; @@ -955,7 +955,7 @@ void RustPrinter::print_pattern(const AST::Pattern& p, bool is_refutable) } m_os << ".."; needs_comma = true; - + if(v.trailing.size()) { if( needs_comma ) { m_os << ", "; @@ -975,7 +975,7 @@ void RustPrinter::print_type(const TypeRef& t) void RustPrinter::handle_struct(const AST::Struct& s) { print_params(s.params()); - + TU_MATCH(AST::StructData, (s.m_data), (e), (Tuple, if( e.ents.size() == 0 ) @@ -997,7 +997,7 @@ void RustPrinter::handle_struct(const AST::Struct& s) (Struct, m_os << "\n"; print_bounds(s.params()); - + m_os << indent() << "{\n"; inc_indent(); for( const auto& i : e.ents ) @@ -1060,7 +1060,7 @@ void RustPrinter::handle_trait(const AST::Trait& s) m_os << indent() << "{\n"; inc_indent(); - + for( const auto& i : s.items() ) { TU_MATCH_DEF(AST::Item, (i.data), (e), @@ -1074,7 +1074,7 @@ void RustPrinter::handle_trait(const AST::Trait& s) ) ) } - + dec_indent(); m_os << indent() << "}\n"; m_os << "\n"; @@ -1107,12 +1107,12 @@ void RustPrinter::handle_function(bool is_pub, const ::std::string& name, const { m_os << " -> " << f.rettype().print_pretty(); } - + if( f.code().is_valid() ) { m_os << "\n"; print_bounds(f.params()); - + m_os << indent(); f.code().visit_nodes(*this); m_os << "\n"; diff --git a/src/ast/expr.cpp b/src/ast/expr.cpp index d3fa1989..cc6ca98f 100644 --- a/src/ast/expr.cpp +++ b/src/ast/expr.cpp @@ -5,7 +5,7 @@ namespace AST { - + Expr::Expr(unique_ptr<ExprNode> node): m_node(node.release()) { @@ -188,7 +188,7 @@ NODE(ExprNode_Match, { os << " " << pat; if( arm.m_cond ) os << " if " << *arm.m_cond; - + os << " => " << *arm.m_code << ","; } os << "}"; @@ -258,11 +258,11 @@ NODE(ExprNode_StructLiteral, { os << "/* todo: sl */"; },{ ExprNode_StructLiteral::t_values vals; - + for(const auto& v : m_values) { vals.push_back( ::std::make_pair(v.first, v.second->clone()) ); } - + return NEWNODE(ExprNode_StructLiteral, AST::Path(m_path), OPT_CLONE(m_base_value), mv$(vals) ); }) diff --git a/src/ast/expr.hpp b/src/ast/expr.hpp index e955a4a4..4c80bcb5 100644 --- a/src/ast/expr.hpp +++ b/src/ast/expr.hpp @@ -24,11 +24,11 @@ class ExprNode Position m_pos; public: virtual ~ExprNode() = 0; - + virtual void visit(NodeVisitor& nv) = 0; virtual void print(::std::ostream& os) const = 0; virtual ::std::unique_ptr<ExprNode> clone() const = 0; - + void set_pos(Position p) { m_pos = ::std::move(p); } const Position& get_pos() const { return m_pos; } Span span() const { return m_pos; } @@ -37,7 +37,7 @@ public: m_attrs = mv$(mi); } MetaItems& attrs() { return m_attrs; } - + static ::std::unique_ptr<ExprNode> from_deserialiser(Deserialiser& d); }; typedef ::std::unique_ptr<ExprNode> ExprNodeP; @@ -68,7 +68,7 @@ struct ExprNode_Block: m_nodes( move(nodes) ) { } - + NODE_METHODS(); }; @@ -78,13 +78,13 @@ struct ExprNode_Macro: ::std::string m_name; ::std::string m_ident; ::TokenTree m_tokens; - + ExprNode_Macro(::std::string name, ::std::string ident, ::TokenTree&& tokens): m_name(name), m_ident(ident), m_tokens( move(tokens) ) {} - + NODE_METHODS(); }; @@ -106,7 +106,7 @@ struct ExprNode_Flow: m_value( move(value) ) { } - + NODE_METHODS(); }; struct ExprNode_LetBinding: @@ -122,7 +122,7 @@ struct ExprNode_LetBinding: m_value( move(value) ) { } - + NODE_METHODS(); }; struct ExprNode_Assign: @@ -145,7 +145,7 @@ struct ExprNode_Assign: m_value( move(value) ) { } - + NODE_METHODS(); }; struct ExprNode_CallPath: @@ -159,7 +159,7 @@ struct ExprNode_CallPath: m_args( move(args) ) { } - + NODE_METHODS(); }; struct ExprNode_CallMethod: @@ -175,7 +175,7 @@ struct ExprNode_CallMethod: m_args( move(args) ) { } - + NODE_METHODS(); }; // Call an object (Fn/FnMut/FnOnce) @@ -234,7 +234,7 @@ struct ExprNode_Match_Arm MetaItems m_attrs; ::std::vector<Pattern> m_patterns; unique_ptr<ExprNode> m_cond; - + unique_ptr<ExprNode> m_code; @@ -246,7 +246,7 @@ struct ExprNode_Match_Arm m_code( mv$(code) ) {} }; - + struct ExprNode_Match: public ExprNode { @@ -305,7 +305,7 @@ struct ExprNode_Integer: m_value(value) { } - + NODE_METHODS(); }; // Literal float @@ -320,7 +320,7 @@ struct ExprNode_Float: m_value(value) { } - + NODE_METHODS(); }; // Literal boolean @@ -333,7 +333,7 @@ struct ExprNode_Bool: m_value(value) { } - + NODE_METHODS(); }; // Literal string @@ -341,11 +341,11 @@ struct ExprNode_String: public ExprNode { ::std::string m_value; - + ExprNode_String(::std::string value): m_value( ::std::move(value) ) {} - + NODE_METHODS(); }; // Literal byte string @@ -353,11 +353,11 @@ struct ExprNode_ByteString: public ExprNode { ::std::string m_value; - + ExprNode_ByteString(::std::string value): m_value( ::std::move(value) ) {} - + NODE_METHODS(); }; @@ -366,19 +366,19 @@ struct ExprNode_Closure: public ExprNode { typedef ::std::vector< ::std::pair<AST::Pattern, TypeRef> > args_t; - + args_t m_args; TypeRef m_return; unique_ptr<ExprNode> m_code; bool m_is_move; - + ExprNode_Closure(args_t args, TypeRef rv, unique_ptr<ExprNode> code, bool is_move): m_args( ::std::move(args) ), m_return( ::std::move(rv) ), m_code( ::std::move(code) ), m_is_move( is_move ) {} - + NODE_METHODS(); }; // Literal structure @@ -395,7 +395,7 @@ struct ExprNode_StructLiteral: m_base_value( move(base_value) ), m_values( move(values) ) {} - + NODE_METHODS(); }; // Array @@ -404,7 +404,7 @@ struct ExprNode_Array: { unique_ptr<ExprNode> m_size; // if non-NULL, it's a sized array ::std::vector< unique_ptr<ExprNode> > m_values; - + ExprNode_Array(::std::vector< unique_ptr<ExprNode> > vals): m_values( ::std::move(vals) ) {} @@ -413,7 +413,7 @@ struct ExprNode_Array: { m_values.push_back( ::std::move(val) ); } - + NODE_METHODS(); }; // Tuple @@ -421,11 +421,11 @@ struct ExprNode_Tuple: public ExprNode { ::std::vector< unique_ptr<ExprNode> > m_values; - + ExprNode_Tuple(::std::vector< unique_ptr<ExprNode> > vals): m_values( ::std::move(vals) ) {} - + NODE_METHODS(); }; // Variable / Constant @@ -459,12 +459,12 @@ struct ExprNode_Index: { ::std::unique_ptr<ExprNode> m_obj; ::std::unique_ptr<ExprNode> m_idx; - + ExprNode_Index(::std::unique_ptr<ExprNode> obj, ::std::unique_ptr<ExprNode> idx): m_obj( ::std::move(obj) ), m_idx( ::std::move(idx) ) {} - + NODE_METHODS(); }; @@ -473,12 +473,12 @@ struct ExprNode_Deref: public ExprNode { ::std::unique_ptr<ExprNode> m_value; - + ExprNode_Deref(::std::unique_ptr<ExprNode> value): m_value( ::std::move(value) ) { } - + NODE_METHODS(); }; @@ -523,7 +523,7 @@ struct ExprNode_BinOp: CMPLTE, CMPGT, CMPGTE, - + RANGE, RANGE_INC, BOOLAND, @@ -535,13 +535,13 @@ struct ExprNode_BinOp: SHL, SHR, - + MULTIPLY, DIVIDE, MODULO, ADD, SUB, - + PLACE_IN, // `in PLACE { expr }` or `PLACE <- expr` }; @@ -555,7 +555,7 @@ struct ExprNode_BinOp: m_right( ::std::move(right) ) { } - + NODE_METHODS(); }; @@ -570,7 +570,7 @@ struct ExprNode_UniOp: NEGATE, // '-<expr>' QMARK, // '<expr>?' }; - + enum Type m_type; ::std::unique_ptr<ExprNode> m_value; @@ -579,7 +579,7 @@ struct ExprNode_UniOp: m_value( ::std::move(value) ) { } - + NODE_METHODS(); }; @@ -593,7 +593,7 @@ public: cnode->visit(*this); } virtual bool is_const() const { return false; } - + #define NT(nt) \ virtual void visit(nt& node) = 0/*; \ virtual void visit(const nt& node) = 0*/ @@ -609,7 +609,7 @@ public: NT(ExprNode_Match); NT(ExprNode_If); NT(ExprNode_IfLet); - + NT(ExprNode_Integer); NT(ExprNode_Float); NT(ExprNode_Bool); @@ -620,7 +620,7 @@ public: NT(ExprNode_Array); NT(ExprNode_Tuple); NT(ExprNode_NamedValue); - + NT(ExprNode_Field); NT(ExprNode_Index); NT(ExprNode_Deref); @@ -653,7 +653,7 @@ public: NT(ExprNode_Match); NT(ExprNode_If); NT(ExprNode_IfLet); - + NT(ExprNode_Integer); NT(ExprNode_Float); NT(ExprNode_Bool); @@ -664,7 +664,7 @@ public: NT(ExprNode_Array); NT(ExprNode_Tuple); NT(ExprNode_NamedValue); - + NT(ExprNode_Field); NT(ExprNode_Index); NT(ExprNode_Deref); diff --git a/src/ast/expr_ptr.hpp b/src/ast/expr_ptr.hpp index eb60c49f..1d68af15 100644 --- a/src/ast/expr_ptr.hpp +++ b/src/ast/expr_ptr.hpp @@ -24,7 +24,7 @@ public: ::std::shared_ptr<ExprNode> take_node() { assert(m_node.get()); return ::std::move(m_node); } void visit_nodes(NodeVisitor& v); void visit_nodes(NodeVisitor& v) const; - + Expr clone() const; friend ::std::ostream& operator<<(::std::ostream& os, const Expr& pat); diff --git a/src/ast/generics.hpp b/src/ast/generics.hpp index 7f8858a8..2de5aeaa 100644 --- a/src/ast/generics.hpp +++ b/src/ast/generics.hpp @@ -26,12 +26,12 @@ public: assert(m_default.is_wildcard()); m_default = ::std::move(type); } - + const ::std::string& name() const { return m_name; } - + const TypeRef& get_default() const { return m_default; } TypeRef& get_default() { return m_default; } - + friend ::std::ostream& operator<<(::std::ostream& os, const TypeParam& tp); }; @@ -69,13 +69,13 @@ TAGGED_UNION_EX( GenericBound, (), Lifetime, TypeRef replacement; }) ), - + (, span(x.span) ), ( span = x.span; ), ( public: - + Span span; - + GenericBound clone() const { TU_MATCH(GenericBound, ( (*this) ), (ent), (Lifetime, return make_Lifetime({ent.test, ent.bound}); ), @@ -102,7 +102,7 @@ public: GenericParams(GenericParams&& x) = default; GenericParams& operator=(GenericParams&& x) = default; GenericParams(const GenericParams& x) = delete; - + GenericParams clone() const { GenericParams rv; rv.m_type_params = ::std::vector<TypeParam>( m_type_params ); // Copy-constructable @@ -112,23 +112,23 @@ public: rv.m_bounds.push_back( e.clone() ); return rv; } - + const ::std::vector<TypeParam>& ty_params() const { return m_type_params; } ::std::vector<TypeParam>& ty_params() { return m_type_params; } const ::std::vector< ::std::string>& lft_params() const { return m_lifetime_params; } const ::std::vector<GenericBound>& bounds() const { return m_bounds; } ::std::vector<GenericBound>& bounds() { return m_bounds; } - + void add_ty_param(TypeParam param) { m_type_params.push_back( ::std::move(param) ); } void add_lft_param(::std::string name) { m_lifetime_params.push_back( ::std::move(name) ); } void add_bound(GenericBound bound) { m_bounds.push_back( ::std::move(bound) ); } - + int find_name(const char* name) const; bool check_params(Crate& crate, const ::std::vector<TypeRef>& types) const; bool check_params(Crate& crate, ::std::vector<TypeRef>& types, bool allow_infer) const; - + friend ::std::ostream& operator<<(::std::ostream& os, const GenericParams& tp); }; diff --git a/src/ast/item.hpp b/src/ast/item.hpp index 2d3d1a1b..cc88f3e2 100644 --- a/src/ast/item.hpp +++ b/src/ast/item.hpp @@ -12,7 +12,7 @@ struct NamedNS ::std::string name; T data; bool is_pub; - + NamedNS(): is_pub(false) {} @@ -25,7 +25,7 @@ struct NamedNS is_pub( is_pub ) { } - + //friend ::std::ostream& operator<<(::std::ostream& os, const Named& i) { // return os << (i.is_pub ? "pub " : " ") << i.name << ": " << i.data; //} diff --git a/src/ast/macro.hpp b/src/ast/macro.hpp index 9ae58fb9..84baa5a3 100644 --- a/src/ast/macro.hpp +++ b/src/ast/macro.hpp @@ -11,7 +11,7 @@ namespace AST { class MacroInvocation { Span m_span; - + ::std::string m_macro_name; ::std::string m_ident; TokenTree m_input; @@ -20,11 +20,11 @@ public: MacroInvocation& operator=(MacroInvocation&&) = default; MacroInvocation(const MacroInvocation&) = delete; MacroInvocation& operator=(const MacroInvocation&) = delete; - + MacroInvocation() { } - + MacroInvocation(Span span, ::std::string macro, ::std::string ident, TokenTree input): m_span( mv$(span) ), m_macro_name( mv$(macro) ), @@ -32,7 +32,7 @@ public: m_input( mv$(input) ) { } - + MacroInvocation clone() const; void clear() { diff --git a/src/ast/path.cpp b/src/ast/path.cpp index ac023c8f..f02f48fb 100644 --- a/src/ast/path.cpp +++ b/src/ast/path.cpp @@ -27,7 +27,7 @@ namespace AST { (TypeAlias, os << "TypeAlias";), (StructMethod, os << "StructMethod"; ), (TraitMethod, os << "TraitMethod"; ), - + (TypeParameter, os << "TyParam(" << i.level << " # " << i.idx << ")"; ), (Variable, os << "Var(" << i.slot << ")"; ) ) @@ -49,7 +49,7 @@ PathBinding PathBinding::clone() const (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); ) ) @@ -84,7 +84,7 @@ PathParams::PathParams(const PathParams& x): m_types.reserve( x.m_types.size() ); for(const auto& t : x.m_types) m_types.push_back(t.clone()); - + m_assoc.reserve( x.m_assoc.size() ); for(const auto& t : x.m_assoc) m_assoc.push_back( ::std::make_pair(t.first, t.second.clone()) ); @@ -180,7 +180,7 @@ 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)); } @@ -199,7 +199,7 @@ void Path::bind_enum_var(const Enum& ent, const ::std::string& name, const ::std } if( idx == ent.variants().size() ) throw ParseError::Generic("Enum variant not found"); - + DEBUG("Bound to enum variant '" << name << "' (#" << idx << ")"); m_binding = PathBinding::make_EnumVar({ &ent, idx }); } @@ -216,10 +216,10 @@ Path& Path::operator+=(const Path& other) Ordering Path::ord(const Path& x) const { Ordering rv; - + rv = ::ord( (unsigned)m_class.tag(), (unsigned)x.m_class.tag() ); if( rv != OrdEqual ) return rv; - + TU_MATCH(Path::Class, (m_class, x.m_class), (ent, x_ent), (Invalid, return OrdEqual; @@ -249,7 +249,7 @@ Ordering Path::ord(const Path& x) const return ::ord(ent.nodes, x_ent.nodes); ) ) - + return OrdEqual; } diff --git a/src/ast/path.hpp b/src/ast/path.hpp index b45767a2..7a67b93e 100644 --- a/src/ast/path.hpp +++ b/src/ast/path.hpp @@ -112,7 +112,7 @@ struct PathParams ::std::vector< ::std::string > m_lifetimes; ::std::vector< TypeRef > m_types; ::std::vector< ::std::pair< ::std::string, TypeRef> > m_assoc; - + PathParams(PathParams&& x) = default; PathParams(const PathParams& x); PathParams() {} @@ -121,16 +121,16 @@ struct PathParams m_types(mv$(tys)), m_assoc(mv$(a)) {} - + PathParams& operator=(PathParams&& x) = default; PathParams& operator=(const PathParams& x) = delete; - + bool is_empty() const { return m_lifetimes.empty() && m_types.empty() && m_assoc.empty(); } - + Ordering ord(const PathParams& x) const; - + friend ::std::ostream& operator<<(::std::ostream& os, const PathParams& x); }; @@ -142,13 +142,13 @@ public: PathNode() {} PathNode(::std::string name, PathParams args = {}); const ::std::string& name() const { return m_name; } - + const ::AST::PathParams& args() const { return m_params; } ::AST::PathParams& args() { return m_params; } - + Ordering ord(const PathNode& x) const; void print_pretty(::std::ostream& os, bool is_type_context) const; - + bool operator==(const PathNode& x) const { return ord(x) == OrdEqual; } friend ::std::ostream& operator<<(::std::ostream& os, const PathNode& pn); }; @@ -201,20 +201,20 @@ public: //DEBUG("Path, " << x); return *this; } - + Path(const Path& x); Path& operator=(const AST::Path&) = delete; - + // ABSOLUTE Path(::std::string crate, ::std::vector<PathNode> nodes): m_class( Class::make_Absolute({ mv$(crate), mv$(nodes)}) ) {} - + // UFCS struct TagUfcs {}; Path(TagUfcs, TypeRef type, ::std::vector<PathNode> nodes={}); Path(TagUfcs, TypeRef type, Path trait, ::std::vector<PathNode> nodes={}); - + // VARIABLE struct TagLocal {}; Path(TagLocal, ::std::string name): @@ -223,7 +223,7 @@ public: Path(::std::string name): m_class( Class::make_Local({ mv$(name) }) ) {} - + // RELATIVE struct TagRelative {}; Path(TagRelative, Ident::Hygiene hygiene, ::std::vector<PathNode> nodes): @@ -239,7 +239,7 @@ public: Path(TagSuper, unsigned int count, ::std::vector<PathNode> nodes): m_class( Class::make_Super({ count, mv$(nodes) }) ) {} - + //void set_crate(::std::string crate) { // if( m_crate == "" ) { // m_crate = crate; @@ -247,11 +247,11 @@ public: // } //} - + Class::Tag class_tag() const { return m_class.tag(); } - + Path operator+(PathNode pn) const { Path tmp = Path(*this); tmp.nodes().push_back( mv$(pn) ); @@ -274,7 +274,7 @@ public: nodes().push_back( mv$(node) ); m_binding = PathBinding(); } - + bool is_trivial() const { TU_MATCH_DEF(Class, (m_class), (e), ( @@ -288,11 +288,11 @@ public: ) ) } - + bool is_valid() const { return !m_class.is_Invalid(); } bool is_absolute() const { return m_class.is_Absolute(); } bool is_relative() const { return m_class.is_Relative() || m_class.is_Super() || m_class.is_Self(); } - + size_t size() const { TU_MATCH(Class, (m_class), (ent), (Invalid, assert(!m_class.is_Invalid()); throw ::std::runtime_error("Path::nodes() on Invalid"); ), @@ -308,11 +308,11 @@ public: //const ::std::string& crate() const { return m_crate; } 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<PathNode>& nodes() { TU_MATCH(Class, (m_class), (ent), (Invalid, assert(!m_class.is_Invalid()); throw ::std::runtime_error("Path::nodes() on Invalid"); ), @@ -328,20 +328,20 @@ public: const ::std::vector<PathNode>& nodes() const { return ((Path*)this)->nodes(); } - + PathNode& operator[](int idx) { if(idx>=0) return nodes()[idx]; else return nodes()[size()+idx]; } const PathNode& operator[](int idx) const { return (*(Path*)this)[idx]; } - + Ordering ord(const Path& x) const; bool operator==(const Path& x) const { return ord(x) == OrdEqual; } bool operator!=(const Path& x) const { return ord(x) != OrdEqual; } bool operator<(const Path& x) const { return ord(x) != OrdLess; } - + void print_pretty(::std::ostream& os, bool is_type_context) const; friend ::std::ostream& operator<<(::std::ostream& os, const Path& path); private: static void resolve_args_nl(::std::vector<PathNode>& nodes, ::std::function<TypeRef(const char*)> fcn); - + 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<TypeRef>& args={}); @@ -349,7 +349,7 @@ public: (void)args; m_binding = PathBinding::make_Function({&ent}); } - + void bind(::AST::PathBinding pb) { m_binding = mv$(pb); } diff --git a/src/ast/pattern.cpp b/src/ast/pattern.cpp index 3128fd91..bfcc6eeb 100644 --- a/src/ast/pattern.cpp +++ b/src/ast/pattern.cpp @@ -123,7 +123,7 @@ namespace AST { os << ent.leading; needs_comma = true; } - + if( needs_comma ) { os << ", "; } @@ -131,7 +131,7 @@ namespace AST { os << ent.extra_bind.m_name; os << ".."; needs_comma = true; - + if(ent.trailing.size()) { if( needs_comma ) { os << ", "; @@ -167,7 +167,7 @@ AST::Pattern AST::Pattern::clone() const AST::Pattern rv; rv.m_span = m_span; rv.m_binding = PatternBinding(m_binding); - + struct H { static ::std::unique_ptr<Pattern> clone_sp(const ::std::unique_ptr<Pattern>& p) { return ::std::make_unique<Pattern>( p->clone() ); @@ -198,7 +198,7 @@ AST::Pattern AST::Pattern::clone() const throw ""; } }; - + TU_MATCH(Pattern::Data, (m_data), (e), (Any, rv.m_data = Data::make_Any(e); @@ -237,7 +237,7 @@ AST::Pattern AST::Pattern::clone() const rv.m_data = Data::make_SplitSlice({ H::clone_list(e.leading), e.extra_bind, H::clone_list(e.trailing) }); ) ) - + return rv; } diff --git a/src/ast/pattern.hpp b/src/ast/pattern.hpp index a2df7b59..af6a5adf 100644 --- a/src/ast/pattern.hpp +++ b/src/ast/pattern.hpp @@ -46,11 +46,11 @@ public: m_mutable(ismut), m_slot( ~0u ) {} - + PatternBinding(PatternBinding&& x) = default; PatternBinding(const PatternBinding& x) = default; PatternBinding& operator=(PatternBinding&& x) = default; - + bool is_valid() const { return m_name.name != ""; } }; @@ -78,7 +78,7 @@ public: bool has_wildcard; ::std::vector<Pattern> end; }; - + TAGGED_UNION(Data, Any, (MaybeBind, struct { Ident name; } ), (Macro, struct { unique_ptr<::AST::MacroInvocation> inv; } ), @@ -96,15 +96,15 @@ private: Span m_span; PatternBinding m_binding; Data m_data; - + public: virtual ~Pattern(); - + Pattern() {} Pattern(Pattern&&) = default; Pattern& operator=(Pattern&&) = default; - + Pattern(Data dat): m_binding(), m_data( mv$(dat) ) @@ -135,8 +135,8 @@ public: Pattern(TagValue, Value val, Value end = Value()): m_data( Data::make_Value({ ::std::move(val), ::std::move(end) }) ) {} - - + + struct TagReference {}; Pattern(TagReference, bool is_mutable, Pattern sub_pattern): m_data( Data::make_Ref( /*Data::Data_Ref */ { @@ -163,20 +163,20 @@ public: struct TagStruct {}; Pattern(TagStruct, Path path, ::std::vector< ::std::pair< ::std::string,Pattern> > sub_patterns, bool is_exhaustive): - m_data( Data::make_Struct( { ::std::move(path), ::std::move(sub_patterns), is_exhaustive } ) ) + m_data( Data::make_Struct( { ::std::move(path), ::std::move(sub_patterns), is_exhaustive } ) ) {} - + // Mutators void set_bind(Ident name, PatternBinding::Type type, bool is_mut) { m_binding = PatternBinding(mv$(name), type, is_mut); } - - + + const Span& span() const { return m_span; } void set_span(Span sp) { m_span = mv$(sp); } - + Pattern clone() const; - + // Accessors PatternBinding& binding() { return m_binding; } const PatternBinding& binding() const { return m_binding; } diff --git a/src/ast/types.cpp b/src/ast/types.cpp index c8f373e5..21e47b4b 100644 --- a/src/ast/types.cpp +++ b/src/ast/types.cpp @@ -1,7 +1,7 @@ /* * MRustC - Mutabah's Rust Compiler * - By John Hodge (Mutabah/thePowersGang) - * + * * types.cpp * - Backing code for the TypeRef class * @@ -87,7 +87,7 @@ Type_Function::Type_Function(const Type_Function& other): Ordering Type_Function::ord(const Type_Function& x) const { Ordering rv; - + rv = ::ord(m_abi, x.m_abi); if(rv != OrdEqual) return rv; rv = ::ord(m_arg_types, x.m_arg_types); @@ -139,10 +139,10 @@ TypeRef TypeRef::clone() const Ordering TypeRef::ord(const TypeRef& x) const { Ordering rv; - + rv = ::ord( (unsigned)m_data.tag(), (unsigned)x.m_data.tag() ); if(rv != OrdEqual) return rv; - + TU_MATCH(TypeData, (m_data, x.m_data), (ent, x_ent), (None, return OrdEqual;), (Macro, throw CompileError::BugCheck("TypeRef::ord - unexpanded macro");), diff --git a/src/ast/types.hpp b/src/ast/types.hpp index 04c1517f..e2114bae 100644 --- a/src/ast/types.hpp +++ b/src/ast/types.hpp @@ -1,276 +1,276 @@ -#ifndef TYPES_HPP_INCLUDED
-#define TYPES_HPP_INCLUDED
-
-#include <memory>
-
-#include "common.hpp"
-#include "coretypes.hpp"
-#include "ast/path.hpp"
-#include "ast/macro.hpp"
-#include <serialise.hpp>
-#include <tagged_union.hpp>
-
-namespace AST {
-class ExprNode;
-class Expr;
-}
-
-class PrettyPrintType
-{
- const TypeRef& m_type;
-public:
- PrettyPrintType(const TypeRef& ty):
- m_type(ty)
- {}
-
- void print(::std::ostream& os) const;
-
- friend ::std::ostream& operator<<(::std::ostream& os, const PrettyPrintType& v);
-};
-
-struct TypeArgRef
-{
- ::std::string name;
- unsigned int level;
- const AST::GenericParams* params;
-};
-
-struct Type_Function
-{
- bool is_unsafe;
- ::std::string m_abi;
- ::std::unique_ptr<TypeRef> m_rettype;
- ::std::vector<TypeRef> m_arg_types;
- bool is_variadic;
-
- Type_Function() {}
- Type_Function(bool is_unsafe, ::std::string abi, ::std::unique_ptr<TypeRef> ret, ::std::vector<TypeRef> args, bool is_variadic):
- is_unsafe(is_unsafe),
- m_abi(mv$(abi)),
- m_rettype(mv$(ret)),
- m_arg_types(mv$(args)),
- is_variadic(is_variadic)
- {}
- Type_Function(Type_Function&& other) = default;
- Type_Function(const Type_Function& other);
-
- Ordering ord(const Type_Function& x) const;
-};
-
-TAGGED_UNION(TypeData, None,
- (None, struct { }),
- (Any, struct { }),
- (Bang, struct { }),
- (Unit, struct { }),
- (Macro, struct {
- ::AST::MacroInvocation inv;
- }),
- (Primitive, struct {
- enum eCoreType core_type;
- }),
- (Function, struct {
- Type_Function info;
- }),
- (Tuple, struct {
- ::std::vector<TypeRef> inner_types;
- }),
- (Borrow, struct {
- bool is_mut;
- ::std::unique_ptr<TypeRef> inner;
- }),
- (Pointer, struct {
- bool is_mut;
- ::std::unique_ptr<TypeRef> inner;
- }),
- (Array, struct {
- ::std::unique_ptr<TypeRef> inner;
- ::std::shared_ptr<AST::ExprNode> size;
- }),
- (Generic, struct {
- ::std::string name;
- unsigned int index;
- }),
- (Path, struct {
- AST::Path path;
- }),
- (TraitObject, struct {
- ::std::vector<::std::string> hrls;
- ::std::vector<AST::Path> traits;
- }),
- (ErasedType, struct {
- ::std::vector<::std::string> hrls;
- ::std::vector<AST::Path> traits;
- })
- );
-
-/// A type
-class TypeRef
-{
- Span m_span;
-public:
- TypeData m_data;
-
- ~TypeRef();
-
- TypeRef(TypeRef&& other) = default;
- TypeRef& operator=(TypeRef&& other) = default;
-
- #if 1
- TypeRef(const TypeRef& other) = delete;
- TypeRef& operator=(const TypeRef& other) = delete;
- #else
- TypeRef(const TypeRef& other): m_span(other.m_span) {
- *this = other.clone();
- }
- TypeRef& operator=(const TypeRef& other) {
- m_data = mv$(other.clone().m_data);
- return *this;
- }
- #endif
-
- TypeRef(Span sp):
- m_span( mv$(sp) ),
- m_data( TypeData::make_Any({}) )
- {}
- TypeRef(Span sp, TypeData data):
- m_span( mv$(sp) ),
- m_data( mv$(data) )
- {}
-
- struct TagInvalid {};
- TypeRef(TagInvalid, Span sp):
- m_span(mv$(sp)),
- m_data(TypeData::make_None({}))
- {}
-
- struct TagMacro {};
- TypeRef(TagMacro, ::AST::MacroInvocation inv):
- m_span(inv.span()),
- m_data(TypeData::make_Macro({mv$(inv)}))
- {}
-
- struct TagUnit {}; // unit maps to a zero-length tuple, just easier to type
- TypeRef(TagUnit, Span sp):
- m_span(mv$(sp)),
- m_data(TypeData::make_Unit({}))
- {}
-
- struct TagPrimitive {};
- TypeRef(TagPrimitive, Span sp, enum eCoreType type):
- m_span(mv$(sp)),
- m_data(TypeData::make_Primitive({type}))
- {}
- TypeRef(Span sp, enum eCoreType type):
- m_span(mv$(sp)),
- m_data(TypeData::make_Primitive({type}))
- {}
-
- struct TagTuple {};
- TypeRef(TagTuple , Span sp, ::std::vector<TypeRef> inner_types):
- m_span(mv$(sp)),
- m_data(TypeData::make_Tuple({::std::move(inner_types)}))
- {}
- struct TagFunction {};
- TypeRef(TagFunction, Span sp, bool is_unsafe, ::std::string abi, ::std::vector<TypeRef> args, bool is_variadic, TypeRef ret):
- m_span(mv$(sp)),
- m_data(TypeData::make_Function({ Type_Function( is_unsafe, abi, box$(ret), mv$(args), is_variadic ) }))
- {}
-
- struct TagReference {};
- TypeRef(TagReference , Span sp, bool is_mut, TypeRef inner_type):
- m_span(mv$(sp)),
- m_data(TypeData::make_Borrow({ is_mut, ::make_unique_ptr(mv$(inner_type)) }))
- {}
- struct TagPointer {};
- TypeRef(TagPointer , Span sp, bool is_mut, TypeRef inner_type):
- m_span(mv$(sp)),
- m_data(TypeData::make_Pointer({ is_mut, ::make_unique_ptr(mv$(inner_type)) }))
- {}
- struct TagSizedArray {};
- TypeRef(TagSizedArray , Span sp, TypeRef inner_type, ::std::shared_ptr<AST::ExprNode> size):
- m_span(mv$(sp)),
- m_data(TypeData::make_Array({ ::make_unique_ptr(mv$(inner_type)), mv$(size) }))
- {}
- struct TagUnsizedArray {};
- TypeRef(TagUnsizedArray , Span sp, TypeRef inner_type):
- m_span(mv$(sp)),
- m_data(TypeData::make_Array({ ::make_unique_ptr(mv$(inner_type)), ::std::shared_ptr<AST::ExprNode>() }))
- {}
-
- struct TagArg {};
- TypeRef(TagArg, Span sp, ::std::string 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(TagArg(), mv$(sp), mv$(name), binding)
- {}
-
- struct TagPath {};
- TypeRef(TagPath, Span sp, AST::Path path):
- m_span(mv$(sp)),
- m_data(TypeData::make_Path({ ::std::move(path) }))
- {}
- TypeRef(Span sp, AST::Path path):
- TypeRef(TagPath(), mv$(sp), mv$(path))
- {}
-
- TypeRef( Span sp, ::std::vector<::std::string> hrls, ::std::vector<AST::Path> traits ):
- m_span(mv$(sp)),
- m_data(TypeData::make_TraitObject({ mv$(hrls), ::std::move(traits) }))
- {}
-
-
- const Span& span() const { return m_span; }
-
- bool is_valid() const { return ! m_data.is_None(); }
-
- bool is_unbounded() const { return m_data.is_Any(); }
- bool is_wildcard() const { return m_data.is_Any(); }
-
- bool is_unit() const { return m_data.is_Unit(); }
- bool is_primitive() const { return m_data.is_Primitive(); }
-
- bool is_path() const { return m_data.is_Path(); }
- const AST::Path& path() const { return m_data.as_Path().path; }
- 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; }
-
- bool is_reference() const { return m_data.is_Borrow(); }
- bool is_pointer() const { return m_data.is_Pointer(); }
- bool is_tuple() const { return m_data.is_Tuple(); }
-
- TypeRef clone() const;
-
- const TypeRef& inner_type() const {
- TU_MATCH_DEF(TypeData, (m_data), (e),
- ( throw ::std::runtime_error("Called inner_type on non-wrapper"); ),
- (Borrow, return *e.inner; ),
- (Pointer, return *e.inner; ),
- (Array, return *e.inner; )
- )
- }
- TypeRef& inner_type() {
- TU_MATCH_DEF(TypeData, (m_data), (e),
- ( throw ::std::runtime_error("Called inner_type on non-wrapper"); ),
- (Borrow, return *e.inner; ),
- (Pointer, return *e.inner; ),
- (Array, return *e.inner; )
- )
- }
-
- Ordering ord(const TypeRef& x) const;
- bool operator==(const TypeRef& x) const { return ord(x) == OrdEqual; }
- bool operator!=(const TypeRef& x) const { return ord(x) != OrdEqual; }
- bool operator<(const TypeRef& x) const { return ord(x) == OrdLess; };
-
- PrettyPrintType print_pretty() const { return PrettyPrintType(*this); }
-
- friend class PrettyPrintType;
-
- friend ::std::ostream& operator<<(::std::ostream& os, const TypeRef& tr);
-};
-
-#endif // TYPES_HPP_INCLUDED
+#ifndef TYPES_HPP_INCLUDED +#define TYPES_HPP_INCLUDED + +#include <memory> + +#include "common.hpp" +#include "coretypes.hpp" +#include "ast/path.hpp" +#include "ast/macro.hpp" +#include <serialise.hpp> +#include <tagged_union.hpp> + +namespace AST { +class ExprNode; +class Expr; +} + +class PrettyPrintType +{ + const TypeRef& m_type; +public: + PrettyPrintType(const TypeRef& ty): + m_type(ty) + {} + + void print(::std::ostream& os) const; + + friend ::std::ostream& operator<<(::std::ostream& os, const PrettyPrintType& v); +}; + +struct TypeArgRef +{ + ::std::string name; + unsigned int level; + const AST::GenericParams* params; +}; + +struct Type_Function +{ + bool is_unsafe; + ::std::string m_abi; + ::std::unique_ptr<TypeRef> m_rettype; + ::std::vector<TypeRef> m_arg_types; + bool is_variadic; + + Type_Function() {} + Type_Function(bool is_unsafe, ::std::string abi, ::std::unique_ptr<TypeRef> ret, ::std::vector<TypeRef> args, bool is_variadic): + is_unsafe(is_unsafe), + m_abi(mv$(abi)), + m_rettype(mv$(ret)), + m_arg_types(mv$(args)), + is_variadic(is_variadic) + {} + Type_Function(Type_Function&& other) = default; + Type_Function(const Type_Function& other); + + Ordering ord(const Type_Function& x) const; +}; + +TAGGED_UNION(TypeData, None, + (None, struct { }), + (Any, struct { }), + (Bang, struct { }), + (Unit, struct { }), + (Macro, struct { + ::AST::MacroInvocation inv; + }), + (Primitive, struct { + enum eCoreType core_type; + }), + (Function, struct { + Type_Function info; + }), + (Tuple, struct { + ::std::vector<TypeRef> inner_types; + }), + (Borrow, struct { + bool is_mut; + ::std::unique_ptr<TypeRef> inner; + }), + (Pointer, struct { + bool is_mut; + ::std::unique_ptr<TypeRef> inner; + }), + (Array, struct { + ::std::unique_ptr<TypeRef> inner; + ::std::shared_ptr<AST::ExprNode> size; + }), + (Generic, struct { + ::std::string name; + unsigned int index; + }), + (Path, struct { + AST::Path path; + }), + (TraitObject, struct { + ::std::vector<::std::string> hrls; + ::std::vector<AST::Path> traits; + }), + (ErasedType, struct { + ::std::vector<::std::string> hrls; + ::std::vector<AST::Path> traits; + }) + ); + +/// A type +class TypeRef +{ + Span m_span; +public: + TypeData m_data; + + ~TypeRef(); + + TypeRef(TypeRef&& other) = default; + TypeRef& operator=(TypeRef&& other) = default; + + #if 1 + TypeRef(const TypeRef& other) = delete; + TypeRef& operator=(const TypeRef& other) = delete; + #else + TypeRef(const TypeRef& other): m_span(other.m_span) { + *this = other.clone(); + } + TypeRef& operator=(const TypeRef& other) { + m_data = mv$(other.clone().m_data); + return *this; + } + #endif + + TypeRef(Span sp): + m_span( mv$(sp) ), + m_data( TypeData::make_Any({}) ) + {} + TypeRef(Span sp, TypeData data): + m_span( mv$(sp) ), + m_data( mv$(data) ) + {} + + struct TagInvalid {}; + TypeRef(TagInvalid, Span sp): + m_span(mv$(sp)), + m_data(TypeData::make_None({})) + {} + + struct TagMacro {}; + TypeRef(TagMacro, ::AST::MacroInvocation inv): + m_span(inv.span()), + m_data(TypeData::make_Macro({mv$(inv)})) + {} + + struct TagUnit {}; // unit maps to a zero-length tuple, just easier to type + TypeRef(TagUnit, Span sp): + m_span(mv$(sp)), + m_data(TypeData::make_Unit({})) + {} + + struct TagPrimitive {}; + TypeRef(TagPrimitive, Span sp, enum eCoreType type): + m_span(mv$(sp)), + m_data(TypeData::make_Primitive({type})) + {} + TypeRef(Span sp, enum eCoreType type): + m_span(mv$(sp)), + m_data(TypeData::make_Primitive({type})) + {} + + struct TagTuple {}; + TypeRef(TagTuple , Span sp, ::std::vector<TypeRef> inner_types): + m_span(mv$(sp)), + m_data(TypeData::make_Tuple({::std::move(inner_types)})) + {} + struct TagFunction {}; + TypeRef(TagFunction, Span sp, bool is_unsafe, ::std::string abi, ::std::vector<TypeRef> args, bool is_variadic, TypeRef ret): + m_span(mv$(sp)), + m_data(TypeData::make_Function({ Type_Function( is_unsafe, abi, box$(ret), mv$(args), is_variadic ) })) + {} + + struct TagReference {}; + TypeRef(TagReference , Span sp, bool is_mut, TypeRef inner_type): + m_span(mv$(sp)), + m_data(TypeData::make_Borrow({ is_mut, ::make_unique_ptr(mv$(inner_type)) })) + {} + struct TagPointer {}; + TypeRef(TagPointer , Span sp, bool is_mut, TypeRef inner_type): + m_span(mv$(sp)), + m_data(TypeData::make_Pointer({ is_mut, ::make_unique_ptr(mv$(inner_type)) })) + {} + struct TagSizedArray {}; + TypeRef(TagSizedArray , Span sp, TypeRef inner_type, ::std::shared_ptr<AST::ExprNode> size): + m_span(mv$(sp)), + m_data(TypeData::make_Array({ ::make_unique_ptr(mv$(inner_type)), mv$(size) })) + {} + struct TagUnsizedArray {}; + TypeRef(TagUnsizedArray , Span sp, TypeRef inner_type): + m_span(mv$(sp)), + m_data(TypeData::make_Array({ ::make_unique_ptr(mv$(inner_type)), ::std::shared_ptr<AST::ExprNode>() })) + {} + + struct TagArg {}; + TypeRef(TagArg, Span sp, ::std::string 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(TagArg(), mv$(sp), mv$(name), binding) + {} + + struct TagPath {}; + TypeRef(TagPath, Span sp, AST::Path path): + m_span(mv$(sp)), + m_data(TypeData::make_Path({ ::std::move(path) })) + {} + TypeRef(Span sp, AST::Path path): + TypeRef(TagPath(), mv$(sp), mv$(path)) + {} + + TypeRef( Span sp, ::std::vector<::std::string> hrls, ::std::vector<AST::Path> traits ): + m_span(mv$(sp)), + m_data(TypeData::make_TraitObject({ mv$(hrls), ::std::move(traits) })) + {} + + + const Span& span() const { return m_span; } + + bool is_valid() const { return ! m_data.is_None(); } + + bool is_unbounded() const { return m_data.is_Any(); } + bool is_wildcard() const { return m_data.is_Any(); } + + bool is_unit() const { return m_data.is_Unit(); } + bool is_primitive() const { return m_data.is_Primitive(); } + + bool is_path() const { return m_data.is_Path(); } + const AST::Path& path() const { return m_data.as_Path().path; } + 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; } + + bool is_reference() const { return m_data.is_Borrow(); } + bool is_pointer() const { return m_data.is_Pointer(); } + bool is_tuple() const { return m_data.is_Tuple(); } + + TypeRef clone() const; + + const TypeRef& inner_type() const { + TU_MATCH_DEF(TypeData, (m_data), (e), + ( throw ::std::runtime_error("Called inner_type on non-wrapper"); ), + (Borrow, return *e.inner; ), + (Pointer, return *e.inner; ), + (Array, return *e.inner; ) + ) + } + TypeRef& inner_type() { + TU_MATCH_DEF(TypeData, (m_data), (e), + ( throw ::std::runtime_error("Called inner_type on non-wrapper"); ), + (Borrow, return *e.inner; ), + (Pointer, return *e.inner; ), + (Array, return *e.inner; ) + ) + } + + Ordering ord(const TypeRef& x) const; + bool operator==(const TypeRef& x) const { return ord(x) == OrdEqual; } + bool operator!=(const TypeRef& x) const { return ord(x) != OrdEqual; } + bool operator<(const TypeRef& x) const { return ord(x) == OrdLess; }; + + PrettyPrintType print_pretty() const { return PrettyPrintType(*this); } + + friend class PrettyPrintType; + + friend ::std::ostream& operator<<(::std::ostream& os, const TypeRef& tr); +}; + +#endif // TYPES_HPP_INCLUDED diff --git a/src/common.hpp b/src/common.hpp index 7334be13..d421e368 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -117,14 +117,14 @@ Ordering ord(const ::std::vector<T>& l, const ::std::vector<T>& r) { if( i >= r.size() ) return OrdGreater; - + auto rv = ::ord( it, r[i] ); if( rv != OrdEqual ) return rv; - + i ++; } - + if( i < r.size() ) return OrdLess; return OrdEqual; @@ -152,7 +152,7 @@ struct LList { const LList* m_prev; T m_item; - + LList(): m_prev(nullptr) {} @@ -161,7 +161,7 @@ struct LList m_item( ::std::move(item) ) { } - + LList end() const { return LList(); } diff --git a/src/coretypes.hpp b/src/coretypes.hpp index f78b1ff2..cfab82c1 100644 --- a/src/coretypes.hpp +++ b/src/coretypes.hpp @@ -1,22 +1,22 @@ -#ifndef CORETYPES_HPP_INCLUDED
-#define CORETYPES_HPP_INCLUDED
-
-enum eCoreType
-{
- CORETYPE_INVAL,
- CORETYPE_ANY,
- CORETYPE_BOOL,
- CORETYPE_CHAR, CORETYPE_STR,
- CORETYPE_UINT, CORETYPE_INT,
- CORETYPE_U8, CORETYPE_I8,
- CORETYPE_U16, CORETYPE_I16,
- CORETYPE_U32, CORETYPE_I32,
- CORETYPE_U64, CORETYPE_I64,
- CORETYPE_F32,
- CORETYPE_F64,
-};
-
-extern enum eCoreType coretype_fromstring(const ::std::string& name);
-extern const char* coretype_name(const eCoreType ct);
-
-#endif // CORETYPES_HPP_INCLUDED
+#ifndef CORETYPES_HPP_INCLUDED +#define CORETYPES_HPP_INCLUDED + +enum eCoreType +{ + CORETYPE_INVAL, + CORETYPE_ANY, + CORETYPE_BOOL, + CORETYPE_CHAR, CORETYPE_STR, + CORETYPE_UINT, CORETYPE_INT, + CORETYPE_U8, CORETYPE_I8, + CORETYPE_U16, CORETYPE_I16, + CORETYPE_U32, CORETYPE_I32, + CORETYPE_U64, CORETYPE_I64, + CORETYPE_F32, + CORETYPE_F64, +}; + +extern enum eCoreType coretype_fromstring(const ::std::string& name); +extern const char* coretype_name(const eCoreType ct); + +#endif // CORETYPES_HPP_INCLUDED diff --git a/src/expand/cfg.cpp b/src/expand/cfg.cpp index e59da886..fcd31742 100644 --- a/src/expand/cfg.cpp +++ b/src/expand/cfg.cpp @@ -31,7 +31,7 @@ void Cfg_SetValueCb(::std::string name, ::std::function<bool(const ::std::string } bool check_cfg(Span sp, const ::AST::MetaItem& mi) { - + if( mi.has_sub_items() ) { // Must be `any`/`not`/`all` if( mi.name() == "any" || mi.name() == "cfg" ) { @@ -66,14 +66,14 @@ bool check_cfg(Span sp, const ::AST::MetaItem& mi) { DEBUG(""<<mi.name()<<": '"<<it->second<<"' == '"<<mi.string()<<"'"); return it->second == mi.string(); } - + auto it2 = g_cfg_value_fcns.find(mi.name()); if(it2 != g_cfg_value_fcns.end() ) { DEBUG(""<<mi.name()<<": ('"<<mi.string()<<"')?"); return it2->second( mi.string() ); } - + WARNING(sp, W0000, "Unknown cfg() param '" << mi.name() << "'"); return false; } @@ -93,11 +93,11 @@ class CCfgExpander: if( ident != "" ) { ERROR(sp, E0000, "cfg! doesn't take an identifier"); } - + auto lex = TTStream(tt); auto attrs = Parse_MetaItem(lex); DEBUG("cfg!() - " << attrs); - + if( check_cfg(sp, attrs) ) { return box$( TTStreamO(TokenTree({},TOK_RWORD_TRUE )) ); } @@ -112,8 +112,8 @@ class CCfgHandler: public ExpandDecorator { AttrStage stage() const override { return AttrStage::Pre; } - - + + void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate) const override { DEBUG("#[cfg] crate - " << mi); // Ignore, as #[cfg] on a crate is handled in expand/mod.cpp @@ -150,7 +150,7 @@ class CCfgHandler: impl.type() = ::TypeRef(sp); } } - + void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate, ::AST::StructItem& si) const override { DEBUG("#[cfg] struct item - " << mi); if( !check_cfg(sp, mi) ) { diff --git a/src/expand/concat.cpp b/src/expand/concat.cpp index 7475325a..a08e9168 100644 --- a/src/expand/concat.cpp +++ b/src/expand/concat.cpp @@ -19,18 +19,18 @@ class CConcatExpander: ::std::unique_ptr<TokenStream> expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override { Token tok; - + auto lex = TTStream(tt); if( ident != "" ) ERROR(sp, E0000, "format_args! doesn't take an ident"); - + ::std::string rv; do { if( LOOK_AHEAD(lex) == TOK_EOF ) { GET_TOK(tok, lex); break ; } - + auto v = Parse_Expr0(lex); DEBUG("concat - v=" << *v); Expand_BareExpr(crate, mod, v); @@ -63,7 +63,7 @@ class CConcatExpander: } while( GET_TOK(tok, lex) == TOK_COMMA ); if( tok.type() != TOK_EOF ) throw ParseError::Unexpected(lex, tok, {TOK_COMMA, TOK_EOF}); - + return box$( TTStreamO(TokenTree(Token(TOK_STRING, mv$(rv)))) ); } }; diff --git a/src/expand/crate_tags.cpp b/src/expand/crate_tags.cpp index df6b339b..ca5a98ce 100644 --- a/src/expand/crate_tags.cpp +++ b/src/expand/crate_tags.cpp @@ -13,7 +13,7 @@ class Decorator_CrateType: { public: AttrStage stage() const override { return AttrStage::Pre; } - + void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate) const override { if( crate.m_crate_type != AST::Crate::Type::Unknown ) { //ERROR(sp, E0000, "Multiple #![crate_type] attributes"); @@ -40,7 +40,7 @@ class Decorator_CrateName: { public: AttrStage stage() const override { return AttrStage::Pre; } - + void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate) const override { if( crate.m_crate_name != "" ) { ERROR(sp, E0000, "Multiple #![crate_name] attributes"); diff --git a/src/expand/derive.cpp b/src/expand/derive.cpp index f6021a7d..46457784 100644 --- a/src/expand/derive.cpp +++ b/src/expand/derive.cpp @@ -66,16 +66,16 @@ struct Deriver { virtual AST::Impl handle_item(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, const AST::Struct& str) const = 0; virtual AST::Impl handle_item(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, const AST::Enum& enm) const = 0; - - + + AST::GenericParams get_params_with_bounds(const Span& sp, const AST::GenericParams& p, const AST::Path& trait_path, ::std::vector<TypeRef> additional_bounded_types) const { AST::GenericParams params = p.clone(); - + // TODO: Get bounds based on generic (or similar) types used within the type. // - How would this code (that runs before resolve) know what's a generic and what's a local type? // - Searches within the type for a Path that starts with that param. - + unsigned int i = 0; for(const auto& arg : params.ty_params()) { @@ -84,7 +84,7 @@ struct Deriver }) ); i ++; } - + // For each field type // - Locate used generic parameters in the type (and sub-types that directly use said parameter) for(auto& ty : additional_bounded_types) @@ -93,11 +93,11 @@ struct Deriver mv$(ty), {}, trait_path }) ); } - + return params; } - - + + ::std::vector<TypeRef> get_field_bounds(const AST::Struct& str) const { ::std::vector<TypeRef> ret; @@ -140,10 +140,10 @@ struct Deriver ) ) } - + return ret; } - + void add_field_bound_from_ty(const AST::GenericParams& params, ::std::vector<TypeRef>& out_list, const TypeRef& ty) const { struct H { @@ -264,14 +264,14 @@ 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<TypeRef> 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, true, TypeRef(sp, AST::Path(core_name, {AST::PathNode("fmt",{}), AST::PathNode("Formatter", {})})) ); - + AST::Function fcn( sp, AST::GenericParams(), @@ -283,19 +283,19 @@ class Deriver_Debug: ) ); fcn.set_code( NEWNODE(Block, vec$(mv$(node))) ); - + AST::GenericParams params = get_params_with_bounds(sp, p, debug_trait, mv$(types_to_bound)); - + AST::Impl rv( AST::ImplDef( sp, AST::MetaItems(), mv$(params), make_spanned(sp, debug_trait), type.clone() ) ); rv.add_function(false, false, "fmt", mv$(fcn)); return mv$(rv); } - + public: AST::Impl handle_item(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, const AST::Struct& str) const override { const ::std::string& name = type.path().nodes().back().name(); - + // Generate code for Debug AST::ExprNodeP node; TU_MATCH(AST::StructData, (str.m_data), (e), @@ -345,20 +345,20 @@ public: node = NEWNODE(CallMethod, mv$(node), AST::PathNode("finish",{}), {}); ) ) - + return this->make_ret(sp, core_name, p, type, this->get_field_bounds(str), mv$(node)); } AST::Impl handle_item(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, const AST::Enum& enm) const override { AST::Path base_path = type.m_data.as_Path().path; base_path.nodes().back() = base_path.nodes().back().name(); - + ::std::vector< AST::ExprNode_Match_Arm> arms; for(const auto& v : enm.variants()) { AST::ExprNodeP code; AST::Pattern pat_a; - + TU_MATCH(::AST::EnumVariantData, (v.m_data), (e), (Value, code = NEWNODE(CallMethod, @@ -372,34 +372,34 @@ public: // TODO: Complete this. ::std::vector<AST::Pattern> pats_a; //::std::vector<AST::ExprNodeP> nodes; - + for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ ) { auto name_a = FMT("a" << idx); pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), name_a, ::AST::PatternBinding::Type::REF) ); //nodes.push_back( this->assert_is_eq(assert_method_path, NEWNODE(NamedValue, AST::Path(name_a))) ); } - + //code = NEWNODE(Block, mv$(nodes)); code = NEWNODE(CallMethod, NEWNODE(NamedValue, AST::Path("f")), AST::PathNode("write_str",{}), vec$( NEWNODE(String, v.m_name + "(...)") ) ); - + pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), base_path + v.m_name, mv$(pats_a)); ), (Struct, ::std::vector< ::std::pair<std::string, AST::Pattern> > pats_a; //::std::vector<AST::ExprNodeP> nodes; - + for( const auto& fld : e.m_fields ) { auto name_a = FMT("a" << fld.m_name); pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), name_a, ::AST::PatternBinding::Type::REF)) ); //nodes.push_back( this->assert_is_eq(assert_method_path, NEWNODE(NamedValue, AST::Path(name_a))) ); } - + //code = NEWNODE(Block, mv$(nodes) ); code = NEWNODE(CallMethod, NEWNODE(NamedValue, AST::Path("f")), @@ -409,10 +409,10 @@ public: pat_a = AST::Pattern(AST::Pattern::TagStruct(), base_path + v.m_name, mv$(pats_a), true); ) ) - + ::std::vector< AST::Pattern> pats; pats.push_back( AST::Pattern(AST::Pattern::TagReference(), false, mv$(pat_a)) ); - + arms.push_back(AST::ExprNode_Match_Arm( mv$(pats), nullptr, @@ -423,7 +423,7 @@ public: NEWNODE(NamedValue, AST::Path("self")), mv$(arms) ); - + return this->make_ret(sp, core_name, p, type, this->get_field_bounds(enm), mv$(node)); } } g_derive_debug; @@ -434,7 +434,7 @@ class Deriver_PartialEq: AST::Impl make_ret(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const { const AST::Path trait_path(core_name, { AST::PathNode("cmp", {}), AST::PathNode("PartialEq", {}) }); - + AST::Function fcn( sp, AST::GenericParams(), @@ -446,9 +446,9 @@ class Deriver_PartialEq: ) ); fcn.set_code( NEWNODE(Block, vec$(mv$(node))) ); - + AST::GenericParams params = get_params_with_bounds(sp, p, trait_path, mv$(types_to_bound)); - + AST::Impl rv( AST::ImplDef( sp, AST::MetaItems(), mv$(params), make_spanned(sp, trait_path), type.clone() ) ); rv.add_function(false, false, "eq", mv$(fcn)); return mv$(rv); @@ -465,7 +465,7 @@ public: AST::Impl handle_item(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, const AST::Struct& str) const override { ::std::vector<AST::ExprNodeP> nodes; - + TU_MATCH(AST::StructData, (str.m_data), (e), (Struct, for( const auto& fld : e.ents ) @@ -488,22 +488,22 @@ public: ) ) nodes.push_back( NEWNODE(Bool, true) ); - + return this->make_ret(sp, core_name, p, type, this->get_field_bounds(str), NEWNODE(Block, mv$(nodes))); } - + AST::Impl handle_item(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, const AST::Enum& enm) const override { AST::Path base_path = type.m_data.as_Path().path; base_path.nodes().back().args() = ::AST::PathParams(); ::std::vector<AST::ExprNode_Match_Arm> arms; - + for(const auto& v : enm.variants()) { AST::ExprNodeP code; AST::Pattern pat_a; AST::Pattern pat_b; - + TU_MATCH(::AST::EnumVariantData, (v.m_data), (e), (Value, code = NEWNODE(Bool, true); @@ -514,7 +514,7 @@ public: ::std::vector<AST::Pattern> pats_a; ::std::vector<AST::Pattern> pats_b; ::std::vector<AST::ExprNodeP> nodes; - + for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ ) { auto name_a = FMT("a" << idx); @@ -526,7 +526,7 @@ public: NEWNODE(NamedValue, AST::Path(name_b)) )); } - + nodes.push_back( NEWNODE(Bool, true) ); pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), base_path + v.m_name, mv$(pats_a)); pat_b = AST::Pattern(AST::Pattern::TagNamedTuple(), base_path + v.m_name, mv$(pats_b)); @@ -536,7 +536,7 @@ public: ::std::vector< ::std::pair<std::string, AST::Pattern> > pats_a; ::std::vector< ::std::pair<std::string, AST::Pattern> > pats_b; ::std::vector<AST::ExprNodeP> nodes; - + for( const auto& fld : e.m_fields ) { auto name_a = FMT("a" << fld.m_name); @@ -548,14 +548,14 @@ public: NEWNODE(NamedValue, AST::Path(name_b)) )); } - + nodes.push_back( NEWNODE(Bool, true) ); pat_a = AST::Pattern(AST::Pattern::TagStruct(), base_path + v.m_name, mv$(pats_a), true); pat_b = AST::Pattern(AST::Pattern::TagStruct(), base_path + v.m_name, mv$(pats_b), true); code = NEWNODE(Block, mv$(nodes)); ) ) - + ::std::vector< AST::Pattern> pats; { ::std::vector< AST::Pattern> tuple_pats; @@ -563,14 +563,14 @@ public: tuple_pats.push_back( AST::Pattern(AST::Pattern::TagReference(), false, mv$(pat_b)) ); pats.push_back( AST::Pattern(AST::Pattern::TagTuple(), mv$(tuple_pats)) ); } - + arms.push_back(AST::ExprNode_Match_Arm( mv$(pats), nullptr, mv$(code) )); } - + // Default arm { arms.push_back(AST::ExprNode_Match_Arm( @@ -593,7 +593,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, {}) }); @@ -602,15 +602,15 @@ class Deriver_PartialOrd: { 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<TypeRef> 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", {}) }); - + AST::Path path_option_ordering(core_name, { AST::PathNode("option", {}), AST::PathNode("Option", {}) }); path_option_ordering.nodes().back().args().m_types.push_back( TypeRef(sp, path_ordering) ); - + AST::Function fcn( sp, AST::GenericParams(), @@ -622,14 +622,14 @@ class Deriver_PartialOrd: ) ); fcn.set_code( NEWNODE(Block, vec$(mv$(node))) ); - + AST::GenericParams params = get_params_with_bounds(sp, p, trait_path, mv$(types_to_bound)); - + AST::Impl rv( AST::ImplDef( sp, AST::MetaItems(), mv$(params), make_spanned(sp, trait_path), type.clone() ) ); rv.add_function(false, false, "partial_cmp", mv$(fcn)); return mv$(rv); } - + AST::ExprNodeP make_compare_and_ret(Span sp, const ::std::string& core_name, AST::ExprNodeP v1, AST::ExprNodeP v2) const { return NEWNODE(Match, @@ -670,7 +670,7 @@ public: AST::Impl handle_item(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, const AST::Struct& str) const override { ::std::vector<AST::ExprNodeP> nodes; - + TU_MATCH(AST::StructData, (str.m_data), (e), (Struct, for( const auto& fld : e.ents ) @@ -693,22 +693,22 @@ public: ) ) nodes.push_back( this->make_ret_equal(core_name) ); - + return this->make_ret(sp, core_name, p, type, this->get_field_bounds(str), NEWNODE(Block, mv$(nodes))); } - + AST::Impl handle_item(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, const AST::Enum& enm) const override { AST::Path base_path = type.m_data.as_Path().path; base_path.nodes().back().args() = ::AST::PathParams(); ::std::vector<AST::ExprNode_Match_Arm> arms; - + for(const auto& v : enm.variants()) { AST::ExprNodeP code; AST::Pattern pat_a; AST::Pattern pat_b; - + TU_MATCH(::AST::EnumVariantData, (v.m_data), (e), (Value, code = this->make_ret_equal(core_name); @@ -719,20 +719,20 @@ public: ::std::vector<AST::Pattern> pats_a; ::std::vector<AST::Pattern> pats_b; ::std::vector<AST::ExprNodeP> nodes; - + for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ ) { auto name_a = FMT("a" << idx); auto name_b = FMT("b" << idx); pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), name_a, ::AST::PatternBinding::Type::REF) ); pats_b.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), name_b, ::AST::PatternBinding::Type::REF) ); - + nodes.push_back(this->make_compare_and_ret( sp, core_name, NEWNODE(NamedValue, AST::Path(name_a)), NEWNODE(NamedValue, AST::Path(name_b)) )); } - + nodes.push_back( this->make_ret_equal(core_name) ); pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), base_path + v.m_name, mv$(pats_a)); pat_b = AST::Pattern(AST::Pattern::TagNamedTuple(), base_path + v.m_name, mv$(pats_b)); @@ -742,27 +742,27 @@ public: ::std::vector< ::std::pair<std::string, AST::Pattern> > pats_a; ::std::vector< ::std::pair<std::string, AST::Pattern> > pats_b; ::std::vector<AST::ExprNodeP> nodes; - + for( const auto& fld : e.m_fields ) { auto name_a = FMT("a" << fld.m_name); auto name_b = FMT("b" << fld.m_name); pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), name_a, ::AST::PatternBinding::Type::REF)) ); pats_b.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), name_b, ::AST::PatternBinding::Type::REF)) ); - + nodes.push_back(this->make_compare_and_ret( sp, core_name, NEWNODE(NamedValue, AST::Path(name_a)), NEWNODE(NamedValue, AST::Path(name_b)) )); } - + nodes.push_back( this->make_ret_equal(core_name) ); pat_a = AST::Pattern(AST::Pattern::TagStruct(), base_path + v.m_name, mv$(pats_a), true); pat_b = AST::Pattern(AST::Pattern::TagStruct(), base_path + v.m_name, mv$(pats_b), true); code = NEWNODE(Block, mv$(nodes)); ) ) - + ::std::vector< AST::Pattern> pats; { ::std::vector< AST::Pattern> tuple_pats; @@ -770,25 +770,25 @@ public: tuple_pats.push_back( AST::Pattern(AST::Pattern::TagReference(), false, mv$(pat_b)) ); pats.push_back( AST::Pattern(AST::Pattern::TagTuple(), mv$(tuple_pats)) ); } - + arms.push_back(AST::ExprNode_Match_Arm( mv$(pats), nullptr, mv$(code) )); } - + 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 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(), AST::Pattern::Value::make_Named(var_path)); @@ -805,7 +805,7 @@ public: }; ::AST::Pattern pat_a = H::get_pat_nc(base_path, enm.variants()[a]); ::AST::Pattern pat_b = H::get_pat_nc(base_path, enm.variants()[b]); - + ::std::vector< AST::Pattern> pats; { ::std::vector< AST::Pattern> tuple_pats; @@ -813,13 +813,13 @@ public: tuple_pats.push_back( AST::Pattern(AST::Pattern::TagReference(), false, mv$(pat_b)) ); pats.push_back( AST::Pattern(AST::Pattern::TagTuple(), mv$(tuple_pats)) ); } - + auto code = NEWNODE(CallPath, this->get_path(core_name, "option", "Option", "Some"), ::make_vec1( NEWNODE(NamedValue, this->get_path(core_name, "cmp", "Ordering", (a < b ? "Less" : "Greater"))) ) ); - + arms.push_back(AST::ExprNode_Match_Arm( mv$(pats), nullptr, @@ -844,11 +844,11 @@ class Deriver_Eq: AST::Path get_trait_path(const ::std::string& 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<TypeRef> types_to_bound, AST::ExprNodeP node) const { const AST::Path trait_path = this->get_trait_path(core_name); - + AST::Function fcn( sp, AST::GenericParams(), @@ -859,9 +859,9 @@ class Deriver_Eq: ) ); fcn.set_code( NEWNODE(Block, vec$(mv$(node))) ); - + AST::GenericParams params = get_params_with_bounds(sp, p, trait_path, mv$(types_to_bound)); - + AST::Impl rv( AST::ImplDef( sp, AST::MetaItems(), mv$(params), make_spanned(sp, trait_path), type.clone() ) ); rv.add_function(false, false, "assert_receiver_is_total_eq", mv$(fcn)); return mv$(rv); @@ -875,13 +875,13 @@ class Deriver_Eq: AST::ExprNodeP field(const ::std::string& name) const { return NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), name); } - + public: AST::Impl handle_item(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, const AST::Struct& str) const override { const AST::Path assert_method_path = this->get_trait_path(core_name) + "assert_receiver_is_total_eq"; ::std::vector<AST::ExprNodeP> nodes; - + TU_MATCH(AST::StructData, (str.m_data), (e), (Struct, for( const auto& fld : e.ents ) @@ -896,10 +896,10 @@ public: } ) ) - + return this->make_ret(sp, core_name, p, type, this->get_field_bounds(str), NEWNODE(Block, mv$(nodes))); } - + AST::Impl handle_item(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, const AST::Enum& enm) const override { const AST::Path assert_method_path = this->get_trait_path(core_name) + "assert_receiver_is_total_eq"; @@ -907,12 +907,12 @@ public: AST::Path base_path = type.m_data.as_Path().path; base_path.nodes().back().args() = ::AST::PathParams(); ::std::vector<AST::ExprNode_Match_Arm> arms; - + for(const auto& v : enm.variants()) { AST::ExprNodeP code; AST::Pattern pat_a; - + TU_MATCH(::AST::EnumVariantData, (v.m_data), (e), (Value, code = NEWNODE(Block); @@ -921,36 +921,36 @@ public: (Tuple, ::std::vector<AST::Pattern> pats_a; ::std::vector<AST::ExprNodeP> nodes; - + for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ ) { auto name_a = FMT("a" << idx); pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), name_a, ::AST::PatternBinding::Type::REF) ); nodes.push_back( this->assert_is_eq(assert_method_path, NEWNODE(NamedValue, AST::Path(name_a))) ); } - + pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), base_path + v.m_name, mv$(pats_a)); code = NEWNODE(Block, mv$(nodes)); ), (Struct, ::std::vector< ::std::pair<std::string, AST::Pattern> > pats_a; ::std::vector<AST::ExprNodeP> nodes; - + for( const auto& fld : e.m_fields ) { auto name_a = FMT("a" << fld.m_name); pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), name_a, ::AST::PatternBinding::Type::REF)) ); nodes.push_back( this->assert_is_eq(assert_method_path, NEWNODE(NamedValue, AST::Path(name_a))) ); } - + pat_a = AST::Pattern(AST::Pattern::TagStruct(), base_path + v.m_name, mv$(pats_a), true); code = NEWNODE(Block, mv$(nodes)); ) ) - + ::std::vector< AST::Pattern> pats; pats.push_back( AST::Pattern(AST::Pattern::TagReference(), false, mv$(pat_a)) ); - + arms.push_back(AST::ExprNode_Match_Arm( mv$(pats), nullptr, @@ -968,7 +968,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, {}) }); @@ -977,12 +977,12 @@ class Deriver_Ord: { 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<TypeRef> 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", {}) }); - + AST::Function fcn( sp, AST::GenericParams(), @@ -994,14 +994,14 @@ class Deriver_Ord: ) ); fcn.set_code( NEWNODE(Block, vec$(mv$(node))) ); - + AST::GenericParams params = get_params_with_bounds(sp, p, trait_path, mv$(types_to_bound)); - + AST::Impl rv( AST::ImplDef( sp, AST::MetaItems(), mv$(params), make_spanned(sp, trait_path), type.clone() ) ); rv.add_function(false, false, "cmp", mv$(fcn)); return mv$(rv); } - + AST::ExprNodeP make_compare_and_ret(Span sp, const ::std::string& core_name, AST::ExprNodeP v1, AST::ExprNodeP v2) const { return NEWNODE(Match, @@ -1034,7 +1034,7 @@ public: AST::Impl handle_item(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, const AST::Struct& str) const override { ::std::vector<AST::ExprNodeP> nodes; - + TU_MATCH(AST::StructData, (str.m_data), (e), (Struct, for( const auto& fld : e.ents ) @@ -1057,22 +1057,22 @@ public: ) ) nodes.push_back( this->make_ret_equal(core_name) ); - + return this->make_ret(sp, core_name, p, type, this->get_field_bounds(str), NEWNODE(Block, mv$(nodes))); } - + AST::Impl handle_item(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, const AST::Enum& enm) const override { AST::Path base_path = type.m_data.as_Path().path; base_path.nodes().back().args() = ::AST::PathParams(); ::std::vector<AST::ExprNode_Match_Arm> arms; - + for(const auto& v : enm.variants()) { AST::ExprNodeP code; AST::Pattern pat_a; AST::Pattern pat_b; - + TU_MATCH(::AST::EnumVariantData, (v.m_data), (e), (Value, code = this->make_ret_equal(core_name); @@ -1083,20 +1083,20 @@ public: ::std::vector<AST::Pattern> pats_a; ::std::vector<AST::Pattern> pats_b; ::std::vector<AST::ExprNodeP> nodes; - + for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ ) { auto name_a = FMT("a" << idx); auto name_b = FMT("b" << idx); pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), name_a, ::AST::PatternBinding::Type::REF) ); pats_b.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), name_b, ::AST::PatternBinding::Type::REF) ); - + nodes.push_back(this->make_compare_and_ret( sp, core_name, NEWNODE(NamedValue, AST::Path(name_a)), NEWNODE(NamedValue, AST::Path(name_b)) )); } - + nodes.push_back( this->make_ret_equal(core_name) ); pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), base_path + v.m_name, mv$(pats_a)); pat_b = AST::Pattern(AST::Pattern::TagNamedTuple(), base_path + v.m_name, mv$(pats_b)); @@ -1106,27 +1106,27 @@ public: ::std::vector< ::std::pair<std::string, AST::Pattern> > pats_a; ::std::vector< ::std::pair<std::string, AST::Pattern> > pats_b; ::std::vector<AST::ExprNodeP> nodes; - + for( const auto& fld : e.m_fields ) { auto name_a = FMT("a" << fld.m_name); auto name_b = FMT("b" << fld.m_name); pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), name_a, ::AST::PatternBinding::Type::REF)) ); pats_b.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), name_b, ::AST::PatternBinding::Type::REF)) ); - + nodes.push_back(this->make_compare_and_ret( sp, core_name, NEWNODE(NamedValue, AST::Path(name_a)), NEWNODE(NamedValue, AST::Path(name_b)) )); } - + nodes.push_back( this->make_ret_equal(core_name) ); pat_a = AST::Pattern(AST::Pattern::TagStruct(), base_path + v.m_name, mv$(pats_a), true); pat_b = AST::Pattern(AST::Pattern::TagStruct(), base_path + v.m_name, mv$(pats_b), true); code = NEWNODE(Block, mv$(nodes)); ) ) - + ::std::vector< AST::Pattern> pats; { ::std::vector< AST::Pattern> tuple_pats; @@ -1134,25 +1134,25 @@ public: tuple_pats.push_back( AST::Pattern(AST::Pattern::TagReference(), false, mv$(pat_b)) ); pats.push_back( AST::Pattern(AST::Pattern::TagTuple(), mv$(tuple_pats)) ); } - + arms.push_back(AST::ExprNode_Match_Arm( mv$(pats), nullptr, mv$(code) )); } - + 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 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(), AST::Pattern::Value::make_Named(var_path)); @@ -1169,7 +1169,7 @@ public: }; ::AST::Pattern pat_a = H::get_pat_nc(base_path, enm.variants()[a]); ::AST::Pattern pat_b = H::get_pat_nc(base_path, enm.variants()[b]); - + ::std::vector< AST::Pattern> pats; { ::std::vector< AST::Pattern> tuple_pats; @@ -1177,9 +1177,9 @@ public: tuple_pats.push_back( AST::Pattern(AST::Pattern::TagReference(), false, mv$(pat_b)) ); pats.push_back( AST::Pattern(AST::Pattern::TagTuple(), mv$(tuple_pats)) ); } - + auto code = NEWNODE(NamedValue, this->get_path(core_name, "cmp", "Ordering", (a < b ? "Less" : "Greater"))); - + arms.push_back(AST::ExprNode_Match_Arm( mv$(pats), nullptr, @@ -1207,11 +1207,11 @@ class Deriver_Clone: AST::Path get_method_path(const ::std::string& 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<TypeRef> types_to_bound, AST::ExprNodeP node) const { const AST::Path trait_path = this->get_trait_path(core_name); - + AST::Function fcn( sp, AST::GenericParams(), @@ -1222,9 +1222,9 @@ class Deriver_Clone: ) ); fcn.set_code( NEWNODE(Block, vec$(mv$(node))) ); - + AST::GenericParams params = get_params_with_bounds(sp, p, trait_path, mv$(types_to_bound)); - + AST::Impl rv( AST::ImplDef( sp, AST::MetaItems(), mv$(params), make_spanned(sp, trait_path), type.clone() ) ); rv.add_function(false, false, "clone", mv$(fcn)); return mv$(rv); @@ -1244,13 +1244,13 @@ class Deriver_Clone: AST::ExprNodeP field(const ::std::string& name) const { return NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), name); } - + public: AST::Impl handle_item(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, const AST::Struct& str) const override { const AST::Path& ty_path = type.m_data.as_Path().path; ::std::vector<AST::ExprNodeP> nodes; - + TU_MATCH(AST::StructData, (str.m_data), (e), (Struct, ::std::vector< ::std::pair< ::std::string, AST::ExprNodeP> > vals; @@ -1276,21 +1276,21 @@ public: } ) ) - + return this->make_ret(sp, core_name, p, type, this->get_field_bounds(str), NEWNODE(Block, mv$(nodes))); } - + AST::Impl handle_item(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, const AST::Enum& enm) const override { AST::Path base_path = type.m_data.as_Path().path; base_path.nodes().back().args() = ::AST::PathParams(); ::std::vector<AST::ExprNode_Match_Arm> arms; - + for(const auto& v : enm.variants()) { AST::ExprNodeP code; AST::Pattern pat_a; - + TU_MATCH(::AST::EnumVariantData, (v.m_data), (e), (Value, code = NEWNODE(NamedValue, base_path + v.m_name); @@ -1299,36 +1299,36 @@ public: (Tuple, ::std::vector<AST::Pattern> pats_a; ::std::vector<AST::ExprNodeP> nodes; - + for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ ) { auto name_a = FMT("a" << idx); pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), name_a, ::AST::PatternBinding::Type::REF) ); nodes.push_back( this->clone_val_direct(core_name, NEWNODE(NamedValue, AST::Path(name_a))) ); } - + pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), base_path + v.m_name, mv$(pats_a)); code = NEWNODE(CallPath, base_path + v.m_name, mv$(nodes)); ), (Struct, ::std::vector< ::std::pair<std::string, AST::Pattern> > pats_a; ::std::vector< ::std::pair<std::string, AST::ExprNodeP> > vals; - + for( const auto& fld : e.m_fields ) { auto name_a = FMT("a" << fld.m_name); pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), name_a, ::AST::PatternBinding::Type::REF)) ); vals.push_back( ::std::make_pair( fld.m_name, this->clone_val_direct(core_name, NEWNODE(NamedValue, AST::Path(name_a))) ) ); } - + pat_a = AST::Pattern(AST::Pattern::TagStruct(), base_path + v.m_name, mv$(pats_a), true); code = NEWNODE(StructLiteral, base_path + v.m_name, nullptr, mv$(vals)); ) ) - + ::std::vector< AST::Pattern> pats; pats.push_back( AST::Pattern(AST::Pattern::TagReference(), false, mv$(pat_a)) ); - + arms.push_back(AST::ExprNode_Match_Arm( mv$(pats), nullptr, @@ -1349,23 +1349,23 @@ class Deriver_Copy: AST::Path get_trait_path(const ::std::string& 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<TypeRef> types_to_bound, AST::ExprNodeP node) const { const AST::Path trait_path = this->get_trait_path(core_name); - + AST::GenericParams params = get_params_with_bounds(sp, p, trait_path, mv$(types_to_bound)); - + AST::Impl rv( AST::ImplDef( sp, AST::MetaItems(), mv$(params), make_spanned(sp, trait_path), type.clone() ) ); return mv$(rv); } - + public: AST::Impl handle_item(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, const AST::Struct& str) const override { return this->make_ret(sp, core_name, p, type, this->get_field_bounds(str), nullptr); } - + AST::Impl handle_item(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, const AST::Enum& enm) const override { return this->make_ret(sp, core_name, p, type, this->get_field_bounds(enm), nullptr); @@ -1381,11 +1381,11 @@ class Deriver_Default: AST::Path get_method_path(const ::std::string& 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<TypeRef> types_to_bound, AST::ExprNodeP node) const { const AST::Path trait_path = this->get_trait_path(core_name); - + AST::Function fcn( sp, AST::GenericParams(), @@ -1394,9 +1394,9 @@ class Deriver_Default: {} ); fcn.set_code( NEWNODE(Block, vec$(mv$(node))) ); - + AST::GenericParams params = get_params_with_bounds(sp, p, trait_path, mv$(types_to_bound)); - + AST::Impl rv( AST::ImplDef( sp, AST::MetaItems(), mv$(params), make_spanned(sp, trait_path), type.clone() ) ); rv.add_function(false, false, "default", mv$(fcn)); return mv$(rv); @@ -1407,13 +1407,13 @@ class Deriver_Default: {} ); } - + public: AST::Impl handle_item(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, const AST::Struct& str) const override { const AST::Path& ty_path = type.m_data.as_Path().path; ::std::vector<AST::ExprNodeP> nodes; - + TU_MATCH(AST::StructData, (str.m_data), (e), (Struct, ::std::vector< ::std::pair< ::std::string, AST::ExprNodeP> > vals; @@ -1439,10 +1439,10 @@ public: } ) ) - + return this->make_ret(sp, core_name, p, type, this->get_field_bounds(str), NEWNODE(Block, mv$(nodes))); } - + AST::Impl handle_item(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, const AST::Enum& enm) const override { ERROR(sp, E0000, "Default cannot be derived for enums"); @@ -1461,11 +1461,11 @@ class Deriver_Hash: AST::Path get_method_path(const ::std::string& 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<TypeRef> types_to_bound, AST::ExprNodeP node) const { const AST::Path trait_path = this->get_trait_path(core_name); - + AST::Function fcn( sp, AST::GenericParams(), @@ -1483,9 +1483,9 @@ class Deriver_Hash: this->get_trait_path_Hasher(core_name) }) ); fcn.set_code( NEWNODE(Block, vec$(mv$(node))) ); - + AST::GenericParams params = get_params_with_bounds(sp, p, trait_path, mv$(types_to_bound)); - + AST::Impl rv( AST::ImplDef( sp, AST::MetaItems(), mv$(params), make_spanned(sp, trait_path), type.clone() ) ); rv.add_function(false, false, "hash", mv$(fcn)); return mv$(rv); @@ -1502,12 +1502,12 @@ class Deriver_Hash: AST::ExprNodeP field(const ::std::string& name) const { return NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), name); } - + public: AST::Impl handle_item(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, const AST::Struct& str) const override { ::std::vector<AST::ExprNodeP> nodes; - + TU_MATCH(AST::StructData, (str.m_data), (e), (Struct, for( const auto& fld : e.ents ) @@ -1522,24 +1522,24 @@ public: } ) ) - + return this->make_ret(sp, core_name, p, type, this->get_field_bounds(str), NEWNODE(Block, mv$(nodes))); } - + AST::Impl handle_item(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, const AST::Enum& enm) const override { AST::Path base_path = type.m_data.as_Path().path; base_path.nodes().back().args() = ::AST::PathParams(); ::std::vector<AST::ExprNode_Match_Arm> arms; - + for(unsigned int var_idx = 0; var_idx < enm.variants().size(); var_idx ++) { const auto& v = enm.variants()[var_idx]; AST::ExprNodeP code; AST::Pattern pat_a; - + auto var_idx_hash = this->hash_val_ref( core_name, NEWNODE(Integer, var_idx, CORETYPE_UINT) ); - + TU_MATCH(::AST::EnumVariantData, (v.m_data), (e), (Value, code = mv$(var_idx_hash); @@ -1549,14 +1549,14 @@ public: ::std::vector<AST::Pattern> pats_a; ::std::vector<AST::ExprNodeP> nodes; nodes.push_back( mv$(var_idx_hash) ); - + for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ ) { auto name_a = FMT("a" << idx); pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), name_a, ::AST::PatternBinding::Type::REF) ); nodes.push_back( this->hash_val_direct(core_name, NEWNODE(NamedValue, AST::Path(name_a))) ); } - + pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), base_path + v.m_name, mv$(pats_a)); code = NEWNODE(Block, mv$(nodes)); ), @@ -1564,22 +1564,22 @@ public: ::std::vector< ::std::pair<std::string, AST::Pattern> > 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); pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), name_a, ::AST::PatternBinding::Type::REF)) ); nodes.push_back( this->hash_val_direct(core_name, NEWNODE(NamedValue, AST::Path(name_a))) ); } - + pat_a = AST::Pattern(AST::Pattern::TagStruct(), base_path + v.m_name, mv$(pats_a), true); code = NEWNODE(Block, mv$(nodes)); ) ) - + ::std::vector< AST::Pattern> pats; pats.push_back( AST::Pattern(AST::Pattern::TagReference(), false, mv$(pat_a)) ); - + arms.push_back(AST::ExprNode_Match_Arm( mv$(pats), nullptr, @@ -1607,15 +1607,15 @@ class Deriver_RustcEncodable: AST::Path get_method_path() const { 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<TypeRef> 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", {}) }); 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",{}) }) )); - + AST::Function fcn( sp, AST::GenericParams(), @@ -1633,9 +1633,9 @@ class Deriver_RustcEncodable: this->get_trait_path_Encoder() }) ); fcn.set_code( NEWNODE(Block, vec$(mv$(node))) ); - + AST::GenericParams params = get_params_with_bounds(sp, p, trait_path, mv$(types_to_bound)); - + AST::Impl rv( AST::ImplDef( sp, AST::MetaItems(), mv$(params), make_spanned(sp, trait_path), type.clone() ) ); rv.add_function(false, false, "encode", mv$(fcn)); return mv$(rv); @@ -1649,7 +1649,7 @@ class Deriver_RustcEncodable: AST::ExprNodeP field(const ::std::string& name) const { return NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), name); } - + AST::ExprNodeP enc_closure(Span sp, AST::ExprNodeP code) const { return NEWNODE(Closure, vec$( ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "s"), ::TypeRef(sp) ) ), ::TypeRef(sp), @@ -1659,12 +1659,12 @@ class Deriver_RustcEncodable: AST::ExprNodeP get_val_ok(const ::std::string& core_name) const { return NEWNODE(CallPath, AST::Path(core_name, {AST::PathNode("result",{}), AST::PathNode("Result",{}), AST::PathNode("Ok",{})}), vec$( NEWNODE(Tuple, {})) ); } - + public: AST::Impl handle_item(Span sp, const ::std::string& core_name, 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::vector<AST::ExprNodeP> nodes; TU_MATCH(AST::StructData, (str.m_data), (e), (Struct, @@ -1691,7 +1691,7 @@ public: nodes.push_back( this->get_val_ok(core_name) ); auto closure = this->enc_closure( sp, NEWNODE(Block, mv$(nodes)) ); - + ::AST::ExprNodeP node; TU_MATCH(AST::StructData, (str.m_data), (e), (Struct, @@ -1707,22 +1707,22 @@ public: ); ) ) - + return this->make_ret(sp, core_name, p, type, this->get_field_bounds(str), mv$(node)); } - + AST::Impl handle_item(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, const AST::Enum& enm) const override { AST::Path base_path = type.m_data.as_Path().path; base_path.nodes().back().args() = ::AST::PathParams(); ::std::vector<AST::ExprNode_Match_Arm> arms; - + for(unsigned int var_idx = 0; var_idx < enm.variants().size(); var_idx ++) { const auto& v = enm.variants()[var_idx]; AST::ExprNodeP code; AST::Pattern pat_a; - + TU_MATCH(::AST::EnumVariantData, (v.m_data), (e), (Value, code = NEWNODE(CallPath, this->get_trait_path_Encoder() + "emit_enum_variant", @@ -1739,7 +1739,7 @@ public: (Tuple, ::std::vector<AST::Pattern> pats_a; ::std::vector<AST::ExprNodeP> nodes; - + for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ ) { auto name_a = FMT("a" << idx); @@ -1753,7 +1753,7 @@ public: ) ); } nodes.push_back( this->get_val_ok(core_name) ); - + code = NEWNODE(CallPath, this->get_trait_path_Encoder() + "emit_enum_variant", vec$( NEWNODE(NamedValue, AST::Path("s")), @@ -1768,13 +1768,13 @@ public: (Struct, ::std::vector< ::std::pair<std::string, AST::Pattern> > 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) ); pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), 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")), @@ -1786,7 +1786,7 @@ public: idx ++; } nodes.push_back( this->get_val_ok(core_name) ); - + pat_a = AST::Pattern(AST::Pattern::TagStruct(), base_path + v.m_name, mv$(pats_a), true); code = NEWNODE(CallPath, this->get_trait_path_Encoder() + "emit_enum_struct_variant", vec$( @@ -1799,19 +1799,19 @@ public: ); ) ) - + ::std::vector< AST::Pattern> pats; pats.push_back( AST::Pattern(AST::Pattern::TagReference(), false, mv$(pat_a)) ); - + arms.push_back(AST::ExprNode_Match_Arm( mv$(pats), nullptr, mv$(code) )); } - + 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(); 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)) ) @@ -1834,15 +1834,15 @@ class Deriver_RustcDecodable: AST::Path get_method_path() const { 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<TypeRef> 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", {}) }); 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",{}) })) ); - + AST::Function fcn( sp, AST::GenericParams(), @@ -1860,9 +1860,9 @@ class Deriver_RustcDecodable: this->get_trait_path_Decoder() }) ); fcn.set_code( NEWNODE(Block, vec$(mv$(node))) ); - + AST::GenericParams params = get_params_with_bounds(sp, p, trait_path, mv$(types_to_bound)); - + AST::Impl rv( AST::ImplDef( sp, AST::MetaItems(), mv$(params), make_spanned(sp, trait_path), type.clone() ) ); rv.add_function(false, false, "decode", mv$(fcn)); return mv$(rv); @@ -1873,7 +1873,7 @@ class Deriver_RustcDecodable: AST::ExprNodeP field(const ::std::string& name) const { return NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), name); } - + AST::ExprNodeP dec_closure(Span sp, AST::ExprNodeP code) const { return NEWNODE(Closure, vec$( ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "d"), ::TypeRef(sp) ) ), ::TypeRef(sp), @@ -1895,13 +1895,13 @@ class Deriver_RustcDecodable: AST::ExprNodeP get_val_ok_unit(const ::std::string& core_name) const { return get_val_ok(core_name, NEWNODE(Tuple, {})); } - + public: AST::Impl handle_item(Span sp, const ::std::string& core_name, 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(); - + AST::ExprNodeP node_v; TU_MATCH(AST::StructData, (str.m_data), (e), (Struct, @@ -1931,9 +1931,9 @@ public: ) auto closure = this->dec_closure( sp, this->get_val_ok(core_name, mv$(node_v)) ); - + auto args = vec$( NEWNODE(NamedValue, AST::Path("d")), NEWNODE(String, struct_name), AST::ExprNodeP(), mv$(closure) ); - + ::AST::ExprNodeP node; TU_MATCH(AST::StructData, (str.m_data), (e), (Struct, @@ -1947,32 +1947,32 @@ public: node = NEWNODE(CallPath, this->get_trait_path_Decoder() + "read_tuple_struct", mv$(args) ); ) ) - + return this->make_ret(sp, core_name, p, type, this->get_field_bounds(str), mv$(node)); } - + AST::Impl handle_item(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, const AST::Enum& enm) const override { AST::Path base_path = type.m_data.as_Path().path; base_path.nodes().back().args() = ::AST::PathParams(); ::std::vector<AST::ExprNode_Match_Arm> arms; - + // 1. Variant names ::std::vector< AST::ExprNodeP> var_name_strs; - + // 2. Decoding arms for(unsigned int var_idx = 0; var_idx < enm.variants().size(); var_idx ++) { const auto& v = enm.variants()[var_idx]; AST::ExprNodeP code; - + TU_MATCH(::AST::EnumVariantData, (v.m_data), (e), (Value, code = NEWNODE(NamedValue, base_path + v.m_name); ), (Tuple, ::std::vector<AST::ExprNodeP> args; - + for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ ) { auto name_a = FMT("a" << idx); @@ -1988,12 +1988,12 @@ public: ), (Struct, ::std::vector< ::std::pair< ::std::string, AST::ExprNodeP > > vals; - + unsigned int idx = 0; for( const auto& fld : e.m_fields ) { auto name_a = FMT("a" << fld.m_name); - + vals.push_back(::std::make_pair(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")), @@ -2004,14 +2004,14 @@ public: ) ))); idx ++; } - + code = NEWNODE(StructLiteral, base_path + v.m_name, nullptr, mv$(vals) ); ) ) - + ::std::vector< AST::Pattern> pats; pats.push_back( AST::Pattern(AST::Pattern::TagValue(), AST::Pattern::Value::make_Integer({CORETYPE_UINT, var_idx})) ); - + arms.push_back(AST::ExprNode_Match_Arm( mv$(pats), nullptr, @@ -2019,7 +2019,7 @@ public: )); var_name_strs.push_back( NEWNODE(String, v.m_name) ); } - + // Default arm { arms.push_back(AST::ExprNode_Match_Arm( @@ -2028,7 +2028,7 @@ public: this->get_val_err_str(core_name, "enum value unknown") )); } - + auto node_match = NEWNODE(Match, NEWNODE(NamedValue, AST::Path("idx")), mv$(arms)); auto node_var_closure = NEWNODE(Closure, vec$( @@ -2040,7 +2040,7 @@ public: false ); const ::std::string& enum_name = type.m_data.as_Path().path.nodes().back().name(); - + auto node_rev = NEWNODE(CallPath, this->get_trait_path_Decoder() + "read_enum_variant", vec$( NEWNODE(NamedValue, AST::Path("d")), @@ -2048,7 +2048,7 @@ public: mv$( node_var_closure ) ) ); - + auto node = NEWNODE(CallPath, this->get_trait_path_Decoder() + "read_enum", vec$( NEWNODE(NamedValue, AST::Path("d")), NEWNODE(String, enum_name), this->dec_closure(sp, mv$(node_rev)) ) ); @@ -2096,17 +2096,17 @@ static void derive_item(const Span& sp, const AST::Crate& crate, AST::Module& mo //ERROR(sp, E0000, "#[derive()] requires a list of known traits to derive"); return ; } - + DEBUG("path = " << path); bool fail = false; - + const auto& params = item.params(); TypeRef type(sp, path); auto& types_args = type.path().nodes().back().args(); for( const auto& param : params.ty_params() ) { types_args.m_types.push_back( TypeRef(TypeRef::TagArg(), sp, param.name()) ); } - + ::std::vector< ::std::string> missing_handlers; for( const auto& trait : attr.items() ) { @@ -2118,10 +2118,10 @@ static void derive_item(const Span& sp, const AST::Crate& crate, AST::Module& mo fail = true; continue ; } - + mod.add_item(false, "", dp->handle_item(sp, (crate.m_load_std == ::AST::Crate::LOAD_NONE ? "" : "core"), params, type, item), {} ); } - + if( fail ) { ERROR(sp, E0000, "Failed to apply #[derive] - Missing handlers for " << missing_handlers); } diff --git a/src/expand/env.cpp b/src/expand/env.cpp index 8e087858..cad2fa7c 100644 --- a/src/expand/env.cpp +++ b/src/expand/env.cpp @@ -15,7 +15,7 @@ namespace { // Read a string out of the input stream ::std::string get_string(const Span& sp, const AST::Crate& crate, AST::Module& mod, const TokenTree& tt) { auto lex = TTStream(tt); - + auto n = Parse_ExprVal(lex); ASSERT_BUG(sp, n, "No expression returned"); if( lex.lookahead(0) != TOK_EOF ) { @@ -39,7 +39,7 @@ class CExpanderEnv: 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"); @@ -56,7 +56,7 @@ class CExpanderOptionEnv: 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; diff --git a/src/expand/format_args.cpp b/src/expand/format_args.cpp index 9f4eaa93..60c92952 100644 --- a/src/expand/format_args.cpp +++ b/src/expand/format_args.cpp @@ -16,7 +16,7 @@ #include <ast/expr.hpp> // for ExprNode_* namespace { - + /// Options for a formatting fragment struct FmtArgs { @@ -31,20 +31,20 @@ namespace { Plus, Minus, }; - + Align align = Align::Unspec; char align_char = ' '; - + Sign sign = Sign::Unspec; bool alternate = false; bool zero_pad = false; - + bool width_is_arg = false; unsigned int width = 0; - + bool prec_is_arg = false; unsigned int prec = 0; - + bool operator==(const FmtArgs& x) const { return ::std::memcmp(this, &x, sizeof(*this)) == 0; } bool operator!=(const FmtArgs& x) const { #define CMP(f) if(f != x.f) return true @@ -83,25 +83,25 @@ namespace { return os; } }; - + /// A single formatting fragment struct FmtFrag { /// Literal text preceding the fragment ::std::string leading_text; - + /// Argument index used unsigned int arg_index; - + /// Trait to use for formatting const char* trait_name; - + // TODO: Support case where this hasn't been edited (telling the formatter that it has nothing to apply) /// Options FmtArgs args; }; - + class string_view { const char* s; const char* e; @@ -109,16 +109,16 @@ namespace { string_view(const char* s, const char* e): s(s), e(e) {} - + friend ::std::ostream& operator<<(::std::ostream& os, const string_view& x) { for(const char* p = x.s; p != x.e; p++) os << *p; return os; } }; - + /// Parse a format string into a sequence of fragments. - /// + /// /// Returns a list of fragments, and the remaining free text after the last format sequence ::std::tuple< ::std::vector<FmtFrag>, ::std::string> parse_format_string( const Span& sp, @@ -129,10 +129,10 @@ namespace { { unsigned int n_named = named.size(); unsigned int next_free = 0; - + ::std::vector<FmtFrag> frags; ::std::string cur_literal; - + const char* s = format_string.c_str(); for( ; *s; s ++) { @@ -155,17 +155,17 @@ namespace { cur_literal += '{'; continue ; } - + // Debugging: A view of the formatting fragment const char* s2 = s; while(*s2 && *s2 != '}') s2 ++; auto fmt_frag_str = string_view { s, s2 }; - + unsigned int index = ~0u; const char* trait_name; FmtArgs args; - + // Formatting parameter if( *s != ':' && *s != '}' ) { // Parse either an integer or an identifer @@ -197,11 +197,11 @@ namespace { // - If index is ~0u at the end of this block, it's set to the next arg // - This allows {:.*} to format correctly (taking <prec> then <arg>) } - + // If next character is ':', parse extra information if( *s == ':' ) { s ++; // eat ':' - + // Alignment if( s[0] != '\0' && (s[1] == '<' || s[1] == '^' || s[1] == '>') ) { args.align_char = s[0]; @@ -222,7 +222,7 @@ namespace { else { //args.align = FmtArgs::Align::Unspec; } - + // Sign if( *s == '+' ) { args.sign = FmtArgs::Sign::Plus; @@ -235,7 +235,7 @@ namespace { else { args.sign = FmtArgs::Sign::Unspec; } - + if( *s == '#' ) { args.alternate = true; s ++; @@ -243,7 +243,7 @@ namespace { else { //args.alternate = false; } - + if( *s == '0' ) { args.zero_pad = true; s ++; @@ -251,7 +251,7 @@ namespace { else { //args.zero_pad = false; } - + // Padded width if( ::std::isdigit(*s) /*|| *s == '*'*/ ) { unsigned int val = 0; @@ -262,7 +262,7 @@ namespace { s ++; } args.width = val; - + if( *s == '$' ) { args.width_is_arg = true; s ++; @@ -287,7 +287,7 @@ namespace { ERROR(sp, E0000, "Named argument '"<<ident<<"' not found"); args.width = n_free + it->second; args.width_is_arg = true; - + s ++; } else { @@ -317,7 +317,7 @@ namespace { s ++; } args.prec = val; - + if( *s == '$' ) { args.prec_is_arg = true; s ++; @@ -330,13 +330,13 @@ namespace { // Wut? } } - + // 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)"); } - + switch(s[0]) { case '\0': @@ -361,7 +361,7 @@ namespace { // Otherwise, it's just a trivial Display call trait_name = "Display"; } - + // Set index if unspecified if( index == ~0u ) { @@ -371,7 +371,7 @@ namespace { index = next_free + n_named; next_free ++; } - + frags.push_back( FmtFrag { mv$(cur_literal), index, trait_name, @@ -379,7 +379,7 @@ namespace { }); } } - + return ::std::make_tuple( mv$(frags), mv$(cur_literal) ); } } @@ -414,11 +414,11 @@ class CFormatArgsExpander: ::std::unique_ptr<TokenStream> expand(const Span& sp, const ::AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override { Token tok; - + auto lex = TTStream(tt); 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); @@ -429,11 +429,11 @@ class CFormatArgsExpander: } 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::vector<TokenTree> named_args; ::std::vector<TokenTree> free_args; - + // - Parse the arguments while( GET_TOK(tok, lex) == TOK_COMMA ) { @@ -441,17 +441,17 @@ class CFormatArgsExpander: GET_TOK(tok, lex); break; } - + // - Named parameters if( lex.lookahead(0) == TOK_IDENT && lex.lookahead(1) == TOK_EQUAL ) { GET_CHECK_TOK(tok, lex, TOK_IDENT); auto name = mv$(tok.str()); - + GET_CHECK_TOK(tok, lex, TOK_EQUAL); - + auto expr_tt = TokenTree(Token( InterpolatedFragment(InterpolatedFragment::EXPR, Parse_Expr0(lex).release()) )); - + auto ins_rv = named_args_index.insert( ::std::make_pair(mv$(name), named_args.size()) ); if( ins_rv.second == false ) { ERROR(sp, E0000, "Duplicate definition of named argument `" << ins_rv.first->first << "`"); @@ -466,12 +466,12 @@ class CFormatArgsExpander: } } CHECK_TOK(tok, TOK_EOF); - + // - Parse the format string ::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()); - + bool is_simple = true; for(unsigned int i = 0; i < fragments.size(); i ++) { @@ -484,7 +484,7 @@ class CFormatArgsExpander: is_simple = false; } } - + ::std::vector<TokenTree> toks; // This should expand to a `match (a, b, c) { (ref _0, ref _1, ref _2) => ... }` to ensure that the values live long enough? // - Also avoids name collisions @@ -513,7 +513,7 @@ class CFormatArgsExpander: toks.push_back( TokenTree(TOK_PAREN_CLOSE) ); toks.push_back( TokenTree(TOK_FATARROW) ); toks.push_back( TokenTree(TOK_BRACE_OPEN) ); - + // Save fragments into a static // `static FRAGMENTS: [&'static str; N] = [...];` // - Contains N+1 entries, where N is the number of fragments @@ -521,7 +521,7 @@ class CFormatArgsExpander: toks.push_back( TokenTree(TOK_RWORD_STATIC) ); toks.push_back( Token(TOK_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") ); @@ -529,9 +529,9 @@ class CFormatArgsExpander: toks.push_back( Token(TOK_SEMICOLON) ); toks.push_back( Token(fragments.size() + 1, CORETYPE_UINT) ); toks.push_back( TokenTree(TOK_SQUARE_CLOSE) ); - + toks.push_back( Token(TOK_EQUAL) ); - + toks.push_back( TokenTree(TOK_SQUARE_OPEN) ); for(const auto& frag : fragments ) { toks.push_back( Token(TOK_STRING, frag.leading_text) ); @@ -539,10 +539,10 @@ class CFormatArgsExpander: } toks.push_back( Token(TOK_STRING, tail) ); toks.push_back( TokenTree(TOK_SQUARE_CLOSE) ); - + toks.push_back( Token(TOK_SEMICOLON) ); } - + if( is_simple ) { // ::fmt::Arguments::new_v1 @@ -553,7 +553,7 @@ class CFormatArgsExpander: toks.push_back( TokenTree(TOK_AMP) ); toks.push_back( Token(TOK_IDENT, "FRAGMENTS") ); toks.push_back( TokenTree(TOK_COMMA) ); - + toks.push_back( TokenTree(TOK_AMP) ); toks.push_back( TokenTree(TOK_SQUARE_OPEN) ); for(const auto& frag : fragments ) @@ -561,9 +561,9 @@ class CFormatArgsExpander: 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( TokenTree(TOK_COMMA) ); - + push_path(toks, crate, {"fmt", frag.trait_name, "fmt"}); toks.push_back( TokenTree(TOK_PAREN_CLOSE) ); toks.push_back( TokenTree(TOK_COMMA) ); @@ -585,9 +585,9 @@ class CFormatArgsExpander: toks.push_back( TokenTree(TOK_AMP) ); toks.push_back( Token(TOK_IDENT, "FRAGMENTS") ); toks.push_back( TokenTree(TOK_COMMA) ); - + // 1. Generate a set of arguments+formatters - + // TODO: Fragments to format // - The format stored by mrustc doesn't quite work with how rustc (and fmt::rt::v1) works toks.push_back( TokenTree(TOK_AMP) ); @@ -599,10 +599,10 @@ class CFormatArgsExpander: // ) toks.push_back( TokenTree(TOK_PAREN_CLOSE) ); } // if(is_simple) else - + toks.push_back( TokenTree(TOK_BRACE_CLOSE) ); toks.push_back( TokenTree(TOK_BRACE_CLOSE) ); - + return box$( TTStreamO(TokenTree(Ident::Hygiene::new_scope(), mv$(toks))) ); } }; diff --git a/src/expand/include.cpp b/src/expand/include.cpp index 83a2aa03..6b1a5508 100644 --- a/src/expand/include.cpp +++ b/src/expand/include.cpp @@ -22,7 +22,7 @@ namespace { return base_path + path; } else { - + auto slash = base_path.find_last_of('/'); if( slash == ::std::string::npos ) { @@ -48,17 +48,17 @@ class CIncludeExpander: { if( ident != "" ) ERROR(sp, E0000, "include! doesn't take an ident"); - + Token tok; auto lex = TTStream(tt); - + // TODO: Parse+expand GET_CHECK_TOK(tok, lex, TOK_STRING); auto path = mv$(tok.str()); GET_CHECK_TOK(tok, lex, TOK_EOF); - + ::std::string file_path = get_path_relative_to(mod.m_file_info.path, mv$(path)); - + return box$( Lexer(file_path) ); } }; diff --git a/src/expand/lang_item.cpp b/src/expand/lang_item.cpp index 1e3564c2..83637bf6 100644 --- a/src/expand/lang_item.cpp +++ b/src/expand/lang_item.cpp @@ -37,10 +37,10 @@ void handle_lang_item(const Span& sp, AST::Crate& crate, const AST::Path& path, else if( name == "mul" ) { DEBUG("Bind '"<<name<<"' to " << path); } else if( name == "div" ) { DEBUG("Bind '"<<name<<"' to " << path); } else if( name == "rem" ) { DEBUG("Bind '"<<name<<"' to " << path); } - + else if( name == "neg" ) { DEBUG("Bind '"<<name<<"' to " << path); } else if( name == "not" ) { DEBUG("Bind '"<<name<<"' to " << path); } - + else if( name == "bitand" ) { DEBUG("Bind '"<<name<<"' to " << path); } else if( name == "bitor" ) { DEBUG("Bind '"<<name<<"' to " << path); } else if( name == "bitxor" ) { DEBUG("Bind '"<<name<<"' to " << path); } @@ -57,7 +57,7 @@ void handle_lang_item(const Span& sp, AST::Crate& crate, const AST::Path& path, else if( name == "bitxor_assign" ) { DEBUG("Bind '"<<name<<"' to " << path); } else if( name == "shl_assign" ) { DEBUG("Bind '"<<name<<"' to " << path); } else if( name == "shr_assign" ) { DEBUG("Bind '"<<name<<"' to " << path); } - + else if( name == "index" ) { DEBUG("Bind '"<<name<<"' to " << path); } else if( name == "deref" ) { DEBUG("Bind '"<<name<<"' to " << path); } else if( name == "index_mut" ) { DEBUG("Bind '"<<name<<"' to " << path); } @@ -65,16 +65,16 @@ void handle_lang_item(const Span& sp, AST::Crate& crate, const AST::Path& path, else if( name == "fn" ) { DEBUG("Bind '"<<name<<"' to " << path); } else if( name == "fn_mut" ) { DEBUG("Bind '"<<name<<"' to " << path); } else if( name == "fn_once" ) { DEBUG("Bind '"<<name<<"' to " << path); } - + else if( name == "eq" ) { DEBUG("Bind '"<<name<<"' to " << path); } else if( name == "ord" ) { DEBUG("Bind '"<<name<<"' to " << path); } else if( name == "unsize" ) { DEBUG("Bind '"<<name<<"' to " << path); } else if( name == "coerce_unsized" ) { DEBUG("Bind '"<<name<<"' to " << path); } - + else if( name == "iterator" ) { /* mrustc just desugars? */ } - + else if( name == "debug_trait" ) { /* TODO: Poke derive() with this */ } - + // Structs else if( name == "non_zero" ) { } else if( name == "phantom_data" ) { } @@ -83,12 +83,12 @@ void handle_lang_item(const Span& sp, AST::Crate& crate, const AST::Path& path, else if( name == "range_from" ) { } else if( name == "range_to" ) { } else if( name == "unsafe_cell" ) { } - + // Functions else if( name == "panic" ) { } else if( name == "panic_bounds_check" ) { } else if( name == "panic_fmt" ) { - + } else if( name == "str_eq" ) { } // - builtin `box` support @@ -98,9 +98,9 @@ void handle_lang_item(const Span& sp, AST::Crate& crate, const AST::Path& path, else if( name == "owned_box" ) { } // - start else if( name == "start" ) { } - + else if( name == "eh_personality" ) { } - + else { ERROR(sp, E0000, "Unknown language item '" << name << "'"); } @@ -145,10 +145,10 @@ public: ) ) } - + void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate, const AST::Module& mod, AST::ImplDef& impl) const override { const ::std::string& name = mi.string(); - + if( name == "i8" ) {} else if( name == "u8" ) {} else if( name == "i16" ) {} @@ -172,7 +172,7 @@ public: else { ERROR(sp, E0000, "Unknown lang item '" << name << "' on impl"); } - + // TODO: Somehow annotate these impls to allow them to provide inherents? // - mrustc is lazy and inefficient, so these don't matter :) } diff --git a/src/expand/macro_rules.cpp b/src/expand/macro_rules.cpp index 638b9ddd..338edd12 100644 --- a/src/expand/macro_rules.cpp +++ b/src/expand/macro_rules.cpp @@ -26,12 +26,12 @@ class CMacroRulesExpander: { if( ident == "" ) ERROR(sp, E0000, "macro_rules! requires an identifier" ); - + DEBUG("Parsing macro_rules! " << ident); TTStream lex(tt); auto mac = Parse_MacroRules(lex); mod.add_macro( false, ident, mv$(mac) ); - + return ::std::unique_ptr<TokenStream>( new TTStreamO(TokenTree()) ); } }; @@ -40,11 +40,11 @@ class CMacroUseHandler: public ExpandDecorator { AttrStage stage() const override { return AttrStage::Post; } - + void handle(const Span& sp, const AST::MetaItem& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item& i) const override { TRACE_FUNCTION_F("path=" << path); - + TU_IFLET( ::AST::Item, i, None, e, // Just ignore ) @@ -107,14 +107,14 @@ class CMacroUseHandler: ERROR(sp, E0000, "Use of #[macro_use] on non-module/crate - " << i.tag_str()); } } - + }; class CMacroExportHandler: public ExpandDecorator { AttrStage stage() const override { return AttrStage::Post; } - + void handle(const Span& sp, const AST::MetaItem& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item& i) const override { if( i.is_None() ) { @@ -125,7 +125,7 @@ class CMacroExportHandler: ERROR(sp, E0000, "#[macro_export] is only valid on macro_rules!"); } const auto& name = mac.input_ident(); - + // Tag the macro in the module for crate export auto it = ::std::find_if( mod.macros().begin(), mod.macros().end(), [&](const auto& x){ return x.name == name; } ); ASSERT_BUG(sp, it != mod.macros().end(), "Macro '" << name << "' not defined in this module"); @@ -150,7 +150,7 @@ class CMacroReexportHandler: const auto& crate_name = i.as_Crate().name; auto& ext_crate = *crate.m_extern_crates.at(crate_name).m_hir; - + if( mi.has_sub_items() ) { for( const auto& si : mi.items() ) diff --git a/src/expand/mod.cpp b/src/expand/mod.cpp index ab016b95..a2537218 100644 --- a/src/expand/mod.cpp +++ b/src/expand/mod.cpp @@ -82,7 +82,7 @@ void Expand_Attrs(::AST::MetaItems& attrs, AttrStage stage, ::AST::Crate& crate if( name == "" ) { return ::std::unique_ptr<TokenStream>(); } - + for( const auto& m : g_macros ) { if( name == m.first ) @@ -91,8 +91,8 @@ void Expand_Attrs(::AST::MetaItems& attrs, AttrStage stage, ::AST::Crate& crate return e; } } - - + + // Iterate up the module tree, using the first located macro for(const auto* ll = &modstack; ll; ll = ll->m_prev) { @@ -104,7 +104,7 @@ void Expand_Attrs(::AST::MetaItems& attrs, AttrStage stage, ::AST::Crate& crate { if( input_ident != "" ) ERROR(mi_span, E0000, "macro_rules! macros can't take an ident"); - + auto e = Macro_Invoke(name.c_str(), *mr.data, mv$(input_tt), mod); return e; } @@ -117,13 +117,13 @@ void Expand_Attrs(::AST::MetaItems& attrs, AttrStage stage, ::AST::Crate& crate { if( input_ident != "" ) ERROR(mi_span, E0000, "macro_rules! macros can't take an ident"); - + auto e = Macro_Invoke(name.c_str(), *mri.data, mv$(input_tt), mod); return e; } } } - + // Error - Unknown macro name ERROR(mi_span, E0000, "Unknown macro '" << name << "'"); } @@ -139,7 +139,7 @@ void Expand_Pattern(::AST::Crate& crate, LList<const AST::Module*> modstack, ::A ), (Macro, const auto span = e.inv->span(); - + auto tt = Expand_Macro(crate, modstack, mod, *e.inv); if( ! tt ) { ERROR(span, E0000, "Macro in pattern didn't expand to anything"); @@ -149,13 +149,13 @@ void Expand_Pattern(::AST::Crate& crate, LList<const AST::Module*> modstack, ::A if( LOOK_AHEAD(lex) != TOK_EOF ) { ERROR(span, E0000, "Trailing tokens in macro expansion"); } - + if( pat.binding().is_valid() ) { - if( newpat.binding().is_valid() ) + if( newpat.binding().is_valid() ) ERROR(span, E0000, "Macro expansion provided a binding, but one already present"); newpat.binding() = mv$(pat.binding()); } - + pat = mv$(newpat); ), (Any, @@ -218,7 +218,7 @@ void Expand_Type(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST: if( tt->lookahead(0) != TOK_EOF ) ERROR(e.inv.span(), E0000, "Extra tokens after parsed type"); ty = mv$(new_ty); - + Expand_Type(crate, modstack, mod, ty); ), (Primitive, @@ -263,19 +263,19 @@ struct CExpandExpr: ::AST::Crate& crate; LList<const AST::Module*> modstack; ::std::unique_ptr<::AST::ExprNode> replacement; - + AST::ExprNode_Block* current_block = nullptr; - + CExpandExpr(::AST::Crate& crate, LList<const AST::Module*> ms): crate(crate), modstack(ms) { } - + ::AST::Module& cur_mod() { return *const_cast< ::AST::Module*>(modstack.m_item); } - + void visit(::std::unique_ptr<AST::ExprNode>& cnode) { if(cnode.get()) Expand_Attrs(cnode->attrs(), AttrStage::Pre, [&](const auto& sp, const auto& d, const auto& a){ d.handle(sp, a, this->crate, cnode); }); @@ -292,7 +292,7 @@ struct CExpandExpr: cnode = mv$(this->replacement); } } - + if(cnode.get()) Expand_Attrs(cnode->attrs(), AttrStage::Post, [&](const auto& sp, const auto& d, const auto& a){ d.handle(sp, a, this->crate, cnode); }); assert( ! this->replacement ); @@ -320,14 +320,14 @@ struct CExpandExpr: } } } - + void visit(::AST::ExprNode_Macro& node) override { TRACE_FUNCTION_F("ExprNode_Macro - name = " << node.m_name); if( node.m_name == "" ) { return ; } - + auto& mod = this->cur_mod(); auto ttl = Expand_Macro( crate, modstack, mod, @@ -365,7 +365,7 @@ struct CExpandExpr: node.m_name = ""; } } - + void visit(::AST::ExprNode_Block& node) override { unsigned int mod_item_count = 0; // TODO: macro_rules! invocations within the expression list influence this. @@ -374,7 +374,7 @@ struct CExpandExpr: Expand_Mod(crate, modstack, node.m_local_mod->path(), *node.m_local_mod); mod_item_count = node.m_local_mod->items().size(); } - + auto saved = this->current_block; this->current_block = &node; this->visit_vector(node.m_nodes); @@ -444,7 +444,7 @@ struct CExpandExpr: nullptr, ::AST::ExprNodeP(new ::AST::ExprNode_Flow(::AST::ExprNode_Flow::BREAK, node.m_label, nullptr)) ) ); - + replacement.reset(new ::AST::ExprNode_Match( ::AST::ExprNodeP(new ::AST::ExprNode_CallPath( ::AST::Path(::AST::Path::TagUfcs(), ::TypeRef(node.span()), path_IntoIterator, { ::AST::PathNode("into_iter") } ), @@ -563,7 +563,7 @@ 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()) ); - + // Desugars into // ``` // match `m_value` { @@ -571,7 +571,7 @@ struct CExpandExpr: // Err(e) => return Err(From::from(e)), // } // ``` - + ::std::vector< ::AST::ExprNode_Match_Arm> arms; // `Ok(v) => v,` arms.push_back(::AST::ExprNode_Match_Arm( @@ -637,23 +637,23 @@ void Expand_Impl(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST: DEBUG("Deleted"); return ; } - + Expand_Type(crate, modstack, mod, impl.def().type()); //Expand_Type(crate, modstack, mod, impl.def().trait()); - + DEBUG("> Items"); for( unsigned int idx = 0; idx < impl.items().size(); idx ++ ) { auto& i = impl.items()[idx]; DEBUG(" - " << i.name << " :: " << i.data->attrs); - + // TODO: Make a path from the impl definition? Requires having the impl def resolved to be correct // - Does it? the namespace is essentially the same. There may be issues with wherever the path is used though //::AST::Path path = modpath + i.name; - + auto attrs = mv$(i.data->attrs); Expand_Attrs(attrs, AttrStage::Pre, crate, AST::Path(), mod, *i.data); - + TU_MATCH_DEF(AST::Item, (*i.data), (e), ( throw ::std::runtime_error("BUG: Unknown item type in impl block"); @@ -665,7 +665,7 @@ void Expand_Impl(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST: 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() ) @@ -697,7 +697,7 @@ void Expand_Impl(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST: Expand_Type(crate, modstack, mod, e.type()); ) ) - + // Run post-expansion decorators and restore attributes { auto& i = impl.items()[idx]; @@ -717,7 +717,7 @@ void Expand_ImplDef(::AST::Crate& crate, LList<const AST::Module*> modstack, ::A DEBUG("Deleted"); return ; } - + Expand_Type(crate, modstack, mod, impl_def.type()); //Expand_Type(crate, modstack, mod, impl_def.trait()); @@ -727,10 +727,10 @@ void Expand_ImplDef(::AST::Crate& crate, LList<const AST::Module*> modstack, ::A void Expand_Mod(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST::Path modpath, ::AST::Module& mod, unsigned int first_item) { TRACE_FUNCTION_F("modpath = " << modpath); - + for( const auto& mi: mod.macro_imports_res() ) DEBUG("- Imports '" << mi.name << "'"); - + // Insert prelude if: Enabled for this module, present for the crate, and this module is not an anon if( crate.m_prelude_path != AST::Path() ) { @@ -738,20 +738,20 @@ void Expand_Mod(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST:: mod.add_alias(false, ::AST::UseStmt(Span(), crate.m_prelude_path), "", {}); } } - + DEBUG("Items"); for( unsigned int idx = first_item; idx < mod.items().size(); idx ++ ) { auto& i = mod.items()[idx]; - + DEBUG("- " << i.name << " (" << ::AST::Item::tag_to_str(i.data.tag()) << ") :: " << i.data.attrs); ::AST::Path path = modpath + i.name; - + auto attrs = mv$(i.data.attrs); Expand_Attrs(attrs, AttrStage::Pre, crate, path, mod, i.data); - + auto dat = mv$(i.data); - + TU_MATCH(::AST::Item, (dat), (e), (None, // Skip, nothing @@ -759,9 +759,9 @@ void Expand_Mod(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST:: (MacroInv, // Move out of the module to avoid invalidation if a new macro invocation is added auto mi_owned = mv$(e); - + TRACE_FUNCTION_F("Macro invoke " << mi_owned.name()); - + auto ttl = Expand_Macro(crate, modstack, mod, mi_owned); assert( mi_owned.name() != ""); @@ -805,7 +805,7 @@ void Expand_Mod(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST:: (Crate, // Can't recurse into an `extern crate` ), - + (Struct, TU_MATCH(AST::StructData, (e.m_data), (sd), (Struct, @@ -883,7 +883,7 @@ void Expand_Mod(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST:: { 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"); @@ -905,7 +905,7 @@ void Expand_Mod(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST:: Expand_Type(crate, modstack, mod, e.type()); ) ) - + Expand_Attrs(attrs, AttrStage::Post, crate, AST::Path(), mod, ti.data); if( ti.data.attrs.m_items.size() == 0 ) ti.data.attrs = mv$(attrs); @@ -914,7 +914,7 @@ void Expand_Mod(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST:: (Type, Expand_Type(crate, modstack, mod, e.type()); ), - + (Function, for(auto& arg : e.args()) { Expand_Pattern(crate, modstack, mod, arg.first, false); @@ -929,9 +929,9 @@ void Expand_Mod(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST:: ) ) Expand_Attrs(attrs, AttrStage::Post, crate, path, mod, dat); - + { - + auto& i = mod.items()[idx]; if( i.data.tag() == ::AST::Item::TAGDEAD ) { i.data = mv$(dat); @@ -941,26 +941,26 @@ void Expand_Mod(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST:: i.data.attrs = mv$(attrs); } } - + // IGNORE m_anon_modules, handled as part of expressions - + //for( const auto& mi: mod.macro_imports_res() ) // DEBUG("- Imports '" << mi.name << "'"); } void Expand_Mod_IndexAnon(::AST::Crate& crate, ::AST::Module& mod) { TRACE_FUNCTION_F("mod=" << mod.path()); - + for(auto& i : mod.items()) { DEBUG("- " << i.data.tag_str() << " '" << i.name << "'"); TU_IFLET(::AST::Item, (i.data), Module, e, Expand_Mod_IndexAnon(crate, e); - + // TODO: Also ensure that all #[macro_export] macros end up in parent ) } - + for( auto& mp : mod.anon_mods() ) { if( mp.unique() ) { @@ -975,10 +975,10 @@ void Expand_Mod_IndexAnon(::AST::Crate& crate, ::AST::Module& mod) void Expand(::AST::Crate& crate) { auto modstack = LList<const ::AST::Module*>(nullptr, &crate.m_root_module); - + // 1. Crate attributes Expand_Attrs(crate.m_attrs, AttrStage::Pre, [&](const auto& sp, const auto& d, const auto& a){ d.handle(sp, a, crate); }); - + // Insert magic for libstd/libcore // NOTE: The actual crates are loaded in "LoadCrates" using magic in AST::Crate::load_externs switch( crate.m_load_std ) @@ -1002,7 +1002,7 @@ void Expand(::AST::Crate& crate) case ::AST::Crate::LOAD_NONE: break; } - + // 2. Module attributes for( auto& a : crate.m_attrs.m_items ) { @@ -1012,10 +1012,10 @@ void Expand(::AST::Crate& crate) } } } - + // 3. Module tree Expand_Mod(crate, modstack, ::AST::Path("",{}), crate.m_root_module); - + // Post-process Expand_Mod_IndexAnon(crate, crate.m_root_module); #if 0 diff --git a/src/expand/rustc_diagnostics.cpp b/src/expand/rustc_diagnostics.cpp index 917a5e4d..f2e436c4 100644 --- a/src/expand/rustc_diagnostics.cpp +++ b/src/expand/rustc_diagnostics.cpp @@ -34,16 +34,16 @@ class CExpanderBuildDiagnosticArray: if( ident != "" ) ERROR(sp, E0000, "__build_diagnostic_array! doesn't take an ident"); auto lex = TTStream(tt); - + Token tok; - + GET_CHECK_TOK(tok, lex, TOK_IDENT); //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()); GET_CHECK_TOK(tok, lex, TOK_EOF); - + ::std::vector<TokenTree> toks; toks.push_back( TOK_RWORD_STATIC ); toks.push_back( Token(TOK_IDENT, item_name) ); @@ -63,7 +63,7 @@ class CExpanderBuildDiagnosticArray: toks.push_back( TOK_SQUARE_OPEN ); toks.push_back( TOK_SQUARE_CLOSE ); toks.push_back( TOK_SEMICOLON ); - + return box$( TTStreamO(TokenTree( lex.getHygiene(), mv$(toks) )) ); } }; diff --git a/src/expand/std_prelude.cpp b/src/expand/std_prelude.cpp index 81eecf7f..16c4ce90 100644 --- a/src/expand/std_prelude.cpp +++ b/src/expand/std_prelude.cpp @@ -8,7 +8,7 @@ class Decorator_NoStd: { public: AttrStage stage() const override { return AttrStage::Pre; } - + void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate) const override { if( crate.m_load_std != AST::Crate::LOAD_STD ) { ERROR(sp, E0000, "Invalid use of #![no_std] with itself or #![no_core]"); @@ -21,7 +21,7 @@ class Decorator_NoCore: { public: AttrStage stage() const override { return AttrStage::Pre; } - + void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate) const override { if( crate.m_load_std != AST::Crate::LOAD_STD ) { ERROR(sp, E0000, "Invalid use of #![no_core] with itself or #![no_std]"); @@ -41,7 +41,7 @@ class Decorator_NoPrelude: { public: AttrStage stage() const override { return AttrStage::Pre; } - + void handle(const Span& sp, const AST::MetaItem& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item&i) const override { if( i.is_Module() ) { i.as_Module().m_insert_prelude = false; @@ -57,7 +57,7 @@ class Decorator_PreludeImport: { public: AttrStage stage() const override { return AttrStage::Post; } - + void handle(const Span& sp, const AST::MetaItem& 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; diff --git a/src/expand/stringify.cpp b/src/expand/stringify.cpp index ce16847b..f43d896f 100644 --- a/src/expand/stringify.cpp +++ b/src/expand/stringify.cpp @@ -16,14 +16,14 @@ class CExpander: { Token tok; ::std::string rv; - + auto lex = TTStream(tt); while( GET_TOK(tok, lex) != TOK_EOF ) { rv += tok.to_str(); rv += " "; } - + return box$( TTStreamO(TokenTree(Token(TOK_STRING, mv$(rv)))) ); } }; diff --git a/src/expand/test.cpp b/src/expand/test.cpp index ba18fd24..fba6556f 100644 --- a/src/expand/test.cpp +++ b/src/expand/test.cpp @@ -12,12 +12,12 @@ class CTestHandler: public ExpandDecorator { AttrStage stage() const override { return AttrStage::Pre; } - + void handle(const Span& sp, const AST::MetaItem& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item&i) const override { if( ! i.is_Function() ) { ERROR(sp, E0000, "#[test] can only be put on functions - found on " << i.tag_str()); } - + // TODO: Proper #[test] support, for now just remove them i = AST::Item::make_None({}); } diff --git a/src/hir/crate_ptr.hpp b/src/hir/crate_ptr.hpp index ad6f374e..c870b1ea 100644 --- a/src/hir/crate_ptr.hpp +++ b/src/hir/crate_ptr.hpp @@ -10,7 +10,7 @@ class Crate; class CratePtr { Crate* m_ptr; - + public: CratePtr(); CratePtr(Crate c); @@ -27,7 +27,7 @@ public: return *this; } ~CratePtr(); - + Crate& operator*() { return *m_ptr; } const Crate& operator*() const { return *m_ptr; } Crate* operator->() { return m_ptr; } diff --git a/src/hir/deserialise.cpp b/src/hir/deserialise.cpp index 7b821630..de0d13da 100644 --- a/src/hir/deserialise.cpp +++ b/src/hir/deserialise.cpp @@ -14,12 +14,12 @@ #include "serialise_lowlevel.hpp" namespace { - + template<typename T> struct D { }; - + class HirDeserialiser { const ::std::string& m_crate_name; @@ -29,10 +29,10 @@ namespace { m_crate_name( crate_name ), m_in(in) {} - + ::std::string read_string() { return m_in.read_string(); } size_t deserialise_count() { return m_in.read_count(); } - + template<typename V> ::std::map< ::std::string,V> deserialise_strmap() { @@ -74,7 +74,7 @@ namespace { } return rv; } - + template<typename T> ::std::vector<T> deserialise_vec() { @@ -100,13 +100,13 @@ namespace { { return ::HIR::VisEnt<T> { m_in.read_bool(), D<T>::des(*this) }; } - + template<typename T> ::std::unique_ptr<T> deserialise_ptr() { return box$( D<T>::des(*this) ); } - - + + ::HIR::TypeRef deserialise_type(); ::HIR::SimplePath deserialise_simplepath(); ::HIR::PathParams deserialise_pathparams(); @@ -117,18 +117,18 @@ namespace { ::HIR::GenericParams deserialise_genericparams(); ::HIR::TypeParamDef deserialise_typaramdef(); ::HIR::GenericBound deserialise_genericbound(); - + ::HIR::Crate deserialise_crate(); ::HIR::Module deserialise_module(); - + ::HIR::TypeImpl deserialise_typeimpl() { ::HIR::TypeImpl rv; TRACE_FUNCTION_FR("", "impl" << rv.m_params.fmt_args() << " " << rv.m_type); - + rv.m_params = deserialise_genericparams(); rv.m_type = deserialise_type(); - + size_t method_count = m_in.read_count(); for(size_t i = 0; i < method_count; i ++) { @@ -152,12 +152,12 @@ namespace { { ::HIR::TraitImpl rv; TRACE_FUNCTION_FR("", "impl" << rv.m_params.fmt_args() << " ?" << rv.m_trait_args << " for " << rv.m_type); - + rv.m_params = deserialise_genericparams(); rv.m_trait_args = deserialise_pathparams(); rv.m_type = deserialise_type(); - - + + size_t method_count = m_in.read_count(); for(size_t i = 0; i < method_count; i ++) { @@ -190,7 +190,7 @@ namespace { m_in.read_bool(), deserialise_type() } ) ); } - + // m_src_module doesn't matter after typeck return rv; } @@ -203,7 +203,7 @@ namespace { deserialise_type() }; } - + ::MacroRulesPtr deserialise_macrorulesptr() { return ::MacroRulesPtr( new MacroRules(deserialise_macrorules()) ); @@ -284,7 +284,7 @@ namespace { throw ""; } } - + ::Token deserialise_token() { ::Token tok; // HACK: Hand off to old serialiser code @@ -298,7 +298,7 @@ namespace { } ::HIR::Literal deserialise_literal(); - + ::HIR::ExprPtr deserialise_exprptr() { ::HIR::ExprPtr rv; @@ -314,7 +314,7 @@ namespace { ::MIR::Statement deserialise_mir_statement(); ::MIR::Terminator deserialise_mir_terminator(); ::MIR::CallTarget deserialise_mir_calltarget(); - + ::MIR::LValue deserialise_mir_lvalue() { ::MIR::LValue rv; TRACE_FUNCTION_FR("", rv); @@ -352,7 +352,7 @@ namespace { ::MIR::RValue deserialise_mir_rvalue() { TRACE_FUNCTION; - + switch( m_in.read_tag() ) { #define _(x, ...) case ::MIR::RValue::TAG_##x: return ::MIR::RValue::make_##x( __VA_ARGS__ ); @@ -414,7 +414,7 @@ namespace { ::MIR::Constant deserialise_mir_constant() { TRACE_FUNCTION; - + switch( m_in.read_tag() ) { #define _(x, ...) case ::MIR::Constant::TAG_##x: DEBUG("- " #x); return ::MIR::Constant::make_##x( __VA_ARGS__ ); @@ -436,7 +436,7 @@ namespace { throw ""; } } - + ::HIR::TypeItem deserialise_typeitem() { switch( m_in.read_tag() ) @@ -479,7 +479,7 @@ namespace { throw ""; } } - + ::HIR::Linkage deserialise_linkage() { return ::HIR::Linkage { @@ -487,12 +487,12 @@ namespace { m_in.read_string(), }; } - + // - Value items ::HIR::Function deserialise_function() { TRACE_FUNCTION; - + ::HIR::Function rv { deserialise_linkage(), static_cast< ::HIR::Function::Receiver>( m_in.read_tag() ), @@ -520,7 +520,7 @@ namespace { ::HIR::Constant deserialise_constant() { TRACE_FUNCTION; - + return ::HIR::Constant { deserialise_genericparams(), deserialise_type(), @@ -531,7 +531,7 @@ namespace { ::HIR::Static deserialise_static() { TRACE_FUNCTION; - + return ::HIR::Static { deserialise_linkage(), m_in.read_bool(), @@ -540,7 +540,7 @@ namespace { deserialise_literal() }; } - + // - Type items ::HIR::TypeAlias deserialise_typealias() { @@ -565,14 +565,14 @@ namespace { // TODO: auto_impls return m; } - + ::HIR::Enum deserialise_enum(); ::HIR::Enum::Variant deserialise_enumvariant(); ::HIR::Struct deserialise_struct(); ::HIR::Union deserialise_union(); ::HIR::Trait deserialise_trait(); - + ::HIR::TraitValueItem deserialise_traitvalueitem() { switch( m_in.read_tag() ) @@ -600,50 +600,50 @@ namespace { #define DEF_D(ty, ...) \ struct D< ty > { static ty des(HirDeserialiser& d) { __VA_ARGS__ } }; - + template<> DEF_D( ::std::string, return d.read_string(); ); - + template<typename T> DEF_D( ::std::unique_ptr<T>, return d.deserialise_ptr<T>(); ) - + template<typename T, typename U> struct D< ::std::pair<T,U> > { static ::std::pair<T,U> des(HirDeserialiser& d) { auto a = D<T>::des(d); return ::std::make_pair( mv$(a), D<U>::des(d) ); }}; - + template<typename T> DEF_D( ::HIR::VisEnt<T>, return d.deserialise_visent<T>(); ) - + 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(); ) template<> DEF_D( ::HIR::TraitPath, return d.deserialise_traitpath(); ) - + template<> DEF_D( ::HIR::TypeParamDef, return d.deserialise_typaramdef(); ) template<> DEF_D( ::HIR::GenericBound, return d.deserialise_genericbound(); ) - + template<> DEF_D( ::HIR::ValueItem, return d.deserialise_valueitem(); ) template<> DEF_D( ::HIR::TypeItem, return d.deserialise_typeitem(); ) - + template<> DEF_D( ::HIR::Enum::Variant, return d.deserialise_enumvariant(); ) template<> DEF_D( ::HIR::Literal, return d.deserialise_literal(); ) - + template<> DEF_D( ::HIR::AssociatedType, return d.deserialise_associatedtype(); ) template<> DEF_D( ::HIR::TraitValueItem, return d.deserialise_traitvalueitem(); ) - + 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(); ) - + template<> DEF_D( ::HIR::TypeImpl, return d.deserialise_typeimpl(); ) template<> DEF_D( ::MacroRulesPtr, return d.deserialise_macrorulesptr(); ) template<> DEF_D( unsigned int, return static_cast<unsigned int>(d.deserialise_count()); ) - + ::HIR::TypeRef HirDeserialiser::deserialise_type() { TRACE_FUNCTION; @@ -704,7 +704,7 @@ namespace { throw ::std::runtime_error(FMT("Bad TypeRef tag - " << tag)); } } - + ::HIR::SimplePath HirDeserialiser::deserialise_simplepath() { TRACE_FUNCTION; @@ -733,7 +733,7 @@ namespace { deserialise_pathparams() }; } - + ::HIR::TraitPath HirDeserialiser::deserialise_traitpath() { return ::HIR::TraitPath { @@ -770,7 +770,7 @@ namespace { throw ""; } } - + ::HIR::GenericParams HirDeserialiser::deserialise_genericparams() { ::HIR::GenericParams params; @@ -810,7 +810,7 @@ namespace { throw ""; } } - + ::HIR::Enum HirDeserialiser::deserialise_enum() { TRACE_FUNCTION; @@ -847,7 +847,7 @@ namespace { auto repr = static_cast< ::HIR::Union::Repr>( m_in.read_tag() ); auto variants = deserialise_vec< ::std::pair< ::std::string, ::HIR::VisEnt< ::HIR::TypeRef> > >(); auto markings = deserialise_markings(); - + return ::HIR::Union { mv$(params), repr, mv$(variants), mv$(markings) }; @@ -858,7 +858,7 @@ namespace { auto params = deserialise_genericparams(); auto repr = static_cast< ::HIR::Struct::Repr>( m_in.read_tag() ); DEBUG("params = " << params.fmt_args() << params.fmt_bounds()); - + switch( m_in.read_tag() ) { case ::HIR::Struct::Data::TAG_Unit: @@ -889,7 +889,7 @@ namespace { ::HIR::Trait HirDeserialiser::deserialise_trait() { TRACE_FUNCTION; - + ::HIR::Trait rv { deserialise_genericparams(), "", // TODO: Better type for lifetime @@ -902,7 +902,7 @@ namespace { rv.m_type_indexes = deserialise_strumap< unsigned int>(); return rv; } - + ::HIR::Literal HirDeserialiser::deserialise_literal() { switch( m_in.read_tag() ) @@ -923,25 +923,25 @@ namespace { throw ""; } } - + ::MIR::FunctionPointer HirDeserialiser::deserialise_mir() { TRACE_FUNCTION; - + ::MIR::Function rv; - + rv.named_variables = deserialise_vec< ::HIR::TypeRef>( ); DEBUG("named_variables = " << rv.named_variables); rv.temporaries = deserialise_vec< ::HIR::TypeRef>( ); DEBUG("temporaries = " << rv.temporaries); rv.blocks = deserialise_vec< ::MIR::BasicBlock>( ); - + return ::MIR::FunctionPointer( new ::MIR::Function(mv$(rv)) ); } ::MIR::BasicBlock HirDeserialiser::deserialise_mir_basicblock() { TRACE_FUNCTION; - + return ::MIR::BasicBlock { deserialise_vec< ::MIR::Statement>(), deserialise_mir_terminator() @@ -950,7 +950,7 @@ namespace { ::MIR::Statement HirDeserialiser::deserialise_mir_statement() { TRACE_FUNCTION; - + switch( m_in.read_tag() ) { case 0: @@ -971,7 +971,7 @@ namespace { ::MIR::Terminator HirDeserialiser::deserialise_mir_terminator() { TRACE_FUNCTION; - + switch( m_in.read_tag() ) { #define _(x, ...) case ::MIR::Terminator::TAG_##x: return ::MIR::Terminator::make_##x( __VA_ARGS__ ); @@ -1001,7 +1001,7 @@ namespace { throw ""; } } - + ::MIR::CallTarget HirDeserialiser::deserialise_mir_calltarget() { switch( m_in.read_tag() ) @@ -1018,27 +1018,27 @@ namespace { throw ""; } } - + ::HIR::Module HirDeserialiser::deserialise_module() { TRACE_FUNCTION; - + ::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> > >(); - + return rv; } ::HIR::Crate HirDeserialiser::deserialise_crate() { ::HIR::Crate rv; - + rv.m_root_module = deserialise_module(); - + rv.m_type_impls = deserialise_vec< ::HIR::TypeImpl>(); - + { size_t n = m_in.read_count(); for(size_t i = 0; i < n; i ++) @@ -1055,10 +1055,10 @@ namespace { rv.m_marker_impls.insert( ::std::make_pair( mv$(p), deserialise_markerimpl() ) ); } } - + rv.m_exported_macros = deserialise_strumap< ::MacroRulesPtr>(); rv.m_lang_items = deserialise_strumap< ::HIR::SimplePath>(); - + { size_t n = m_in.read_count(); for(size_t i = 0; i < n; i ++) @@ -1067,7 +1067,7 @@ namespace { rv.m_ext_crates.insert( ::std::make_pair(ext_crate_name, ::HIR::CratePtr{}) ); } } - + return rv; } } @@ -1076,11 +1076,11 @@ namespace { { ::HIR::serialise::Reader in { filename }; HirDeserialiser s { loaded_name, in }; - + try { ::HIR::Crate rv = s.deserialise_crate(); - + return ::HIR::CratePtr( mv$(rv) ); } catch(int) diff --git a/src/hir/dump.cpp b/src/hir/dump.cpp index 6838f40b..ea113a00 100644 --- a/src/hir/dump.cpp +++ b/src/hir/dump.cpp @@ -12,21 +12,21 @@ #define NODE_IS(valptr, tysuf) ( dynamic_cast<const ::HIR::ExprNode##tysuf*>(&*valptr) != nullptr ) namespace { - + class TreeVisitor: public ::HIR::Visitor, public ::HIR::ExprVisitor { ::std::ostream& m_os; unsigned int m_indent_level; - + public: TreeVisitor(::std::ostream& os): m_os(os), m_indent_level(0) { } - + void visit_module(::HIR::ItemPath p, ::HIR::Module& mod) override { if( p.get_name()[0] ) @@ -34,17 +34,17 @@ namespace { m_os << indent() << "mod " << p.get_name() << " {\n"; inc_indent(); } - + // TODO: Print publicitiy. ::HIR::Visitor::visit_module(p, mod); - + if( p.get_name()[0] ) { dec_indent(); m_os << indent() << "}\n"; } } - + void visit_type_impl(::HIR::TypeImpl& impl) override { m_os << indent() << "impl" << impl.m_params.fmt_args() << " " << impl.m_type << "\n"; @@ -80,7 +80,7 @@ namespace { } m_os << indent() << "{ }\n"; } - + // - Type Items void visit_type_alias(::HIR::ItemPath p, ::HIR::TypeAlias& item) override { @@ -165,7 +165,7 @@ namespace { (Unit, ), (Value, - m_os << " = ?";// << + m_os << " = ?";// << ), (Tuple, m_os << "("; @@ -189,7 +189,7 @@ namespace { dec_indent(); m_os << indent() << "}\n"; } - + // - Value Items void visit_function(::HIR::ItemPath p, ::HIR::Function& item) override { @@ -210,7 +210,7 @@ namespace { { m_os << indent() << " " << item.m_params.fmt_bounds() << "\n"; } - + if( item.m_code ) { m_os << indent(); @@ -221,9 +221,9 @@ namespace { m_os << "{\n"; inc_indent(); m_os << indent(); - + item.m_code->visit( *this ); - + m_os << "\n"; dec_indent(); m_os << indent(); @@ -255,18 +255,18 @@ namespace { { m_os << indent() << "const " << p.get_name() << ": " << item.m_type << " = " << item.m_value_res << ";\n"; } - + // - Misc #if 0 virtual void visit_params(::HIR::GenericParams& params); virtual void visit_pattern(::HIR::Pattern& pat); virtual void visit_pattern_val(::HIR::Pattern::Value& val); virtual void visit_type(::HIR::TypeRef& tr); - + enum class PathContext { TYPE, TRAIT, - + VALUE, }; virtual void visit_trait_path(::HIR::TraitPath& p); @@ -276,7 +276,7 @@ namespace { virtual void visit_expr(::HIR::ExprPtr& exp); #endif - + bool node_is_leaf(const ::HIR::ExprNode& node) { if( NODE_IS(&node, _PathValue) ) return true; @@ -290,7 +290,7 @@ namespace { return true; return false; } - + void visit(::HIR::ExprNode_Block& node) override { if( node.m_nodes.size() == 0 ) { @@ -321,7 +321,7 @@ namespace { m_os << indent() << "}"; } } - + void visit(::HIR::ExprNode_Return& node) override { m_os << "return"; @@ -366,7 +366,7 @@ namespace { for(unsigned int i = 1; i < arm.m_patterns.size(); i ++ ) { m_os << " | " << arm.m_patterns[i]; } - + if( arm.m_cond ) { m_os << " if "; this->visit_node_ptr(arm.m_cond); @@ -473,7 +473,7 @@ namespace { void visit(::HIR::ExprNode_Deref& node) override { m_os << "*"; - + bool skip_parens = this->node_is_leaf(*node.m_value); if( !skip_parens ) m_os << "("; this->visit_node_ptr(node.m_value); @@ -692,7 +692,7 @@ namespace { void HIR_Dump(::std::ostream& sink, const ::HIR::Crate& crate) { TreeVisitor tv { sink }; - + tv.visit_crate( const_cast< ::HIR::Crate&>(crate) ); } diff --git a/src/hir/expr.cpp b/src/hir/expr.cpp index 7921cf98..46e7d886 100644 --- a/src/hir/expr.cpp +++ b/src/hir/expr.cpp @@ -91,10 +91,10 @@ DEF_VISIT(ExprNode_Emplace, node, DEF_VISIT(ExprNode_TupleVariant, node, visit_generic_path(::HIR::Visitor::PathContext::VALUE, node.m_path); - + for(auto& ty : node.m_arg_types) visit_type(ty); - + for(auto& arg : node.m_args) visit_node_ptr(arg); ) @@ -102,7 +102,7 @@ DEF_VISIT(ExprNode_CallPath, node, TRACE_FUNCTION_F("_CallPath: " << node.m_path); for(auto& ty : node.m_cache.m_arg_types) visit_type(ty); - + visit_path(::HIR::Visitor::PathContext::VALUE, node.m_path); for(auto& arg : node.m_args) visit_node_ptr(arg); @@ -111,7 +111,7 @@ DEF_VISIT(ExprNode_CallValue, node, TRACE_FUNCTION_F("_CallValue:"); for(auto& ty : node.m_arg_types) visit_type(ty); - + visit_node_ptr(node.m_value); for(auto& arg : node.m_args) visit_node_ptr(arg); @@ -122,7 +122,7 @@ DEF_VISIT(ExprNode_CallMethod, node, visit_type(ty); visit_path(::HIR::Visitor::PathContext::VALUE, node.m_method_path); - + visit_node_ptr(node.m_value); for(auto& arg : node.m_args) visit_node_ptr(arg); diff --git a/src/hir/expr.hpp b/src/hir/expr.hpp index 5bb7f248..b8227aa0 100644 --- a/src/hir/expr.hpp +++ b/src/hir/expr.hpp @@ -46,7 +46,7 @@ public: ValueUsage m_usage = ValueUsage::Unknown; const Span& span() const { return m_span; } - + virtual void visit(ExprVisitor& v) = 0; ExprNode(Span sp): m_span( mv$(sp) ) @@ -72,7 +72,7 @@ struct ExprNode_Block: ::HIR::SimplePath m_local_mod; t_trait_list m_traits; - + ExprNode_Block(Span sp): ExprNode(mv$(sp)), m_is_unsafe(false), @@ -84,20 +84,20 @@ struct ExprNode_Block: m_nodes( mv$(nodes) ), m_yields_final(false) {} - + NODE_METHODS(); }; struct ExprNode_Return: public ExprNode { ::HIR::ExprNodeP m_value; - + ExprNode_Return(Span sp, ::HIR::ExprNodeP value): ExprNode(mv$(sp), ::HIR::TypeRef::new_diverge()), m_value( mv$(value) ) { } - + NODE_METHODS(); }; struct ExprNode_Loop: @@ -106,14 +106,14 @@ struct ExprNode_Loop: ::std::string m_label; ::HIR::ExprNodeP m_code; bool m_diverges = false; - + ExprNode_Loop(Span sp, ::std::string label, ::HIR::ExprNodeP code): //ExprNode(mv$(sp), ::HIR::TypeRef::new_unit()), ExprNode(mv$(sp), ::HIR::TypeRef()), m_label( mv$(label) ), m_code( mv$(code) ) {} - + NODE_METHODS(); }; struct ExprNode_LoopControl: @@ -128,7 +128,7 @@ struct ExprNode_LoopControl: m_label( mv$(label) ), m_continue( cont ) {} - + NODE_METHODS(); }; struct ExprNode_Let: @@ -137,14 +137,14 @@ struct ExprNode_Let: ::HIR::Pattern m_pattern; ::HIR::TypeRef m_type; ::HIR::ExprNodeP m_value; - + ExprNode_Let(Span sp, ::HIR::Pattern pat, ::HIR::TypeRef ty, ::HIR::ExprNodeP val): ExprNode(mv$(sp), ::HIR::TypeRef::new_unit()), m_pattern( mv$(pat) ), m_type( mv$(ty) ), m_value( mv$(val) ) {} - + NODE_METHODS(); }; @@ -157,7 +157,7 @@ struct ExprNode_Match: ::HIR::ExprNodeP m_cond; ::HIR::ExprNodeP m_code; }; - + ::HIR::ExprNodeP m_value; ::std::vector<Arm> m_arms; @@ -176,14 +176,14 @@ struct ExprNode_If: ::HIR::ExprNodeP m_cond; ::HIR::ExprNodeP m_true; ::HIR::ExprNodeP m_false; - + ExprNode_If(Span sp, ::HIR::ExprNodeP cond, ::HIR::ExprNodeP true_code, ::HIR::ExprNodeP false_code): ExprNode( mv$(sp) ), m_cond( mv$(cond) ), m_true( mv$(true_code) ), m_false( mv$(false_code) ) {} - + NODE_METHODS(); }; @@ -206,17 +206,17 @@ struct ExprNode_Assign: case Op::Mul: return "*"; case Op::Div: return "/"; case Op::Mod: return "%"; - + case Op::And: return "&"; case Op::Or: return "|"; case Op::Xor: return "^"; - + case Op::Shr: return ">>"; case Op::Shl: return "<<"; } throw ""; } - + Op m_op; ExprNodeP m_slot; ExprNodeP m_value; @@ -227,7 +227,7 @@ struct ExprNode_Assign: m_slot( mv$(slot) ), m_value( mv$(value) ) {} - + NODE_METHODS(); }; struct ExprNode_BinOp: @@ -240,7 +240,7 @@ struct ExprNode_BinOp: CmpLtE, CmpGt, CmpGtE, - + BoolAnd, BoolOr, @@ -258,20 +258,20 @@ struct ExprNode_BinOp: case Op::CmpLtE: return "<="; case Op::CmpGt: return ">"; case Op::CmpGtE: return ">="; - + case Op::BoolAnd: return "&&"; case Op::BoolOr: return "||"; - + case Op::Add: return "+"; case Op::Sub: return "-"; case Op::Mul: return "*"; case Op::Div: return "/"; case Op::Mod: return "%"; - + case Op::And: return "&"; case Op::Or: return "|"; case Op::Xor: return "^"; - + case Op::Shr: return ">>"; case Op::Shl: return "<<"; } @@ -300,7 +300,7 @@ struct ExprNode_BinOp: break; } } - + NODE_METHODS(); }; struct ExprNode_UniOp: @@ -317,7 +317,7 @@ struct ExprNode_UniOp: } throw ""; } - + Op m_op; ::HIR::ExprNodeP m_value; @@ -326,7 +326,7 @@ struct ExprNode_UniOp: m_op(op), m_value( mv$(value) ) {} - + NODE_METHODS(); }; struct ExprNode_Borrow: @@ -340,7 +340,7 @@ struct ExprNode_Borrow: m_type(bt), m_value( mv$(value) ) {} - + NODE_METHODS(); }; struct ExprNode_Cast: @@ -353,7 +353,7 @@ struct ExprNode_Cast: ExprNode( mv$(sp), mv$(dst_type) ), m_value( mv$(value) ) {} - + NODE_METHODS(); }; // Magical pointer unsizing operation: @@ -369,7 +369,7 @@ struct ExprNode_Unsize: ExprNode( mv$(sp), mv$(dst_type) ), m_value( mv$(value) ) {} - + NODE_METHODS(); }; struct ExprNode_Index: @@ -377,13 +377,13 @@ struct ExprNode_Index: { ::HIR::ExprNodeP m_value; ::HIR::ExprNodeP m_index; - + ExprNode_Index(Span sp, ::HIR::ExprNodeP val, ::HIR::ExprNodeP index): ExprNode(mv$(sp)), m_value( mv$(val) ), m_index( mv$(index) ) {} - + NODE_METHODS(); }; // unary `*` @@ -391,12 +391,12 @@ struct ExprNode_Deref: public ExprNode { ::HIR::ExprNodeP m_value; - + ExprNode_Deref(Span sp, ::HIR::ExprNodeP val): ExprNode(mv$(sp)), m_value( mv$(val) ) {} - + NODE_METHODS(); }; /// `box` and `in`/`<-` @@ -409,11 +409,11 @@ struct ExprNode_Emplace: Placer, Boxer, }; - + Type m_type; ExprNodeP m_place; ExprNodeP m_value; - + ExprNode_Emplace(Span sp, Type ty, ::HIR::ExprNodeP place, ::HIR::ExprNodeP val): ExprNode( mv$(sp) ), m_type(ty), @@ -421,7 +421,7 @@ struct ExprNode_Emplace: m_value( mv$(val) ) { } - + NODE_METHODS(); }; @@ -432,17 +432,17 @@ struct ExprNode_TupleVariant: ::HIR::GenericPath m_path; bool m_is_struct; ::std::vector<ExprNodeP> m_args; - + // - Cache for typeck ::std::vector< ::HIR::TypeRef> m_arg_types; - + ExprNode_TupleVariant(Span sp, ::HIR::GenericPath path, bool is_struct, ::std::vector< ::HIR::ExprNodeP> args): ExprNode(mv$(sp)), m_path( mv$(path) ), m_is_struct( is_struct ), m_args( mv$(args) ) {} - + NODE_METHODS(); }; @@ -452,7 +452,7 @@ struct ExprCallCache const ::HIR::GenericParams* m_fcn_params; const ::HIR::GenericParams* m_top_params; const ::HIR::Function* m_fcn; - + ::std::function<const ::HIR::TypeRef&(const ::HIR::TypeRef&)> m_monomorph_cb; }; @@ -461,16 +461,16 @@ struct ExprNode_CallPath: { ::HIR::Path m_path; ::std::vector<ExprNodeP> m_args; - + // - Cache for typeck ExprCallCache m_cache; - + ExprNode_CallPath(Span sp, ::HIR::Path path, ::std::vector< ::HIR::ExprNodeP> args): ExprNode(mv$(sp)), m_path( mv$(path) ), m_args( mv$(args) ) {} - + NODE_METHODS(); }; struct ExprNode_CallValue: @@ -478,13 +478,13 @@ struct ExprNode_CallValue: { ::HIR::ExprNodeP m_value; ::std::vector<ExprNodeP> m_args; - + // - Argument types used as coercion targets ::std::vector< ::HIR::TypeRef> m_arg_ivars; - + // - Cache for typeck ::std::vector< ::HIR::TypeRef> m_arg_types; - + // Indicates what trait should/is being used for this call // - Determined by typeck using the present trait bound (also adds borrows etc) // - If the called value is a closure, this stays a Unknown until closure expansion @@ -495,13 +495,13 @@ struct ExprNode_CallValue: FnOnce, }; TraitUsed m_trait_used = TraitUsed::Unknown; - + ExprNode_CallValue(Span sp, ::HIR::ExprNodeP val, ::std::vector< ::HIR::ExprNodeP> args): ExprNode(mv$(sp)), m_value( mv$(val) ), m_args( mv$(args) ) {} - + NODE_METHODS(); }; struct ExprNode_CallMethod: @@ -511,12 +511,12 @@ struct ExprNode_CallMethod: ::std::string m_method; ::HIR::PathParams m_params; ::std::vector< ::HIR::ExprNodeP> m_args; - + // - Set during typeck to the real path to the method ::HIR::Path m_method_path; // - Cache of argument/return types ExprCallCache m_cache; - + // - List of possible traits (in-scope traits that contain this method) t_trait_list m_traits; // - A pool of ivars to use for searching for trait impls @@ -528,11 +528,11 @@ struct ExprNode_CallMethod: m_method( mv$(method_name) ), m_params( mv$(params) ), m_args( mv$(args) ), - + m_method_path( ::HIR::SimplePath("",{}) ) { } - + NODE_METHODS(); }; struct ExprNode_Field: @@ -540,13 +540,13 @@ struct ExprNode_Field: { ::HIR::ExprNodeP m_value; ::std::string m_field; - + ExprNode_Field(Span sp, ::HIR::ExprNodeP val, ::std::string field): ExprNode(mv$(sp)), m_value( mv$(val) ), m_field( mv$(field) ) {} - + NODE_METHODS(); }; @@ -607,7 +607,7 @@ struct ExprNode_Literal: ) ) } - + NODE_METHODS(); }; struct ExprNode_UnitVariant: @@ -616,13 +616,13 @@ struct ExprNode_UnitVariant: // Path to variant/struct ::HIR::GenericPath m_path; bool m_is_struct; - + ExprNode_UnitVariant(Span sp, ::HIR::GenericPath path, bool is_struct): ExprNode(mv$(sp)), m_path( mv$(path) ), m_is_struct( is_struct ) {} - + NODE_METHODS(); }; struct ExprNode_PathValue: @@ -638,13 +638,13 @@ struct ExprNode_PathValue: }; ::HIR::Path m_path; Target m_target; - + ExprNode_PathValue(Span sp, ::HIR::Path path, Target target): ExprNode(mv$(sp)), m_path( mv$(path) ), m_target( target ) {} - + NODE_METHODS(); }; struct ExprNode_Variable: @@ -652,13 +652,13 @@ struct ExprNode_Variable: { ::std::string m_name; unsigned int m_slot; - + ExprNode_Variable(Span sp, ::std::string name, unsigned int slot): ExprNode(mv$(sp)), m_name( mv$(name) ), m_slot( slot ) {} - + NODE_METHODS(); }; @@ -666,15 +666,15 @@ struct ExprNode_StructLiteral: public ExprNode { typedef ::std::vector< ::std::pair< ::std::string, ExprNodeP > > t_values; - + ::HIR::GenericPath m_path; bool m_is_struct; ::HIR::ExprNodeP m_base_value; t_values m_values; - + /// 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( mv$(sp) ), m_path( mv$(path) ), @@ -685,7 +685,7 @@ struct ExprNode_StructLiteral: // TODO: set m_res_type based on path? // - Defer, because it requires binding ivars between m_path and m_res_type } - + NODE_METHODS(); }; struct ExprNode_UnionLiteral: @@ -694,9 +694,9 @@ struct ExprNode_UnionLiteral: ::HIR::GenericPath m_path; ::std::string 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( mv$(sp) ), m_path( mv$(path) ), @@ -704,31 +704,31 @@ struct ExprNode_UnionLiteral: m_value( mv$(value) ) { } - + NODE_METHODS(); }; struct ExprNode_Tuple: public ExprNode { ::std::vector< ::HIR::ExprNodeP> m_vals; - + ExprNode_Tuple(Span sp, ::std::vector< ::HIR::ExprNodeP> vals): ExprNode(mv$(sp)), m_vals( mv$(vals) ) {} - + NODE_METHODS(); }; struct ExprNode_ArrayList: public ExprNode { ::std::vector< ::HIR::ExprNodeP> m_vals; - + ExprNode_ArrayList(Span sp, ::std::vector< ::HIR::ExprNodeP> vals): ExprNode( mv$(sp), ::HIR::TypeRef::new_array( ::HIR::TypeRef(), vals.size() ) ), m_vals( mv$(vals) ) {} - + NODE_METHODS(); }; struct ExprNode_ArraySized: @@ -737,14 +737,14 @@ struct ExprNode_ArraySized: ::HIR::ExprNodeP m_val; ::HIR::ExprNodeP m_size; // TODO: Has to be constant size_t m_size_val; - + ExprNode_ArraySized(Span sp, ::HIR::ExprNodeP val, ::HIR::ExprNodeP size): ExprNode(mv$(sp)), m_val( mv$(val) ), m_size( mv$(size) ), m_size_val( ~0u ) {} - + NODE_METHODS(); }; @@ -752,12 +752,12 @@ struct ExprNode_Closure: public ExprNode { typedef ::std::vector< ::std::pair< ::HIR::Pattern, ::HIR::TypeRef> > args_t; - + args_t m_args; ::HIR::TypeRef m_return; ::HIR::ExprNodeP m_code; bool m_is_move = false; - + enum class Class { Unknown, NoCapture, @@ -765,12 +765,12 @@ struct ExprNode_Closure: Mut, Once, } m_class = Class::Unknown; - + // - Path to the generated closure type ::HIR::GenericPath m_obj_path_base; ::HIR::GenericPath m_obj_path; ::std::vector< ::HIR::ExprNodeP> m_captures; - + ExprNode_Closure(Span sp, args_t args, ::HIR::TypeRef rv, ::HIR::ExprNodeP code, bool is_move): ExprNode(mv$(sp)), m_args( ::std::move(args) ), @@ -778,7 +778,7 @@ struct ExprNode_Closure: m_code( ::std::move(code) ), m_is_move(is_move) {} - + NODE_METHODS(); }; @@ -790,7 +790,7 @@ public: virtual void visit_node_ptr(::std::unique_ptr<ExprNode>& node_ptr); virtual void visit_node(ExprNode& node); #define NV(nt) virtual void visit(nt& n) = 0; - + NV(ExprNode_Block) NV(ExprNode_Return) NV(ExprNode_Let) @@ -798,7 +798,7 @@ public: NV(ExprNode_LoopControl) NV(ExprNode_Match) NV(ExprNode_If) - + NV(ExprNode_Assign) NV(ExprNode_BinOp) NV(ExprNode_UniOp) @@ -808,7 +808,7 @@ public: NV(ExprNode_Index) NV(ExprNode_Deref) NV(ExprNode_Emplace) - + NV(ExprNode_TupleVariant); NV(ExprNode_CallPath); NV(ExprNode_CallValue); @@ -819,13 +819,13 @@ public: NV(ExprNode_UnitVariant); NV(ExprNode_PathValue); NV(ExprNode_Variable); - + NV(ExprNode_StructLiteral); NV(ExprNode_UnionLiteral); NV(ExprNode_Tuple); NV(ExprNode_ArrayList); NV(ExprNode_ArraySized); - + NV(ExprNode_Closure); #undef NV }; @@ -835,7 +835,7 @@ class ExprVisitorDef: { public: #define NV(nt) virtual void visit(nt& n); - + NV(ExprNode_Block) NV(ExprNode_Return) NV(ExprNode_Let) @@ -843,7 +843,7 @@ public: NV(ExprNode_LoopControl) NV(ExprNode_Match) NV(ExprNode_If) - + NV(ExprNode_Assign) NV(ExprNode_BinOp) NV(ExprNode_UniOp) @@ -853,7 +853,7 @@ public: NV(ExprNode_Index) NV(ExprNode_Deref) NV(ExprNode_Emplace) - + NV(ExprNode_TupleVariant); NV(ExprNode_CallPath); NV(ExprNode_CallValue); @@ -864,16 +864,16 @@ public: NV(ExprNode_UnitVariant); NV(ExprNode_PathValue); NV(ExprNode_Variable); - + NV(ExprNode_StructLiteral); NV(ExprNode_UnionLiteral); NV(ExprNode_Tuple); NV(ExprNode_ArrayList); NV(ExprNode_ArraySized); - + NV(ExprNode_Closure); #undef NV - + virtual void visit_pattern(const Span& sp, ::HIR::Pattern& pat); virtual void visit_type(::HIR::TypeRef& ty); virtual void visit_trait_path(::HIR::TraitPath& p); diff --git a/src/hir/expr_ptr.hpp b/src/hir/expr_ptr.hpp index 21bc9e9d..5bedd1da 100644 --- a/src/hir/expr_ptr.hpp +++ b/src/hir/expr_ptr.hpp @@ -30,7 +30,7 @@ public: x.ptr = nullptr; } ~ExprPtrInner(); - + ExprPtrInner& operator=(ExprPtrInner&& x) { this->~ExprPtrInner(); @@ -38,7 +38,7 @@ public: x.ptr = nullptr; return *this; } - + ::std::unique_ptr< ::HIR::ExprNode> into_unique(); operator bool () const { return ptr != nullptr; } ::HIR::ExprNode* get() const { return ptr; } @@ -46,7 +46,7 @@ public: this->~ExprPtrInner(); this->ptr = p; } - + ::HIR::ExprNode& operator*() { return *ptr; } const ::HIR::ExprNode& operator*() const { return *ptr; } ::HIR::ExprNode* operator->() { return ptr; } @@ -56,21 +56,21 @@ public: class ExprPtr { ::HIR::ExprPtrInner node; - + public: ::std::vector< ::HIR::TypeRef> m_bindings; ::std::vector< ::HIR::TypeRef> m_erased_types; ::MIR::FunctionPointer m_mir; - + public: ExprPtr() {} ExprPtr(::std::unique_ptr< ::HIR::ExprNode> _); - + ::std::unique_ptr< ::HIR::ExprNode> into_unique(); operator bool () const { return node; } ::HIR::ExprNode* get() const { return node.get(); } void reset(::HIR::ExprNode* p) { node.reset(p); } - + ::HIR::ExprNode& operator*() { return *node; } const ::HIR::ExprNode& operator*() const { return *node; } ::HIR::ExprNode* operator->() { return &*node; } diff --git a/src/hir/from_ast.cpp b/src/hir/from_ast.cpp index c4e250a0..e3691f16 100644 --- a/src/hir/from_ast.cpp +++ b/src/hir/from_ast.cpp @@ -29,7 +29,7 @@ ::HIR::GenericParams LowerHIR_GenericParams(const ::AST::GenericParams& gp, bool* self_is_sized) { ::HIR::GenericParams rv; - + if( gp.ty_params().size() > 0 ) { for(const auto& tp : gp.ty_params()) @@ -61,9 +61,9 @@ ), (IsTrait, auto type = LowerHIR_Type(e.type); - + // TODO: Check for `Sized` - + rv.m_bounds.push_back(::HIR::GenericBound::make_TraitBound({ mv$(type), LowerHIR_TraitPath(bound.span, e.trait) })); rv.m_bounds.back().as_TraitBound().trait.m_hrls = e.hrls; ), @@ -85,7 +85,7 @@ BUG(bound.span, "MaybeTrait on parameter not in parameter list (#" << ge.index << " " << param_name << ")"); } } - + // Compare with list of known default traits (just Sized atm) and set a marker auto trait = LowerHIR_GenericPath(bound.span, e.trait); if( trait.m_path == path_Sized ) { @@ -105,7 +105,7 @@ (NotTrait, TODO(bound.span, "Negative trait bounds"); ), - + (Equality, rv.m_bounds.push_back(::HIR::GenericBound::make_TypeEquality({ LowerHIR_Type(e.type), @@ -115,14 +115,14 @@ ) } } - + return rv; } ::HIR::Pattern LowerHIR_Pattern(const ::AST::Pattern& pat) { TRACE_FUNCTION_F("@" << pat.span().filename << ":" << pat.span().start_line << " pat = " << pat); - + ::HIR::PatternBinding binding; if( pat.binding().is_valid() ) { @@ -135,7 +135,7 @@ } binding = ::HIR::PatternBinding(pat.binding().m_mutable, bt, pat.binding().m_name.name, pat.binding().m_slot); } - + struct H { static ::std::vector< ::HIR::Pattern> lowerhir_patternvec(const ::std::vector< ::AST::Pattern>& sub_patterns) { ::std::vector< ::HIR::Pattern> rv; @@ -144,7 +144,7 @@ return rv; } }; - + TU_MATCH(::AST::Pattern::Data, (pat.data()), (e), (MaybeBind, BUG(pat.span(), "Encountered MaybeBind pattern"); @@ -178,7 +178,7 @@ (Tuple, auto leading = H::lowerhir_patternvec( e.start ); auto trailing = H::lowerhir_patternvec( e.end ); - + if( e.has_wildcard ) { return ::HIR::Pattern { @@ -199,7 +199,7 @@ }; } ), - + (StructTuple, unsigned int leading_count = e.tup_pat.start.size(); unsigned int trailing_count = e.tup_pat.end .size(); @@ -219,7 +219,7 @@ field_count = var.as_Tuple().size(); } ::std::vector<HIR::Pattern> sub_patterns; - + if( e.tup_pat.has_wildcard ) { sub_patterns.reserve( field_count ); if( leading_count + trailing_count > field_count ) { @@ -238,13 +238,13 @@ } else { assert( trailing_count == 0 ); - + if( leading_count != field_count ) { ERROR(pat.span(), E0000, "Enum variant pattern has a mismatched field count - " << field_count << " exp, got " << leading_count); } sub_patterns = H::lowerhir_patternvec( e.tup_pat.start ); } - + return ::HIR::Pattern { mv$(binding), ::HIR::Pattern::Data::make_EnumTuple({ @@ -268,7 +268,7 @@ field_count = pb.hir->m_data.as_Tuple().size(); } ::std::vector<HIR::Pattern> sub_patterns; - + if( e.tup_pat.has_wildcard ) { sub_patterns.reserve( field_count ); if( leading_count + trailing_count > field_count ) { @@ -287,13 +287,13 @@ } else { assert( trailing_count == 0 ); - + if( leading_count != field_count ) { ERROR(pat.span(), E0000, "Struct pattern has a mismatched field count - " << field_count << " exp, got " << leading_count); } sub_patterns = H::lowerhir_patternvec( e.tup_pat.start ); } - + return ::HIR::Pattern { mv$(binding), ::HIR::Pattern::Data::make_StructTuple({ @@ -309,8 +309,8 @@ ::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)) ); - - + + TU_MATCH_DEF(::AST::PathBinding, (e.path.binding()), (pb), ( BUG(pat.span(), "Encountered Struct pattern not pointing to a enum variant or a struct - " << e.path); @@ -350,7 +350,7 @@ ) ) ), - + (Value, struct H { static ::HIR::CoreType get_int_type(const Span& sp, const ::eCoreType ct) { @@ -369,11 +369,11 @@ case CORETYPE_INT: return ::HIR::CoreType::Isize; case CORETYPE_UINT: return ::HIR::CoreType::Usize; - + case CORETYPE_CHAR: return ::HIR::CoreType::Char; - + case CORETYPE_BOOL: return ::HIR::CoreType::Bool; - + default: BUG(sp, "Unknown type for integer literal in pattern - " << ct ); } @@ -451,17 +451,17 @@ ::std::vector< ::HIR::Pattern> leading; for(const auto& sp : e.leading) leading.push_back( LowerHIR_Pattern(sp) ); - + ::std::vector< ::HIR::Pattern> trailing; for(const auto& sp : e.trailing) trailing.push_back( LowerHIR_Pattern(sp) ); - + auto extra_bind = e.extra_bind.is_valid() // TODO: Share code with the outer binding code ? ::HIR::PatternBinding(false, ::HIR::PatternBinding::Type::Ref, e.extra_bind.m_name.name, e.extra_bind.m_slot) : ::HIR::PatternBinding() ; - + return ::HIR::Pattern { mv$(binding), ::HIR::Pattern::Data::make_SplitSlice({ @@ -509,7 +509,7 @@ throw "BUG: Encountered path with parameters when creating ::HIR::GenericPath"; } } - + rv.m_components.push_back( node.name() ); } return rv; @@ -521,7 +521,7 @@ ::HIR::PathParams LowerHIR_PathParams(const Span& sp, const ::AST::PathParams& src_params, bool allow_assoc) { ::HIR::PathParams params; - + // TODO: Lifetime params (not encoded in ::HIR::PathNode as yet) //for(const auto& param : src_params.m_lifetimes) { //} @@ -529,7 +529,7 @@ for(const auto& param : src_params.m_types) { params.m_types.push_back( LowerHIR_Type(param) ); } - + // Leave 'm_assoc' alone? if( !allow_assoc && src_params.m_assoc.size() > 0 ) { @@ -559,12 +559,12 @@ {}, nullptr }; - + for(const auto& assoc : path.nodes().back().args().m_assoc) { rv.m_type_bounds.insert(::std::make_pair( assoc.first, LowerHIR_Type(assoc.second) )); } - + return rv; } ::HIR::Path LowerHIR_Path(const Span& sp, const ::AST::Path& path) @@ -654,7 +654,7 @@ case CORETYPE_STR : return ::HIR::TypeRef( ::HIR::CoreType::Str ); case CORETYPE_F32: return ::HIR::TypeRef( ::HIR::CoreType::F32 ); case CORETYPE_F64: return ::HIR::TypeRef( ::HIR::CoreType::F64 ); - + case CORETYPE_I8 : return ::HIR::TypeRef( ::HIR::CoreType::I8 ); case CORETYPE_U8 : return ::HIR::TypeRef( ::HIR::CoreType::U8 ); case CORETYPE_I16: return ::HIR::TypeRef( ::HIR::CoreType::I16 ); @@ -700,14 +700,14 @@ return ::HIR::TypeRef::new_array( mv$(inner), size_val ); } } - + return ::HIR::TypeRef::new_array( mv$(inner), LowerHIR_Expr(e.size) ); } else { return ::HIR::TypeRef::new_slice( mv$(inner) ); } ), - + (Path, TU_IFLET(::AST::Path::Class, e.path.m_class, Local, l, unsigned int slot; @@ -754,7 +754,7 @@ //if( e.hrls.size() > 0 ) // TODO(ty.span(), "ErasedType with HRLS - " << ty); ASSERT_BUG(ty.span(), e.traits.size() > 0, "ErasedType with no traits"); - + ::std::vector< ::HIR::TraitPath> traits; for(const auto& t : e.traits) { @@ -810,7 +810,7 @@ namespace { { TRACE_FUNCTION_F(path); ::HIR::Struct::Data data; - + TU_MATCH(::AST::StructData, (ent.m_data), (e), (Tuple, if( e.ents.size() == 0 ) { @@ -818,10 +818,10 @@ namespace { } else { ::HIR::Struct::Data::Data_Tuple fields; - + for(const auto& field : e.ents) fields.push_back( { field.m_is_public, LowerHIR_Type(field.m_type) } ); - + data = ::HIR::Struct::Data::make_Tuple( mv$(fields) ); } ), @@ -844,7 +844,7 @@ namespace { ::HIR::Enum LowerHIR_Enum(::HIR::ItemPath path, const ::AST::Enum& f) { ::std::vector< ::std::pair< ::std::string, ::HIR::Enum::Variant> > variants; - + for(const auto& var : f.variants()) { TU_MATCH(::AST::EnumVariantData, (var.m_data), (e), @@ -875,7 +875,7 @@ namespace { ) ) } - + return ::HIR::Enum { LowerHIR_GenericParams(f.params(), nullptr), // TODO: Get repr from attributes @@ -886,7 +886,7 @@ namespace { ::HIR::Union LowerHIR_Union(::HIR::ItemPath path, const ::AST::Union& f, const ::AST::MetaItems& attrs) { auto repr = ::HIR::Union::Repr::Rust; - + if( const auto* attr_repr = attrs.get("repr") ) { const auto& repr_str = attr_repr->string(); @@ -897,11 +897,11 @@ namespace { // TODO: Error? } } - + ::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)) ) ); - + return ::HIR::Union { LowerHIR_GenericParams(f.m_params, nullptr), repr, @@ -913,7 +913,7 @@ namespace { TRACE_FUNCTION_F(trait_path); bool trait_reqires_sized = false; auto params = LowerHIR_GenericParams(f.params(), &trait_reqires_sized); - + ::std::string lifetime; ::std::vector< ::HIR::TraitPath> supertraits; for(const auto& st : f.supertraits()) { @@ -939,12 +939,12 @@ namespace { } rv.m_params.m_bounds.push_back( ::HIR::GenericBound::make_TraitBound({ ::HIR::TypeRef("Self",0xFFFF), { mv$(this_trait) } }) ); } - + for(const auto& item : f.items()) { auto trait_ip = ::HIR::ItemPath(trait_path); auto item_path = ::HIR::ItemPath( trait_ip, item.name.c_str() ); - + TU_MATCH_DEF(::AST::Item, (item.data), (i), ( BUG(item.data.span, "Encountered unexpected item type in trait"); @@ -1003,23 +1003,23 @@ namespace { ) ) } - + rv.m_is_marker = f.is_marker(); - + return rv; } ::HIR::Function LowerHIR_Function(::HIR::ItemPath p, const ::AST::MetaItems& attrs, const ::AST::Function& f, const ::HIR::TypeRef& self_type) { static Span sp; - + TRACE_FUNCTION_F(p); - + ::std::vector< ::std::pair< ::HIR::Pattern, ::HIR::TypeRef > > args; for(const auto& arg : f.args()) args.push_back( ::std::make_pair( LowerHIR_Pattern(arg.first), LowerHIR_Type(arg.second) ) ); - + auto receiver = ::HIR::Function::Receiver::Free; - + if( args.size() > 0 && args.front().first.m_binding.m_name == "self" ) { const auto& arg_self_ty = args.front().second; @@ -1051,15 +1051,15 @@ namespace { ) else { } - + if( receiver == ::HIR::Function::Receiver::Free ) { ERROR(sp, E0000, "Unknown receiver type - " << arg_self_ty); } } - + ::HIR::Linkage linkage; - + // Convert #[link_name/no_mangle] attributes into the name if( const auto* a = attrs.get("link_name") ) { @@ -1083,13 +1083,13 @@ namespace { { // Leave linkage.name as empty } - + // If there's no code, demangle the name (TODO: By ABI) and set linkage. if( linkage.name == "" && ! f.code().is_valid() ) { linkage.name = p.get_name(); } - + return ::HIR::Function { mv$(linkage), receiver, @@ -1112,19 +1112,19 @@ void _add_mod_val_item(::HIR::Module& mod, ::std::string name, bool is_pub, ::H { TRACE_FUNCTION_F("path = " << path); ::HIR::Module mod { }; - + mod.m_traits = mv$(traits); - + // Populate trait list for(const auto& item : ast_mod.m_type_items) { if( item.second.path.binding().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) ); + mod.m_traits.push_back( mv$(sp) ); } } - + for( unsigned int i = 0; i < ast_mod.anon_mods().size(); i ++ ) { const auto& submod_ptr = ast_mod.anon_mods()[i]; @@ -1216,7 +1216,7 @@ void _add_mod_val_item(::HIR::Module& mod, ::std::string name, bool is_pub, ::H ) ) } - + Span mod_span; for( const auto& ie : ast_mod.m_namespace_items ) { @@ -1243,7 +1243,7 @@ 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::ValueItem vi; - + TU_MATCH_DEF( ::AST::PathBinding, (ie.second.path.binding()), (pb), ( DEBUG("Import VAL " << ie.first << " = " << hir_path); @@ -1257,14 +1257,14 @@ void _add_mod_val_item(::HIR::Module& mod, ::std::string name, bool is_pub, ::H _add_mod_val_item(mod, ie.first, ie.second.is_pub, mv$(vi)); } } - + return mod; } void LowerHIR_Module_Impls(const ::AST::Module& ast_mod, ::HIR::Crate& hir_crate) { DEBUG(ast_mod.path()); - + // Sub-modules for( const auto& item : ast_mod.items() ) { @@ -1278,16 +1278,16 @@ void LowerHIR_Module_Impls(const ::AST::Module& ast_mod, ::HIR::Crate& hir_crat LowerHIR_Module_Impls(*submod_ptr, hir_crate); } } - - // + + // for( const auto& i : ast_mod.items() ) { if( !i.data.is_Impl() ) continue; const auto& impl = i.data.as_Impl(); auto params = LowerHIR_GenericParams(impl.def().params(), nullptr); - + TRACE_FUNCTION_F("IMPL " << impl.def()); - + if( impl.def().trait().ent.is_valid() ) { const auto& pb = impl.def().trait().ent.binding(); @@ -1297,18 +1297,18 @@ void LowerHIR_Module_Impls(const ::AST::Module& ast_mod, ::HIR::Crate& hir_crat auto trait_path = LowerHIR_GenericPath(impl.def().trait().sp, impl.def().trait().ent); auto trait_name = mv$(trait_path.m_path); auto trait_args = mv$(trait_path.m_params); - + if( !is_marker ) { auto type = LowerHIR_Type(impl.def().type()); - + ::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; - + for(const auto& item : impl.items()) { ::HIR::ItemPath item_path(path, item.name.c_str()); @@ -1343,17 +1343,17 @@ void LowerHIR_Module_Impls(const ::AST::Module& ast_mod, ::HIR::Crate& hir_crat ) ) } - + hir_crate.m_trait_impls.insert( ::std::make_pair(mv$(trait_name), ::HIR::TraitImpl { mv$(params), mv$(trait_args), mv$(type), - + mv$(methods), mv$(constants), {}, // Statics mv$(types), - + LowerHIR_SimplePath(Span(), ast_mod.path()) }) ); } @@ -1369,7 +1369,7 @@ void LowerHIR_Module_Impls(const ::AST::Module& ast_mod, ::HIR::Crate& hir_crat mv$(trait_args), true, mv$(type), - + LowerHIR_SimplePath(Span(), ast_mod.path()) } ) ); } @@ -1379,10 +1379,10 @@ void LowerHIR_Module_Impls(const ::AST::Module& ast_mod, ::HIR::Crate& hir_crat // Inherent impls auto type = LowerHIR_Type(impl.def().type()); ::HIR::ItemPath path(type); - + ::std::map< ::std::string, ::HIR::TypeImpl::VisImplEnt< ::HIR::Function> > methods; ::std::map< ::std::string, ::HIR::TypeImpl::VisImplEnt< ::HIR::Constant> > constants; - + for(const auto& item : impl.items()) { ::HIR::ItemPath item_path(path, item.name.c_str()); @@ -1413,13 +1413,13 @@ void LowerHIR_Module_Impls(const ::AST::Module& ast_mod, ::HIR::Crate& hir_crat ) ) } - + hir_crate.m_type_impls.push_back( ::HIR::TypeImpl { mv$(params), mv$(type), mv$(methods), mv$(constants), - + LowerHIR_SimplePath(Span(), ast_mod.path()) } ); } @@ -1428,19 +1428,19 @@ void LowerHIR_Module_Impls(const ::AST::Module& ast_mod, ::HIR::Crate& hir_crat { if( !i.data.is_NegImpl() ) continue; const auto& impl = i.data.as_NegImpl(); - + auto params = LowerHIR_GenericParams(impl.params(), nullptr); auto type = LowerHIR_Type(impl.type()); auto trait = LowerHIR_GenericPath(impl.trait().sp, impl.trait().ent); auto trait_name = mv$(trait.m_path); auto trait_args = mv$(trait.m_params); - + hir_crate.m_marker_impls.insert( ::std::make_pair( mv$(trait_name), ::HIR::MarkerImpl { mv$(params), mv$(trait_args), false, mv$(type), - + LowerHIR_SimplePath(Span(), ast_mod.path()) } ) ); } @@ -1456,7 +1456,7 @@ public: IndexVisitor(const ::HIR::Crate& crate): crate(crate) {} - + void visit_params(::HIR::GenericParams& params) override { for( auto& bound : params.m_bounds ) @@ -1478,7 +1478,7 @@ public: g_crate_ptr = &rv; g_core_crate = (crate.m_load_std == ::AST::Crate::LOAD_NONE ? "" : "core"); auto& macros = rv.m_exported_macros; - + // - Extract exported macros { ::std::vector< ::AST::Module*> mods; @@ -1487,7 +1487,7 @@ public: { auto& mod = *mods.back(); mods.pop_back(); - + for( /*const*/ auto& mac : mod.macros() ) { if( mac.data->m_exported ) { auto res = macros.insert( ::std::make_pair( mac.name, mv$(mac.data) ) ); @@ -1498,13 +1498,13 @@ public: DEBUG("- Non-exported " << mac.name << "!"); } } - + for(auto& i : mod.items()) { if( i.data.is_Module() ) mods.push_back( &i.data.as_Module() ); } } while( mods.size() > 0 ); - + for( auto& mac : crate.m_root_module.macro_imports_res() ) { if( mac.data->m_exported && mac.name != "" ) { auto v = ::std::make_pair( mac.name, MacroRulesPtr(new MacroRules( mv$(*const_cast<MacroRules*>(mac.data)) )) ); @@ -1521,7 +1521,7 @@ public: } } } - + auto sp = Span(); // - Store the lang item paths so conversion code can use them. for( const auto& lang_item_path : crate.m_lang_items ) @@ -1544,14 +1544,14 @@ public: rv.m_ext_crates.insert( ::std::make_pair( ext_crate.first, mv$(ext_crate.second.m_hir) ) ); } path_Sized = rv.get_lang_item_path(sp, "sized"); - + rv.m_root_module = LowerHIR_Module( crate.m_root_module, ::HIR::ItemPath() ); - + LowerHIR_Module_Impls(crate.m_root_module, rv); - + // Set all pointers in the HIR to the correct (now fixed) locations IndexVisitor(rv).visit_crate( rv ); - + g_crate_ptr = nullptr; return ::HIR::CratePtr( mv$(rv) ); } diff --git a/src/hir/from_ast_expr.cpp b/src/hir/from_ast_expr.cpp index 273e2b04..39b33e53 100644 --- a/src/hir/from_ast_expr.cpp +++ b/src/hir/from_ast_expr.cpp @@ -25,7 +25,7 @@ struct LowerHIR_ExprNode_Visitor: public ::AST::NodeVisitor { ::std::unique_ptr< ::HIR::ExprNode> m_rv; - + virtual void visit(::AST::ExprNode_Block& v) override { auto rv = new ::HIR::ExprNode_Block(v.span()); for(const auto& n : v.m_nodes) @@ -34,13 +34,13 @@ struct LowerHIR_ExprNode_Visitor: rv->m_nodes.push_back( LowerHIR_ExprNode_Inner( *n ) ); } rv->m_yields_final = v.m_yields_final_value; - + if( v.m_local_mod ) { // TODO: Populate m_traits from the local module's import list rv->m_local_mod = LowerHIR_SimplePath(v.span(), v.m_local_mod->path()); } - + m_rv.reset( static_cast< ::HIR::ExprNode*>(rv) ); } virtual void visit(::AST::ExprNode_Macro& v) override { @@ -78,15 +78,15 @@ struct LowerHIR_ExprNode_Visitor: case ::AST::ExprNode_Assign::NONE: return ::HIR::ExprNode_Assign::Op::None; case ::AST::ExprNode_Assign::ADD: return ::HIR::ExprNode_Assign::Op::Add; case ::AST::ExprNode_Assign::SUB: return ::HIR::ExprNode_Assign::Op::Sub; - + case ::AST::ExprNode_Assign::DIV: return ::HIR::ExprNode_Assign::Op::Mul; case ::AST::ExprNode_Assign::MUL: return ::HIR::ExprNode_Assign::Op::Div; case ::AST::ExprNode_Assign::MOD: return ::HIR::ExprNode_Assign::Op::Mod; - + case ::AST::ExprNode_Assign::AND: return ::HIR::ExprNode_Assign::Op::And; case ::AST::ExprNode_Assign::OR : return ::HIR::ExprNode_Assign::Op::Or ; case ::AST::ExprNode_Assign::XOR: return ::HIR::ExprNode_Assign::Op::Xor; - + case ::AST::ExprNode_Assign::SHR: return ::HIR::ExprNode_Assign::Op::Shr; case ::AST::ExprNode_Assign::SHL: return ::HIR::ExprNode_Assign::Op::Shl; } @@ -109,13 +109,13 @@ struct LowerHIR_ExprNode_Visitor: auto path_RangeFrom = ::HIR::GenericPath( ::HIR::SimplePath(g_core_crate, {"ops", "RangeFrom"}) ); auto path_RangeTo = ::HIR::GenericPath( ::HIR::SimplePath(g_core_crate, {"ops", "RangeTo"}) ); auto path_RangeFull = ::HIR::GenericPath( ::HIR::SimplePath(g_core_crate, {"ops", "RangeFull"}) ); - + ::HIR::ExprNode_StructLiteral::t_values values; if( v.m_left ) values.push_back( ::std::make_pair( ::std::string("start"), LowerHIR_ExprNode_Inner( *v.m_left ) ) ); if( v.m_right ) values.push_back( ::std::make_pair( ::std::string("end") , LowerHIR_ExprNode_Inner( *v.m_right ) ) ); - + if( v.m_left ) { if( v.m_right ) { m_rv.reset( new ::HIR::ExprNode_StructLiteral(v.span(), mv$(path_Range), true, nullptr, mv$(values)) ); @@ -137,7 +137,7 @@ struct LowerHIR_ExprNode_Visitor: // NOTE: Not language items auto path_RangeInclusive_NonEmpty = ::HIR::GenericPath( ::HIR::SimplePath(g_core_crate, {"ops", "RangeInclusive", "NonEmpty"}) ); auto path_RangeToInclusive = ::HIR::GenericPath( ::HIR::SimplePath(g_core_crate, {"ops", "RangeToInclusive"}) ); - + if( v.m_left ) { ::HIR::ExprNode_StructLiteral::t_values values; @@ -155,7 +155,7 @@ struct LowerHIR_ExprNode_Visitor: case ::AST::ExprNode_BinOp::PLACE_IN: TODO(v.get_pos(), "Desugar placement syntax"); break; - + case ::AST::ExprNode_BinOp::CMPEQU : op = ::HIR::ExprNode_BinOp::Op::CmpEqu ; if(0) case ::AST::ExprNode_BinOp::CMPNEQU: op = ::HIR::ExprNode_BinOp::Op::CmpNEqu; if(0) case ::AST::ExprNode_BinOp::CMPLT : op = ::HIR::ExprNode_BinOp::Op::CmpLt ; if(0) @@ -164,7 +164,7 @@ struct LowerHIR_ExprNode_Visitor: case ::AST::ExprNode_BinOp::CMPGTE: op = ::HIR::ExprNode_BinOp::Op::CmpGtE; if(0) case ::AST::ExprNode_BinOp::BOOLAND: op = ::HIR::ExprNode_BinOp::Op::BoolAnd; if(0) case ::AST::ExprNode_BinOp::BOOLOR : op = ::HIR::ExprNode_BinOp::Op::BoolOr ; if(0) - + case ::AST::ExprNode_BinOp::BITAND: op = ::HIR::ExprNode_BinOp::Op::And; if(0) case ::AST::ExprNode_BinOp::BITOR : op = ::HIR::ExprNode_BinOp::Op::Or ; if(0) case ::AST::ExprNode_BinOp::BITXOR: op = ::HIR::ExprNode_BinOp::Op::Xor; if(0) @@ -175,7 +175,7 @@ struct LowerHIR_ExprNode_Visitor: case ::AST::ExprNode_BinOp::SUB: op = ::HIR::ExprNode_BinOp::Op::Sub; if(0) case ::AST::ExprNode_BinOp::SHR: op = ::HIR::ExprNode_BinOp::Op::Shr; if(0) case ::AST::ExprNode_BinOp::SHL: op = ::HIR::ExprNode_BinOp::Op::Shl; - + m_rv.reset( new ::HIR::ExprNode_BinOp( v.span(), op, LowerHIR_ExprNode_Inner( *v.m_left ), @@ -201,14 +201,14 @@ struct LowerHIR_ExprNode_Visitor: case ::AST::ExprNode_UniOp::QMARK: BUG(v.get_pos(), "Encounterd question mark operator (should have been expanded in AST)"); break; - + case ::AST::ExprNode_UniOp::REF: m_rv.reset(new ::HIR::ExprNode_Borrow(v.span(), ::HIR::BorrowType::Shared, LowerHIR_ExprNode_Inner( *v.m_value ) )); break; case ::AST::ExprNode_UniOp::REFMUT: m_rv.reset(new ::HIR::ExprNode_Borrow(v.span(), ::HIR::BorrowType::Unique, LowerHIR_ExprNode_Inner( *v.m_value ) )); break; - + case ::AST::ExprNode_UniOp::INVERT: op = ::HIR::ExprNode_UniOp::Op::Invert; if(0) case ::AST::ExprNode_UniOp::NEGATE: op = ::HIR::ExprNode_UniOp::Op::Negate; m_rv.reset( new ::HIR::ExprNode_UniOp( v.span(), @@ -231,12 +231,12 @@ struct LowerHIR_ExprNode_Visitor: LowerHIR_Type(v.m_type) ) ); } - + virtual void visit(::AST::ExprNode_CallPath& v) override { ::std::vector< ::HIR::ExprNodeP> args; for(const auto& arg : v.m_args) args.push_back( LowerHIR_ExprNode_Inner(*arg) ); - + 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 )), @@ -274,12 +274,12 @@ struct LowerHIR_ExprNode_Visitor: ::std::vector< ::HIR::ExprNodeP> args; for(const auto& arg : v.m_args) args.push_back( LowerHIR_ExprNode_Inner(*arg) ); - + // TODO: Should this be abstracted? ::HIR::PathParams params; for(const auto& param : v.m_method.args().m_types) params.m_types.push_back( LowerHIR_Type(param) ); - + m_rv.reset( new ::HIR::ExprNode_CallMethod( v.span(), LowerHIR_ExprNode_Inner(*v.m_val), v.m_method.name(), @@ -291,7 +291,7 @@ struct LowerHIR_ExprNode_Visitor: ::std::vector< ::HIR::ExprNodeP> args; for(const auto& arg : v.m_args) args.push_back( LowerHIR_ExprNode_Inner(*arg) ); - + m_rv.reset( new ::HIR::ExprNode_CallValue( v.span(), LowerHIR_ExprNode_Inner(*v.m_val), mv$(args) @@ -315,7 +315,7 @@ struct LowerHIR_ExprNode_Visitor: ::HIR::ExprNodeP( new ::HIR::ExprNode_LoopControl(v.span(), v.m_label, false) ) )) ); code.push_back( LowerHIR_ExprNode_Inner(*v.m_code) ); - + m_rv.reset( new ::HIR::ExprNode_Loop( v.span(), v.m_label, ::HIR::ExprNodeP(new ::HIR::ExprNode_Block( v.span(), false, mv$(code))) @@ -323,7 +323,7 @@ struct LowerHIR_ExprNode_Visitor: break; } case ::AST::ExprNode_Loop::WHILELET: { ::std::vector< ::HIR::ExprNode_Match::Arm> arms; - + // - Matches pattern - Run inner code arms.push_back(::HIR::ExprNode_Match::Arm { ::make_vec1( LowerHIR_Pattern(v.m_pattern) ), @@ -336,7 +336,7 @@ struct LowerHIR_ExprNode_Visitor: ::HIR::ExprNodeP(), ::HIR::ExprNodeP( new ::HIR::ExprNode_LoopControl( v.span(), v.m_label, false) ) }); - + m_rv.reset( new ::HIR::ExprNode_Loop( v.span(), v.m_label, ::HIR::ExprNodeP(new ::HIR::ExprNode_Match( v.span(), @@ -350,7 +350,7 @@ struct LowerHIR_ExprNode_Visitor: BUG(v.get_pos(), "Encountered still-sugared for loop"); break; } - + // TODO: Iterate the constructed loop and determine if there are any `break` statements pointing to it { struct LoopVisitor: @@ -359,13 +359,13 @@ struct LowerHIR_ExprNode_Visitor: const ::std::string& top_label; bool top_is_broken; ::std::vector< const ::std::string*> name_stack; - + LoopVisitor(const ::std::string& top_label): top_label(top_label), top_is_broken(false), name_stack() {} - + void visit(::HIR::ExprNode_Loop& node) override { if( node.m_label != "" ) { this->name_stack.push_back( &node.m_label ); @@ -377,7 +377,7 @@ struct LowerHIR_ExprNode_Visitor: } void visit(::HIR::ExprNode_LoopControl& node) override { ::HIR::ExprVisitorDef::visit(node); - + if( node.m_continue ) { } else { @@ -395,7 +395,7 @@ struct LowerHIR_ExprNode_Visitor: } } }; - + auto& loop_node = dynamic_cast< ::HIR::ExprNode_Loop&>(*m_rv);; LoopVisitor lv { loop_node.m_label }; loop_node.m_code->visit(lv); @@ -407,7 +407,7 @@ struct LowerHIR_ExprNode_Visitor: } virtual void visit(::AST::ExprNode_Match& v) override { ::std::vector< ::HIR::ExprNode_Match::Arm> arms; - + for(const auto& arm : v.m_arms) { ::HIR::ExprNode_Match::Arm new_arm { @@ -415,13 +415,13 @@ struct LowerHIR_ExprNode_Visitor: LowerHIR_ExprNode_Inner_Opt(arm.m_cond.get()), LowerHIR_ExprNode_Inner(*arm.m_code) }; - + for(const auto& pat : arm.m_patterns) new_arm.m_patterns.push_back( LowerHIR_Pattern(pat) ); - + arms.push_back( mv$(new_arm) ); } - + m_rv.reset( new ::HIR::ExprNode_Match( v.span(), LowerHIR_ExprNode_Inner(*v.m_val), mv$(arms) @@ -436,7 +436,7 @@ struct LowerHIR_ExprNode_Visitor: } virtual void visit(::AST::ExprNode_IfLet& v) override { ::std::vector< ::HIR::ExprNode_Match::Arm> arms; - + // - Matches pattern - Take true branch arms.push_back(::HIR::ExprNode_Match::Arm { ::make_vec1( LowerHIR_Pattern(v.m_pattern) ), @@ -454,7 +454,7 @@ struct LowerHIR_ExprNode_Visitor: mv$(arms) )); } - + virtual void visit(::AST::ExprNode_Integer& v) override { struct H { static ::HIR::CoreType get_type(Span sp, ::eCoreType ct) { @@ -473,9 +473,9 @@ struct LowerHIR_ExprNode_Visitor: case CORETYPE_INT: return ::HIR::CoreType::Isize; case CORETYPE_UINT: return ::HIR::CoreType::Usize; - + case CORETYPE_CHAR: return ::HIR::CoreType::Char; - + default: BUG(sp, "Unknown type for integer literal - " << coretype_name(ct)); } @@ -544,7 +544,7 @@ struct LowerHIR_ExprNode_Visitor: ERROR(v.span(), E0000, "Union constructors can only specify a single field"); if( v.m_base_value ) ERROR(v.span(), E0000, "Union constructors can't take a base value"); - + m_rv.reset( new ::HIR::ExprNode_UnionLiteral( v.span(), LowerHIR_GenericPath(v.get_pos(), v.m_path), v.m_values[0].first, @@ -645,7 +645,7 @@ struct LowerHIR_ExprNode_Visitor: const auto& enm = *e.enum_; auto it = ::std::find_if(enm.variants().begin(), enm.variants().end(), [&](const auto& x){ return x.m_name == var_name; }); assert(it != enm.variants().end()); - + var_idx = static_cast<unsigned int>(it - enm.variants().begin()); if( it->m_data.is_Struct() ) { ERROR(v.span(), E0000, "Named value referring to an enum that isn't tuple-like or unit-like - " << v.m_path); @@ -657,7 +657,7 @@ struct LowerHIR_ExprNode_Visitor: const auto& enm = *e.hir; auto it = ::std::find_if(enm.m_variants.begin(), enm.m_variants.end(), [&](const auto& x){ return x.first == var_name; }); assert(it != enm.m_variants.end()); - + var_idx = static_cast<unsigned int>(it - enm.m_variants.begin()); if( it->second.is_Struct() ) { ERROR(v.span(), E0000, "Named value referring to an enum that isn't tuple-like or unit-like - " << v.m_path); @@ -698,7 +698,7 @@ struct LowerHIR_ExprNode_Visitor: ) } } - + virtual void visit(::AST::ExprNode_Field& v) override { m_rv.reset( new ::HIR::ExprNode_Field( v.span(), LowerHIR_ExprNode_Inner(*v.m_obj), @@ -721,9 +721,9 @@ struct LowerHIR_ExprNode_Visitor: ::std::unique_ptr< ::HIR::ExprNode> LowerHIR_ExprNode_Inner(const ::AST::ExprNode& e) { LowerHIR_ExprNode_Visitor v; - + const_cast<::AST::ExprNode*>(&e)->visit( v ); - + if( ! v.m_rv ) { BUG(e.get_pos(), typeid(e).name() << " - Yielded a nullptr HIR node"); } diff --git a/src/hir/generic_params.cpp b/src/hir/generic_params.cpp index 54290731..984d8a3a 100644 --- a/src/hir/generic_params.cpp +++ b/src/hir/generic_params.cpp @@ -21,7 +21,7 @@ namespace HIR { ) return os; } - + ::std::ostream& operator<<(::std::ostream& os, const ::HIR::GenericParams::PrintArgs& x) { if( x.gp.m_lifetimes.size() > 0 || x.gp.m_types.size() > 0 ) diff --git a/src/hir/generic_params.hpp b/src/hir/generic_params.hpp index 79ce2cb9..8753ae7e 100644 --- a/src/hir/generic_params.hpp +++ b/src/hir/generic_params.hpp @@ -44,13 +44,13 @@ class GenericParams public: ::std::vector<TypeParamDef> m_types; ::std::vector< ::std::string> m_lifetimes; - + ::std::vector<GenericBound> m_bounds; - + //GenericParams() {} - + GenericParams clone() const; - + struct PrintArgs { const GenericParams& gp; PrintArgs(const GenericParams& gp): gp(gp) {} diff --git a/src/hir/hir.cpp b/src/hir/hir.cpp index 0ae4a786..2ec4d40b 100644 --- a/src/hir/hir.cpp +++ b/src/hir/hir.cpp @@ -45,7 +45,7 @@ namespace HIR { ) return os; } - + bool operator==(const Literal& l, const Literal& r) { if( l.tag() != r.tag() ) @@ -96,7 +96,7 @@ const ::HIR::Enum::Variant* ::HIR::Enum::get_variant(const ::std::string& name) 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() ); @@ -105,9 +105,9 @@ namespace { expand_generic = false; //DEBUG("left = " << left << ", right = " << right); - + // TODO: What indicates what out of ty_res? - + if( right.m_data.is_Infer() ) { //DEBUG("left = " << left << ", right = " << right); switch(right.m_data.as_Infer().ty_class) @@ -135,7 +135,7 @@ namespace { } throw ""; } - + // A local generic could match anything, leave that up to the caller if( left.m_data.is_Generic() ) { return true; @@ -150,7 +150,7 @@ namespace { if( right.m_data.is_Generic() ) { return left.m_data.is_Generic(); } - + if( left.m_data.tag() != right.m_data.tag() ) { return false; } @@ -247,7 +247,7 @@ namespace { 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 ) { if( left.m_params.m_types.size() != right.m_params.m_types.size() ) { return true; @@ -316,11 +316,11 @@ bool ::HIR::MarkerImpl::matches_type(const ::HIR::TypeRef& type, ::HIR::t_cb_res namespace { ::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<T> Foo<T> for T` vs `impl<T,U> Foo<U> 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() ) { @@ -330,7 +330,7 @@ namespace { if( right.m_data.is_Generic() ) { return ::OrdGreater; } - + TU_MATCH(::HIR::TypeRef::Data, (left.m_data), (le), (Generic, throw ""; @@ -436,7 +436,7 @@ namespace { ) 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; @@ -459,7 +459,7 @@ namespace { 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_parent_traits) { // 1. Monomorph @@ -469,7 +469,7 @@ namespace { // 3. Add rv.push_back( ::HIR::GenericBound::make_TraitBound({ type.clone(), mv$(trait_path_mono) }) ); } - + // TODO: Add traits from `Self: Foo` bounds? } ::std::vector< ::HIR::GenericBound> flatten_bounds(const ::std::vector<::HIR::GenericBound>& bounds) @@ -501,7 +501,7 @@ bool ::HIR::TraitImpl::more_specific_than(const ::HIR::TraitImpl& other) const { static const Span _sp; const Span& sp = _sp; - + // >> 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 if( type_ord_specific(sp, this->m_type, other.m_type) == ::OrdLess ) { @@ -511,9 +511,9 @@ bool ::HIR::TraitImpl::more_specific_than(const ::HIR::TraitImpl& other) const if( typelist_ord_specific(sp, this->m_trait_args.m_types, other.m_trait_args.m_types) == ::OrdLess ) { return false; } - + //assert(m_params.m_types.size() == other.m_params.m_types.size()); - + if( other.m_params.m_bounds.size() == 0 ) { return m_params.m_bounds.size() > 0; } @@ -523,13 +523,13 @@ bool ::HIR::TraitImpl::more_specific_than(const ::HIR::TraitImpl& other) const auto bounds_o = flatten_bounds(other.m_params.m_bounds); ::std::sort(bounds_t.begin(), bounds_t.end(), [](const auto& a, const auto& b){ return ::ord(a,b) == OrdLess; }); ::std::sort(bounds_o.begin(), bounds_o.end(), [](const auto& a, const auto& b){ return ::ord(a,b) == OrdLess; }); - + DEBUG("bounds_t = " << bounds_t); DEBUG("bounds_o = " << bounds_o); - + if( bounds_t.size() < bounds_o.size() ) return false; - + auto it_t = bounds_t.begin(); for(auto it_o = bounds_o.begin(); it_o != bounds_o.end(); ++it_o) { @@ -569,7 +569,7 @@ const ::HIR::SimplePath& ::HIR::Crate::get_lang_item_path_opt(const char* name) const ::HIR::TypeItem& ::HIR::Crate::get_typeitem_by_path(const Span& sp, const ::HIR::SimplePath& path, bool ignore_crate_name) const { ASSERT_BUG(sp, path.m_components.size() > 0, "get_typeitem_by_path received invalid path - " << path); - + const ::HIR::Module* mod; if( !ignore_crate_name && path.m_crate_name != "" ) { ASSERT_BUG(sp, m_ext_crates.count(path.m_crate_name) > 0, "Crate '" << path.m_crate_name << "' not loaded"); @@ -596,14 +596,14 @@ const ::HIR::TypeItem& ::HIR::Crate::get_typeitem_by_path(const Span& sp, const if( it == mod->m_mod_items.end() ) { BUG(sp, "Could not find type name in " << path); } - + return it->second->ent; } const ::HIR::Module& ::HIR::Crate::get_mod_by_path(const Span& sp, const ::HIR::SimplePath& path) const { if( path.m_components.size() == 0 ) - { + { if( path.m_crate_name != "" ) { ASSERT_BUG(sp, m_ext_crates.count(path.m_crate_name) > 0, "Crate '" << path.m_crate_name << "' not loaded"); @@ -622,7 +622,7 @@ const ::HIR::Module& ::HIR::Crate::get_mod_by_path(const Span& sp, const ::HIR:: ) else { BUG(sp, "Module path " << path << " didn't point to a module"); - } + } } } const ::HIR::Trait& ::HIR::Crate::get_trait_by_path(const Span& sp, const ::HIR::SimplePath& path) const @@ -697,7 +697,7 @@ const ::HIR::ValueItem& ::HIR::Crate::get_valitem_by_path(const Span& sp, const if( it == mod->m_value_items.end() ) { BUG(sp, "Could not find value name " << path); } - + return it->second->ent; } const ::HIR::Function& ::HIR::Crate::get_function_by_path(const Span& sp, const ::HIR::SimplePath& path) const diff --git a/src/hir/hir.hpp b/src/hir/hir.hpp index 5f1f55f0..2f8c39bb 100644 --- a/src/hir/hir.hpp +++ b/src/hir/hir.hpp @@ -78,10 +78,10 @@ struct Linkage Weak, // Weak linkage (multiple definitions are allowed External, // Force the symbol to be externally visible }; - + // Linkage type Type type = Type::Auto; - + // External symbol name ::std::string name; }; @@ -92,16 +92,16 @@ public: Linkage m_linkage; bool m_is_mut; TypeRef m_type; - + ExprPtr m_value; - + Literal m_value_res; }; struct Constant { // NOTE: The generics can't influence the value of this `const` GenericParams m_params; - + TypeRef m_type; ExprPtr m_value; Literal m_value_res; @@ -119,24 +119,24 @@ public: //PointerConst, Box, }; - + typedef ::std::vector< ::std::pair< ::HIR::Pattern, ::HIR::TypeRef> > args_t; - + Linkage m_linkage; - + Receiver m_receiver; ::std::string m_abi; bool m_unsafe; bool m_const; - + GenericParams m_params; - + args_t m_args; bool m_variadic; TypeRef m_return; - + ExprPtr m_code; - + //::HIR::TypeRef make_ty(const Span& sp, const ::HIR::PathParams& params) const; }; @@ -157,17 +157,17 @@ struct TraitMarkings { /// There is at least one Unsize impl for this type bool can_unsize = false; - + /// Indicates that there is at least one Deref impl bool has_a_deref = false; - + /// Indicates that there is a Drop impl /// - If there is an impl, there must be an applicable impl to every instance. bool has_drop_impl = false; - + // If populated, indicates the field that is the coercable pointer. unsigned int coerce_unsized_index = ~0u; - + // TODO: This would have to be changed for custom DSTs enum class DstType { None, // Sized @@ -176,7 +176,7 @@ struct TraitMarkings TraitObject, // (Trait) } dst_type; unsigned int unsized_field = ~0u; - + /// `true` if there is a Copy impl bool is_copy = false; @@ -186,7 +186,7 @@ struct TraitMarkings // Implementation state bool is_impled; }; - + // General auto trait impls mutable ::std::map< ::HIR::SimplePath, AutoMarking> auto_impls; }; @@ -209,13 +209,13 @@ public: C, U8, U16, U32, }; - + GenericParams m_params; Repr m_repr; ::std::vector< ::std::pair< ::std::string, Variant > > m_variants; - + TraitMarkings m_markings; - + const Variant* get_variant(const ::std::string& ) const; }; class Struct @@ -233,11 +233,11 @@ public: (Tuple, t_tuple_fields), (Named, t_struct_fields) ); - + GenericParams m_params; Repr m_repr; Data m_data; - + TraitMarkings m_markings; }; class Union @@ -248,11 +248,11 @@ public: Rust, C, }; - + GenericParams m_params; Repr m_repr; t_struct_fields m_variants; - + TraitMarkings m_markings; }; @@ -273,17 +273,17 @@ struct Trait GenericParams m_params; ::std::string 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; - + // Indexes into the vtable for each present method and value ::std::unordered_multimap< ::std::string, ::std::pair<unsigned int,::HIR::GenericPath> > m_value_indexes; // Indexes in the vtable parameter list for each associated type ::std::unordered_map< ::std::string, unsigned int > m_type_indexes; - + Trait( GenericParams gps, ::std::string lifetime, ::std::vector< ::HIR::TraitPath> parents): m_params( mv$(gps) ), m_lifetime( mv$(lifetime) ), @@ -297,12 +297,12 @@ class Module public: // List of in-scope traits in this module ::std::vector< ::HIR::SimplePath> m_traits; - + // Contains all values and functions (including type constructors) ::std::unordered_map< ::std::string, ::std::unique_ptr<VisEnt<ValueItem>> > m_value_items; // Contains types, traits, and modules ::std::unordered_map< ::std::string, ::std::unique_ptr<VisEnt<TypeItem>> > m_mod_items; - + Module() {} Module(const Module&) = delete; Module(Module&& x) = default; @@ -344,12 +344,12 @@ 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; ::HIR::SimplePath m_src_module; - + bool matches_type(const ::HIR::TypeRef& tr, t_cb_resolve_type ty_res) const; bool matches_type(const ::HIR::TypeRef& tr) const { return matches_type(tr, [](const auto& x)->const auto&{ return x; }); @@ -368,20 +368,20 @@ public: ::HIR::GenericParams m_params; ::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< ::std::string, ImplEnt< ::HIR::TypeRef> > m_types; - + ::HIR::SimplePath m_src_module; - + bool matches_type(const ::HIR::TypeRef& tr, t_cb_resolve_type ty_res) const; bool matches_type(const ::HIR::TypeRef& tr) const { return matches_type(tr, [](const auto& x)->const auto&{ return x; }); } - + bool more_specific_than(const TraitImpl& x) const; }; @@ -392,9 +392,9 @@ public: ::HIR::PathParams m_trait_args; bool is_positive; ::HIR::TypeRef m_type; - + ::HIR::SimplePath m_src_module; - + bool matches_type(const ::HIR::TypeRef& tr, t_cb_resolve_type ty_res) const; bool matches_type(const ::HIR::TypeRef& tr) const { return matches_type(tr, [](const auto& x)->const auto&{ return x; }); @@ -405,35 +405,35 @@ class Crate { public: Module m_root_module; - + /// Impl blocks on just a type ::std::vector< ::HIR::TypeImpl > m_type_impls; /// Impl blocks ::std::multimap< ::HIR::SimplePath, ::HIR::TraitImpl > m_trait_impls; ::std::multimap< ::HIR::SimplePath, ::HIR::MarkerImpl > m_marker_impls; - + /// Macros exported by this crate ::std::unordered_map< ::std::string, ::MacroRulesPtr > m_exported_macros; - + /// Language items avaliable through this crate (includes ones from loaded externs) ::std::unordered_map< ::std::string, ::HIR::SimplePath> m_lang_items; - + ::std::unordered_map< ::std::string, ::HIR::CratePtr> m_ext_crates; - + /// Method called to populate runtime state after deserialisation /// See hir/crate_post_load.cpp void post_load_update(const ::std::string& 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; - + const ::HIR::TypeItem& get_typeitem_by_path(const Span& sp, const ::HIR::SimplePath& path, bool ignore_crate_name=false) const; const ::HIR::Trait& get_trait_by_path(const Span& sp, const ::HIR::SimplePath& path) const; const ::HIR::Struct& get_struct_by_path(const Span& sp, const ::HIR::SimplePath& path) const; const ::HIR::Union& get_union_by_path(const Span& sp, const ::HIR::SimplePath& path) const; const ::HIR::Enum& get_enum_by_path(const Span& sp, const ::HIR::SimplePath& path) const; const ::HIR::Module& get_mod_by_path(const Span& sp, const ::HIR::SimplePath& path) const; - + const ::HIR::ValueItem& get_valitem_by_path(const Span& sp, const ::HIR::SimplePath& path, bool ignore_crate_name=false) const; const ::HIR::Function& get_function_by_path(const Span& sp, const ::HIR::SimplePath& path) const; const ::HIR::Static& get_static_by_path(const Span& sp, const ::HIR::SimplePath& path) const { @@ -454,7 +454,7 @@ public: BUG(sp, "`const` path " << path << " didn't point to an enum"); } } - + bool find_trait_impls(const ::HIR::SimplePath& path, const ::HIR::TypeRef& type, t_cb_resolve_type ty_res, ::std::function<bool(const ::HIR::TraitImpl&)> callback) const; bool find_auto_trait_impls(const ::HIR::SimplePath& path, const ::HIR::TypeRef& type, t_cb_resolve_type ty_res, ::std::function<bool(const ::HIR::MarkerImpl&)> callback) const; bool find_type_impls(const ::HIR::TypeRef& type, t_cb_resolve_type ty_res, ::std::function<bool(const ::HIR::TypeImpl&)> callback) const; diff --git a/src/hir/item_path.hpp b/src/hir/item_path.hpp index 8ed140af..606c6817 100644 --- a/src/hir/item_path.hpp +++ b/src/hir/item_path.hpp @@ -17,7 +17,7 @@ public: const ::HIR::SimplePath* trait = nullptr; const ::HIR::PathParams* trait_params = nullptr; const char* name = nullptr; - + ItemPath() {} ItemPath(const ItemPath& p, const char* n): parent(&p), @@ -34,10 +34,10 @@ public: ItemPath(const ::HIR::SimplePath& path): trait(&path) {} - + const ::HIR::SimplePath* trait_path() const { return trait; } const ::HIR::PathParams* trait_args() const { return trait_params; } - + ::HIR::SimplePath get_simple_path() const { if( parent ) { assert(name); @@ -51,7 +51,7 @@ public: ::HIR::Path get_full_path() const { assert(parent); assert(name); - + if( parent->name ) { return get_simple_path(); } @@ -65,14 +65,14 @@ public: const char* get_name() const { return name ? name : ""; } - + ItemPath operator+(const ::std::string& name) const { return ItemPath(*this, name.c_str()); } - + bool operator==(const ::HIR::SimplePath& sp) const { if( sp.m_crate_name != "" ) return false; - + unsigned int i = sp.m_components.size(); const auto* n = this; while( n && i -- ) @@ -87,7 +87,7 @@ public: return false; return true; } - + friend ::std::ostream& operator<<(::std::ostream& os, const ItemPath& x) { if( x.parent ) { os << *x.parent; diff --git a/src/hir/path.cpp b/src/hir/path.cpp index 73d1b92f..e6dab41f 100644 --- a/src/hir/path.cpp +++ b/src/hir/path.cpp @@ -12,9 +12,9 @@ { ::HIR::SimplePath ret(m_crate_name); ret.m_components = m_components; - + ret.m_components.push_back( s ); - + return ret; } namespace HIR { @@ -38,7 +38,7 @@ namespace HIR { ::std::ostream& operator<<(::std::ostream& os, const PathParams& x) { bool has_args = ( x.m_types.size() > 0 ); - + if(has_args) { os << "<"; } @@ -65,7 +65,7 @@ namespace HIR { } os << x.m_path.m_path; bool has_args = ( x.m_path.m_params.m_types.size() > 0 || x.m_type_bounds.size() > 0 ); - + if(has_args) { os << "<"; } @@ -160,10 +160,10 @@ bool ::HIR::GenericPath::operator==(const GenericPath& x) const {}, m_trait_ptr }; - + for( const auto& assoc : m_type_bounds ) rv.m_type_bounds.insert(::std::make_pair( assoc.first, assoc.second.clone() )); - + return rv; } bool ::HIR::TraitPath::operator==(const ::HIR::TraitPath& x) const @@ -172,10 +172,10 @@ bool ::HIR::TraitPath::operator==(const ::HIR::TraitPath& x) const return false; if( m_hrls != x.m_hrls ) return false; - + if( m_type_bounds.size() != x.m_type_bounds.size() ) return false; - + for(auto it_l = m_type_bounds.begin(), it_r = x.m_type_bounds.begin(); it_l != m_type_bounds.end(); it_l++, it_r++ ) { if( it_l->first != it_r->first ) return false; @@ -237,7 +237,7 @@ bool ::HIR::TraitPath::operator==(const ::HIR::TraitPath& x) const ::HIR::Compare HIR::PathParams::compare_with_placeholders(const Span& sp, const ::HIR::PathParams& x, ::HIR::t_cb_resolve_type resolve_placeholder) const { using ::HIR::Compare; - + auto rv = Compare::Equal; if( this->m_types.size() > 0 || x.m_types.size() > 0 ) { if( this->m_types.size() != x.m_types.size() ) { @@ -283,7 +283,7 @@ bool ::HIR::TraitPath::operator==(const ::HIR::TraitPath& x) const if( this->m_path.m_components[i] != x.m_path.m_components[i] ) return Compare::Unequal; } - + return this->m_params. compare_with_placeholders(sp, x.m_params, resolve_placeholder); } @@ -319,9 +319,9 @@ namespace { auto rv = m_path .compare_with_placeholders(sp, x.m_path, resolve_placeholder); if( rv == Compare::Unequal ) return rv; - + // TODO: HRLs - + auto it_l = m_type_bounds.begin(); auto it_r = x.m_type_bounds.begin(); while( it_l != m_type_bounds.end() && it_r != x.m_type_bounds.end() ) @@ -333,12 +333,12 @@ namespace { ++ it_l; ++ it_r; } - + if( it_l != m_type_bounds.end() || it_r != x.m_type_bounds.end() ) { return Compare::Unequal; } - + return rv; } @@ -353,7 +353,7 @@ namespace { (UfcsUnknown, if( ple.item != pre.item) return Compare::Unequal; - + TODO(sp, "Path::compare_with_placeholders - UfcsUnknown"); ), (UfcsInherent, @@ -367,7 +367,7 @@ namespace { (UfcsKnown, if( ple.item != pre.item) return Compare::Unequal; - + ::HIR::Compare rv = ::HIR::Compare::Equal; CMP(rv, ple.type->compare_with_placeholders(sp, *pre.type, resolve_placeholder)); CMP(rv, ::compare_with_placeholders(sp, ple.trait, pre.trait, resolve_placeholder)); diff --git a/src/hir/path.hpp b/src/hir/path.hpp index e6b4e381..80fb4caa 100644 --- a/src/hir/path.hpp +++ b/src/hir/path.hpp @@ -72,7 +72,7 @@ struct SimplePath } SimplePath clone() const; - + SimplePath operator+(const ::std::string& s) const; bool operator==(const SimplePath& x) const { return m_crate_name == x.m_crate_name && m_components == x.m_components; @@ -98,7 +98,7 @@ struct SimplePath struct PathParams { ::std::vector<TypeRef> m_types; - + PathParams(); PathParams(::HIR::TypeRef ); PathParams clone() const; @@ -106,10 +106,10 @@ struct PathParams PathParams& operator=(const PathParams&) = delete; PathParams(PathParams&&) = default; PathParams& operator=(PathParams&&) = default; - + Compare compare_with_placeholders(const Span& sp, const PathParams& x, t_cb_resolve_type resolve_placeholder) const; Compare match_test_generics_fuzz(const Span& sp, const PathParams& x, t_cb_resolve_type resolve_placeholder, t_cb_match_generics) const; - + bool operator==(const PathParams& x) const; bool operator!=(const PathParams& x) const { return !(*this == x); } bool operator<(const PathParams& x) const { return ord(x) == OrdLess; } @@ -130,14 +130,14 @@ public: GenericPath(); GenericPath(::HIR::SimplePath sp); GenericPath(::HIR::SimplePath sp, ::HIR::PathParams params); - + GenericPath clone() const; Compare compare_with_placeholders(const Span& sp, const GenericPath& x, t_cb_resolve_type resolve_placeholder) const; - + bool operator==(const GenericPath& x) const; bool operator!=(const GenericPath& x) const { return !(*this == x); } bool operator<(const GenericPath& x) const { return ord(x) == OrdLess; } - + Ordering ord(const GenericPath& x) const { auto rv = ::ord(m_path, x.m_path); if(rv != OrdEqual) return rv; @@ -154,21 +154,21 @@ public: ::std::vector< ::std::string> m_hrls; // TODO: Each bound should list its origin trait ::std::map< ::std::string, ::HIR::TypeRef> m_type_bounds; - + const ::HIR::Trait* m_trait_ptr; - + TraitPath clone() const; Compare compare_with_placeholders(const Span& sp, const TraitPath& x, t_cb_resolve_type resolve_placeholder) const; - + bool operator==(const TraitPath& x) const; bool operator!=(const TraitPath& x) const { return !(*this == x); } - + Ordering ord(const TraitPath& x) const { ORD(m_path, x.m_path); ORD(m_hrls, x.m_hrls); return ::ord(m_type_bounds, x.m_type_bounds); } - + friend ::std::ostream& operator<<(::std::ostream& os, const TraitPath& x); }; @@ -207,19 +207,19 @@ 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 clone() const; Compare compare_with_placeholders(const Span& sp, const Path& x, t_cb_resolve_type resolve_placeholder) const; - + Ordering ord(const Path& x) const; - + bool operator==(const Path& x) const; bool operator!=(const Path& x) const { return !(*this == x); } bool operator<(const Path& x) const { return ord(x) == OrdLess; } - + friend ::std::ostream& operator<<(::std::ostream& os, const Path& x); }; diff --git a/src/hir/pattern.cpp b/src/hir/pattern.cpp index 71b0a9bb..74528aeb 100644 --- a/src/hir/pattern.cpp +++ b/src/hir/pattern.cpp @@ -90,14 +90,14 @@ namespace HIR { os << ns.first << ": " << ns.second << ", "; os << "}"; ), - + (Value, os << e.val; ), (Range, os << e.start << " ... " << e.end; ), - + (EnumValue, os << e.path; ), @@ -154,7 +154,7 @@ namespace { rv.push_back( ::std::make_pair(field.first, field.second.clone()) ); return rv; } - + ::HIR::Pattern::Value clone_patval(const ::HIR::Pattern::Value& val) { TU_MATCH(::HIR::Pattern::Value, (val), (e), (Integer, @@ -225,7 +225,7 @@ namespace { e.is_exhaustive })); ), - + (Value, return Pattern(m_binding, Data::make_Value({ clone_patval(e.val) @@ -237,7 +237,7 @@ namespace { clone_patval(e.end) })); ), - + (EnumValue, return Pattern(m_binding, Data::make_EnumValue({ e.path.clone(), e.binding_ptr, e.binding_idx })); ), @@ -271,7 +271,7 @@ namespace { })); ) ) - + throw ""; } diff --git a/src/hir/pattern.hpp b/src/hir/pattern.hpp index f86907fb..51e20c5c 100644 --- a/src/hir/pattern.hpp +++ b/src/hir/pattern.hpp @@ -26,14 +26,14 @@ struct PatternBinding Ref, MutRef, }; - + bool m_mutable; Type m_type; ::std::string m_name; unsigned int m_slot; - + bool is_valid() const { return m_name != ""; } - + PatternBinding(): m_mutable(false), m_type(Type::Move), @@ -67,7 +67,7 @@ struct Pattern }) ); friend ::std::ostream& operator<<(::std::ostream& os, const Pattern::Value& x); - + enum class GlobPos { None, Start, @@ -136,7 +136,7 @@ struct Pattern PatternBinding m_binding; Data m_data; - + Pattern() {} Pattern(PatternBinding pb, Data d): m_binding( mv$(pb) ), @@ -146,9 +146,9 @@ struct Pattern Pattern(Pattern&&) = default; Pattern& operator=(const Pattern&) = delete; Pattern& operator=(Pattern&&) = default; - + Pattern clone() const; - + friend ::std::ostream& operator<<(::std::ostream& os, const Pattern& x); }; diff --git a/src/hir/serialise.cpp b/src/hir/serialise.cpp index 0acd95ea..0dfb9b01 100644 --- a/src/hir/serialise.cpp +++ b/src/hir/serialise.cpp @@ -20,7 +20,7 @@ namespace { HirSerialiser(::HIR::serialise::Writer& out): m_out( out ) {} - + template<typename V> void serialise_strmap(const ::std::map< ::std::string,V>& map) { @@ -77,7 +77,7 @@ namespace { m_out.write_count(e.first); serialise(e.second); } - + void serialise_type(const ::HIR::TypeRef& ty) { m_out.write_tag( ty.m_data.tag() ); @@ -107,7 +107,7 @@ namespace { (ErasedType, serialise_path(e.m_origin); m_out.write_count(e.m_index); - + m_out.write_count(e.m_traits.size()); for(const auto& t : e.m_traits) serialise_traitpath(t); @@ -233,12 +233,12 @@ namespace { ) ) } - - + + void serialise_crate(const ::HIR::Crate& crate) { serialise_module(crate.m_root_module); - + m_out.write_count(crate.m_type_impls.size()); for(const auto& impl : crate.m_type_impls) { serialise_typeimpl(impl); @@ -253,10 +253,10 @@ namespace { serialise_simplepath(tr_impl.first); serialise_markerimpl(tr_impl.second); } - + serialise_strmap(crate.m_exported_macros); serialise_strmap(crate.m_lang_items); - + m_out.write_count(crate.m_ext_crates.size()); for(const auto& ext : crate.m_ext_crates) m_out.write_string(ext.first); @@ -264,9 +264,9 @@ namespace { void serialise_module(const ::HIR::Module& mod) { TRACE_FUNCTION; - + // m_traits doesn't need to be serialised - + serialise_strmap(mod.m_value_items); serialise_strmap(mod.m_mod_items); } @@ -275,7 +275,7 @@ namespace { TRACE_FUNCTION_F("impl" << impl.m_params.fmt_args() << " " << impl.m_type); serialise_generics(impl.m_params); serialise_type(impl.m_type); - + m_out.write_count(impl.m_methods.size()); for(const auto& v : impl.m_methods) { m_out.write_string(v.first); @@ -298,7 +298,7 @@ namespace { serialise_generics(impl.m_params); serialise_pathparams(impl.m_trait_args); serialise_type(impl.m_type); - + m_out.write_count(impl.m_methods.size()); for(const auto& v : impl.m_methods) { DEBUG("fn " << v.first); @@ -336,7 +336,7 @@ namespace { m_out.write_bool(impl.is_positive); serialise_type(impl.m_type); } - + void serialise(const ::HIR::TypeRef& ty) { serialise_type(ty); } @@ -408,10 +408,10 @@ namespace { Serialiser_TextTree ser(tmp); tok.serialise( ser ); } - + m_out.write_string(tmp.str()); } - + void serialise(const ::HIR::Literal& lit) { m_out.write_tag(lit.tag()); @@ -440,7 +440,7 @@ namespace { ) ) } - + void serialise(const ::HIR::ExprPtr& exp) { m_out.write_bool( (bool)exp.m_mir ); @@ -659,7 +659,7 @@ namespace { ) ) } - + void serialise(const ::HIR::TypeItem& item) { TU_MATCHA( (item), (e), @@ -726,27 +726,27 @@ namespace { ) ) } - + void serialise(unsigned int v) { m_out.write_count(v); }; - + void serialise(const ::HIR::Linkage& linkage) { //m_out.write_tag( static_cast<int>(linkage.type) ); m_out.write_string( linkage.name ); } - + // - Value items void serialise(const ::HIR::Function& fcn) { TRACE_FUNCTION_F("_function:"); - + serialise(fcn.m_linkage); - + m_out.write_tag( static_cast<int>(fcn.m_receiver) ); m_out.write_string(fcn.m_abi); m_out.write_bool(fcn.m_unsafe); m_out.write_bool(fcn.m_const); - + serialise_generics(fcn.m_params); m_out.write_count(fcn.m_args.size()); for(const auto& a : fcn.m_args) @@ -754,13 +754,13 @@ namespace { m_out.write_bool(fcn.m_variadic); serialise(fcn.m_return); DEBUG("m_args = " << fcn.m_args); - + serialise(fcn.m_code); } void serialise(const ::HIR::Constant& item) { TRACE_FUNCTION_F("_constant:"); - + serialise_generics(item.m_params); serialise(item.m_type); serialise(item.m_value); @@ -769,15 +769,15 @@ namespace { void serialise(const ::HIR::Static& item) { TRACE_FUNCTION_F("_static:"); - + serialise(item.m_linkage); - + m_out.write_bool(item.m_is_mut); serialise(item.m_type); - + serialise(item.m_value_res); } - + // - Type items void serialise(const ::HIR::TypeAlias& ta) { @@ -788,9 +788,9 @@ namespace { { serialise_generics(item.m_params); m_out.write_tag( static_cast<int>(item.m_repr) ); - + serialise_vec( item.m_variants ); - + serialise(item.m_markings); } void serialise(const ::HIR::Enum::Variant& v) @@ -811,7 +811,7 @@ namespace { ) ) } - + void serialise(const ::HIR::TraitMarkings& m) { uint8_t bitflag_1 = 0; @@ -822,7 +822,7 @@ namespace { BIT(3, m.has_drop_impl) #undef BIT m_out.write_u8(bitflag_1); - + m_out.write_tag( static_cast<unsigned int>(m.dst_type) ); m_out.write_count( m.coerce_unsized_index ); m_out.write_count( m.unsized_field ); @@ -832,10 +832,10 @@ namespace { void serialise(const ::HIR::Struct& item) { TRACE_FUNCTION_F("Struct"); - + serialise_generics(item.m_params); m_out.write_tag( static_cast<int>(item.m_repr) ); - + m_out.write_tag( item.m_data.tag() ); TU_MATCHA( (item.m_data), (e), (Unit, @@ -847,18 +847,18 @@ namespace { serialise_vec(e); ) ) - + serialise(item.m_markings); } void serialise(const ::HIR::Union& item) { TRACE_FUNCTION_F("Union"); - + serialise_generics(item.m_params); m_out.write_tag( static_cast<int>(item.m_repr) ); - + serialise_vec(item.m_variants); - + serialise(item.m_markings); } void serialise(const ::HIR::Trait& item) diff --git a/src/hir/serialise_lowlevel.cpp b/src/hir/serialise_lowlevel.cpp index 95a547c8..a3bb3870 100644 --- a/src/hir/serialise_lowlevel.cpp +++ b/src/hir/serialise_lowlevel.cpp @@ -19,7 +19,7 @@ class WriterInner ::std::ofstream m_backing; z_stream m_zstream; ::std::vector<unsigned char> m_buffer; - + unsigned int m_byte_out_count = 0; unsigned int m_byte_in_count = 0; public: @@ -51,7 +51,7 @@ WriterInner::WriterInner(const ::std::string& filename): m_zstream.zalloc = Z_NULL; m_zstream.zfree = Z_NULL; m_zstream.opaque = Z_NULL; - + const int COMPRESSION_LEVEL = Z_BEST_COMPRESSION; int ret = deflateInit(&m_zstream, COMPRESSION_LEVEL); if(ret != Z_OK) @@ -63,7 +63,7 @@ WriterInner::WriterInner(const ::std::string& filename): WriterInner::~WriterInner() { assert( m_zstream.avail_in == 0 ); - + // Complete the compression int ret; do @@ -78,7 +78,7 @@ WriterInner::~WriterInner() size_t rem = m_buffer.size() - m_zstream.avail_out; m_byte_out_count += rem; m_backing.write( reinterpret_cast<char*>(m_buffer.data()), rem ); - + m_zstream.avail_out = m_buffer.size(); m_zstream.next_out = m_buffer.data(); } @@ -90,23 +90,23 @@ void WriterInner::write(const void* buf, size_t len) { m_zstream.avail_in = len; m_zstream.next_in = reinterpret_cast<unsigned char*>( const_cast<void*>(buf) ); - + size_t last_avail_in = m_zstream.avail_in; // While there's data to compress while( m_zstream.avail_in > 0 ) { assert(m_zstream.avail_out != 0); - + // Compress the data int ret = deflate(&m_zstream, Z_NO_FLUSH); if(ret == Z_STREAM_ERROR) throw ::std::runtime_error("zlib deflate stream error"); - + size_t used_this_time = last_avail_in - m_zstream.avail_in; last_avail_in = m_zstream.avail_in; m_byte_in_count += used_this_time; - + // If the entire input wasn't consumed, then it was likely due to a lack of output space // - Flush the output buffer to the file if( m_zstream.avail_in > 0 ) @@ -114,7 +114,7 @@ void WriterInner::write(const void* buf, size_t len) size_t bytes = m_buffer.size() - m_zstream.avail_out; m_backing.write( reinterpret_cast<char*>(m_buffer.data()), bytes ); m_byte_out_count += bytes; - + m_zstream.avail_out = m_buffer.size(); m_zstream.next_out = m_buffer.data(); } @@ -126,10 +126,10 @@ void WriterInner::write(const void* buf, size_t len) size_t bytes = m_buffer.size() - m_zstream.avail_out; m_backing.write( reinterpret_cast<char*>(m_buffer.data()), bytes ); m_byte_out_count += bytes; - + m_zstream.avail_out = m_buffer.size(); m_zstream.next_out = m_buffer.data(); - + int ret = deflate(&m_zstream, Z_NO_FLUSH); if(ret == Z_STREAM_ERROR) throw ::std::runtime_error("zlib deflate stream error"); @@ -201,7 +201,7 @@ void Reader::read(void* buf, size_t len) } buf = reinterpret_cast<uint8_t*>(buf) + used; len -= used; - + if( len >= m_buffer.capacity() ) { m_inner->read(buf, len); @@ -224,7 +224,7 @@ ReaderInner::ReaderInner(const ::std::string& filename): m_zstream.zalloc = Z_NULL; m_zstream.zfree = Z_NULL; m_zstream.opaque = Z_NULL; - + int ret = inflateInit(&m_zstream); if(ret != Z_OK) throw ::std::runtime_error("zlib init failure"); @@ -251,10 +251,10 @@ size_t ReaderInner::read(void* buf, size_t len) return len - m_zstream.avail_out; } m_zstream.next_in = const_cast<unsigned char*>(m_buffer.data()); - + m_byte_in_count += m_zstream.avail_in; } - + int ret = inflate(&m_zstream, Z_NO_FLUSH); if(ret == Z_STREAM_ERROR) throw ::std::runtime_error("zlib inflate stream error"); @@ -268,10 +268,10 @@ size_t ReaderInner::read(void* buf, size_t len) default: break; } - + } while( m_zstream.avail_out > 0 ); m_byte_out_count += len; - + return len; } diff --git a/src/hir/serialise_lowlevel.hpp b/src/hir/serialise_lowlevel.hpp index 5172e8e9..fb4504e7 100644 --- a/src/hir/serialise_lowlevel.hpp +++ b/src/hir/serialise_lowlevel.hpp @@ -26,9 +26,9 @@ public: Writer(const Writer&) = delete; Writer(Writer&&) = delete; ~Writer(); - + void write(const void* data, size_t count); - + void write_u8(uint8_t v) { write(reinterpret_cast<const char*>(&v), 1); } @@ -134,7 +134,7 @@ class ReadBuffer unsigned int m_ofs; public: ReadBuffer(size_t size); - + size_t capacity() const { return m_backing.capacity(); } size_t read(void* dst, size_t len); void populate(ReaderInner& is); @@ -151,7 +151,7 @@ public: ~Reader(); void read(void* dst, size_t count); - + uint8_t read_u8() { uint8_t v; read(&v, sizeof v); @@ -212,7 +212,7 @@ public: uint64_t va = read_u64c(); bool sign = (va & 0x1) != 0; va >>= 1; - + if( va == 0 && sign ) { return INT64_MIN; } diff --git a/src/hir/type.cpp b/src/hir/type.cpp index c5e1984a..f2709a90 100644 --- a/src/hir/type.cpp +++ b/src/hir/type.cpp @@ -31,10 +31,10 @@ namespace HIR { case CoreType::I32: return os << "i32"; case CoreType::U64: return os << "u64"; case CoreType::I64: return os << "i64"; - + case CoreType::F32: return os << "f32"; case CoreType::F64: return os << "f64"; - + case CoreType::Bool: return os << "bool"; case CoreType::Char: return os << "char"; case CoreType::Str: return os << "str"; @@ -185,7 +185,7 @@ bool ::HIR::TypeRef::operator==(const ::HIR::TypeRef& x) const { if( m_data.tag() != x.m_data.tag() ) return false; - + TU_MATCH(::HIR::TypeRef::Data, (m_data, x.m_data), (te, xe), (Infer, // TODO: Should comparing inferrence vars be an error? @@ -306,9 +306,9 @@ bool ::HIR::TypeRef::operator==(const ::HIR::TypeRef& x) const Ordering HIR::TypeRef::ord(const ::HIR::TypeRef& x) const { Ordering rv; - + ORD( static_cast<unsigned int>(m_data.tag()), static_cast<unsigned int>(x.m_data.tag()) ); - + TU_MATCH(::HIR::TypeRef::Data, (m_data, x.m_data), (te, xe), (Infer, // TODO: Should comparing inferrence vars be an error? @@ -454,7 +454,7 @@ namespace { if( t.m_types.size() != x.m_types.size() ) { return ::HIR::Compare::Unequal; } - + auto rv = ::HIR::Compare::Equal; for(unsigned int i = 0; i < t.m_types.size(); i ++ ) { @@ -462,7 +462,7 @@ namespace { if( rv == ::HIR::Compare::Unequal ) return rv; } - + return rv; } } @@ -533,11 +533,11 @@ bool ::HIR::TypeRef::match_test_generics(const Span& sp, const ::HIR::TypeRef& x break; } ) - + TU_IFLET(::HIR::TypeRef::Data, v.m_data, Infer, te, // TODO: Restrict this block with a flag so it panics if an ivar is seen when not expected ASSERT_BUG(sp, te.index != ~0u, "Encountered ivar for `this` - " << v); - + switch(te.ty_class) { case ::HIR::InferClass::None: @@ -576,7 +576,7 @@ bool ::HIR::TypeRef::match_test_generics(const Span& sp, const ::HIR::TypeRef& x break; } ) - + if( v.m_data.tag() != x.m_data.tag() ) { // HACK: If the path is Opaque, return a fuzzy match. // - This works around an impl selection bug. @@ -644,7 +644,7 @@ bool ::HIR::TypeRef::match_test_generics(const Span& sp, const ::HIR::TypeRef& x ) ) } - + if( rv == ::HIR::Compare::Unequal ) { if( te.binding.is_Unbound() || xe.binding.is_Unbound() ) { rv = ::HIR::Compare::Fuzzy; @@ -668,7 +668,7 @@ bool ::HIR::TypeRef::match_test_generics(const Span& sp, const ::HIR::TypeRef& x { cmp &= match_generics_pp(sp, te.m_markers[i].m_params, xe.m_markers[i].m_params, resolve_placeholder, callback); } - + auto it_l = te.m_trait.m_type_bounds.begin(); auto it_r = xe.m_trait.m_type_bounds.begin(); while( it_l != te.m_trait.m_type_bounds.end() && it_r != xe.m_trait.m_type_bounds.end() ) @@ -680,7 +680,7 @@ bool ::HIR::TypeRef::match_test_generics(const Span& sp, const ::HIR::TypeRef& x ++ it_l; ++ it_r; } - + if( it_l != te.m_trait.m_type_bounds.end() || it_r != xe.m_trait.m_type_bounds.end() ) { return Compare::Unequal; } @@ -859,12 +859,12 @@ bool ::HIR::TypeRef::match_test_generics(const Span& sp, const ::HIR::TypeRef& 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)); - + // If the two types are the same ivar, return equal if( left.m_data.is_Infer() && left == right ) { return Compare::Equal; } - + // If left is infer TU_IFLET(::HIR::TypeRef::Data, left.m_data, Infer, e, switch(e.ty_class) @@ -934,7 +934,7 @@ bool ::HIR::TypeRef::match_test_generics(const Span& sp, const ::HIR::TypeRef& x } throw ""; ) - + // If righthand side is infer, it's a fuzzy match (or not a match) TU_IFLET(::HIR::TypeRef::Data, right.m_data, Infer, e, switch( e.ty_class ) @@ -982,10 +982,10 @@ bool ::HIR::TypeRef::match_test_generics(const Span& sp, const ::HIR::TypeRef& x } throw ""; ) - + // If righthand is a type parameter, it can only match another type parameter // - 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; diff --git a/src/hir/type.hpp b/src/hir/type.hpp index d7436607..adb4e82c 100644 --- a/src/hir/type.hpp +++ b/src/hir/type.hpp @@ -38,9 +38,9 @@ enum class CoreType U16, I16, U32, I32, U64, I64, - + F32, F64, - + Bool, Char, Str, }; @@ -80,7 +80,7 @@ extern ::std::ostream& operator<<(::std::ostream& os, const BorrowType& bt); struct LifetimeRef { ::std::string name; - + bool operator==(const LifetimeRef& x) const { return name == x.name; } @@ -101,7 +101,7 @@ public: // - Primitive // - Parameter // - Path - + // - Array // - Tuple // - Borrow @@ -169,15 +169,15 @@ public: ::std::vector<TypeRef> m_arg_types; }) ); - + Data m_data; - + TypeRef() {} TypeRef(TypeRef&& ) = default; TypeRef(const TypeRef& ) = delete; TypeRef& operator=(TypeRef&& ) = default; TypeRef& operator=(const TypeRef&) = delete; - + struct TagUnit {}; TypeRef(TagUnit ): m_data( Data::make_Tuple({}) ) @@ -227,27 +227,27 @@ public: static TypeRef new_closure(::HIR::ExprNode_Closure* node_ptr, ::std::vector< ::HIR::TypeRef> args, ::HIR::TypeRef rv) { return TypeRef(Data::make_Closure({ node_ptr, box$(mv$(rv)), mv$(args) })); } - + TypeRef clone() const; - + void fmt(::std::ostream& os) const; - + bool operator==(const ::HIR::TypeRef& x) const; bool operator!=(const ::HIR::TypeRef& x) const { return !(*this == x); } bool operator<(const ::HIR::TypeRef& x) const { return ord(x) == OrdLess; } Ordering ord(const ::HIR::TypeRef& x) const; bool contains_generics() const; - + // Match generics in `this` with types from `x` // Raises a bug against `sp` if there is a form mismatch or `this` has an infer void match_generics(const Span& sp, const ::HIR::TypeRef& x, t_cb_resolve_type resolve_placeholder, t_cb_match_generics) const; - + bool match_test_generics(const Span& sp, const ::HIR::TypeRef& x, t_cb_resolve_type resolve_placeholder, t_cb_match_generics) const; - + // Compares this type with another, calling the first callback to resolve placeholders in the other type, and the second callback for generics in this type ::HIR::Compare match_test_generics_fuzz(const Span& sp, const ::HIR::TypeRef& x_in, t_cb_resolve_type resolve_placeholder, t_cb_match_generics callback) const; - + // Compares this type with another, using `resolve_placeholder` to get replacements for generics/infers in `x` Compare compare_with_placeholders(const Span& sp, const ::HIR::TypeRef& x, t_cb_resolve_type resolve_placeholder) const; }; diff --git a/src/hir/visitor.cpp b/src/hir/visitor.cpp index 889b3a77..40bc14a4 100644 --- a/src/hir/visitor.cpp +++ b/src/hir/visitor.cpp @@ -15,7 +15,7 @@ void ::HIR::Visitor::visit_crate(::HIR::Crate& crate) { this->visit_module(::HIR::ItemPath(), crate.m_root_module ); - + for( auto& ty_impl : crate.m_type_impls ) { this->visit_type_impl(ty_impl); @@ -102,7 +102,7 @@ void ::HIR::Visitor::visit_type_impl(::HIR::TypeImpl& impl) TRACE_FUNCTION_F("impl.m_type=" << impl.m_type); this->visit_params(impl.m_params); this->visit_type(impl.m_type); - + for(auto& method : impl.m_methods) { DEBUG("method " << method.first); this->visit_function(p + method.first, method.second.data); @@ -124,7 +124,7 @@ void ::HIR::Visitor::visit_trait_impl(const ::HIR::SimplePath& trait_path, ::HIR impl.m_trait_args = mv$(gp.m_params); } this->visit_type(impl.m_type); - + for(auto& ent : impl.m_methods) { DEBUG("method " << ent.first); this->visit_function(p + ent.first, ent.second.data); @@ -159,7 +159,7 @@ void ::HIR::Visitor::visit_trait(::HIR::ItemPath p, ::HIR::Trait& item) ::HIR::SimplePath trait_sp = p.get_simple_path(); ItemPath trait_ip(trait_sp); TRACE_FUNCTION; - + this->visit_params(item.m_params); for(auto& par : item.m_parent_traits) { this->visit_trait_path(par); diff --git a/src/hir/visitor.hpp b/src/hir/visitor.hpp index dfae710d..dbf759a4 100644 --- a/src/hir/visitor.hpp +++ b/src/hir/visitor.hpp @@ -20,15 +20,15 @@ class Visitor { public: virtual ~Visitor(); - + virtual void visit_crate(::HIR::Crate& crate); - + virtual void visit_module(ItemPath p, ::HIR::Module& mod); - + virtual void visit_type_impl(::HIR::TypeImpl& impl); virtual void visit_trait_impl(const ::HIR::SimplePath& trait_path, ::HIR::TraitImpl& impl); virtual void visit_marker_impl(const ::HIR::SimplePath& trait_path, ::HIR::MarkerImpl& impl); - + // - Type Items virtual void visit_type_alias(ItemPath p, ::HIR::TypeAlias& item); virtual void visit_trait(ItemPath p, ::HIR::Trait& item); @@ -39,17 +39,17 @@ public: virtual void visit_function(ItemPath p, ::HIR::Function& item); virtual void visit_static(ItemPath p, ::HIR::Static& item); virtual void visit_constant(ItemPath p, ::HIR::Constant& item); - + // - Misc virtual void visit_params(::HIR::GenericParams& params); virtual void visit_pattern(::HIR::Pattern& pat); virtual void visit_pattern_val(::HIR::Pattern::Value& val); virtual void visit_type(::HIR::TypeRef& tr); - + enum class PathContext { TYPE, TRAIT, - + VALUE, }; virtual void visit_trait_path(::HIR::TraitPath& p); diff --git a/src/hir_conv/bind.cpp b/src/hir_conv/bind.cpp index 198b8ea1..4601b90d 100644 --- a/src/hir_conv/bind.cpp +++ b/src/hir_conv/bind.cpp @@ -18,7 +18,7 @@ void ConvertHIR_Bind(::HIR::Crate& crate); namespace { - + enum class Target { TypeItem, Struct, @@ -36,7 +36,7 @@ namespace { else { mod = &crate.m_root_module; } - + for( unsigned int i = 0; i < path.m_components.size()-1; i ++ ) { const auto& pc = path.m_components[i]; @@ -44,7 +44,7 @@ namespace { if( it == mod->m_mod_items.end() ) { BUG(sp, "Couldn't find component " << i << " of " << path); } - + // If second-last, and an enum variant is desired, return the pointer to the enum if( i+1 == path.m_components.size()-1 && t == Target::EnumVariant ) { @@ -72,12 +72,12 @@ namespace { if( it == mod->m_mod_items.end() ) { BUG(sp, "Couldn't find final component of " << path); } - + switch(t) { case Target::TypeItem: return &it->second->ent; case Target::EnumVariant: throw ""; - + case Target::Struct: TU_IFLET(::HIR::TypeItem, it->second->ent, Struct, e2, return &e2; @@ -97,7 +97,7 @@ namespace { } throw ""; } - + void fix_type_params(const Span& sp, const ::HIR::GenericParams& params_def, ::HIR::PathParams& params) { #if 1 @@ -109,7 +109,7 @@ namespace { } #endif } - + const ::HIR::Struct& get_struct_ptr(const Span& sp, const ::HIR::Crate& crate, ::HIR::GenericPath& path) { const auto& str = *reinterpret_cast< const ::HIR::Struct*>( get_type_pointer(sp, crate, path.m_path, Target::Struct) ); fix_type_params(sp, str.m_params, path.m_params); @@ -122,12 +122,12 @@ namespace { if( idx == enm.m_variants.size() ) { ERROR(sp, E0000, "Couldn't find enum variant " << path); } - + fix_type_params(sp, enm.m_params, path.m_params); return ::std::make_pair( &enm, idx ); } - - + + class Visitor: public ::HIR::Visitor { @@ -137,15 +137,15 @@ namespace { Visitor(const ::HIR::Crate& crate): m_crate(crate) {} - + void visit_trait_path(::HIR::TraitPath& p) override { static Span sp; p.m_trait_ptr = &m_crate.get_trait_by_path(sp, p.m_path.m_path); - + ::HIR::Visitor::visit_trait_path(p); } - + void visit_literal(const Span& sp, ::HIR::Literal& lit) { TU_MATCH(::HIR::Literal, (lit), (e), @@ -172,11 +172,11 @@ namespace { ) ) } - + void visit_pattern_Value(const Span& sp, ::HIR::Pattern& pat, ::HIR::Pattern::Value& val) { bool is_single_value = pat.m_data.is_Value(); - + TU_IFLET( ::HIR::Pattern::Value, val, Named, ve, TU_IFLET( ::HIR::Path::Data, ve.path.m_data, Generic, pe, const ::HIR::Enum* enm = nullptr; @@ -196,7 +196,7 @@ namespace { if( it == mod->m_mod_items.end() ) { BUG(sp, "Couldn't find component " << i << " of " << path); } - + if( i == path.m_components.size() - 2 ) { // Here it's allowed to be either a module, or an enum. TU_IFLET( ::HIR::TypeItem, it->second->ent, Module, e2, @@ -223,7 +223,7 @@ namespace { if( !is_single_value ) { ERROR(sp, E0000, "Enum variant in range pattern - " << pat); } - + // Enum variant auto it = ::std::find_if( enm->m_variants.begin(), enm->m_variants.end(), [&](const auto&v){ return v.first == pc; }); if( it == enm->m_variants.end() ) { @@ -273,15 +273,15 @@ namespace { } ) } - - + + void visit_pattern(::HIR::Pattern& pat) override { static Span _sp = Span(); const Span& sp = _sp; ::HIR::Visitor::visit_pattern(pat); - + TU_MATCH_DEF(::HIR::Pattern::Data, (pat.m_data), (e), ( ), @@ -340,7 +340,7 @@ namespace { // Nothing to do, all good return ; } - + if( params.m_types.size() == 0 ) { for(const auto& typ : param_defs.m_types) { (void)typ; @@ -368,7 +368,7 @@ namespace { //TRACE_FUNCTION_F(ty); static Span _sp = Span(); const Span& sp = _sp; - + TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Path, e, TU_MATCH( ::HIR::Path::Data, (e.path.m_data), (pe), (Generic, @@ -426,10 +426,10 @@ namespace { ) ) ) - + ::HIR::Visitor::visit_type(ty); } - + void visit_static(::HIR::ItemPath p, ::HIR::Static& i) override { ::HIR::Visitor::visit_static(p, i); @@ -440,23 +440,23 @@ namespace { ::HIR::Visitor::visit_constant(p, i); visit_literal(Span(), i.m_value_res); } - + void visit_expr(::HIR::ExprPtr& expr) override { struct ExprVisitor: public ::HIR::ExprVisitorDef { Visitor& upper_visitor; - + ExprVisitor(Visitor& uv): upper_visitor(uv) {} - + void visit_generic_path(::HIR::Visitor::PathContext pc, ::HIR::GenericPath& p) { upper_visitor.visit_generic_path(p, pc); } - + void visit_node_ptr(::HIR::ExprNodeP& node_ptr) override { upper_visitor.visit_type(node_ptr->m_res_type); @@ -482,7 +482,7 @@ namespace { upper_visitor.visit_type(node.m_res_type); ::HIR::ExprVisitorDef::visit(node); } - + void visit(::HIR::ExprNode_PathValue& node) override { upper_visitor.visit_path(node.m_path, ::HIR::Visitor::PathContext::VALUE); @@ -497,13 +497,13 @@ namespace { upper_visitor.visit_path_params(node.m_params); ::HIR::ExprVisitorDef::visit(node); } - + void visit(::HIR::ExprNode_StructLiteral& node) override { upper_visitor.visit_generic_path(node.m_path, ::HIR::Visitor::PathContext::TYPE); ::HIR::ExprVisitorDef::visit(node); } - + void visit(::HIR::ExprNode_Closure& node) override { upper_visitor.visit_type(node.m_return); @@ -514,7 +514,7 @@ namespace { ::HIR::ExprVisitorDef::visit(node); } }; - + if( expr.get() != nullptr ) { ExprVisitor v { *this }; @@ -675,7 +675,7 @@ 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) { diff --git a/src/hir_conv/constant_evaluation.cpp b/src/hir_conv/constant_evaluation.cpp index 38444b82..35cacbcd 100644 --- a/src/hir_conv/constant_evaluation.cpp +++ b/src/hir_conv/constant_evaluation.cpp @@ -16,13 +16,13 @@ namespace { typedef ::std::vector< ::std::pair< ::std::string, ::HIR::Static> > t_new_values; - + struct NewvalState { t_new_values& newval_output; const ::HIR::ItemPath& mod_path; ::std::string name_prefix; unsigned int next_item_idx; - + NewvalState(t_new_values& newval_output, const ::HIR::ItemPath& mod_path, ::std::string prefix): newval_output(newval_output), mod_path(mod_path), @@ -30,7 +30,7 @@ namespace { next_item_idx(0) { } - + ::HIR::SimplePath new_static(::HIR::TypeRef type, ::HIR::Literal value) { auto name = FMT(name_prefix << next_item_idx); @@ -46,9 +46,9 @@ namespace { return rv; } }; - + ::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 clone_literal(const ::HIR::Literal& v) { TU_MATCH(::HIR::Literal, (v), (e), @@ -84,7 +84,7 @@ namespace { ) throw ""; } - + TAGGED_UNION(EntPtr, NotFound, (NotFound, struct{}), (Function, const ::HIR::Function*), @@ -106,7 +106,7 @@ namespace { else { mod = &crate.m_root_module; } - + for( unsigned int i = 0; i < path.m_components.size() - 1; i ++ ) { const auto& pc = path.m_components[i]; @@ -123,7 +123,7 @@ namespace { ) ) } - + switch( ns ) { case EntNS::Value: { @@ -131,7 +131,7 @@ namespace { if( it == mod->m_value_items.end() ) { return EntPtr {}; } - + TU_MATCH( ::HIR::ValueItem, (it->second->ent), (e), (Import, ), @@ -156,7 +156,7 @@ namespace { if( it == mod->m_mod_items.end() ) { return EntPtr {}; } - + TU_MATCH( ::HIR::TypeItem, (it->second->ent), (e), (Import, ), @@ -268,7 +268,7 @@ namespace { TODO(sp, "Could not find function for " << path << " - " << rv.tag_str()); } } - + ::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) { struct Visitor: @@ -276,26 +276,26 @@ namespace { { const ::HIR::Crate& m_crate; NewvalState m_newval_state; - + ::std::vector< ::HIR::Literal> m_values; - + ::HIR::TypeRef m_exp_type; ::HIR::TypeRef m_rv_type; ::HIR::Literal m_rv; - + Visitor(const ::HIR::Crate& crate, NewvalState newval_state, ::HIR::TypeRef exp_ty): m_crate(crate), m_newval_state( mv$(newval_state) ), m_exp_type( mv$(exp_ty) ) {} - + void badnode(const ::HIR::ExprNode& node) const { ERROR(node.span(), E0000, "Node " << typeid(node).name() << " not allowed in constant expression"); } - + void visit(::HIR::ExprNode_Block& node) override { TRACE_FUNCTION_F("_Block"); - + for(const auto& e : node.m_nodes) { e->visit(*this); @@ -319,7 +319,7 @@ namespace { void visit(::HIR::ExprNode_If& node) override { badnode(node); } - + void visit(::HIR::ExprNode_Assign& node) override { badnode(node); } @@ -329,11 +329,11 @@ namespace { auto left = mv$(m_rv); node.m_right->visit(*this); auto right = mv$(m_rv); - + if( left.tag() != right.tag() ) { ERROR(node.span(), E0000, "ExprNode_BinOp - Types mismatched - " << left.tag_str() << " != " << right.tag_str()); } - + // Keep m_rv_type switch(node.m_op) { @@ -421,17 +421,17 @@ namespace { ) break; } - + m_rv_type = m_exp_type.clone(); } void visit(::HIR::ExprNode_UniOp& node) override { TRACE_FUNCTION_FR("_UniOp", m_rv); - + auto exp_type = m_exp_type.clone(); - + node.m_value->visit(*this); auto val = mv$(m_rv); - + // Keep m_rv_type switch(node.m_op) { @@ -453,12 +453,12 @@ namespace { m_rv_type = mv$(exp_type); } void visit(::HIR::ExprNode_Borrow& node) override { - + //m_rv_type = ::HIR::TypeRef(); //m_rv = ::HIR::Literal::make_BorrowOf( ::HIR::SimplePath() ); //return ; //badnode(node); - + TU_MATCH_DEF( ::HIR::TypeRef::Data, (m_exp_type.m_data), (te), ( ERROR(node.span(), E0000, "Invalid expected type for a &-ptr - " << m_exp_type); @@ -470,30 +470,30 @@ namespace { m_exp_type = mv$(inner); ) ) - + node.m_value->visit(*this); auto val = mv$(m_rv); - + if( node.m_type != ::HIR::BorrowType::Shared ) { ERROR(node.span(), E0000, "Only shared borrows are allowed in constants"); } - + if( visit_ty_with(m_rv_type, [&](const auto& x){ return x.m_data.is_Infer(); }) ) { ERROR(node.span(), E0000, "Could not trivially infer type of referenced static - " << m_rv_type << ", lit = " << val); } - + // Create new static containing borrowed data //auto path = m_newval_state.new_static( m_rv_type.clone(), mv$(val) ); auto path = m_newval_state.new_static( ::HIR::TypeRef(), mv$(val) ); - + m_rv_type = ::HIR::TypeRef::new_borrow( node.m_type, mv$(m_rv_type) ); m_rv = ::HIR::Literal::make_BorrowOf( mv$(path) ); } void visit(::HIR::ExprNode_Cast& node) override { TRACE_FUNCTION_F("_Cast"); - + m_exp_type = ::HIR::TypeRef(); // Can't know. - + node.m_value->visit(*this); auto val = mv$(m_rv); //DEBUG("ExprNode_Cast - val = " << val << " as " << node.m_type); @@ -548,7 +548,7 @@ namespace { m_rv_type = node.m_res_type.clone(); } void visit(::HIR::ExprNode_Index& node) override { - + auto exp_ty = mv$(m_exp_type); // Index m_exp_type = ::HIR::TypeRef(::HIR::CoreType::Usize); @@ -556,19 +556,19 @@ namespace { if( !m_rv.is_Integer() ) ERROR(node.span(), E0000, "Array index isn't an integer - got " << m_rv.tag_str()); auto idx = m_rv.as_Integer(); - + // Value m_exp_type = ::HIR::TypeRef::new_slice( mv$(exp_ty) ); node.m_value->visit(*this); if( !m_rv.is_List() ) ERROR(node.span(), E0000, "Indexed value isn't a list - got " << m_rv.tag_str()); auto v = mv$( m_rv.as_List() ); - + // -> Perform if( idx >= v.size() ) ERROR(node.span(), E0000, "Constant array index " << idx << " out of range " << v.size()); m_rv = mv$(v[idx]); - + TU_MATCH_DEF( ::HIR::TypeRef::Data, (m_rv_type.m_data), (e), ( ERROR(node.span(), E0000, "Indexing non-array - " << m_rv_type); @@ -585,23 +585,23 @@ namespace { void visit(::HIR::ExprNode_Emplace& node) override { badnode(node); } - + void visit(::HIR::ExprNode_TupleVariant& node) override { m_exp_type = ::HIR::TypeRef(); - + ::std::vector< ::HIR::Literal> vals; for(const auto& vn : node.m_args ) { vn->visit(*this); assert( !m_rv.is_Invalid() ); vals.push_back( mv$(m_rv) ); } - + if( node.m_is_struct ) { const auto& ent = m_crate.get_typeitem_by_path(node.span(), node.m_path.m_path); ASSERT_BUG(node.span(), ent.is_Struct(), "_TupleVariant with m_is_struct set pointing to " << ent.tag_str()); const auto& str = ent.as_Struct(); - + m_rv = ::HIR::Literal::make_List(mv$(vals)); m_rv_type = ::HIR::TypeRef::new_path( node.m_path.clone(), ::HIR::TypeRef::TypePathBinding(&str) ); } @@ -613,7 +613,7 @@ namespace { const auto& ent = m_crate.get_typeitem_by_path(node.span(), tmp_path); ASSERT_BUG(node.span(), ent.is_Enum(), "_TupleVariant with m_is_struct clear pointing to " << ent.tag_str()); const auto& enm = ent.as_Enum(); - + auto it = ::std::find_if( enm.m_variants.begin(), enm.m_variants.end(), [&](const auto&x){ return x.first == varname; } ); ASSERT_BUG(node.span(), it != enm.m_variants.end(), "_TupleVariant points to unknown variant - " << node.m_path); unsigned int var_idx = it - enm.m_variants.begin(); @@ -624,20 +624,20 @@ namespace { } void visit(::HIR::ExprNode_CallPath& node) override { - + TRACE_FUNCTION_FR("_CallPath - " << node.m_path, m_rv); auto& fcn = get_function(node.span(), m_crate, node.m_path); - + // TODO: Set m_const during parse //if( ! fcn.m_const ) { // ERROR(node.span(), E0000, "Calling non-const function in const context - " << node.m_path); //} - + if( fcn.m_args.size() != node.m_args.size() ) { ERROR(node.span(), E0000, "Incorrect argument count for " << node.m_path << " - expected " << fcn.m_args.size() << ", got " << node.m_args.size()); } auto exp_ret_type = mv$( m_exp_type ); - + ::std::vector< ::HIR::Literal> args; args.reserve( fcn.m_args.size() ); for(unsigned int i = 0; i < fcn.m_args.size(); i ++ ) @@ -655,11 +655,11 @@ namespace { else { ERROR(node.span(), E0000, "Constant functions can't have destructuring pattern argments"); } - + node.m_args[i]->visit(*this); args.push_back( mv$(m_rv) ); } - + // Call by invoking evaluate_constant on the function { TRACE_FUNCTION_F("Call const fn " << node.m_path << " args={ " << args << " }"); @@ -676,16 +676,16 @@ namespace { void visit(::HIR::ExprNode_Field& node) override { const auto& sp = node.span(); TRACE_FUNCTION_FR("_Field", m_rv); - + m_exp_type = ::HIR::TypeRef(); - + node.m_value->visit(*this); auto val = mv$( m_rv ); - + if( !val.is_List() ) ERROR(sp, E0000, "Field access on invalid literal type - " << val.tag_str()); auto& vals = val.as_List(); - + TU_MATCH_DEF( ::HIR::TypeRef::Data, (m_rv_type.m_data), (e), ( ERROR(sp, E0000, "Field access on invalid type - " << m_rv_type); @@ -732,7 +732,7 @@ namespace { unsigned int idx = ::std::atoi( node.m_field.c_str() ); ASSERT_BUG(sp, idx < e.size(), "Index out of range in tuple"); ASSERT_BUG(sp, idx < vals.size(), "Index out of range in literal"); - + m_rv = mv$( vals[idx] ); m_rv_type = mv$( e[idx] ); ) @@ -770,7 +770,7 @@ namespace { const auto& ent = m_crate.get_typeitem_by_path(node.span(), node.m_path.m_path); ASSERT_BUG(node.span(), ent.is_Struct(), "_UnitVariant with m_is_struct set pointing to " << ent.tag_str()); const auto& str = ent.as_Struct(); - + m_rv = ::HIR::Literal::make_List({}); m_rv_type = ::HIR::TypeRef::new_path( node.m_path.clone(), ::HIR::TypeRef::TypePathBinding(&str) ); } @@ -782,7 +782,7 @@ namespace { const auto& ent = m_crate.get_typeitem_by_path(node.span(), tmp_path); ASSERT_BUG(node.span(), ent.is_Enum(), "_UnitVariant with m_is_struct clear pointing to " << ent.tag_str()); const auto& enm = ent.as_Enum(); - + auto it = ::std::find_if( enm.m_variants.begin(), enm.m_variants.end(), [&](const auto&x){ return x.first == varname; } ); ASSERT_BUG(node.span(), it != enm.m_variants.end(), "_UnitVariant points to unknown variant - " << node.m_path); unsigned int var_idx = it - enm.m_variants.begin(); @@ -845,24 +845,24 @@ namespace { ) m_rv_type = ::HIR::TypeRef(); // TODO: } - + void visit(::HIR::ExprNode_StructLiteral& node) override { TRACE_FUNCTION_FR("_StructLiteral - " << node.m_path, m_rv); - + if( node.m_is_struct ) { const auto& ent = m_crate.get_typeitem_by_path(node.span(), node.m_path.m_path); ASSERT_BUG(node.span(), ent.is_Struct(), "_StructLiteral with m_is_struct set pointing to a " << ent.tag_str()); const auto& str = ent.as_Struct(); const auto& fields = str.m_data.as_Named(); - + auto rv_type = ::HIR::TypeRef::new_path( node.m_path.clone(), ::HIR::TypeRef::TypePathBinding(&str) ); - + ::std::vector< ::HIR::Literal> vals; if( node.m_base_value ) { m_exp_type = rv_type.clone(); - + node.m_base_value->visit(*this); auto base_val = mv$(m_rv); if( !base_val.is_List() || base_val.as_List().size() != fields.size() ) { @@ -878,14 +878,14 @@ namespace { if( idx == fields.size() ) { ERROR(node.span(), E0000, "Field name " << val_set.first << " isn't a member of " << node.m_path); } - + if( monomorphise_type_needed(fields[idx].second.ent) ) { m_exp_type = ::HIR::TypeRef(); } else { m_exp_type = fields[idx].second.ent.clone(); } - + val_set.second->visit(*this); vals[idx] = mv$(m_rv); } @@ -903,7 +903,7 @@ namespace { { const auto& ent = m_crate.get_typeitem_by_path(node.span(), node.m_path.m_path); ASSERT_BUG(node.span(), ent.is_Enum(), "_StructLiteral with m_is_struct clear pointing to a " << ent.tag_str()); - + TODO(node.span(), "Handle Enum _UnitVariant - " << node.m_path); } } @@ -925,21 +925,21 @@ namespace { ASSERT_BUG(node.span(), exp_tys.size() == node.m_vals.size(), "Tuple literal size mismatches with expected type"); ) ) - + ::std::vector< ::HIR::Literal> vals; ::std::vector< ::HIR::TypeRef> tys; for(unsigned int i = 0; i < node.m_vals.size(); i ++) { if( exp_tys.size() > 0 ) m_exp_type = mv$(exp_tys[i]); - + node.m_vals[i]->visit(*this); assert( !m_rv.is_Invalid() ); - + vals.push_back( mv$(m_rv) ); tys.push_back( mv$(m_rv_type) ); } - + m_rv = ::HIR::Literal::make_List(mv$(vals)); m_rv_type = ::HIR::TypeRef( mv$(tys) ); } @@ -960,7 +960,7 @@ namespace { exp_inner_ty = mv$(*te.inner); ) ) - + ::std::vector< ::HIR::Literal> vals; for(const auto& vn : node.m_vals ) { @@ -969,7 +969,7 @@ namespace { assert( !m_rv.is_Invalid() ); vals.push_back( mv$(m_rv) ); } - + m_rv_type = ::HIR::TypeRef::new_array( mv$(m_rv_type), vals.size() ); m_rv = ::HIR::Literal::make_List(mv$(vals)); } @@ -989,12 +989,12 @@ namespace { exp_inner_ty = mv$(*te.inner); ) ) - + m_exp_type = ::HIR::CoreType::Usize; node.m_size->visit(*this); assert( m_rv.is_Integer() ); unsigned int count = static_cast<unsigned int>(m_rv.as_Integer()); - + ::std::vector< ::HIR::Literal> vals; vals.reserve( count ); if( count > 0 ) @@ -1011,37 +1011,37 @@ namespace { m_rv = ::HIR::Literal::make_List(mv$(vals)); m_rv_type = ::HIR::TypeRef::new_array( mv$(m_rv_type), count ); } - + void visit(::HIR::ExprNode_Closure& node) override { badnode(node); } }; - + Visitor v { crate, newval_state, mv$(exp_type) }; for(auto& arg : args) v.m_values.push_back( mv$(arg) ); const_cast<::HIR::ExprNode&>(expr).visit(v); - + if( v.m_rv.is_Invalid() ) { BUG(sp, "Expression did not yeild a literal"); } - + 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) { TRACE_FUNCTION; - + StaticTraitResolve resolve { crate }; ::MIR::TypeResolve state { sp, resolve, FMT_CB(), exp, {}, fcn }; - + ::HIR::Literal retval; ::std::vector< ::HIR::Literal> locals; ::std::vector< ::HIR::Literal> temps; locals.resize( fcn.named_variables.size() ); temps.resize( fcn.temporaries.size() ); - + auto get_lval = [&](const ::MIR::LValue& lv) -> ::HIR::Literal& { TU_MATCHA( (lv), (e), (Variable, @@ -1098,7 +1098,7 @@ namespace { ) ) }; - + unsigned int cur_block = 0; for(;;) { @@ -1107,12 +1107,12 @@ namespace { for(const auto& stmt : block.statements) { state.set_cur_stmt(cur_block, next_stmt_idx++); - + if( ! stmt.is_Assign() ) { //BUG(sp, "Non-assign statement - drop " << stmt.as_Drop().slot); continue ; } - + ::HIR::Literal val; const auto& sa = stmt.as_Assign(); TU_MATCHA( (sa.src), (e), @@ -1165,14 +1165,14 @@ namespace { if( e.type != ::HIR::BorrowType::Shared ) { MIR_BUG(state, "Only shared borrows are allowed in constants"); } - + auto inner_val = read_lval(e.val); - + ::HIR::TypeRef inner_ty; const auto& inner_ty_r = state.get_lvalue_type(inner_ty, e.val); if( &inner_ty_r != &inner_ty ) inner_ty = inner_ty_r.clone(); - + // Create new static containing borrowed data auto item_path = newval_state.new_static( mv$(inner_ty), mv$(inner_val) ); val = ::HIR::Literal::make_BorrowOf( mv$(item_path) ); @@ -1206,7 +1206,7 @@ namespace { case ::HIR::CoreType::Usize: case ::HIR::CoreType::Isize: mask = 0xFFFFFFFFFFFFFFFF; - + TU_IFLET( ::HIR::Literal, inval, Integer, i, val = ::HIR::Literal(i & mask); ) @@ -1268,7 +1268,7 @@ namespace { case ::MIR::eBinOp::MUL_OV: case ::MIR::eBinOp::DIV_OV: TODO(sp, "RValue::BinOp - " << sa.src << ", val = " << inval_l << " , " << inval_r); - + case ::MIR::eBinOp::BIT_OR : case ::MIR::eBinOp::BIT_AND: case ::MIR::eBinOp::BIT_XOR: @@ -1297,7 +1297,7 @@ namespace { case ::MIR::eBinOp::MUL_OV: case ::MIR::eBinOp::DIV_OV: TODO(sp, "RValue::BinOp - " << sa.src << ", val = " << inval_l << " , " << inval_r); - + case ::MIR::eBinOp::BIT_OR : val = ::HIR::Literal( l | r ); break; case ::MIR::eBinOp::BIT_AND: val = ::HIR::Literal( l & r ); break; case ::MIR::eBinOp::BIT_XOR: val = ::HIR::Literal( l ^ r ); break; @@ -1383,7 +1383,7 @@ namespace { val = ::HIR::Literal::make_List( mv$(vals) ); ) ) - + auto& dst = get_lval(sa.dst); dst = mv$(val); } @@ -1405,25 +1405,25 @@ namespace { auto& dst = get_lval(e.ret_val); auto& fcn = get_function(sp, crate, fcnp); - + ::std::vector< ::HIR::Literal> call_args; call_args.reserve( e.args.size() ); for(const auto& a : e.args) call_args.push_back( read_lval(a) ); // TODO: Set m_const during parse and check here - + // 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, ::HIR::TypeRef(), mv$(call_args)); } - + cur_block = e.ret_block; ) ) } } - + ::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) { if( expr.m_mir ) { @@ -1436,7 +1436,7 @@ namespace { BUG(sp, "Attempting to evaluate constant expression with no associated code"); } } - + void check_lit_type(const Span& sp, const ::HIR::TypeRef& type, ::HIR::Literal& lit) { // TODO: Mask down limited size integers @@ -1455,7 +1455,7 @@ namespace { ), (Closure, ), - + (Path, // List ), @@ -1465,7 +1465,7 @@ namespace { (Tuple, // List ), - + (Borrow, // A whole host of things ), @@ -1475,7 +1475,7 @@ namespace { (Function, // ItemAddr ), - + (Primitive, switch(te) { @@ -1492,7 +1492,7 @@ namespace { case ::HIR::CoreType::U8: lit.as_Integer() &= (1ull<<8)-1; break; case ::HIR::CoreType::U16: lit.as_Integer() &= (1ull<<16)-1; break; case ::HIR::CoreType::U32: lit.as_Integer() &= (1ull<<32)-1; break; - + case ::HIR::CoreType::I8: lit.as_Integer() &= (1ull<<8)-1; break; case ::HIR::CoreType::I16: lit.as_Integer() &= (1ull<<16)-1; break; case ::HIR::CoreType::I32: lit.as_Integer() &= (1ull<<32)-1; break; @@ -1516,15 +1516,15 @@ namespace { Expander(const ::HIR::Crate& crate): m_crate(crate) {} - + void visit_module(::HIR::ItemPath p, ::HIR::Module& mod) override { auto saved_mp = m_mod_path; m_mod_path = &p; auto saved = mv$( m_new_values ); - + ::HIR::Visitor::visit_module(p, mod); - + for( auto& item : m_new_values ) { mod.m_value_items.insert( ::std::make_pair( @@ -1535,11 +1535,11 @@ namespace { m_new_values = mv$(saved); m_mod_path = saved_mp; } - + void visit_type(::HIR::TypeRef& ty) override { ::HIR::Visitor::visit_type(ty); - + TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Array, e, if( e.size_val == ~0u ) { @@ -1558,7 +1558,7 @@ namespace { void visit_constant(::HIR::ItemPath p, ::HIR::Constant& item) override { ::HIR::Visitor::visit_constant(p, item); - + if( item.m_value ) { //if( item.m_type.m_data.is_Primitive() ) @@ -1567,12 +1567,12 @@ namespace { // ; //else // 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(), {}); - + check_lit_type(item.m_value->span(), item.m_type, item.m_value_res); - + DEBUG("constant: " << item.m_type << " = " << item.m_value_res); } } @@ -1586,18 +1586,18 @@ namespace { } ::HIR::Visitor::visit_enum(p, item); } - + void visit_expr(::HIR::ExprPtr& expr) override { struct Visitor: public ::HIR::ExprVisitorDef { Expander& m_exp; - + Visitor(Expander& exp): m_exp(exp) {} - + void visit(::HIR::ExprNode_Let& node) override { ::HIR::ExprVisitorDef::visit(node); m_exp.visit_type(node.m_type); @@ -1627,7 +1627,7 @@ namespace { node.m_size_val = val.as_Integer(); DEBUG("Array literal [?; " << node.m_size_val << "]"); } - + void visit(::HIR::ExprNode_CallPath& node) override { ::HIR::ExprVisitorDef::visit(node); m_exp.visit_path(node.m_path, ::HIR::Visitor::PathContext::VALUE); @@ -1637,7 +1637,7 @@ namespace { m_exp.visit_path_params(node.m_params); } }; - + if( expr.get() != nullptr ) { Visitor v { *this }; diff --git a/src/hir_conv/expand_type.cpp b/src/hir_conv/expand_type.cpp index 5e95592c..dccccace 100644 --- a/src/hir_conv/expand_type.cpp +++ b/src/hir_conv/expand_type.cpp @@ -10,7 +10,7 @@ ::HIR::TypeRef ConvertHIR_ExpandAliases_GetExpansion_GP(const Span& sp, const ::HIR::Crate& crate, const ::HIR::GenericPath& path, bool is_expr) { ::HIR::TypeRef empty_type; - + const auto& ti = crate.get_typeitem_by_path(sp, path.m_path); TU_MATCH_DEF( ::HIR::TypeItem, (ti), (e2), ( @@ -79,11 +79,11 @@ public: Expander(const ::HIR::Crate& crate): m_crate(crate) {} - + void visit_type(::HIR::TypeRef& ty) override { ::HIR::Visitor::visit_type(ty); - + TU_IFLET(::HIR::TypeRef::Data, (ty.m_data), Path, (e), ::HIR::TypeRef new_type = ConvertHIR_ExpandAliases_GetExpansion(m_crate, e.path, m_in_expr); // Keep trying to expand down the chain @@ -110,15 +110,15 @@ public: } ) } - - + + ::HIR::GenericPath expand_alias_gp(const Span& sp, const ::HIR::GenericPath& path) { const unsigned int MAX_RECURSIVE_TYPE_EXPANSIONS = 100; - + ::HIR::GenericPath rv; const auto* cur = &path; - + unsigned int num_exp = 0; do { auto ty = ConvertHIR_ExpandAliases_GetExpansion_GP(sp, m_crate, *cur, m_in_expr); @@ -130,20 +130,20 @@ public: if( !ty_p.m_data.is_Generic() ) ERROR(sp, E0000, "Type alias referenced in generic path doesn't point to a generic path"); rv = mv$( ty_p.m_data.as_Generic() ); - + this->visit_generic_path(rv, ::HIR::Visitor::PathContext::TYPE); - + cur = &rv; } while( ++num_exp < MAX_RECURSIVE_TYPE_EXPANSIONS ); ASSERT_BUG(sp, num_exp < MAX_RECURSIVE_TYPE_EXPANSIONS, "Recursion limit expanding " << path << " (currently on " << *cur << ")"); return rv; } - + void visit_pattern(::HIR::Pattern& pat) override { static Span sp; ::HIR::Visitor::visit_pattern(pat); - + TU_MATCH_DEF( ::HIR::Pattern::Data, (pat.m_data), (e), ( ), @@ -173,18 +173,18 @@ public: ) ) } - + void visit_expr(::HIR::ExprPtr& expr) override { struct Visitor: public ::HIR::ExprVisitorDef { Expander& upper_visitor; - + Visitor(Expander& uv): upper_visitor(uv) {} - + // TODO: Use the other visitors. void visit_path(::HIR::Visitor::PathContext pc, ::HIR::Path& p) { @@ -194,7 +194,7 @@ public: { upper_visitor.visit_generic_path(p, pc); } - + void visit(::HIR::ExprNode_Let& node) override { upper_visitor.visit_type(node.m_type); @@ -206,7 +206,7 @@ public: upper_visitor.visit_type(node.m_res_type); ::HIR::ExprVisitorDef::visit(node); } - + void visit(::HIR::ExprNode_CallPath& node) override { upper_visitor.visit_path(node.m_path, ::HIR::Visitor::PathContext::VALUE); @@ -217,7 +217,7 @@ public: upper_visitor.visit_path_params(node.m_params); ::HIR::ExprVisitorDef::visit(node); } - + void visit(::HIR::ExprNode_Closure& node) override { upper_visitor.visit_type(node.m_return); @@ -227,7 +227,7 @@ public: } ::HIR::ExprVisitorDef::visit(node); } - + void visit(::HIR::ExprNode_StructLiteral& node) override { if( node.m_is_struct ) @@ -239,10 +239,10 @@ public: node.m_path = mv$(new_path); } } - + ::HIR::ExprVisitorDef::visit(node); } - + void visit(::HIR::ExprNode_Match& node) override { for(auto& arm : node.m_arms) { @@ -253,15 +253,15 @@ public: ::HIR::ExprVisitorDef::visit(node); } }; - + if( expr.get() != nullptr ) { auto old = m_in_expr; m_in_expr = true; - + Visitor v { *this }; (*expr).visit(v); - + m_in_expr = old; } } diff --git a/src/hir_conv/markings.cpp b/src/hir_conv/markings.cpp index ed49be52..fe17aedc 100644 --- a/src/hir_conv/markings.cpp +++ b/src/hir_conv/markings.cpp @@ -33,11 +33,11 @@ public: m_lang_PhantomData( crate.get_lang_item_path_opt("phantom_data") ) { } - + void visit_struct(::HIR::ItemPath ip, ::HIR::Struct& str) override { ::HIR::Visitor::visit_struct(ip, str); - + TU_MATCHA( (str.m_data), (se), (Unit, ), @@ -48,7 +48,7 @@ public: // - If it is Sized, leave as-is (struct is marked as Sized) // - If it is known unsized, record the type // - If it is a ?Sized parameter, mark as possible and record index for MIR - + // TODO: Ensure that only the last field is ?Sized if( se.size() > 0 ) { @@ -59,7 +59,7 @@ public: if( last_field.m_data.is_Generic() ) { const auto& te = last_field.m_data.as_Generic(); - + if( str.m_params.m_types.at(te.binding).m_is_sized == false ) { str.m_markings.unsized_field = se.size() - 1; @@ -86,9 +86,9 @@ public: void visit_trait_impl(const ::HIR::SimplePath& trait_path, ::HIR::TraitImpl& impl) override { static Span sp; - + ::HIR::Visitor::visit_trait_impl(trait_path, impl); - + if( impl.m_type.m_data.is_Path() ) { const auto& te = impl.m_type.m_data.as_Path(); @@ -115,7 +115,7 @@ public: else if( trait_path == m_lang_CoerceUnsized ) { if( markings_ptr->coerce_unsized_index != ~0u ) ERROR(sp, E0000, "CoerceUnsized can only be implemented once per struct"); - + DEBUG("Type " << impl.m_type << " can Coerce"); if( impl.m_trait_args.m_types.size() != 1 ) ERROR(sp, E0000, "Unexpected number of arguments for CoerceUnsized"); @@ -130,18 +130,18 @@ public: ERROR(sp, E0000, "Cannot implement CoerceUnsized from non-structs"); if( dst_te.binding.as_Struct() != te.binding.as_Struct() ) ERROR(sp, E0000, "CoerceUnsized can only be implemented between variants of the same struct"); - + // NOTES: (from IRC: eddyb) // < eddyb> they're required that T and U are the same struct definition (with different type parameters) and exactly one field differs in type between T and U (ignoring PhantomData) // < eddyb> Mutabah: I forgot to mention that the field that differs in type must also impl CoerceUnsized - + // Determine the difference in monomorphised variants. unsigned int field = ~0u; const auto& str = te.binding.as_Struct(); - + auto monomorph_cb_l = monomorphise_type_get_cb(sp, nullptr, &dst_te.path.m_data.as_Generic().m_params, nullptr); auto monomorph_cb_r = monomorphise_type_get_cb(sp, nullptr, &te.path.m_data.as_Generic().m_params, nullptr); - + TU_MATCHA( (str->m_data), (se), (Unit, ), diff --git a/src/hir_conv/resolve_ufcs.cpp b/src/hir_conv/resolve_ufcs.cpp index 671c5be8..03cbd168 100644 --- a/src/hir_conv/resolve_ufcs.cpp +++ b/src/hir_conv/resolve_ufcs.cpp @@ -17,27 +17,27 @@ namespace { public ::HIR::Visitor { const ::HIR::Crate& m_crate; - + typedef ::std::vector< ::std::pair< const ::HIR::SimplePath*, const ::HIR::Trait* > > t_trait_imports; t_trait_imports m_traits; - + StaticTraitResolve m_resolve; const ::HIR::TypeRef* m_current_type = nullptr; const ::HIR::Trait* m_current_trait; const ::HIR::ItemPath* m_current_trait_path; bool m_in_expr = false; - + public: Visitor(const ::HIR::Crate& crate): m_crate(crate), m_resolve(crate), m_current_trait(nullptr) {} - + struct ModTraitsGuard { Visitor* v; t_trait_imports old_imports; - + ~ModTraitsGuard() { this->v->m_traits = mv$(this->old_imports); } @@ -89,17 +89,17 @@ 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: 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_trait_impl(trait_path, impl); m_traits.pop_back( ); - + m_current_trait = nullptr; m_current_type = nullptr; } @@ -110,11 +110,11 @@ namespace { public ::HIR::ExprVisitorDef { Visitor& upper_visitor; - + ExprVisitor(Visitor& uv): upper_visitor(uv) {} - + void visit(::HIR::ExprNode_Let& node) override { upper_visitor.visit_pattern(node.m_pattern); @@ -126,7 +126,7 @@ namespace { upper_visitor.visit_type(node.m_res_type); ::HIR::ExprVisitorDef::visit(node); } - + void visit(::HIR::ExprNode_CallPath& node) override { upper_visitor.visit_path(node.m_path, ::HIR::Visitor::PathContext::VALUE); @@ -137,13 +137,13 @@ namespace { upper_visitor.visit_path_params(node.m_params); ::HIR::ExprVisitorDef::visit(node); } - + void visit(::HIR::ExprNode_PathValue& node) override { upper_visitor.visit_path(node.m_path, ::HIR::Visitor::PathContext::VALUE); ::HIR::ExprVisitorDef::visit(node); } - + void visit(::HIR::ExprNode_Match& node) override { for(auto& arm : node.m_arms) @@ -153,7 +153,7 @@ namespace { } ::HIR::ExprVisitorDef::visit(node); } - + void visit(::HIR::ExprNode_Closure& node) override { upper_visitor.visit_type(node.m_return); @@ -163,7 +163,7 @@ namespace { } ::HIR::ExprVisitorDef::visit(node); } - + void visit(::HIR::ExprNode_Block& node) override { if( node.m_traits.size() == 0 && node.m_local_mod.m_components.size() > 0 ) { @@ -179,7 +179,7 @@ namespace { upper_visitor.m_traits.pop_back(); } }; - + if( expr.get() != nullptr ) { m_in_expr = true; @@ -203,7 +203,7 @@ namespace { } } ); - // - + // - } return false; } @@ -214,7 +214,7 @@ namespace { 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: @@ -305,13 +305,13 @@ namespace { } return false; } - + bool locate_in_trait_impl_and_set(const Span& sp, ::HIR::Visitor::PathContext pc, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait, ::HIR::Path::Data& pd) { auto& e = pd.as_UfcsUnknown(); if( this->locate_item_in_trait(pc, trait, pd) ) { const auto& type = *e.type; - + // TODO: This is VERY arbitary and possibly nowhere near what rustc does. this->m_resolve.find_impl(sp, trait_path.m_path, nullptr, type, [&](const auto& impl, bool fuzzy){ auto pp = impl.get_trait_params(); @@ -356,8 +356,8 @@ namespace { else { DEBUG("- Item " << e.item << " not in trait " << trait_path.m_path); } - - + + // Search supertraits (recursively) for( unsigned int i = 0; i < trait.m_parent_traits.size(); i ++ ) { @@ -371,7 +371,7 @@ namespace { } return false; } - + bool resolve_UfcsUnknown_inherent(const ::HIR::Path& p, ::HIR::Visitor::PathContext pc, ::HIR::Path::Data& pd) { auto& e = pd.as_UfcsUnknown(); @@ -394,14 +394,14 @@ namespace { 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; }); } - + bool resolve_UfcsUnknown_trait(const ::HIR::Path& p, ::HIR::Visitor::PathContext pc, ::HIR::Path::Data& pd) { static Span sp; @@ -409,7 +409,7 @@ namespace { for( const auto& trait_info : m_traits ) { const auto& trait = *trait_info.second; - + DEBUG( e.item << " in? " << *trait_info.first ); switch(pc) { @@ -424,14 +424,14 @@ namespace { break; } DEBUG("- Trying trait " << *trait_info.first); - + auto trait_path = ::HIR::GenericPath( *trait_info.first ); for(unsigned int i = 0; i < trait.m_params.m_types.size(); i ++ ) { trait_path.m_params.m_types.push_back( ::HIR::TypeRef() ); } - + // TODO: If there's only one trait with this name, assume it's the correct one. - + // TODO: Search supertraits // TODO: Should impls be searched first, or item names? // - Item names add complexity, but impls are slower @@ -441,17 +441,17 @@ namespace { } return false; } - + void visit_path(::HIR::Path& p, ::HIR::Visitor::PathContext pc) override { static Span sp; - + TU_IFLET(::HIR::Path::Data, p.m_data, UfcsUnknown, e, 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_resolve.m_item_generics != nullptr && locate_trait_item_in_bounds(pc, *e.type, *m_resolve.m_item_generics, p.m_data) ) { DEBUG("Found in item params, p = " << p); @@ -468,7 +468,7 @@ namespace { return ; } assert(p.m_data.is_UfcsUnknown()); - + // 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( *e.type == ::HIR::TypeRef("Self", 0xFFFF) || (m_current_type && *e.type == *m_current_type) ) @@ -497,13 +497,13 @@ namespace { } DEBUG("- Item " << e.item << " not found in Self - ty=" << *e.type); } - + // 2. Search all impls of in-scope traits for this method on this type if( this->resolve_UfcsUnknown_trait(p, pc, p.m_data) ) { return ; } assert(p.m_data.is_UfcsUnknown()); - + // Couldn't find it ERROR(sp, E0000, "Failed to find impl with '" << e.item << "' for " << *e.type << " (in " << p << ")"); ) @@ -511,14 +511,14 @@ namespace { ::HIR::Visitor::visit_path(p, pc); } } - + void visit_pattern(::HIR::Pattern& pat) override { static Span _sp = Span(); const Span& sp = _sp; ::HIR::Visitor::visit_pattern(pat); - + TU_MATCH_DEF(::HIR::Pattern::Data, (pat.m_data), (e), ( ), diff --git a/src/hir_expand/annotate_value_usage.cpp b/src/hir_expand/annotate_value_usage.cpp index 4aaf1f84..8141f1a6 100644 --- a/src/hir_expand/annotate_value_usage.cpp +++ b/src/hir_expand/annotate_value_usage.cpp @@ -12,13 +12,13 @@ #include "main_bindings.hpp" namespace { - + class ExprVisitor_Mark: public ::HIR::ExprVisitor//Def { const StaticTraitResolve& m_resolve; ::std::vector< ::HIR::ValueUsage> m_usage; - + struct UsageGuard { ExprVisitor_Mark& m_parent; @@ -35,7 +35,7 @@ namespace { } } }; - + ::HIR::ValueUsage get_usage() const { return (m_usage.empty() ? ::HIR::ValueUsage::Move : m_usage.back()); } @@ -48,12 +48,12 @@ namespace { return UsageGuard(*this, true); } } - + public: ExprVisitor_Mark(const StaticTraitResolve& resolve): m_resolve(resolve) {} - + void visit_root(::HIR::ExprPtr& root_ptr) { assert(root_ptr); @@ -65,27 +65,27 @@ namespace { void visit_node_ptr(::HIR::ExprNodeP& node_ptr) override { assert(node_ptr); - + const auto& node_ref = *node_ptr; const char* node_tyname = typeid(node_ref).name(); TRACE_FUNCTION_FR(&*node_ptr << " " << node_tyname, node_ptr->m_usage); - + node_ptr->m_usage = this->get_usage(); - + auto expected_size = m_usage.size(); node_ptr->visit( *this ); assert( m_usage.size() == expected_size ); } - + void visit(::HIR::ExprNode_Block& node) override { auto _ = this->push_usage( ::HIR::ValueUsage::Move ); - + for( auto& subnode : node.m_nodes ) { this->visit_node_ptr(subnode); } } - + void visit(::HIR::ExprNode_Return& node) override { auto _ = this->push_usage( ::HIR::ValueUsage::Move ); @@ -115,13 +115,13 @@ namespace { ::HIR::ValueUsage vu = ::HIR::ValueUsage::Unknown; for( const auto& arm : node.m_arms ) { - for( const auto& pat : arm.m_patterns ) + for( const auto& pat : arm.m_patterns ) vu = ::std::max( vu, this->get_usage_for_pattern(node.span(), pat, val_ty) ); } auto _ = this->push_usage( vu ); this->visit_node_ptr( node.m_value ); } - + auto _ = this->push_usage( ::HIR::ValueUsage::Move ); for(auto& arm : node.m_arms) { @@ -140,7 +140,7 @@ namespace { this->visit_node_ptr( node.m_false ); } } - + void visit(::HIR::ExprNode_Assign& node) override { { @@ -155,9 +155,9 @@ namespace { void visit(::HIR::ExprNode_UniOp& node) override { m_usage.push_back( ::HIR::ValueUsage::Move ); - + this->visit_node_ptr(node.m_value); - + m_usage.pop_back(); } void visit(::HIR::ExprNode_Borrow& node) override @@ -174,12 +174,12 @@ namespace { m_usage.push_back( ::HIR::ValueUsage::Move ); break; } - + this->visit_node_ptr(node.m_value); - + m_usage.pop_back(); } - + void visit(::HIR::ExprNode_BinOp& node) override { switch(node.m_op) @@ -196,10 +196,10 @@ namespace { m_usage.push_back( ::HIR::ValueUsage::Move ); break; } - + this->visit_node_ptr(node.m_left); this->visit_node_ptr(node.m_right); - + m_usage.pop_back(); } void visit(::HIR::ExprNode_Cast& node) override @@ -222,7 +222,7 @@ namespace { else { this->visit_node_ptr(node.m_value); } - + auto _ = push_usage( ::HIR::ValueUsage::Move ); this->visit_node_ptr(node.m_index); } @@ -241,7 +241,7 @@ namespace { this->visit_node_ptr(node.m_value); } } - + void visit(::HIR::ExprNode_Emplace& node) override { if( node.m_type == ::HIR::ExprNode_Emplace::Type::Noop ) { @@ -256,7 +256,7 @@ namespace { this->visit_node_ptr(node.m_value); } } - + void visit(::HIR::ExprNode_Field& node) override { bool is_copy = m_resolve.type_is_copy(node.span(), node.m_res_type); @@ -270,18 +270,18 @@ namespace { this->visit_node_ptr(node.m_value); } } - + void visit(::HIR::ExprNode_TupleVariant& node) override { auto _ = push_usage( ::HIR::ValueUsage::Move ); - + for( auto& val : node.m_args ) this->visit_node_ptr(val); } void visit(::HIR::ExprNode_CallPath& node) override { auto _ = push_usage( ::HIR::ValueUsage::Move ); - + for( auto& val : node.m_args ) this->visit_node_ptr(val); } @@ -311,7 +311,7 @@ namespace { auto _ = push_usage( vu ); this->visit_node_ptr(node.m_value); } - + auto _ = push_usage( ::HIR::ValueUsage::Move ); for( auto& val : node.m_args ) this->visit_node_ptr(val); @@ -319,12 +319,12 @@ namespace { void visit(::HIR::ExprNode_CallMethod& node) override { auto _ = push_usage( ::HIR::ValueUsage::Move ); - + this->visit_node_ptr(node.m_value); for( auto& val : node.m_args ) this->visit_node_ptr(val); } - + void visit(::HIR::ExprNode_Literal& node) override { } @@ -358,7 +358,7 @@ namespace { unsigned idx = ::std::find_if( fields.begin(), fields.end(), [&](const auto& x){ return x.first == fld.first; }) - fields.begin(); provided_mask[idx] = true; } - + const auto monomorph_cb = monomorphise_type_get_cb(node.span(), nullptr, &node.m_path.m_params, nullptr); for( unsigned int i = 0; i < fields.size(); i ++ ) { if( ! provided_mask[i] ) { @@ -372,12 +372,12 @@ namespace { } } } - + // If only Copy fields will be used, set usage to Borrow auto _ = push_usage( is_moved ? ::HIR::ValueUsage::Move : ::HIR::ValueUsage::Borrow ); this->visit_node_ptr(node.m_base_value); } - + auto _ = push_usage( ::HIR::ValueUsage::Move ); for( auto& fld_val : node.m_values ) { this->visit_node_ptr(fld_val.second); @@ -407,13 +407,13 @@ namespace { auto _ = push_usage( ::HIR::ValueUsage::Move ); this->visit_node_ptr(node.m_val); } - + void visit(::HIR::ExprNode_Closure& node) override { auto _ = push_usage( ::HIR::ValueUsage::Move ); this->visit_node_ptr(node.m_code); } - + private: ::HIR::ValueUsage get_usage_for_pattern_binding(const Span& sp, const ::HIR::PatternBinding& pb, const ::HIR::TypeRef& ty) const { @@ -431,13 +431,13 @@ namespace { } throw ""; } - + ::HIR::ValueUsage get_usage_for_pattern(const Span& sp, const ::HIR::Pattern& pat, const ::HIR::TypeRef& ty) const { if( pat.m_binding.is_valid() ) { return get_usage_for_pattern_binding(sp, pat.m_binding, ty); } - + TU_MATCHA( (pat.m_data), (pe), (Any, return ::HIR::ValueUsage::Borrow; @@ -477,7 +477,7 @@ namespace { const auto& flds = str.m_data.as_Tuple(); assert(pe.sub_patterns.size() == flds.size()); auto monomorph_cb = monomorphise_type_get_cb(sp, nullptr, &pe.path.m_params, nullptr); - + auto rv = ::HIR::ValueUsage::Borrow; for(unsigned int i = 0; i < flds.size(); i ++) { auto sty = monomorphise_type_with(sp, flds[i].ent, monomorph_cb); @@ -489,13 +489,13 @@ namespace { const auto& str = *pe.binding; const auto& flds = str.m_data.as_Named(); auto monomorph_cb = monomorphise_type_get_cb(sp, nullptr, &pe.path.m_params, nullptr); - + auto rv = ::HIR::ValueUsage::Borrow; for(const auto& fld_pat : pe.sub_patterns) { auto fld_it = ::std::find_if(flds.begin(), flds.end(), [&](const auto& x){return x.first == fld_pat.first;}); ASSERT_BUG(sp, fld_it != flds.end(), ""); - + auto sty = monomorphise_type_with(sp, fld_it->second.ent, monomorph_cb); rv = ::std::max(rv, get_usage_for_pattern(sp, fld_pat.second, sty)); } @@ -516,7 +516,7 @@ namespace { const auto& flds = var.second.as_Tuple(); assert(pe.sub_patterns.size() == flds.size()); auto monomorph_cb = monomorphise_type_get_cb(sp, nullptr, &pe.path.m_params, nullptr); - + auto rv = ::HIR::ValueUsage::Borrow; for(unsigned int i = 0; i < flds.size(); i ++) { auto sty = monomorphise_type_with(sp, flds[i].ent, monomorph_cb); @@ -529,13 +529,13 @@ namespace { const auto& var = enm.m_variants.at(pe.binding_idx); const auto& flds = var.second.as_Struct(); auto monomorph_cb = monomorphise_type_get_cb(sp, nullptr, &pe.path.m_params, nullptr); - + auto rv = ::HIR::ValueUsage::Borrow; for(const auto& fld_pat : pe.sub_patterns) { auto fld_it = ::std::find_if(flds.begin(), flds.end(), [&](const auto& x){return x.first == fld_pat.first;}); ASSERT_BUG(sp, fld_it != flds.end(), ""); - + auto sty = monomorphise_type_with(sp, fld_it->second.ent, monomorph_cb); rv = ::std::max(rv, get_usage_for_pattern(sp, fld_pat.second, sty)); } @@ -564,7 +564,7 @@ namespace { } }; - + class OuterVisitor: public ::HIR::Visitor { @@ -573,7 +573,7 @@ namespace { OuterVisitor(const ::HIR::Crate& crate): m_resolve(crate) {} - + void visit_expr(::HIR::ExprPtr& exp) override { if( exp ) { @@ -581,7 +581,7 @@ namespace { ev.visit_root( exp ); } } - + // ------ // Code-containing items // ------ @@ -602,25 +602,25 @@ namespace { auto _ = this->m_resolve.set_item_generics(item.m_params); ::HIR::Visitor::visit_enum(p, item); } - - + + void visit_trait(::HIR::ItemPath p, ::HIR::Trait& item) override { auto _ = this->m_resolve.set_impl_generics(item.m_params); ::HIR::Visitor::visit_trait(p, item); } - + void visit_type_impl(::HIR::TypeImpl& impl) override { TRACE_FUNCTION_F("impl " << impl.m_type); auto _ = this->m_resolve.set_impl_generics(impl.m_params); - + ::HIR::Visitor::visit_type_impl(impl); } void visit_trait_impl(const ::HIR::SimplePath& trait_path, ::HIR::TraitImpl& impl) override { TRACE_FUNCTION_F("impl " << trait_path << " for " << impl.m_type); auto _ = this->m_resolve.set_impl_generics(impl.m_params); - + ::HIR::Visitor::visit_trait_impl(trait_path, impl); } }; diff --git a/src/hir_expand/closures.cpp b/src/hir_expand/closures.cpp index 71e6a8c2..51b99d5a 100644 --- a/src/hir_expand/closures.cpp +++ b/src/hir_expand/closures.cpp @@ -17,10 +17,10 @@ namespace { #define NEWNODE(TY, CLASS, ...) mk_exprnodep(new HIR::ExprNode_##CLASS(__VA_ARGS__), TY) namespace { - + typedef ::std::function< ::HIR::SimplePath(::HIR::Struct )> new_type_cb_t; typedef ::std::vector< ::std::pair< ::HIR::ExprNode_Closure::Class, ::HIR::TraitImpl> > out_impls_t; - + template<typename K, typename V> ::std::map<K,V> make_map1(K k1, V v1) { ::std::map<K,V> rv; @@ -44,7 +44,7 @@ namespace { rv.push_back( mv$(v3) ); return rv; } - + /// Mutate the contents of a closure to update captures, variables, and types class ExprVisitor_Mutate: public ::HIR::ExprVisitorDef @@ -52,10 +52,10 @@ namespace { const ::HIR::TypeRef& m_closure_type; const ::std::vector<unsigned int>& m_local_vars; const ::std::vector< ::std::pair<unsigned int, ::HIR::ValueUsage> >& m_captures; - + typedef ::std::function< const ::HIR::TypeRef&(const ::HIR::TypeRef&)> t_monomorph_cb; t_monomorph_cb m_monomorph_cb; - + ::HIR::ExprNodeP m_replacement; public: ExprVisitor_Mutate( @@ -71,7 +71,7 @@ namespace { m_monomorph_cb(mcb) { } - + void visit_pattern(const Span& sp, ::HIR::Pattern& pat) override { if( pat.m_binding.is_valid() ) { auto binding_it = ::std::find(m_local_vars.begin(), m_local_vars.end(), pat.m_binding.m_slot); @@ -83,14 +83,14 @@ namespace { BUG(sp, "Pattern binds to non-local"); } } - + TU_IFLET(::HIR::Pattern::Data, (pat.m_data), SplitSlice, e, TODO(sp, "Fixup binding in split slice"); ) - + ::HIR::ExprVisitorDef::visit_pattern(sp, pat); } - + void visit_type(::HIR::TypeRef& ty) override { TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Generic, e, auto n = m_monomorph_cb(ty).clone(); @@ -101,24 +101,24 @@ namespace { ::HIR::ExprVisitorDef::visit_type(ty); } } - + void visit_node_ptr(::HIR::ExprNodeP& node_ptr) override { assert( node_ptr ); auto& node = *node_ptr; const char* node_ty = typeid(node).name(); TRACE_FUNCTION_FR(&node << " " << node_ty << " : " << node.m_res_type, node_ty); node.visit(*this); - + if( m_replacement ) { node_ptr = mv$(m_replacement); } - + visit_type( node_ptr->m_res_type ); } void visit(::HIR::ExprNode_Closure& node) override { assert( ! node.m_code ); - + // Fix params in path visit_generic_path( ::HIR::Visitor::PathContext::VALUE, node.m_obj_path ); // Visit captures @@ -138,7 +138,7 @@ namespace { return ; } } - + // 2. Is it a capture? { auto binding_it = ::std::find_if(m_captures.begin(), m_captures.end(), [&](const auto& x){return x.first == node.m_slot;}); @@ -150,7 +150,7 @@ namespace { ); if( binding_it->second != ::HIR::ValueUsage::Move ) { auto bt = (binding_it->second == ::HIR::ValueUsage::Mutate ? ::HIR::BorrowType::Unique : ::HIR::BorrowType::Shared); - + m_replacement->m_res_type = ::HIR::TypeRef::new_borrow( bt, mv$(m_replacement->m_res_type) ); m_replacement = NEWNODE(node.m_res_type.clone(), Deref, node.span(), mv$(m_replacement)); } @@ -158,10 +158,10 @@ namespace { return ; } } - + BUG(node.span(), "Encountered non-captured and unknown-origin variable - " << node.m_name << " #" << node.m_slot); } - + ::HIR::ExprNodeP get_self(const Span& sp) const { ::HIR::ExprNodeP self; @@ -187,7 +187,7 @@ namespace { return self; } }; - + /// Visitor to replace closure types with actual type class ExprVisitor_Fixup: public ::HIR::ExprVisitorDef @@ -200,7 +200,7 @@ namespace { m_monomorph_cb( mv$(monomorph_cb) ) { } - + static void fix_type(const ::HIR::Crate& crate, 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); @@ -210,28 +210,28 @@ namespace { ty = ::HIR::TypeRef::new_path( mv$(path), ::HIR::TypeRef::TypePathBinding::make_Struct(&str) ); ) } - + void visit_root(::HIR::ExprPtr& root) { TRACE_FUNCTION; - + root->visit(*this); visit_type(root->m_res_type); - + DEBUG("Locals"); for(auto& ty : root.m_bindings) visit_type(ty); - + for(auto& ty : root.m_erased_types) visit_type(ty); } - + void visit_node_ptr(::HIR::ExprNodeP& node) override { node->visit(*this); visit_type(node->m_res_type); } - + void visit(::HIR::ExprNode_CallValue& node) override { TU_IFLET( ::HIR::TypeRef::Data, node.m_value->m_res_type.m_data, Closure, e, @@ -251,17 +251,17 @@ namespace { break; } ) - + ::HIR::ExprVisitorDef::visit(node); } - + void visit_type(::HIR::TypeRef& ty) override { fix_type(m_crate, m_monomorph_cb, ty); ::HIR::ExprVisitorDef::visit_type(ty); } }; - + struct H { static void fix_fn_params(::HIR::ExprPtr& code, const ::HIR::TypeRef& self_ty, const ::HIR::TypeRef& args_ty) { @@ -390,7 +390,7 @@ namespace { }; } }; - + class ExprVisitor_Extract: public ::HIR::ExprVisitorDef { @@ -399,13 +399,13 @@ namespace { Mutate, Move, }; - + struct ClosureScope { ::HIR::ExprNode_Closure& node; ::std::vector<unsigned int> local_vars; // - Lists captured variables to be stored in autogenerated struct (and how they're used, influencing the borrow type) ::std::vector< ::std::pair<unsigned int, ::HIR::ValueUsage> > captured_vars; - + ClosureScope(::HIR::ExprNode_Closure& node): node(node) { @@ -415,14 +415,14 @@ namespace { const StaticTraitResolve& m_resolve; const ::HIR::TypeRef* m_self_type; ::std::vector< ::HIR::TypeRef>& m_variable_types; - + // Outputs out_impls_t& m_out_impls; const new_type_cb_t& m_new_type; - + /// Stack of active closures ::std::vector<ClosureScope> m_closure_stack; - + public: ExprVisitor_Extract(const StaticTraitResolve& resolve, const ::HIR::TypeRef* self_type, ::std::vector< ::HIR::TypeRef>& var_types, out_impls_t& out_impls, const new_type_cb_t& new_type): m_resolve(resolve), @@ -432,30 +432,30 @@ namespace { m_new_type( new_type ) { } - + void visit_root(::HIR::ExprNode& root) { root.visit(*this); } - + void visit(::HIR::ExprNode_Closure& node) override { const auto& sp = node.span(); - + TRACE_FUNCTION_F("Extract closure - " << node.m_res_type); - + // --- Determine borrow set --- m_closure_stack.push_back( ClosureScope(node) ); - + for(const auto& arg : node.m_args) { add_closure_def_from_pattern(node.span(), arg.first); } - + ::HIR::ExprVisitorDef::visit(node); - + auto ent = mv$( m_closure_stack.back() ); m_closure_stack.pop_back(); - + // - If this closure is a move closure, mutate `captured_vars` such that all captures are tagged with ValueUsage::Move if( node.m_is_move ) { @@ -474,9 +474,9 @@ namespace { } } - + // --- Extract and mutate code into a trait impl on the closure type --- - + // 1. Construct closure type (saving path/index in the node) ::HIR::GenericParams params; ::HIR::PathParams constructor_path_params; @@ -506,7 +506,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) ); } - + auto monomorph_cb = [&](const auto& ty)->const auto& { const auto& ge = ty.m_data.as_Generic(); if( ge.binding == 0xFFFF ) { @@ -537,8 +537,8 @@ namespace { } //else if( tpl.m_data.is_ErasedType() ) { // const auto& e = tpl.m_data.as_ErasedType(); - // - // // TODO: Share code with + // + // // TODO: Share code with // TODO(sp, "Repalce ErasedType with origin " << e.m_origin << " #" << e.m_index); // //ASSERT_BUG(sp, e.m_index < fcn_ptr->m_code.m_erased_types.size(), ""); // //const auto& erased_type_replacement = fcn_ptr->m_code.m_erased_types.at(e.m_index); @@ -549,7 +549,7 @@ namespace { return false; } }; - + // - Clone the bounds (from both levels) auto monomorph_bound = [&](const ::HIR::GenericBound& b)->auto { TU_MATCHA( (b), (e), @@ -570,13 +570,13 @@ namespace { for(const auto& bound : m_resolve.item_generics().m_bounds ) { params.m_bounds.push_back( monomorph_bound(bound) ); } - + DEBUG("--- Mutate inner code"); // 2. Iterate over the nodes and rewrite variable accesses to either renumbered locals, or field accesses ExprVisitor_Mutate ev { node.m_res_type, ent.local_vars, ent.captured_vars, monomorph_cb }; ev.visit_node_ptr( node.m_code ); // NOTE: `ev` is used down in `Args` to convert the argument destructuring pattern - + // - Types of local variables DEBUG("--- Build locals and captures"); ::std::vector< ::HIR::TypeRef> local_types; @@ -599,10 +599,10 @@ namespace { const auto& cap_ty = m_variable_types.at(binding_idx); auto ty_mono = monomorphise_type_with(sp, cap_ty, monomorph_cb); - + auto val_node = NEWNODE(cap_ty.clone(), Variable, sp, "", binding_idx); ::HIR::BorrowType bt; - + switch(binding_type) { case ::HIR::ValueUsage::Unknown: @@ -624,7 +624,7 @@ namespace { capture_nodes.push_back( mv$(val_node) ); break; } - + // - Fix type to replace closure types with known paths ExprVisitor_Fixup fixup { m_resolve.m_crate, monomorph_cb }; fixup.visit_type(ty_mono); @@ -638,7 +638,7 @@ namespace { } ); const auto& closure_struct_ref = m_resolve.m_crate.get_struct_by_path(sp, closure_struct_path); - + // Mark the object pathname in the closure. node.m_obj_path = ::HIR::GenericPath( closure_struct_path, mv$(constructor_path_params) ); node.m_obj_path_base = node.m_obj_path.clone(); @@ -647,11 +647,11 @@ namespace { DEBUG("-- Object name: " << node.m_obj_path); ::HIR::TypeRef closure_type = ::HIR::TypeRef( ::HIR::GenericPath(node.m_obj_path.m_path.clone(), mv$(impl_path_params)) ); closure_type.m_data.as_Path().binding = ::HIR::TypeRef::TypePathBinding::make_Struct({ &closure_struct_ref }); - + // - Args ::std::vector< ::HIR::Pattern> args_pat_inner; ::std::vector< ::HIR::TypeRef> args_ty_inner; - + for(const auto& arg : node.m_args) { args_pat_inner.push_back( arg.first.clone() ); ev.visit_pattern(sp, args_pat_inner.back() ); @@ -660,23 +660,23 @@ namespace { ::HIR::TypeRef args_ty { mv$(args_ty_inner) }; ::HIR::Pattern args_pat { {}, ::HIR::Pattern::Data::make_Tuple({ mv$(args_pat_inner) }) }; ::HIR::TypeRef ret_type = clone_ty_with(sp, node.m_return, cb_replace); - + DEBUG("args_ty = " << args_ty << ", ret_type = " << ret_type); - + ::HIR::ExprPtr body_code { mv$(node.m_code) }; body_code.m_bindings = mv$(local_types); - + { DEBUG("-- Fixing types in body code"); ExprVisitor_Fixup fixup { m_resolve.m_crate, monomorph_cb }; fixup.visit_root( body_code ); - + DEBUG("-- Fixing types in signature"); fixup.visit_type( args_ty ); fixup.visit_type( ret_type ); // TODO: Replace erased types too } - + // --- // 3. Create trait impls // --- @@ -690,7 +690,7 @@ namespace { 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() ); - + // - FnOnce { auto dispatch_node = NEWNODE(ret_type.clone(), CallPath, sp, @@ -730,7 +730,7 @@ namespace { H::make_fnmut( params.clone(), trait_params.clone(), closure_type.clone(), mv$(args_arg), ret_type.clone(), mv$(dispatch_node) ) )); } - + // - Fn m_out_impls.push_back(::std::make_pair( ::HIR::ExprNode_Closure::Class::Shared, @@ -740,7 +740,7 @@ namespace { case ::HIR::ExprNode_Closure::Class::Mut: { const auto& lang_FnMut = m_resolve.m_crate.get_lang_item_path(node.span(), "fn_mut"); const auto method_self_ty = ::HIR::TypeRef::new_borrow( ::HIR::BorrowType::Unique, closure_type.clone() ); - + // - FnOnce { auto dispatch_node = NEWNODE(ret_type.clone(), CallPath, sp, @@ -760,7 +760,7 @@ namespace { H::make_fnonce( params.clone(), trait_params.clone(), closure_type.clone(), mv$(args_arg), ret_type.clone(), mv$(dispatch_node) ) )); } - + // - FnMut (code) m_out_impls.push_back(::std::make_pair( ::HIR::ExprNode_Closure::Class::Mut, @@ -776,7 +776,7 @@ namespace { break; } } - + void visit_pattern(const Span& sp, ::HIR::Pattern& pat) override { if( !m_closure_stack.empty() ) @@ -792,7 +792,7 @@ namespace { } ::HIR::ExprVisitorDef::visit(node); } - + void visit(::HIR::ExprNode_CallValue& node) override { const auto& fcn_ty = node.m_value->m_res_type; @@ -844,13 +844,13 @@ namespace { ::HIR::ExprVisitorDef::visit(node); } } - + private: void add_closure_def(unsigned int slot) { assert(m_closure_stack.size() > 0); auto& closure_defs = m_closure_stack.back().local_vars; - + auto it = ::std::lower_bound(closure_defs.begin(), closure_defs.end(), slot); if( it == closure_defs.end() || *it != slot ) { closure_defs.insert(it, slot); @@ -863,7 +863,7 @@ namespace { const auto& pb = pat.m_binding; add_closure_def(pb.m_slot); } - + // Recurse TU_MATCH(::HIR::Pattern::Data, (pat.m_data), (e), (Any, @@ -901,7 +901,7 @@ namespace { add_closure_def(e.extra_bind.m_slot); } ), - + // - Enums/Structs (StructValue, ), @@ -937,7 +937,7 @@ namespace { return ; } - + if( usage == ::HIR::ValueUsage::Move ) { if( m_resolve.type_is_copy(sp, m_variable_types.at(slot)) ) { usage = ::HIR::ValueUsage::Borrow; @@ -948,11 +948,11 @@ namespace { else { } } - + assert(m_closure_stack.size() > 0 ); auto& closure_rec = m_closure_stack.back(); auto& closure = closure_rec.node; - + auto it = ::std::lower_bound(closure_rec.captured_vars.begin(), closure_rec.captured_vars.end(), slot, [](const auto& a, const auto& b){ return a.first < b; }); if( it == closure_rec.captured_vars.end() || it->first != slot ) { closure_rec.captured_vars.insert( it, ::std::make_pair(slot, usage) ); @@ -960,7 +960,7 @@ namespace { else { it->second = ::std::max(it->second, usage); } - + const char* cap_type_name = "?"; switch( usage ) { @@ -987,7 +987,7 @@ namespace { DEBUG("Captured " << slot << " - " << m_variable_types.at(slot) << " :: " << cap_type_name); } }; - + class OuterVisitor: public ::HIR::Visitor { @@ -1001,11 +1001,11 @@ namespace { m_resolve(crate), m_cur_mod_path( nullptr ) {} - + void visit_crate(::HIR::Crate& crate) override { Span sp; - + unsigned int closure_count = 0; ::HIR::SimplePath root_mod_path("",{}); m_cur_mod_path = &root_mod_path; @@ -1016,9 +1016,9 @@ namespace { crate.m_root_module.m_mod_items.insert( ::std::make_pair(name, mv$(boxed)) ); return ::HIR::SimplePath() + name; }; - + ::HIR::Visitor::visit_crate(crate); - + for(auto& impl : m_new_trait_impls) { const auto& trait = @@ -1030,13 +1030,13 @@ namespace { } m_new_trait_impls.resize(0); } - + void visit_module(::HIR::ItemPath p, ::HIR::Module& mod) override { auto saved = m_cur_mod_path; auto path = p.get_simple_path(); m_cur_mod_path = &path; - + unsigned int closure_count = 0; auto saved_nt = mv$(m_new_type); m_new_type = [&](auto s)->auto { @@ -1046,18 +1046,18 @@ namespace { mod.m_mod_items.insert( ::std::make_pair(name, mv$(boxed)) ); return (p + name).get_simple_path(); }; - + ::HIR::Visitor::visit_module(p, mod); - + m_cur_mod_path = saved; m_new_type = mv$(saved_nt); } - + // NOTE: This is left here to ensure that any expressions that aren't handled by higher code cause a failure void visit_expr(::HIR::ExprPtr& exp) override { BUG(Span(), "visit_expr hit in OuterVisitor"); } - + void visit_type(::HIR::TypeRef& ty) override { TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Array, e, @@ -1083,12 +1083,12 @@ namespace { { assert( m_cur_mod_path ); DEBUG("Function code " << p); - + { ExprVisitor_Extract ev(m_resolve, m_self_type, item.m_code.m_bindings, m_new_trait_impls, m_new_type); ev.visit_root( *item.m_code ); } - + { ExprVisitor_Fixup fixup(m_resolve.m_crate, [](const auto& x)->const auto&{ return x; }); fixup.visit_root( item.m_code ); @@ -1129,7 +1129,7 @@ namespace { ) } } - + void visit_trait(::HIR::ItemPath p, ::HIR::Trait& item) override { auto _ = this->m_resolve.set_impl_generics(item.m_params); @@ -1138,16 +1138,16 @@ namespace { ::HIR::Visitor::visit_trait(p, item); m_self_type = nullptr; } - - + + void visit_type_impl(::HIR::TypeImpl& impl) override { TRACE_FUNCTION_F("impl " << impl.m_type); m_self_type = &impl.m_type; auto _ = this->m_resolve.set_impl_generics(impl.m_params); - + ::HIR::Visitor::visit_type_impl(impl); - + m_self_type = nullptr; } void visit_trait_impl(const ::HIR::SimplePath& trait_path, ::HIR::TraitImpl& impl) override @@ -1155,9 +1155,9 @@ namespace { TRACE_FUNCTION_F("impl " << trait_path << " for " << impl.m_type); m_self_type = &impl.m_type; auto _ = this->m_resolve.set_impl_generics(impl.m_params); - + ::HIR::Visitor::visit_trait_impl(trait_path, impl); - + m_self_type = nullptr; } }; diff --git a/src/hir_expand/const_eval_full.cpp b/src/hir_expand/const_eval_full.cpp index f385c816..85fdd112 100644 --- a/src/hir_expand/const_eval_full.cpp +++ b/src/hir_expand/const_eval_full.cpp @@ -16,13 +16,13 @@ namespace { typedef ::std::vector< ::std::pair< ::std::string, ::HIR::Static> > t_new_values; - + struct NewvalState { t_new_values& newval_output; const ::HIR::ItemPath& mod_path; ::std::string name_prefix; unsigned int next_item_idx; - + NewvalState(t_new_values& newval_output, const ::HIR::ItemPath& mod_path, ::std::string prefix): newval_output(newval_output), mod_path(mod_path), @@ -30,7 +30,7 @@ namespace { next_item_idx(0) { } - + ::HIR::SimplePath new_static(::HIR::TypeRef type, ::HIR::Literal value) { auto name = FMT(name_prefix << next_item_idx); @@ -46,9 +46,9 @@ namespace { return rv; } }; - + ::HIR::Literal evaluate_constant(const Span& sp, const ::StaticTraitResolve& resolve, NewvalState newval_state, const ::HIR::ExprPtr& expr, MonomorphState ms, ::std::vector< ::HIR::Literal> args); - + ::HIR::Literal clone_literal(const ::HIR::Literal& v) { TU_MATCH(::HIR::Literal, (v), (e), @@ -84,7 +84,7 @@ namespace { ) throw ""; } - + void monomorph_literal_inplace(const Span& sp, ::HIR::Literal& lit, const MonomorphState& ms) { TU_MATCH(::HIR::Literal, (lit), (e), @@ -113,7 +113,7 @@ namespace { ) ) } - + TAGGED_UNION(EntPtr, NotFound, (NotFound, struct{}), (Function, const ::HIR::Function*), @@ -135,7 +135,7 @@ namespace { else { mod = &crate.m_root_module; } - + for( unsigned int i = 0; i < path.m_components.size() - 1; i ++ ) { const auto& pc = path.m_components[i]; @@ -152,7 +152,7 @@ namespace { ) ) } - + switch( ns ) { case EntNS::Value: { @@ -160,7 +160,7 @@ namespace { if( it == mod->m_value_items.end() ) { return EntPtr {}; } - + TU_MATCH( ::HIR::ValueItem, (it->second->ent), (e), (Import, ), @@ -185,7 +185,7 @@ namespace { if( it == mod->m_mod_items.end() ) { return EntPtr {}; } - + TU_MATCH( ::HIR::TypeItem, (it->second->ent), (e), (Import, ), @@ -305,19 +305,19 @@ namespace { TODO(sp, "Could not find function for " << path << " - " << rv.tag_str()); } } - + ::HIR::Literal evaluate_constant_mir(const Span& sp, const StaticTraitResolve& resolve, NewvalState newval_state, const ::MIR::Function& fcn, MonomorphState ms, ::std::vector< ::HIR::Literal> args) { TRACE_FUNCTION; - + ::MIR::TypeResolve state { sp, resolve, FMT_CB(), ::HIR::TypeRef(), {}, fcn }; - + ::HIR::Literal retval; ::std::vector< ::HIR::Literal> locals; ::std::vector< ::HIR::Literal> temps; locals.resize( fcn.named_variables.size() ); temps.resize( fcn.temporaries.size() ); - + struct LocalState { typedef ::std::vector< ::HIR::Literal> t_vec_lit; ::MIR::TypeResolve& state; @@ -325,7 +325,7 @@ namespace { ::std::vector< ::HIR::Literal>& locals; ::std::vector< ::HIR::Literal>& temps; ::std::vector< ::HIR::Literal>& args; - + LocalState(::MIR::TypeResolve& state, ::HIR::Literal& retval, t_vec_lit& locals, t_vec_lit& temps, t_vec_lit& args): state(state), retval(retval), @@ -333,7 +333,7 @@ namespace { temps(temps), args(args) {} - + ::HIR::Literal& get_lval(const ::MIR::LValue& lv) { TU_MATCHA( (lv), (e), @@ -377,7 +377,7 @@ namespace { } }; LocalState local_state( state, retval, locals, temps, args ); - + auto get_lval = [&](const ::MIR::LValue& lv) -> ::HIR::Literal& { return local_state.get_lval(lv); }; auto read_lval = [&](const ::MIR::LValue& lv) -> ::HIR::Literal { auto& v = get_lval(lv); @@ -399,7 +399,7 @@ namespace { ) ) }; - + unsigned int cur_block = 0; for(;;) { @@ -408,13 +408,13 @@ namespace { for(const auto& stmt : block.statements) { state.set_cur_stmt(cur_block, next_stmt_idx++); - + if( ! stmt.is_Assign() ) { //BUG(sp, "Non-assign statement - drop " << stmt.as_Drop().slot); continue ; } const auto& sa = stmt.as_Assign(); - + DEBUG(sa.dst << " = " << sa.src); ::HIR::Literal val; TU_MATCHA( (sa.src), (e), @@ -474,19 +474,19 @@ namespace { if( e.type != ::HIR::BorrowType::Shared ) { MIR_BUG(state, "Only shared borrows are allowed in constants"); } - + if( e.val.is_Static() ) { // Borrow of a static, emit BorrowOf with the same path val = ::HIR::Literal::make_BorrowOf( e.val.as_Static().clone() ); } else { auto inner_val = read_lval(e.val); - + ::HIR::TypeRef inner_ty; const auto& inner_ty_r = state.get_lvalue_type(inner_ty, e.val); if( &inner_ty_r != &inner_ty ) inner_ty = inner_ty_r.clone(); - + // Create new static containing borrowed data auto item_path = newval_state.new_static( mv$(inner_ty), mv$(inner_val) ); val = ::HIR::Literal::make_BorrowOf( mv$(item_path) ); @@ -527,12 +527,12 @@ namespace { case ::HIR::CoreType::U16: val = cast_to_int(false, 16); break; case ::HIR::CoreType::I32: val = cast_to_int(true , 32); break; case ::HIR::CoreType::U32: val = cast_to_int(false, 32); break; - + case ::HIR::CoreType::I64: val = cast_to_int(true , 64); break; case ::HIR::CoreType::U64: val = cast_to_int(false, 64); break; case ::HIR::CoreType::Isize: val = cast_to_int(true , 64); break; case ::HIR::CoreType::Usize: val = cast_to_int(false, 64); break; - + case ::HIR::CoreType::F32: case ::HIR::CoreType::F64: TU_IFLET( ::HIR::Literal, inval, Integer, i, @@ -584,7 +584,7 @@ namespace { case ::MIR::eBinOp::MUL_OV: case ::MIR::eBinOp::DIV_OV: TODO(sp, "RValue::BinOp - " << sa.src << ", val = " << inval_l << " , " << inval_r); - + case ::MIR::eBinOp::BIT_OR : case ::MIR::eBinOp::BIT_AND: case ::MIR::eBinOp::BIT_XOR: @@ -613,7 +613,7 @@ namespace { case ::MIR::eBinOp::MUL_OV: case ::MIR::eBinOp::DIV_OV: TODO(sp, "RValue::BinOp - " << sa.src << ", val = " << inval_l << " , " << inval_r); - + case ::MIR::eBinOp::BIT_OR : val = ::HIR::Literal( l | r ); break; case ::MIR::eBinOp::BIT_AND: val = ::HIR::Literal( l & r ); break; case ::MIR::eBinOp::BIT_XOR: val = ::HIR::Literal( l ^ r ); break; @@ -702,7 +702,7 @@ namespace { val = ::HIR::Literal::make_Variant({ e.variant_idx, mv$(vals) }); ) ) - + auto& dst = get_lval(sa.dst); DEBUG("= " << val); dst = mv$(val); @@ -728,26 +728,26 @@ namespace { auto& dst = get_lval(e.ret_val); MonomorphState fcn_ms; auto& fcn = get_function(sp, 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_lval(a) ); // TODO: Set m_const during parse and check here - + // Call by invoking evaluate_constant on the function { TRACE_FUNCTION_F("Call const fn " << fcnp << " args={ " << call_args << " }"); dst = evaluate_constant(sp, resolve, newval_state, fcn.m_code, fcn_ms, mv$(call_args)); } - + DEBUG("= " << dst); cur_block = e.ret_block; ) ) } } - + ::HIR::Literal evaluate_constant(const Span& sp, const StaticTraitResolve& resolve, NewvalState newval_state, const ::HIR::ExprPtr& expr, MonomorphState ms, ::std::vector< ::HIR::Literal> args) { if( expr.m_mir ) { @@ -757,7 +757,7 @@ namespace { BUG(sp, "Attempting to evaluate constant expression with no associated code"); } } - + void check_lit_type(const Span& sp, const ::HIR::TypeRef& type, ::HIR::Literal& lit) { // TODO: Mask down limited size integers @@ -776,7 +776,7 @@ namespace { ), (Closure, ), - + (Path, // List ), @@ -786,7 +786,7 @@ namespace { (Tuple, // List ), - + (Borrow, // A whole host of things ), @@ -796,7 +796,7 @@ namespace { (Function, // ItemAddr ), - + (Primitive, switch(te) { @@ -813,7 +813,7 @@ namespace { case ::HIR::CoreType::U8: lit.as_Integer() &= (1ull<<8)-1; break; case ::HIR::CoreType::U16: lit.as_Integer() &= (1ull<<16)-1; break; case ::HIR::CoreType::U32: lit.as_Integer() &= (1ull<<32)-1; break; - + //case ::HIR::CoreType::I8: lit.as_Integer() &= (1ull<<8)-1; break; //case ::HIR::CoreType::I16: lit.as_Integer() &= (1ull<<16)-1; break; //case ::HIR::CoreType::I32: lit.as_Integer() &= (1ull<<32)-1; break; @@ -831,7 +831,7 @@ namespace { { const ::HIR::Crate& m_crate; StaticTraitResolve m_resolve; - + const ::HIR::ItemPath* m_mod_path; t_new_values m_new_values; @@ -840,15 +840,15 @@ namespace { m_crate(crate), m_resolve(crate) {} - + void visit_module(::HIR::ItemPath p, ::HIR::Module& mod) override { auto saved_mp = m_mod_path; m_mod_path = &p; auto saved = mv$( m_new_values ); - + ::HIR::Visitor::visit_module(p, mod); - + for( auto& item : m_new_values ) { auto boxed_ent = box$(::HIR::VisEnt<::HIR::ValueItem> { false, ::HIR::ValueItem(mv$(item.second)) }); @@ -865,11 +865,11 @@ namespace { m_new_values = mv$(saved); m_mod_path = saved_mp; } - + void visit_type(::HIR::TypeRef& ty) override { ::HIR::Visitor::visit_type(ty); - + TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Array, e, assert( e.size_val != ~0u ); ) @@ -881,7 +881,7 @@ namespace { { auto nvs = NewvalState { m_new_values, *m_mod_path, FMT(p.get_name() << "$") }; item.m_value_res = evaluate_constant(item.m_value->span(), m_resolve, nvs, item.m_value, {}, {}); - + check_lit_type(item.m_value->span(), item.m_type, item.m_value_res); DEBUG("constant: " << item.m_type << " = " << item.m_value_res); visit_expr(item.m_value); diff --git a/src/hir_expand/erased_types.cpp b/src/hir_expand/erased_types.cpp index 5cbb9726..44bb17de 100644 --- a/src/hir_expand/erased_types.cpp +++ b/src/hir_expand/erased_types.cpp @@ -52,7 +52,7 @@ const ::HIR::Function& HIR_Expand_ErasedType_GetFunction(const Span& sp, const S for(const auto& t : impl_params.m_types) if( t == ::HIR::TypeRef() ) TODO(sp, "Handle ErasedType where an impl parameter comes from a bound - " << origin_path); - + monomorph_cb = monomorphise_type_get_cb(sp, &*pe.type, &impl_params, &pe.params); ) ) @@ -61,19 +61,19 @@ const ::HIR::Function& HIR_Expand_ErasedType_GetFunction(const Span& sp, const S } namespace { - - + + class ExprVisitor_Extract: public ::HIR::ExprVisitorDef { const StaticTraitResolve& m_resolve; - + public: ExprVisitor_Extract(const StaticTraitResolve& resolve): m_resolve(resolve) { } - + void visit_root(::HIR::ExprPtr& root) { root->visit(*this); @@ -83,31 +83,31 @@ namespace { for(auto& ty : root.m_erased_types) visit_type(ty); } - + void visit_node_ptr(::std::unique_ptr< ::HIR::ExprNode>& node_ptr) override { assert(node_ptr); node_ptr->visit(*this); visit_type(node_ptr->m_res_type); } - + void visit_type(::HIR::TypeRef& ty) override { static Span sp; - + if( ty.m_data.is_ErasedType() ) { TRACE_FUNCTION_FR(ty, ty); - + const auto& e = ty.m_data.as_ErasedType(); - + ::HIR::PathParams impl_params; // cache. t_cb_generic monomorph_cb; const auto& fcn = HIR_Expand_ErasedType_GetFunction(sp, m_resolve, e.m_origin, monomorph_cb, impl_params); const auto& erased_types = fcn.m_code.m_erased_types; - + ASSERT_BUG(sp, e.m_index < erased_types.size(), "Erased type index out of range for " << e.m_origin << " - " << e.m_index << " >= " << erased_types.size()); const auto& tpl = erased_types[e.m_index]; - + auto new_ty = monomorphise_type_with(sp, tpl, monomorph_cb); DEBUG("> " << ty << " => " << new_ty); ty = mv$(new_ty); @@ -120,7 +120,7 @@ namespace { } } }; - + class OuterVisitor: public ::HIR::Visitor { @@ -130,7 +130,7 @@ namespace { OuterVisitor(const ::HIR::Crate& crate): m_resolve(crate) {} - + void visit_expr(::HIR::ExprPtr& exp) override { if( exp ) @@ -139,23 +139,23 @@ namespace { ev.visit_root( exp ); } } - + void visit_function(::HIR::ItemPath p, ::HIR::Function& fcn) override { m_fcn_path = p; ::HIR::Visitor::visit_function(p, fcn); m_fcn_path = ::HIR::ItemPath(); } - + void visit_type(::HIR::TypeRef& ty) override { static const Span sp; if( ty.m_data.is_ErasedType() ) { ASSERT_BUG(sp, m_fcn_path.get_name(), ""); - + const auto& e = ty.m_data.as_ErasedType(); - + TU_MATCHA( (e.m_origin.m_data), (pe), (Generic, if( m_fcn_path == pe.m_path ) { @@ -176,17 +176,17 @@ namespace { } ) ) - + TRACE_FUNCTION_FR(ty, ty); - + ::HIR::PathParams impl_params; t_cb_generic monomorph_cb; const auto& fcn = HIR_Expand_ErasedType_GetFunction(sp, m_resolve, e.m_origin, monomorph_cb, impl_params); const auto& erased_types = fcn.m_code.m_erased_types; - + ASSERT_BUG(sp, e.m_index < erased_types.size(), "Erased type index out of range for " << e.m_origin << " - " << e.m_index << " >= " << erased_types.size()); const auto& tpl = erased_types[e.m_index]; - + auto new_ty = monomorphise_type_with(sp, tpl, monomorph_cb); DEBUG("> " << ty << " => " << new_ty); ty = mv$(new_ty); diff --git a/src/hir_expand/reborrow.cpp b/src/hir_expand/reborrow.cpp index 8395f340..688dcf97 100644 --- a/src/hir_expand/reborrow.cpp +++ b/src/hir_expand/reborrow.cpp @@ -17,12 +17,12 @@ namespace { #define NEWNODE(TY, CLASS, ...) mk_exprnodep(new HIR::ExprNode_##CLASS(__VA_ARGS__), TY) namespace { - + class ExprVisitor_Mutate: public ::HIR::ExprVisitorDef { const ::HIR::Crate& m_crate; - + public: ExprVisitor_Mutate(const ::HIR::Crate& crate): m_crate(crate) @@ -32,9 +32,9 @@ namespace { const auto& node_ref = *root; const char* node_ty = typeid(node_ref).name(); TRACE_FUNCTION_FR(&*root << " " << node_ty << " : " << root->m_res_type, node_ty); - + root->visit(*this); - + // 1. Convert into an ExprNodeP auto np = root.into_unique(); // 2. Pass to do_reborrow @@ -42,7 +42,7 @@ namespace { // 3. Convert back root.reset( np.release() ); } - + void visit_node_ptr(::HIR::ExprNodeP& node) override { const auto& node_ref = *node; const char* node_ty = typeid(node_ref).name(); @@ -50,7 +50,7 @@ namespace { assert( node ); node->visit(*this); } - + ::HIR::ExprNodeP do_reborrow(::HIR::ExprNodeP node_ptr) { TU_IFLET( ::HIR::TypeRef::Data, node_ptr->m_res_type.m_data, Borrow, e, @@ -86,7 +86,7 @@ namespace { ) return node_ptr; } - + void visit(::HIR::ExprNode_Assign& node) override { ::HIR::ExprVisitorDef::visit(node); node.m_value = do_reborrow(mv$(node.m_value)); @@ -109,7 +109,7 @@ namespace { arg = do_reborrow(mv$(arg)); } } - + void visit(::HIR::ExprNode_ArrayList& node) override { ::HIR::ExprVisitorDef::visit(node); for(auto& arg : node.m_vals) { @@ -154,12 +154,12 @@ namespace { m_crate(crate) { } - + // NOTE: This is left here to ensure that any expressions that aren't handled by higher code cause a failure void visit_expr(::HIR::ExprPtr& exp) override { BUG(Span(), "visit_expr hit in OuterVisitor"); } - + void visit_type(::HIR::TypeRef& ty) override { TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Array, e, @@ -209,7 +209,7 @@ namespace { { TU_IFLET(::HIR::Enum::Variant, var.second, Value, e, DEBUG("Enum value " << p << " - " << var.first); - + ExprVisitor_Mutate ev(m_crate); ev.visit_node_ptr(e.expr); ) diff --git a/src/hir_expand/ufcs_everything.cpp b/src/hir_expand/ufcs_everything.cpp index daba3e6a..0562c418 100644 --- a/src/hir_expand/ufcs_everything.cpp +++ b/src/hir_expand/ufcs_everything.cpp @@ -18,14 +18,14 @@ namespace { #define NEWNODE(TY, CLASS, ...) mk_exprnodep(new HIR::ExprNode_##CLASS(__VA_ARGS__), TY) namespace { - + class ExprVisitor_Mutate: public ::HIR::ExprVisitorDef { const ::HIR::Crate& m_crate; ::HIR::ExprNodeP m_replacement; ::HIR::SimplePath m_lang_Box; - + public: ExprVisitor_Mutate(const ::HIR::Crate& crate): m_crate(crate) @@ -47,7 +47,7 @@ namespace { root->m_usage = usage; } } - + void visit_node_ptr(::HIR::ExprNodeP& node) override { const auto& node_ref = *node; const char* node_ty = typeid(node_ref).name(); @@ -62,7 +62,7 @@ namespace { node->m_usage = usage; } } - + // ---------- // _CallValue // ---------- @@ -70,15 +70,15 @@ namespace { void visit(::HIR::ExprNode_CallValue& node) override { const auto& sp = node.span(); - + ::HIR::ExprVisitorDef::visit(node); const auto& ty_val = node.m_value->m_res_type; - + // Calling a `fn` type should be kept as a _CallValue if( ty_val.m_data.is_Function() ) { return ; } - + // 1. Construct tuple type containing argument types for `Args` ::HIR::TypeRef arg_tup_type; { @@ -90,7 +90,7 @@ namespace { // - Make the trait arguments. ::HIR::PathParams trait_args; trait_args.m_types.push_back( arg_tup_type.clone() ); - + // - If the called value is a local closure, figure out how it's being used. // TODO: You can call via &-ptrs, but that currently isn't handled in typeck TU_IFLET(::HIR::TypeRef::Data, node.m_value->m_res_type.m_data, Closure, e, @@ -114,7 +114,7 @@ namespace { } } ) - + // Use marking in node to determine trait to use ::HIR::TypeRef self_arg_type; ::HIR::Path method_path(::HIR::SimplePath{}); @@ -147,32 +147,32 @@ namespace { "call_once" ); break; - + //case ::HIR::ExprNode_CallValue::TraitUsed::Unknown: default: BUG(node.span(), "Encountered CallValue with TraitUsed::Unknown, ty=" << node.m_value->m_res_type); } assert(self_arg_type != ::HIR::TypeRef()); - - + + // Construct argument list for the output ::std::vector< ::HIR::ExprNodeP> args; args.reserve( 2 ); args.push_back( mv$(node.m_value) ); args.push_back(NEWNODE( arg_tup_type.clone(), Tuple, sp, mv$(node.m_args) )); - + m_replacement = NEWNODE(mv$(node.m_res_type), CallPath, sp, mv$(method_path), mv$(args) ); - + // Populate the cache for later passes auto& arg_types = dynamic_cast< ::HIR::ExprNode_CallPath&>(*m_replacement).m_cache.m_arg_types; arg_types.push_back( mv$(self_arg_type) ); arg_types.push_back( mv$(arg_tup_type) ); arg_types.push_back( m_replacement->m_res_type.clone() ); } - + // ---------- // _CallMethod // ---------- @@ -180,15 +180,15 @@ namespace { void visit(::HIR::ExprNode_CallMethod& node) override { const auto& sp = node.span(); - + ::HIR::ExprVisitorDef::visit(node); - + ::std::vector< ::HIR::ExprNodeP> args; args.reserve( 1 + node.m_args.size() ); args.push_back( mv$(node.m_value) ); for(auto& arg : node.m_args) args.push_back( mv$(arg) ); - + // Replace using known function path m_replacement = NEWNODE(mv$(node.m_res_type), CallPath, sp, mv$(node.m_method_path), @@ -197,8 +197,8 @@ namespace { // Populate the cache for later passes dynamic_cast< ::HIR::ExprNode_CallPath&>(*m_replacement).m_cache = mv$(node.m_cache); } - - + + static bool is_op_valid_shift(const ::HIR::TypeRef& ty_l, const ::HIR::TypeRef& ty_r) { // Integer with any other integer is valid, others go to overload resolution @@ -226,7 +226,7 @@ namespace { } break; } - + } return false; } @@ -267,7 +267,7 @@ namespace { } return false; } - + // ------- // _Assign // ------- @@ -276,10 +276,10 @@ namespace { { const auto& sp = node.span(); ::HIR::ExprVisitorDef::visit(node); - + const auto& ty_slot = node.m_slot->m_res_type; const auto& ty_val = node.m_value->m_res_type; - + const char* langitem = nullptr; const char* opname = nullptr; #define _(opname) case ::HIR::ExprNode_Assign::Op::opname @@ -295,7 +295,7 @@ namespace { return ; } break; - + _(And): {langitem = "bitand_assign"; opname = "bitand_assign"; } if(0) _(Or ): {langitem = "bitor_assign" ; opname = "bitor_assign" ; } if(0) _(Xor): {langitem = "bitxor_assign"; opname = "bitxor_assign"; } if(0) @@ -320,12 +320,12 @@ namespace { #undef _ assert( langitem ); assert( opname ); - + // Needs replacement, continue ::HIR::PathParams trait_params; trait_params.m_types.push_back( ty_val.clone() ); ::HIR::GenericPath trait { m_crate.get_lang_item_path(node.span(), langitem), mv$(trait_params) }; - + auto slot_type_refmut = ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Unique, ty_slot.clone()); ::std::vector< ::HIR::ExprNodeP> args; args.push_back(NEWNODE( slot_type_refmut.clone(), Borrow, sp, ::HIR::BorrowType::Unique, mv$(node.m_slot) )); @@ -334,22 +334,22 @@ namespace { ::HIR::Path(ty_slot.clone(), mv$(trait), opname), mv$(args) ); - + // Populate the cache for later passes auto& arg_types = dynamic_cast< ::HIR::ExprNode_CallPath&>(*m_replacement).m_cache.m_arg_types; arg_types.push_back( mv$(slot_type_refmut) ); arg_types.push_back( ty_val.clone() ); arg_types.push_back( ::HIR::TypeRef::new_unit() ); } - + void visit(::HIR::ExprNode_BinOp& node) override { const auto& sp = node.span(); ::HIR::ExprVisitorDef::visit(node); - + const auto& ty_l = node.m_left->m_res_type; const auto& ty_r = node.m_right->m_res_type; - + const char* langitem = nullptr; const char* method = nullptr; switch(node.m_op) @@ -383,19 +383,19 @@ namespace { ::HIR::PathParams trait_params; trait_params.m_types.push_back( ty_r.clone() ); ::HIR::GenericPath trait { m_crate.get_lang_item_path(node.span(), langitem), mv$(trait_params) }; - + auto ty_l_ref = ::HIR::TypeRef::new_borrow( ::HIR::BorrowType::Shared, ty_l.clone() ); auto ty_r_ref = ::HIR::TypeRef::new_borrow( ::HIR::BorrowType::Shared, ty_r.clone() ); - + ::std::vector< ::HIR::ExprNodeP> args; args.push_back(NEWNODE(ty_l_ref.clone(), Borrow, node.m_left ->span(), ::HIR::BorrowType::Shared, mv$(node.m_left ) )); args.push_back(NEWNODE(ty_r_ref.clone(), Borrow, node.m_right->span(), ::HIR::BorrowType::Shared, mv$(node.m_right) )); - + m_replacement = NEWNODE(mv$(node.m_res_type), CallPath, sp, ::HIR::Path(ty_l.clone(), mv$(trait), method), mv$(args) ); - + // Populate the cache for later passes auto& arg_types = dynamic_cast< ::HIR::ExprNode_CallPath&>(*m_replacement).m_cache.m_arg_types; arg_types.push_back( mv$(ty_l_ref) ); @@ -403,7 +403,7 @@ namespace { arg_types.push_back( ::HIR::TypeRef( ::HIR::CoreType::Bool ) ); return ; } break; - + case ::HIR::ExprNode_BinOp::Op::Xor: langitem = method = "bitxor"; if(0) case ::HIR::ExprNode_BinOp::Op::Or : langitem = method = "bitor" ; if(0) case ::HIR::ExprNode_BinOp::Op::And: langitem = method = "bitand"; if(0) @@ -412,14 +412,14 @@ namespace { return ; } break; - + case ::HIR::ExprNode_BinOp::Op::Shr: langitem = method = "shr"; if(0) case ::HIR::ExprNode_BinOp::Op::Shl: langitem = method = "shr"; if( is_op_valid_shift(ty_l, ty_r) ) { return ; } break; - + case ::HIR::ExprNode_BinOp::Op::Add: langitem = method = "add"; if(0) case ::HIR::ExprNode_BinOp::Op::Sub: langitem = method = "sub"; if(0) case ::HIR::ExprNode_BinOp::Op::Mul: langitem = method = "mul"; if(0) @@ -429,7 +429,7 @@ namespace { return ; } break; - + case ::HIR::ExprNode_BinOp::Op::BoolAnd: case ::HIR::ExprNode_BinOp::Op::BoolOr: ASSERT_BUG(sp, ty_l == ::HIR::TypeRef(::HIR::CoreType::Bool), "&& operator requires bool"); @@ -438,35 +438,35 @@ namespace { } assert(langitem); assert(method); - + // Needs replacement, continue ::HIR::PathParams trait_params; trait_params.m_types.push_back( ty_r.clone() ); ::HIR::GenericPath trait { m_crate.get_lang_item_path(node.span(), langitem), mv$(trait_params) }; - + ::std::vector< ::HIR::ExprNodeP> args; args.push_back( mv$(node.m_left) ); args.push_back( mv$(node.m_right) ); - + m_replacement = NEWNODE(mv$(node.m_res_type), CallPath, sp, ::HIR::Path(ty_l.clone(), mv$(trait), method), mv$(args) ); - + // Populate the cache for later passes auto& arg_types = dynamic_cast< ::HIR::ExprNode_CallPath&>(*m_replacement).m_cache.m_arg_types; arg_types.push_back( ty_l.clone() ); arg_types.push_back( ty_r.clone() ); arg_types.push_back( m_replacement->m_res_type.clone() ); } - + void visit(::HIR::ExprNode_UniOp& node) override { const auto& sp = node.span(); ::HIR::ExprVisitorDef::visit(node); - + const auto& ty_val = node.m_value->m_res_type; - + const char* langitem = nullptr; const char* method = nullptr; switch(node.m_op) @@ -518,33 +518,33 @@ namespace { } assert(langitem); assert(method); - + // Needs replacement, continue ::HIR::GenericPath trait { m_crate.get_lang_item_path(node.span(), langitem), {} }; - + ::std::vector< ::HIR::ExprNodeP> args; args.push_back( mv$(node.m_value) ); - + m_replacement = NEWNODE(mv$(node.m_res_type), CallPath, sp, ::HIR::Path(ty_val.clone(), mv$(trait), method), mv$(args) ); - + // Populate the cache for later passes auto& arg_types = dynamic_cast< ::HIR::ExprNode_CallPath&>(*m_replacement).m_cache.m_arg_types; arg_types.push_back( ty_val.clone() ); arg_types.push_back( m_replacement->m_res_type.clone() ); } - - + + void visit(::HIR::ExprNode_Index& node) override { const auto& sp = node.span(); ::HIR::ExprVisitorDef::visit(node); - + const auto& ty_idx = node.m_index->m_res_type; const auto& ty_val = node.m_value->m_res_type; - + TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty_val.m_data), (val_te), ( // Unknown? fall down to the method call @@ -564,7 +564,7 @@ namespace { // Any other index type goes to the function call ) ) - + // TODO: Which trait should be used? const char* langitem = nullptr; const char* method = nullptr; @@ -589,16 +589,16 @@ namespace { // Needs replacement, continue assert(langitem); assert(method); - + // - Construct trait path - Index*<IdxTy> ::HIR::PathParams pp; pp.m_types.push_back( ty_idx.clone() ); ::HIR::GenericPath trait { m_crate.get_lang_item_path(node.span(), langitem), mv$(pp) }; - + ::std::vector< ::HIR::ExprNodeP> args; args.push_back( NEWNODE( ::HIR::TypeRef::new_borrow(bt, ty_val.clone()), Borrow, sp, bt, mv$(node.m_value) ) ); args.push_back( mv$(node.m_index) ); - + m_replacement = NEWNODE( ::HIR::TypeRef::new_borrow(bt, node.m_res_type.clone()), CallPath, sp, ::HIR::Path(ty_val.clone(), mv$(trait), method), mv$(args) @@ -610,19 +610,19 @@ namespace { arg_types.push_back( ::HIR::TypeRef::new_borrow(bt, ty_val.clone()) ); arg_types.push_back( ty_idx.clone() ); arg_types.push_back( m_replacement->m_res_type.clone() ); - + // - Dereference the result (which is an &-ptr) m_replacement = NEWNODE( mv$(node.m_res_type), Deref, sp, mv$(m_replacement) ); } - + void visit(::HIR::ExprNode_Deref& node) override { const auto& sp = node.span(); - + ::HIR::ExprVisitorDef::visit(node); - + const auto& ty_val = node.m_value->m_res_type; - + TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty_val.m_data), (e), ( BUG(sp, "Deref on unexpected type - " << ty_val); @@ -647,7 +647,7 @@ namespace { return ; ) ) - + const char* langitem = nullptr; const char* method = nullptr; ::HIR::BorrowType bt; @@ -672,13 +672,13 @@ namespace { // Needs replacement, continue assert(langitem); assert(method); - + // - Construct trait path - Index*<IdxTy> ::HIR::GenericPath trait { m_crate.get_lang_item_path(node.span(), langitem), {} }; - + ::std::vector< ::HIR::ExprNodeP> args; args.push_back( NEWNODE( ::HIR::TypeRef::new_borrow(bt, ty_val.clone()), Borrow, sp, bt, mv$(node.m_value) ) ); - + m_replacement = NEWNODE( ::HIR::TypeRef::new_borrow(bt, node.m_res_type.clone()), CallPath, sp, ::HIR::Path(ty_val.clone(), mv$(trait), method), mv$(args) @@ -689,23 +689,23 @@ namespace { auto& arg_types = call_node.m_cache.m_arg_types; arg_types.push_back( ::HIR::TypeRef::new_borrow(bt, ty_val.clone()) ); arg_types.push_back( m_replacement->m_res_type.clone() ); - + // - Dereference the result (which is an &-ptr) m_replacement = NEWNODE( mv$(node.m_res_type), Deref, sp, mv$(m_replacement) ); } - - - + + + void visit(::HIR::ExprNode_Unsize& node) override { ::HIR::ExprVisitorDef::visit(node); - + // HACK: The autoderef code has to run before usage information is avaliable, so emits "invalid" _Unsize nodes // - Fix that. if( node.m_value->m_res_type.m_data.is_Array() ) { const Span& sp = node.span(); - + ::HIR::BorrowType bt = ::HIR::BorrowType::Shared; switch( node.m_usage ) { @@ -722,7 +722,7 @@ namespace { TODO(sp, "Support moving in _Unsize"); break; } - + auto ty_src = ::HIR::TypeRef::new_borrow(bt, node.m_value->m_res_type.clone()); auto ty_dst = ::HIR::TypeRef::new_borrow(bt, node.m_res_type.clone()); auto ty_dst2 = ty_dst.clone(); @@ -744,12 +744,12 @@ namespace { m_crate(crate) { } - + // NOTE: This is left here to ensure that any expressions that aren't handled by higher code cause a failure void visit_expr(::HIR::ExprPtr& exp) override { BUG(Span(), "visit_expr hit in OuterVisitor"); } - + void visit_type(::HIR::TypeRef& ty) override { TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Array, e, @@ -799,7 +799,7 @@ namespace { { TU_IFLET(::HIR::Enum::Variant, var.second, Value, e, DEBUG("Enum value " << p << " - " << var.first); - + ExprVisitor_Mutate ev(m_crate); ev.visit_node_ptr(e.expr); ) diff --git a/src/hir_expand/vtable.cpp b/src/hir_expand/vtable.cpp index f12f8de5..f366a7d4 100644 --- a/src/hir_expand/vtable.cpp +++ b/src/hir_expand/vtable.cpp @@ -25,11 +25,11 @@ namespace { { m_lang_Sized = crate.get_lang_item_path_opt("sized"); } - + void visit_module(::HIR::ItemPath p, ::HIR::Module& mod) override { auto saved_nt = mv$(m_new_type); - + ::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) ) }) ); @@ -37,19 +37,19 @@ namespace { new_types.push_back( ::std::make_pair( mv$(name), mv$(boxed)) ); return ret; }; - + ::HIR::Visitor::visit_module(p, mod); for(auto& i : new_types ) mod.m_mod_items.insert( mv$(i) ); - + m_new_type = mv$(saved_nt); } - + void visit_trait(::HIR::ItemPath p, ::HIR::Trait& tr) override { static Span sp; TRACE_FUNCTION_F(p); - + ::HIR::GenericPath trait_path( p.get_simple_path() ); { unsigned int i = 0; @@ -58,7 +58,7 @@ namespace { i ++; } } - + ::std::unordered_map< ::std::string,unsigned int> assoc_type_indexes; struct Foo { ::HIR::Trait* trait_ptr; @@ -87,12 +87,12 @@ namespace { } visitor.add_types_from_trait(tr); auto args = mv$(visitor.params); - + struct VtableConstruct { const OuterVisitor* m_outer; ::HIR::Trait* trait_ptr; ::HIR::t_struct_fields fields; - + bool add_ents_from_trait(const ::HIR::Trait& tr, const ::HIR::GenericPath& trait_path) { TRACE_FUNCTION_F(trait_path); @@ -136,7 +136,7 @@ namespace { DEBUG("- '" << vi.first << "' NOT object safe (generic), not creating vtable"); return false; } - + ::HIR::FunctionType ft; ft.is_unsafe = ve.m_unsafe; ft.m_abi = ve.m_abi; @@ -147,14 +147,14 @@ namespace { ft.m_arg_types.push_back( clone_ty_with(sp, ve.m_args[i].second, clone_cb) ); // Clear the first argument (the receiver) ::HIR::TypeRef fcn_type( mv$(ft) ); - + // Detect use of `Self` and don't create the vtable if there is. if( visit_ty_with(fcn_type, [&](const auto& t){ return (t == ::HIR::TypeRef("Self", 0xFFFF)); }) ) { DEBUG("- '" << vi.first << "' NOT object safe (Self), not creating vtable - " << fcn_type); return false; } - + trait_ptr->m_value_indexes.insert( ::std::make_pair( vi.first, ::std::make_pair(fields.size(), trait_path.clone()) @@ -186,7 +186,7 @@ namespace { return true; } }; - + VtableConstruct vtc { this, &tr, {} }; if( ! vtc.add_ents_from_trait(tr, trait_path) ) { @@ -195,7 +195,7 @@ namespace { return ; } auto fields = mv$(vtc.fields); - + ::HIR::PathParams params; { unsigned int i = 0; @@ -217,21 +217,21 @@ namespace { }); DEBUG("Vtable structure created - " << item_path); ::HIR::GenericPath path( mv$(item_path), mv$(params) ); - + tr.m_values.insert( ::std::make_pair( "#vtable", ::HIR::TraitValueItem(::HIR::Static { ::HIR::Linkage(), false, ::HIR::TypeRef( mv$(path) ), {},{} }) ) ); } - + void visit_trait_impl(const ::HIR::SimplePath& trait_path, ::HIR::TraitImpl& impl) override { static Span sp; TRACE_FUNCTION_F("impl " << trait_path << " for " << impl.m_type); //auto _ = this->m_resolve.set_impl_generics(impl.m_params); - + ::HIR::Visitor::visit_trait_impl(trait_path, impl); - + #if 0 // Check if the trait has a vtable, and if it does emit an associated static for it. const auto& tr = m_crate.get_trait_by_path(sp, trait_path); @@ -239,7 +239,7 @@ namespace { { auto monomorph_cb_trait = monomorphise_type_get_cb(sp, &impl.m_type, &impl.m_trait_args, nullptr); auto trait_gpath = ::HIR::GenericPath(trait_path, impl.m_trait_args.clone()); - + ::std::vector< ::HIR::Literal> vals; vals.resize( tr.m_value_indexes.size() ); for(const auto& m : tr.m_value_indexes) @@ -249,7 +249,7 @@ namespace { auto gpath = monomorphise_genericpath_with(sp, m.second.second, monomorph_cb_trait, false); vals.at(m.second.first) = ::HIR::Literal::make_BorrowOf( ::HIR::Path(impl.m_type.clone(), mv$(gpath), m.first) ); } - + auto vtable_sp = trait_path; vtable_sp.m_components.back() += "#vtable"; auto vtable_params = impl.m_trait_args.clone(); @@ -257,7 +257,7 @@ namespace { ::HIR::Path path( impl.m_type.clone(), mv$(trait_gpath), ty.first ); vtable_params.m_types.push_back( ::HIR::TypeRef( mv$(path) ) ); } - + const auto& vtable_ref = m_crate.get_struct_by_path(sp, vtable_sp); impl.m_statics.insert(::std::make_pair( "#vtable", ::HIR::TraitImpl::ImplEnt<::HIR::Static> { true, ::HIR::Static { ::HIR::Linkage(), diff --git a/src/hir_typeck/common.cpp b/src/hir_typeck/common.cpp index 0751d5a1..96508345 100644 --- a/src/hir_typeck/common.cpp +++ b/src/hir_typeck/common.cpp @@ -143,7 +143,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 rv; rv.m_types.reserve( tpl.m_types.size() ); - for( const auto& ty : tpl.m_types) + for( const auto& ty : tpl.m_types) rv.m_types.push_back( clone_ty_with(sp, ty, callback) ); return rv; } @@ -157,14 +157,14 @@ bool monomorphise_type_needed(const ::HIR::TypeRef& tpl) {}, tpl.m_trait_ptr }; - + for(const auto& assoc : tpl.m_type_bounds) { rv.m_type_bounds.insert(::std::make_pair( assoc.first, clone_ty_with(sp, assoc.second, callback) )); } - + return rv; } ::HIR::Path clone_ty_with__path(const Span& sp, const ::HIR::Path& tpl, t_cb_clone_ty callback) { @@ -201,12 +201,12 @@ bool monomorphise_type_needed(const ::HIR::TypeRef& tpl) ::HIR::TypeRef clone_ty_with(const Span& sp, const ::HIR::TypeRef& tpl, t_cb_clone_ty callback) { ::HIR::TypeRef rv; - + if( callback(tpl, rv) ) { DEBUG(tpl << " => " << rv); return rv; } - + TU_MATCH(::HIR::TypeRef::Data, (tpl.m_data), (e), (Infer, rv = ::HIR::TypeRef(e); @@ -235,19 +235,19 @@ bool monomorphise_type_needed(const ::HIR::TypeRef& tpl) to.m_trait = clone_ty_with__trait_path(sp, e.m_trait, callback); for(const auto& trait : e.m_markers) { - to.m_markers.push_back( clone_ty_with__generic_path(sp, trait, callback) ); + to.m_markers.push_back( clone_ty_with__generic_path(sp, trait, callback) ); } to.m_lifetime = e.m_lifetime; rv = ::HIR::TypeRef( mv$(to) ); ), (ErasedType, auto origin = clone_ty_with__path(sp, e.m_origin, callback); - + ::std::vector< ::HIR::TraitPath> traits; traits.reserve( e.m_traits.size() ); for(const auto& trait : e.m_traits) traits.push_back( clone_ty_with__trait_path(sp, trait, callback) ); - + rv = ::HIR::TypeRef( ::HIR::TypeRef::Data::Data_ErasedType { mv$(origin), e.m_index, mv$(traits), @@ -306,12 +306,12 @@ namespace { return [&sp,&outer_tpl,callback,allow_infer](const auto& tpl, auto& rv) { if( tpl.m_data.is_Infer() && !allow_infer ) BUG(sp, "_ type found in " << outer_tpl); - + if( tpl.m_data.is_Generic() ) { rv = callback(tpl).clone(); return true; } - + return false; }; } diff --git a/src/hir_typeck/common.hpp b/src/hir_typeck/common.hpp index d6bf30c1..40e7e73c 100644 --- a/src/hir_typeck/common.hpp +++ b/src/hir_typeck/common.hpp @@ -44,9 +44,9 @@ struct MonomorphState const ::HIR::TypeRef* self_ty; const ::HIR::PathParams* pp_impl; const ::HIR::PathParams* pp_method; - + t_cb_generic get_cb(const Span& sp) const; - + ::HIR::TypeRef monomorph(const Span& sp, const ::HIR::TypeRef& ty, bool allow_infer=true) const { return monomorphise_type_with(sp, ty, this->get_cb(sp), allow_infer); } diff --git a/src/hir_typeck/expr_check.cpp b/src/hir_typeck/expr_check.cpp index 4009a76a..11e895cb 100644 --- a/src/hir_typeck/expr_check.cpp +++ b/src/hir_typeck/expr_check.cpp @@ -13,7 +13,7 @@ namespace { typedef ::std::vector< ::std::pair< ::HIR::Pattern, ::HIR::TypeRef> > t_args; - + class ExprVisitor_Validate: public ::HIR::ExprVisitor { @@ -21,7 +21,7 @@ namespace { //const t_args& m_args; const ::HIR::TypeRef& ret_type; ::std::vector< const ::HIR::TypeRef*> closure_ret_types; - + public: ExprVisitor_Validate(const StaticTraitResolve& res, const t_args& args, const ::HIR::TypeRef& ret_type): m_resolve(res), @@ -29,12 +29,12 @@ namespace { ret_type(ret_type) { } - + void visit_root(::HIR::ExprPtr& node_ptr) { const auto& sp = node_ptr->span(); node_ptr->visit(*this); - + // Monomorphise erased type ::HIR::TypeRef new_ret_type = clone_ty_with(sp, ret_type, [&](const auto& tpl, auto& rv) { if( tpl.m_data.is_ErasedType() ) @@ -51,7 +51,7 @@ namespace { check_types_equal(sp, new_ret_type, node_ptr->m_res_type); } - + void visit(::HIR::ExprNode_Block& node) override { TRACE_FUNCTION_F(&node << " { ... }"); @@ -113,7 +113,7 @@ namespace { void visit(::HIR::ExprNode_Assign& node) override { TRACE_FUNCTION_F(&node << "... ?= ..."); - + if( node.m_op == ::HIR::ExprNode_Assign::Op::None ) { check_types_equal(node.span(), node.m_slot->m_res_type, node.m_value->m_res_type); } @@ -137,17 +137,17 @@ namespace { } assert(lang_item); const auto& trait_path = this->get_lang_item_path(node.span(), lang_item); - + check_associated_type(node.span(), ::HIR::TypeRef(), trait_path, { node.m_value->m_res_type.clone() }, node.m_slot->m_res_type, ""); } - + node.m_slot->visit( *this ); node.m_value->visit( *this ); } void visit(::HIR::ExprNode_BinOp& node) override { TRACE_FUNCTION_F(&node << "... "<<::HIR::ExprNode_BinOp::opname(node.m_op)<<" ..."); - + switch(node.m_op) { case ::HIR::ExprNode_BinOp::Op::CmpEqu: @@ -157,7 +157,7 @@ namespace { case ::HIR::ExprNode_BinOp::Op::CmpGt: case ::HIR::ExprNode_BinOp::Op::CmpGtE: { check_types_equal(node.span(), ::HIR::TypeRef(::HIR::CoreType::Bool), node.m_res_type); - + const char* item_name = nullptr; switch(node.m_op) { @@ -171,10 +171,10 @@ namespace { } assert(item_name); const auto& op_trait = this->get_lang_item_path(node.span(), item_name); - + check_associated_type(node.span(), ::HIR::TypeRef(), op_trait, { node.m_right->m_res_type.clone() }, node.m_left->m_res_type, ""); break; } - + case ::HIR::ExprNode_BinOp::Op::BoolAnd: case ::HIR::ExprNode_BinOp::Op::BoolOr: // No validation needed, result forced in typeck @@ -197,25 +197,25 @@ namespace { case ::HIR::ExprNode_BinOp::Op::Mul: item_name = "mul"; break; case ::HIR::ExprNode_BinOp::Op::Div: item_name = "div"; break; case ::HIR::ExprNode_BinOp::Op::Mod: item_name = "rem"; break; - + case ::HIR::ExprNode_BinOp::Op::And: item_name = "bitand"; break; case ::HIR::ExprNode_BinOp::Op::Or: item_name = "bitor"; break; case ::HIR::ExprNode_BinOp::Op::Xor: item_name = "bitxor"; break; - + case ::HIR::ExprNode_BinOp::Op::Shr: item_name = "shr"; break; case ::HIR::ExprNode_BinOp::Op::Shl: item_name = "shl"; break; } assert(item_name); const auto& op_trait = this->get_lang_item_path(node.span(), item_name); - + check_associated_type(node.span(), node.m_res_type, op_trait, { node.m_right->m_res_type.clone() }, node.m_left->m_res_type, "Output"); break; } } - + node.m_left ->visit( *this ); node.m_right->visit( *this ); } - + void visit(::HIR::ExprNode_UniOp& node) override { TRACE_FUNCTION_F(&node << " " << ::HIR::ExprNode_UniOp::opname(node.m_op) << "..."); @@ -243,24 +243,24 @@ namespace { node.m_res_type, this->get_lang_item_path(node.span(), "index"), { node.m_index->m_res_type.clone() }, node.m_value->m_res_type, "Target" ); - + node.m_value->visit( *this ); node.m_index->visit( *this ); } - + void visit(::HIR::ExprNode_Cast& node) override { TRACE_FUNCTION_F(&node << " ... as " << node.m_res_type); const Span& sp = node.span(); - + const auto& src_ty = node.m_value->m_res_type; const auto& dst_ty = node.m_res_type; - + if( dst_ty == src_ty ) { // Would be nice to delete it, but this is a readonly pass return ; } - + // Check castability TU_MATCH_DEF(::HIR::TypeRef::Data, (dst_ty.m_data), (de), ( @@ -307,17 +307,17 @@ namespace { // TODO: Check cast to primitive ) ) - + node.m_value->visit( *this ); } void visit(::HIR::ExprNode_Unsize& node) override { TRACE_FUNCTION_F(&node << " ... : " << node.m_res_type); const Span& sp = node.span(); - + const auto& src_ty = node.m_value->m_res_type; const auto& dst_ty = node.m_res_type; - + if( src_ty.m_data.is_Borrow() && dst_ty.m_data.is_Borrow() ) { const auto& se = src_ty.m_data.as_Borrow(); @@ -327,7 +327,7 @@ namespace { } const auto& src_ty = *se.inner; const auto& dst_ty = *de.inner; - + const auto& lang_Unsize = this->get_lang_item_path(node.span(), "unsize"); // _ == < `src_ty` as Unsize< `dst_ty` >::"" check_associated_type(sp, ::HIR::TypeRef(), lang_Unsize, { dst_ty.clone() }, src_ty, ""); @@ -342,7 +342,7 @@ namespace { // _ == < `src_ty` as CoerceUnsized< `dst_ty` >::"" check_associated_type(sp, ::HIR::TypeRef(), lang_CoerceUnsized, { dst_ty.clone() }, src_ty, ""); } - + node.m_value->visit( *this ); } void visit(::HIR::ExprNode_Deref& node) override @@ -361,7 +361,7 @@ namespace { { case ::HIR::ExprNode_Emplace::Type::Noop: assert( !node.m_place ); - + check_types_equal(node.span(), node.m_res_type, node.m_value->m_res_type); break; case ::HIR::ExprNode_Emplace::Type::Boxer: @@ -371,7 +371,7 @@ namespace { // TODO: Check trait break; } - + if( node.m_place ) this->visit_node_ptr(node.m_place); this->visit_node_ptr(node.m_value); @@ -380,10 +380,10 @@ namespace { { TRACE_FUNCTION_F(&node << " " << node.m_path << "(...,) [" << (node.m_is_struct ? "struct" : "enum") << "]"); const auto& sp = node.span(); - + // - Create ivars in path, and set result type const auto& ty = node.m_res_type; - + const ::HIR::t_tuple_fields* fields_ptr = nullptr; ASSERT_BUG(sp, ty.m_data.is_Path(), "Result type of _TupleVariant isn't Path"); TU_MATCH(::HIR::TypeRef::TypePathBinding, (ty.m_data.as_Path().binding), (e), @@ -412,7 +412,7 @@ namespace { assert(fields_ptr); const ::HIR::t_tuple_fields& fields = *fields_ptr; ASSERT_BUG(sp, fields.size() == node.m_args.size(), ""); - + // Bind fields with type params (coercable) // TODO: Remove use of m_arg_types (maybe assert that cache is correct?) for( unsigned int i = 0; i < node.m_args.size(); i ++ ) @@ -423,10 +423,10 @@ namespace { assert( node.m_arg_types[i] != ::HIR::TypeRef() ); des_ty = &node.m_arg_types[i]; } - + check_types_equal(*des_ty, node.m_args[i]); } - + for( auto& val : node.m_args ) { val->visit( *this ); } @@ -438,11 +438,11 @@ 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 ); } - + // - Create ivars in path, and set result type const auto& ty = node.m_res_type; ASSERT_BUG(sp, ty.m_data.is_Path(), "Result type of _StructLiteral isn't Path"); - + const ::HIR::t_struct_fields* fields_ptr = nullptr; TU_MATCH(::HIR::TypeRef::TypePathBinding, (ty.m_data.as_Path().binding), (e), (Unbound, ), @@ -463,7 +463,7 @@ namespace { ) ASSERT_BUG(node.span(), fields_ptr, "Didn't get field for path in _StructLiteral - " << ty); const ::HIR::t_struct_fields& fields = *fields_ptr; - + #if 1 const auto& ty_params = node.m_path.m_params.m_types; auto monomorph_cb = [&](const auto& gt)->const auto& { @@ -482,7 +482,7 @@ namespace { } }; #endif - + // Bind fields with type params (coercable) for( auto& val : node.m_values) { @@ -492,7 +492,7 @@ namespace { 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; - + if( monomorphise_type_needed(des_ty_r) ) { assert( des_ty_cache != ::HIR::TypeRef() ); des_ty_cache = monomorphise_type_with(node.span(), des_ty_r, monomorph_cb); @@ -502,7 +502,7 @@ namespace { DEBUG("." << name << " : " << *des_ty); check_types_equal(*des_ty, val.second); } - + for( auto& val : node.m_values ) { val.second->visit( *this ); } @@ -521,7 +521,7 @@ namespace { const auto& sp = node.span(); const auto& ty = node.m_res_type; ASSERT_BUG(sp, ty.m_data.is_Path(), "Result type of _UnitVariant isn't Path"); - + TU_MATCH(::HIR::TypeRef::TypePathBinding, (ty.m_data.as_Path().binding), (e), (Unbound, ), (Opaque, ), @@ -545,26 +545,26 @@ namespace { { const auto& sp = node.span(); TRACE_FUNCTION_F(&node << " " << node.m_path << "(..., )"); - + for( auto& val : node.m_args ) { val->visit( *this ); } - + // Do function resolution again, this time with concrete types. const auto& path = node.m_path; /*const*/ auto& cache = node.m_cache; - + const ::HIR::Function* fcn_ptr = nullptr; ::std::function<const ::HIR::TypeRef&(const ::HIR::TypeRef&)> monomorph_cb; - + TU_MATCH(::HIR::Path::Data, (path.m_data), (e), (Generic, const auto& path_params = e.m_params; - + const auto& fcn = m_resolve.m_crate.get_function_by_path(sp, e.m_path); fcn_ptr = &fcn; cache.m_fcn_params = &fcn.m_params; - + monomorph_cb = [&](const auto& gt)->const auto& { const auto& e = gt.m_data.as_Generic(); if( e.name == "Self" || e.binding == 0xFFFF ) @@ -587,21 +587,21 @@ namespace { (UfcsKnown, const auto& trait_params = e.trait.m_params; const auto& path_params = e.params; - + const auto& trait = m_resolve.m_crate.get_trait_by_path(sp, e.trait.m_path); if( trait.m_values.count(e.item) == 0 ) { BUG(sp, "Method '" << e.item << "' of trait " << e.trait.m_path << " doesn't exist"); } - + const auto& fcn = trait.m_values.at(e.item).as_Function(); cache.m_fcn_params = &fcn.m_params; cache.m_top_params = &trait.m_params; - + // Add a bound requiring the Self type impl the trait check_associated_type(sp, ::HIR::TypeRef(), e.trait.m_path, e.trait.m_params, *e.type, ""); - + fcn_ptr = &fcn; - + monomorph_cb = [&](const auto& gt)->const auto& { const auto& ge = gt.m_data.as_Generic(); if( ge.binding == 0xFFFF ) { @@ -646,14 +646,14 @@ namespace { ERROR(sp, E0000, "Failed to locate function " << path); } assert(impl_ptr); - + cache.m_fcn_params = &fcn_ptr->m_params; - - + + // NOTE: Trusts the existing cache. ASSERT_BUG(sp, 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 = [&](const auto& gt)->const auto& { @@ -684,7 +684,7 @@ namespace { assert( fcn_ptr ); const auto& fcn = *fcn_ptr; - + // --- Monomorphise the argument/return types (into current context) cache.m_arg_types.clear(); for(const auto& arg : fcn.m_args) { @@ -705,7 +705,7 @@ namespace { } else if( 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(), ""); const auto& erased_type_replacement = fcn_ptr->m_code.m_erased_types.at(e.m_index); rv = monomorphise_type_with(sp, erased_type_replacement, monomorph_cb, false); @@ -717,7 +717,7 @@ namespace { }) ); m_resolve.expand_associated_types(sp, cache.m_arg_types.back()); DEBUG("= " << cache.m_arg_types.back()); - + // Check types for(unsigned int i = 0; i < fcn.m_args.size(); i ++) { DEBUG("CHECK ARG " << i << " " << node.m_cache.m_arg_types[i] << " == " << node.m_args[i]->m_res_type); @@ -729,9 +729,9 @@ namespace { } DEBUG("CHECK RV " << node.m_res_type << " == " << node.m_cache.m_arg_types.back()); check_types_equal(node.span(), node.m_res_type, node.m_cache.m_arg_types.back()); - + cache.m_monomorph_cb = mv$(monomorph_cb); - + // Bounds for(const auto& bound : cache.m_fcn_params->m_bounds) { @@ -746,17 +746,17 @@ namespace { DEBUG("Bound " << be.type << ": " << be.trait); DEBUG("= (" << real_type << ": " << real_trait << ")"); const auto& trait_params = real_trait.m_params; - + const auto& trait_path = be.trait.m_path.m_path; check_associated_type(sp, ::HIR::TypeRef(), trait_path, trait_params, real_type, ""); - + // 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; m_resolve.trait_contains_type(sp, real_trait, *be.trait.m_trait_ptr, assoc.first, type_trait_path); - + auto other_ty = monomorphise_type_with(sp, assoc.second, cache.m_monomorph_cb, true); - + check_associated_type(sp, other_ty, type_trait_path.m_path, type_trait_path.m_params, real_type, assoc.first.c_str()); } ), @@ -773,9 +773,9 @@ namespace { void visit(::HIR::ExprNode_CallValue& node) override { TRACE_FUNCTION_F(&node << " (...)(..., )"); - + const auto& val_ty = node.m_value->m_res_type; - + TU_IFLET( ::HIR::TypeRef::Data, val_ty.m_data, Function, e, DEBUG("- Function pointer: " << val_ty); if( node.m_args.size() != e.m_arg_types.size() ) { @@ -796,14 +796,14 @@ namespace { : node.m_trait_used == ::HIR::ExprNode_CallValue::TraitUsed::FnOnce ? m_resolve.m_crate.get_lang_item_path(node.span(), "fn_once") : throw "" ); - + ::std::vector< ::HIR::TypeRef> tup_ents; for(const auto& arg : node.m_args) { tup_ents.push_back( arg->m_res_type.clone() ); } ::HIR::PathParams params; params.m_types.push_back( ::HIR::TypeRef( mv$(tup_ents) ) ); - + bool found = m_resolve.find_impl(node.span(), trait, ¶ms, val_ty, [&](auto , bool fuzzy){ ASSERT_BUG(node.span(), !fuzzy, "Fuzzy match in check pass"); return true; @@ -819,7 +819,7 @@ namespace { m_resolve.expand_associated_types(node.span(), exp_ret); check_types_equal(node.span(), node.m_res_type, exp_ret); } - + node.m_value->visit( *this ); for( auto& val : node.m_args ) { val->visit( *this ); @@ -837,19 +837,19 @@ namespace { check_types_equal(node.m_cache.m_arg_types[1+i], node.m_args[i]); } check_types_equal(node.span(), node.m_res_type, node.m_cache.m_arg_types.back()); - + node.m_value->visit( *this ); for( auto& val : node.m_args ) { val->visit( *this ); } } - + void visit(::HIR::ExprNode_Field& node) override { TRACE_FUNCTION_F(&node << " (...)." << node.m_field); 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' ); if( str_ty.m_data.is_Tuple() ) { @@ -876,20 +876,20 @@ namespace { ASSERT_BUG(sp, ty_e.binding.is_Struct() || ty_e.binding.is_Union(), "Value type of _Field isn't a Struct or Union - " << str_ty); } } - + node.m_value->visit( *this ); } void visit(::HIR::ExprNode_Tuple& node) override { TRACE_FUNCTION_F(&node << " (...,)"); const auto& tys = node.m_res_type.m_data.as_Tuple(); - + ASSERT_BUG(node.span(), tys.size() == node.m_vals.size(), "Bad element count in tuple literal - " << tys.size() << " != " << node.m_vals.size()); for(unsigned int i = 0; i < node.m_vals.size(); i ++) { check_types_equal(node.span(), tys[i], node.m_vals[i]->m_res_type); } - + for( auto& val : node.m_vals ) { val->visit( *this ); } @@ -902,7 +902,7 @@ namespace { for( auto& val : node.m_vals ) { check_types_equal(val->span(), inner_ty, val->m_res_type); } - + for( auto& val : node.m_vals ) { val->visit( *this ); } @@ -910,15 +910,15 @@ namespace { void visit(::HIR::ExprNode_ArraySized& node) override { TRACE_FUNCTION_F(&node << " [...; "<<node.m_size_val<<"]"); - + //check_types_equal(node.m_size->span(), ::HIR::TypeRef(::HIR::Primitive::Usize), node.m_size->m_res_type); const auto& inner_ty = *node.m_res_type.m_data.as_Array().inner; check_types_equal(node.m_val->span(), inner_ty, node.m_val->m_res_type); - + node.m_val->visit( *this ); node.m_size->visit( *this ); } - + void visit(::HIR::ExprNode_Literal& node) override { // No validation needed @@ -927,7 +927,7 @@ namespace { { TRACE_FUNCTION_F(&node << " " << node.m_path); const auto& sp = node.span(); - + TU_MATCH(::HIR::Path::Data, (node.m_path.m_data), (e), (Generic, switch(node.m_target) @@ -953,7 +953,7 @@ namespace { ), (UfcsKnown, check_associated_type(sp, ::HIR::TypeRef(), e.trait.m_path, e.trait.m_params, e.type->clone(), ""); - + const auto& trait = this->m_resolve.m_crate.get_trait_by_path(sp, e.trait.m_path); auto it = trait.m_values.find( e.item ); if( it == trait.m_values.end() ) { @@ -978,16 +978,16 @@ namespace { ) ) } - + void visit(::HIR::ExprNode_Variable& node) override { // TODO: Check against variable slot? Nah. } - + void visit(::HIR::ExprNode_Closure& node) override { TRACE_FUNCTION_F(&node << " |...| ..."); - + if( node.m_code ) { check_types_equal(node.m_code->span(), node.m_return, node.m_code->m_res_type); @@ -996,7 +996,7 @@ namespace { this->closure_ret_types.pop_back( ); } } - + private: void check_types_equal(const ::HIR::TypeRef& l, const ::HIR::ExprNodeP& node) const { @@ -1023,8 +1023,8 @@ namespace { // TODO: Actually check. #if 0 bool found = m_resolve.find_impl(sp, trait, ¶ms, ity, [&](auto impl, bool fuzzy){ - - + + return true; }); if( !found ) @@ -1033,14 +1033,14 @@ namespace { } #endif } - + const ::HIR::SimplePath& get_lang_item_path(const Span& sp, const char* name) const { return m_resolve.m_crate.get_lang_item_path(sp, name); } }; - - + + class OuterVisitor: public ::HIR::Visitor { @@ -1049,12 +1049,12 @@ namespace { OuterVisitor(const ::HIR::Crate& crate): m_resolve(crate) {} - + // NOTE: This is left here to ensure that any expressions that aren't handled by higher code cause a failure void visit_expr(::HIR::ExprPtr& exp) override { BUG(Span(), "visit_expr hit in OuterVisitor"); } - + void visit_type(::HIR::TypeRef& ty) override { TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Array, e, @@ -1107,19 +1107,19 @@ namespace { //auto _ = this->m_ms.set_item_generics(item.m_params); // TODO: Use a different type depding on repr() auto enum_type = ::HIR::TypeRef(::HIR::CoreType::Isize); - + for(auto& var : item.m_variants) { TU_IFLET(::HIR::Enum::Variant, var.second, Value, e, DEBUG("Enum value " << p << " - " << var.first); - + t_args tmp; ExprVisitor_Validate ev(m_resolve, tmp, enum_type); ev.visit_root(e.expr); ) } } - + void visit_trait(::HIR::ItemPath p, ::HIR::Trait& item) override { auto _ = this->m_resolve.set_impl_generics(item.m_params); @@ -1129,14 +1129,14 @@ namespace { { TRACE_FUNCTION_F("impl " << impl.m_type); auto _ = this->m_resolve.set_impl_generics(impl.m_params); - + ::HIR::Visitor::visit_type_impl(impl); } void visit_trait_impl(const ::HIR::SimplePath& trait_path, ::HIR::TraitImpl& impl) override { TRACE_FUNCTION_F("impl" << impl.m_params.fmt_args() << " " << trait_path << " for " << impl.m_type); auto _ = this->m_resolve.set_impl_generics(impl.m_params); - + ::HIR::Visitor::visit_trait_impl(trait_path, impl); } }; diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 91febcc4..b1ee04bc 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -28,20 +28,20 @@ struct Context virtual void fmt(::std::ostream& os) const = 0; virtual bool revisit(Context& context) = 0; }; - + struct Binding { ::std::string name; ::HIR::TypeRef ty; //unsigned int ivar; }; - + /// Inferrence variable equalities struct Coercion { ::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 << ")"; return os; @@ -51,15 +51,15 @@ struct Context { Span span; ::HIR::TypeRef left_ty; - + ::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 - + // HACK: operators are special - the result when both types are primitives is ALWAYS the lefthand side bool is_operator; - + friend ::std::ostream& operator<<(::std::ostream& os, const Associated& v) { if( v.name == "" ) { os << "req ty " << v.impl_ty << " impl " << v.trait << v.params; @@ -70,7 +70,7 @@ struct Context return os; } }; - + struct IVarPossible { bool force_no_to = false; @@ -80,7 +80,7 @@ struct Context ::std::vector<::HIR::TypeRef> types_coerce_from; ::std::vector<::HIR::TypeRef> types_unsize_from; //::std::vector<::HIR::TypeRef> types_default; - + void reset() { //auto tmp = mv$(this->types_default); *this = IVarPossible(); @@ -90,38 +90,38 @@ struct Context return !types_unsize_to.empty() || !types_coerce_to.empty() || !types_unsize_from.empty() || !types_coerce_from.empty() /* || !types_default.empty()*/; } }; - + const ::HIR::Crate& m_crate; - + ::std::vector<Binding> m_bindings; HMTypeInferrence m_ivars; TraitResolution m_resolve; - + ::std::vector<Coercion> link_coerce; ::std::vector<Associated> link_assoc; /// Nodes that need revisiting (e.g. method calls when the receiver isn't known) ::std::vector< ::HIR::ExprNode*> to_visit; /// Callback-based revisits (e.g. for slice patterns handling slices/arrays) ::std::vector< ::std::unique_ptr<Revisitor> > adv_revisits; - + ::std::vector< IVarPossible> possible_ivar_vals; - + const ::HIR::SimplePath m_lang_Box; - + 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") ) { } - + void dump() const; - + bool take_changed() { return m_ivars.take_changed(); } bool has_rules() const { return !(link_coerce.empty() && link_assoc.empty() && to_visit.empty() && adv_revisits.empty()); } - + inline void add_ivars(::HIR::TypeRef& ty) { m_ivars.add_ivars(ty); } @@ -144,12 +144,12 @@ struct Context equate_types_assoc(sp, l, trait, mv$(pp), impl_ty, name, is_op); } void equate_types_assoc(const Span& sp, const ::HIR::TypeRef& l, const ::HIR::SimplePath& trait, ::HIR::PathParams params, const ::HIR::TypeRef& impl_ty, const char *name, bool is_op); - + // - Add a trait bound (gets encoded as an associated type bound) void add_trait_bound(const Span& sp, const ::HIR::TypeRef& impl_ty, const ::HIR::SimplePath& trait, ::HIR::PathParams params) { equate_types_assoc(sp, ::HIR::TypeRef(), trait, mv$(params), impl_ty, "", false); } - + /// Disable possibility checking for the type (as if <impossible> was added as a coerce_to) void equate_types_to_shadow(const Span& sp, const ::HIR::TypeRef& r) { equate_types_shadow(sp, r, true); @@ -186,26 +186,26 @@ struct Context } /// Default type //void possible_equate_type_def(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); - + // - Add a pattern binding (forcing the type to match) void add_binding(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); const ::HIR::TypeRef& get_var(const Span& sp, unsigned int idx) const; - + // - Add a revisit entry void add_revisit(::HIR::ExprNode& node); void add_revisit_adv(::std::unique_ptr<Revisitor> ent); const ::HIR::TypeRef& get_type(const ::HIR::TypeRef& ty) const { return m_ivars.get_type(ty); } - + /// Create an autoderef operation from val_node->m_res_type to ty_dst (handling implicit unsizing) ::HIR::ExprNodeP create_autoderef(::HIR::ExprNodeP val_node, ::HIR::TypeRef ty_dst) const; - + private: void add_ivars_params(::HIR::PathParams& params) { m_ivars.add_ivars_params(params); @@ -216,7 +216,7 @@ static void fix_param_count(const Span& sp, Context& context, const ::HIR::TypeR static void fix_param_count(const Span& sp, Context& context, const ::HIR::TypeRef& self_ty, bool use_defaults, const ::HIR::GenericPath& path, const ::HIR::GenericParams& param_defs, ::HIR::PathParams& params); namespace { - + void apply_bounds_as_rules(Context& context, const Span& sp, const ::HIR::GenericParams& params_def, t_cb_generic monomorph_cb) { for(const auto& bound : params_def.m_bounds) @@ -232,7 +232,7 @@ namespace { DEBUG("Bound " << be.type << ": " << be.trait); DEBUG("= (" << real_type << ": " << real_trait << ")"); const auto& trait_params = real_trait.m_params; - + const auto& trait_path = be.trait.m_path.m_path; // If there's no type bounds, emit a trait bound // - Otherwise, the assocated type bounds will serve the same purpose @@ -240,15 +240,15 @@ namespace { { context.add_trait_bound(sp, real_type, trait_path, trait_params.clone()); } - + for( const auto& assoc : be.trait.m_type_bounds ) { ::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? context.m_resolve.trait_contains_type(sp, real_trait, *be.trait.m_trait_ptr, assoc.first, type_trait_path); - + auto other_ty = monomorphise_type_with(sp, assoc.second, monomorph_cb, true); - + context.equate_types_assoc(sp, other_ty, type_trait_path.m_path, mv$(type_trait_path.m_params.m_types), real_type, assoc.first.c_str()); } ), @@ -260,26 +260,26 @@ namespace { ) } } - + bool visit_call_populate_cache(Context& context, const Span& sp, ::HIR::Path& path, ::HIR::ExprCallCache& cache) __attribute__((warn_unused_result)); bool visit_call_populate_cache_UfcsInherent(Context& context, const Span& sp, ::HIR::Path& path, ::HIR::ExprCallCache& cache, const ::HIR::Function*& fcn_ptr); - + /// (HELPER) Populate the cache for nodes that use visit_call /// TODO: If the function has multiple mismatched options, tell the caller to try again later? bool visit_call_populate_cache(Context& context, const Span& sp, ::HIR::Path& path, ::HIR::ExprCallCache& cache) { TRACE_FUNCTION_FR(path, path); assert(cache.m_arg_types.size() == 0); - + const ::HIR::Function* fcn_ptr = nullptr; - + TU_MATCH(::HIR::Path::Data, (path.m_data), (e), (Generic, const auto& fcn = context.m_crate.get_function_by_path(sp, e.m_path); fix_param_count(sp, context, ::HIR::TypeRef(), false, path, fcn.m_params, e.m_params); fcn_ptr = &fcn; cache.m_fcn_params = &fcn.m_params; - + //const auto& params_def = fcn.m_params; const auto& path_params = e.m_params; cache.m_monomorph_cb = [&](const auto& gt)->const auto& { @@ -311,12 +311,12 @@ namespace { fix_param_count(sp, context, *e.type, false, path, fcn.m_params, e.params); cache.m_fcn_params = &fcn.m_params; cache.m_top_params = &trait.m_params; - + // Add a bound requiring the Self type impl the trait context.add_trait_bound(sp, *e.type, e.trait.m_path, e.trait.m_params.clone()); - + fcn_ptr = &fcn; - + const auto& trait_params = e.trait.m_params; const auto& path_params = e.params; cache.m_monomorph_cb = [&](const auto& gt)->const auto& { @@ -367,16 +367,16 @@ namespace { } DEBUG("Ret " << fcn.m_return); 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); - + return true; } bool visit_call_populate_cache_UfcsInherent(Context& context, const Span& sp, ::HIR::Path& path, ::HIR::ExprCallCache& cache, const ::HIR::Function*& fcn_ptr) { auto& e = path.m_data.as_UfcsInherent(); - + const ::HIR::TypeImpl* impl_ptr = nullptr; // Detect multiple applicable methods and get the caller to try again later if there are multiple unsigned int count = 0; @@ -402,8 +402,8 @@ namespace { DEBUG("Found impl" << impl_ptr->m_params.fmt_args() << " " << impl_ptr->m_type); fix_param_count(sp, context, *e.type, false, path, fcn_ptr->m_params, e.params); cache.m_fcn_params = &fcn_ptr->m_params; - - + + // If the impl block has parameters, figure out what types they map to // - The function params are already mapped (from fix_param_count) auto& impl_params = e.impl_params; @@ -411,7 +411,7 @@ namespace { { // Default-construct entires in the `impl_params` array impl_params.m_types.resize( impl_ptr->m_params.m_types.size() ); - + auto cmp = impl_ptr->m_type.match_test_generics_fuzz(sp, *e.type, context.m_ivars.callback_resolve_infer(), [&](auto idx, const auto& ty) { assert( idx < impl_params.m_types.size() ); impl_params.m_types[idx] = ty.clone(); @@ -427,8 +427,8 @@ namespace { ty = context.m_ivars.new_ivar_tr(); } } - - + + // Monomorphise the impl type with the new ivars, and equate to *e.type auto impl_monomorph_cb = [&](const auto& gt)->const auto& { const auto& ge = gt.m_data.as_Generic(); @@ -448,10 +448,10 @@ namespace { }; auto impl_ty_mono = monomorphise_type_with(sp, impl_ptr->m_type, impl_monomorph_cb, false); DEBUG("- impl_ty_mono = " << impl_ty_mono); - + context.equate_types(sp, impl_ty_mono, *e.type); } - + // Fill unknown parametrs with ivars for(auto& ty : impl_params.m_types) { if( ty == ::HIR::TypeRef() ) { @@ -460,7 +460,7 @@ namespace { } } } - + // Create monomorphise callback const auto& fcn_params = e.params; cache.m_monomorph_cb = [&](const auto& gt)->const auto& { @@ -490,24 +490,24 @@ namespace { BUG(sp, "Generic bounding out of total range - " << ge.binding); } }; - + // Add trait bounds for all impl and function bounds apply_bounds_as_rules(context, sp, impl_ptr->m_params, cache.m_monomorph_cb); - + // Equate `Self` and `impl_ptr->m_type` (after monomorph) { ::HIR::TypeRef tmp; const auto& impl_ty_m = (monomorphise_type_needed(impl_ptr->m_type) ? tmp = monomorphise_type_with(sp, impl_ptr->m_type, cache.m_monomorph_cb) : impl_ptr->m_type); - + context.equate_types(sp, *e.type, impl_ty_m); } - + return true; } - + // ----------------------------------------------------------------------- // Enumeration visitor - // + // // Iterates the HIR expression tree and extracts type "equations" // ----------------------------------------------------------------------- class ExprVisitor_Enum: @@ -516,11 +516,11 @@ namespace { Context& context; const ::HIR::TypeRef& ret_type; ::std::vector< const ::HIR::TypeRef*> closure_ret_types; - + ::std::vector<bool> inner_coerce_enabled_stack; - + ::std::vector< ::HIR::ExprNode_Loop*> loop_blocks; // Used for `break` type markings - + // TEMP: List of in-scope traits for buildup ::HIR::t_trait_list m_traits; public: @@ -530,37 +530,37 @@ namespace { m_traits( mv$(base_traits) ) { } - + void visit(::HIR::ExprNode_Block& node) override { TRACE_FUNCTION_F(&node << " { ... }"); - + const auto is_diverge = [&](const ::HIR::TypeRef& rty)->bool { 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); }; - + if( node.m_nodes.size() > 0 ) { bool diverges = false; this->push_traits( node.m_traits ); - + this->push_inner_coerce(false); for( unsigned int i = 0; i < node.m_nodes.size()-1; i ++ ) { auto& snp = node.m_nodes[i]; this->context.add_ivars( snp->m_res_type ); snp->visit(*this); - + // If this statement yields !, then mark the block as diverging if( is_diverge(snp->m_res_type) ) { diverges = true; } } this->pop_inner_coerce(); - + if( node.m_yields_final ) { auto& snp = node.m_nodes.back(); @@ -575,7 +575,7 @@ namespace { this->context.add_ivars( snp->m_res_type ); // - Not yielded - so don't equate the return snp->visit(*this); - + // NOTE: If the final statement in the block diverges, mark this as diverging bool defer = false; if( !diverges ) @@ -599,7 +599,7 @@ namespace { diverges = false; } } - + // If a statement in this block diverges if( defer ) { DEBUG("Block final node returns _, derfer diverge check"); @@ -614,7 +614,7 @@ namespace { this->context.equate_types(node.span(), node.m_res_type, ::HIR::TypeRef::new_unit()); } } - + this->pop_traits( node.m_traits ); } else @@ -631,12 +631,12 @@ namespace { const auto& ret_ty = ( this->closure_ret_types.size() > 0 ? *this->closure_ret_types.back() : this->ret_type ); this->context.equate_types_coerce(node.span(), ret_ty, node.m_value); - + this->push_inner_coerce( true ); node.m_value->visit( *this ); this->pop_inner_coerce(); } - + void visit(::HIR::ExprNode_Loop& node) override { auto _ = this->push_inner_coerce_scoped(false); @@ -644,16 +644,16 @@ namespace { // Push this node to a stack so `break` statements can update the yeilded value this->loop_blocks.push_back( &node ); node.m_diverges = true; // Set to `false` if a break is hit - + // NOTE: This doesn't set the ivar to !, but marks it as a ! ivar (similar to the int/float markers) this->context.equate_types(node.span(), node.m_res_type, ::HIR::TypeRef::new_diverge()); - + this->context.add_ivars(node.m_code->m_res_type); this->context.equate_types(node.span(), node.m_code->m_res_type, ::HIR::TypeRef::new_unit()); node.m_code->visit( *this ); - + this->loop_blocks.pop_back( ); - + if( node.m_diverges ) { DEBUG("Loop diverged"); } @@ -667,10 +667,10 @@ namespace { if( this->loop_blocks.empty() ) { ERROR(node.span(), E0000, "Break statement with no acive loop"); } - + // NOTE: There's an RFC proposal (that's on track to be accepted) that allows `break value;` auto break_type = ::HIR::TypeRef::new_unit(); - + ::HIR::ExprNode_Loop* loop_node_ptr; if( node.m_label != "" ) { @@ -691,14 +691,14 @@ namespace { this->context.equate_types(node.span(), loop_node.m_res_type, break_type); } } - + void visit(::HIR::ExprNode_Let& node) override { 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); - + if( node.m_value ) { this->context.add_ivars( node.m_value->m_res_type ); @@ -716,7 +716,7 @@ namespace { this->context.equate_types_coerce( node.span(), node.m_type, node.m_value ); this->push_inner_coerce(true); } - + node.m_value->visit( *this ); this->pop_inner_coerce(); } @@ -724,17 +724,17 @@ namespace { void visit(::HIR::ExprNode_Match& node) override { TRACE_FUNCTION_F(&node << " match ..."); - + 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 ); } - + for(auto& arm : node.m_arms) { TRACE_FUNCTION_F("ARM " << arm.m_patterns); @@ -742,7 +742,7 @@ namespace { { this->context.add_binding(node.span(), pat, val_type); } - + if( arm.m_cond ) { auto _ = this->push_inner_coerce_scoped(false); @@ -750,29 +750,29 @@ namespace { this->context.equate_types(arm.m_cond->span(), ::HIR::TypeRef(::HIR::CoreType::Bool), arm.m_cond->m_res_type); arm.m_cond->visit( *this ); } - + this->context.add_ivars( arm.m_code->m_res_type ); this->equate_types_inner_coerce(node.span(), node.m_res_type, arm.m_code); arm.m_code->visit( *this ); } } - + void visit(::HIR::ExprNode_If& node) override { TRACE_FUNCTION_F(&node << " if ..."); - + this->context.add_ivars( node.m_cond->m_res_type ); - + { auto _ = this->push_inner_coerce_scoped(false); this->context.equate_types(node.m_cond->span(), ::HIR::TypeRef(::HIR::CoreType::Bool), node.m_cond->m_res_type); node.m_cond->visit( *this ); } - + this->context.add_ivars( node.m_true->m_res_type ); this->equate_types_inner_coerce(node.span(), node.m_res_type, node.m_true); node.m_true->visit( *this ); - + if( node.m_false ) { this->context.add_ivars( node.m_false->m_res_type ); this->equate_types_inner_coerce(node.span(), node.m_res_type, node.m_false); @@ -782,16 +782,16 @@ namespace { this->context.equate_types(node.span(), node.m_res_type, ::HIR::TypeRef::new_unit()); } } - - + + void visit(::HIR::ExprNode_Assign& node) override { auto _ = this->push_inner_coerce_scoped(false); - + TRACE_FUNCTION_F(&node << "... = ..."); this->context.add_ivars( node.m_slot ->m_res_type ); this->context.add_ivars( node.m_value->m_res_type ); - + // Plain assignment can't be overloaded, requires equal types if( node.m_op == ::HIR::ExprNode_Assign::Op::None ) { this->context.equate_types_coerce(node.span(), node.m_slot->m_res_type, node.m_value); @@ -816,29 +816,29 @@ namespace { } assert(lang_item); const auto& trait_path = this->context.m_crate.get_lang_item_path(node.span(), lang_item); - + this->context.equate_types_assoc(node.span(), ::HIR::TypeRef(), trait_path, ::make_vec1(node.m_value->m_res_type.clone()), node.m_slot->m_res_type.clone(), ""); } - + node.m_slot->visit( *this ); - + auto _2 = this->push_inner_coerce_scoped( node.m_op == ::HIR::ExprNode_Assign::Op::None ); node.m_value->visit( *this ); } void visit(::HIR::ExprNode_BinOp& node) override { auto _ = this->push_inner_coerce_scoped(false); - + TRACE_FUNCTION_F(&node << "... "<<::HIR::ExprNode_BinOp::opname(node.m_op)<<" ..."); - + this->context.add_ivars( node.m_left ->m_res_type ); this->context.add_ivars( node.m_right->m_res_type ); - + const auto& left_ty = node.m_left ->m_res_type; ::HIR::TypeRef right_ty_inner = this->context.m_ivars.new_ivar_tr(); const auto& right_ty = right_ty_inner;//node.m_right->m_res_type; this->context.equate_types_coerce(node.span(), right_ty_inner, node.m_right); - + switch(node.m_op) { case ::HIR::ExprNode_BinOp::Op::CmpEqu: @@ -848,7 +848,7 @@ namespace { case ::HIR::ExprNode_BinOp::Op::CmpGt: case ::HIR::ExprNode_BinOp::Op::CmpGtE: { this->context.equate_types(node.span(), node.m_res_type, ::HIR::TypeRef(::HIR::CoreType::Bool)); - + const char* item_name = nullptr; switch(node.m_op) { @@ -865,7 +865,7 @@ namespace { this->context.equate_types_assoc(node.span(), ::HIR::TypeRef(), op_trait, ::make_vec1(right_ty.clone()), left_ty.clone(), ""); break; } - + case ::HIR::ExprNode_BinOp::Op::BoolAnd: case ::HIR::ExprNode_BinOp::Op::BoolOr: this->context.equate_types(node.span(), node.m_res_type, ::HIR::TypeRef(::HIR::CoreType::Bool)); @@ -890,17 +890,17 @@ namespace { case ::HIR::ExprNode_BinOp::Op::Mul: item_name = "mul"; break; case ::HIR::ExprNode_BinOp::Op::Div: item_name = "div"; break; case ::HIR::ExprNode_BinOp::Op::Mod: item_name = "rem"; break; - + case ::HIR::ExprNode_BinOp::Op::And: item_name = "bitand"; break; case ::HIR::ExprNode_BinOp::Op::Or: item_name = "bitor"; break; case ::HIR::ExprNode_BinOp::Op::Xor: item_name = "bitxor"; break; - + case ::HIR::ExprNode_BinOp::Op::Shr: item_name = "shr"; break; case ::HIR::ExprNode_BinOp::Op::Shl: item_name = "shl"; break; } assert(item_name); const auto& op_trait = this->context.m_crate.get_lang_item_path(node.span(), item_name); - + // NOTE: `true` marks the association as coming from a binary operation, which changes integer handling this->context.equate_types_assoc(node.span(), node.m_res_type, op_trait, ::make_vec1(right_ty.clone()), left_ty.clone(), "Output", true); break; } @@ -912,7 +912,7 @@ namespace { void visit(::HIR::ExprNode_UniOp& node) override { auto _ = this->push_inner_coerce_scoped(false); - + TRACE_FUNCTION_F(&node << " " << ::HIR::ExprNode_UniOp::opname(node.m_op) << "..."); this->context.add_ivars( node.m_value->m_res_type ); const char* item_name = nullptr; @@ -934,21 +934,21 @@ namespace { { TRACE_FUNCTION_F(&node << " &_ ..."); this->context.add_ivars( node.m_value->m_res_type ); - + // TODO: Can Ref/RefMut trigger coercions? this->context.equate_types( node.span(), node.m_res_type, ::HIR::TypeRef::new_borrow(node.m_type, node.m_value->m_res_type.clone()) ); - + node.m_value->visit( *this ); } void visit(::HIR::ExprNode_Cast& node) override { auto _ = this->push_inner_coerce_scoped(false); - + TRACE_FUNCTION_F(&node << " ... as " << node.m_res_type); this->context.add_ivars( node.m_value->m_res_type ); - + node.m_value->visit( *this ); - + // TODO: Only revisit if the cast type requires inferring. this->context.add_revisit(node); } @@ -959,25 +959,25 @@ namespace { void visit(::HIR::ExprNode_Index& node) override { auto _ = this->push_inner_coerce_scoped(false); - + TRACE_FUNCTION_F(&node << " ... [ ... ]"); this->context.add_ivars( node.m_value->m_res_type ); this->context.add_ivars( node.m_index->m_res_type ); - + node.m_value->visit( *this ); node.m_index->visit( *this ); - + this->context.add_revisit(node); } void visit(::HIR::ExprNode_Deref& node) override { auto _ = this->push_inner_coerce_scoped(false); - + TRACE_FUNCTION_F(&node << " *..."); this->context.add_ivars( node.m_value->m_res_type ); node.m_value->visit( *this ); - + this->context.add_revisit(node); } void visit(::HIR::ExprNode_Emplace& node) override @@ -986,11 +986,11 @@ namespace { TRACE_FUNCTION_F(&node << " ... <- ... "); this->context.add_ivars( node.m_place->m_res_type ); this->context.add_ivars( node.m_value->m_res_type ); - + node.m_place->visit( *this ); auto _2 = this->push_inner_coerce_scoped(true); node.m_value->visit( *this ); - + this->context.add_revisit(node); } @@ -1019,28 +1019,28 @@ namespace { ) ) } - + ::HIR::TypeRef get_structenum_ty(const Span& sp, bool is_struct, ::HIR::GenericPath& gp) { if( is_struct ) { const auto& str = this->context.m_crate.get_struct_by_path(sp, gp.m_path); fix_param_count(sp, this->context, ::HIR::TypeRef(), false, gp, str.m_params, gp.m_params); - + return ::HIR::TypeRef::new_path( gp.clone(), ::HIR::TypeRef::TypePathBinding::make_Struct(&str) ); } else { auto s_path = gp.m_path; s_path.m_components.pop_back(); - + 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); - + return ::HIR::TypeRef::new_path( ::HIR::GenericPath(mv$(s_path), gp.m_params.clone()), ::HIR::TypeRef::TypePathBinding::make_Enum(&enm) ); } } - + void visit(::HIR::ExprNode_TupleVariant& node) override { const auto& sp = node.span(); @@ -1048,11 +1048,11 @@ namespace { for( auto& val : node.m_args ) { this->context.add_ivars( val->m_res_type ); } - + // - Create ivars in path, and set result type const auto ty = this->get_structenum_ty(node.span(), node.m_is_struct, node.m_path); this->context.equate_types(node.span(), node.m_res_type, ty); - + const ::HIR::t_tuple_fields* fields_ptr = nullptr; TU_MATCH(::HIR::TypeRef::TypePathBinding, (ty.m_data.as_Path().binding), (e), (Unbound, ), @@ -1078,7 +1078,7 @@ namespace { if( fields.size() != node.m_args.size() ) { ERROR(node.span(), E0000, ""); } - + const auto& ty_params = node.m_path.m_params.m_types; auto monomorph_cb = [&](const auto& gt)->const auto& { const auto& ge = gt.m_data.as_Generic(); @@ -1095,7 +1095,7 @@ namespace { BUG(sp, "Method-level parameter on struct (#" << ge.binding << " " << ge.name << ")"); } }; - + // Bind fields with type params (coercable) node.m_arg_types.resize( node.m_args.size() ); for( unsigned int i = 0; i < node.m_args.size(); i ++ ) @@ -1106,10 +1106,10 @@ namespace { node.m_arg_types[i] = monomorphise_type_with(sp, des_ty_r, monomorph_cb); des_ty = &node.m_arg_types[i]; } - + this->context.equate_types_coerce(node.span(), *des_ty, node.m_args[i]); } - + auto _ = this->push_inner_coerce_scoped(true); for( auto& val : node.m_args ) { val->visit( *this ); @@ -1124,14 +1124,14 @@ namespace { if( node.m_base_value ) { this->context.add_ivars( node.m_base_value->m_res_type ); } - + // - Create ivars in path, and set result type const auto ty = this->get_structenum_ty(node.span(), node.m_is_struct, node.m_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); } - + const ::HIR::t_struct_fields* fields_ptr = nullptr; const ::HIR::GenericParams* generics; TU_MATCH(::HIR::TypeRef::TypePathBinding, (ty.m_data.as_Path().binding), (e), @@ -1155,7 +1155,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; auto monomorph_cb = [&](const auto& gt)->const auto& { const auto& ge = gt.m_data.as_Generic(); @@ -1172,9 +1172,9 @@ namespace { BUG(node.span(), "Method-level parameter on struct (#" << ge.binding << " " << ge.name << ")"); } }; - + node.m_value_types.resize( fields.size() ); - + // Bind fields with type params (coercable) for( auto& val : node.m_values) { @@ -1184,7 +1184,7 @@ namespace { 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; - + DEBUG(name << " : " << des_ty_r); if( monomorphise_type_needed(des_ty_r) ) { if( des_ty_cache == ::HIR::TypeRef() ) { @@ -1197,10 +1197,10 @@ namespace { } this->equate_types_inner_coerce(node.span(), *des_ty, val.second); } - + // Convert bounds on the type into rules apply_bounds_as_rules(context, node.span(), *generics, monomorph_cb); - + auto _ = this->push_inner_coerce_scoped(true); for( auto& val : node.m_values ) { val.second->visit( *this ); @@ -1215,13 +1215,13 @@ namespace { const Span& sp = node.span(); TRACE_FUNCTION_F(&node << " " << node.m_path << "{ " << node.m_variant_name << ": ... }"); this->context.add_ivars( node.m_value->m_res_type ); - + const auto& unm = this->context.m_crate.get_union_by_path(sp, node.m_path.m_path); fix_param_count(sp, this->context, ::HIR::TypeRef(), false, node.m_path, unm.m_params, node.m_path.m_params); const auto ty = ::HIR::TypeRef::new_path( node.m_path.clone(), ::HIR::TypeRef::TypePathBinding::make_Union(&unm) ); - + this->context.equate_types(node.span(), node.m_res_type, ty); - + const auto& ty_params = node.m_path.m_params.m_types; auto monomorph_cb = [&](const auto& gt)->const auto& { const auto& ge = gt.m_data.as_Generic(); @@ -1238,7 +1238,7 @@ namespace { BUG(node.span(), "Method-level parameter on struct (#" << ge.binding << " " << ge.name << ")"); } }; - + // Convert bounds on the type into rules apply_bounds_as_rules(context, node.span(), unm.m_params, monomorph_cb); @@ -1257,15 +1257,15 @@ namespace { des_ty = &des_ty_cache; } this->equate_types_inner_coerce(node.span(), *des_ty, node.m_value); - + node.m_value->visit(*this); } void visit(::HIR::ExprNode_UnitVariant& node) override { TRACE_FUNCTION_F(&node << " " << node.m_path << " [" << (node.m_is_struct ? "struct" : "enum") << "]"); - + // TODO: Check? - + // - Create ivars in path, and set result type const auto ty = this->get_structenum_ty(node.span(), node.m_is_struct, node.m_path); this->context.equate_types(node.span(), node.m_res_type, ty); @@ -1278,7 +1278,7 @@ namespace { for( auto& val : node.m_args ) { this->context.add_ivars( val->m_res_type ); } - + // Populate cache { if( !visit_call_populate_cache(this->context, node.span(), node.m_path, node.m_cache) ) { @@ -1286,7 +1286,7 @@ namespace { } assert( node.m_cache.m_arg_types.size() >= 1); unsigned int exp_argc = node.m_cache.m_arg_types.size() - 1; - + if( node.m_args.size() != exp_argc ) { if( node.m_cache.m_fcn->m_variadic && node.m_args.size() > exp_argc ) { } @@ -1296,7 +1296,7 @@ namespace { } } } - + // Link arguments // - NOTE: Uses the cache for the count because vaargs aren't checked (they're checked for suitability in expr_check.cpp) for(unsigned int i = 0; i < node.m_cache.m_arg_types.size() - 1; i ++) @@ -1331,7 +1331,7 @@ namespace { this->context.equate_types_coerce(val->span(), node.m_arg_ivars[i], val); val->visit( *this ); } - + // Nothing can be done until type is known this->context.add_revisit(node); } @@ -1345,7 +1345,7 @@ namespace { for( auto& ty : node.m_params.m_types ) { this->context.add_ivars( ty ); } - + // - Search in-scope trait list for traits that provide a method of this name const ::std::string& method_name = node.m_method; ::HIR::t_trait_list possible_traits; @@ -1354,14 +1354,14 @@ namespace { { if( trait_ref.first == nullptr ) break; - + // TODO: Search supertraits too auto it = trait_ref.second->m_values.find(method_name); if( it == trait_ref.second->m_values.end() ) continue ; if( !it->second.is_Function() ) continue ; - + if( ::std::none_of( possible_traits.begin(), possible_traits.end(), [&](const auto&x){return x.second == trait_ref.second;}) ) { possible_traits.push_back( trait_ref ); if( trait_ref.second->m_params.m_types.size() > max_num_params ) @@ -1374,7 +1374,7 @@ namespace { { node.m_trait_param_ivars.push_back( this->context.m_ivars.new_ivar() ); } - + { auto _ = this->push_inner_coerce_scoped(false); node.m_value->visit( *this ); @@ -1383,7 +1383,7 @@ namespace { for( auto& val : node.m_args ) { val->visit( *this ); } - + // Resolution can't be done until lefthand type is known. // > Has to be done during iteraton this->context.add_revisit( node ); @@ -1393,19 +1393,19 @@ namespace { auto _ = this->push_inner_coerce_scoped(false); TRACE_FUNCTION_F(&node << " (...)."<<node.m_field); this->context.add_ivars( node.m_value->m_res_type ); - + node.m_value->visit( *this ); - + this->context.add_revisit( node ); } - + void visit(::HIR::ExprNode_Tuple& node) override { TRACE_FUNCTION_F(&node << " (...,)"); for( auto& val : node.m_vals ) { this->context.add_ivars( val->m_res_type ); } - + if( can_coerce_inner_result() ) { const auto& ty = this->context.get_type(node.m_res_type); @@ -1428,7 +1428,7 @@ namespace { } const auto& inner_tys = this->context.get_type(node.m_res_type).m_data.as_Tuple(); assert( inner_tys.size() == node.m_vals.size() ); - + for(unsigned int i = 0; i < inner_tys.size(); i ++) { this->context.equate_types_coerce(node.span(), inner_tys[i], node.m_vals[i]); @@ -1443,7 +1443,7 @@ namespace { } this->context.equate_types(node.span(), node.m_res_type, ::HIR::TypeRef(mv$(tuple_tys))); } - + for( auto& val : node.m_vals ) { val->visit( *this ); } @@ -1454,14 +1454,14 @@ namespace { for( auto& val : node.m_vals ) { this->context.add_ivars( val->m_res_type ); } - + // Cleanly equate into array (with coercions) // - Result type already set, just need to extract ivar const auto& inner_ty = *node.m_res_type.m_data.as_Array().inner; for( auto& val : node.m_vals ) { this->equate_types_inner_coerce(node.span(), inner_ty, val); } - + for( auto& val : node.m_vals ) { val->visit( *this ); } @@ -1471,7 +1471,7 @@ namespace { TRACE_FUNCTION_F(&node << " [...; "<<node.m_size_val<<"]"); this->context.add_ivars( node.m_val->m_res_type ); this->context.add_ivars( node.m_size->m_res_type ); - + // Create result type (can't be known until after const expansion) // - Should it be created in const expansion? auto ty = ::HIR::TypeRef::new_array( ::HIR::TypeRef(), node.m_size_val ); @@ -1481,11 +1481,11 @@ namespace { const auto& inner_ty = *ty.m_data.as_Array().inner; this->equate_types_inner_coerce(node.span(), inner_ty, node.m_val); this->context.equate_types(node.span(), ::HIR::TypeRef(::HIR::CoreType::Usize), node.m_size->m_res_type); - + node.m_val->visit( *this ); node.m_size->visit( *this ); } - + void visit(::HIR::ExprNode_Literal& node) override { TU_MATCH(::HIR::ExprNode_Literal::Data, (node.m_data), (e), @@ -1511,9 +1511,9 @@ namespace { const auto& sp = node.span(); this->visit_path(sp, node.m_path); TRACE_FUNCTION_F(&node << " " << node.m_path); - + this->add_ivars_path(node.span(), node.m_path); - + TU_MATCH(::HIR::Path::Data, (node.m_path.m_data), (e), (Generic, switch(node.m_target) { @@ -1522,7 +1522,7 @@ namespace { case ::HIR::ExprNode_PathValue::FUNCTION: { const auto& f = this->context.m_crate.get_function_by_path(sp, e.m_path); fix_param_count(sp, this->context, ::HIR::TypeRef(), false, e, f.m_params, e.m_params); - + const auto& params = e.m_params; auto monomorph_cb = [&](const auto& gt)->const auto& { const auto& e = gt.m_data.as_Generic(); @@ -1543,7 +1543,7 @@ namespace { BUG(sp, "Unknown param in free function - " << gt); } }; - + ::HIR::FunctionType ft { f.m_unsafe, f.m_abi, @@ -1554,7 +1554,7 @@ namespace { { ft.m_arg_types.push_back( monomorphise_type_with(sp, arg.second, monomorph_cb) ); } - + auto ty = ::HIR::TypeRef( ::HIR::TypeRef::Data::make_Function(mv$(ft)) ); this->context.equate_types(sp, node.m_res_type, ty); } break; @@ -1562,7 +1562,7 @@ namespace { const auto& s = this->context.m_crate.get_struct_by_path(sp, e.m_path); const auto& se = s.m_data.as_Tuple(); fix_param_count(sp, this->context, ::HIR::TypeRef(), false, e, s.m_params, e.m_params); - + ::HIR::FunctionType ft { false, ABI_RUST, @@ -1573,7 +1573,7 @@ namespace { { ft.m_arg_types.push_back( monomorphise_type(sp, s.m_params, e.m_params, arg.ent) ); } - + auto ty = ::HIR::TypeRef( ::HIR::TypeRef::Data::make_Function(mv$(ft)) ); this->context.equate_types(sp, node.m_res_type, ty); } break; @@ -1585,7 +1585,7 @@ namespace { fix_param_count(sp, this->context, ::HIR::TypeRef(), false, e, enm.m_params, e.m_params); const auto& var = *::std::find_if(enm.m_variants.begin(), enm.m_variants.end(), [&](const auto&x){ return x.first == var_name; }); const auto& var_data = var.second.as_Tuple(); - + ::HIR::FunctionType ft { false, ABI_RUST, @@ -1596,7 +1596,7 @@ namespace { { ft.m_arg_types.push_back( monomorphise_type(sp, enm.m_params, e.m_params, arg.ent) ); } - + auto ty = ::HIR::TypeRef( ::HIR::TypeRef::Data::make_Function(mv$(ft)) ); this->context.equate_types(sp, node.m_res_type, ty); } break; @@ -1621,10 +1621,10 @@ namespace { (UfcsKnown, const auto& trait = this->context.m_crate.get_trait_by_path(sp, e.trait.m_path); fix_param_count(sp, this->context, *e.type, true, e.trait, trait.m_params, e.trait.m_params); - + // 1. Add trait bound to be checked. this->context.add_trait_bound(sp, *e.type, e.trait.m_path, e.trait.m_params.clone()); - + // 2. Locate this item in the trait // - If it's an associated `const`, will have to revisit auto it = trait.m_values.find( e.item ); @@ -1643,7 +1643,7 @@ namespace { ), (Function, fix_param_count(sp, this->context, *e.type, false, node.m_path, ie.m_params, e.params); - + const auto& fcn_params = e.params; const auto& trait_params = e.trait.m_params; auto monomorph_cb = [&](const auto& gt)->const auto& { @@ -1675,14 +1675,14 @@ namespace { for(const auto& arg : ie.m_args) ft.m_arg_types.push_back( monomorphise_type_with(sp, arg.second, monomorph_cb) ); auto ty = ::HIR::TypeRef(mv$(ft)); - + this->context.equate_types(node.span(), node.m_res_type, ty); ) ) ), (UfcsInherent, // TODO: Share code with visit_call_populate_cache - + // - Locate function (and impl block) const ::HIR::Function* fcn_ptr = nullptr; const ::HIR::Constant* const_ptr = nullptr; @@ -1719,17 +1719,17 @@ namespace { if( count > 1 ) { TODO(sp, "Revisit _PathValue when UfcsInherent has multiple options - " << node.m_path); } - + assert(fcn_ptr || const_ptr); assert(impl_ptr); - + if( fcn_ptr ) { fix_param_count(sp, this->context, *e.type, false, node.m_path, fcn_ptr->m_params, e.params); } else { fix_param_count(sp, this->context, *e.type, false, node.m_path, const_ptr->m_params, e.params); } - + // If the impl block has parameters, figure out what types they map to // - The function params are already mapped (from fix_param_count) auto& impl_params = e.impl_params; @@ -1743,8 +1743,8 @@ namespace { for(const auto& ty : impl_params.m_types) assert( !( ty.m_data.is_Infer() && ty.m_data.as_Infer().index == ~0u) ); } - - + + if( fcn_ptr ) { // Create monomorphise callback @@ -1772,9 +1772,9 @@ namespace { BUG(sp, "Generic bounding out of total range"); } }; - + // TODO: Impl/method type bounds - + ::HIR::FunctionType ft { fcn_ptr->m_unsafe, fcn_ptr->m_abi, box$( monomorphise_type_with(sp, fcn_ptr->m_return, monomorph_cb) ), @@ -1783,16 +1783,16 @@ namespace { for(const auto& arg : fcn_ptr->m_args) ft.m_arg_types.push_back( monomorphise_type_with(sp, arg.second, monomorph_cb) ); auto ty = ::HIR::TypeRef(mv$(ft)); - + this->context.equate_types(node.span(), node.m_res_type, ty); } else // !fcn_ptr, ergo const_ptr { auto monomorph_cb = monomorphise_type_get_cb(sp, &*e.type, &impl_params, &e.params); - + ::HIR::TypeRef tmp; const auto& ty = ( monomorphise_type_needed(const_ptr->m_type) ? tmp = monomorphise_type_with(sp, const_ptr->m_type, monomorph_cb) : const_ptr->m_type ); - + this->context.equate_types(node.span(), node.m_res_type, ty); } ) @@ -1801,10 +1801,10 @@ namespace { void visit(::HIR::ExprNode_Variable& node) override { TRACE_FUNCTION_F(&node << " " << node.m_name << "{" << node.m_slot << "}"); - + this->context.equate_types(node.span(), node.m_res_type, this->context.get_var(node.span(), node.m_slot)); } - + void visit(::HIR::ExprNode_Closure& node) override { TRACE_FUNCTION_F(&node << " |...| ..."); @@ -1814,7 +1814,7 @@ namespace { } this->context.add_ivars( node.m_return ); this->context.add_ivars( node.m_code->m_res_type ); - + // Closure result type ::std::vector< ::HIR::TypeRef> arg_types; for(auto& arg : node.m_args) { @@ -1823,13 +1823,13 @@ namespace { this->context.equate_types( node.span(), node.m_res_type, ::HIR::TypeRef::new_closure(&node, mv$(arg_types), node.m_return.clone()) ); this->context.equate_types_coerce( node.span(), node.m_return, node.m_code ); - + auto _ = this->push_inner_coerce_scoped(true); this->closure_ret_types.push_back( &node.m_return ); node.m_code->visit( *this ); this->closure_ret_types.pop_back( ); } - + private: void push_traits(const ::HIR::t_trait_list& list) { this->m_traits.insert( this->m_traits.end(), list.begin(), list.end() ); @@ -1862,7 +1862,7 @@ namespace { ) ) } - + class InnerCoerceGuard { ExprVisitor_Enum& t; public: @@ -1920,23 +1920,23 @@ namespace { context(context), m_completed(false) {} - + bool node_completed() const { return m_completed; } void visit(::HIR::ExprNode_Block& node) override { - + const auto is_diverge = [&](const ::HIR::TypeRef& rty)->bool { 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); }; - + const auto& last_ty = this->context.get_type( node.m_nodes.back()->m_res_type ); DEBUG("_Block: last_ty = " << last_ty); - + bool diverges = false; // NOTE: If the final statement in the block diverges, mark this as diverging TU_IFLET(::HIR::TypeRef::Data, last_ty.m_data, Infer, e, @@ -1985,7 +1985,7 @@ namespace { void visit(::HIR::ExprNode_If& node) override { no_revisit(node); } - + void visit(::HIR::ExprNode_Assign& node) override { no_revisit(node); } @@ -2003,12 +2003,12 @@ namespace { const auto& tgt_ty = this->context.get_type(node.m_res_type); const auto& src_ty = this->context.get_type(node.m_value->m_res_type); TRACE_FUNCTION_F(src_ty << " as " << tgt_ty); - + if( this->context.m_ivars.types_equal(src_ty, tgt_ty) ) { this->m_completed = true; return ; } - + TU_MATCH( ::HIR::TypeRef::Data, (tgt_ty.m_data), (e), (Infer, // Can't know anything @@ -2123,7 +2123,7 @@ namespace { ERROR(sp, E0000, "Invalid cast from " << src_ty << " to " << tgt_ty); } const auto& src_inner = this->context.get_type(*s_e.inner); - + // NOTE: &mut T -> *mut U where T: Unsize<U> is allowed // TODO: Wouldn't this be better served by a coercion point? TU_IFLET( ::HIR::TypeRef::Data, src_inner.m_data, Infer, s_e_i, @@ -2184,22 +2184,22 @@ namespace { const auto& val_ty = this->context.get_type(node.m_value->m_res_type); const auto& idx_ty = this->context.get_type(node.m_index->m_res_type); TRACE_FUNCTION_F("Index: val=" << val_ty << ", idx=" << idx_ty << ""); - + this->context.equate_types_from_shadow(node.span(), node.m_res_type); - + // NOTE: Indexing triggers autoderef unsigned int deref_count = 0; ::HIR::TypeRef tmp_type; // Temporary type used for handling Deref const auto* current_ty = &node.m_value->m_res_type; ::std::vector< ::HIR::TypeRef> deref_res_types; - + // TODO: (CHECK) rustc doesn't use the index value type when finding the indexable item, mrustc does. ::HIR::PathParams trait_pp; trait_pp.m_types.push_back( idx_ty.clone() ); do { const auto& ty = this->context.get_type(*current_ty); DEBUG("(Index): (: " << ty << ")[: " << trait_pp.m_types[0] << "]"); - + ::HIR::TypeRef possible_index_type; ::HIR::TypeRef possible_res_type; unsigned int count = 0; @@ -2231,13 +2231,13 @@ namespace { else { // Either no matches, or multiple fuzzy matches } - + deref_count += 1; current_ty = this->context.m_resolve.autoderef(node.span(), ty, tmp_type); if( current_ty ) deref_res_types.push_back( current_ty->clone() ); } while( current_ty ); - + if( current_ty ) { DEBUG("Found impl on type " << *current_ty << " with " << deref_count << " derefs"); @@ -2245,18 +2245,18 @@ namespace { for(auto& ty_r : deref_res_types) { auto ty = mv$(ty_r); - + node.m_value = this->context.create_autoderef( mv$(node.m_value), mv$(ty) ); context.m_ivars.get_type(node.m_value->m_res_type); } - + m_completed = true; } } void visit(::HIR::ExprNode_Deref& node) override { const auto& ty = this->context.get_type(node.m_value->m_res_type); TRACE_FUNCTION_F("Deref: ty=" << ty); - + TU_MATCH_DEF(::HIR::TypeRef::Data, (ty.m_data), (e), ( const auto& op_trait = this->context.m_crate.get_lang_item_path(node.span(), "deref"); @@ -2284,7 +2284,7 @@ namespace { const auto& data_ty = node.m_value->m_res_type; auto node_ty = node.m_type; TRACE_FUNCTION_F("_Emplace: exp_ty=" << exp_ty); - + if( exp_ty.m_data.is_Infer() ) { // If the expected result type is still an ivar, nothing can be done @@ -2315,7 +2315,7 @@ namespace { if( gpath.m_params.m_types.size() > 0 ) { // TODO: If there's only one, check if it's a valid coercion target, if not don't bother making the coercion. - + // Take a copy of the type with all type parameters replaced with new ivars auto newpath = ::HIR::GenericPath(gpath.m_path); for( const auto& t : gpath.m_params.m_types ) @@ -2324,7 +2324,7 @@ namespace { newpath.m_params.m_types.push_back( this->context.m_ivars.new_ivar_tr() ); } auto newty = ::HIR::TypeRef::new_path( mv$(newpath), exp_ty.m_data.as_Path().binding.clone() ); - + // Turn this revisit into a coercion point with the new result type // - Mangle this node to be a passthrough to a copy of itself. @@ -2332,14 +2332,14 @@ namespace { node.m_type = ::HIR::ExprNode_Emplace::Type::Noop; node.m_value->m_res_type = mv$(newty); inner_ty = &node.m_value->m_res_type; - + this->context.equate_types_coerce(sp, exp_ty, node.m_value); } else { inner_ty = &exp_ty; } - + // Insert a trait bound on the result type to impl `Placer/Boxer` switch( node_ty ) { @@ -2354,10 +2354,10 @@ namespace { this->context.equate_types_assoc(sp, {}, ::HIR::SimplePath("core", { "ops", "Placer" }), ::make_vec1(data_ty.clone()), *inner_ty, ""); break; } - + this->m_completed = true; } - + void visit(::HIR::ExprNode_TupleVariant& node) override { no_revisit(node); } @@ -2368,23 +2368,23 @@ namespace { //const auto& sp = node.span(); const auto& ty_o = this->context.get_type(node.m_value->m_res_type); TRACE_FUNCTION_F("CallValue: ty=" << ty_o); - + // - 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); } - + if( ty_o.m_data.is_Infer() ) { // - Don't even bother return ; } - + const auto& lang_FnOnce = this->context.m_crate.get_lang_item_path(node.span(), "fn_once"); const auto& lang_FnMut = this->context.m_crate.get_lang_item_path(node.span(), "fn_mut"); const auto& lang_Fn = this->context.m_crate.get_lang_item_path(node.span(), "fn"); - - + + // 1. Create a param set with a single tuple (of all argument types) ::HIR::PathParams trait_pp; { @@ -2394,37 +2394,37 @@ namespace { } trait_pp.m_types.push_back( ::HIR::TypeRef( mv$(arg_types) ) ); } - + unsigned int deref_count = 0; ::HIR::TypeRef tmp_type; // for autoderef const auto* ty_p = &ty_o; - + bool keep_looping = false; do // } while( keep_looping ); { // Reset at the start of each loop keep_looping = false; - + const auto& ty = *ty_p; DEBUG("- ty = " << ty); TU_MATCH_DEF(decltype(ty.m_data), (ty.m_data), (e), ( ::HIR::TypeRef fcn_args_tup; ::HIR::TypeRef fcn_ret; - + // TODO: Use `find_trait_impls` instead of two different calls // - This will get the TraitObject impl search too - + // Locate an impl of FnOnce (exists for all other Fn* traits) unsigned int count = 0; this->context.m_resolve.find_trait_impls(node.span(), lang_FnOnce, trait_pp, ty, [&](auto impl, auto cmp) { count ++; - + auto tup = impl.get_trait_ty_param(0); if( !tup.m_data.is_Tuple() ) ERROR(node.span(), E0000, "FnOnce expects a tuple argument, got " << tup); fcn_args_tup = mv$(tup); - + fcn_ret = impl.get_type("Output"); DEBUG("[visit:_CallValue] fcn_args_tup=" << fcn_args_tup << ", fcn_ret=" << fcn_ret); return cmp == ::HIR::Compare::Equal; @@ -2435,7 +2435,7 @@ namespace { } if( count == 1 ) { - + // 3. Locate the most permissive implemented Fn* trait (Fn first, then FnMut, then assume just FnOnce) // NOTE: Borrowing is added by the expansion to CallPath if( this->context.m_resolve.find_trait_impls(node.span(), lang_Fn, trait_pp, ty, [&](auto impl, auto cmp) { @@ -2448,7 +2448,7 @@ namespace { { DEBUG("-- Using Fn"); node.m_trait_used = ::HIR::ExprNode_CallValue::TraitUsed::Fn; - + this->context.equate_types_assoc(node.span(), node.m_res_type, lang_Fn, ::make_vec1( fcn_args_tup.clone() ), ty, "Output"); } else if( this->context.m_resolve.find_trait_impls(node.span(), lang_FnMut, trait_pp, ty, [&](auto impl, auto cmp) { @@ -2461,17 +2461,17 @@ namespace { { DEBUG("-- Using FnMut"); node.m_trait_used = ::HIR::ExprNode_CallValue::TraitUsed::FnMut; - + this->context.equate_types_assoc(node.span(), node.m_res_type, lang_FnMut, ::make_vec1( fcn_args_tup.clone() ), ty, "Output"); } else { DEBUG("-- Using FnOnce (default)"); node.m_trait_used = ::HIR::ExprNode_CallValue::TraitUsed::FnOnce; - + this->context.equate_types_assoc(node.span(), node.m_res_type, lang_FnOnce, ::make_vec1( fcn_args_tup.clone() ), ty, "Output"); } - + // If the return type wasn't found in the impls, emit it as a UFCS if( fcn_ret == ::HIR::TypeRef() ) { @@ -2498,7 +2498,7 @@ namespace { bool found = this->context.m_resolve.find_trait_impls_crate(node.span(), lang_FnOnce, trait_pp, ty, [&](auto impl, auto cmp) { if( cmp == ::HIR::Compare::Fuzzy ) TODO(node.span(), "Handle fuzzy match - " << impl); - + auto tup = impl.get_trait_ty_param(0); if( !tup.m_data.is_Tuple() ) ERROR(node.span(), E0000, "FnOnce expects a tuple argument, got " << tup); @@ -2523,11 +2523,11 @@ namespace { keep_looping = true; continue ; } - + // Didn't find anything. Error? ERROR(node.span(), E0000, "Unable to find an implementation of Fn*"<<trait_pp<<" for " << this->context.m_ivars.fmt_type(ty)); } - + node.m_arg_types = mv$( fcn_args_tup.m_data.as_Tuple() ); node.m_arg_types.push_back( mv$(fcn_ret) ); ), @@ -2549,7 +2549,7 @@ namespace { ) ) } while( keep_looping ); - + if( deref_count > 0 ) { ty_p = &ty_o; @@ -2560,7 +2560,7 @@ namespace { node.m_value = this->context.create_autoderef( mv$(node.m_value), ty_p->clone() ); } } - + assert( node.m_arg_types.size() == node.m_args.size() + 1 ); for(unsigned int i = 0; i < node.m_args.size(); i ++) { @@ -2571,16 +2571,16 @@ namespace { } void visit(::HIR::ExprNode_CallMethod& node) override { 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); - + // 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); for( const auto& arg_node : node.m_args ) { this->context.equate_types_to_shadow(node.span(), arg_node->m_res_type); } - + // Using autoderef, locate this method on the type ::HIR::Path fcn_path { ::HIR::SimplePath() }; TraitResolution::AutoderefBorrow ad_borrow; @@ -2588,7 +2588,7 @@ namespace { if( deref_count != ~0u ) { DEBUG("- deref_count = " << deref_count << ", fcn_path = " << fcn_path); - + node.m_method_path = mv$(fcn_path); // NOTE: Steals the params from the node TU_MATCH(::HIR::Path::Data, (node.m_method_path.m_data), (e), @@ -2610,15 +2610,15 @@ namespace { return ; } DEBUG("> m_method_path = " << node.m_method_path); - + assert( node.m_cache.m_arg_types.size() >= 1); - + if( node.m_args.size()+1 != node.m_cache.m_arg_types.size() - 1 ) { ERROR(node.span(), E0000, "Incorrect number of arguments to " << node.m_method_path << " - exp " << node.m_cache.m_arg_types.size()-2 << " got " << node.m_args.size()); } DEBUG("- fcn_path=" << node.m_method_path); - + // --- Check and equate self/arguments/return DEBUG("node.m_cache.m_arg_types = " << node.m_cache.m_arg_types); // NOTE: `Self` is equated after autoderef and autoref @@ -2630,7 +2630,7 @@ namespace { } DEBUG("> Ret : " << node.m_cache.m_arg_types.back()); this->context.equate_types(sp, node.m_res_type, node.m_cache.m_arg_types.back()); - + // Add derefs if( deref_count > 0 ) { @@ -2646,11 +2646,11 @@ namespace { cur_ty = this->context.m_resolve.autoderef(span, *cur_ty, tmp_ty); assert(cur_ty); auto ty = cur_ty->clone(); - + node.m_value = this->context.create_autoderef( mv$(node.m_value), mv$(ty) ); } } - + // Autoref if( ad_borrow != TraitResolution::AutoderefBorrow::None ) { @@ -2662,7 +2662,7 @@ namespace { case TraitResolution::AutoderefBorrow::Unique: bt = ::HIR::BorrowType::Unique; break; case TraitResolution::AutoderefBorrow::Owned : bt = ::HIR::BorrowType::Owned ; break; } - + auto ty = ::HIR::TypeRef::new_borrow(bt, node.m_value->m_res_type.clone()); DEBUG("- Ref (cmd) " << &*node.m_value << " -> " << ty); auto span = node.m_value->span(); @@ -2672,7 +2672,7 @@ namespace { { auto receiver_class = node.m_cache.m_fcn->m_receiver; ::HIR::BorrowType bt; - + auto& node_ptr = node.m_value; auto span = node_ptr->span(); switch(receiver_class) @@ -2697,7 +2697,7 @@ namespace { ASSERT_BUG(sp, deref_ptr != nullptr, "Calling Box receiver method but no deref happened"); node_ptr = mv$(deref_ptr->m_value); DEBUG("- Undo deref " << deref_ptr << " -> " << node_ptr->m_res_type); - + // Triple-check that the input to the above Deref was a Box (lang="owned_box") const auto& box_ty = this->context.get_type(node_ptr->m_res_type); TU_IFLET(::HIR::TypeRef::Data, box_ty.m_data, Path, e, @@ -2718,10 +2718,10 @@ namespace { } break; } } - + // Equate the type for `self` (to ensure that Self's type params infer correctly) this->context.equate_types(sp, node.m_cache.m_arg_types[0], node.m_value->m_res_type); - + this->m_completed = true; } } @@ -2738,7 +2738,7 @@ namespace { ::HIR::TypeRef tmp_type; // Temporary type used for handling Deref const auto* current_ty = &node.m_value->m_res_type; ::std::vector< ::HIR::TypeRef> deref_res_types; - + do { const auto& ty = this->context.m_ivars.get_type(*current_ty); if( ty.m_data.is_Infer() ) { @@ -2753,18 +2753,18 @@ namespace { this->context.equate_types(node.span(), node.m_res_type, out_type); break; } - + deref_count += 1; current_ty = this->context.m_resolve.autoderef(node.span(), ty, tmp_type); if( current_ty ) deref_res_types.push_back( current_ty->clone() ); } while(current_ty); - + if( !current_ty ) { ERROR(node.span(), E0000, "Couldn't find the field " << field_name << " in " << this->context.m_ivars.fmt_type(node.m_value->m_res_type)); } - + assert( deref_count == deref_res_types.size() ); for(unsigned int i = 0; i < deref_res_types.size(); i ++ ) { @@ -2776,7 +2776,7 @@ namespace { node.m_value = NEWNODE(mv$(ty), node.span(), _Deref, mv$(node.m_value)); context.m_ivars.get_type(node.m_value->m_res_type); } - + m_completed = true; } @@ -2792,7 +2792,7 @@ namespace { void visit(::HIR::ExprNode_Variable& node) override { no_revisit(node); } - + void visit(::HIR::ExprNode_StructLiteral& node) override { no_revisit(node); } @@ -2808,7 +2808,7 @@ namespace { void visit(::HIR::ExprNode_ArraySized& node) override { no_revisit(node); } - + void visit(::HIR::ExprNode_Closure& node) override { no_revisit(node); } @@ -2817,7 +2817,7 @@ namespace { BUG(node.span(), "Node revisit unexpected - " << typeid(node).name()); } }; - + // ----------------------------------------------------------------------- // Post-inferrence visitor // @@ -2839,16 +2839,16 @@ namespace { { auto& node = *node_ptr; const char* node_ty = typeid(node).name(); - + TRACE_FUNCTION_FR(&node << " " << &node << " " << node_ty << " : " << node.m_res_type, node_ty); this->check_type_resolved_top(node.span(), node.m_res_type); DEBUG(node_ty << " : = " << node.m_res_type); - + node_ptr->visit(*this); - + for( auto& ty : node_ptr.m_bindings ) this->check_type_resolved_top(node.span(), ty); - + for( auto& ty : node_ptr.m_erased_types ) this->check_type_resolved_top(node.span(), ty); } @@ -2860,7 +2860,7 @@ namespace { DEBUG(node_ty << " : = " << node.m_res_type); ::HIR::ExprVisitorDef::visit_node_ptr(node_ptr); } - + void visit_pattern(const Span& sp, ::HIR::Pattern& pat) override { TU_MATCH_DEF( ::HIR::Pattern::Data, (pat.m_data), (e), ( @@ -2899,7 +2899,7 @@ namespace { ) ::HIR::ExprVisitorDef::visit_pattern(sp, pat); } - + void visit(::HIR::ExprNode_Let& node) override { this->check_type_resolved_top(node.span(), node.m_type); ::HIR::ExprVisitorDef::visit(node); @@ -2910,7 +2910,7 @@ namespace { this->check_type_resolved_top(node.span(), node.m_return); ::HIR::ExprVisitorDef::visit(node); } - + void visit_callcache(const Span&sp, ::HIR::ExprCallCache& cache) { for(auto& ty : cache.m_arg_types) @@ -2918,13 +2918,13 @@ namespace { } void visit(::HIR::ExprNode_CallPath& node) override { this->visit_callcache(node.span(), node.m_cache); - + this->check_type_resolved_path(node.span(), node.m_path); ::HIR::ExprVisitorDef::visit(node); } void visit(::HIR::ExprNode_CallMethod& node) override { this->visit_callcache(node.span(), node.m_cache); - + this->check_type_resolved_path(node.span(), node.m_method_path); ::HIR::ExprVisitorDef::visit(node); } @@ -2933,7 +2933,7 @@ namespace { this->check_type_resolved_top(node.span(), ty); ::HIR::ExprVisitorDef::visit(node); } - + void visit(::HIR::ExprNode_PathValue& node) override { this->check_type_resolved_path(node.span(), node.m_path); } @@ -2947,7 +2947,7 @@ namespace { this->check_type_resolved_top(node.span(), ty); } } - + ::HIR::ExprVisitorDef::visit(node); } void visit(::HIR::ExprNode_TupleVariant& node) override { @@ -2957,10 +2957,10 @@ namespace { this->check_type_resolved_top(node.span(), ty); } } - + ::HIR::ExprVisitorDef::visit(node); } - + void visit(::HIR::ExprNode_Literal& node) override { TU_MATCH(::HIR::ExprNode_Literal::Data, (node.m_data), (e), (Integer, @@ -3109,15 +3109,15 @@ void Context::dump() const { } void Context::equate_types(const Span& sp, const ::HIR::TypeRef& li, const ::HIR::TypeRef& ri) { - + if( li == ri || this->m_ivars.get_type(li) == this->m_ivars.get_type(ri) ) { DEBUG(li << " == " << ri); return ; } - + // Instantly apply equality TRACE_FUNCTION_F(li << " == " << ri); - + visit_ty_with(ri, [&](const auto& ty) { if( ty.m_data.is_Generic() && ty.m_data.as_Generic().binding >> 8 == 2 ) { BUG(sp, "Type contained an impl placeholder parameter - " << ri); @@ -3135,16 +3135,16 @@ void Context::equate_types(const Span& sp, const ::HIR::TypeRef& li, const ::HIR ::HIR::TypeRef r_tmp; 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); - + equate_types_inner(sp, l_t, r_t); } void Context::equate_types_inner(const Span& sp, const ::HIR::TypeRef& li, const ::HIR::TypeRef& ri) { - + if( li == ri || this->m_ivars.get_type(li) == this->m_ivars.get_type(ri) ) { return ; } - + // Check if the type contains a replacable associated type ::HIR::TypeRef l_tmp; ::HIR::TypeRef r_tmp; @@ -3153,7 +3153,7 @@ void Context::equate_types_inner(const Span& sp, const ::HIR::TypeRef& li, const if( l_t == r_t ) { return ; } - + // If either side is still a UfcsUnkonw after `expand_associated_types`, then emit an assoc bound instead of damaging ivars TU_IFLET(::HIR::TypeRef::Data, r_t.m_data, Path, r_e, TU_IFLET(::HIR::Path::Data, r_e.path.m_data, UfcsKnown, rpe, @@ -3171,7 +3171,7 @@ void Context::equate_types_inner(const Span& sp, const ::HIR::TypeRef& li, const } ) ) - + DEBUG("- l_t = " << l_t << ", r_t = " << r_t); TU_IFLET(::HIR::TypeRef::Data, r_t.m_data, Infer, r_e, TU_IFLET(::HIR::TypeRef::Data, l_t.m_data, Infer, l_e, @@ -3199,7 +3199,7 @@ void Context::equate_types_inner(const Span& sp, const ::HIR::TypeRef& li, const this->equate_types_inner(sp, l.m_types[i], r.m_types[i]); } }; - + // If either side is !, return early // TODO: Should ! end up in an ivar? #if 1 @@ -3225,7 +3225,7 @@ void Context::equate_types_inner(const Span& sp, const ::HIR::TypeRef& li, const return ; } #endif - + if( l_t.m_data.tag() != r_t.m_data.tag() ) { ERROR(sp, E0000, "Type mismatch between " << this->m_ivars.fmt_type(l_t) << " and " << this->m_ivars.fmt_type(r_t)); } @@ -3392,14 +3392,14 @@ void Context::add_binding_inner(const Span& sp, const ::HIR::PatternBinding& pb, void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::TypeRef& type) { TRACE_FUNCTION_F("pat = " << pat << ", type = " << type); - + if( pat.m_binding.is_valid() ) { this->add_binding_inner(sp, pat.m_binding, type.clone()); - + // 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), @@ -3429,8 +3429,8 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type ) } }; - - // + + // TU_MATCH(::HIR::Pattern::Data, (pat.m_data), (e), (Any, // Just leave it, the pattern says nothing @@ -3482,16 +3482,16 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type (Tuple, const auto& ty = this->get_type(type); TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Tuple, te, - - if( e.sub_patterns.size() != te.size() ) { + + 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); } - + for(unsigned int i = 0; i < e.sub_patterns.size(); i ++ ) this->add_binding(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() ); @@ -3505,7 +3505,7 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Tuple, te, // - Should have been checked in AST resolve ASSERT_BUG(sp, e.leading.size() + e.trailing.size() <= te.size(), "Invalid field count for split tuple pattern"); - + unsigned int tup_idx = 0; for(auto& subpat : e.leading) { this->add_binding(sp, subpat, te[tup_idx++]); @@ -3514,7 +3514,7 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type for(auto& subpat : e.trailing) { this->add_binding(sp, subpat, te[tup_idx++]); } - + // TODO: Should this replace the pattern with a non-split? // - Changing the address of the pattern means that the below revisit could fail. e.total_size = te.size(); @@ -3523,7 +3523,7 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type if( !ty.m_data.is_Infer() ) { ERROR(sp, E0000, "Tuple pattern on non-tuple"); } - + ::std::vector<::HIR::TypeRef> leading_tys; leading_tys.reserve(e.leading.size()); for(auto& subpat : e.leading) { @@ -3535,7 +3535,7 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type trailing_tys.push_back( this->m_ivars.new_ivar_tr() ); this->add_binding(sp, subpat, trailing_tys.back()); } - + struct SplitTuplePatRevisit: public Revisitor { @@ -3544,13 +3544,13 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type ::std::vector<::HIR::TypeRef> m_leading_tys; ::std::vector<::HIR::TypeRef> m_trailing_tys; unsigned int& m_pat_total_size; - + SplitTuplePatRevisit(Span sp, ::HIR::TypeRef outer, ::std::vector<::HIR::TypeRef> leading, ::std::vector<::HIR::TypeRef> trailing, unsigned int& pat_total_size): sp(mv$(sp)), m_outer_ty(mv$(outer)), m_leading_tys( mv$(leading) ), m_trailing_tys( mv$(trailing) ), m_pat_total_size(pat_total_size) {} - + void fmt(::std::ostream& os) const override { os << "SplitTuplePatRevisit { " << m_outer_ty << " = (" << m_leading_tys << ", ..., " << m_trailing_tys << ") }"; } @@ -3575,7 +3575,7 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type } } }; - + // Register a revisit and wait until the tuple is known - then bind through. this->add_revisit_adv( box$(( SplitTuplePatRevisit { sp, ty.clone(), mv$(leading_tys), mv$(trailing_tys), e.total_size } )) ); } @@ -3594,7 +3594,7 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type auto inner = this->m_ivars.new_ivar_tr(); for(auto& sub : e.sub_patterns) this->add_binding(sp, sub, inner); - + struct SlicePatRevisit: public Revisitor { @@ -3602,11 +3602,11 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type ::HIR::TypeRef inner; ::HIR::TypeRef type; unsigned int size; - + SlicePatRevisit(Span sp, ::HIR::TypeRef inner, ::HIR::TypeRef type, unsigned int size): sp(mv$(sp)), inner(mv$(inner)), type(mv$(type)), size(size) {} - + void fmt(::std::ostream& os) const override { os << "SlicePatRevisit { " << inner << ", " << type << ", " << size; } bool revisit(Context& context) override { const auto& ty = context.get_type(type); @@ -3653,7 +3653,7 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type ERROR(sp, E0000, "Slice pattern on an array smaller than the pattern"); } unsigned extra_len = te.size_val - min_len; - + if( e.extra_bind.is_valid() ) { this->add_binding_inner( sp, e.extra_bind, ::HIR::TypeRef::new_array(inner.clone(), extra_len) ); } @@ -3665,7 +3665,7 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type var_ty = this->m_ivars.new_ivar_tr(); this->add_binding_inner( sp, e.extra_bind, var_ty.clone() ); } - + struct SplitSlicePatRevisit: public Revisitor { @@ -3677,17 +3677,17 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type // Binding type (if not default value) ::HIR::TypeRef var_ty; unsigned int min_size; - + SplitSlicePatRevisit(Span sp, ::HIR::TypeRef inner, ::HIR::TypeRef type, ::HIR::TypeRef var_ty, unsigned int size): sp(mv$(sp)), inner(mv$(inner)), type(mv$(type)), var_ty(mv$(var_ty)), min_size(size) {} - + void fmt(::std::ostream& os) const override { os << "SplitSlice inner=" << inner << ", outer=" << type << ", binding="<<var_ty<<", " << min_size; } bool revisit(Context& context) override { const auto& ty = context.get_type(this->type); if( ty.m_data.is_Infer() ) return false; - + // Slice - Equate inners TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Slice, te, context.equate_types(this->sp, this->inner, *te.inner); @@ -3702,7 +3702,7 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type ERROR(sp, E0000, "Slice pattern on an array smaller than the pattern"); } unsigned extra_len = te.size_val - this->min_size; - + if( this->var_ty != ::HIR::TypeRef() ) { context.equate_types(this->sp, this->var_ty, ::HIR::TypeRef::new_array(this->inner.clone(), extra_len) ); } @@ -3725,7 +3725,7 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type for(auto& sub : e.trailing) this->add_binding( sp, sub, inner ); ), - + // - Enums/Structs (StructValue, this->add_ivars_params( e.path.m_params ); @@ -3739,11 +3739,11 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type // - assert check from earlier pass assert( str.m_data.is_Tuple() ); const auto& sd = str.m_data.as_Tuple(); - + const auto& params = e.path.m_params; assert(e.binding); this->equate_types( sp, type, ::HIR::TypeRef::new_path(e.path.clone(), ::HIR::TypeRef::TypePathBinding(e.binding)) ); - + for( unsigned int i = 0; i < e.sub_patterns.size(); i ++ ) { /*const*/ auto& sub_pat = e.sub_patterns[i]; @@ -3760,14 +3760,14 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type (Struct, 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)) ); - + assert(e.binding); const auto& str = *e.binding; // - assert check from earlier pass assert( str.m_data.is_Named() ); const auto& sd = str.m_data.as_Named(); const auto& params = e.path.m_params; - + 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(); @@ -3810,13 +3810,13 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type const auto& var = enm.m_variants[e.binding_idx].second; assert(var.is_Tuple()); const auto& tup_var = var.as_Tuple(); - + const auto& params = e.path.m_params; - + ASSERT_BUG(sp, e.sub_patterns.size() == tup_var.size(), "Enum pattern with an incorrect number of fields - " << e.path << " - expected " << tup_var.size() << ", got " << e.sub_patterns.size() ); - + for( unsigned int i = 0; i < e.sub_patterns.size(); i ++ ) { if( monomorphise_type_needed(tup_var[i].ent) ) { @@ -3843,7 +3843,7 @@ void Context::add_binding(const Span& sp, ::HIR::Pattern& pat, const ::HIR::Type assert(var.is_Struct()); const auto& tup_var = var.as_Struct(); const auto& params = e.path.m_params; - + 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(); @@ -3916,7 +3916,7 @@ void Context::equate_types_assoc(const Span& sp, const ::HIR::TypeRef& l, const this->link_assoc.push_back(Associated { sp, l.clone(), - + trait.clone(), mv$(pp), impl_ty.clone(), @@ -3940,7 +3940,7 @@ void Context::possible_equate_type(unsigned int ivar_index, const ::HIR::TypeRef ty_l.m_data.as_Infer().index = ivar_index; assert( m_ivars.get_type(ty_l).m_data.is_Infer() ); } - + if( ivar_index >= possible_ivar_vals.size() ) { possible_ivar_vals.resize( ivar_index + 1 ); } @@ -3958,7 +3958,7 @@ void Context::possible_equate_type_disable(unsigned int ivar_index, bool is_to) ty_l.m_data.as_Infer().index = ivar_index; assert( m_ivars.get_type(ty_l).m_data.is_Infer() ); } - + if( ivar_index >= possible_ivar_vals.size() ) { possible_ivar_vals.resize( ivar_index + 1 ); } @@ -4002,7 +4002,7 @@ const ::HIR::TypeRef& Context::get_var(const Span& sp, unsigned int idx) const { if( get_type(ty_src).m_data.is_Array() ) { ASSERT_BUG(span, ty_dst.m_data.is_Slice(), "Array should only ever autoderef to Slice"); - + // HACK: Emit an invalid _Unsize op that is fixed once usage type is known. auto ty_dst_c = ty_dst.clone(); val_node = NEWNODE( mv$(ty_dst), span, _Unsize, mv$(val_node), mv$(ty_dst_c) ); @@ -4012,7 +4012,7 @@ const ::HIR::TypeRef& Context::get_var(const Span& sp, unsigned int idx) const { val_node = NEWNODE( mv$(ty_dst), span, _Deref, mv$(val_node) ); DEBUG("- Deref " << &*val_node << " -> " << val_node->m_res_type); } - + return val_node; } @@ -4024,7 +4024,7 @@ void fix_param_count_(const Span& sp, Context& context, const ::HIR::TypeRef& se // Nothing to do, all good return ; } - + if( params.m_types.size() > param_defs.m_types.size() ) { ERROR(sp, E0000, "Too many type parameters passed to " << path); } @@ -4073,7 +4073,7 @@ namespace { void add_coerce_borrow(Context& context, ::HIR::ExprNodeP& node_ptr, const ::HIR::TypeRef& des_borrow_inner, ::std::function<void(::HIR::ExprNodeP& n)> cb) { const auto& src_type = context.m_ivars.get_type(node_ptr->m_res_type); - + // Since this function operates on destructured &-ptrs, the dereferences have to be added behind a borrow ::HIR::ExprNodeP* node_ptr_ptr = nullptr; // - If the pointed node is a borrow operation, add the dereferences within its value @@ -4086,14 +4086,14 @@ namespace { auto span = node_ptr->span(); const auto& src_inner_ty = *src_type.m_data.as_Borrow().inner; auto borrow_type = src_type.m_data.as_Borrow().type; - + auto inner_ty_ref = ::HIR::TypeRef::new_borrow(borrow_type, des_borrow_inner.clone()); - + // 1. Dereference (resulting in the dereferenced input type) node_ptr = NEWNODE(src_inner_ty.clone(), span, _Deref, mv$(node_ptr)); // 2. Borrow (resulting in the referenced output type) node_ptr = NEWNODE(mv$(inner_ty_ref), span, _Borrow, borrow_type, mv$(node_ptr)); - + // - Set node pointer reference to point into the new borrow op node_ptr_ptr = &dynamic_cast< ::HIR::ExprNode_Borrow&>(*node_ptr).m_value; } @@ -4102,16 +4102,16 @@ namespace { // Set the result of the borrow operation to the output type node_ptr->m_res_type = ::HIR::TypeRef::new_borrow(borrow_type, des_borrow_inner.clone()); } - + cb(*node_ptr_ptr); - + context.m_ivars.mark_change(); } - + bool check_coerce_borrow(Context& context, ::HIR::BorrowType bt, const ::HIR::TypeRef& inner_l, const ::HIR::TypeRef& inner_r, ::HIR::ExprNodeP& node_ptr) { const auto& sp = node_ptr->span(); - + const auto& ty_dst = context.m_ivars.get_type(inner_l); const auto& ty_src = context.m_ivars.get_type(inner_r); @@ -4119,14 +4119,14 @@ namespace { if( context.m_ivars.types_equal(ty_dst, ty_src) ) { return true; } - + // If either side (or both) are ivars, then coercion can't be known yet - but they could be equal // TODO: Fix and deduplicate the following code for InferClass::Diverge if( ty_src.m_data.is_Infer() && ty_dst.m_data.is_Infer() ) { const auto& r_e = ty_src.m_data.as_Infer(); const auto& l_e = ty_dst.m_data.as_Infer(); - + // TODO: Commented out - &-ptrs can infer to trait objects, and &-ptrs can infer from deref coercion //if( r_e.ty_class != ::HIR::InferClass::None ) { // context.equate_types(sp, ty_dst, ty_src); @@ -4141,11 +4141,11 @@ namespace { DEBUG("- Infer, add possibility"); return false; } - + // If the source is '_', we can't know yet TU_IFLET(::HIR::TypeRef::Data, ty_src.m_data, Infer, r_e, // TODO: If the source is a literal, and the destination isn't a TraitObject, equate. - + // - Except if it's known to be a primitive //if( r_e.ty_class != ::HIR::InferClass::None ) { // context.equate_types(sp, ty_dst, ty_src); @@ -4155,9 +4155,9 @@ namespace { DEBUG("- Infer, add possibility"); return false; ) - + TU_IFLET(::HIR::TypeRef::Data, ty_dst.m_data, Infer, l_e, - + // If the destination is known to be a primitive (integer or float) and the source is a primitive // - Equate. // - NOTE: The source can't be something that could deref coerce into the literal. @@ -4169,24 +4169,24 @@ namespace { context.equate_types(sp, ty_dst, ty_src); return true; } - + context.possible_equate_type_unsize_from(l_e.index, ty_src); DEBUG("- Infer, add possibility"); return false; ) - + // Fast hack for slices (avoids going via the Deref impl search) if( ty_dst.m_data.is_Slice() && !ty_src.m_data.is_Slice() ) { const auto& dst_slice = ty_dst.m_data.as_Slice(); TU_IFLET(::HIR::TypeRef::Data, ty_src.m_data, Array, src_array, context.equate_types(sp, *dst_slice.inner, *src_array.inner); - + auto ty_dst_b = ::HIR::TypeRef::new_borrow(bt, ty_dst.clone()); auto ty_dst_b2 = ty_dst_b.clone(); auto span = node_ptr->span(); node_ptr = NEWNODE( mv$(ty_dst_b), span, _Unsize, mv$(node_ptr), mv$(ty_dst_b2) ); - + context.m_ivars.mark_change(); return true; ) @@ -4195,7 +4195,7 @@ namespace { // Apply deref coercions } } - + // Deref coercions // - If right can be dereferenced to left { @@ -4206,17 +4206,17 @@ namespace { while( (out_ty = context.m_resolve.autoderef(sp, *out_ty, tmp_ty)) ) { count += 1; - + if( out_ty->m_data.is_Infer() && out_ty->m_data.as_Infer().ty_class == ::HIR::InferClass::None ) { // Hit a _, so can't keep going break; } - + types.push_back( out_ty->clone() ); - + if( context.m_ivars.types_equal(ty_dst, *out_ty) == false ) { // Check equivalence - + if( ty_dst.m_data.tag() == out_ty->m_data.tag() ) { TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty_dst.m_data, out_ty->m_data), (d_e, s_e), ( @@ -4238,7 +4238,7 @@ namespace { continue ; } } - + add_coerce_borrow(context, node_ptr, types.back(), [&](auto& node_ptr) { // node_ptr = node that yeilds ty_src assert( count == types.size() ); @@ -4254,12 +4254,12 @@ namespace { context.m_ivars.get_type(node_ptr->m_res_type); } }); - + return true; } // Either ran out of deref, or hit a _ } - + // Desination coercions (Trait objects) TU_MATCH_DEF(::HIR::TypeRef::Data, (ty_dst.m_data), (e), ( @@ -4290,12 +4290,12 @@ namespace { DEBUG("Defer as there are multiple applicable impls"); return false; } - + if( best_impl.has_magic_params() ) { DEBUG("Defer as there were magic parameters"); return false; } - + // TODO: Get a better way of equating these that doesn't require getting copies of the impl's types context.equate_types(sp, ty_src, best_impl.get_impl_type()); auto args = best_impl.get_trait_params(); @@ -4305,7 +4305,7 @@ namespace { context.equate_types(sp, trait.m_params.m_types[i], args.m_types[i]); } } - + for(const auto& marker : e.m_markers) { bool found = context.m_resolve.find_trait_impls(sp, marker.m_path, marker.m_params, ty_src, [&](auto impl, auto cmp) { @@ -4321,17 +4321,17 @@ namespace { return false; } } - + // Add _Unsize operator auto ty_dst_b = ::HIR::TypeRef::new_borrow(bt, ty_dst.clone()); auto ty_dst_b2 = ty_dst_b.clone(); auto span = node_ptr->span(); node_ptr = NEWNODE( mv$(ty_dst_b), span, _Unsize, mv$(node_ptr), mv$(ty_dst_b2) ); - + return true; ) ) - + TU_MATCH_DEF(::HIR::TypeRef::Data, (ty_src.m_data), (e), ( ), @@ -4346,7 +4346,7 @@ namespace { // return true; ) ) - + // Search for Unsize // - If `right`: ::core::marker::Unsize<`left`> { @@ -4363,11 +4363,11 @@ namespace { auto ty_dst_b2 = ty_dst_b.clone(); auto span = node_ptr->span(); node_ptr = NEWNODE( mv$(ty_dst_b), span, _Unsize, mv$(node_ptr), mv$(ty_dst_b2) ); - + return true; } } - + if( ty_dst.m_data.is_Path() && ty_dst.m_data.as_Path().binding.is_Unbound() ) { } @@ -4376,7 +4376,7 @@ namespace { context.equate_types(sp, ty_dst, ty_src); return true; } - + // Keep trying // TODO: If both types are fully known, then error. return false; @@ -4388,14 +4388,14 @@ namespace { const auto& ty_dst = context.m_ivars.get_type(v.left_ty); const auto& ty_src = context.m_ivars.get_type(node_ptr->m_res_type); TRACE_FUNCTION_F(v << " - " << ty_dst << " := " << ty_src); - + if( context.m_ivars.types_equal(ty_dst, ty_src) ) { DEBUG("Equal"); return true; } - + const auto& lang_CoerceUnsized = context.m_crate.get_lang_item_path(sp, "coerce_unsized"); - + struct H { // Check if a path type has or could have a CoerceUnsized impl static bool type_has_coerce_path(const ::HIR::TypeRef& ty) { @@ -4421,17 +4421,17 @@ namespace { return false; } }; - + // CoerceUnsized trait // - Only valid for generic or path destination types if( ty_dst.m_data.is_Generic() || H::type_has_coerce_path(ty_dst) ) { // `CoerceUnsized<U> for T` means `T -> U` - + ::HIR::PathParams pp { ty_dst.clone() }; - + // PROBLEM: This can false-negative leading to the types being falsely equated. - + bool fuzzy_match = false; ImplRef best_impl; bool found = context.m_resolve.find_trait_impls(sp, lang_CoerceUnsized, pp, ty_src, [&](auto impl, auto cmp) { @@ -4453,7 +4453,7 @@ namespace { if( found ) { DEBUG("- NEWNODE _Unsize " << &*node_ptr << " -> " << ty_dst); - + auto span = node_ptr->span(); node_ptr = NEWNODE( ty_dst.clone(), span, _Unsize, mv$(node_ptr), ty_dst.clone() ); return true; @@ -4469,7 +4469,7 @@ namespace { } DEBUG("- No CoerceUnsized impl found"); } - + // 1. Check that the source type can coerce TU_MATCH( ::HIR::TypeRef::Data, (ty_src.m_data), (e), (Infer, @@ -4479,20 +4479,20 @@ namespace { context.equate_types(sp, ty_dst, ty_src); return true; } - + TU_IFLET(::HIR::TypeRef::Data, ty_dst.m_data, Infer, e2, - + if( e2.ty_class != ::HIR::InferClass::None ) { context.equate_types(sp, ty_dst, ty_src); return true; } - + DEBUG("Both infer, add possibilities"); context.possible_equate_type_coerce_to(e.index, ty_dst); context.possible_equate_type_coerce_from(e2.index, ty_src); return false; ) - + context.possible_equate_type_coerce_to(e.index, ty_dst); DEBUG("Source infer, add possibility and continue"); ), @@ -4560,7 +4560,7 @@ namespace { return true; ) ) - + // 2. Check target type is a valid coercion // - Otherwise - Force equality TU_MATCH( ::HIR::TypeRef::Data, (ty_dst.m_data), (l_e), @@ -4631,7 +4631,7 @@ namespace { // TODO: &move reboorrowing rules? //if( l_e.type < r_e.type ) { if( l_e.type == ::HIR::BorrowType::Shared && r_e.type == ::HIR::BorrowType::Unique ) { - + // Add cast down auto span = node_ptr->span(); // > Goes from `ty_src` -> `*ty_src` -> `&`l_e.type` `&ty_src` @@ -4646,15 +4646,15 @@ namespace { DEBUG("- Borrow -> " << new_type); node_ptr = NEWNODE( mv$(new_type) , span, _Borrow, dst_bt, mv$(node_ptr) ); context.m_ivars.get_type(node_ptr->m_res_type); - + context.m_ivars.mark_change(); - + // Continue on with coercion (now that node_ptr is updated) } else if( l_e.type != r_e.type ) { ERROR(sp, E0000, "Type mismatch between " << ty_dst << " and " << ty_src << " - Borrow classes differ"); } - + // - Check for coercions return check_coerce_borrow(context, l_e.type, *l_e.inner, *r_e.inner, node_ptr); ) @@ -4665,7 +4665,7 @@ namespace { context.equate_types(sp, ty_dst, ty_src); BUG(sp, "Type error expected " << ty_dst << " == " << ty_src); } - + context.possible_equate_type_coerce_to(r_e.index, ty_dst); DEBUG("- Infer, add possibility"); return false; @@ -4687,14 +4687,14 @@ namespace { if( !(l_e.type <= s_e.type) ) { ERROR(sp, E0000, "Type mismatch between " << ty_dst << " and " << ty_src << " - Mutability not compatible"); } - + // TODO: Can this can unsize as well as convert to raw? context.equate_types(sp, *l_e.inner, *s_e.inner); // Add downcast auto span = node_ptr->span(); node_ptr = ::HIR::ExprNodeP(new ::HIR::ExprNode_Cast( mv$(span), mv$(node_ptr), ty_dst.clone() )); node_ptr->m_res_type = ty_dst.clone(); - + context.m_ivars.mark_change(); return true; ) @@ -4702,17 +4702,17 @@ namespace { // If using `*mut T` where `*const T` is expected - add cast if( l_e.type == ::HIR::BorrowType::Shared && r_e.type == ::HIR::BorrowType::Unique ) { context.equate_types(sp, *l_e.inner, *r_e.inner); - + // Add cast down auto span = node_ptr->span(); node_ptr->m_res_type = ty_src.clone(); node_ptr = ::HIR::ExprNodeP(new ::HIR::ExprNode_Cast( mv$(span), mv$(node_ptr), ty_dst.clone() )); node_ptr->m_res_type = ty_dst.clone(); - + context.m_ivars.mark_change(); return true; } - + if( l_e.type != r_e.type ) { ERROR(sp, E0000, "Type mismatch between " << ty_dst << " and " << ty_src << " - Pointer mutability differs"); } @@ -4741,17 +4741,17 @@ namespace { TU_IFLET( ::HIR::TypeRef::Data, ty_src.m_data, Function, r_e, if(l_e.m_abi != r_e.m_abi && l_e.is_unsafe == true && r_e.is_unsafe == false ) { // LHS is unsafe, RHS is not - Insert a cast - + auto ty_dst_new = ty_src.clone(); ty_dst_new.m_data.as_Function().is_unsafe = true; context.equate_types(sp, ty_dst, ty_dst_new); - + // Add cast down auto span = node_ptr->span(); node_ptr->m_res_type = ty_src.clone(); node_ptr = ::HIR::ExprNodeP(new ::HIR::ExprNode_Cast( mv$(span), mv$(node_ptr), ty_dst_new.clone() )); node_ptr->m_res_type = mv$(ty_dst_new); - + context.m_ivars.mark_change(); return true; } @@ -4771,21 +4771,21 @@ namespace { return true; ) ) - + //TODO(sp, "Typecheck_Code_CS - Coercion " << context.m_ivars.fmt_type(ty) << " from " << context.m_ivars.fmt_type(node_ptr->m_res_type)); DEBUG("TODO - Coercion " << context.m_ivars.fmt_type(ty_dst) << " from " << context.m_ivars.fmt_type(node_ptr->m_res_type)); return false; } - + bool check_associated(Context& context, const Context::Associated& v) { const auto& sp = v.span; TRACE_FUNCTION_F(v); - + ::HIR::TypeRef possible_impl_ty; ::HIR::PathParams possible_params; ::HIR::TypeRef output_type; - + struct H { static bool type_is_num(const ::HIR::TypeRef& t) { TU_MATCH_DEF(::HIR::TypeRef::Data, (t.m_data), (e), @@ -4806,7 +4806,7 @@ namespace { ) } }; - + // MAGIC! Have special handling for operator overloads if( v.is_operator ) { if( v.params.m_types.size() == 0 ) @@ -4835,14 +4835,14 @@ namespace { BUG(sp, "Associated type rule with `is_operator` set but an incorrect parameter count"); } } - + // If the output type is present, prevent it from being guessed // - This generates an exact equation. if( v.left_ty != ::HIR::TypeRef() ) { context.equate_types_from_shadow(sp, v.left_ty); } - + // HACK! If the trait is `Unsize` then pretend `impl<T> Unsize<T> for T` exists to possibly propagate the type through // - Also applies to CoerceUnsized (which may not get its impl detected because actually `T: !Unsize<T>`) // - This is needed because `check_coerce` will emit coercions where they're not actually needed in some cases. @@ -4854,7 +4854,7 @@ namespace { ASSERT_BUG(sp, v.params.m_types.size() == 1, "Incorrect number of parameters for Unsize"); const auto& src_ty = context.get_type(v.impl_ty); const auto& dst_ty = context.get_type(v.params.m_types[0]); - + // - If the two types are equal (for unsizing purposes) then equate them and delete this rule if( context.m_ivars.types_equal( src_ty, dst_ty ) ) { // A type cannot unsize to itself, but CoerceUnsize code leads to these requirements when coercion points chain. @@ -4929,7 +4929,7 @@ namespace { DEBUG("Found at least one impl of CoerceUnsized, running expensive code"); } } - + // 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)); @@ -4949,7 +4949,7 @@ namespace { // TODO: if this is an unbound UfcsUnknown, treat as a fuzzy match. // - Shouldn't compare_with_placeholders do that? const auto& out_ty = out_ty_o; - + // - If we're looking for an associated type, allow it to eliminate impossible impls // > This makes `let v: usize = !0;` work without special cases auto cmp2 = v.left_ty.compare_with_placeholders(sp, out_ty, context.m_ivars.callback_resolve_infer()); @@ -4974,13 +4974,13 @@ namespace { } else { DEBUG("- (possible) " << impl); - + if( possible_impl_ty == ::HIR::TypeRef() ) { possible_impl_ty = impl.get_impl_type(); possible_params = impl.get_trait_params(); best_impl = mv$(impl); } - + return false; } }); @@ -5009,11 +5009,11 @@ namespace { else if( v.trait == context.m_crate.get_lang_item_path(sp, "unsize") ) { // TODO: Detect if this was a compiler-generated bound, or was actually in the code. - + ASSERT_BUG(sp, v.params.m_types.size() == 1, "Incorrect number of parameters for Unsize"); const auto& src_ty = context.get_type(v.impl_ty); const auto& dst_ty = context.get_type(v.params.m_types[0]); - + context.equate_types(sp, dst_ty, src_ty); return true; } @@ -5081,12 +5081,12 @@ namespace { return false; } } - + bool check_ivar_poss(Context& context, unsigned int i, Context::IVarPossible& ivar_ent) { static Span _span; const auto& sp = _span; - + if( ! ivar_ent.has_rules() ) { // No idea! (or unused) // - Clear the `force_no` flag @@ -5094,18 +5094,18 @@ namespace { ivar_ent.force_no_from = false; 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; } - + enum class DedupKeep { Both, Left, @@ -5115,7 +5115,7 @@ namespace { static void dedup_type_list_with(::std::vector< ::HIR::TypeRef>& list, ::std::function<DedupKeep(const ::HIR::TypeRef& l, const ::HIR::TypeRef& r)> cmp) { if( list.size() <= 1 ) return ; - + for( auto it = list.begin(); it != list.end(); ) { bool found = false; @@ -5147,7 +5147,7 @@ namespace { 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; }); } - + // 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) @@ -5224,25 +5224,25 @@ namespace { 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); } - + // 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; - + 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; @@ -5256,7 +5256,7 @@ namespace { return context.m_ivars.types_equal(*s_e.inner, *d_e.inner); } } - + 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(); @@ -5273,7 +5273,7 @@ namespace { return context.m_ivars.types_equal(*s_e.inner, *d_e.inner); } } - + 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(); @@ -5283,7 +5283,7 @@ namespace { } 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, @@ -5295,7 +5295,7 @@ namespace { ) return false; } - + static const ::HIR::TypeRef* find_lowest_type(const Context& context, const ::std::vector< ::HIR::TypeRef>& list) { // 1. Locate types that cannot coerce to anything @@ -5314,7 +5314,7 @@ namespace { ) ) } - + // 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]; @@ -5336,13 +5336,13 @@ namespace { // TODO: Replace //return cur_type; } - + return nullptr; } - + /// 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) { - + ::HIR::TypeRef tmp; const ::HIR::TypeRef* ty = &src; do @@ -5352,7 +5352,7 @@ namespace { } while( (ty = context.m_resolve.autoderef(sp, *ty, tmp)) ); return false; } - + 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) { if( list_a.size() == 0 ) @@ -5371,7 +5371,7 @@ namespace { } } }; - + // If this type has an infer class active, don't allw a non-primitive to coerce over it. switch( ty_l.m_data.as_Infer().ty_class ) { @@ -5402,7 +5402,7 @@ namespace { default: break; } - + if( ivar_ent.force_no_to == true || ivar_ent.force_no_from ) { DEBUG("- IVar " << ty_l << " is forced unknown"); @@ -5411,15 +5411,15 @@ 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); 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 ) { @@ -5427,7 +5427,7 @@ namespace { ASSERT_BUG(Span(), ivar_ent.types_def.size() == 1, "TODO: Multiple default types for an ivar - " << ivar_ent.types_def); } #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 ) @@ -5436,7 +5436,7 @@ namespace { } 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) { // &T and T @@ -5462,12 +5462,12 @@ namespace { 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; - + if( l.m_data.is_Borrow() ) { const auto& le = l.m_data.as_Borrow(); const auto& re = r.m_data.as_Borrow(); - + // 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) ) @@ -5477,8 +5477,8 @@ namespace { } 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() ) { @@ -5506,18 +5506,18 @@ namespace { } } #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? - + // Same type on both sides, pick it. if( types_from == types_to && types_from.size() == 1 ) { const auto& new_ty = types_from[0]; @@ -5525,7 +5525,7 @@ namespace { 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 ) { @@ -5540,7 +5540,7 @@ namespace { { 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, @@ -5553,7 +5553,7 @@ namespace { } } } - + if( remove ) { it = types_from.erase(it); } @@ -5561,7 +5561,7 @@ namespace { ++it; } } - + // 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(); ) @@ -5571,7 +5571,7 @@ namespace { continue; } bool remove = false; - + for(const auto& src : types_from) { if( H::cannot_coerce_to(context, *it, src) ) { @@ -5580,7 +5580,7 @@ namespace { break; } } - + if( remove ) { it = types_to.erase(it); } @@ -5589,8 +5589,8 @@ namespace { } } } - - + + // Prefer cases where this type is being created from a known type if( types_from.size() == 1 ) { const ::HIR::TypeRef& ty_r = types_from[0]; @@ -5608,7 +5608,7 @@ namespace { } 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 ) { @@ -5631,7 +5631,7 @@ namespace { } } } - + return false; } } @@ -5641,10 +5641,10 @@ namespace { void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR::TypeRef& result_type, ::HIR::ExprPtr& expr) { TRACE_FUNCTION; - + auto root_ptr = expr.into_unique(); 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 ); } @@ -5677,22 +5677,22 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR: } return false; }); - + ExprVisitor_Enum visitor(context, ms.m_traits, result_type); context.add_ivars(root_ptr->m_res_type); root_ptr->visit(visitor); - + DEBUG("Return type = " << new_res_ty); context.equate_types_coerce(sp, new_res_ty, root_ptr); } - + const unsigned int MAX_ITERATIONS = 1000; unsigned int count = 0; while( context.take_changed() /*&& context.has_rules()*/ && count < MAX_ITERATIONS ) { TRACE_FUNCTION_F("=== PASS " << count << " ==="); context.dump(); - + // 1. Check coercions for ones that cannot coerce due to RHS type (e.g. `str` which doesn't coerce to anything) // 2. (???) Locate coercions that cannot coerce (due to being the only way to know a type) // - Keep a list in the ivar of what types that ivar could be equated to. @@ -5702,7 +5702,7 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR: it->left_ty = context.m_resolve.expand_associated_types( (*it->right_node_ptr)->span(), mv$(it->left_ty) ); if( check_coerce(context, *it) ) { DEBUG("- Consumed coercion " << it->left_ty << " := " << src_ty); - + #if 1 unsigned int i = it - context.link_coerce.begin(); if( it != context.link_coerce.end()-1 ) @@ -5725,7 +5725,7 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR: for(unsigned int i = 0; i < context.link_assoc.size(); ) { // - Move out (and back in later) to avoid holding a bad pointer if the list is updated auto rule = mv$(context.link_assoc[i]); - + DEBUG("- " << rule); for( auto& ty : rule.params.m_types ) { ty = context.m_resolve.expand_associated_types(rule.span, mv$(ty)); @@ -5734,7 +5734,7 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR: rule.left_ty = context.m_resolve.expand_associated_types(rule.span, mv$(rule.left_ty)); } rule.impl_ty = context.m_resolve.expand_associated_types(rule.span, mv$(rule.impl_ty)); - + if( check_associated(context, rule) ) { DEBUG("- Consumed associated type rule - " << rule); #if 1 @@ -5778,7 +5778,7 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR: ++ it; } } - + // If nothing changed this pass, apply ivar possibilities // - This essentially forces coercions not to happen. if( ! context.m_ivars.peek_changed() ) @@ -5826,14 +5826,14 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR: context.m_ivars.mark_change(); } } - + count ++; context.m_resolve.compact_ivars(context.m_ivars); } if( count == MAX_ITERATIONS ) { BUG(root_ptr->span(), "Typecheck ran for too many iterations, max - " << MAX_ITERATIONS); } - + if( context.has_rules() ) { for(const auto& coercion : context.link_coerce) @@ -5869,7 +5869,7 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR: } BUG(root_ptr->span(), "Spare rules left after typecheck stabilised"); } - + // - Recreate the pointer expr.reset( root_ptr.release() ); // > Steal the binding types @@ -5877,12 +5877,12 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR: for(auto& binding : context.m_bindings) { expr.m_bindings.push_back( binding.ty.clone() ); } - + // - Validate typeck { DEBUG("==== VALIDATE ==== (" << count << " rounds)"); context.dump(); - + ExprVisitor_Apply visitor { context }; visitor.visit_node_ptr( expr ); } diff --git a/src/hir_typeck/expr_visit.cpp b/src/hir_typeck/expr_visit.cpp index 83036720..95e0c29c 100644 --- a/src/hir_typeck/expr_visit.cpp +++ b/src/hir_typeck/expr_visit.cpp @@ -10,8 +10,8 @@ namespace { //Typecheck_Code_Simple(ms, args, result_type, expr); Typecheck_Code_CS(ms, args, result_type, expr); } - - + + class OuterVisitor: public ::HIR::Visitor { @@ -21,8 +21,8 @@ namespace { m_ms(crate) { } - - + + public: void visit_module(::HIR::ItemPath p, ::HIR::Module& mod) override { @@ -30,7 +30,7 @@ namespace { ::HIR::Visitor::visit_module(p, mod); m_ms.pop_traits(mod); } - + // NOTE: This is left here to ensure that any expressions that aren't handled by higher code cause a failure void visit_expr(::HIR::ExprPtr& exp) override { BUG(exp->m_span, "Reached expression"); @@ -41,12 +41,12 @@ namespace { auto _ = this->m_ms.set_impl_generics(item.m_params); ::HIR::Visitor::visit_trait(p, item); } - + void visit_type_impl(::HIR::TypeImpl& impl) override { TRACE_FUNCTION_F("impl " << impl.m_type); 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); ::HIR::Visitor::visit_type_impl(impl); @@ -56,7 +56,7 @@ namespace { { TRACE_FUNCTION_F("impl " << trait_path << " for " << impl.m_type); 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.m_traits.push_back( ::std::make_pair( &trait_path, &this->m_ms.m_crate.get_trait_by_path(Span(), trait_path) ) ); @@ -68,13 +68,13 @@ namespace { { TRACE_FUNCTION_F("impl " << trait_path << " for " << impl.m_type << " { }"); 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); ::HIR::Visitor::visit_marker_impl(trait_path, impl); m_ms.pop_traits(mod); } - + void visit_type(::HIR::TypeRef& ty) override { TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Array, e, @@ -124,10 +124,10 @@ namespace { } void visit_enum(::HIR::ItemPath p, ::HIR::Enum& item) override { auto _ = this->m_ms.set_item_generics(item.m_params); - + // TODO: Use a different type depding on repr() auto enum_type = ::HIR::TypeRef(::HIR::CoreType::Isize); - + // TODO: Check types too? for(auto& var : item.m_variants) { diff --git a/src/hir_typeck/expr_visit.hpp b/src/hir_typeck/expr_visit.hpp index 5ef2a838..3fe601e4 100644 --- a/src/hir_typeck/expr_visit.hpp +++ b/src/hir_typeck/expr_visit.hpp @@ -3,18 +3,18 @@ namespace typeck { struct ModuleState { ::HIR::Crate& m_crate; - + ::HIR::GenericParams* m_impl_generics; ::HIR::GenericParams* m_item_generics; - + ::std::vector< ::std::pair< const ::HIR::SimplePath*, const ::HIR::Trait* > > m_traits; - + ModuleState(::HIR::Crate& crate): m_crate(crate), m_impl_generics(nullptr), m_item_generics(nullptr) {} - + template<typename T> class NullOnDrop { T*& ptr; @@ -36,7 +36,7 @@ namespace typeck { m_item_generics = &gps; return NullOnDrop< ::HIR::GenericParams>(m_item_generics); } - + void push_traits(const ::HIR::Module& mod) { auto sp = Span(); DEBUG("Module has " << mod.m_traits.size() << " in-scope traits"); diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index a9577835..ac94909d 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -41,7 +41,7 @@ void HMTypeInferrence::check_for_loops() { struct LoopChecker { ::std::vector<unsigned int> m_indexes; - + void check_pathparams(const HMTypeInferrence& ivars, const ::HIR::PathParams& pp) { for(const auto& ty : pp.m_types) this->check_ty(ivars, ty); @@ -144,25 +144,25 @@ void HMTypeInferrence::check_for_loops() void HMTypeInferrence::compact_ivars() { this->check_for_loops(); - + unsigned int i = 0; for(auto& v : m_ivars) { if( !v.is_alias() ) { //auto nt = this->expand_associated_types(Span(), v.type->clone()); auto nt = v.type->clone(); - + DEBUG("- " << i << " " << *v.type << " -> " << nt); *v.type = mv$(nt); } else { - + auto index = v.alias; unsigned int count = 0; assert(index < m_ivars.size()); while( m_ivars.at(index).is_alias() ) { index = m_ivars.at(index).alias; - + if( count >= m_ivars.size() ) { this->dump(); BUG(Span(), "Loop detected in ivar list when starting at " << v.alias << ", current is " << index); @@ -206,7 +206,7 @@ bool HMTypeInferrence::apply_defaults() } } return rv; -} +} void HMTypeInferrence::print_type(::std::ostream& os, const ::HIR::TypeRef& tr) const { @@ -548,12 +548,12 @@ void HMTypeInferrence::set_ivar_to(unsigned int slot, ::HIR::TypeRef type) auto sp = Span(); auto& root_ivar = this->get_pointed_ivar(slot); DEBUG("set_ivar_to(" << slot << " { " << *root_ivar.type << " }, " << type << ")"); - + // If the left type was '_', alias the right to it TU_IFLET(::HIR::TypeRef::Data, type.m_data, Infer, l_e, assert( l_e.index != slot ); DEBUG("Set IVar " << slot << " = @" << l_e.index); - + if( l_e.ty_class != ::HIR::InferClass::None ) { TU_MATCH_DEF(::HIR::TypeRef::Data, (root_ivar.type->m_data), (e), ( @@ -570,7 +570,7 @@ void HMTypeInferrence::set_ivar_to(unsigned int slot, ::HIR::TypeRef type) ) ) } - + root_ivar.alias = l_e.index; root_ivar.type.reset(); ) @@ -607,7 +607,7 @@ void HMTypeInferrence::set_ivar_to(unsigned int slot, ::HIR::TypeRef type) else { BUG(sp, "Overwriting ivar " << slot << " (" << *root_ivar.type << ") with " << type); } - + #if 1 TU_IFLET(::HIR::TypeRef::Data, type.m_data, Diverge, e, root_ivar.type->m_data.as_Infer().ty_class = ::HIR::InferClass::Diverge; @@ -616,7 +616,7 @@ void HMTypeInferrence::set_ivar_to(unsigned int slot, ::HIR::TypeRef type) #endif root_ivar.type = box$( mv$(type) ); } - + this->mark_change(); } @@ -626,10 +626,10 @@ void HMTypeInferrence::ivar_unify(unsigned int left_slot, unsigned int right_slo if( left_slot != right_slot ) { auto& left_ivar = this->get_pointed_ivar(left_slot); - + // TODO: Assert that setting this won't cause a loop. auto& root_ivar = this->get_pointed_ivar(right_slot); - + TU_IFLET(::HIR::TypeRef::Data, root_ivar.type->m_data, Infer, re, if( re.ty_class == ::HIR::InferClass::Diverge ) { @@ -670,11 +670,11 @@ void HMTypeInferrence::ivar_unify(unsigned int left_slot, unsigned int right_slo else { BUG(sp, "Unifying over a concrete type - " << *root_ivar.type); } - + DEBUG("IVar " << root_ivar.type->m_data.as_Infer().index << " = @" << left_slot); root_ivar.alias = left_slot; root_ivar.type.reset(); - + this->mark_change(); } } @@ -685,7 +685,7 @@ HMTypeInferrence::IVar& HMTypeInferrence::get_pointed_ivar(unsigned int slot) co assert(index < m_ivars.size()); while( m_ivars.at(index).is_alias() ) { index = m_ivars.at(index).alias; - + if( count >= m_ivars.size() ) { this->dump(); BUG(Span(), "Loop detected in ivar list when starting at " << slot << ", current is " << index); @@ -799,7 +799,7 @@ namespace { { if( l.size() != r.size() ) return false; - + for( unsigned int i = 0; i < l.size(); i ++ ) { if( !context.types_equal(l[i], r[i]) ) return false; @@ -817,7 +817,7 @@ bool HMTypeInferrence::types_equal(const ::HIR::TypeRef& rl, const ::HIR::TypeRe const auto& r = this->get_type(rr); if( l.m_data.tag() != r.m_data.tag() ) return false; - + struct H { static bool compare_path(const HMTypeInferrence& self, const ::HIR::Path& l, const ::HIR::Path& r) { if( l.m_data.tag() != r.m_data.tag() ) @@ -851,7 +851,7 @@ bool HMTypeInferrence::types_equal(const ::HIR::TypeRef& rl, const ::HIR::TypeRe throw ""; } }; - + TU_MATCH(::HIR::TypeRef::Data, (l.m_data, r.m_data), (le, re), (Infer, return le.index == re.index; ), (Primitive, return le == re; ), @@ -923,13 +923,13 @@ void TraitResolution::prep_indexes() { static Span sp_AAA; const Span& sp = sp_AAA; - + 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) )); }; - + this->iterate_bounds([&](const auto& b) { TU_MATCH_DEF(::HIR::GenericBound, (b), (be), ( @@ -940,10 +940,10 @@ void TraitResolution::prep_indexes() DEBUG("[prep_indexes] Equality (TB) - <" << be.type << " as " << be.trait.m_path << ">::" << tb.first << " = " << tb.second); auto ty_l = ::HIR::TypeRef( ::HIR::Path( be.type.clone(), be.trait.m_path.clone(), tb.first ) ); ty_l.m_data.as_Path().binding = ::HIR::TypeRef::TypePathBinding::make_Opaque({}); - + add_equality( mv$(ty_l), tb.second.clone() ); } - + const auto& trait_params = be.trait.m_path.m_params; auto cb_mono = [&](const auto& ty)->const auto& { const auto& ge = ty.m_data.as_Generic(); @@ -959,7 +959,7 @@ void TraitResolution::prep_indexes() BUG(sp, "Unknown generic binding " << ty); } }; - + const auto& trait = m_crate.get_trait_by_path(sp, be.trait.m_path.m_path); for(const auto& a_ty : trait.m_types) { @@ -973,10 +973,10 @@ void TraitResolution::prep_indexes() ty_a.m_data.as_Path().binding = ::HIR::TypeRef::TypePathBinding::make_Opaque({}); } DEBUG("[prep_indexes] Equality (ATB) - <" << ty_a << " as " << a_ty_b.m_path << ">::" << tb.first << " = " << tb.second); - + auto ty_l = ::HIR::TypeRef( ::HIR::Path( ty_a.clone(), trait_mono.m_path.clone(), tb.first ) ); ty_l.m_data.as_Path().binding = ::HIR::TypeRef::TypePathBinding::make_Opaque({}); - + add_equality( mv$(ty_l), mv$(tb.second) ); } } @@ -1031,7 +1031,7 @@ bool TraitResolution::find_trait_impls(const Span& sp, const auto& type = this->m_ivars.get_type(ty); TRACE_FUNCTION_F("trait = " << trait << params << ", type = " << type); - + 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_Unsize = this->m_crate.get_lang_item_path(sp, "unsize"); @@ -1041,7 +1041,7 @@ bool TraitResolution::find_trait_impls(const Span& sp, const auto& trait_fn_once = this->m_crate.get_lang_item_path(sp, "fn_once"); 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 ) { TU_MATCH_DEF(::HIR::TypeRef::Data, (type.m_data), (e), ( @@ -1063,7 +1063,7 @@ bool TraitResolution::find_trait_impls(const Span& sp, ) return callback( ImplRef(&type, &null_params, &null_assoc), ::HIR::Compare::Equal ); } - + if( trait == lang_Copy ) { auto cmp = this->type_is_copy(sp, type); if( cmp != ::HIR::Compare::Unequal ) { @@ -1073,7 +1073,7 @@ bool TraitResolution::find_trait_impls(const Span& sp, 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"); @@ -1081,10 +1081,10 @@ bool TraitResolution::find_trait_impls(const Span& sp, TU_IFLET( ::HIR::TypeRef::Data, dst_ty.m_data, TraitObject, e, // Magic impl if T: ThisTrait bool good; - + ::HIR::TypeRef::Data::Data_TraitObject tmp_e; tmp_e.m_trait.m_path = e.m_trait.m_path.m_path; - + ::HIR::Compare total_cmp = ::HIR::Compare::Equal; if( e.m_trait.m_path.m_path == ::HIR::SimplePath() ) { ASSERT_BUG(sp, e.m_markers.size() > 0, "TraitObject with no traits - " << dst_ty); @@ -1124,10 +1124,10 @@ bool TraitResolution::find_trait_impls(const Span& sp, return false; } ) - + // [T;N] -> [T] is handled down with array indexing } - + // Magical CoerceUnsized impls for various types if( trait == lang_CoerceUnsized ) { const auto& dst_ty = params.m_types.at(0); @@ -1148,7 +1148,7 @@ bool TraitResolution::find_trait_impls(const Span& sp, ) ) } - + // Magic impls of the Fn* traits for closure types TU_IFLET(::HIR::TypeRef::Data, type.m_data, Closure, e, DEBUG("Closure, "<< trait <<" " << trait_fn << " " << trait_fn_mut << " " << trait_fn_once); @@ -1157,12 +1157,12 @@ bool TraitResolution::find_trait_impls(const Span& sp, BUG(sp, "Fn* traits require a single tuple argument"); if( !params.m_types[0].m_data.is_Tuple() ) BUG(sp, "Fn* traits require a single tuple argument"); - + const auto& args_des = params.m_types[0].m_data.as_Tuple(); if( args_des.size() != e.m_arg_types.size() ) { return false; } - + auto cmp = ::HIR::Compare::Equal; ::std::vector< ::HIR::TypeRef> args; for(unsigned int i = 0; i < e.m_arg_types.size(); i ++) @@ -1176,9 +1176,9 @@ bool TraitResolution::find_trait_impls(const Span& sp, // NOTE: This is a conditional "true", we know nothing about the move/mut-ness of this closure yet // - Could we? // - Not until after the first stage of typeck - + DEBUG("Closure Fn* impl - cmp = " << cmp); - + ::HIR::PathParams pp; pp.m_types.push_back( ::HIR::TypeRef(mv$(args)) ); ::std::map< ::std::string, ::HIR::TypeRef> types; @@ -1192,7 +1192,7 @@ bool TraitResolution::find_trait_impls(const Span& sp, } } ) - + // Magic Fn* trait impls for function pointers TU_IFLET(::HIR::TypeRef::Data, type.m_data, Function, e, if( trait == trait_fn || trait == trait_fn_mut || trait == trait_fn_once ) { @@ -1204,14 +1204,14 @@ bool TraitResolution::find_trait_impls(const Span& sp, if( args_des.size() != e.m_arg_types.size() ) { return false; } - + // NOTE: unsafe or non-rust ABI functions aren't valid if( e.m_abi != ABI_RUST || e.is_unsafe ) { DEBUG("- No magic impl, wrong ABI or unsafe in " << type); return false; } DEBUG("- Magic impl of Fn* for " << type); - + auto cmp = ::HIR::Compare::Equal; ::std::vector< ::HIR::TypeRef> args; for(unsigned int i = 0; i < e.m_arg_types.size(); i ++) @@ -1220,7 +1220,7 @@ bool TraitResolution::find_trait_impls(const Span& sp, args.push_back( at.clone() ); cmp &= at.compare_with_placeholders(sp, args_des[i], this->m_ivars.callback_resolve_infer()); } - + ::HIR::PathParams pp; pp.m_types.push_back( ::HIR::TypeRef(mv$(args)) ); ::std::map< ::std::string, ::HIR::TypeRef> types; @@ -1229,7 +1229,7 @@ bool TraitResolution::find_trait_impls(const Span& sp, } // Continue ) - + // Magic index and unsize impls for Arrays // NOTE: The index impl for [T] is in libcore. TU_IFLET(::HIR::TypeRef::Data, type.m_data, Array, e, @@ -1238,9 +1238,9 @@ bool TraitResolution::find_trait_impls(const Span& sp, BUG(sp, "Index* traits require a single argument"); DEBUG("- Magic impl of Index* for " << type); const auto& index_ty = m_ivars.get_type(params.m_types[0]); - + ::HIR::Compare cmp; - + // Index<usize> ? auto ty_usize = ::HIR::TypeRef(::HIR::CoreType::Usize); cmp = ty_usize.compare_with_placeholders(sp, index_ty, this->m_ivars.callback_resolve_infer()); @@ -1252,7 +1252,7 @@ bool TraitResolution::find_trait_impls(const Span& sp, types.insert( ::std::make_pair( "Output", e.inner->clone() ) ); return callback( ImplRef(type.clone(), mv$(pp), mv$(types)), cmp ); } - + /* // TODO: Index<Range/RangeFrom/RangeTo/FullRange>? - Requires knowing the path to the range ops (which isn't a lang item) ::HIR::PathParams pp; @@ -1269,13 +1269,13 @@ bool TraitResolution::find_trait_impls(const Span& sp, */ return false; } - + // Unsize impl for arrays if( trait == lang_Unsize ) { ASSERT_BUG(sp, params.m_types.size() == 1, ""); const auto& dst_ty = m_ivars.get_type( params.m_types[0] ); - + TU_IFLET(::HIR::TypeRef::Data, dst_ty.m_data, Slice, e2, auto cmp = e.inner->compare_with_placeholders(sp, *e2.inner, m_ivars.callback_resolve_infer()); if( cmp != ::HIR::Compare::Unequal ) { @@ -1287,8 +1287,8 @@ bool TraitResolution::find_trait_impls(const Span& sp, ) } ) - - + + // Trait objects automatically implement their own traits // - IF object safe (TODO) TU_IFLET(::HIR::TypeRef::Data, type.m_data, TraitObject, e, @@ -1310,7 +1310,7 @@ bool TraitResolution::find_trait_impls(const Span& sp, } } } - + // - Check if the desired trait is a supertrait of this. // NOTE: `params` (aka des_params) is not used (TODO) bool rv = false; @@ -1334,7 +1334,7 @@ bool TraitResolution::find_trait_impls(const Span& sp, { return rv; } - + // Trait objects can unsize to a subset of their traits. if( trait == lang_Unsize ) { @@ -1345,9 +1345,9 @@ bool TraitResolution::find_trait_impls(const Span& sp, return false; } const auto& e2 = dst_ty.m_data.as_TraitObject(); - + auto cmp = ::HIR::Compare::Equal; - + // TODO: Fuzzy compare if( e2.m_trait != e.m_trait ) { return false; @@ -1370,11 +1370,11 @@ bool TraitResolution::find_trait_impls(const Span& sp, return false; } } - + return callback( ImplRef(&type, &e.m_trait.m_path.m_params, &e.m_trait.m_type_bounds), cmp ); } ) - + TU_IFLET(::HIR::TypeRef::Data, type.m_data, ErasedType, e, for( const auto& trait_path : e.m_traits ) { @@ -1385,7 +1385,7 @@ bool TraitResolution::find_trait_impls(const Span& sp, return callback( ImplRef(&type, &trait_path.m_path.m_params, &trait_path.m_type_bounds), cmp ); } } - + // - Check if the desired trait is a supertrait of this. // NOTE: `params` (aka des_params) is not used (TODO) bool rv = false; @@ -1421,19 +1421,19 @@ bool TraitResolution::find_trait_impls(const Span& sp, return callback( ImplRef(&type, &null_params, &null_assoc), ::HIR::Compare::Fuzzy ); } ) - + // If this type is an opaque UfcsKnown - check bounds TU_IFLET(::HIR::TypeRef::Data, type.m_data, Path, e, if( e.binding.is_Opaque() ) { 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(); - + // If this associated type has a bound of the desired trait, return it. const auto& trait_ref = m_crate.get_trait_by_path(sp, pe.trait.m_path); ASSERT_BUG(sp, trait_ref.m_types.count( pe.item ) != 0, "Trait " << pe.trait.m_path << " doesn't contain an associated type " << pe.item); const auto& aty_def = trait_ref.m_types.find(pe.item)->second; - + auto monomorph_cb = monomorphise_type_get_cb(sp, &*pe.type, &pe.trait.m_params, nullptr, nullptr); for(const auto& bound : aty_def.m_trait_bounds) @@ -1441,7 +1441,7 @@ bool TraitResolution::find_trait_impls(const Span& sp, 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); - + if( bound.m_path.m_path == trait ) { auto cmp = this->compare_pp(sp, b_params_mono, params); @@ -1460,7 +1460,7 @@ bool TraitResolution::find_trait_impls(const Span& sp, } } } - + 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); @@ -1475,10 +1475,10 @@ bool TraitResolution::find_trait_impls(const Span& sp, { if( ! bound.is_TraitBound() ) continue ; const auto& be = bound.as_TraitBound(); - + if( ! be.type.m_data.is_Path() ) continue ; if( ! be.type.m_data.as_Path().binding.is_Opaque() ) continue ; - + const auto& be_type_pe = be.type.m_data.as_Path().path.m_data.as_UfcsKnown(); if( *be_type_pe.type != ::HIR::TypeRef("Self", 0xFFFF) ) continue ; @@ -1486,12 +1486,12 @@ bool TraitResolution::find_trait_impls(const Span& sp, continue ; if( be_type_pe.item != pe.item ) continue ; - + // TODO: Merge the below code with the code from the above loop. const auto& b_params = be.trait.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); - + if( be.trait.m_path.m_path == trait ) { auto cmp = this->compare_pp(sp, b_params_mono, params); @@ -1510,7 +1510,7 @@ bool TraitResolution::find_trait_impls(const Span& sp, } } } - + bool ret = this->find_named_trait_in_trait(sp, trait, params, *be.trait.m_trait_ptr, be.trait.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); @@ -1522,7 +1522,7 @@ bool TraitResolution::find_trait_impls(const Span& sp, } } ) - + // 1. Search generic params if( find_trait_impls_bound(sp, trait, params, type, callback) ) return true; @@ -1537,7 +1537,7 @@ bool TraitResolution::find_trait_impls(const Span& sp, void TraitResolution::compact_ivars(HMTypeInferrence& m_ivars) { m_ivars.check_for_loops(); - + //m_ivars.compact_ivars([&](const ::HIR::TypeRef& t)->auto{ return this->expand_associated_types(Span(), t.clone); }); unsigned int i = 0; for(auto& v : m_ivars.m_ivars) @@ -1553,13 +1553,13 @@ void TraitResolution::compact_ivars(HMTypeInferrence& m_ivars) } } else { - + auto index = v.alias; unsigned int count = 0; assert(index < m_ivars.m_ivars.size()); while( m_ivars.m_ivars.at(index).is_alias() ) { index = m_ivars.m_ivars.at(index).alias; - + if( count >= m_ivars.m_ivars.size() ) { this->m_ivars.dump(); BUG(Span(), "Loop detected in ivar list when starting at " << v.alias << ", current is " << index); @@ -1768,7 +1768,7 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp, TRACE_FUNCTION_FR("input=" << input, input); auto& e = input.m_data.as_Path(); auto& pe = e.path.m_data.as_UfcsKnown(); - + struct D { const TraitResolution& m_tr; D(const TraitResolution& tr, ::HIR::TypeRef v): m_tr(tr) { @@ -1781,9 +1781,9 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp, D _(*this, input.clone()); // State stack to avoid infinite recursion LList<const ::HIR::TypeRef*> stack(&prev_stack, &m_eat_active_stack.back()); - + expand_associated_types_inplace(sp, *pe.type, stack); - + // - If it's a closure, then the only trait impls are those generated by typeck TU_IFLET(::HIR::TypeRef::Data, pe.type->m_data, Closure, te, const auto trait_fn = this->m_crate.get_lang_item_path(sp, "fn"); @@ -1799,7 +1799,7 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp, } } ) - + TU_IFLET(::HIR::TypeRef::Data, pe.type->m_data, Function, te, if( te.m_abi == ABI_RUST && !te.is_unsafe ) { @@ -1817,7 +1817,7 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp, } } ) - + // If it's a TraitObject, then maybe we're asking for a bound TU_IFLET(::HIR::TypeRef::Data, pe.type->m_data, TraitObject, te, const auto& data_trait = te.m_trait.m_path; @@ -1844,12 +1844,12 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp, // - Why opaque? It's not bounded, don't even bother TODO(sp, "Handle unconstrained associate type " << pe.item << " from " << *pe.type); } - + input = it->second.clone(); return ; } } - + // - Check if the desired trait is a supertrait of this. // NOTE: `params` (aka des_params) is not used (TODO) bool is_supertrait = this->find_named_trait_in_trait(sp, pe.trait.m_path,pe.trait.m_params, *te.m_trait.m_trait_ptr, data_trait.m_path,data_trait.m_params, *pe.type, @@ -1877,7 +1877,7 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp, return ; } ) - + // If it's a ErasedType, then maybe we're asking for a bound TU_IFLET(::HIR::TypeRef::Data, pe.type->m_data, ErasedType, te, for( const auto& trait : te.m_traits ) @@ -1906,12 +1906,12 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp, // - Why opaque? It's not bounded, don't even bother TODO(sp, "Handle unconstrained associate type " << pe.item << " from " << *pe.type); } - + input = it->second.clone(); return ; } } - + // - Check if the desired trait is a supertrait of this. // NOTE: `params` (aka des_params) is not used (TODO) bool is_supertrait = this->find_named_trait_in_trait(sp, pe.trait.m_path,pe.trait.m_params, *trait.m_trait_ptr, trait_gp.m_path,trait_gp.m_params, *pe.type, @@ -1940,7 +1940,7 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp, } } ) - + // 1. Bounds bool rv; bool assume_opaque = true; @@ -1969,7 +1969,7 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp, } return true; } - + bool found_supertrait = this->find_named_trait_in_trait(sp, pe.trait.m_path, pe.trait.m_params, *be.trait.m_trait_ptr, be.trait.m_path.m_path, be.trait.m_path.m_params, *pe.type, @@ -1998,7 +1998,7 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp, } return true; } - + // - Didn't match ), (TypeEquality, @@ -2016,11 +2016,11 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp, if( assume_opaque ) { DEBUG("Assuming that " << input << " is an opaque name"); input.m_data.as_Path().binding = ::HIR::TypeRef::TypePathBinding::make_Opaque({}); - + DEBUG("- " << m_type_equalities.size() << " replacements"); for( const auto& v : m_type_equalities ) DEBUG(" > " << v.first << " = " << v.second); - + auto a = m_type_equalities.find(input); if( a != m_type_equalities.end() ) { input = a->second.clone(); @@ -2042,7 +2042,7 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp, const auto& trait_ptr = this->m_crate.get_trait_by_path(sp, pe_inner.trait.m_path); const auto& assoc_ty = trait_ptr.m_types.at(pe_inner.item); DEBUG("TODO: Search bounds on associated type - " << assoc_ty.m_trait_bounds); - + // Resolve where Self=pe_inner.type (i.e. for the trait this inner UFCS is on) auto cb_placeholders_trait = [&](const auto& ty)->const auto&{ TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Generic, e, @@ -2087,7 +2087,7 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp, 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); //pe.trait = mv$(trait_path); - + DEBUG("Searching for impl"); bool can_fuzz = true; unsigned int count = 0; @@ -2112,7 +2112,7 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp, best_impl = ImplRef(); can_fuzz = false; } - + // If the type is specialisable if( impl.type_is_specialisable(pe.item.c_str()) ) { // Check if this is more specific @@ -2126,10 +2126,10 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp, auto ty = impl.get_type( pe.item.c_str() ); if( ty == ::HIR::TypeRef() ) ERROR(sp, E0000, "Couldn't find assocated type " << pe.item << " in " << pe.trait); - + if( impl.has_magic_params() ) ; - + // TODO: What if there's multiple impls? DEBUG("Converted UfcsKnown - " << e.path << " = " << ty); input = mv$(ty); @@ -2149,13 +2149,13 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp, auto ty = best_impl.get_type( pe.item.c_str() ); if( ty == ::HIR::TypeRef() ) ERROR(sp, E0000, "Couldn't find assocated type " << pe.item << " in " << pe.trait); - + // Try again later? if( best_impl.has_magic_params() ) { DEBUG("- Placeholder parameters present in impl, can't expand"); return ; } - + DEBUG("Converted UfcsKnown - " << e.path << " = " << ty); input = mv$(ty); rv = true; @@ -2165,7 +2165,7 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp, expand_associated_types_inplace(sp, input, stack); return ; } - + // If there are no ivars in this path, set its binding to Opaque if( !this->m_ivars.type_contains_ivars(input) ) { // TODO: If the type is a generic or an opaque associated, we can't know. @@ -2195,7 +2195,7 @@ bool TraitResolution::find_named_trait_in_trait(const Span& sp, if( pp.m_types.size() != trait_ptr.m_params.m_types.size() ) { BUG(sp, "Incorrect number of parameters for trait"); } - + const auto monomorph_cb = [&](const auto& gt)->const auto& { const auto& ge = gt.m_data.as_Generic(); if( ge.binding == 0xFFFF ) { @@ -2207,7 +2207,7 @@ bool TraitResolution::find_named_trait_in_trait(const Span& sp, return pp.m_types[ge.binding]; } }; - + for( const auto& pt : trait_ptr.m_parent_traits ) { auto pt_mono = monomorphise_traitpath_with(sp, pt, monomorph_cb, false); @@ -2222,19 +2222,19 @@ bool TraitResolution::find_named_trait_in_trait(const Span& sp, //} return true; } - + const auto& tr = m_crate.get_trait_by_path(sp, pt.m_path.m_path); if( find_named_trait_in_trait(sp, des, des_params, tr, pt.m_path.m_path, pt_mono.m_path.m_params, target_type, callback) ) { return true; } } - + // Also check bounds for `Self: T` bounds for(const auto& b : trait_ptr.m_params.m_bounds) { if( !b.is_TraitBound() ) continue; const auto& be = b.as_TraitBound(); - + if( be.type == ::HIR::TypeRef("Self", 0xFFFF) ) { // Something earlier adds a "Self: SelfTrait" bound, prevent that from causing infinite recursion @@ -2252,14 +2252,14 @@ bool TraitResolution::find_named_trait_in_trait(const Span& sp, //} return true; } - + const auto& tr = m_crate.get_trait_by_path(sp, pt_mono.m_path.m_path); if( find_named_trait_in_trait(sp, des, des_params, tr, pt_mono.m_path.m_path, pt_mono.m_path.m_params, target_type, callback) ) { return true; } } } - + return false; } bool TraitResolution::find_trait_impls_bound(const Span& sp, const ::HIR::SimplePath& trait, const ::HIR::PathParams& params, const ::HIR::TypeRef& type, t_cb_trait_impl_r callback) const @@ -2274,17 +2274,17 @@ bool TraitResolution::find_trait_impls_bound(const Span& sp, const ::HIR::Simple if( m_ivars.get_type(type).m_data.is_Infer() ) return false; - + // TODO: A bound can imply something via its associated types. How deep can this go? // E.g. `T: IntoIterator<Item=&u8>` implies `<T as IntoIterator>::IntoIter : Iterator<Item=&u8>` return this->iterate_bounds([&](const auto& b) { TU_IFLET(::HIR::GenericBound, b, TraitBound, e, const auto& b_params = e.trait.m_path.m_params; - + auto cmp = e.type .compare_with_placeholders(sp, type, m_ivars.callback_resolve_infer()); if( cmp == ::HIR::Compare::Unequal ) return false; - + if( e.trait.m_path.m_path == trait ) { // Check against `params` DEBUG("Checking " << params << " vs " << b_params); @@ -2301,7 +2301,7 @@ bool TraitResolution::find_trait_impls_bound(const Span& sp, const ::HIR::Simple return true; } } - + // TODO: Allow fuzzy equality? if( cmp == ::HIR::Compare::Equal ) { @@ -2329,7 +2329,7 @@ bool TraitResolution::find_trait_impls_bound(const Span& sp, const ::HIR::Simple 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 ) @@ -2342,7 +2342,7 @@ bool TraitResolution::find_trait_impls_bound(const Span& sp, const ::HIR::Simple if( ord == ::HIR::Compare::Unequal ) { return false; } - + 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) { @@ -2359,7 +2359,7 @@ bool TraitResolution::find_trait_impls_bound(const Span& sp, const ::HIR::Simple 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; if( monomorphise_pathparams_needed(bound.m_path.m_params) ) { @@ -2375,7 +2375,7 @@ bool TraitResolution::find_trait_impls_bound(const Span& sp, const ::HIR::Simple 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) { @@ -2389,7 +2389,7 @@ bool TraitResolution::find_trait_impls_bound(const Span& sp, const ::HIR::Simple } } } - + return false; ) return false; @@ -2403,7 +2403,7 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, { 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); - + // Handle auto traits (aka OIBITs) if( m_crate.get_trait_by_path(sp, trait).m_is_marker ) { @@ -2416,7 +2416,7 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, continue ; if( *::std::get<2>(ent) != type ) continue ; - + return callback( ImplRef(&type, params_ptr, &null_assoc), ::HIR::Compare::Equal ); } stack.push_back( ::std::make_tuple( &trait, params_ptr, &type ) ); @@ -2424,13 +2424,13 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, ~Guard() { stack.pop_back(); } }; Guard _; - + // NOTE: Expected behavior is for Ivars to return false // TODO: Should they return Compare::Fuzzy instead? if( type.m_data.is_Infer() ) { return false; } - + const ::HIR::TraitMarkings* markings = nullptr; TU_IFLET( ::HIR::TypeRef::Data, (type.m_data), Path, e, if( e.path.m_data.is_Generic() && e.path.m_data.as_Generic().m_params.m_types.size() == 0 ) @@ -2471,7 +2471,7 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, } } } - + // - Search for positive impls for this type DEBUG("- Search positive impls"); bool positive_found = false; @@ -2480,9 +2480,9 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, // Skip any negative impls on this pass if( impl.is_positive != true ) return false; - + DEBUG("[find_trait_impls_crate] - Auto Pos Found impl" << impl.m_params.fmt_args() << " " << trait << impl.m_trait_args << " for " << impl.m_type << " " << impl.m_params.fmt_bounds()); - + // Compare with `params` ::std::vector< const ::HIR::TypeRef*> impl_params; ::std::vector< ::HIR::TypeRef> placeholders; @@ -2491,7 +2491,7 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, // If any bound failed, return false (continue searching) return false; } - + auto monomorph = [&](const auto& gt)->const auto& { const auto& ge = gt.m_data.as_Generic(); ASSERT_BUG(sp, ge.binding >> 8 != 2, ""); @@ -2502,11 +2502,11 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, return *impl_params[ge.binding]; }; // TODO: Ensure that there are no-longer any magic params? - + auto ty_mono = monomorphise_type_with(sp, impl.m_type, monomorph, false); auto args_mono = monomorphise_path_params_with(sp, impl.m_trait_args, monomorph, false); // NOTE: Auto traits can't have items, so no associated types - + positive_found = true; DEBUG("[find_trait_impls_crate] Auto Positive callback(args=" << args_mono << ")"); return callback(ImplRef(mv$(ty_mono), mv$(args_mono), {}), match); @@ -2515,7 +2515,7 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, // A positive impl was found, so return true (callback should have been called) return true; } - + // - Search for negative impls for this type DEBUG("- Search negative impls"); bool negative_found = this->m_crate.find_auto_trait_impls(trait, type, this->m_ivars.callback_resolve_infer(), @@ -2524,7 +2524,7 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, if( impl.is_positive != false ) return false; DEBUG("[find_trait_impls_crate] - Found auto neg impl" << impl.m_params.fmt_args() << " " << trait << impl.m_trait_args << " for " << impl.m_type << " " << impl.m_params.fmt_bounds()); - + // Compare with `params` ::std::vector< const ::HIR::TypeRef*> impl_params; ::std::vector< ::HIR::TypeRef> placeholders; @@ -2533,7 +2533,7 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, // If any bound failed, return false (continue searching) return false; } - + DEBUG("[find_trait_impls_crate] - Found neg impl"); return true; }); @@ -2541,7 +2541,7 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, // A negative impl _was_ found, so return false return false; } - + auto cmp = this->check_auto_trait_impl_destructure(sp, trait, params_ptr, type); if( cmp != ::HIR::Compare::Unequal ) { @@ -2559,7 +2559,7 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, return false; } } - + return this->m_crate.find_trait_impls(trait, type, this->m_ivars.callback_resolve_infer(), [&](const auto& impl) { DEBUG("[find_trait_impls_crate] Found impl" << impl.m_params.fmt_args() << " " << trait << impl.m_trait_args << " for " << impl.m_type << " " << impl.m_params.fmt_bounds()); @@ -2588,7 +2588,7 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, DEBUG("[check_auto_trait_impl_destructure] " << inner_ty << " - " << l_res); return l_res; }; - + // - 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, ::HIR::Compare res = ::HIR::Compare::Equal; @@ -2618,7 +2618,7 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, return ty; } }; - + TU_MATCH( ::HIR::TypeRef::TypePathBinding, (e.binding), (tpb), (Opaque, BUG(sp, "Opaque binding on generic path - " << type); @@ -2628,7 +2628,7 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, ), (Struct, const auto& str = *tpb; - + // TODO: Somehow store a ruleset for auto traits on the type // - Map of trait->does_impl for local fields? // - Problems occur with type parameters @@ -2650,7 +2650,7 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, { const auto& fld_ty_mono = monomorph_get(fld.second.ent); DEBUG("Struct::Named '" << fld.first << "' " << fld_ty_mono); - + res &= type_impls_trait(fld_ty_mono); if( res == ::HIR::Compare::Unequal ) return ::HIR::Compare::Unequal; @@ -2660,7 +2660,7 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, ), (Enum, const auto& enm = *tpb; - + for(const auto& var : enm.m_variants) { TU_MATCH(::HIR::Enum::Variant, (var.second), (ve), @@ -2683,7 +2683,7 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, { const auto& fld_ty_mono = monomorph_get(fld.second.ent); DEBUG("Enum '" << var.first << "'::Struct '" << fld.first << "' " << fld_ty_mono); - + res &= type_impls_trait(fld_ty_mono); if( res == ::HIR::Compare::Unequal ) return ::HIR::Compare::Unequal; @@ -2782,7 +2782,7 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, return ::HIR::Compare::Unequal; } } - + // 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. @@ -2794,7 +2794,7 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, } } auto cb_infer = [&](const auto& ty)->const auto& { - if( ty.m_data.is_Infer() ) + if( ty.m_data.is_Infer() ) return this->m_ivars.get_type(ty); else if( ty.m_data.is_Generic() && ty.m_data.as_Generic().binding >> 8 == 2 ) { // Generic group 2 = Placeholders unsigned int i = ty.m_data.as_Generic().binding % 256; @@ -2833,7 +2833,7 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, } return *impl_params[ge.binding]; }; - + // Check bounds for this impl // - If a bound fails, then this can't be a valid impl for(const auto& bound : impl_params_def.m_bounds) @@ -2866,7 +2866,7 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, for(const auto& assoc_bound : real_trait.m_type_bounds) { ::HIR::TypeRef tmp; const ::HIR::TypeRef* ty_p; - + tmp = impl.get_type(assoc_bound.first.c_str()); if( tmp == ::HIR::TypeRef() ) { // This bound isn't from this particular trait, go the slow way of using expand_associated_types @@ -2929,7 +2929,7 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, ) ) } - + return match; } @@ -2956,7 +2956,7 @@ bool TraitResolution::trait_contains_method(const Span& sp, const ::HIR::Generic } } } - + // TODO: Prevent infinite recursion for(const auto& st : trait_ptr.m_parent_traits) { @@ -2988,7 +2988,7 @@ bool TraitResolution::trait_contains_type(const Span& sp, const ::HIR::GenericPa out_path = trait_path.clone(); return true; } - + auto monomorph = [&](const auto& gt)->const auto& { const auto& ge = gt.m_data.as_Generic(); assert(ge.binding < 256); @@ -3134,9 +3134,9 @@ unsigned int TraitResolution::autoderef_find_method(const Span& sp, const HIR::t ::HIR::TypeRef tmp_type; // Temporary type used for handling Deref const auto& top_ty_r = this->m_ivars.get_type(top_ty); const auto* current_ty = &top_ty_r; - + bool unconditional_allow_move = true; - + // If the top is a borrow, search dereferenced first. TU_IFLET(::HIR::TypeRef::Data, top_ty_r.m_data, Borrow, e, if( e.type == ::HIR::BorrowType::Owned ) { @@ -3152,7 +3152,7 @@ unsigned int TraitResolution::autoderef_find_method(const Span& sp, const HIR::t current_ty = &*e.inner; deref_count += 1; ) - + // Handle `self: Box<Self>` methods by detecting m_lang_Box and searchig for box receiver methods TU_IFLET(::HIR::TypeRef::Data, top_ty_r.m_data, Path, e, TU_IFLET(::HIR::Path::Data, e.path.m_data, Generic, pe, @@ -3171,10 +3171,10 @@ unsigned int TraitResolution::autoderef_find_method(const Span& sp, const HIR::t } ) ) - + // TODO: This appears to dereference a &mut to call a `self: Self` method, where it should use the trait impl on &mut Self. // - Shouldn't deref to get a by-value receiver.// unless it's via a &move. - + do { // TODO: Update `unconditional_allow_move` based on the current type. const auto& ty = this->m_ivars.get_type(*current_ty); @@ -3186,15 +3186,15 @@ unsigned int TraitResolution::autoderef_find_method(const Span& sp, const HIR::t DEBUG("- Unbound type path " << ty << ", pausing"); return ~0u; } - + auto allowed_receivers = (unconditional_allow_move || (deref_count == 0) ? AllowedReceivers::All : AllowedReceivers::AnyBorrow); if( this->find_method(sp, traits, ivars, ty, method_name, allowed_receivers, fcn_path) ) { DEBUG("FOUND " << deref_count << ", fcn_path = " << fcn_path); borrow = AutoderefBorrow::None; return deref_count; } - - + + auto borrow_ty = ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, ty.clone()); if( find_method(sp, traits, ivars, borrow_ty, method_name, AllowedReceivers::Value, fcn_path) ) { DEBUG("FOUND &*" << deref_count << ", fcn_path = " << fcn_path); @@ -3213,30 +3213,30 @@ unsigned int TraitResolution::autoderef_find_method(const Span& sp, const HIR::t borrow = AutoderefBorrow::Owned; return deref_count; } - + // 3. Dereference and try again deref_count += 1; current_ty = this->autoderef(sp, ty, tmp_type); } while( current_ty ); - - // If the top is a borrow, search for methods on &/&mut + + // If the top is a borrow, search for methods on &/&mut TU_IFLET(::HIR::TypeRef::Data, top_ty_r.m_data, Borrow, e, const auto& ty = top_ty_r; - + if( find_method(sp, traits, ivars, ty, method_name, AllowedReceivers::All, fcn_path) ) { DEBUG("FOUND " << 0 << ", fcn_path = " << fcn_path); borrow = AutoderefBorrow::None; return 0; } ) - + // If there are ivars within the type, don't error (yet) if( this->m_ivars.type_contains_ivars(top_ty) ) { DEBUG("- Contains ivars, pausing"); return ~0u; } - + // Insert a single reference and try again (only allowing by-value methods), returning a magic value (e.g. ~1u) // - Required for calling `(self[..]: str).into_searcher(haystack)` - Which invokes `<&str as Pattern>::into_searcher(&self[..], haystack)` // - Have to do several tries, each with different borrow classes. @@ -3258,7 +3258,7 @@ unsigned int TraitResolution::autoderef_find_method(const Span& sp, const HIR::t borrow = AutoderefBorrow::Owned; return 0; } - + // 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 << "`"); @@ -3294,7 +3294,7 @@ bool TraitResolution::find_method( // TODO: Do a fuzzy match here? if( e.type != ty ) continue ; - + // - Bound's type matches, check if the bounded trait has the method we're searching for DEBUG("Bound `" << e.type << " : " << e.trait.m_path << "` - Type match " << ty); ::HIR::GenericPath final_trait_path; @@ -3306,7 +3306,7 @@ bool TraitResolution::find_method( DEBUG("- Found trait " << final_trait_path); // TODO: Re-monomorphise final trait using `ty`? // - Could collide with legitimate uses of `Self` - + // Found the method, return the UFCS path for it fcn_path = ::HIR::Path( ::HIR::Path::Data::make_UfcsKnown({ box$( ty.clone() ), @@ -3324,13 +3324,13 @@ bool TraitResolution::find_method( //assert( e.m_trait.m_trait_ptr ); //const auto& trait = *e.m_trait.m_trait_ptr; const auto& trait = this->m_crate.get_trait_by_path(sp, e.m_trait.m_path.m_path); - - + + ::HIR::GenericPath final_trait_path; if( this->trait_contains_method(sp, e.m_trait.m_path, trait, ::HIR::TypeRef("Self", 0xFFFF), method_name, ar, final_trait_path) ) { DEBUG("- Found trait " << final_trait_path); - + fcn_path = ::HIR::Path( ::HIR::Path::Data::Data_UfcsKnown({ box$( ty.clone() ), mv$(final_trait_path), @@ -3340,18 +3340,18 @@ bool TraitResolution::find_method( return true; } ) - + // Erased type - `impl Trait` TU_IFLET(::HIR::TypeRef::Data, ty.m_data, ErasedType, e, for(const auto& trait_path : e.m_traits) { const auto& trait = this->m_crate.get_trait_by_path(sp, trait_path.m_path.m_path); - + ::HIR::GenericPath final_trait_path; if( this->trait_contains_method(sp, trait_path.m_path, trait, ::HIR::TypeRef("Self", 0xFFFF), method_name, ar, final_trait_path) ) { DEBUG("- Found trait " << final_trait_path); - + fcn_path = ::HIR::Path( ::HIR::Path::Data::Data_UfcsKnown({ box$( ty.clone() ), mv$(final_trait_path), @@ -3362,7 +3362,7 @@ bool TraitResolution::find_method( } } ) - + // Trait object - `(Trait)` TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Generic, e, // No match, keep trying. @@ -3371,9 +3371,9 @@ bool TraitResolution::find_method( { const auto& e = ty.m_data.as_Path().path.m_data.as_UfcsKnown(); DEBUG("UfcsKnown - Search associated type bounds in trait - " << e.trait); - + // UFCS known - Assuming that it's reached the maximum resolvable level (i.e. a type within is generic), search for trait bounds on the type - + // `Self` = `*e.type` // `/*I:#*/` := `e.trait.m_params` auto monomorph_cb = [&](const auto& gt)->const auto& { @@ -3393,7 +3393,7 @@ bool TraitResolution::find_method( // `Self` = `*e.type` // `/*I:#*/` := `e.trait.m_params` //auto monomorph_cb = monomorphise_type_get_cb(sp, &*e.type, &e.trait.m_params, nullptr); - + const auto& trait = this->m_crate.get_trait_by_path(sp, e.trait.m_path); const auto& assoc_ty = trait.m_types.at( e.item ); // NOTE: The bounds here have 'Self' = the type @@ -3404,12 +3404,12 @@ bool TraitResolution::find_method( if( !this->trait_contains_method(sp, bound.m_path, *bound.m_trait_ptr, ::HIR::TypeRef("Self", 0xFFFF), method_name, ar, final_trait_path) ) continue ; DEBUG("- Found trait " << 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); } - + // Found the method, return the UFCS path for it fcn_path = ::HIR::Path( ::HIR::Path::Data::make_UfcsKnown({ box$( ty.clone() ), @@ -3419,16 +3419,16 @@ bool TraitResolution::find_method( }) ); return true; } - + // Search `<Self as Trait>::Name` bounds on the trait itself for(const auto& bound : trait.m_params.m_bounds) { if( ! bound.is_TraitBound() ) continue ; const auto& be = bound.as_TraitBound(); - + if( ! be.type.m_data.is_Path() ) continue ; if( ! be.type.m_data.as_Path().binding.is_Opaque() ) continue ; - + const auto& be_type_pe = be.type.m_data.as_Path().path.m_data.as_UfcsKnown(); if( *be_type_pe.type != ::HIR::TypeRef("Self", 0xFFFF) ) continue ; @@ -3436,17 +3436,17 @@ bool TraitResolution::find_method( continue ; if( be_type_pe.item != e.item ) continue ; - + ::HIR::GenericPath final_trait_path; if( !this->trait_contains_method(sp, be.trait.m_path, *be.trait.m_trait_ptr, ::HIR::TypeRef("Self", 0xFFFF), method_name, ar, final_trait_path) ) continue ; DEBUG("- Found trait " << 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); } - + // Found the method, return the UFCS path for it fcn_path = ::HIR::Path( ::HIR::Path::Data::make_UfcsKnown({ box$( ty.clone() ), @@ -3495,18 +3495,18 @@ bool TraitResolution::find_method( return true; } } - + // 3. Search for trait methods (using currently in-scope traits) for(const auto& trait_ref : ::reverse(traits)) { if( trait_ref.first == nullptr ) break; - + //::HIR::GenericPath final_trait_path; //if( !this->trait_contains_method(sp, *trait_ref.first, *trait_ref.second, method_name, final_trait_path) ) // continue ; //DEBUG("- Found trait " << final_trait_path); - + // TODO: Shouldn't this use trait_contains_method? // TODO: Search supertraits too auto it = trait_ref.second->m_values.find(method_name); @@ -3531,7 +3531,7 @@ bool TraitResolution::find_method( if( ar == AllowedReceivers::Value || ar == AllowedReceivers::Box || (v.m_receiver == ::HIR::Function::Receiver::Box && ar != AllowedReceivers::AnyBorrow) ) break; DEBUG("Search for impl of " << *trait_ref.first); - + // Use the set of ivars we were given to populate the trait parameters unsigned int n_params = trait_ref.second->m_params.m_types.size(); assert(n_params <= ivars.size()); @@ -3541,7 +3541,7 @@ bool TraitResolution::find_method( trait_params.m_types.push_back( ::HIR::TypeRef( ::HIR::TypeRef::Data::make_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( find_trait_impls(sp, *trait_ref.first, trait_params, ty, [](auto , auto ) { return true; }) ) { if( find_trait_impls_crate(sp, *trait_ref.first, &trait_params, ty, [](auto , auto ) { return true; }) ) { DEBUG("Found trait impl " << *trait_ref.first << trait_params << " for " << ty << " ("<<m_ivars.fmt_type(ty)<<")"); @@ -3556,7 +3556,7 @@ bool TraitResolution::find_method( break; } } - + return false; } @@ -3569,7 +3569,7 @@ unsigned int TraitResolution::autoderef_find_field(const Span& sp, const ::HIR:: current_ty = &*e.inner; deref_count += 1; ) - + do { const auto& ty = this->m_ivars.get_type(*current_ty); if( ty.m_data.is_Infer() ) { @@ -3578,24 +3578,24 @@ unsigned int TraitResolution::autoderef_find_field(const Span& sp, const ::HIR:: if(ty.m_data.is_Path() && ty.m_data.as_Path().binding.is_Unbound()) { return ~0u; } - + if( this->find_field(sp, ty, field_name, field_type) ) { return deref_count; } - + // 3. Dereference and try again deref_count += 1; current_ty = this->autoderef(sp, ty, tmp_type); } while( current_ty ); - + TU_IFLET(::HIR::TypeRef::Data, this->m_ivars.get_type(top_ty).m_data, Borrow, e, const auto& ty = this->m_ivars.get_type(top_ty); - + if( find_field(sp, ty, field_name, field_type) ) { return 0; } ) - + // Dereference failed! This is a hard error (hitting _ is checked above and returns ~0) this->m_ivars.dump(); TODO(sp, "Error when no field could be found, but type is known - (: " << top_ty << ")." << field_name); @@ -3673,7 +3673,7 @@ bool TraitResolution::find_field(const Span& sp, const ::HIR::TypeRef& ty, const } return gt; }; - + for( const auto& fld : unm.m_variants ) { // TODO: Privacy diff --git a/src/hir_typeck/helpers.hpp b/src/hir_typeck/helpers.hpp index 9bf8d4d9..19235a8e 100644 --- a/src/hir_typeck/helpers.hpp +++ b/src/hir_typeck/helpers.hpp @@ -45,22 +45,22 @@ public: // ?? - Needed once, anymore? { unsigned int alias; // If not ~0, this points to another ivar ::std::unique_ptr< ::HIR::TypeRef> type; // Type (only nullptr if alias!=0) - + IVar(): alias(~0u), type(new ::HIR::TypeRef()) {} bool is_alias() const { return alias != ~0u; } }; - + ::std::vector< IVar> m_ivars; bool m_has_changed; - + public: HMTypeInferrence(): m_has_changed(false) {} - + bool peek_changed() const { return m_has_changed; } @@ -75,36 +75,36 @@ public: m_has_changed = true; } } - + void compact_ivars(); bool apply_defaults(); - + void dump() const; - + void print_type(::std::ostream& os, const ::HIR::TypeRef& tr) const; void print_pathparams(::std::ostream& os, const ::HIR::PathParams& pps) const; - + FmtType fmt_type(const ::HIR::TypeRef& tr) const { return FmtType(*this, tr); } FmtPP fmt(const ::HIR::PathParams& v) const { return FmtPP(*this, v); } - + /// Add (and bind) all '_' types in `type` void add_ivars(::HIR::TypeRef& type); // (helper) Add ivars to path parameters void add_ivars_params(::HIR::PathParams& params); - + ::std::function<const ::HIR::TypeRef&(const ::HIR::TypeRef&)> callback_resolve_infer() const { return [&](const auto& ty)->const auto& { - if( ty.m_data.is_Infer() ) + if( ty.m_data.is_Infer() ) return this->get_type(ty); else return ty; }; } - + // Mutation unsigned int new_ivar(); ::HIR::TypeRef new_ivar_tr(); @@ -114,7 +114,7 @@ public: // Lookup ::HIR::TypeRef& get_type(::HIR::TypeRef& type); const ::HIR::TypeRef& get_type(const ::HIR::TypeRef& type) const; - + void check_for_loops(); void expand_ivars(::HIR::TypeRef& type); void expand_ivars_params(::HIR::PathParams& params); @@ -131,13 +131,13 @@ private: class TraitResolution { const HMTypeInferrence& m_ivars; - + const ::HIR::Crate& m_crate; const ::HIR::GenericParams* m_impl_params; const ::HIR::GenericParams* m_item_params; - + ::std::map< ::HIR::TypeRef, ::HIR::TypeRef> m_type_equalities; - + ::HIR::SimplePath m_lang_Box; mutable ::std::vector< ::HIR::TypeRef> m_eat_active_stack; public: @@ -150,7 +150,7 @@ public: prep_indexes(); m_lang_Box = crate.get_lang_item_path_opt("owned_box"); } - + const ::HIR::GenericParams& impl_params() const { static ::HIR::GenericParams empty; return m_impl_params ? *m_impl_params : empty; @@ -159,16 +159,16 @@ public: static ::HIR::GenericParams empty; return m_item_params ? *m_item_params : empty; } - + void prep_indexes(); - + ::HIR::Compare compare_pp(const Span& sp, const ::HIR::PathParams& left, const ::HIR::PathParams& right) const; - + void compact_ivars(HMTypeInferrence& m_ivars); - + /// Check if a trait bound applies, using the passed function to expand Generic/Infer types bool check_trait_bound(const Span& sp, const ::HIR::TypeRef& type, const ::HIR::GenericPath& trait, t_cb_generic placeholder) const; - + bool has_associated_type(const ::HIR::TypeRef& ty) const; /// Expand any located associated types in the input, operating in-place and returning the result ::HIR::TypeRef expand_associated_types(const Span& sp, ::HIR::TypeRef input) const { @@ -184,16 +184,16 @@ public: return input; } } - + /// Iterate over in-scope bounds (function then top) bool iterate_bounds( ::std::function<bool(const ::HIR::GenericBound&)> cb) const; typedef ::std::function<bool(const ::HIR::TypeRef&, const ::HIR::PathParams&, const ::std::map< ::std::string,::HIR::TypeRef>&)> t_cb_trait_impl; typedef ::std::function<bool(ImplRef, ::HIR::Compare)> 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; - + /// Locate a named trait in the provied trait (either itself or as a parent trait) bool find_named_trait_in_trait(const Span& sp, const ::HIR::SimplePath& des, const ::HIR::PathParams& params, @@ -209,7 +209,7 @@ 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; - + 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; ::HIR::Compare ftic_check_params(const Span& sp, const ::HIR::SimplePath& trait, @@ -218,7 +218,7 @@ private: /*Out->*/ ::std::vector< const ::HIR::TypeRef*>& impl_params, ::std::vector< ::HIR::TypeRef>& placeholders ) const ; public: - + enum class AutoderefBorrow { None, Shared, @@ -231,10 +231,10 @@ public: /// 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; - + /// 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; enum class AllowedReceivers { @@ -245,7 +245,7 @@ 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<unsigned>& ivars, const ::HIR::TypeRef& ty, const ::std::string& method_name, AllowedReceivers ar, /* Out -> */::HIR::Path& fcn_path) 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, AllowedReceivers ar, ::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; diff --git a/src/hir_typeck/impl_ref.cpp b/src/hir_typeck/impl_ref.cpp index abda820e..73472c16 100644 --- a/src/hir_typeck/impl_ref.cpp +++ b/src/hir_typeck/impl_ref.cpp @@ -127,7 +127,7 @@ bool ImplRef::type_is_specialisable(const char* name) const if( e.impl == nullptr ) { BUG(Span(), "nullptr"); } - + return monomorphise_path_params_with(sp, e.impl->m_trait_args, this->get_cb_monomorph_traitimpl(sp), true); ), (BoundedPtr, diff --git a/src/hir_typeck/impl_ref.hpp b/src/hir_typeck/impl_ref.hpp index bbff0054..dc5378fd 100644 --- a/src/hir_typeck/impl_ref.hpp +++ b/src/hir_typeck/impl_ref.hpp @@ -29,9 +29,9 @@ struct ImplRef ::std::map< ::std::string, ::HIR::TypeRef> assoc; }) ); - + Data m_data; - + ImplRef(): m_data(Data::make_TraitImpl({ {}, {}, nullptr, nullptr })) {} @@ -45,13 +45,13 @@ struct ImplRef ImplRef(::HIR::TypeRef type, ::HIR::PathParams args, ::std::map< ::std::string, ::HIR::TypeRef> assoc): m_data(Data::make_Bounded({ mv$(type), mv$(args), mv$(assoc) })) {} - + bool is_valid() const { return !(m_data.is_TraitImpl() && m_data.as_TraitImpl().impl == nullptr); } - + bool more_specific_than(const ImplRef& other) const; - + bool has_magic_params() const { TU_IFLET(Data, m_data, TraitImpl, e, for(const auto& t : e.params_ph) @@ -60,17 +60,17 @@ struct ImplRef ) return false; } - + /// HELPER: Returns callback to monomorphise a type using parameters from Data::TraitImpl ::std::function<const ::HIR::TypeRef&(const ::HIR::TypeRef&)> get_cb_monomorph_traitimpl(const Span& sp) const; - + ::HIR::TypeRef get_impl_type() const; ::HIR::PathParams get_trait_params() const; - + ::HIR::TypeRef get_trait_ty_param(unsigned int) const; - + bool type_is_specialisable(const char* name) const; ::HIR::TypeRef get_type(const char* name) const; - + friend ::std::ostream& operator<<(::std::ostream& os, const ImplRef& x); }; diff --git a/src/hir_typeck/outer.cpp b/src/hir_typeck/outer.cpp index ed2063d4..5f5e5a75 100644 --- a/src/hir_typeck/outer.cpp +++ b/src/hir_typeck/outer.cpp @@ -10,14 +10,14 @@ #include <hir_typeck/static.hpp> namespace { - + const ::HIR::GenericParams& get_params_for_item(const Span& sp, const ::HIR::Crate& crate, const ::HIR::SimplePath& path, ::HIR::Visitor::PathContext pc) { switch( pc ) { case ::HIR::Visitor::PathContext::VALUE: { const auto& item = crate.get_valitem_by_path(sp, path); - + TU_MATCH( ::HIR::ValueItem, (item), (e), (Import, BUG(sp, "Value path pointed to import - " << path << " = " << e.path); @@ -44,7 +44,7 @@ namespace { // TODO: treat PathContext::TRAIT differently case ::HIR::Visitor::PathContext::TYPE: { const auto& item = crate.get_typeitem_by_path(sp, path); - + TU_MATCH( ::HIR::TypeItem, (item), (e), (Import, BUG(sp, "Type path pointed to import - " << path); @@ -71,25 +71,25 @@ namespace { } break; } throw ""; - + } - + class Visitor: public ::HIR::Visitor { ::HIR::Crate& crate; StaticTraitResolve m_resolve; - + const ::HIR::Trait* m_current_trait = nullptr; const ::HIR::ItemPath* m_current_trait_path = nullptr; - - + + ::HIR::ItemPath* m_fcn_path = nullptr; ::HIR::Function* m_fcn_ptr = nullptr; unsigned int m_fcn_erased_count = 0; - + ::std::vector< ::HIR::TypeRef* > m_self_types; - + typedef ::std::vector< ::std::pair< const ::HIR::SimplePath*, const ::HIR::Trait* > > t_trait_imports; t_trait_imports m_traits; public: @@ -98,12 +98,12 @@ namespace { m_resolve(crate) { } - + private: struct ModTraitsGuard { Visitor* v; t_trait_imports old_imports; - + ~ModTraitsGuard() { this->v->m_traits = mv$(this->old_imports); } @@ -118,7 +118,7 @@ namespace { } return rv; } - + void update_self_type(const Span& sp, ::HIR::TypeRef& ty) const { struct H { @@ -127,7 +127,7 @@ namespace { self.update_self_type(sp, typ); } }; - + TU_MATCH(::HIR::TypeRef::Data, (ty.m_data), (e), (Generic, if(e.name == "Self") { @@ -139,7 +139,7 @@ namespace { return; } ), - + (Infer, ), (Diverge, @@ -200,17 +200,17 @@ namespace { void check_parameters(const Span& sp, const ::HIR::GenericParams& param_def, ::HIR::PathParams& param_vals) { while( param_vals.m_types.size() < param_def.m_types.size() ) { - unsigned int i = param_vals.m_types.size(); + unsigned int i = param_vals.m_types.size(); if( param_def.m_types[i].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() ); auto& ty = param_vals.m_types.back(); update_self_type(sp, ty); } - + if( param_vals.m_types.size() != param_def.m_types.size() ) { ERROR(sp, E0000, "Incorrect number of parameters - expected " << param_def.m_types.size() << ", got " << param_vals.m_types.size()); } @@ -225,7 +225,7 @@ namespace { update_self_type(sp, param_vals.m_types[i]); } } - + // TODO: Check generic bounds for( const auto& bound : param_def.m_bounds ) { @@ -246,14 +246,14 @@ namespace { ) } } - + public: void visit_type(::HIR::TypeRef& ty) override { static Span _sp; const Span& sp = _sp; ::HIR::Visitor::visit_type(ty); - + TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Path, e, TU_MATCH( ::HIR::Path::Data, (e.path.m_data), (pe), (Generic, @@ -270,7 +270,7 @@ namespace { ) ) ) - + // If an ErasedType is encountered, check if it has an origin set. TU_IFLET(::HIR::TypeRef::Data, ty.m_data, ErasedType, e, if( e.m_origin == ::HIR::SimplePath() ) @@ -278,7 +278,7 @@ namespace { // If not, ensure taht we're checking a function return type, and error if not if( ! m_fcn_path ) ERROR(sp, E0000, "Use of an erased type outside of a function return - " << ty); - + ::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)); @@ -294,20 +294,20 @@ namespace { } ) } - + void visit_generic_path(::HIR::GenericPath& p, PathContext pc) override { static Span sp; TRACE_FUNCTION_F("p = " << p); const auto& params = get_params_for_item(sp, crate, p.m_path, pc); auto& args = p.m_params; - + check_parameters(sp, params, args); DEBUG("p = " << p); - + ::HIR::Visitor::visit_generic_path(p, pc); } - + private: bool locate_trait_item_in_bounds(const Span& sp, ::HIR::Visitor::PathContext pc, const ::HIR::TypeRef& tr, const ::HIR::GenericParams& params, ::HIR::Path::Data& pd) { //const auto& name = pd.as_UfcsUnknown().item; @@ -322,7 +322,7 @@ namespace { } } ); - // - + // - } return false; } @@ -333,7 +333,7 @@ namespace { 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: @@ -370,12 +370,12 @@ namespace { } bool locate_in_trait_impl_and_set(::HIR::Visitor::PathContext pc, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait, ::HIR::Path::Data& pd) { static Span sp; - + auto& e = pd.as_UfcsUnknown(); //if( this->m_resolve.trait_contains_type(sp, trait_path, trait, e.item, out_path) ) if( this->locate_item_in_trait(pc, trait, pd) ) { const auto& type = *e.type; - + return this->crate.find_trait_impls(trait_path.m_path, type, [](const auto& x)->const auto&{return x;}, [&](const auto& impl) { DEBUG("FOUND impl" << impl.m_params.fmt_args() << " " << trait_path.m_path << impl.m_trait_args << " for " << impl.m_type); // TODO: Check bounds @@ -390,8 +390,8 @@ namespace { else { DEBUG("- Item " << e.item << " not in trait " << trait_path.m_path); } - - + + // Search supertraits (recursively) for( unsigned int i = 0; i < trait.m_parent_traits.size(); i ++ ) { @@ -417,10 +417,10 @@ namespace { { TRACE_FUNCTION_FR("UfcsUnknown - p=" << p, p); auto& e = p.m_data.as_UfcsUnknown(); - + this->visit_type( *e.type ); this->visit_path_params( e.params ); - + // Search for matching impls in current generic blocks if( m_resolve.m_item_generics != nullptr && locate_trait_item_in_bounds(sp, pc, *e.type, *m_resolve.m_item_generics, p.m_data) ) { return ; @@ -428,7 +428,7 @@ namespace { if( m_resolve.m_impl_generics != nullptr && locate_trait_item_in_bounds(sp, pc, *e.type, *m_resolve.m_impl_generics, p.m_data) ) { return ; } - + TU_IFLET(::HIR::TypeRef::Data, e.type->m_data, Generic, te, // 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? @@ -466,7 +466,7 @@ namespace { case ::HIR::Visitor::PathContext::TYPE: continue ; } - + auto new_data = ::HIR::Path::Data::make_UfcsInherent({ mv$(e.type), mv$(e.item), mv$(e.params)} ); p.m_data = mv$(new_data); DEBUG("- Resolved, replace with " << p); @@ -476,7 +476,7 @@ namespace { for( const auto& trait_info : m_traits ) { const auto& trait = *trait_info.second; - + switch(pc) { case ::HIR::Visitor::PathContext::VALUE: @@ -490,12 +490,12 @@ namespace { break; } DEBUG("- Trying trait " << *trait_info.first); - + auto trait_path = ::HIR::GenericPath( *trait_info.first ); for(unsigned int i = 0; i < trait.m_params.m_types.size(); i ++ ) { trait_path.m_params.m_types.push_back( ::HIR::TypeRef() ); } - + // TODO: Search supertraits // TODO: Should impls be searched first, or item names? // - Item names add complexity, but impls are slower @@ -504,11 +504,11 @@ namespace { } } } - + // Couldn't find it ERROR(sp, E0000, "Failed to find impl with '" << e.item << "' for " << *e.type << " (in " << p << ")"); } - + public: void visit_path(::HIR::Path& p, ::HIR::Visitor::PathContext pc) override { @@ -533,12 +533,12 @@ namespace { ) ) } - + void visit_params(::HIR::GenericParams& params) override { for(auto& tps : params.m_types) this->visit_type( tps.m_default ); - + for(auto& bound : params.m_bounds ) { TU_MATCH(::HIR::GenericBound, (bound), (e), @@ -564,24 +564,24 @@ namespace { ) } } - + void visit_module(::HIR::ItemPath p, ::HIR::Module& mod) override { auto _ = this->push_mod_traits( mod ); ::HIR::Visitor::visit_module(p, mod); } - + void visit_trait(::HIR::ItemPath p, ::HIR::Trait& item) override { m_current_trait = &item; m_current_trait_path = &p; - + auto _ = m_resolve.set_impl_generics(item.m_params); ::HIR::TypeRef tr { "Self", 0xFFFF }; m_self_types.push_back(&tr); ::HIR::Visitor::visit_trait(p, item); m_self_types.pop_back(); - + m_current_trait = nullptr; } void visit_struct(::HIR::ItemPath p, ::HIR::Struct& item) override @@ -599,16 +599,16 @@ namespace { auto _ = m_resolve.set_item_generics(item.m_params); ::HIR::Visitor::visit_enum(p, item); } - + void visit_type_impl(::HIR::TypeImpl& impl) override { TRACE_FUNCTION_F("impl " << impl.m_type); auto _ = m_resolve.set_impl_generics(impl.m_params); m_self_types.push_back( &impl.m_type ); - + ::HIR::Visitor::visit_type_impl(impl); // Check that the type is valid - + m_self_types.pop_back(); } void visit_trait_impl(const ::HIR::SimplePath& trait_path, ::HIR::TraitImpl& impl) override @@ -616,10 +616,10 @@ namespace { TRACE_FUNCTION_F("impl " << trait_path << " for " << impl.m_type); auto _ = m_resolve.set_impl_generics(impl.m_params); m_self_types.push_back( &impl.m_type ); - + ::HIR::Visitor::visit_trait_impl(trait_path, impl); // Check that the type+trait is valid - + m_self_types.pop_back(); } void visit_marker_impl(const ::HIR::SimplePath& trait_path, ::HIR::MarkerImpl& impl) override @@ -627,22 +627,22 @@ namespace { TRACE_FUNCTION_F("impl " << trait_path << " for " << impl.m_type << " { }"); auto _ = m_resolve.set_impl_generics(impl.m_params); m_self_types.push_back( &impl.m_type ); - + ::HIR::Visitor::visit_marker_impl(trait_path, impl); // Check that the type+trait is valid - + m_self_types.pop_back(); } - + void visit_function(::HIR::ItemPath p, ::HIR::Function& item) override { auto _ = m_resolve.set_item_generics(item.m_params); - + m_fcn_path = &p; m_fcn_ptr = &item; m_fcn_erased_count = 0; visit_type(item.m_return); m_fcn_path = nullptr; - + ::HIR::Visitor::visit_function(p, item); } }; diff --git a/src/hir_typeck/static.cpp b/src/hir_typeck/static.cpp index fdb1a685..eba58331 100644 --- a/src/hir_typeck/static.cpp +++ b/src/hir_typeck/static.cpp @@ -11,15 +11,15 @@ void StaticTraitResolve::prep_indexes() { static Span sp_AAA; const Span& sp = sp_AAA; - + TRACE_FUNCTION_F(""); - + 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) )); }; - + this->iterate_bounds([&](const auto& b) { TU_MATCH_DEF(::HIR::GenericBound, (b), (be), ( @@ -30,10 +30,10 @@ void StaticTraitResolve::prep_indexes() DEBUG("[prep_indexes] Equality (TB) - <" << be.type << " as " << be.trait.m_path << ">::" << tb.first << " = " << tb.second); auto ty_l = ::HIR::TypeRef( ::HIR::Path( be.type.clone(), be.trait.m_path.clone(), tb.first ) ); ty_l.m_data.as_Path().binding = ::HIR::TypeRef::TypePathBinding::make_Opaque({}); - + add_equality( mv$(ty_l), tb.second.clone() ); } - + const auto& trait_params = be.trait.m_path.m_params; auto cb_mono = [&](const auto& ty)->const auto& { const auto& ge = ty.m_data.as_Generic(); @@ -49,7 +49,7 @@ void StaticTraitResolve::prep_indexes() BUG(sp, "Unknown generic binding " << ty); } }; - + const auto& trait = m_crate.get_trait_by_path(sp, be.trait.m_path.m_path); for(const auto& a_ty : trait.m_types) { @@ -63,10 +63,10 @@ void StaticTraitResolve::prep_indexes() ty_a.m_data.as_Path().binding = ::HIR::TypeRef::TypePathBinding::make_Opaque({}); } DEBUG("[prep_indexes] Equality (ATB) - <" << ty_a << " as " << a_ty_b.m_path << ">::" << tb.first << " = " << tb.second); - + auto ty_l = ::HIR::TypeRef( ::HIR::Path( ty_a.clone(), trait_mono.m_path.clone(), tb.first ) ); ty_l.m_data.as_Path().binding = ::HIR::TypeRef::TypePathBinding::make_Opaque({}); - + add_equality( mv$(ty_l), mv$(tb.second) ); } } @@ -91,10 +91,10 @@ bool StaticTraitResolve::find_impl( { TRACE_FUNCTION_F(trait_path << FMT_CB(os, if(trait_params) { os << *trait_params; } else { os << "<?>"; }) << " for " << type); auto cb_ident = [](const auto&ty)->const auto&{return ty;}; - + static ::HIR::PathParams null_params; static ::std::map< ::std::string, ::HIR::TypeRef> null_assoc; - + if( !dont_handoff_to_specialised ) { if( trait_path == m_lang_Copy ) { if( this->type_is_copy(sp, type) ) { @@ -112,7 +112,7 @@ bool StaticTraitResolve::find_impl( // } //} } - + // --- MAGIC IMPLS --- // TODO: There should be quite a few more here, but laziness TU_IFLET(::HIR::TypeRef::Data, type.m_data, Function, e, @@ -139,7 +139,7 @@ bool StaticTraitResolve::find_impl( return found_cb( ImplRef(type.clone(), trait_params->clone(), mv$(assoc)), false ); } ) - + // ---- // TraitObject traits and supertraits // ---- @@ -162,7 +162,7 @@ bool StaticTraitResolve::find_impl( } } } - + // - Check if the desired trait is a supertrait of this. // TODO: What if `trait_params` is nullptr? bool rv = false; @@ -193,7 +193,7 @@ bool StaticTraitResolve::find_impl( { return found_cb( ImplRef(&type, &trait.m_path.m_params, &trait.m_type_bounds), false ); } - + // TODO: What if `trait_params` is nullptr? bool rv = false; 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, @@ -216,7 +216,7 @@ bool StaticTraitResolve::find_impl( } } ) - + // --- // If this type is an opaque UfcsKnown - check bounds // --- @@ -225,12 +225,12 @@ bool StaticTraitResolve::find_impl( { 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(); - + // If this associated type has a bound of the desired trait, return it. const auto& trait_ref = m_crate.get_trait_by_path(sp, pe.trait.m_path); ASSERT_BUG(sp, trait_ref.m_types.count( pe.item ) != 0, "Trait " << pe.trait.m_path << " doesn't contain an associated type " << pe.item); const auto& aty_def = trait_ref.m_types.find(pe.item)->second; - + auto monomorph_cb = monomorphise_type_get_cb(sp, &*pe.type, &pe.trait.m_params, nullptr, nullptr); for(const auto& bound : aty_def.m_trait_bounds) @@ -238,7 +238,7 @@ bool StaticTraitResolve::find_impl( 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); - + if( bound.m_path.m_path == trait_path ) { if( !trait_params || b_params_mono == *trait_params ) @@ -256,7 +256,7 @@ bool StaticTraitResolve::find_impl( } } } - + bool ret = trait_params && this->find_named_trait_in_trait(sp, trait_path, *trait_params, *bound.m_trait_ptr, bound.m_path.m_path, b_params_mono, type, [&](const auto& i_params, const auto& i_assoc) { if( i_params != *trait_params ) @@ -270,9 +270,9 @@ bool StaticTraitResolve::find_impl( } ) // --- /UfcsKnown --- - + bool ret; - + // TODO: A bound can imply something via its associated types. How deep can this go? // E.g. `T: IntoIterator<Item=&u8>` implies `<T as IntoIterator>::IntoIter : Iterator<Item=&u8>` ret = this->iterate_bounds([&](const auto& b) { @@ -280,7 +280,7 @@ bool StaticTraitResolve::find_impl( }); if(ret) return true; - + if( m_crate.get_trait_by_path(sp, trait_path).m_is_marker ) { // Positive/negative impls @@ -303,7 +303,7 @@ bool StaticTraitResolve::find_impl( }); if(ret) return rv; - + // Detect recursion and return true if detected static ::std::vector< ::std::tuple< const ::HIR::SimplePath*, const ::HIR::PathParams*, const ::HIR::TypeRef*> > stack; for(const auto& ent : stack ) { @@ -313,7 +313,7 @@ bool StaticTraitResolve::find_impl( continue ; if( *::std::get<2>(ent) != type ) continue ; - + return found_cb( ImplRef(&type, trait_params, &null_assoc), false ); } stack.push_back( ::std::make_tuple( &trait_path, trait_params, &type ) ); @@ -321,7 +321,7 @@ bool StaticTraitResolve::find_impl( ~Guard() { stack.pop_back(); } }; Guard _; - + auto cmp = this->check_auto_trait_impl_destructure(sp, trait_path, trait_params, type); if( cmp != ::HIR::Compare::Unequal ) return found_cb( ImplRef(&type, trait_params, &null_assoc), cmp == ::HIR::Compare::Fuzzy ); @@ -335,7 +335,7 @@ bool StaticTraitResolve::find_impl( }); if(ret) return true; - + return false; } } @@ -357,15 +357,15 @@ bool StaticTraitResolve::find_impl__check_bound( } } return true; - } + } }; - + // Can only get good information out of TraitBound if( !bound.is_TraitBound() ) { return false; } const auto& e = bound.as_TraitBound(); - + // Obtain a pointer to UfcsKnown for magic later const ::HIR::Path::Data::Data_UfcsKnown* assoc_info = nullptr; TU_IFLET(::HIR::TypeRef::Data, type.m_data, Path, e, @@ -373,7 +373,7 @@ bool StaticTraitResolve::find_impl__check_bound( assoc_info = &pe; ) ) - + const auto& b_params = e.trait.m_path.m_params; DEBUG("(bound) - " << e.type << " : " << e.trait); if( e.type == type ) @@ -409,17 +409,17 @@ bool StaticTraitResolve::find_impl__check_bound( 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 && H::compare_pp(sp, b_params, assoc_info->trait.m_params) ) { - + 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_path && (!trait_params || H::compare_pp(sp, bound.m_path.m_params, *trait_params)) ) { DEBUG("- Found an associated type impl"); - + auto tp_mono = monomorphise_traitpath_with(sp, bound, [&assoc_info,&sp](const auto& gt)->const auto& { const auto& ge = gt.m_data.as_Generic(); if( ge.binding == 0xFFFF ) { @@ -443,7 +443,7 @@ bool StaticTraitResolve::find_impl__check_bound( } } } - + return false; } @@ -456,10 +456,10 @@ bool StaticTraitResolve::find_impl__check_crate_raw( { auto cb_ident = [](const auto&ty)->const auto&{return ty;}; DEBUG("impl" << impl_params_def.fmt_args() << " " << des_trait_path << impl_trait_params << " for " << impl_type << impl_params_def.fmt_bounds()); - + ::std::vector< const ::HIR::TypeRef*> impl_params; impl_params.resize( impl_params_def.m_types.size() ); - + auto cb = [&impl_params,&sp,cb_ident](auto idx, const auto& ty) { assert( idx < impl_params.size() ); if( ! impl_params[idx] ) { @@ -485,7 +485,7 @@ bool StaticTraitResolve::find_impl__check_crate_raw( DEBUG(" > Type mismatch"); return false; } - + ::std::vector< ::HIR::TypeRef> placeholders; for(unsigned int i = 0; i < impl_params.size(); i ++ ) { if( !impl_params[i] ) { @@ -525,7 +525,7 @@ bool StaticTraitResolve::find_impl__check_crate_raw( } return *impl_params[ge.binding]; }; - + // Bounds for(const auto& bound : impl_params_def.m_bounds) { TU_MATCH_DEF(::HIR::GenericBound, (bound), (e), @@ -548,17 +548,17 @@ bool StaticTraitResolve::find_impl__check_crate_raw( if( b_ty_mono.m_data.is_Infer() ) { continue ; } - + // TODO: This is extrememly inefficient (looks up the trait impl 1+N times) if( b_tp_mono.m_type_bounds.size() > 0 ) { // for(const auto& assoc_bound : b_tp_mono.m_type_bounds) { const auto& aty_name = assoc_bound.first; 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); - + bool rv = false; if( b_ty_mono.m_data.is_Generic() && (b_ty_mono.m_data.as_Generic().binding >> 8) == 2 ) { DEBUG("- Placeholder param " << b_ty_mono << ", magic success"); @@ -568,7 +568,7 @@ bool StaticTraitResolve::find_impl__check_crate_raw( rv = this->find_impl(sp, aty_src_trait.m_path, aty_src_trait.m_params, b_ty_mono, [&](const auto& impl, bool) { ::HIR::TypeRef have = impl.get_type(aty_name.c_str()); this->expand_associated_types(sp, have); - + //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); ASSERT_BUG(sp, cmp == ::HIR::Compare::Equal, "Assoc ty " << aty_name << " mismatch, " << have << " != des " << exp); @@ -600,7 +600,7 @@ bool StaticTraitResolve::find_impl__check_crate_raw( ) ) } - + return found_cb( mv$(impl_params), mv$(placeholders), match ); } @@ -632,7 +632,7 @@ bool StaticTraitResolve::find_impl__check_crate( DEBUG("[check_auto_trait_impl_destructure] " << inner_ty << " - " << l_res); return l_res; }; - + // - 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, ::HIR::Compare res = ::HIR::Compare::Equal; @@ -662,7 +662,7 @@ bool StaticTraitResolve::find_impl__check_crate( return ty; } }; - + TU_MATCH( ::HIR::TypeRef::TypePathBinding, (e.binding), (tpb), (Opaque, BUG(sp, "Opaque binding on generic path - " << type); @@ -672,7 +672,7 @@ bool StaticTraitResolve::find_impl__check_crate( ), (Struct, const auto& str = *tpb; - + // TODO: Somehow store a ruleset for auto traits on the type // - Map of trait->does_impl for local fields? // - Problems occur with type parameters @@ -694,7 +694,7 @@ bool StaticTraitResolve::find_impl__check_crate( { const auto& fld_ty_mono = monomorph_get(fld.second.ent); DEBUG("Struct::Named '" << fld.first << "' " << fld_ty_mono); - + res &= type_impls_trait(fld_ty_mono); if( res == ::HIR::Compare::Unequal ) return ::HIR::Compare::Unequal; @@ -704,7 +704,7 @@ bool StaticTraitResolve::find_impl__check_crate( ), (Enum, const auto& enm = *tpb; - + for(const auto& var : enm.m_variants) { TU_MATCH(::HIR::Enum::Variant, (var.second), (ve), @@ -727,7 +727,7 @@ bool StaticTraitResolve::find_impl__check_crate( { const auto& fld_ty_mono = monomorph_get(fld.second.ent); DEBUG("Enum '" << var.first << "'::Struct '" << fld.first << "' " << fld_ty_mono); - + res &= type_impls_trait(fld_ty_mono); if( res == ::HIR::Compare::Unequal ) return ::HIR::Compare::Unequal; @@ -856,13 +856,13 @@ void StaticTraitResolve::expand_associated_types__UfcsKnown(const Span& sp, ::HI { auto& e = input.m_data.as_Path(); auto& e2 = e.path.m_data.as_UfcsKnown(); - + this->expand_associated_types_inner(sp, *e2.type); for(auto& arg : e2.trait.m_params.m_types) this->expand_associated_types_inner(sp, arg); - + DEBUG("Locating associated type for " << e.path); - + // - If it's a closure, then the only trait impls are those generated by typeck TU_IFLET(::HIR::TypeRef::Data, e2.type->m_data, Closure, te, //if( te.node->m_obj_path == ::HIR::GenericPath() ) @@ -885,7 +885,7 @@ void StaticTraitResolve::expand_associated_types__UfcsKnown(const Span& sp, ::HI // // TODO: Locate impl _without_ binding params too hard? //} ) - + // If it's a TraitObject, then maybe we're asking for a bound TU_IFLET(::HIR::TypeRef::Data, e2.type->m_data, TraitObject, te, const auto& data_trait = te.m_trait.m_path; @@ -898,13 +898,13 @@ void StaticTraitResolve::expand_associated_types__UfcsKnown(const Span& sp, ::HI // - Why opaque? It's not bounded, don't even bother TODO(sp, "Handle unconstrained associate type " << e2.item << " from " << *e2.type); } - + input = it->second.clone(); return ; } } ) - + // 1. Bounds bool rv; bool assume_opaque = true; @@ -933,7 +933,7 @@ void StaticTraitResolve::expand_associated_types__UfcsKnown(const Span& sp, ::HI } return true; } - + bool found_supertrait = this->find_named_trait_in_trait(sp, e2.trait.m_path, e2.trait.m_params, *be.trait.m_trait_ptr, be.trait.m_path.m_path, be.trait.m_path.m_params, *e2.type, @@ -962,7 +962,7 @@ void StaticTraitResolve::expand_associated_types__UfcsKnown(const Span& sp, ::HI } return true; } - + // - Didn't match ), (TypeEquality, @@ -979,7 +979,7 @@ void StaticTraitResolve::expand_associated_types__UfcsKnown(const Span& sp, ::HI if( assume_opaque ) { input.m_data.as_Path().binding = ::HIR::TypeRef::TypePathBinding::make_Opaque({}); DEBUG("Assuming that " << input << " is an opaque name"); - + this->replace_equalities(input); } this->expand_associated_types_inner(sp, input); @@ -994,7 +994,7 @@ void StaticTraitResolve::expand_associated_types__UfcsKnown(const Span& sp, ::HI // - Does simplification of complex associated types const auto& trait_ptr = this->m_crate.get_trait_by_path(sp, pe_inner.trait.m_path); const auto& assoc_ty = trait_ptr.m_types.at(pe_inner.item); - + // Resolve where Self=pe_inner.type (i.e. for the trait this inner UFCS is on) auto cb_placeholders_trait = [&](const auto& ty)->const auto&{ TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Generic, e, @@ -1038,7 +1038,7 @@ void StaticTraitResolve::expand_associated_types__UfcsKnown(const Span& sp, ::HI if( !this->trait_contains_type(sp, e2.trait, this->m_crate.get_trait_by_path(sp, e2.trait.m_path), e2.item, trait_path) ) BUG(sp, "Cannot find associated type " << e2.item << " anywhere in trait " << e2.trait); //e2.trait = mv$(trait_path); - + ::ImplRef best_impl; rv = this->find_impl(sp, trait_path.m_path, trait_path.m_params, *e2.type, [&](auto impl, bool fuzzy) { DEBUG("[expand_associated_types] Found " << impl); @@ -1047,7 +1047,7 @@ void StaticTraitResolve::expand_associated_types__UfcsKnown(const Span& sp, ::HI // - TODO: Move this logic into `find_impl` if( fuzzy ) { DEBUG("[expand_associated_types] - Fuzzy, monomorph+expand and recheck"); - + auto impl_ty = impl.get_impl_type(); this->expand_associated_types(sp, impl_ty); if(impl_ty != *e2.type) { @@ -1063,7 +1063,7 @@ void StaticTraitResolve::expand_associated_types__UfcsKnown(const Span& sp, ::HI } DEBUG("[expand_associated_types] - Fuzzy - Actually matches"); } - + if( impl.type_is_specialisable(e2.item.c_str()) ) { if( impl.more_specific_than(best_impl) ) { best_impl = mv$(impl); @@ -1095,7 +1095,7 @@ void StaticTraitResolve::expand_associated_types__UfcsKnown(const Span& sp, ::HI DEBUG("- Couldn't find a non-specialised impl of " << trait_path << " for " << *e2.type << " - treating as opaque"); return ; } - + ERROR(sp, E0000, "Cannot find an implementation of " << trait_path << " for " << *e2.type); } @@ -1139,7 +1139,7 @@ bool StaticTraitResolve::find_named_trait_in_trait(const Span& sp, if( pp.m_types.size() != trait_ptr.m_params.m_types.size() ) { BUG(sp, "Incorrect number of parameters for trait"); } - + auto monomorph_cb = [&](const auto& gt)->const auto& { const auto& ge = gt.m_data.as_Generic(); if( ge.binding == 0xFFFF ) { @@ -1151,7 +1151,7 @@ bool StaticTraitResolve::find_named_trait_in_trait(const Span& sp, return pp.m_types[ge.binding]; } }; - + for( const auto& pt : trait_ptr.m_parent_traits ) { auto pt_mono = monomorphise_traitpath_with(sp, pt, monomorph_cb, false); @@ -1161,19 +1161,19 @@ bool StaticTraitResolve::find_named_trait_in_trait(const Span& sp, callback( pt_mono.m_path.m_params, mv$(pt_mono.m_type_bounds) ); return true; } - + const auto& tr = m_crate.get_trait_by_path(sp, pt.m_path.m_path); if( find_named_trait_in_trait(sp, des, des_params, tr, pt.m_path.m_path, pt_mono.m_path.m_params, target_type, callback) ) { return true; } } - + // Also check bounds for `Self: T` bounds for(const auto& b : trait_ptr.m_params.m_bounds) { if( !b.is_TraitBound() ) continue; const auto& be = b.as_TraitBound(); - + if( be.type == ::HIR::TypeRef("Self", 0xFFFF) ) { // Something earlier adds a "Self: SelfTrait" bound, prevent that from causing infinite recursion @@ -1186,14 +1186,14 @@ bool StaticTraitResolve::find_named_trait_in_trait(const Span& sp, callback( pt_mono.m_path.m_params, mv$(pt_mono.m_type_bounds) ); return true; } - + const auto& tr = m_crate.get_trait_by_path(sp, pt_mono.m_path.m_path); if( find_named_trait_in_trait(sp, des, des_params, tr, pt_mono.m_path.m_path, pt_mono.m_path.m_params, target_type, callback) ) { return true; } } } - + 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 @@ -1203,7 +1203,7 @@ bool StaticTraitResolve::trait_contains_type(const Span& sp, const ::HIR::Generi out_path = trait_path.clone(); return true; } - + auto monomorph = [&](const auto& gt)->const auto& { const auto& ge = gt.m_data.as_Generic(); assert(ge.binding < 256); @@ -1375,12 +1375,12 @@ const ::HIR::TypeRef* StaticTraitResolve::is_type_owned_box(const ::HIR::TypeRef return nullptr; } const auto& te = ty.m_data.as_Path(); - + if( ! te.path.m_data.is_Generic() ) { return nullptr; } const auto& pe = te.path.m_data.as_Generic(); - + if( pe.m_path != m_lang_Box ) { return nullptr; } @@ -1393,12 +1393,12 @@ const ::HIR::TypeRef* StaticTraitResolve::is_type_phantom_data(const ::HIR::Type return nullptr; } const auto& te = ty.m_data.as_Path(); - + if( ! te.path.m_data.is_Generic() ) { return nullptr; } const auto& pe = te.path.m_data.as_Generic(); - + if( pe.m_path != m_lang_PhantomData ) { return nullptr; } diff --git a/src/hir_typeck/static.hpp b/src/hir_typeck/static.hpp index a823536e..66a65be5 100644 --- a/src/hir_typeck/static.hpp +++ b/src/hir_typeck/static.hpp @@ -15,11 +15,11 @@ class StaticTraitResolve { public: const ::HIR::Crate& m_crate; - + ::HIR::GenericParams* m_impl_generics; ::HIR::GenericParams* m_item_generics; - - + + ::std::map< ::HIR::TypeRef, ::HIR::TypeRef> m_type_equalities; ::HIR::SimplePath m_lang_Copy; @@ -31,7 +31,7 @@ public: ::HIR::SimplePath m_lang_FnOnce; ::HIR::SimplePath m_lang_Box; ::HIR::SimplePath m_lang_PhantomData; - + public: StaticTraitResolve(const ::HIR::Crate& crate): m_crate(crate), @@ -52,7 +52,7 @@ public: private: void prep_indexes(); - + public: bool has_self() const { return m_impl_generics ? true : false; @@ -65,7 +65,7 @@ public: static ::HIR::GenericParams empty; return m_item_generics ? *m_item_generics : empty; } - + /// \brief State manipulation /// \{ template<typename T> @@ -94,11 +94,11 @@ public: return NullOnDrop< ::HIR::GenericParams>(m_item_generics); } /// \} - + /// \brief Lookups /// \{ typedef ::std::function<bool(ImplRef, bool is_fuzzed)> t_cb_find_impl; - + bool find_impl( const Span& sp, const ::HIR::SimplePath& trait_path, const ::HIR::PathParams& trait_params, @@ -115,7 +115,7 @@ public: t_cb_find_impl found_cb, bool dont_handoff_to_specialised = false ) const; - + private: bool find_impl__check_bound( const Span& sp, @@ -154,7 +154,7 @@ private: public: /// \} - + /// Iterate over in-scope bounds (function then top) bool iterate_bounds( ::std::function<bool(const ::HIR::GenericBound&)> cb) const; @@ -165,16 +165,16 @@ public: const ::HIR::TypeRef& self_type, ::std::function<void(const ::HIR::PathParams&, ::std::map< ::std::string, ::HIR::TypeRef>)> callback ) 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; - - + + // -------------- // Common bounds // ------------- bool type_is_copy(const Span& sp, const ::HIR::TypeRef& ty) const; bool type_is_sized(const Span& sp, const ::HIR::TypeRef& ty) const; - + const ::HIR::TypeRef* is_type_owned_box(const ::HIR::TypeRef& ty) const; const ::HIR::TypeRef* is_type_phantom_data(const ::HIR::TypeRef& ty) const; }; diff --git a/src/ident.cpp b/src/ident.cpp index 45c96f2e..da029e21 100644 --- a/src/ident.cpp +++ b/src/ident.cpp @@ -20,7 +20,7 @@ bool Ident::Hygiene::is_visible(const Hygiene& src) const if( this->contexts.size() == 0 ) { return src.contexts.size() == 0; } - + auto des = this->contexts.back(); for(const auto& c : src.contexts) if( des == c ) diff --git a/src/include/debug.hpp b/src/include/debug.hpp index cb258bf5..ce2f89da 100644 --- a/src/include/debug.hpp +++ b/src/include/debug.hpp @@ -30,7 +30,7 @@ struct RepeatLitStr { const char *s; int n; - + friend ::std::ostream& operator<<(::std::ostream& os, const RepeatLitStr& r) { for(int i = 0; i < r.n; i ++ ) os << r.s; diff --git a/src/include/ident.hpp b/src/include/ident.hpp index 1122a68b..d702385c 100644 --- a/src/include/ident.hpp +++ b/src/include/ident.hpp @@ -14,9 +14,9 @@ struct Ident class Hygiene { static unsigned g_next_scope; - + ::std::vector<unsigned int> contexts; - + Hygiene(unsigned int index): contexts({index}) {} @@ -24,7 +24,7 @@ struct Ident Hygiene(): contexts({}) {} - + static Hygiene new_scope() { return Hygiene(++g_next_scope); @@ -37,23 +37,23 @@ struct Ident rv.contexts.push_back( ++g_next_scope ); return rv; } - + 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 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; } - + friend ::std::ostream& operator<<(::std::ostream& os, const Hygiene& v); }; - + Hygiene hygiene; ::std::string name; - + Ident(const char* name): hygiene(), name(name) @@ -65,20 +65,20 @@ struct Ident Ident(Hygiene hygiene, ::std::string name): hygiene(::std::move(hygiene)), name(::std::move(name)) { } - + Ident(Ident&& x) = default; Ident(const Ident& x) = default; Ident& operator=(Ident&& x) = default; Ident& operator=(const Ident& x) = default; - + ::std::string into_string() { return ::std::move(name); } - + bool operator==(const char* s) const { return this->name == s; } - + bool operator==(const Ident& x) const { if( this->name != x.name ) return false; @@ -90,6 +90,6 @@ struct Ident return !(*this == x); } bool operator<(const Ident& x) const; - + friend ::std::ostream& operator<<(::std::ostream& os, const Ident& x); }; diff --git a/src/include/rc_string.hpp b/src/include/rc_string.hpp index 630f8e89..fd230062 100644 --- a/src/include/rc_string.hpp +++ b/src/include/rc_string.hpp @@ -23,7 +23,7 @@ public: RcString(s.data(), s.size()) { } - + RcString(const RcString& x): m_ptr(x.m_ptr), m_len(x.m_len) @@ -37,9 +37,9 @@ public: x.m_ptr = nullptr; x.m_len = 0; } - + ~RcString(); - + RcString& operator=(const RcString& x) { if( &x != this ) @@ -63,8 +63,8 @@ public: } return *this; } - - + + const char* c_str() const { if( m_len > 0 ) { diff --git a/src/include/rustic.hpp b/src/include/rustic.hpp index 5d768152..93992f61 100644 --- a/src/include/rustic.hpp +++ b/src/include/rustic.hpp @@ -24,11 +24,11 @@ public: m_first(ptr), m_len(len) {} - + ::std::vector<T> to_vec() const { return ::std::vector<T>(begin(), end()); } - + unsigned int size() const { return m_len; } @@ -42,7 +42,7 @@ public: assert(ofs + len <= m_len); return slice { m_first + ofs, len }; } - + T* begin() const { return m_first; } T* end() const { return m_first + m_len; } @@ -73,7 +73,7 @@ class option { char m_data[ sizeof(T) ]; bool m_set; - + void* data_ptr() { return m_data; } const void* data_ptr() const { return m_data; } public: @@ -90,15 +90,15 @@ public: reinterpret_cast<T*>(data_ptr())->~T(); } } - + bool is_none() const { return !m_set; } bool is_some() const { return m_set; } - + const T& unwrap() const { assert(is_some()); return *reinterpret_cast<const T*>(m_data); } - + void if_set(::std::function<void (const T&)> f) const { if( m_set ) { return f(m_data); @@ -125,7 +125,7 @@ public: option(): m_ptr(nullptr) {} - + bool is_none() const { return m_ptr == nullptr; } bool is_some() const { return m_ptr != nullptr; } T& unwrap() const { diff --git a/src/include/serialise.hpp b/src/include/serialise.hpp index db311bb1..6a9abf95 100644 --- a/src/include/serialise.hpp +++ b/src/include/serialise.hpp @@ -19,7 +19,7 @@ class Deserialiser; #define SERIALISE_TYPE(method_prefix, tag_str, body, des_body) \ const char* method_prefix serialise_tag() const { return tag_str; } \ void method_prefix serialise(::Serialiser& s) const { body } \ - void method_prefix deserialise(::Deserialiser& s) { des_body } + void method_prefix deserialise(::Deserialiser& s) { des_body } #define SERIALISE_TYPE_A(method_prefix, tag_str, body) SERIALISE_TYPE(method_prefix, tag_str, body, body) #define SERIALISE_TYPE_S(class_, body) SERIALISE_TYPE(class_::, #class_, body, body) #define SERIALISE_TU(class_, tag_str, val_name, ...) SERIALISE_TYPE(class_::, tag_str,\ @@ -74,7 +74,7 @@ protected: public: template<typename T> inline void item(T& v) { *this << v; } - + virtual Serialiser& operator<<(bool val) = 0; virtual Serialiser& operator<<(uint64_t val) = 0; virtual Serialiser& operator<<(int64_t val) = 0; @@ -149,7 +149,7 @@ public: virtual void start_object(const char *tag) = 0; virtual void end_object(const char *tag) = 0; ::std::string start_object(); - + void item(Serialisable& v); Deserialiser& operator>>(Serialisable& v) { this->item(v); @@ -171,9 +171,9 @@ public: void item(::std::shared_ptr<T>& v) { bool present; - + item(present); - + if(present) { v.reset(new T); item(*v); @@ -186,9 +186,9 @@ public: void item(::std::unique_ptr<T>& v) { bool present; - + item(present); - + if(present) { v.reset( T::from_deserialiser(*this).release() ); } diff --git a/src/include/serialiser_texttree.hpp b/src/include/serialiser_texttree.hpp index bdad7d7a..7c86d326 100644 --- a/src/include/serialiser_texttree.hpp +++ b/src/include/serialiser_texttree.hpp @@ -16,13 +16,13 @@ class Serialiser_TextTree: bool m_array_was_empty; public: Serialiser_TextTree(::std::ostream& os); - + virtual Serialiser& operator<<(bool val) override; virtual Serialiser& operator<<(uint64_t val) override; virtual Serialiser& operator<<(int64_t val) override; virtual Serialiser& operator<<(double val) override; virtual Serialiser& operator<<(const char* s) override; - + protected: virtual void start_object(const char *tag) override; virtual void end_object(const char* tag) override; @@ -39,15 +39,15 @@ class Deserialiser_TextTree: public Deserialiser { ::std::istream& m_is; - + static bool is_ws(char c); char getc(); char peekc(); void eat_ws(); public: Deserialiser_TextTree(::std::istream& is); - -protected: + +protected: virtual size_t start_array() override; virtual void end_array() override; virtual ::std::string read_tag() override; diff --git a/src/include/span.hpp b/src/include/span.hpp index eafebb0a..11ffc005 100644 --- a/src/include/span.hpp +++ b/src/include/span.hpp @@ -24,19 +24,19 @@ class Position; struct ProtoSpan { RcString filename; - + unsigned int start_line; unsigned int start_ofs; }; struct Span { RcString filename; - + unsigned int start_line; unsigned int start_ofs; unsigned int end_line; unsigned int end_ofs; - + Span(RcString filename, unsigned int start_line, unsigned int start_ofs, unsigned int end_line, unsigned int end_ofs): filename( ::std::move(filename) ), start_line(start_line), @@ -47,12 +47,12 @@ struct Span Span(const Span& x); Span(const Position& position); Span(); - + void bug(::std::function<void(::std::ostream&)> msg) const; void error(ErrorType tag, ::std::function<void(::std::ostream&)> msg) const; void warning(WarningType tag, ::std::function<void(::std::ostream&)> msg) const; void note(::std::function<void(::std::ostream&)> msg) const; - + friend ::std::ostream& operator<<(::std::ostream& os, const Span& sp); }; diff --git a/src/include/synext_decorator.hpp b/src/include/synext_decorator.hpp index 0404889f..c3985855 100644 --- a/src/include/synext_decorator.hpp +++ b/src/include/synext_decorator.hpp @@ -18,14 +18,14 @@ namespace AST { struct StructItem; struct TupleItem; struct EnumVariant; - + class Module; class Item; - + class Expr; class ExprNode; struct ExprNode_Match_Arm; - + class ImplDef; } @@ -40,7 +40,7 @@ class ExpandDecorator void unexpected(const Span& sp, const AST::MetaItem& mi, const char* loc_str) const; public: virtual AttrStage stage() const = 0; - + virtual void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate) const { unexpected(sp, mi, "crate"); } virtual void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item&i) const { unexpected(sp, mi, "item"); } // NOTE: To delete, set the type to `_` @@ -51,7 +51,7 @@ public: virtual void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate, ::AST::TupleItem& si) const { unexpected(sp, mi, "tuple item"); } // NOTE: To delete, clear the name virtual void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate, ::AST::EnumVariant& ev) const { unexpected(sp, mi, "enum variant"); } - + virtual void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate, ::std::unique_ptr<AST::ExprNode>& expr) const { unexpected(sp, mi, "expression"); } // NOTE: To delete, clear the patterns vector virtual void handle(const Span& sp, const AST::MetaItem& mi, AST::Crate& crate, ::AST::ExprNode_Match_Arm& expr) const { unexpected(sp, mi, "match arm"); } diff --git a/src/include/tagged_union.hpp b/src/include/tagged_union.hpp index 0627b525..bb9c537e 100644 --- a/src/include/tagged_union.hpp +++ b/src/include/tagged_union.hpp @@ -19,7 +19,7 @@ #define TU_FIRST(a, ...) a // Argument iteration -#define _DISP0(n) +#define _DISP0(n) #define _DISP1(n, _1) n _1 #define _DISP2(n, _1, _2) n _1 n _2 #define _DISP3(n, v, v2, v3) n v n v2 n v3 @@ -37,7 +37,7 @@ #define _DISP15(n, a1,a2,a3,a4,a5, b1,b2,b3,b4,b5, c1,c2,c3,c4,c5) _DISP5(n, a1,a2,a3,a4,a5) _DISP5(n, b1,b2,b3,b4,b5) _DISP5(n, c1,c2,c3,c4,c5) #define _DISP16(n, a1,a2,a3,a4,a5, b1,b2,b3,b4,b5, c1,c2,c3,c4,c5, d1) _DISP5(n, a1,a2,a3,a4,a5) _DISP5(n, b1,b2,b3,b4,b5) _DISP5(n, c1,c2,c3,c4,c5) _DISP1(n, d1) -#define _DISPO0(n) +#define _DISPO0(n) #define _DISPO1(n, _1) n(_1) #define _DISPO2(n, _1, _2) n(_1) n(_2) #define _DISPO3(n, v, v2, v3) n(v) n(v2) n(v3) diff --git a/src/macro_rules/eval.cpp b/src/macro_rules/eval.cpp index 166dd2cc..11ec74f2 100644 --- a/src/macro_rules/eval.cpp +++ b/src/macro_rules/eval.cpp @@ -24,25 +24,25 @@ class ParameterMappings unsigned int num_used; // Number of times it has been used InterpolatedFragment frag; }; - + /// A single layer of the capture set TAGGED_UNION(CaptureLayer, Vals, (Vals, ::std::vector<CapturedVal>), (Nested, ::std::vector<CaptureLayer>) ); - + /// Represents the fragments captured for a name struct CapturedVar { CaptureLayer top_layer; - + friend ::std::ostream& operator<<(::std::ostream& os, const CapturedVar& x) { os << "CapturedVar { top_layer: " << x.top_layer << " }"; return os; } - + }; - + ::std::vector<CapturedVar> m_mappings; unsigned m_layer_count; public: @@ -51,28 +51,28 @@ public: { } ParameterMappings(ParameterMappings&&) = default; - + const ::std::vector<CapturedVar>& mappings() const { return m_mappings; } - + void dump() const { DEBUG("m_mappings = {" << m_mappings << "}"); } - + size_t layer_count() const { return m_layer_count+1; } - + void insert(unsigned int name_index, const ::std::vector<unsigned int>& iterations, InterpolatedFragment data); - + InterpolatedFragment* get(const ::std::vector<unsigned int>& iterations, unsigned int name_idx); unsigned int count_in(const ::std::vector<unsigned int>& iterations, unsigned int name_idx) const; - + /// Increment the number of times a particular fragment will be used void inc_count(const ::std::vector<unsigned int>& iterations, unsigned int name_idx); /// Decrement the number of times a particular fragment is used (returns true if there are still usages remaining) bool dec_count(const ::std::vector<unsigned int>& iterations, unsigned int name_idx); - - + + friend ::std::ostream& operator<<(::std::ostream& os, const CapturedVal& x) { os << x.frag; return os; @@ -88,7 +88,7 @@ public: ) return os; } - + private: CapturedVal& get_cap(const ::std::vector<unsigned int>& iterations, unsigned int name_idx); }; @@ -122,10 +122,10 @@ class MacroPatternStream ::std::vector<unsigned int> m_pos; // Iteration index of each active loop level ::std::vector<unsigned int> m_loop_iterations; - + ::std::vector<SimplePatEnt> m_stack; unsigned int m_skip_count; - + SimplePatEnt m_peek_cache; bool m_peek_cache_valid = false; @@ -137,10 +137,10 @@ public: m_pos({0}) { } - + /// Get the next pattern entry SimplePatEnt next(); - + const SimplePatEnt& peek() { if( !m_peek_cache_valid ) { m_peek_cache = next(); @@ -148,23 +148,23 @@ public: } return m_peek_cache; } - + /// Inform the stream that the `if` rule that was just returned succeeded void if_succeeded(); /// Get the current loop iteration count const ::std::vector<unsigned int>& get_loop_iters() const { 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; } - + void break_loop(); }; @@ -188,7 +188,7 @@ void ParameterMappings::insert(unsigned int name_index, const ::std::vector<unsi for(unsigned int i = 0; i < iterations.size()-1; i ++ ) { auto iter = iterations[i]; - + if( layer->is_Vals() ) { assert( layer->as_Vals().size() == 0 ); *layer = CaptureLayer::make_Nested({}); @@ -198,7 +198,7 @@ void ParameterMappings::insert(unsigned int name_index, const ::std::vector<unsi DEBUG("- Skipped iteration " << e.size()); e.push_back( CaptureLayer::make_Nested({}) ); } - + if(e.size() == iter) { e.push_back( CaptureLayer::make_Vals({}) ); } @@ -223,7 +223,7 @@ ParameterMappings::CapturedVal& ParameterMappings::get_cap(const ::std::vector<u auto& e = m_mappings.at(name_idx); //DEBUG("- e = " << e); auto* layer = &e.top_layer; - + // - If the top layer is a 1-sized set of values, unconditionally return it TU_IFLET(CaptureLayer, (*layer), Vals, e, if( e.size() == 1 ) { @@ -233,7 +233,7 @@ ParameterMappings::CapturedVal& ParameterMappings::get_cap(const ::std::vector<u BUG(Span(), "Attempting to get binding for empty capture - #" << name_idx); } ) - + for(const auto iter : iterations) { TU_MATCH(CaptureLayer, (*layer), (e), @@ -316,28 +316,28 @@ 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; @@ -351,18 +351,18 @@ SimplePatEnt MacroPatternStream::next() parent_ents = ents; ents = &parent_pat->subpats; } - + DEBUG( (m_pos.size()-1) << " " << m_pos.back() << " / " << ents->size()); if( m_pos.back() < ents->size() ) { 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); @@ -391,7 +391,7 @@ SimplePatEnt MacroPatternStream::next() // - 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. @@ -437,17 +437,17 @@ namespace { void get_loop_entry_pats(const MacroPatEnt& pat, ::std::vector<const MacroPatEnt*>& entry_pats) { assert( pat.type == MacroPatEnt::PAT_LOOP ); - + // If this pattern is a loop, get the entry concrete patterns for it - // - Otherwise, just + // - Otherwise, just unsigned int i = 0; while( i < pat.subpats.size() && pat.subpats[i].type == MacroPatEnt::PAT_LOOP ) { 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 @@ -456,7 +456,7 @@ namespace { // Optional, so continue the loop. i ++; } - + // First non-loop pattern if( i < pat.subpats.size() ) { @@ -471,10 +471,10 @@ SimplePatEnt MacroPatternStream::emit_loop_start(const MacroPatEnt& pat) { // Find the next non-loop pattern to control if this loop should be entered ::std::vector<const MacroPatEnt*> 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 ) @@ -483,7 +483,7 @@ SimplePatEnt MacroPatternStream::emit_loop_start(const MacroPatEnt& pat) return SimplePatEnt::make_IfPat({ flag, mpe.type }); } }; - + const auto* entry_pat = m_entry_pats.back(); m_entry_pats.pop_back(); if( m_entry_pats.size() > 0 ) @@ -521,13 +521,13 @@ void MacroPatternStream::break_loop() 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(); } @@ -546,10 +546,10 @@ class MacroExpandState /// Layer states : Index and Iteration ::std::vector< t_offset > m_offsets; ::std::vector< unsigned int> m_iterations; - + /// Cached pointer to the current layer const ::std::vector<MacroExpansionEnt>* m_cur_ents; // For faster lookup. - + public: MacroExpandState(const ::std::vector<MacroExpansionEnt>& contents, const ParameterMappings& mappings): m_root_contents(contents), @@ -558,11 +558,11 @@ public: m_cur_ents(&m_root_contents) { } - + // Returns a pointer to the next entry to expand, or nullptr if the end is reached // - NOTE: When a Loop entry is returned, the separator token should be emitted const MacroExpansionEnt* next_ent(); - + const ::std::vector<unsigned int> iterations() const { return m_iterations; } unsigned int top_pos() const { return m_offsets[0].read_pos; } @@ -577,17 +577,17 @@ class MacroExpander: const RcString m_macro_filename; const ::std::string m_crate_name; - + ParameterMappings m_mappings; MacroExpandState m_state; - + Token m_next_token; // used for inserting a single token into the stream ::std::unique_ptr<TTStreamO> m_ttstream; Ident::Hygiene m_hygiene; - + public: MacroExpander(const MacroExpander& x) = delete; - + MacroExpander(const ::std::string& macro_name, const Ident::Hygiene& parent_hygiene, const ::std::vector<MacroExpansionEnt>& contents, ParameterMappings mappings, ::std::string crate_name): m_macro_filename( FMT("Macro:" << macro_name) ), m_crate_name( mv$(crate_name) ), @@ -683,7 +683,7 @@ InterpolatedFragment Macro_HandlePatternCap(TokenStream& lex, MacroPatEnt::Type BUG(lex.getPosition(), "Encountered PAT_TOKEN when handling capture"); case MacroPatEnt::PAT_LOOP: BUG(lex.getPosition(), "Encountered PAT_LOOP when handling capture"); - + case MacroPatEnt::PAT_TT: if( GET_TOK(tok, lex) == TOK_EOF ) throw ParseError::Unexpected(lex, TOK_EOF); @@ -725,24 +725,24 @@ InterpolatedFragment Macro_HandlePatternCap(TokenStream& lex, MacroPatEnt::Type ::std::unique_ptr<TokenStream> Macro_InvokeRules(const char *name, const MacroRules& rules, TokenTree input, AST::Module& mod) { TRACE_FUNCTION_F("'" << name << "', " << input); - + ParameterMappings bound_tts; unsigned int rule_index = Macro_InvokeRules_MatchPattern(rules, mv$(input), mod, bound_tts); - + const auto& rule = rules.m_rules.at(rule_index); - + DEBUG( rule.m_contents.size() << " rule contents with " << bound_tts.mappings().size() << " bound values - " << name ); for( unsigned int i = 0; i < ::std::min( bound_tts.mappings().size(), rule.m_param_names.size() ); i ++ ) { DEBUG("- #" << i << " " << rule.m_param_names.at(i) << " = [" << bound_tts.mappings()[i] << "]"); } //bound_tts.dump(); - + // Run through the expansion counting the number of times each fragment is used Macro_InvokeRules_CountSubstUses(bound_tts, rule.m_contents); - + TokenStream* ret_ptr = new MacroExpander(name, rules.m_hygiene, rule.m_contents, mv$(bound_tts), rules.m_source_crate); - + return ::std::unique_ptr<TokenStream>( ret_ptr ); } @@ -750,7 +750,7 @@ unsigned int Macro_InvokeRules_MatchPattern(const MacroRules& rules, TokenTree i { TRACE_FUNCTION; Span sp;// = input.span(); - + struct Capture { unsigned int binding_idx; ::std::vector<unsigned int> iterations; @@ -768,10 +768,10 @@ unsigned int Macro_InvokeRules_MatchPattern(const MacroRules& rules, TokenTree i { active_arms.push_back( ActiveArm { i, {}, MacroPatternStream(rules.m_rules[i].m_pattern) } ); } - + // - List of captured values ::std::vector<InterpolatedFragment> captures; - + TTStreamO lex( mv$(input) ); SET_MODULE(lex, mod); while(true) @@ -783,7 +783,7 @@ unsigned int Macro_InvokeRules_MatchPattern(const MacroRules& rules, TokenTree i { auto idx = arm.index; SimplePatEnt pat; - // Consume all If* rules + // Consume all If* rules do { pat = arm.stream.next(); @@ -809,7 +809,7 @@ unsigned int Macro_InvokeRules_MatchPattern(const MacroRules& rules, TokenTree i 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");), @@ -826,14 +826,14 @@ unsigned int Macro_InvokeRules_MatchPattern(const MacroRules& rules, TokenTree i 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");), @@ -862,12 +862,12 @@ unsigned int Macro_InvokeRules_MatchPattern(const MacroRules& rules, TokenTree i } j ++; } - + if( arm_pats.size() == 0 ) { auto tok = lex.getToken(); ERROR(tok.get_pos(), E0000, "No rules expected " << tok); } - + // 3. If there is a token pattern in the list, take that arm (and any other token arms) const SimplePatEnt* tok_pat = nullptr; unsigned int ident_pat_idx = arm_pats.size(); @@ -893,7 +893,7 @@ unsigned int Macro_InvokeRules_MatchPattern(const MacroRules& rules, TokenTree i } ) } - + if( tok_pat ) { auto tok = lex.getToken(); @@ -936,7 +936,7 @@ unsigned int Macro_InvokeRules_MatchPattern(const MacroRules& rules, TokenTree i (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 ); @@ -945,7 +945,7 @@ unsigned int Macro_InvokeRules_MatchPattern(const MacroRules& rules, TokenTree i ++ 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 @@ -963,7 +963,7 @@ unsigned int Macro_InvokeRules_MatchPattern(const MacroRules& rules, TokenTree 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 ++) @@ -990,7 +990,7 @@ unsigned int Macro_InvokeRules_MatchPattern(const MacroRules& rules, TokenTree i ) ) } - + // 4. Apply patterns. TU_MATCH( SimplePatEnt, (arm_pats[0]), (e), (End, @@ -1025,9 +1025,9 @@ unsigned int Macro_InvokeRules_MatchPattern(const MacroRules& rules, TokenTree i } } }; - + 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 ++) @@ -1039,7 +1039,7 @@ unsigned int Macro_InvokeRules_MatchPattern(const MacroRules& rules, TokenTree i ) ) } - + // Keep looping - breakout is handled in 'End' above } } @@ -1048,7 +1048,7 @@ void Macro_InvokeRules_CountSubstUses(ParameterMappings& bound_tts, const ::std: { TRACE_FUNCTION; MacroExpandState state(contents, bound_tts); - + while(const auto* ent_ptr = state.next_ent()) { DEBUG(*ent_ptr); @@ -1096,7 +1096,7 @@ Token MacroExpander::realGetToken() return rv; m_ttstream.reset(); } - + // Loop to handle case where $crate expands to nothing while( const auto* next_ent_ptr = m_state.next_ent() ) { @@ -1125,7 +1125,7 @@ Token MacroExpander::realGetToken() else { auto* frag = m_mappings.get(m_state.iterations(), e); ASSERT_BUG(this->getPosition(), frag, "Cannot find '" << e << "' for " << m_state.iterations()); - + bool can_steal = ( m_mappings.dec_count(m_state.iterations(), e) == false ); DEBUG("Insert replacement #" << e << " = " << *frag); if( frag->m_type == InterpolatedFragment::TT ) @@ -1162,7 +1162,7 @@ Token MacroExpander::realGetToken() throw ""; } } - + DEBUG("EOF"); return Token(TOK_EOF); } @@ -1176,10 +1176,10 @@ const MacroExpansionEnt* MacroExpandState::next_ent() { unsigned int layer = m_offsets.size() - 1; const auto& ents = *m_cur_ents; - + // Obtain current read position in layer, and increment size_t idx = m_offsets.back().read_pos++; - + // Check if limit has been reached if( idx < ents.size() ) { @@ -1230,11 +1230,11 @@ const MacroExpansionEnt* MacroExpandState::next_ent() if( cur_ofs.loop_index + 1 < cur_ofs.max_index ) { m_iterations.back() ++; - + DEBUG("Restart layer"); cur_ofs.read_pos = 0; cur_ofs.loop_index ++; - + auto& loop_layer = getCurLayerEnt(); if( loop_layer.as_Loop().joiner.type() != TOK_NULL ) { DEBUG("- Separator token = " << loop_layer.as_Loop().joiner); @@ -1261,14 +1261,14 @@ const MacroExpansionEnt* MacroExpandState::next_ent() assert( m_offsets.size() == 0 ); } } // while( m_offsets NONEMPTY ) - + return nullptr; } const MacroExpansionEnt& MacroExpandState::getCurLayerEnt() const { assert( m_offsets.size() > 1 ); - + const auto* ents = &m_root_contents; for( unsigned int i = 0; i < m_offsets.size()-2; i ++ ) { @@ -1277,7 +1277,7 @@ const MacroExpansionEnt& MacroExpandState::getCurLayerEnt() const ents = &(*ents)[ofs-1].as_Loop().entries; } return (*ents)[m_offsets[m_offsets.size()-2].read_pos-1]; - + } const ::std::vector<MacroExpansionEnt>* MacroExpandState::getCurLayer() const { diff --git a/src/macro_rules/macro_rules.hpp b/src/macro_rules/macro_rules.hpp index 337a4707..aed0e8ce 100644 --- a/src/macro_rules/macro_rules.hpp +++ b/src/macro_rules/macro_rules.hpp @@ -1,162 +1,162 @@ -/*
- * MRustC - Rust Compiler
- * - By John Hodge (Mutabah/thePowersGang)
- *
- * macro_rules/macro_rules.hpp
- * - Macros by example - `macro_rules!`
- */
-#ifndef MACROS_HPP_INCLUDED
-#define MACROS_HPP_INCLUDED
-
-#include "parse/lex.hpp"
-#include "parse/tokentree.hpp"
-#include <common.hpp>
-#include <map>
-#include <memory>
-#include <cstring>
-#include "macro_rules_ptr.hpp"
-#include <set>
-
-class MacroExpander;
-
-TAGGED_UNION_EX(MacroExpansionEnt, (: public Serialisable), Token, (
- // TODO: have a "raw" stream instead of just tokens
- (Token, Token),
- // TODO: Have a flag on `NamedValue` that indicates that it is the only/last usage of this particular value (at this level)
- // NOTE: This is a 2:30 bitfield - with the high range indicating $crate
- (NamedValue, unsigned int),
- (Loop, struct {
- /// Contained entries
- ::std::vector< MacroExpansionEnt> entries;
- /// Token used to join iterations
- Token joiner;
- /// List of variables within this loop that control its iteration count
- /// Boolean is true if the variable will be unconditionally expanded
- ::std::map< unsigned int, bool> variables;
- })
- ),
- (),
- (),
- (
- public:
- SERIALISABLE_PROTOTYPES();
- )
- );
-extern ::std::ostream& operator<<(::std::ostream& os, const MacroExpansionEnt& x);
-
-/// Matching pattern entry
-struct MacroPatEnt:
- public Serialisable
-{
- ::std::string name;
- unsigned int name_index = 0;
- Token tok;
-
- ::std::vector<MacroPatEnt> subpats;
-
- enum Type {
- PAT_TOKEN, // A token
- PAT_LOOP, // $() Enables use of subpats
-
- PAT_TT, // :tt
- PAT_PAT, // :pat
- PAT_IDENT,
- PAT_PATH,
- PAT_TYPE,
- PAT_EXPR,
- PAT_STMT,
- PAT_BLOCK,
- PAT_META,
- PAT_ITEM, // :item
- } type;
-
- MacroPatEnt():
- tok(TOK_NULL),
- type(PAT_TOKEN)
- {
- }
- MacroPatEnt(Token tok):
- tok( mv$(tok) ),
- type(PAT_TOKEN)
- {
- }
-
- MacroPatEnt(::std::string name, unsigned int name_index, Type type):
- name( mv$(name) ),
- name_index( name_index ),
- tok(),
- type(type)
- {
- }
-
- MacroPatEnt(Token sep, bool need_once, ::std::vector<MacroPatEnt> ents):
- name( need_once ? "+" : "*" ),
- tok( mv$(sep) ),
- subpats( move(ents) ),
- type(PAT_LOOP)
- {
- }
-
- friend ::std::ostream& operator<<(::std::ostream& os, const MacroPatEnt& x);
- friend ::std::ostream& operator<<(::std::ostream& os, const MacroPatEnt::Type& x);
-
- SERIALISABLE_PROTOTYPES();
-};
-
-/// An expansion arm within a macro_rules! blcok
-struct MacroRulesArm:
- public Serialisable
-{
- /// Names for the parameters
- ::std::vector< ::std::string> m_param_names;
-
- /// Patterns
- ::std::vector<MacroPatEnt> m_pattern;
-
- /// Rule contents
- ::std::vector<MacroExpansionEnt> m_contents;
-
- MacroRulesArm()
- {}
- MacroRulesArm(::std::vector<MacroPatEnt> pattern, ::std::vector<MacroExpansionEnt> contents):
- m_pattern( mv$(pattern) ),
- m_contents( mv$(contents) )
- {}
- MacroRulesArm(const MacroRulesArm&) = delete;
- MacroRulesArm& operator=(const MacroRulesArm&) = delete;
- MacroRulesArm(MacroRulesArm&&) = default;
- MacroRulesArm& operator=(MacroRulesArm&&) = default;
-
- SERIALISABLE_PROTOTYPES();
-};
-
-/// A sigle 'macro_rules!' block
-class MacroRules:
- public Serialisable
-{
-public:
- /// Marks if this macro should be exported from the defining crate
- bool m_exported = false;
-
- /// Crate that defined this macro
- /// - Populated on deserialise if not already set
- ::std::string m_source_crate;
-
- Ident::Hygiene m_hygiene;
-
- /// Expansion rules
- ::std::vector<MacroRulesArm> m_rules;
-
- MacroRules()
- {
- }
- virtual ~MacroRules();
- MacroRules(MacroRules&&) = default;
-
- SERIALISABLE_PROTOTYPES();
-};
-
-extern ::std::unique_ptr<TokenStream> Macro_InvokeRules(const char *name, const MacroRules& rules, TokenTree input, AST::Module& mod);
-extern MacroRulesPtr Parse_MacroRules(TokenStream& lex);
-
-#endif // MACROS_HPP_INCLUDED
+/* + * MRustC - Rust Compiler + * - By John Hodge (Mutabah/thePowersGang) + * + * macro_rules/macro_rules.hpp + * - Macros by example - `macro_rules!` + */ +#ifndef MACROS_HPP_INCLUDED +#define MACROS_HPP_INCLUDED + +#include "parse/lex.hpp" +#include "parse/tokentree.hpp" +#include <common.hpp> +#include <map> +#include <memory> +#include <cstring> +#include "macro_rules_ptr.hpp" +#include <set> + +class MacroExpander; + +TAGGED_UNION_EX(MacroExpansionEnt, (: public Serialisable), Token, ( + // TODO: have a "raw" stream instead of just tokens + (Token, Token), + // TODO: Have a flag on `NamedValue` that indicates that it is the only/last usage of this particular value (at this level) + // NOTE: This is a 2:30 bitfield - with the high range indicating $crate + (NamedValue, unsigned int), + (Loop, struct { + /// Contained entries + ::std::vector< MacroExpansionEnt> entries; + /// Token used to join iterations + Token joiner; + /// List of variables within this loop that control its iteration count + /// Boolean is true if the variable will be unconditionally expanded + ::std::map< unsigned int, bool> variables; + }) + ), + (), + (), + ( + public: + SERIALISABLE_PROTOTYPES(); + ) + ); +extern ::std::ostream& operator<<(::std::ostream& os, const MacroExpansionEnt& x); + +/// Matching pattern entry +struct MacroPatEnt: + public Serialisable +{ + ::std::string name; + unsigned int name_index = 0; + Token tok; + + ::std::vector<MacroPatEnt> subpats; + + enum Type { + PAT_TOKEN, // A token + PAT_LOOP, // $() Enables use of subpats + + PAT_TT, // :tt + PAT_PAT, // :pat + PAT_IDENT, + PAT_PATH, + PAT_TYPE, + PAT_EXPR, + PAT_STMT, + PAT_BLOCK, + PAT_META, + PAT_ITEM, // :item + } type; + + MacroPatEnt(): + tok(TOK_NULL), + type(PAT_TOKEN) + { + } + MacroPatEnt(Token tok): + tok( mv$(tok) ), + type(PAT_TOKEN) + { + } + + MacroPatEnt(::std::string name, unsigned int name_index, Type type): + name( mv$(name) ), + name_index( name_index ), + tok(), + type(type) + { + } + + MacroPatEnt(Token sep, bool need_once, ::std::vector<MacroPatEnt> ents): + name( need_once ? "+" : "*" ), + tok( mv$(sep) ), + subpats( move(ents) ), + type(PAT_LOOP) + { + } + + friend ::std::ostream& operator<<(::std::ostream& os, const MacroPatEnt& x); + friend ::std::ostream& operator<<(::std::ostream& os, const MacroPatEnt::Type& x); + + SERIALISABLE_PROTOTYPES(); +}; + +/// An expansion arm within a macro_rules! blcok +struct MacroRulesArm: + public Serialisable +{ + /// Names for the parameters + ::std::vector< ::std::string> m_param_names; + + /// Patterns + ::std::vector<MacroPatEnt> m_pattern; + + /// Rule contents + ::std::vector<MacroExpansionEnt> m_contents; + + MacroRulesArm() + {} + MacroRulesArm(::std::vector<MacroPatEnt> pattern, ::std::vector<MacroExpansionEnt> contents): + m_pattern( mv$(pattern) ), + m_contents( mv$(contents) ) + {} + MacroRulesArm(const MacroRulesArm&) = delete; + MacroRulesArm& operator=(const MacroRulesArm&) = delete; + MacroRulesArm(MacroRulesArm&&) = default; + MacroRulesArm& operator=(MacroRulesArm&&) = default; + + SERIALISABLE_PROTOTYPES(); +}; + +/// A sigle 'macro_rules!' block +class MacroRules: + public Serialisable +{ +public: + /// Marks if this macro should be exported from the defining crate + bool m_exported = false; + + /// Crate that defined this macro + /// - Populated on deserialise if not already set + ::std::string m_source_crate; + + Ident::Hygiene m_hygiene; + + /// Expansion rules + ::std::vector<MacroRulesArm> m_rules; + + MacroRules() + { + } + virtual ~MacroRules(); + MacroRules(MacroRules&&) = default; + + SERIALISABLE_PROTOTYPES(); +}; + +extern ::std::unique_ptr<TokenStream> Macro_InvokeRules(const char *name, const MacroRules& rules, TokenTree input, AST::Module& mod); +extern MacroRulesPtr Parse_MacroRules(TokenStream& lex); + +#endif // MACROS_HPP_INCLUDED diff --git a/src/macro_rules/macro_rules_ptr.hpp b/src/macro_rules/macro_rules_ptr.hpp index c5c01488..fdb01fbe 100644 --- a/src/macro_rules/macro_rules_ptr.hpp +++ b/src/macro_rules/macro_rules_ptr.hpp @@ -25,9 +25,9 @@ public: m_ptr = x.m_ptr; x.m_ptr = nullptr; return *this; } - + ~MacroRulesPtr(); - + const MacroRules& operator*() const { assert(m_ptr); return *m_ptr; } MacroRules& operator*() { assert(m_ptr); return *m_ptr; } const MacroRules* operator->() const { assert(m_ptr); return m_ptr; } diff --git a/src/macro_rules/mod.cpp b/src/macro_rules/mod.cpp index 2803b061..f685f6dc 100644 --- a/src/macro_rules/mod.cpp +++ b/src/macro_rules/mod.cpp @@ -1,303 +1,303 @@ -/*
- */
-#include <common.hpp>
-#include "macro_rules.hpp"
-#include <parse/parseerror.hpp>
-#include <parse/tokentree.hpp>
-#include <parse/common.hpp>
-#include <limits.h>
-
-#include "pattern_checks.hpp"
-
-bool is_token_path(eTokenType tt) {
- switch(tt)
- {
- case TOK_IDENT:
- case TOK_DOUBLE_COLON:
- case TOK_LT:
- case TOK_DOUBLE_LT:
- case TOK_RWORD_SELF:
- case TOK_RWORD_SUPER:
- case TOK_INTERPOLATED_PATH:
- return true;
- default:
- return false;
- }
-}
-bool is_token_pat(eTokenType tt) {
- if( is_token_path(tt) )
- return true;
- switch( tt )
- {
- case TOK_PAREN_OPEN:
- case TOK_SQUARE_OPEN:
-
- case TOK_UNDERSCORE:
- case TOK_AMP:
- case TOK_RWORD_BOX:
- case TOK_RWORD_REF:
- case TOK_RWORD_MUT:
- case TOK_STRING:
- case TOK_INTEGER:
- case TOK_CHAR:
- case TOK_INTERPOLATED_PATTERN:
- return true;
- default:
- return false;
- }
-}
-bool is_token_type(eTokenType tt) {
- if( is_token_path(tt) )
- return true;
- switch( tt )
- {
- case TOK_PAREN_OPEN:
- case TOK_SQUARE_OPEN:
- case TOK_STAR:
- case TOK_AMP:
- case TOK_RWORD_EXTERN:
- case TOK_RWORD_UNSAFE:
- case TOK_RWORD_FN:
- case TOK_INTERPOLATED_TYPE:
- return true;
- default:
- return false;
- }
-}
-bool is_token_expr(eTokenType tt) {
- if( is_token_path(tt) )
- return true;
- switch( tt )
- {
- // Leading unary operators
- case TOK_AMP: // Borrow
- case TOK_STAR: // Deref
- case TOK_DASH: // Negate
- case TOK_EXCLAM: // Invert
- case TOK_RWORD_BOX: // Box
- // Composite values
- case TOK_MACRO:
- case TOK_PAREN_OPEN: // Parenthesised
- case TOK_SQUARE_OPEN: // Array
-
- // Flow
- case TOK_RWORD_RETURN:
- case TOK_RWORD_BREAK:
- case TOK_RWORD_CONTINUE:
-
- // Blocks
- case TOK_BRACE_OPEN:
- case TOK_RWORD_MATCH:
- case TOK_RWORD_IF:
- case TOK_RWORD_FOR:
- case TOK_RWORD_WHILE:
- case TOK_RWORD_LOOP:
- case TOK_RWORD_UNSAFE:
-
- // Closures
- case TOK_RWORD_MOVE:
- case TOK_PIPE:
- case TOK_DOUBLE_PIPE:
-
- // Literal tokens
- case TOK_INTEGER:
- case TOK_FLOAT:
- case TOK_STRING:
- case TOK_BYTESTRING:
- case TOK_RWORD_TRUE:
- case TOK_RWORD_FALSE:
-
- case TOK_INTERPOLATED_EXPR:
- return true;
- default:
- return false;
- }
-}
-bool is_token_stmt(eTokenType tt) {
- if( is_token_expr(tt) )
- return true;
- switch( tt )
- {
- case TOK_BRACE_OPEN:
- case TOK_RWORD_LET:
- case TOK_INTERPOLATED_STMT:
- return true;
- default:
- return false;
- }
-}
-
-bool is_token_item(eTokenType tt) {
- switch( tt )
- {
- case TOK_ATTR_OPEN:
-
- case TOK_RWORD_PUB:
- case TOK_RWORD_UNSAFE:
- case TOK_RWORD_TYPE:
- case TOK_RWORD_CONST:
- case TOK_RWORD_STATIC:
- case TOK_RWORD_FN:
- case TOK_RWORD_STRUCT:
- case TOK_RWORD_ENUM:
- case TOK_RWORD_TRAIT:
- case TOK_RWORD_MOD:
- case TOK_RWORD_USE:
- case TOK_RWORD_EXTERN:
- case TOK_RWORD_IMPL:
- // TODO: more?
- case TOK_INTERPOLATED_ITEM:
- return true;
- default:
- return false;
- }
-}
-
-MacroRulesPtr::~MacroRulesPtr()
-{
- if(m_ptr)
- {
- delete m_ptr;
- m_ptr = nullptr;
- }
-}
-
-SERIALISE_TYPE_S(MacroRulesArm, {
-})
-
-void operator%(Serialiser& s, MacroPatEnt::Type c) {
- switch(c) {
- #define _(v) case MacroPatEnt::v: s << #v; return
- _(PAT_TOKEN);
- _(PAT_TT);
- _(PAT_PAT);
- _(PAT_TYPE);
- _(PAT_EXPR);
- _(PAT_LOOP);
- _(PAT_STMT);
- _(PAT_PATH);
- _(PAT_BLOCK);
- _(PAT_META);
- _(PAT_ITEM);
- _(PAT_IDENT);
- #undef _
- }
-}
-void operator%(::Deserialiser& s, MacroPatEnt::Type& c) {
- ::std::string n;
- s.item(n);
- #define _(v) else if(n == #v) c = MacroPatEnt::v
- if(0) ;
- _(PAT_TOKEN);
- _(PAT_TT);
- _(PAT_PAT);
- _(PAT_TYPE);
- _(PAT_EXPR);
- _(PAT_LOOP);
- //_(PAT_OPTLOOP);
- _(PAT_STMT);
- _(PAT_PATH);
- _(PAT_BLOCK);
- _(PAT_META);
- _(PAT_IDENT);
- _(PAT_ITEM);
- else
- throw ::std::runtime_error( FMT("No conversion for '" << n << "'") );
- #undef _
-}
-SERIALISE_TYPE_S(MacroPatEnt, {
- s % type;
- s.item(name);
- s.item(tok);
- s.item(subpats);
-});
-::std::ostream& operator<<(::std::ostream& os, const MacroPatEnt& x)
-{
- switch(x.type)
- {
- case MacroPatEnt::PAT_TOKEN: os << "=" << x.tok; break;
- case MacroPatEnt::PAT_LOOP: os << "loop w/ " << x.tok << " [" << x.subpats << "]"; break;
- default:
- os << "$" << x.name << ":";
- switch(x.type)
- {
- case MacroPatEnt::PAT_TOKEN: throw "";
- case MacroPatEnt::PAT_LOOP: throw "";
- case MacroPatEnt::PAT_TT: os << "tt"; break;
- case MacroPatEnt::PAT_PAT: os << "pat"; break;
- case MacroPatEnt::PAT_IDENT: os << "ident"; break;
- case MacroPatEnt::PAT_PATH: os << "path"; break;
- case MacroPatEnt::PAT_TYPE: os << "type"; break;
- case MacroPatEnt::PAT_EXPR: os << "expr"; break;
- case MacroPatEnt::PAT_STMT: os << "stmt"; break;
- case MacroPatEnt::PAT_BLOCK: os << "block"; break;
- case MacroPatEnt::PAT_META: os << "meta"; break;
- case MacroPatEnt::PAT_ITEM: os << "item"; break;
- }
- break;
- }
- return os;
-}
-::std::ostream& operator<<(::std::ostream& os, const MacroPatEnt::Type& x)
-{
- switch(x)
- {
- case MacroPatEnt::PAT_TOKEN: os << "PAT_TOKEN"; break;
- case MacroPatEnt::PAT_LOOP: os << "PAT_LOOP"; break;
- case MacroPatEnt::PAT_TT: os << "PAT_TT"; break;
- case MacroPatEnt::PAT_PAT: os << "PAT_PAT"; break;
- case MacroPatEnt::PAT_IDENT: os << "PAT_IDENT"; break;
- case MacroPatEnt::PAT_PATH: os << "PAT_PATH"; break;
- case MacroPatEnt::PAT_TYPE: os << "PAT_TYPE"; break;
- case MacroPatEnt::PAT_EXPR: os << "PAT_EXPR"; break;
- case MacroPatEnt::PAT_STMT: os << "PAT_STMT"; break;
- case MacroPatEnt::PAT_BLOCK: os << "PAT_BLOCK"; break;
- case MacroPatEnt::PAT_META: os << "PAT_META"; break;
- case MacroPatEnt::PAT_ITEM: os << "PAT_ITEM"; break;
- }
- return os;
-}
-
-SERIALISE_TU(MacroExpansionEnt, "MacroExpansionEnt", e,
-(Token,
- s.item(e);
- ),
-(NamedValue,
- s.item(e);
- ),
-(Loop,
- s.item(e.entries);
- s.item(e.joiner);
- //s.item(e.variables);
- )
-);
-
-::std::ostream& operator<<(::std::ostream& os, const MacroExpansionEnt& x)
-{
- TU_MATCH( MacroExpansionEnt, (x), (e),
- (Token,
- os << "=" << e;
- ),
- (NamedValue,
- if( e >> 30 ) {
- os << "$crate";
- }
- else {
- os << "$" << e;
- }
- ),
- (Loop,
- os << "${" << *e.variables.begin() << "}(" << e.entries << ") " << e.joiner;
- )
- )
- return os;
-}
-
-MacroRules::~MacroRules()
-{
-}
-SERIALISE_TYPE_S(MacroRules, {
- s.item( m_exported );
- s.item( m_rules );
-});
-
+/* + */ +#include <common.hpp> +#include "macro_rules.hpp" +#include <parse/parseerror.hpp> +#include <parse/tokentree.hpp> +#include <parse/common.hpp> +#include <limits.h> + +#include "pattern_checks.hpp" + +bool is_token_path(eTokenType tt) { + switch(tt) + { + case TOK_IDENT: + case TOK_DOUBLE_COLON: + case TOK_LT: + case TOK_DOUBLE_LT: + case TOK_RWORD_SELF: + case TOK_RWORD_SUPER: + case TOK_INTERPOLATED_PATH: + return true; + default: + return false; + } +} +bool is_token_pat(eTokenType tt) { + if( is_token_path(tt) ) + return true; + switch( tt ) + { + case TOK_PAREN_OPEN: + case TOK_SQUARE_OPEN: + + case TOK_UNDERSCORE: + case TOK_AMP: + case TOK_RWORD_BOX: + case TOK_RWORD_REF: + case TOK_RWORD_MUT: + case TOK_STRING: + case TOK_INTEGER: + case TOK_CHAR: + case TOK_INTERPOLATED_PATTERN: + return true; + default: + return false; + } +} +bool is_token_type(eTokenType tt) { + if( is_token_path(tt) ) + return true; + switch( tt ) + { + case TOK_PAREN_OPEN: + case TOK_SQUARE_OPEN: + case TOK_STAR: + case TOK_AMP: + case TOK_RWORD_EXTERN: + case TOK_RWORD_UNSAFE: + case TOK_RWORD_FN: + case TOK_INTERPOLATED_TYPE: + return true; + default: + return false; + } +} +bool is_token_expr(eTokenType tt) { + if( is_token_path(tt) ) + return true; + switch( tt ) + { + // Leading unary operators + case TOK_AMP: // Borrow + case TOK_STAR: // Deref + case TOK_DASH: // Negate + case TOK_EXCLAM: // Invert + case TOK_RWORD_BOX: // Box + // Composite values + case TOK_MACRO: + case TOK_PAREN_OPEN: // Parenthesised + case TOK_SQUARE_OPEN: // Array + + // Flow + case TOK_RWORD_RETURN: + case TOK_RWORD_BREAK: + case TOK_RWORD_CONTINUE: + + // Blocks + case TOK_BRACE_OPEN: + case TOK_RWORD_MATCH: + case TOK_RWORD_IF: + case TOK_RWORD_FOR: + case TOK_RWORD_WHILE: + case TOK_RWORD_LOOP: + case TOK_RWORD_UNSAFE: + + // Closures + case TOK_RWORD_MOVE: + case TOK_PIPE: + case TOK_DOUBLE_PIPE: + + // Literal tokens + case TOK_INTEGER: + case TOK_FLOAT: + case TOK_STRING: + case TOK_BYTESTRING: + case TOK_RWORD_TRUE: + case TOK_RWORD_FALSE: + + case TOK_INTERPOLATED_EXPR: + return true; + default: + return false; + } +} +bool is_token_stmt(eTokenType tt) { + if( is_token_expr(tt) ) + return true; + switch( tt ) + { + case TOK_BRACE_OPEN: + case TOK_RWORD_LET: + case TOK_INTERPOLATED_STMT: + return true; + default: + return false; + } +} + +bool is_token_item(eTokenType tt) { + switch( tt ) + { + case TOK_ATTR_OPEN: + + case TOK_RWORD_PUB: + case TOK_RWORD_UNSAFE: + case TOK_RWORD_TYPE: + case TOK_RWORD_CONST: + case TOK_RWORD_STATIC: + case TOK_RWORD_FN: + case TOK_RWORD_STRUCT: + case TOK_RWORD_ENUM: + case TOK_RWORD_TRAIT: + case TOK_RWORD_MOD: + case TOK_RWORD_USE: + case TOK_RWORD_EXTERN: + case TOK_RWORD_IMPL: + // TODO: more? + case TOK_INTERPOLATED_ITEM: + return true; + default: + return false; + } +} + +MacroRulesPtr::~MacroRulesPtr() +{ + if(m_ptr) + { + delete m_ptr; + m_ptr = nullptr; + } +} + +SERIALISE_TYPE_S(MacroRulesArm, { +}) + +void operator%(Serialiser& s, MacroPatEnt::Type c) { + switch(c) { + #define _(v) case MacroPatEnt::v: s << #v; return + _(PAT_TOKEN); + _(PAT_TT); + _(PAT_PAT); + _(PAT_TYPE); + _(PAT_EXPR); + _(PAT_LOOP); + _(PAT_STMT); + _(PAT_PATH); + _(PAT_BLOCK); + _(PAT_META); + _(PAT_ITEM); + _(PAT_IDENT); + #undef _ + } +} +void operator%(::Deserialiser& s, MacroPatEnt::Type& c) { + ::std::string n; + s.item(n); + #define _(v) else if(n == #v) c = MacroPatEnt::v + if(0) ; + _(PAT_TOKEN); + _(PAT_TT); + _(PAT_PAT); + _(PAT_TYPE); + _(PAT_EXPR); + _(PAT_LOOP); + //_(PAT_OPTLOOP); + _(PAT_STMT); + _(PAT_PATH); + _(PAT_BLOCK); + _(PAT_META); + _(PAT_IDENT); + _(PAT_ITEM); + else + throw ::std::runtime_error( FMT("No conversion for '" << n << "'") ); + #undef _ +} +SERIALISE_TYPE_S(MacroPatEnt, { + s % type; + s.item(name); + s.item(tok); + s.item(subpats); +}); +::std::ostream& operator<<(::std::ostream& os, const MacroPatEnt& x) +{ + switch(x.type) + { + case MacroPatEnt::PAT_TOKEN: os << "=" << x.tok; break; + case MacroPatEnt::PAT_LOOP: os << "loop w/ " << x.tok << " [" << x.subpats << "]"; break; + default: + os << "$" << x.name << ":"; + switch(x.type) + { + case MacroPatEnt::PAT_TOKEN: throw ""; + case MacroPatEnt::PAT_LOOP: throw ""; + case MacroPatEnt::PAT_TT: os << "tt"; break; + case MacroPatEnt::PAT_PAT: os << "pat"; break; + case MacroPatEnt::PAT_IDENT: os << "ident"; break; + case MacroPatEnt::PAT_PATH: os << "path"; break; + case MacroPatEnt::PAT_TYPE: os << "type"; break; + case MacroPatEnt::PAT_EXPR: os << "expr"; break; + case MacroPatEnt::PAT_STMT: os << "stmt"; break; + case MacroPatEnt::PAT_BLOCK: os << "block"; break; + case MacroPatEnt::PAT_META: os << "meta"; break; + case MacroPatEnt::PAT_ITEM: os << "item"; break; + } + break; + } + return os; +} +::std::ostream& operator<<(::std::ostream& os, const MacroPatEnt::Type& x) +{ + switch(x) + { + case MacroPatEnt::PAT_TOKEN: os << "PAT_TOKEN"; break; + case MacroPatEnt::PAT_LOOP: os << "PAT_LOOP"; break; + case MacroPatEnt::PAT_TT: os << "PAT_TT"; break; + case MacroPatEnt::PAT_PAT: os << "PAT_PAT"; break; + case MacroPatEnt::PAT_IDENT: os << "PAT_IDENT"; break; + case MacroPatEnt::PAT_PATH: os << "PAT_PATH"; break; + case MacroPatEnt::PAT_TYPE: os << "PAT_TYPE"; break; + case MacroPatEnt::PAT_EXPR: os << "PAT_EXPR"; break; + case MacroPatEnt::PAT_STMT: os << "PAT_STMT"; break; + case MacroPatEnt::PAT_BLOCK: os << "PAT_BLOCK"; break; + case MacroPatEnt::PAT_META: os << "PAT_META"; break; + case MacroPatEnt::PAT_ITEM: os << "PAT_ITEM"; break; + } + return os; +} + +SERIALISE_TU(MacroExpansionEnt, "MacroExpansionEnt", e, +(Token, + s.item(e); + ), +(NamedValue, + s.item(e); + ), +(Loop, + s.item(e.entries); + s.item(e.joiner); + //s.item(e.variables); + ) +); + +::std::ostream& operator<<(::std::ostream& os, const MacroExpansionEnt& x) +{ + TU_MATCH( MacroExpansionEnt, (x), (e), + (Token, + os << "=" << e; + ), + (NamedValue, + if( e >> 30 ) { + os << "$crate"; + } + else { + os << "$" << e; + } + ), + (Loop, + os << "${" << *e.variables.begin() << "}(" << e.entries << ") " << e.joiner; + ) + ) + return os; +} + +MacroRules::~MacroRules() +{ +} +SERIALISE_TYPE_S(MacroRules, { + s.item( m_exported ); + s.item( m_rules ); +}); + diff --git a/src/macro_rules/parse.cpp b/src/macro_rules/parse.cpp index 4da91a90..fa82e0e0 100644 --- a/src/macro_rules/parse.cpp +++ b/src/macro_rules/parse.cpp @@ -26,9 +26,9 @@ public: { TRACE_FUNCTION; Token tok; - + ::std::vector<MacroPatEnt> ret; - + int depth = 0; while( GET_TOK(tok, lex) != close || depth > 0 ) { @@ -42,7 +42,7 @@ public: throw ParseError::Generic(FMT("Unmatched " << Token(close) << " in macro pattern")); depth --; } - + switch(tok.type()) { case TOK_DOLLAR: @@ -53,11 +53,11 @@ public: GET_CHECK_TOK(tok, lex, TOK_COLON); GET_CHECK_TOK(tok, lex, TOK_IDENT); ::std::string type = mv$(tok.str()); - + unsigned int idx = ::std::find( names.begin(), names.end(), name ) - names.begin(); if( idx == names.size() ) names.push_back( name ); - + if(0) ; else if( type == "tt" ) @@ -119,7 +119,7 @@ public: break; } } - + return ret; } @@ -132,10 +132,10 @@ public: ) { TRACE_FUNCTION; - + Token tok; ::std::vector<MacroExpansionEnt> ret; - + int depth = 0; while( GET_TOK(tok, lex) != close || depth > 0 ) { @@ -144,7 +144,7 @@ public: } if( tok.type() == TOK_NULL ) continue ; - + if( tok.type() == open ) { DEBUG("depth++"); @@ -157,19 +157,19 @@ public: ERROR(lex.getPosition(), E0000, "Unmatched " << Token(close) << " in macro content"); depth --; } - + // `$` - Macro metavars if( tok.type() == TOK_DOLLAR ) { GET_TOK(tok, lex); - + // `$(` if( tok.type() == TOK_PAREN_OPEN ) - { + { ::std::map<unsigned int, bool> var_set; auto content = Parse_MacroRules_Cont(lex, TOK_PAREN_OPEN, TOK_PAREN_CLOSE, var_names, &var_set); // ^^ The above will eat the PAREN_CLOSE - + GET_TOK(tok, lex); enum eTokenType joiner = TOK_NULL; if( tok.type() != TOK_PLUS && tok.type() != TOK_STAR ) @@ -197,7 +197,7 @@ public: default: throw ParseError::Unexpected(lex, tok); } - + } else if( tok.type() == TOK_IDENT ) { @@ -225,7 +225,7 @@ public: ret.push_back( MacroExpansionEnt( mv$(tok) ) ); } } - + return ret; } @@ -234,9 +234,9 @@ MacroRule Parse_MacroRules_Var(TokenStream& lex) { TRACE_FUNCTION; Token tok; - + MacroRule rule; - + // Pattern enum eTokenType close; switch(GET_TOK(tok, lex)) @@ -249,7 +249,7 @@ MacroRule Parse_MacroRules_Var(TokenStream& lex) // - Pattern entries ::std::vector< ::std::string> names; rule.m_pattern = Parse_MacroRules_Pat(lex, tok.type(), close, names); - + GET_CHECK_TOK(tok, lex, TOK_FATARROW); // Replacement @@ -263,7 +263,7 @@ MacroRule Parse_MacroRules_Var(TokenStream& lex) rule.m_contents = Parse_MacroRules_Cont(lex, tok.type(), close, names); DEBUG("Rule - ["<<rule.m_pattern<<"] => "<<rule.m_contents<<""); - + return rule; } @@ -271,11 +271,11 @@ bool patterns_are_same(const Span& sp, const MacroPatEnt& left, const MacroPatEn { 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) { @@ -295,13 +295,13 @@ bool patterns_are_same(const Span& sp, const MacroPatEnt& left, const MacroPatEn 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) { @@ -444,15 +444,15 @@ void enumerate_names(const ::std::vector<MacroPatEnt>& pats, ::std::vector< ::st MacroRulesPtr Parse_MacroRules(TokenStream& lex) { TRACE_FUNCTION_F(""); - + Token tok; - + // Parse the patterns and replacements ::std::vector<MacroRule> rules; while( GET_TOK(tok, lex) != TOK_EOF ) { lex.putback(tok); - + rules.push_back( Parse_MacroRules_Var(lex) ); if(GET_TOK(tok, lex) != TOK_SEMICOLON) { CHECK_TOK(tok, TOK_EOF); @@ -460,22 +460,22 @@ MacroRulesPtr Parse_MacroRules(TokenStream& lex) } } DEBUG("- " << rules.size() << " rules"); - + ::std::vector<MacroRulesArm> rule_arms; - + // Re-parse the patterns into a unified form for(auto& rule : rules) { MacroRulesArm arm = MacroRulesArm( mv$(rule.m_pattern), mv$(rule.m_contents) ); - + enumerate_names(arm.m_pattern, arm.m_param_names); - + rule_arms.push_back( mv$(arm) ); } - + auto rv = new MacroRules( ); rv->m_hygiene = lex.getHygiene(); rv->m_rules = mv$(rule_arms); - + return MacroRulesPtr(rv); } diff --git a/src/main.cpp b/src/main.cpp index affd981f..5acb8545 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,613 +1,613 @@ -/*
- * MRustC - Rust Compiler
- * - By John Hodge (Mutabah/thePowersGang)
- *
- * main.cpp
- * - Compiler Entrypoint
- */
-#include <iostream>
-#include <iomanip>
-#include <string>
-#include <set>
-#include "parse/lex.hpp"
-#include "parse/parseerror.hpp"
-#include "ast/ast.hpp"
-#include "ast/crate.hpp"
-#include <serialiser_texttree.hpp>
-#include <cstring>
-#include <main_bindings.hpp>
-#include "resolve/main_bindings.hpp"
-#include "hir/main_bindings.hpp"
-#include "hir_conv/main_bindings.hpp"
-#include "hir_typeck/main_bindings.hpp"
-#include "hir_expand/main_bindings.hpp"
-#include "mir/main_bindings.hpp"
-#include "trans/main_bindings.hpp"
-
-#include "expand/cfg.hpp"
-
-int g_debug_indent_level = 0;
-bool g_debug_enabled = true;
-::std::string g_cur_phase;
-::std::set< ::std::string> g_debug_disable_map;
-
-void init_debug_list()
-{
- g_debug_disable_map.insert( "Parse" );
- g_debug_disable_map.insert( "LoadCrates" );
- g_debug_disable_map.insert( "Expand" );
-
- g_debug_disable_map.insert( "Resolve Use" );
- g_debug_disable_map.insert( "Resolve Index" );
- g_debug_disable_map.insert( "Resolve Absolute" );
-
- g_debug_disable_map.insert( "HIR Lower" );
-
- g_debug_disable_map.insert( "Resolve Type Aliases" );
- g_debug_disable_map.insert( "Resolve Bind" );
- g_debug_disable_map.insert( "Resolve UFCS paths" );
- g_debug_disable_map.insert( "Resolve HIR Markings" );
- g_debug_disable_map.insert( "Constant Evaluate" );
-
- g_debug_disable_map.insert( "Typecheck Outer");
- g_debug_disable_map.insert( "Typecheck Expressions" );
-
- g_debug_disable_map.insert( "Expand HIR Annotate" );
- g_debug_disable_map.insert( "Expand HIR Closures" );
- g_debug_disable_map.insert( "Expand HIR Calls" );
- g_debug_disable_map.insert( "Expand HIR VTables" );
- g_debug_disable_map.insert( "Expand HIR Reborrows" );
- g_debug_disable_map.insert( "Expand HIR ErasedType" );
- g_debug_disable_map.insert( "Typecheck Expressions (validate)" );
-
- g_debug_disable_map.insert( "Dump HIR" );
- g_debug_disable_map.insert( "Lower MIR" );
- g_debug_disable_map.insert( "MIR Validate" );
- g_debug_disable_map.insert( "Dump MIR" );
- g_debug_disable_map.insert( "Constant Evaluate Full" );
- g_debug_disable_map.insert( "MIR Cleanup" );
- g_debug_disable_map.insert( "MIR Optimise" );
-
- g_debug_disable_map.insert( "HIR Serialise" );
- g_debug_disable_map.insert( "Trans Enumerate" );
- g_debug_disable_map.insert( "Trans Codegen" );
-
- // Mutate this map using an environment variable
- const char* debug_string = ::std::getenv("MRUSTC_DEBUG");
- if( debug_string )
- {
- while( debug_string[0] )
- {
- const char* end = strchr(debug_string, ':');
-
- if( end ) {
- ::std::string s { debug_string, end };
- // TODO: Emit a warning when this name wasn't in the map?
- g_debug_disable_map.erase( s );
- debug_string = end + 1;
- }
- else {
- g_debug_disable_map.erase( debug_string );
- break;
- }
- }
- }
-}
-bool debug_enabled_update() {
- if( g_debug_disable_map.count(g_cur_phase) != 0 ) {
- return false;
- }
- else {
- return true;
- }
-}
-bool debug_enabled()
-{
- return g_debug_enabled;
-}
-::std::ostream& debug_output(int indent, const char* function)
-{
- return ::std::cout << g_cur_phase << "- " << RepeatLitStr { " ", indent } << function << ": ";
-}
-
-struct ProgramParams
-{
- enum eLastStage {
- STAGE_PARSE,
- STAGE_EXPAND,
- STAGE_RESOLVE,
- STAGE_TYPECK,
- STAGE_BORROWCK,
- STAGE_MIR,
- STAGE_ALL,
- } last_stage = STAGE_ALL;
-
- ::std::string infile;
- ::std::string outfile;
- ::std::string output_dir = "";
- const char *crate_path = ".";
-
- ::AST::Crate::Type crate_type = ::AST::Crate::Type::Unknown;
-
- ::std::set< ::std::string> features;
-
- ProgramParams(int argc, char *argv[]);
-};
-
-template <typename Rv, typename Fcn>
-Rv CompilePhase(const char *name, Fcn f) {
- ::std::cout << name << ": V V V" << ::std::endl;
- g_cur_phase = name;
- g_debug_enabled = debug_enabled_update();
- auto start = clock();
- auto rv = f();
- auto end = clock();
- g_cur_phase = "";
- g_debug_enabled = debug_enabled_update();
-
- ::std::cout <<"(" << ::std::fixed << ::std::setprecision(2) << static_cast<double>(end - start) / static_cast<double>(CLOCKS_PER_SEC) << " s) ";
- ::std::cout << name << ": DONE";
- ::std::cout << ::std::endl;
- return rv;
-}
-template <typename Fcn>
-void CompilePhaseV(const char *name, Fcn f) {
- CompilePhase<int>(name, [&]() { f(); return 0; });
-}
-
-/// main!
-int main(int argc, char *argv[])
-{
- init_debug_list();
- ProgramParams params(argc, argv);
-
- // Set up cfg values
- // TODO: Target spec
- Cfg_SetFlag("unix");
- Cfg_SetFlag("linux");
- Cfg_SetValue("target_os", "linux");
- Cfg_SetValue("target_pointer_width", "64");
- Cfg_SetValue("target_endian", "little");
- Cfg_SetValue("target_arch", "x86_64");
- Cfg_SetValue("target_env", "gnu");
- Cfg_SetValueCb("target_has_atomic", [](const ::std::string& s) {
- if(s == "8") return true; // Has an atomic byte
- if(s == "ptr") return true; // Has an atomic pointer-sized value
- return false;
- });
- Cfg_SetValueCb("target_feature", [](const ::std::string& s) {
- return false;
- });
- Cfg_SetValueCb("feature", [¶ms](const ::std::string& s) {
- return params.features.count(s) != 0;
- });
-
-
-
- try
- {
- // Parse the crate into AST
- AST::Crate crate = CompilePhase<AST::Crate>("Parse", [&]() {
- return Parse_Crate(params.infile);
- });
-
- if( params.last_stage == ProgramParams::STAGE_PARSE ) {
- return 0;
- }
-
- // Load external crates.
- CompilePhaseV("LoadCrates", [&]() {
- crate.load_externs();
- });
-
- // Iterate all items in the AST, applying syntax extensions
- CompilePhaseV("Expand", [&]() {
- Expand(crate);
- });
-
- // Extract the crate type and name from the crate attributes
- auto crate_type = params.crate_type;
- if( crate_type == ::AST::Crate::Type::Unknown ) {
- crate_type = crate.m_crate_type;
- }
- if( crate_type == ::AST::Crate::Type::Unknown ) {
- // Assume to be executable
- crate_type = ::AST::Crate::Type::Executable;
- }
- crate.m_crate_type = crate_type;
- auto crate_name = crate.m_crate_name;
- if( crate_name == "" ) {
- auto s = params.infile.find_last_of('/');
- if( s == ::std::string::npos )
- s = 0;
- else
- s += 1;
- auto e = params.infile.find_first_of('.', s);
- if( e == ::std::string::npos )
- e = params.infile.size() - s;
-
- crate_name = ::std::string(params.infile.begin() + s, params.infile.begin() + e);
- for(auto& b : crate_name)
- {
- switch(b)
- {
- case '0' ... '9':
- case 'A' ... 'Z':
- case 'a' ... 'z':
- case '_':
- break;
- case '-':
- b = '_';
- break;
- default:
- break;
- }
- }
- crate.m_crate_name = crate_name;
- }
-
- if( params.outfile == "" ) {
- switch( crate.m_crate_type )
- {
- case ::AST::Crate::Type::RustLib:
- params.outfile = FMT(params.output_dir << "lib" << crate.m_crate_name << ".hir");
- break;
- case ::AST::Crate::Type::Executable:
- params.outfile = FMT(params.output_dir << crate.m_crate_name);
- break;
- default:
- params.outfile = FMT(params.output_dir << crate.m_crate_name << ".o");
- break;
- }
- DEBUG("params.outfile = " << params.outfile);
- }
-
- // XXX: Dump crate before resolve
- CompilePhaseV("Temp output - Parsed", [&]() {
- Dump_Rust( FMT(params.outfile << "_0a_exp.rs").c_str(), crate );
- });
-
- if( params.last_stage == ProgramParams::STAGE_EXPAND ) {
- return 0;
- }
-
- // Allocator and panic strategies
- if( crate.m_crate_type == ::AST::Crate::Type::Executable )
- {
- // TODO: Detect if an allocator crate is already present.
- crate.load_extern_crate(Span(), "alloc_system");
- crate.load_extern_crate(Span(), "panic_abort");
- }
-
- // Resolve names to be absolute names (include references to the relevant struct/global/function)
- // - This does name checking on types and free functions.
- // - Resolves all identifiers/paths to references
- CompilePhaseV("Resolve Use", [&]() {
- Resolve_Use(crate); // - Absolutise and resolve use statements
- });
- CompilePhaseV("Resolve Index", [&]() {
- Resolve_Index(crate); // - Build up a per-module index of avalable names (faster and simpler later resolve)
- });
- CompilePhaseV("Resolve Absolute", [&]() {
- Resolve_Absolutise(crate); // - Convert all paths to Absolute or UFCS, and resolve variables
- });
-
- // XXX: Dump crate before HIR
- CompilePhaseV("Temp output - Resolved", [&]() {
- Dump_Rust( FMT(params.outfile << "_1_res.rs").c_str(), crate );
- });
-
- if( params.last_stage == ProgramParams::STAGE_RESOLVE ) {
- return 0;
- }
-
- // --------------------------------------
- // HIR Section
- // --------------------------------------
- // Construc the HIR from the AST
- ::HIR::CratePtr hir_crate = CompilePhase< ::HIR::CratePtr>("HIR Lower", [&]() {
- return LowerHIR_FromAST(mv$( crate ));
- });
- // Deallocate the original crate
- crate = ::AST::Crate();
-
- // Replace type aliases (`type`) into the actual type
- CompilePhaseV("Resolve Type Aliases", [&]() {
- ConvertHIR_ExpandAliases(*hir_crate);
- });
- // Set up bindings and other useful information.
- CompilePhaseV("Resolve Bind", [&]() {
- ConvertHIR_Bind(*hir_crate);
- });
- CompilePhaseV("Resolve UFCS paths", [&]() {
- ConvertHIR_ResolveUFCS(*hir_crate);
- });
- CompilePhaseV("Resolve HIR Markings", [&]() {
- ConvertHIR_Markings(*hir_crate);
- });
- // Basic constant evalulation (intergers/floats only)
- CompilePhaseV("Constant Evaluate", [&]() {
- ConvertHIR_ConstantEvaluate(*hir_crate);
- });
-
- CompilePhaseV("Dump HIR", [&]() {
- ::std::ofstream os (FMT(params.outfile << "_2_hir.rs"));
- HIR_Dump( os, *hir_crate );
- });
-
- // === Type checking ===
- // - This can recurse and call the MIR lower to evaluate constants
-
- // Check outer items first (types of constants/functions/statics/impls/...)
- // - Doesn't do any expressions except those in types
- CompilePhaseV("Typecheck Outer", [&]() {
- Typecheck_ModuleLevel(*hir_crate);
- });
- // Check the rest of the expressions (including function bodies)
- CompilePhaseV("Typecheck Expressions", [&]() {
- Typecheck_Expressions(*hir_crate);
- });
- // === HIR Expansion ===
- // Annotate how each node's result is used
- CompilePhaseV("Expand HIR Annotate", [&]() {
- HIR_Expand_AnnotateUsage(*hir_crate);
- });
- // - Now that all types are known, closures can be desugared
- CompilePhaseV("Expand HIR Closures", [&]() {
- HIR_Expand_Closures(*hir_crate);
- });
- // - Construct VTables for all traits and impls.
- CompilePhaseV("Expand HIR VTables", [&]() { HIR_Expand_VTables(*hir_crate); });
- // - And calls can be turned into UFCS
- CompilePhaseV("Expand HIR Calls", [&]() {
- HIR_Expand_UfcsEverything(*hir_crate);
- });
- CompilePhaseV("Expand HIR Reborrows", [&]() {
- HIR_Expand_Reborrows(*hir_crate);
- });
- CompilePhaseV("Expand HIR ErasedType", [&]() {
- HIR_Expand_ErasedType(*hir_crate);
- });
- CompilePhaseV("Dump HIR", [&]() {
- ::std::ofstream os (FMT(params.outfile << "_2_hir.rs"));
- HIR_Dump( os, *hir_crate );
- });
- // - Ensure that typeck worked (including Fn trait call insertion etc)
- CompilePhaseV("Typecheck Expressions (validate)", [&]() {
- Typecheck_Expressions_Validate(*hir_crate);
- });
-
- if( params.last_stage == ProgramParams::STAGE_TYPECK ) {
- return 0;
- }
-
- // Lower expressions into MIR
- CompilePhaseV("Lower MIR", [&]() {
- HIR_GenerateMIR(*hir_crate);
- });
-
- CompilePhaseV("Dump MIR", [&]() {
- ::std::ofstream os (FMT(params.outfile << "_3_mir.rs"));
- MIR_Dump( os, *hir_crate );
- });
-
- // Validate the MIR
- CompilePhaseV("MIR Validate", [&]() {
- MIR_CheckCrate(*hir_crate);
- });
-
- // Second shot of constant evaluation (with full type information)
- CompilePhaseV("Constant Evaluate Full", [&]() {
- ConvertHIR_ConstantEvaluateFull(*hir_crate);
- });
- CompilePhaseV("Dump HIR", [&]() {
- ::std::ofstream os (FMT(params.outfile << "_2_hir.rs"));
- HIR_Dump( os, *hir_crate );
- });
-
- // - Expand constants in HIR and virtualise calls
- CompilePhaseV("MIR Cleanup", [&]() {
- MIR_CleanupCrate(*hir_crate);
- });
- // Optimise the MIR
- CompilePhaseV("MIR Optimise", [&]() {
- MIR_OptimiseCrate(*hir_crate);
- });
-
- CompilePhaseV("Dump MIR", [&]() {
- ::std::ofstream os (FMT(params.outfile << "_3_mir.rs"));
- MIR_Dump( os, *hir_crate );
- });
-
- if( params.last_stage == ProgramParams::STAGE_MIR ) {
- return 0;
- }
-
- // TODO: Pass to mark items that are
- // - Signature Exportable (public)
- // - MIR Exportable (public generic, #[inline], or used by a either of those)
- // - Require codegen (public or used by an exported function)
-
- // Generate code for non-generic public items (if requested)
- switch( crate_type )
- {
- case ::AST::Crate::Type::Unknown:
- // ERROR?
- break;
- case ::AST::Crate::Type::RustLib:
- // Save a loadable HIR dump
- CompilePhaseV("HIR Serialise", [&]() {
- //HIR_Serialise(params.outfile + ".meta", *hir_crate);
- HIR_Serialise(params.outfile, *hir_crate);
- });
- //TransList items;
- //CompilePhaseV("Trans Enumerate", [&]() { Trans_Enumerate_Public(*hir_crate); });
- //CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile + ".o", *hir_crate, items); });
- // Generate a .o
- //HIR_Codegen_Lib(params.outfile + ".o", *hir_crate);
- // Link metatdata and object into a .rlib
- break;
- case ::AST::Crate::Type::RustDylib:
- // Save a loadable HIR dump
- CompilePhaseV("HIR Serialise", [&]() { HIR_Serialise(params.outfile, *hir_crate); });
- // - Enumerate codegen for visible and non-generic items
- //TransList items;
- //CompilePhaseV("Trans Enumerate", [&]() { Trans_Enumerate_Public(*hir_crate); });
- //CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile, *hir_crate, items); });
- // Generate a .so/.dll
- // TODO: Codegen and include the metadata in a non-loadable segment
- break;
- case ::AST::Crate::Type::CDylib:
- // Generate a .so/.dll
- break;
- case ::AST::Crate::Type::Executable:
- // Generate a binary
- // - Enumerate items for translation
- TransList items = CompilePhase<TransList>("Trans Enumerate", [&]() { return Trans_Enumerate_Main(*hir_crate); });
- // - Perform codegen
- CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile, *hir_crate, items); });
- // - Invoke linker?
- break;
- }
- }
- catch(unsigned int) {}
- //catch(const CompileError::Base& e)
- //{
- // ::std::cerr << "Parser Error: " << e.what() << ::std::endl;
- // return 2;
- //}
- //catch(const ::std::exception& e)
- //{
- // ::std::cerr << "Misc Error: " << e.what() << ::std::endl;
- // return 2;
- //}
- //catch(const char* e)
- //{
- // ::std::cerr << "Internal Compiler Error: " << e << ::std::endl;
- // return 2;
- //}
- return 0;
-}
-
-ProgramParams::ProgramParams(int argc, char *argv[])
-{
- // Hacky command-line parsing
- for( int i = 1; i < argc; i ++ )
- {
- const char* arg = argv[i];
-
- if( arg[0] != '-' )
- {
- if( this->infile != "" )
- ;
- this->infile = arg;
-
- if( this->infile == "" )
- ;
- }
- else if( arg[1] != '-' )
- {
- arg ++; // eat '-'
- for( ; *arg; arg ++ )
- {
- switch(*arg)
- {
- // "-o <file>" : Set output file
- case 'o':
- if( i == argc - 1 ) {
- // TODO: BAIL!
- exit(1);
- }
- this->outfile = argv[++i];
- break;
- default:
- exit(1);
- }
- }
- }
- else
- {
- if( strcmp(arg, "--crate-path") == 0 ) {
- if( i == argc - 1 ) {
- ::std::cerr << "Flag --crate-path requires an argument" << ::std::endl;
- exit(1);
- }
- this->crate_path = argv[++i];
- }
- else if( strcmp(arg, "--out-dir") == 0 ) {
- if( i == argc - 1 ) {
- ::std::cerr << "Flag " << arg << " requires an argument" << ::std::endl;
- exit(1);
- }
- this->output_dir = argv[++i];
- if( this->output_dir == "" )
- ;
- if( this->output_dir.back() != '/' )
- this->output_dir += '/';
- }
- else if( strcmp(arg, "--crate-type") == 0 ) {
- if( i == argc - 1 ) {
- ::std::cerr << "Flag --crate-type requires an argument" << ::std::endl;
- exit(1);
- }
- const char* type_str = argv[++i];
-
- if( strcmp(type_str, "rlib") == 0 ) {
- this->crate_type = ::AST::Crate::Type::RustLib;
- }
- else {
- ::std::cerr << "Unknown value for --crate-type" << ::std::endl;
- exit(1);
- }
- }
- else if( strcmp(arg, "--cfg") == 0 ) {
- if( i == argc - 1 ) {
- ::std::cerr << "Flag --cfg requires an argument" << ::std::endl;
- exit(1);
- }
- char* opt_and_val = argv[++i];
- if( char* p = strchr(opt_and_val, '=') ) {
- *p = '\0';
- const char* opt = opt_and_val;
- const char* val = p + 1;
- if( ::std::strcmp(opt, "feature") == 0 ) {
- this->features.insert( ::std::string(val) );
- }
- else {
- Cfg_SetValue(opt, val);
- }
- }
- else {
- Cfg_SetFlag(opt_and_val);
- }
- }
- else if( strcmp(arg, "--stop-after") == 0 ) {
- if( i == argc - 1 ) {
- ::std::cerr << "Flag --stop-after requires an argument" << ::std::endl;
- exit(1);
- }
-
- arg = argv[++i];
- if( strcmp(arg, "parse") == 0 )
- this->last_stage = STAGE_PARSE;
- else if( strcmp(arg, "expand") == 0 )
- this->last_stage = STAGE_EXPAND;
- else if( strcmp(arg, "resolve") == 0 )
- this->last_stage = STAGE_RESOLVE;
- else if( strcmp(arg, "mir") == 0 )
- this->last_stage = STAGE_MIR;
- else if( strcmp(arg, "ALL") == 0 )
- this->last_stage = STAGE_ALL;
- else {
- ::std::cerr << "Unknown argument to --stop-after : '" << arg << "'" << ::std::endl;
- exit(1);
- }
- }
- else {
- ::std::cerr << "Unknown option '" << arg << "'" << ::std::endl;
- exit(1);
- }
- }
- }
-}
-
+/* + * MRustC - Rust Compiler + * - By John Hodge (Mutabah/thePowersGang) + * + * main.cpp + * - Compiler Entrypoint + */ +#include <iostream> +#include <iomanip> +#include <string> +#include <set> +#include "parse/lex.hpp" +#include "parse/parseerror.hpp" +#include "ast/ast.hpp" +#include "ast/crate.hpp" +#include <serialiser_texttree.hpp> +#include <cstring> +#include <main_bindings.hpp> +#include "resolve/main_bindings.hpp" +#include "hir/main_bindings.hpp" +#include "hir_conv/main_bindings.hpp" +#include "hir_typeck/main_bindings.hpp" +#include "hir_expand/main_bindings.hpp" +#include "mir/main_bindings.hpp" +#include "trans/main_bindings.hpp" + +#include "expand/cfg.hpp" + +int g_debug_indent_level = 0; +bool g_debug_enabled = true; +::std::string g_cur_phase; +::std::set< ::std::string> g_debug_disable_map; + +void init_debug_list() +{ + g_debug_disable_map.insert( "Parse" ); + g_debug_disable_map.insert( "LoadCrates" ); + g_debug_disable_map.insert( "Expand" ); + + g_debug_disable_map.insert( "Resolve Use" ); + g_debug_disable_map.insert( "Resolve Index" ); + g_debug_disable_map.insert( "Resolve Absolute" ); + + g_debug_disable_map.insert( "HIR Lower" ); + + g_debug_disable_map.insert( "Resolve Type Aliases" ); + g_debug_disable_map.insert( "Resolve Bind" ); + g_debug_disable_map.insert( "Resolve UFCS paths" ); + g_debug_disable_map.insert( "Resolve HIR Markings" ); + g_debug_disable_map.insert( "Constant Evaluate" ); + + g_debug_disable_map.insert( "Typecheck Outer"); + g_debug_disable_map.insert( "Typecheck Expressions" ); + + g_debug_disable_map.insert( "Expand HIR Annotate" ); + g_debug_disable_map.insert( "Expand HIR Closures" ); + g_debug_disable_map.insert( "Expand HIR Calls" ); + g_debug_disable_map.insert( "Expand HIR VTables" ); + g_debug_disable_map.insert( "Expand HIR Reborrows" ); + g_debug_disable_map.insert( "Expand HIR ErasedType" ); + g_debug_disable_map.insert( "Typecheck Expressions (validate)" ); + + g_debug_disable_map.insert( "Dump HIR" ); + g_debug_disable_map.insert( "Lower MIR" ); + g_debug_disable_map.insert( "MIR Validate" ); + g_debug_disable_map.insert( "Dump MIR" ); + g_debug_disable_map.insert( "Constant Evaluate Full" ); + g_debug_disable_map.insert( "MIR Cleanup" ); + g_debug_disable_map.insert( "MIR Optimise" ); + + g_debug_disable_map.insert( "HIR Serialise" ); + g_debug_disable_map.insert( "Trans Enumerate" ); + g_debug_disable_map.insert( "Trans Codegen" ); + + // Mutate this map using an environment variable + const char* debug_string = ::std::getenv("MRUSTC_DEBUG"); + if( debug_string ) + { + while( debug_string[0] ) + { + const char* end = strchr(debug_string, ':'); + + if( end ) { + ::std::string s { debug_string, end }; + // TODO: Emit a warning when this name wasn't in the map? + g_debug_disable_map.erase( s ); + debug_string = end + 1; + } + else { + g_debug_disable_map.erase( debug_string ); + break; + } + } + } +} +bool debug_enabled_update() { + if( g_debug_disable_map.count(g_cur_phase) != 0 ) { + return false; + } + else { + return true; + } +} +bool debug_enabled() +{ + return g_debug_enabled; +} +::std::ostream& debug_output(int indent, const char* function) +{ + return ::std::cout << g_cur_phase << "- " << RepeatLitStr { " ", indent } << function << ": "; +} + +struct ProgramParams +{ + enum eLastStage { + STAGE_PARSE, + STAGE_EXPAND, + STAGE_RESOLVE, + STAGE_TYPECK, + STAGE_BORROWCK, + STAGE_MIR, + STAGE_ALL, + } last_stage = STAGE_ALL; + + ::std::string infile; + ::std::string outfile; + ::std::string output_dir = ""; + const char *crate_path = "."; + + ::AST::Crate::Type crate_type = ::AST::Crate::Type::Unknown; + + ::std::set< ::std::string> features; + + ProgramParams(int argc, char *argv[]); +}; + +template <typename Rv, typename Fcn> +Rv CompilePhase(const char *name, Fcn f) { + ::std::cout << name << ": V V V" << ::std::endl; + g_cur_phase = name; + g_debug_enabled = debug_enabled_update(); + auto start = clock(); + auto rv = f(); + auto end = clock(); + g_cur_phase = ""; + g_debug_enabled = debug_enabled_update(); + + ::std::cout <<"(" << ::std::fixed << ::std::setprecision(2) << static_cast<double>(end - start) / static_cast<double>(CLOCKS_PER_SEC) << " s) "; + ::std::cout << name << ": DONE"; + ::std::cout << ::std::endl; + return rv; +} +template <typename Fcn> +void CompilePhaseV(const char *name, Fcn f) { + CompilePhase<int>(name, [&]() { f(); return 0; }); +} + +/// main! +int main(int argc, char *argv[]) +{ + init_debug_list(); + ProgramParams params(argc, argv); + + // Set up cfg values + // TODO: Target spec + Cfg_SetFlag("unix"); + Cfg_SetFlag("linux"); + Cfg_SetValue("target_os", "linux"); + Cfg_SetValue("target_pointer_width", "64"); + Cfg_SetValue("target_endian", "little"); + Cfg_SetValue("target_arch", "x86_64"); + Cfg_SetValue("target_env", "gnu"); + Cfg_SetValueCb("target_has_atomic", [](const ::std::string& s) { + if(s == "8") return true; // Has an atomic byte + if(s == "ptr") return true; // Has an atomic pointer-sized value + return false; + }); + Cfg_SetValueCb("target_feature", [](const ::std::string& s) { + return false; + }); + Cfg_SetValueCb("feature", [¶ms](const ::std::string& s) { + return params.features.count(s) != 0; + }); + + + + try + { + // Parse the crate into AST + AST::Crate crate = CompilePhase<AST::Crate>("Parse", [&]() { + return Parse_Crate(params.infile); + }); + + if( params.last_stage == ProgramParams::STAGE_PARSE ) { + return 0; + } + + // Load external crates. + CompilePhaseV("LoadCrates", [&]() { + crate.load_externs(); + }); + + // Iterate all items in the AST, applying syntax extensions + CompilePhaseV("Expand", [&]() { + Expand(crate); + }); + + // Extract the crate type and name from the crate attributes + auto crate_type = params.crate_type; + if( crate_type == ::AST::Crate::Type::Unknown ) { + crate_type = crate.m_crate_type; + } + if( crate_type == ::AST::Crate::Type::Unknown ) { + // Assume to be executable + crate_type = ::AST::Crate::Type::Executable; + } + crate.m_crate_type = crate_type; + auto crate_name = crate.m_crate_name; + if( crate_name == "" ) { + auto s = params.infile.find_last_of('/'); + if( s == ::std::string::npos ) + s = 0; + else + s += 1; + auto e = params.infile.find_first_of('.', s); + if( e == ::std::string::npos ) + e = params.infile.size() - s; + + crate_name = ::std::string(params.infile.begin() + s, params.infile.begin() + e); + for(auto& b : crate_name) + { + switch(b) + { + case '0' ... '9': + case 'A' ... 'Z': + case 'a' ... 'z': + case '_': + break; + case '-': + b = '_'; + break; + default: + break; + } + } + crate.m_crate_name = crate_name; + } + + if( params.outfile == "" ) { + switch( crate.m_crate_type ) + { + case ::AST::Crate::Type::RustLib: + params.outfile = FMT(params.output_dir << "lib" << crate.m_crate_name << ".hir"); + break; + case ::AST::Crate::Type::Executable: + params.outfile = FMT(params.output_dir << crate.m_crate_name); + break; + default: + params.outfile = FMT(params.output_dir << crate.m_crate_name << ".o"); + break; + } + DEBUG("params.outfile = " << params.outfile); + } + + // XXX: Dump crate before resolve + CompilePhaseV("Temp output - Parsed", [&]() { + Dump_Rust( FMT(params.outfile << "_0a_exp.rs").c_str(), crate ); + }); + + if( params.last_stage == ProgramParams::STAGE_EXPAND ) { + return 0; + } + + // Allocator and panic strategies + if( crate.m_crate_type == ::AST::Crate::Type::Executable ) + { + // TODO: Detect if an allocator crate is already present. + crate.load_extern_crate(Span(), "alloc_system"); + crate.load_extern_crate(Span(), "panic_abort"); + } + + // Resolve names to be absolute names (include references to the relevant struct/global/function) + // - This does name checking on types and free functions. + // - Resolves all identifiers/paths to references + CompilePhaseV("Resolve Use", [&]() { + Resolve_Use(crate); // - Absolutise and resolve use statements + }); + CompilePhaseV("Resolve Index", [&]() { + Resolve_Index(crate); // - Build up a per-module index of avalable names (faster and simpler later resolve) + }); + CompilePhaseV("Resolve Absolute", [&]() { + Resolve_Absolutise(crate); // - Convert all paths to Absolute or UFCS, and resolve variables + }); + + // XXX: Dump crate before HIR + CompilePhaseV("Temp output - Resolved", [&]() { + Dump_Rust( FMT(params.outfile << "_1_res.rs").c_str(), crate ); + }); + + if( params.last_stage == ProgramParams::STAGE_RESOLVE ) { + return 0; + } + + // -------------------------------------- + // HIR Section + // -------------------------------------- + // Construc the HIR from the AST + ::HIR::CratePtr hir_crate = CompilePhase< ::HIR::CratePtr>("HIR Lower", [&]() { + return LowerHIR_FromAST(mv$( crate )); + }); + // Deallocate the original crate + crate = ::AST::Crate(); + + // Replace type aliases (`type`) into the actual type + CompilePhaseV("Resolve Type Aliases", [&]() { + ConvertHIR_ExpandAliases(*hir_crate); + }); + // Set up bindings and other useful information. + CompilePhaseV("Resolve Bind", [&]() { + ConvertHIR_Bind(*hir_crate); + }); + CompilePhaseV("Resolve UFCS paths", [&]() { + ConvertHIR_ResolveUFCS(*hir_crate); + }); + CompilePhaseV("Resolve HIR Markings", [&]() { + ConvertHIR_Markings(*hir_crate); + }); + // Basic constant evalulation (intergers/floats only) + CompilePhaseV("Constant Evaluate", [&]() { + ConvertHIR_ConstantEvaluate(*hir_crate); + }); + + CompilePhaseV("Dump HIR", [&]() { + ::std::ofstream os (FMT(params.outfile << "_2_hir.rs")); + HIR_Dump( os, *hir_crate ); + }); + + // === Type checking === + // - This can recurse and call the MIR lower to evaluate constants + + // Check outer items first (types of constants/functions/statics/impls/...) + // - Doesn't do any expressions except those in types + CompilePhaseV("Typecheck Outer", [&]() { + Typecheck_ModuleLevel(*hir_crate); + }); + // Check the rest of the expressions (including function bodies) + CompilePhaseV("Typecheck Expressions", [&]() { + Typecheck_Expressions(*hir_crate); + }); + // === HIR Expansion === + // Annotate how each node's result is used + CompilePhaseV("Expand HIR Annotate", [&]() { + HIR_Expand_AnnotateUsage(*hir_crate); + }); + // - Now that all types are known, closures can be desugared + CompilePhaseV("Expand HIR Closures", [&]() { + HIR_Expand_Closures(*hir_crate); + }); + // - Construct VTables for all traits and impls. + CompilePhaseV("Expand HIR VTables", [&]() { HIR_Expand_VTables(*hir_crate); }); + // - And calls can be turned into UFCS + CompilePhaseV("Expand HIR Calls", [&]() { + HIR_Expand_UfcsEverything(*hir_crate); + }); + CompilePhaseV("Expand HIR Reborrows", [&]() { + HIR_Expand_Reborrows(*hir_crate); + }); + CompilePhaseV("Expand HIR ErasedType", [&]() { + HIR_Expand_ErasedType(*hir_crate); + }); + CompilePhaseV("Dump HIR", [&]() { + ::std::ofstream os (FMT(params.outfile << "_2_hir.rs")); + HIR_Dump( os, *hir_crate ); + }); + // - Ensure that typeck worked (including Fn trait call insertion etc) + CompilePhaseV("Typecheck Expressions (validate)", [&]() { + Typecheck_Expressions_Validate(*hir_crate); + }); + + if( params.last_stage == ProgramParams::STAGE_TYPECK ) { + return 0; + } + + // Lower expressions into MIR + CompilePhaseV("Lower MIR", [&]() { + HIR_GenerateMIR(*hir_crate); + }); + + CompilePhaseV("Dump MIR", [&]() { + ::std::ofstream os (FMT(params.outfile << "_3_mir.rs")); + MIR_Dump( os, *hir_crate ); + }); + + // Validate the MIR + CompilePhaseV("MIR Validate", [&]() { + MIR_CheckCrate(*hir_crate); + }); + + // Second shot of constant evaluation (with full type information) + CompilePhaseV("Constant Evaluate Full", [&]() { + ConvertHIR_ConstantEvaluateFull(*hir_crate); + }); + CompilePhaseV("Dump HIR", [&]() { + ::std::ofstream os (FMT(params.outfile << "_2_hir.rs")); + HIR_Dump( os, *hir_crate ); + }); + + // - Expand constants in HIR and virtualise calls + CompilePhaseV("MIR Cleanup", [&]() { + MIR_CleanupCrate(*hir_crate); + }); + // Optimise the MIR + CompilePhaseV("MIR Optimise", [&]() { + MIR_OptimiseCrate(*hir_crate); + }); + + CompilePhaseV("Dump MIR", [&]() { + ::std::ofstream os (FMT(params.outfile << "_3_mir.rs")); + MIR_Dump( os, *hir_crate ); + }); + + if( params.last_stage == ProgramParams::STAGE_MIR ) { + return 0; + } + + // TODO: Pass to mark items that are + // - Signature Exportable (public) + // - MIR Exportable (public generic, #[inline], or used by a either of those) + // - Require codegen (public or used by an exported function) + + // Generate code for non-generic public items (if requested) + switch( crate_type ) + { + case ::AST::Crate::Type::Unknown: + // ERROR? + break; + case ::AST::Crate::Type::RustLib: + // Save a loadable HIR dump + CompilePhaseV("HIR Serialise", [&]() { + //HIR_Serialise(params.outfile + ".meta", *hir_crate); + HIR_Serialise(params.outfile, *hir_crate); + }); + //TransList items; + //CompilePhaseV("Trans Enumerate", [&]() { Trans_Enumerate_Public(*hir_crate); }); + //CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile + ".o", *hir_crate, items); }); + // Generate a .o + //HIR_Codegen_Lib(params.outfile + ".o", *hir_crate); + // Link metatdata and object into a .rlib + break; + case ::AST::Crate::Type::RustDylib: + // Save a loadable HIR dump + CompilePhaseV("HIR Serialise", [&]() { HIR_Serialise(params.outfile, *hir_crate); }); + // - Enumerate codegen for visible and non-generic items + //TransList items; + //CompilePhaseV("Trans Enumerate", [&]() { Trans_Enumerate_Public(*hir_crate); }); + //CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile, *hir_crate, items); }); + // Generate a .so/.dll + // TODO: Codegen and include the metadata in a non-loadable segment + break; + case ::AST::Crate::Type::CDylib: + // Generate a .so/.dll + break; + case ::AST::Crate::Type::Executable: + // Generate a binary + // - Enumerate items for translation + TransList items = CompilePhase<TransList>("Trans Enumerate", [&]() { return Trans_Enumerate_Main(*hir_crate); }); + // - Perform codegen + CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile, *hir_crate, items); }); + // - Invoke linker? + break; + } + } + catch(unsigned int) {} + //catch(const CompileError::Base& e) + //{ + // ::std::cerr << "Parser Error: " << e.what() << ::std::endl; + // return 2; + //} + //catch(const ::std::exception& e) + //{ + // ::std::cerr << "Misc Error: " << e.what() << ::std::endl; + // return 2; + //} + //catch(const char* e) + //{ + // ::std::cerr << "Internal Compiler Error: " << e << ::std::endl; + // return 2; + //} + return 0; +} + +ProgramParams::ProgramParams(int argc, char *argv[]) +{ + // Hacky command-line parsing + for( int i = 1; i < argc; i ++ ) + { + const char* arg = argv[i]; + + if( arg[0] != '-' ) + { + if( this->infile != "" ) + ; + this->infile = arg; + + if( this->infile == "" ) + ; + } + else if( arg[1] != '-' ) + { + arg ++; // eat '-' + for( ; *arg; arg ++ ) + { + switch(*arg) + { + // "-o <file>" : Set output file + case 'o': + if( i == argc - 1 ) { + // TODO: BAIL! + exit(1); + } + this->outfile = argv[++i]; + break; + default: + exit(1); + } + } + } + else + { + if( strcmp(arg, "--crate-path") == 0 ) { + if( i == argc - 1 ) { + ::std::cerr << "Flag --crate-path requires an argument" << ::std::endl; + exit(1); + } + this->crate_path = argv[++i]; + } + else if( strcmp(arg, "--out-dir") == 0 ) { + if( i == argc - 1 ) { + ::std::cerr << "Flag " << arg << " requires an argument" << ::std::endl; + exit(1); + } + this->output_dir = argv[++i]; + if( this->output_dir == "" ) + ; + if( this->output_dir.back() != '/' ) + this->output_dir += '/'; + } + else if( strcmp(arg, "--crate-type") == 0 ) { + if( i == argc - 1 ) { + ::std::cerr << "Flag --crate-type requires an argument" << ::std::endl; + exit(1); + } + const char* type_str = argv[++i]; + + if( strcmp(type_str, "rlib") == 0 ) { + this->crate_type = ::AST::Crate::Type::RustLib; + } + else { + ::std::cerr << "Unknown value for --crate-type" << ::std::endl; + exit(1); + } + } + else if( strcmp(arg, "--cfg") == 0 ) { + if( i == argc - 1 ) { + ::std::cerr << "Flag --cfg requires an argument" << ::std::endl; + exit(1); + } + char* opt_and_val = argv[++i]; + if( char* p = strchr(opt_and_val, '=') ) { + *p = '\0'; + const char* opt = opt_and_val; + const char* val = p + 1; + if( ::std::strcmp(opt, "feature") == 0 ) { + this->features.insert( ::std::string(val) ); + } + else { + Cfg_SetValue(opt, val); + } + } + else { + Cfg_SetFlag(opt_and_val); + } + } + else if( strcmp(arg, "--stop-after") == 0 ) { + if( i == argc - 1 ) { + ::std::cerr << "Flag --stop-after requires an argument" << ::std::endl; + exit(1); + } + + arg = argv[++i]; + if( strcmp(arg, "parse") == 0 ) + this->last_stage = STAGE_PARSE; + else if( strcmp(arg, "expand") == 0 ) + this->last_stage = STAGE_EXPAND; + else if( strcmp(arg, "resolve") == 0 ) + this->last_stage = STAGE_RESOLVE; + else if( strcmp(arg, "mir") == 0 ) + this->last_stage = STAGE_MIR; + else if( strcmp(arg, "ALL") == 0 ) + this->last_stage = STAGE_ALL; + else { + ::std::cerr << "Unknown argument to --stop-after : '" << arg << "'" << ::std::endl; + exit(1); + } + } + else { + ::std::cerr << "Unknown option '" << arg << "'" << ::std::endl; + exit(1); + } + } + } +} + diff --git a/src/mir/check.cpp b/src/mir/check.cpp index 65473b50..186e93fb 100644 --- a/src/mir/check.cpp +++ b/src/mir/check.cpp @@ -35,10 +35,10 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path continue ; } visited_bbs[block] = true; - - + + state.set_cur_stmt_term(block); - + #define PUSH_BB(idx, desc) do {\ if( !(idx < fcn.blocks.size() ) ) MIR_BUG(state, "Invalid target block - " << desc << " bb" << idx);\ if( visited_bbs[idx] == false ) {\ @@ -81,7 +81,7 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path DEBUG("- Function doesn't return."); } } - + // [ValState] = Value state tracking (use after move, uninit, ...) // - [ValState] No drops or usage of uninitalised values (Uninit, Moved, or Dropped) // - [ValState] Temporaries are write-once. @@ -98,7 +98,7 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path ::std::vector<State> arguments; ::std::vector<State> temporaries; ::std::vector<State> variables; - + ValStates() {} ValStates(size_t n_args, size_t n_temps, size_t n_vars): arguments(n_args, State::Valid), @@ -106,11 +106,11 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path variables(n_vars) { } - + bool empty() const { return arguments.empty() && temporaries.empty() && variables.empty(); } - + bool merge(ValStates& other) { if( this->empty() ) @@ -131,7 +131,7 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path return rv; } } - + void mark_validity(const ::MIR::TypeResolve& state, const ::MIR::LValue& lv, bool is_valid) { TU_MATCH_DEF( ::MIR::LValue, (lv), (e), @@ -228,7 +228,7 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path auto val_state = mv$( to_visit_blocks.back().second ); to_visit_blocks.pop_back(); assert(block < fcn.blocks.size()); - + // 1. Apply current state to `block_start_states` (merging if needed) // - If no change happened, skip. if( ! block_start_states.at(block).merge( val_state ) ) { @@ -241,7 +241,7 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path { const auto& stmt = bb.statements[stmt_idx]; state.set_cur_stmt(block, stmt_idx); - + if( stmt.is_Drop() ) { // Invalidate the slot @@ -366,14 +366,14 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path { const auto& stmt = bb.statements[stmt_idx]; state.set_cur_stmt(bb_idx, stmt_idx); - + switch( stmt.tag() ) { case ::MIR::Statement::TAGDEAD: throw ""; case ::MIR::Statement::TAG_Assign: { const auto& a = stmt.as_Assign(); - + auto check_type = [&](const auto& src_ty) { ::HIR::TypeRef tmp; const auto& dst_ty = state.get_lvalue_type(tmp, a.dst); @@ -528,7 +528,7 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path break; } } - + state.set_cur_stmt_term(bb_idx); TU_MATCH(::MIR::Terminator, (bb.terminator), (e), (Incomplete, diff --git a/src/mir/cleanup.cpp b/src/mir/cleanup.cpp index 972914a6..5744a033 100644 --- a/src/mir/cleanup.cpp +++ b/src/mir/cleanup.cpp @@ -23,32 +23,32 @@ struct MirMutator unsigned int cur_block; unsigned int cur_stmt; mutable ::std::vector< ::MIR::Statement> new_statements; - + MirMutator(::MIR::Function& fcn, unsigned int bb, unsigned int stmt): m_fcn(fcn), cur_block(bb), cur_stmt(stmt) { } - + ::MIR::LValue new_temporary(::HIR::TypeRef ty) { auto rv = ::MIR::LValue::make_Temporary({ static_cast<unsigned int>(m_fcn.temporaries.size()) }); m_fcn.temporaries.push_back( mv$(ty) ); return rv; } - + void push_statement(::MIR::Statement stmt) { new_statements.push_back( mv$(stmt) ); } - + ::MIR::LValue in_temporary(::HIR::TypeRef ty, ::MIR::RValue val) { auto rv = this->new_temporary( mv$(ty) ); push_statement( ::MIR::Statement::make_Assign({ rv.clone(), mv$(val) }) ); return rv; } - + decltype(new_statements.begin()) flush() { DEBUG("flush - " << cur_block << "/" << cur_stmt); @@ -101,37 +101,37 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR MIR_ASSERT(state, lit.is_List(), "Non-list literal for Tuple - " << lit); const auto& vals = lit.as_List(); MIR_ASSERT(state, vals.size() == te.size(), "Literal size mismatched with tuple size"); - + ::std::vector< ::MIR::LValue> lvals; lvals.reserve( vals.size() ); - + for(unsigned int i = 0; i < vals.size(); i ++) { auto rval = MIR_Cleanup_LiteralToRValue(state, mutator, vals[i], te[i].clone(), ::HIR::GenericPath()); lvals.push_back( mutator.in_temporary( mv$(te[i]), mv$(rval)) ); } - + return ::MIR::RValue::make_Tuple({ mv$(lvals) }); ), (Array, MIR_ASSERT(state, lit.is_List(), "Non-list literal for Array - " << lit); const auto& vals = lit.as_List(); - + MIR_ASSERT(state, vals.size() == te.size_val, "Literal size mismatched with array size"); - + bool is_all_same = false; if( vals.size() > 1 ) { is_all_same = true; for(unsigned int i = 1; i < vals.size(); i ++) { - + if( vals[i] != vals[0] ) { is_all_same = false; break ; } } } - + if( is_all_same ) { auto rval = MIR_Cleanup_LiteralToRValue(state, mutator, vals[0], te.inner->clone(), ::HIR::GenericPath()); @@ -142,13 +142,13 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR { ::std::vector< ::MIR::LValue> lvals; lvals.reserve( vals.size() ); - + for(const auto& val: vals) { auto rval = MIR_Cleanup_LiteralToRValue(state, mutator, val, te.inner->clone(), ::HIR::GenericPath()); lvals.push_back( mutator.in_temporary(te.inner->clone(), mv$(rval)) ); } - + return ::MIR::RValue::make_Array({ mv$(lvals) }); } ), @@ -157,9 +157,9 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR { const auto& str = *te.binding.as_Struct(); const auto& vals = lit.as_List(); - + auto monomorph = [&](const auto& tpl) { return monomorphise_type(state.sp, str.m_params, te.path.m_data.as_Generic().m_params, tpl); }; - + ::std::vector< ::MIR::LValue> lvals; TU_MATCHA( (str.m_data), (se), (Unit, @@ -190,9 +190,9 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR { const auto& enm = *te.binding.as_Enum(); const auto& lit_var = lit.as_Variant(); - + auto monomorph = [&](const auto& tpl) { return monomorphise_type(state.sp, enm.m_params, te.path.m_data.as_Generic().m_params, tpl); }; - + ::std::vector< ::MIR::LValue> lvals; MIR_ASSERT(state, lit_var.idx < enm.m_variants.size(), "Variant index out of range"); TU_MATCHA( (enm.m_variants[lit_var.idx].second), (ve), @@ -254,7 +254,7 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR ), (Pointer, if( lit.is_BorrowOf() ) { - // TODO: + // TODO: MIR_TODO(state, "BorrowOf into pointer - " << lit << " into " << ty); } else { @@ -272,11 +272,11 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR const auto& ty = state.get_static_type(tmp, path); MIR_ASSERT(state, ty.m_data.is_Array(), "BorrowOf returning slice not of an array, instead " << ty); unsigned int size = ty.m_data.as_Array().size_val; - + auto ptr_type = ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, (&ty == &tmp ? mv$(tmp) : ty.clone()) ); - + auto ptr_lval = mutator.in_temporary( mv$(ptr_type), ::MIR::Constant::make_ItemAddr(path.clone()) ); auto size_lval = mutator.in_temporary( ::HIR::CoreType::Usize, ::MIR::Constant::make_Uint(size) ); return ::MIR::RValue::make_MakeDst({ mv$(ptr_lval), mv$(size_lval) }); @@ -317,7 +317,7 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR { assert( te.m_trait.m_trait_ptr ); const auto& trait = *te.m_trait.m_trait_ptr; - + // 1. Get the vtable index for this function auto it = trait.m_value_indexes.find( pe.item ); while( it != trait.m_value_indexes.end() ) @@ -333,7 +333,7 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR if( it == trait.m_value_indexes.end() || it->first != pe.item ) BUG(sp, "Calling method '" << pe.item << "' from " << pe.trait << " through " << te.m_trait.m_path << " which isn't in the vtable"); unsigned int vtable_idx = it->second.first; - + // 2. Load from the vtable auto vtable_ty_spath = te.m_trait.m_path.m_path; vtable_ty_spath.m_components.back() += "#vtable"; @@ -351,15 +351,15 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR ::HIR::BorrowType::Shared, ::HIR::TypeRef( ::HIR::GenericPath(vtable_ty_spath, mv$(vtable_params)), &vtable_ref ) ); - + // Allocate a temporary for the vtable pointer itself auto vtable_lv = mutator.new_temporary( mv$(vtable_ty) ); // - Load the vtable and store it auto vtable_rval = ::MIR::RValue::make_DstMeta({ ::MIR::LValue::make_Deref({ box$(receiver_lvp.clone()) }) }); 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 }); - + ::HIR::TypeRef tmp; const auto& ty = state.get_lvalue_type(tmp, fcn_lval); const auto& receiver = ty.m_data.as_Function().m_arg_types.at(0); @@ -368,7 +368,7 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR // TODO: If the receiver is Box, create a Box<()> as the value. // - Requires de/restructuring the Box same as CoerceUnsized // - Can use the `coerce_unsized_index` field too - + struct H { static ::MIR::LValue get_unit_ptr(const ::MIR::TypeResolve& state, MirMutator& mutator, ::HIR::TypeRef ty, ::MIR::LValue lv) { @@ -407,7 +407,7 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR } ) ) - + auto new_path = ty_path.clone(); return mutator.in_temporary( mv$(ty), ::MIR::RValue::make_Struct({ mv$(new_path), ~0u, mv$(vals) }) ); } @@ -424,18 +424,18 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const Span& sp, const StaticTraitR } } }; - + receiver_lvp = H::get_unit_ptr(state,mutator, receiver.clone(), receiver_lvp.clone()); } else { auto ptr_rval = ::MIR::RValue::make_DstPtr({ ::MIR::LValue::make_Deref({ box$(receiver_lvp.clone()) }) }); - + auto ptr_lv = mutator.new_temporary( ::HIR::TypeRef::new_pointer(::HIR::BorrowType::Shared, ::HIR::TypeRef::new_unit()) ); mutator.push_statement( ::MIR::Statement::make_Assign({ ptr_lv.clone(), mv$(ptr_rval) }) ); receiver_lvp = mv$(ptr_lv); } - + // Update the terminator with the new information. return fcn_lval; } @@ -457,7 +457,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator& // Source must be Path and Unsize if( de.binding.is_Opaque() ) return false; - + MIR_ASSERT(state, src_ty.m_data.is_Path(), "Unsize to path from non-path - " << src_ty); const auto& se = src_ty.m_data.as_Path(); MIR_ASSERT(state, de.binding.tag() == se.binding.tag(), "Unsize between mismatched types - " << dst_ty << " and " << src_ty); @@ -465,10 +465,10 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator& MIR_ASSERT(state, de.binding.as_Struct() == se.binding.as_Struct(), "Unsize between mismatched types - " << dst_ty << " and " << src_ty); const auto& str = *de.binding.as_Struct(); MIR_ASSERT(state, str.m_markings.unsized_field != ~0u, "Unsize on type that doesn't implement have a ?Sized field - " << dst_ty); - + auto monomorph_cb_d = monomorphise_type_get_cb(state.sp, nullptr, &de.path.m_data.as_Generic().m_params, nullptr); auto monomorph_cb_s = monomorphise_type_get_cb(state.sp, nullptr, &se.path.m_data.as_Generic().m_params, nullptr); - + // Return GetMetadata on the inner type TU_MATCHA( (str.m_data), (se), (Unit, @@ -478,14 +478,14 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator& const auto& ty_tpl = se.at( str.m_markings.unsized_field ).ent; auto ty_d = monomorphise_type_with(state.sp, ty_tpl, monomorph_cb_d, false); auto ty_s = monomorphise_type_with(state.sp, ty_tpl, monomorph_cb_s, false); - + return MIR_Cleanup_Unsize_GetMetadata(state, mutator, ty_d, ty_s, ptr_value, out_meta_val,out_meta_ty,out_src_is_dst); ), (Named, const auto& ty_tpl = se.at( str.m_markings.unsized_field ).second.ent; auto ty_d = monomorphise_type_with(state.sp, ty_tpl, monomorph_cb_d, false); auto ty_s = monomorphise_type_with(state.sp, ty_tpl, monomorph_cb_s, false); - + return MIR_Cleanup_Unsize_GetMetadata(state, mutator, ty_d, ty_s, ptr_value, out_meta_val,out_meta_ty,out_src_is_dst); ) ) @@ -504,9 +504,9 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator& { // HACK: FixedSizeArray uses `A: Unsize<[T]>` which will lead to the above code not working (as the size isn't known). // - Maybe _Meta on the `&A` would work as a stopgap (since A: Sized, it won't collide with &[T] or similar) - + return false; - + //out_meta_ty = ::HIR::CoreType::Usize; //out_meta_val = ::MIR::RValue::make_DstMeta({ ptr_value.clone() }); //return true; @@ -517,9 +517,9 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator& } ), (TraitObject, - + auto ty_unit_ptr = ::HIR::TypeRef::new_pointer(::HIR::BorrowType::Shared, ::HIR::TypeRef::new_unit()); - + // No data trait, vtable is a null unit pointer. // - Shouldn't the vtable be just unit? // - Codegen assumes it's a pointer. @@ -548,9 +548,9 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator& vtable_params.m_types[idx] = ty_b.second.clone(); } auto vtable_type = ::HIR::TypeRef( ::HIR::GenericPath(vtable_ty_spath, mv$(vtable_params)), &vtable_ref ); - + out_meta_ty = ::HIR::TypeRef::new_pointer(::HIR::BorrowType::Shared, mv$(vtable_type)); - + // If the data trait hasn't changed, return the vtable pointer if( src_ty.m_data.is_TraitObject() ) { @@ -572,7 +572,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator& ::MIR::RValue MIR_Cleanup_Unsize(const ::MIR::TypeResolve& state, MirMutator& mutator, const ::HIR::TypeRef& dst_ty, const ::HIR::TypeRef& src_ty_inner, ::MIR::LValue ptr_value) { const auto& dst_ty_inner = (dst_ty.m_data.is_Borrow() ? *dst_ty.m_data.as_Borrow().inner : *dst_ty.m_data.as_Pointer().inner); - + ::HIR::TypeRef meta_type; ::MIR::RValue meta_value; bool source_is_dst = false; @@ -585,7 +585,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator& auto ty_unit_ptr = ::HIR::TypeRef::new_pointer(::HIR::BorrowType::Shared, ::HIR::TypeRef::new_unit()); auto deref_ptr_val = ::MIR::LValue::make_Deref({ box$(ptr_value) }); auto thin_ptr_lval = mutator.in_temporary( mv$(ty_unit_ptr), ::MIR::RValue::make_DstPtr({ mv$(deref_ptr_val) }) ); - + return ::MIR::RValue::make_MakeDst({ mv$(thin_ptr_lval), mv$(meta_lval) }); } else @@ -610,7 +610,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator& MIR_ASSERT(state, src_ty.m_data.is_Path(), "CoerceUnsized to Path must have a Path source - " << src_ty << " to " << dst_ty); const auto& dte = dst_ty.m_data.as_Path(); const auto& ste = src_ty.m_data.as_Path(); - + // - Types must differ only by a single field, and be from the same definition MIR_ASSERT(state, dte.binding.is_Struct(), "Note, can't CoerceUnsized non-structs"); MIR_ASSERT(state, dte.binding.tag() == ste.binding.tag(), @@ -620,10 +620,10 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator& const auto& str = *dte.binding.as_Struct(); MIR_ASSERT(state, str.m_markings.coerce_unsized_index != ~0u, "Struct " << src_ty << " doesn't impl CoerceUnsized"); - + auto monomorph_cb_d = monomorphise_type_get_cb(state.sp, nullptr, &dte.path.m_data.as_Generic().m_params, nullptr); auto monomorph_cb_s = monomorphise_type_get_cb(state.sp, nullptr, &ste.path.m_data.as_Generic().m_params, nullptr); - + // - Destructure and restrucure with the unsized fields ::std::vector<::MIR::LValue> ents; TU_MATCHA( (str.m_data), (se), @@ -638,19 +638,19 @@ 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_lval = mutator.in_temporary( mv$(ty_d), mv$(new_rval) ); - + ents.push_back( mv$(new_lval) ); } else if( state.m_resolve.is_type_phantom_data( se[i].ent ) ) { auto ty_d = monomorphise_type_with(state.sp, se[i].ent, monomorph_cb_d, false); - + auto new_rval = ::MIR::RValue::make_Cast({ ::MIR::LValue::make_Field({ box$(value.clone()), i }), ty_d.clone() }); auto new_lval = mutator.in_temporary( mv$(ty_d), mv$(new_rval) ); - + ents.push_back( mv$(new_lval) ); } else @@ -667,20 +667,20 @@ 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_lval = mutator.new_temporary( mv$(ty_d) ); mutator.push_statement( ::MIR::Statement::make_Assign({ new_lval.clone(), mv$(new_rval) }) ); - + ents.push_back( mv$(new_lval) ); } else if( state.m_resolve.is_type_phantom_data( se[i].second.ent ) ) { auto ty_d = monomorphise_type_with(state.sp, se[i].second.ent, monomorph_cb_d, false); - + auto new_rval = ::MIR::RValue::make_Cast({ ::MIR::LValue::make_Field({ box$(value.clone()), i }), ty_d.clone() }); auto new_lval = mutator.in_temporary( mv$(ty_d), mv$(new_rval) ); - + ents.push_back( mv$(new_lval) ); } else @@ -692,22 +692,22 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator& ) return ::MIR::RValue::make_Struct({ dte.path.m_data.as_Generic().clone(), ~0u, mv$(ents) }); } - + if( dst_ty.m_data.is_Borrow() ) { MIR_ASSERT(state, src_ty.m_data.is_Borrow(), "CoerceUnsized to Borrow must have a Borrow source - " << src_ty << " to " << dst_ty); const auto& ste = src_ty.m_data.as_Borrow(); - + return MIR_Cleanup_Unsize(state, mutator, dst_ty, *ste.inner, mv$(value)); } - + // Pointer Coercion - Downcast and unsize if( dst_ty.m_data.is_Pointer() ) { MIR_ASSERT(state, src_ty.m_data.is_Pointer(), "CoerceUnsized to Pointer must have a Pointer source - " << src_ty << " to " << dst_ty); const auto& dte = dst_ty.m_data.as_Pointer(); const auto& ste = src_ty.m_data.as_Pointer(); - + if( dte.type == ste.type ) { // TODO: Use unsize code above @@ -717,11 +717,11 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator& { MIR_ASSERT(state, *dte.inner == *ste.inner, "TODO: Can pointer CoerceUnsized unsize? " << src_ty << " to " << dst_ty); MIR_ASSERT(state, dte.type < ste.type, "CoerceUnsize attempting to raise pointer type"); - + return ::MIR::RValue::make_Cast({ mv$(value), dst_ty.clone() }); } } - + MIR_BUG(state, "Unknown CoerceUnsized target " << dst_ty << " from " << src_ty); throw ""; } @@ -788,7 +788,7 @@ 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); } @@ -803,7 +803,7 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, Span sp; TRACE_FUNCTION_F(path); ::MIR::TypeResolve state { sp, resolve, FMT_CB(ss, ss << path;), ret_type, args, fcn }; - + MirMutator mutator { fcn, 0, 0 }; for(auto& block : fcn.blocks) { @@ -811,7 +811,7 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, { state.set_cur_stmt( mutator.cur_block, mutator.cur_stmt ); auto& stmt = *it; - + // 1. Visit all LValues for box deref hackery TU_MATCHA( (stmt), (se), (Drop, @@ -874,7 +874,7 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, if( stmt.is_Assign() ) { auto& se = stmt.as_Assign(); - + TU_IFLET( ::MIR::RValue, se.src, Constant, e, // TODO: Replace `Const` with actual values TU_IFLET( ::MIR::Constant, e, Const, ce, @@ -887,14 +887,14 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, } ) ) - + if( se.src.is_Borrow() && se.src.as_Borrow().val.is_Field() ) { auto& e = se.src.as_Borrow(); // TODO: If borrowing a !Sized value via a field access, create the DST ::HIR::TypeRef tmp; const auto& src_ty = state.get_lvalue_type(tmp, e.val); - + if( !resolve.type_is_sized(sp, src_ty) && !src_ty.m_data.is_Generic() ) { auto ty_unit_ptr = ::HIR::TypeRef::new_borrow( e.type, ::HIR::TypeRef::new_unit() ); @@ -909,24 +909,24 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, while( lv->is_Field() ) lv = &*lv->as_Field().val; MIR_ASSERT(state, lv->is_Deref(), "Access of !Sized field not via a deref"); - + const auto& dst_val_lval = *lv; - + auto meta_rval = ::MIR::RValue::make_DstMeta({ dst_val_lval.clone() }); // TODO: How can the thin pointer to the field be obtained without tripping this twice? auto ptr_rval = mv$( se.src ); - + // TODO: Get the metadata type. auto meta_ty = ::HIR::TypeRef( ::HIR::CoreType::Usize ); auto meta_lval = mutator.in_temporary( mv$(meta_ty), mv$(meta_rval) ); - + // HACK: Store the pointer as &() auto ptr_lval = mutator.in_temporary( mv$(ty_unit_ptr), mv$(ptr_rval) ); se.src = ::MIR::RValue::make_MakeDst({ mv$(ptr_lval), mv$(meta_lval) }); } } } - + if( se.src.is_Cast() ) { auto& e = se.src.as_Cast(); @@ -943,7 +943,7 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, // Casts to PhantomData are only valid from PhandomData, and are added by _CoerceUnsized else if( state.m_resolve.is_type_phantom_data(e.type) ) { - // Leave + // Leave MIR_ASSERT(state, state.m_resolve.is_type_phantom_data(src_ty) != nullptr, "PhandomData can only cast from PhantomData"); } // - CoerceUnsized should re-create the inner type if known. @@ -966,15 +966,15 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, } } } - + DEBUG(it - block.statements.begin()); it = mutator.flush(); DEBUG(it - block.statements.begin()); mutator.cur_stmt += 1; } - + state.set_cur_stmt_term( mutator.cur_block ); - + TU_MATCHA( (block.terminator), (e), (Incomplete, ), @@ -1001,9 +1001,9 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, MIR_Cleanup_LValue(state, mutator, lv); ) ) - + TU_IFLET( ::MIR::Terminator, block.terminator, Call, e, - + TU_IFLET( ::MIR::CallTarget, e.fcn, Path, path, // Detect calling `<Trait as Trait>::method()` and replace with vtable call if( path.m_data.is_UfcsKnown() && path.m_data.as_UfcsKnown().type->m_data.is_TraitObject() ) @@ -1024,7 +1024,7 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, e.fcn = mv$(tgt_lvalue); } } - + if( path.m_data.is_UfcsKnown() && path.m_data.as_UfcsKnown().type->m_data.is_Function() ) { const auto& pe = path.m_data.as_UfcsKnown(); @@ -1034,9 +1034,9 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, MIR_ASSERT(state, e.args.size() == 2, "Fn* call requires two arguments"); auto fcn_lvalue = mv$(e.args[0]); auto args_lvalue = mv$(e.args[1]); - + DEBUG("Convert function pointer call"); - + e.args.clear(); e.args.reserve( fcn_ty.m_arg_types.size() ); for(unsigned int i = 0; i < fcn_ty.m_arg_types.size(); i ++) @@ -1048,7 +1048,7 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, } ) ) - + mutator.flush(); mutator.cur_block += 1; mutator.cur_stmt = 0; diff --git a/src/mir/dump.cpp b/src/mir/dump.cpp index d1fdc503..555093f2 100644 --- a/src/mir/dump.cpp +++ b/src/mir/dump.cpp @@ -10,14 +10,14 @@ #include "mir.hpp" namespace { - + class TreeVisitor: public ::HIR::Visitor { ::std::ostream& m_os; unsigned int m_indent_level; bool m_short_item_name = false; - + public: TreeVisitor(::std::ostream& os): m_os(os), @@ -28,7 +28,7 @@ namespace { void visit_type_impl(::HIR::TypeImpl& impl) override { m_short_item_name = true; - + m_os << indent() << "impl" << impl.m_params.fmt_args() << " " << impl.m_type << "\n"; if( ! impl.m_params.m_bounds.empty() ) { @@ -39,13 +39,13 @@ namespace { ::HIR::Visitor::visit_type_impl(impl); dec_indent(); m_os << indent() << "}\n"; - + m_short_item_name = false; } virtual void visit_trait_impl(const ::HIR::SimplePath& trait_path, ::HIR::TraitImpl& impl) override { m_short_item_name = true; - + m_os << indent() << "impl" << impl.m_params.fmt_args() << " " << trait_path << impl.m_trait_args << " for " << impl.m_type << "\n"; if( ! impl.m_params.m_bounds.empty() ) { @@ -56,28 +56,28 @@ namespace { ::HIR::Visitor::visit_trait_impl(trait_path, impl); dec_indent(); m_os << indent() << "}\n"; - + m_short_item_name = false; } void visit_marker_impl(const ::HIR::SimplePath& trait_path, ::HIR::MarkerImpl& impl) override { m_short_item_name = true; - + m_os << indent() << "impl" << impl.m_params.fmt_args() << " " << (impl.is_positive ? "" : "!") << trait_path << impl.m_trait_args << " for " << impl.m_type << "\n"; if( ! impl.m_params.m_bounds.empty() ) { m_os << indent() << " " << impl.m_params.fmt_bounds() << "\n"; } m_os << indent() << "{ }\n"; - + m_short_item_name = false; } - + // - Type Items void visit_trait(::HIR::ItemPath p, ::HIR::Trait& item) override { m_short_item_name = true; - + m_os << indent() << "trait " << p << item.m_params.fmt_args() << "\n"; if( ! item.m_params.m_bounds.empty() ) { @@ -88,7 +88,7 @@ namespace { ::HIR::Visitor::visit_trait(p, item); dec_indent(); m_os << indent() << "}\n"; - + m_short_item_name = false; } @@ -119,7 +119,7 @@ namespace { { m_os << indent() << " " << item.m_params.fmt_bounds() << "\n"; } - + if( item.m_code ) { m_os << indent() << "{\n"; @@ -133,8 +133,8 @@ namespace { m_os << indent() << " ;\n"; } } - - + + void dump_mir(const ::MIR::Function& fcn) { for(unsigned int i = 0; i < fcn.named_variables.size(); i ++) @@ -145,19 +145,19 @@ namespace { { m_os << indent() << "let tmp$" << i << ": " << fcn.temporaries[i] << ";\n"; } - + #define FMT_M(x) FMT_CB(os, this->fmt_val(os,x);) for(unsigned int i = 0; i < fcn.blocks.size(); i ++) { const auto& block = fcn.blocks[i]; DEBUG("BB" << i); - + m_os << indent() << "bb" << i << ": {\n"; inc_indent(); for(const auto& stmt : block.statements) { m_os << indent(); - + TU_MATCHA( (stmt), (e), (Assign, DEBUG("- Assign " << e.dst << " = " << e.src); @@ -169,7 +169,7 @@ namespace { ) ) } - + m_os << indent(); TU_MATCHA( (block.terminator), (e), (Incomplete, @@ -217,7 +217,7 @@ namespace { ) dec_indent(); m_os << indent() << "}\n"; - + m_os.flush(); } #undef FMT @@ -329,14 +329,14 @@ namespace { case ::MIR::eBinOp::MUL_OV: os << "MUL_OV"; break; case ::MIR::eBinOp::DIV_OV: os << "DIV_OV"; break; //case ::MIR::eBinOp::MOD_OV: os << "MOD_OV"; break; - + case ::MIR::eBinOp::BIT_OR : os << "BIT_OR"; break; case ::MIR::eBinOp::BIT_AND: os << "BIT_AND"; break; case ::MIR::eBinOp::BIT_XOR: os << "BIT_XOR"; break; - + case ::MIR::eBinOp::BIT_SHR: os << "BIT_SHR"; break; case ::MIR::eBinOp::BIT_SHL: os << "BIT_SHL"; break; - + case ::MIR::eBinOp::EQ: os << "EQ"; break; case ::MIR::eBinOp::NE: os << "NE"; break; case ::MIR::eBinOp::GT: os << "GT"; break; @@ -424,7 +424,7 @@ namespace { void MIR_Dump(::std::ostream& sink, const ::HIR::Crate& crate) { TreeVisitor tv { sink }; - + tv.visit_crate( const_cast< ::HIR::Crate&>(crate) ); } diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index 7218563b..e21ca993 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -20,14 +20,14 @@ namespace { - + class ExprVisitor_Conv: public MirConverter { MirBuilder& m_builder; - + const ::std::vector< ::HIR::TypeRef>& m_variable_types; - + struct LoopDesc { ScopeHandle scope; ::std::string label; @@ -35,26 +35,26 @@ namespace { unsigned int next; }; ::std::vector<LoopDesc> m_loop_stack; - + public: ExprVisitor_Conv(MirBuilder& builder, const ::std::vector< ::HIR::TypeRef>& var_types): m_builder(builder), m_variable_types(var_types) { } - + void destructure_from(const Span& sp, const ::HIR::Pattern& pat, ::MIR::LValue lval, bool allow_refutable=false) override { destructure_from_ex(sp, pat, mv$(lval), (allow_refutable ? 1 : 0)); } - + // Brings variables defined in `pat` into scope void define_vars_from(const Span& sp, const ::HIR::Pattern& pat) override { if( pat.m_binding.is_valid() ) { m_builder.define_variable( pat.m_binding.m_slot ); } - + TU_MATCHA( (pat.m_data), (e), (Any, ), @@ -98,7 +98,7 @@ namespace { ), (EnumValue, ), - + (EnumTuple, for(unsigned int i = 0; i < e.sub_patterns.size(); i ++ ) { @@ -132,7 +132,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 { if( allow_refutable != 3 && pat.m_binding.is_valid() ) { @@ -146,7 +146,7 @@ namespace { // Refutable and binding allowed destructure_from_ex(sp, pat, lval.clone(), 3); } - + switch( pat.m_binding.m_type ) { case ::HIR::PatternBinding::Type::Move: @@ -168,7 +168,7 @@ namespace { if( allow_refutable == 3 ) { allow_refutable = 2; } - + TU_MATCHA( (pat.m_data), (e), (Any, ), @@ -267,7 +267,7 @@ namespace { else { ASSERT_BUG(sp, allow_refutable, "Refutable pattern not expected - " << pat); - + // TODO: Emit code to triple-check the size? Or just assume that match did that correctly. for(unsigned int i = 0; i < e.sub_patterns.size(); i ++) { @@ -320,7 +320,7 @@ namespace { ) ) } - + // -- ExprVisitor void visit(::HIR::ExprNode_Block& node) override { @@ -329,38 +329,38 @@ namespace { if( node.m_nodes.size() > 0 ) { bool diverged = false; - + auto scope = m_builder.new_scope_var(node.span()); - + for(unsigned int i = 0; i < node.m_nodes.size() - (node.m_yields_final ? 1 : 0); i ++) { auto& subnode = node.m_nodes[i]; const Span& sp = subnode->span(); - + auto stmt_scope = m_builder.new_scope_temp(sp); this->visit_node_ptr(subnode); if( m_builder.has_result() ) { // TODO: Drop. m_builder.get_result(sp); } - + if( m_builder.block_active() ) { m_builder.terminate_scope(sp, mv$(stmt_scope)); } else { auto _ = mv$(stmt_scope); - + m_builder.set_cur_block( m_builder.new_bb_unlinked() ); diverged = true; } } - + // - For the last node, don't bother with a statement scope if( node.m_yields_final ) { auto& subnode = node.m_nodes.back(); const Span& sp = subnode->span(); - + auto stmt_scope = m_builder.new_scope_temp(sp); this->visit_node_ptr(subnode); if( m_builder.has_result() || m_builder.block_active() ) @@ -368,10 +368,10 @@ namespace { ASSERT_BUG(sp, m_builder.block_active(), "Result yielded, but no active block"); ASSERT_BUG(sp, m_builder.has_result(), "Active block but no result yeilded"); // PROBLEM: This can drop the result before we want to use it. - + auto res = m_builder.get_result(sp); m_builder.raise_variables(sp, res); - + m_builder.terminate_scope(sp, mv$(stmt_scope)); m_builder.terminate_scope( node.span(), mv$(scope) ); m_builder.set_result( node.span(), mv$(res) ); @@ -407,7 +407,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.terminate_scope_early( node.span(), m_builder.fcn_scope() ); m_builder.end_block( ::MIR::Terminator::make_Return({}) ); @@ -419,11 +419,11 @@ namespace { if( node.m_value ) { this->visit_node_ptr(node.m_value); - + if( ! m_builder.block_active() ) { return ; } - + if( node.m_pattern.m_binding.is_valid() && node.m_pattern.m_data.is_Any() && node.m_pattern.m_binding.m_type == ::HIR::PatternBinding::Type::Move ) { m_builder.push_stmt_assign( node.span(), ::MIR::LValue::make_Variable(node.m_pattern.m_binding.m_slot), m_builder.get_result(node.span()) ); @@ -441,12 +441,12 @@ namespace { auto loop_body_scope = m_builder.new_scope_loop(node.span()); auto loop_block = m_builder.new_bb_linked(); auto loop_next = m_builder.new_bb_unlinked(); - + m_loop_stack.push_back( LoopDesc { mv$(loop_body_scope), node.m_label, loop_block, loop_next } ); this->visit_node_ptr(node.m_code); auto loop_scope = mv$(m_loop_stack.back().scope); m_loop_stack.pop_back(); - + // If there's a stray result, drop it if( m_builder.has_result() ) { assert( m_builder.block_active() ); @@ -467,7 +467,7 @@ namespace { // Terminate scope without emitting cleanup (cleanup was handled by `break`) m_builder.terminate_scope( node.span(), mv$(loop_scope), false ); } - + if( ! node.m_diverges ) { DEBUG("- Doesn't diverge"); @@ -478,7 +478,7 @@ namespace { { DEBUG("- Diverges"); assert( !m_builder.has_result() ); - + m_builder.set_cur_block(loop_next); m_builder.end_split_arm_early(node.span()); assert( !m_builder.has_result() ); @@ -491,7 +491,7 @@ namespace { if( m_loop_stack.size() == 0 ) { BUG(node.span(), "Loop control outside of a loop"); } - + const auto* target_block = &m_loop_stack.back(); if( node.m_label != "" ) { auto it = ::std::find_if(m_loop_stack.rbegin(), m_loop_stack.rend(), [&](const auto& x){ return x.label == node.m_label; }); @@ -500,7 +500,7 @@ namespace { } target_block = &*it; } - + // TODO: Insert drop of all active scopes within the loop m_builder.terminate_scope_early( node.span(), target_block->scope ); if( node.m_continue ) { @@ -510,13 +510,13 @@ namespace { m_builder.end_block( ::MIR::Terminator::make_Goto(target_block->next) ); } } - + void visit(::HIR::ExprNode_Match& node) override { TRACE_FUNCTION_FR("_Match", "_Match"); this->visit_node_ptr(node.m_value); auto match_val = m_builder.get_result_in_lvalue(node.m_value->span(), node.m_value->m_res_type); - + if( node.m_arms.size() == 0 ) { // Nothing //const auto& ty = node.m_value->m_res_type; @@ -531,21 +531,21 @@ namespace { // - Shortcut: Single-arm match auto& arm = node.m_arms[0]; const auto& pat = arm.m_patterns[0]; - + auto scope = m_builder.new_scope_var(arm.m_code->span()); auto tmp_scope = m_builder.new_scope_temp(arm.m_code->span()); this->define_vars_from(node.span(), pat); // TODO: Do the same shortcut as _Let? this->destructure_from(node.span(), pat, mv$(match_val)); - + // Temp scope. this->visit_node_ptr(arm.m_code); - + if( m_builder.block_active() ) { auto res = m_builder.get_result(arm.m_code->span()); m_builder.raise_variables( arm.m_code->span(), res ); m_builder.set_result(arm.m_code->span(), mv$(res)); - + m_builder.terminate_scope( node.span(), mv$(tmp_scope) ); m_builder.terminate_scope( node.span(), mv$(scope) ); } @@ -558,11 +558,11 @@ namespace { MIR_LowerHIR_Match(m_builder, *this, node, mv$(match_val)); } } // ExprNode_Match - + void visit(::HIR::ExprNode_If& node) override { TRACE_FUNCTION_FR("_If", "_If"); - + bool reverse = false; { auto* cond_p = &node.m_cond; @@ -572,11 +572,11 @@ namespace { cond_p = &cond_uni->m_value; reverse = !reverse; } - + this->visit_node_ptr(*cond_p); } auto decision_val = m_builder.get_result_in_lvalue(node.m_cond->span(), node.m_cond->m_res_type); - + auto true_branch = m_builder.new_bb_unlinked(); auto false_branch = m_builder.new_bb_unlinked(); auto next_block = m_builder.new_bb_unlinked(); @@ -586,12 +586,12 @@ namespace { else { m_builder.end_block( ::MIR::Terminator::make_If({ mv$(decision_val), true_branch, false_branch }) ); } - + auto result_val = m_builder.new_temporary(node.m_res_type); - + // Scope handles cases where one arm moves a value but the other doesn't auto scope = m_builder.new_scope_split( node.m_true->span() ); - + // 'true' branch { m_builder.set_cur_block(true_branch); @@ -605,7 +605,7 @@ namespace { m_builder.end_split_arm(node.span(), scope, false); } } - + // 'false' branch m_builder.set_cur_block(false_branch); if( node.m_false ) @@ -630,10 +630,10 @@ namespace { } m_builder.set_cur_block(next_block); m_builder.terminate_scope( node.span(), mv$(scope) ); - + m_builder.set_result( node.span(), mv$(result_val) ); } - + void generate_checked_binop(const Span& sp, ::MIR::LValue res_slot, ::MIR::eBinOp op, ::MIR::LValue val_l, const ::HIR::TypeRef& ty_l, ::MIR::LValue val_r, const ::HIR::TypeRef& ty_r) { switch(op) @@ -726,29 +726,29 @@ namespace { break; } } - + void visit(::HIR::ExprNode_Assign& node) override { TRACE_FUNCTION_F("_Assign"); const auto& sp = node.span(); - + this->visit_node_ptr(node.m_value); ::MIR::RValue val = m_builder.get_result(sp); - + this->visit_node_ptr(node.m_slot); auto dst = m_builder.get_result_unwrap_lvalue(sp); - + const auto& ty_slot = node.m_slot->m_res_type; const auto& ty_val = node.m_value->m_res_type; - + if( node.m_op != ::HIR::ExprNode_Assign::Op::None ) { auto dst_clone = dst.clone(); auto val_lv = m_builder.lvalue_or_temp( node.span(), ty_val, mv$(val) ); - + ASSERT_BUG(sp, ty_slot.m_data.is_Primitive(), "Assignment operator overloads are only valid on primitives - ty_slot="<<ty_slot); ASSERT_BUG(sp, ty_val.m_data.is_Primitive(), "Assignment operator overloads are only valid on primitives - ty_val="<<ty_val); - + #define _(v) ::HIR::ExprNode_Assign::Op::v ::MIR::eBinOp op; switch(node.m_op) @@ -783,20 +783,20 @@ namespace { } m_builder.set_result(node.span(), ::MIR::RValue::make_Tuple({})); } - + void visit(::HIR::ExprNode_BinOp& node) override { const auto& sp = node.span(); TRACE_FUNCTION_F("_BinOp"); - + const auto& ty_l = node.m_left->m_res_type; this->visit_node_ptr(node.m_left); auto left = m_builder.get_result_in_lvalue(node.m_left->span(), ty_l); - + const auto& ty_r = node.m_right->m_res_type; this->visit_node_ptr(node.m_right); auto right = m_builder.get_result_in_lvalue(node.m_right->span(), ty_r); - + auto res = m_builder.new_temporary(node.m_res_type); ::MIR::eBinOp op; switch(node.m_op) @@ -809,18 +809,18 @@ namespace { case ::HIR::ExprNode_BinOp::Op::CmpGtE: op = ::MIR::eBinOp::GE; this->generate_checked_binop(sp, res.clone(), op, mv$(left), ty_l, mv$(right), ty_r); break; - + case ::HIR::ExprNode_BinOp::Op::Xor: op = ::MIR::eBinOp::BIT_XOR; if(0) case ::HIR::ExprNode_BinOp::Op::Or : op = ::MIR::eBinOp::BIT_OR ; if(0) case ::HIR::ExprNode_BinOp::Op::And: op = ::MIR::eBinOp::BIT_AND; this->generate_checked_binop(sp, res.clone(), op, mv$(left), ty_l, mv$(right), ty_r); break; - + case ::HIR::ExprNode_BinOp::Op::Shr: op = ::MIR::eBinOp::BIT_SHR; if(0) case ::HIR::ExprNode_BinOp::Op::Shl: op = ::MIR::eBinOp::BIT_SHL; this->generate_checked_binop(sp, res.clone(), op, mv$(left), ty_l, mv$(right), ty_r); break; - + case ::HIR::ExprNode_BinOp::Op::Add: op = ::MIR::eBinOp::ADD; if(0) case ::HIR::ExprNode_BinOp::Op::Sub: op = ::MIR::eBinOp::SUB; if(0) case ::HIR::ExprNode_BinOp::Op::Mul: op = ::MIR::eBinOp::MUL; if(0) @@ -828,7 +828,7 @@ namespace { case ::HIR::ExprNode_BinOp::Op::Mod: op = ::MIR::eBinOp::MOD; this->generate_checked_binop(sp, res.clone(), op, mv$(left), ty_l, mv$(right), ty_r); break; - + case ::HIR::ExprNode_BinOp::Op::BoolAnd: { auto bb_next = m_builder.new_bb_unlinked(); auto bb_true = m_builder.new_bb_unlinked(); @@ -838,12 +838,12 @@ namespace { m_builder.set_cur_block( bb_false ); m_builder.push_stmt_assign(node.span(), res.clone(), ::MIR::RValue( ::MIR::Constant::make_Bool(false) )); m_builder.end_block( ::MIR::Terminator::make_Goto(bb_next) ); - + // If left is true, assign result to right m_builder.set_cur_block( bb_true ); m_builder.push_stmt_assign(node.span(), res.clone(), mv$(right)); // TODO: Right doens't need to be an LValue here. m_builder.end_block( ::MIR::Terminator::make_Goto(bb_next) ); - + m_builder.set_cur_block( bb_next ); } break; case ::HIR::ExprNode_BinOp::Op::BoolOr: { @@ -855,26 +855,26 @@ namespace { m_builder.set_cur_block( bb_true ); m_builder.push_stmt_assign(node.span(), res.clone(), ::MIR::RValue( ::MIR::Constant::make_Bool(true) )); m_builder.end_block( ::MIR::Terminator::make_Goto(bb_next) ); - + // If left is false, assign result to right m_builder.set_cur_block( bb_false ); m_builder.push_stmt_assign(node.span(), res.clone(), mv$(right)); // TODO: Right doens't need to be an LValue here. m_builder.end_block( ::MIR::Terminator::make_Goto(bb_next) ); - + m_builder.set_cur_block( bb_next ); } break; } m_builder.set_result( node.span(), mv$(res) ); } - + void visit(::HIR::ExprNode_UniOp& node) override { TRACE_FUNCTION_F("_UniOp"); - + const auto& ty_val = node.m_value->m_res_type; this->visit_node_ptr(node.m_value); auto val = m_builder.get_result_in_lvalue(node.m_value->span(), ty_val); - + ::MIR::RValue res; switch(node.m_op) { @@ -928,11 +928,11 @@ namespace { void visit(::HIR::ExprNode_Borrow& node) override { TRACE_FUNCTION_F("_Borrow"); - + const auto& ty_val = node.m_value->m_res_type; this->visit_node_ptr(node.m_value); auto val = m_builder.get_result_in_lvalue(node.m_value->span(), ty_val); - + auto res = m_builder.new_temporary(node.m_res_type); m_builder.push_stmt_assign( node.span(), res.as_Temporary(), ::MIR::RValue::make_Borrow({ 0, node.m_type, mv$(val) })); m_builder.set_result( node.span(), mv$(res) ); @@ -941,16 +941,16 @@ namespace { { TRACE_FUNCTION_F("_Cast"); this->visit_node_ptr(node.m_value); - + const auto& ty_out = node.m_res_type; const auto& ty_in = node.m_value->m_res_type; - + if( ty_out == ty_in ) { return ; } - + 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), ( BUG(node.span(), "Invalid cast to " << ty_out << " from " << ty_in); @@ -1067,16 +1067,16 @@ namespace { { TRACE_FUNCTION_F("_Unsize"); this->visit_node_ptr(node.m_value); - + const auto& ty_out = node.m_res_type; const auto& ty_in = node.m_value->m_res_type; - + if( ty_out == ty_in ) { return ; } - + auto ptr_lval = m_builder.get_result_in_lvalue(node.m_value->span(), node.m_value->m_res_type); - + if( ty_out.m_data.is_Borrow() && ty_in.m_data.is_Borrow() ) { const auto& oe = ty_out.m_data.as_Borrow(); @@ -1135,14 +1135,14 @@ namespace { vtable_params.m_types[idx] = ty_b.second.clone(); } auto vtable_type = ::HIR::TypeRef( ::HIR::GenericPath(vtable_ty_spath, mv$(vtable_params)), &vtable_ref ); - + ::HIR::Path vtable { ty_in.clone(), e.m_trait.m_path.clone(), "#vtable" }; auto vtable_lval = m_builder.lvalue_or_temp( node.span(), ::HIR::TypeRef::new_pointer(::HIR::BorrowType::Shared, mv$(vtable_type)), ::MIR::RValue( ::MIR::Constant::make_ItemAddr(mv$(vtable)) ) ); - + m_builder.set_result( node.span(), ::MIR::RValue::make_MakeDst({ mv$(ptr_lval), mv$(vtable_lval) }) ); #else m_builder.set_result( node.span(), ::MIR::RValue::make_Cast({ mv$(ptr_lval), node.m_res_type.clone() }) ); @@ -1164,16 +1164,16 @@ namespace { void visit(::HIR::ExprNode_Index& node) override { TRACE_FUNCTION_F("_Index"); - + // NOTE: Calculate the index first (so if it borrows from the source, it's over by the time that's needed) const auto& ty_idx = node.m_index->m_res_type; this->visit_node_ptr(node.m_index); auto index = m_builder.get_result_in_lvalue(node.m_index->span(), ty_idx); - + const auto& ty_val = node.m_value->m_res_type; this->visit_node_ptr(node.m_value); auto value = m_builder.get_result_in_lvalue(node.m_value->span(), ty_val); - + ::MIR::RValue limit_val; TU_MATCH_DEF(::HIR::TypeRef::Data, (ty_val.m_data), (e), ( @@ -1186,7 +1186,7 @@ namespace { limit_val = ::MIR::RValue::make_DstMeta({ value.clone() }); ) ) - + TU_MATCH_DEF(::HIR::TypeRef::Data, (ty_idx.m_data), (e), ( BUG(node.span(), "Indexing using unsupported index type " << ty_idx); @@ -1197,38 +1197,38 @@ namespace { } ) ) - + // Range checking (DISABLED) if( false ) { auto limit_lval = m_builder.lvalue_or_temp( node.span(), ty_idx, mv$(limit_val) ); - + auto cmp_res = m_builder.new_temporary( ::HIR::CoreType::Bool ); m_builder.push_stmt_assign(node.span(), cmp_res.clone(), ::MIR::RValue::make_BinOp({ index.clone(), ::MIR::eBinOp::GE, mv$(limit_lval) })); auto arm_panic = m_builder.new_bb_unlinked(); auto arm_continue = m_builder.new_bb_unlinked(); m_builder.end_block( ::MIR::Terminator::make_If({ mv$(cmp_res), arm_panic, arm_continue }) ); - + m_builder.set_cur_block( arm_panic ); // TODO: Call an "index fail" method which always panics. //m_builder.end_block( ::MIR::Terminator::make_Panic({}) ); m_builder.end_block( ::MIR::Terminator::make_Diverge({}) ); - + m_builder.set_cur_block( arm_continue ); } - + m_builder.set_result( node.span(), ::MIR::LValue::make_Index({ box$(value), box$(index) }) ); } - + void visit(::HIR::ExprNode_Deref& node) override { const Span& sp = node.span(); TRACE_FUNCTION_F("_Deref"); - + const auto& ty_val = node.m_value->m_res_type; 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), ( if( m_builder.is_type_owned_box( ty_val ) ) @@ -1246,10 +1246,10 @@ namespace { // Deref on a borrow - Always valid... assuming borrowck is there :) ) ) - + m_builder.set_result( node.span(), ::MIR::LValue::make_Deref({ box$(val) }) ); } - + void visit(::HIR::ExprNode_Emplace& node) override { if( node.m_type == ::HIR::ExprNode_Emplace::Type::Noop ) { @@ -1260,9 +1260,9 @@ namespace { auto path_Place = ::HIR::SimplePath("core", {"ops", "Place"}); auto path_Boxed = ::HIR::SimplePath("core", {"ops", "Boxed"}); //auto path_InPlace = ::HIR::SimplePath("core", {"ops", "InPlace"}); - + const auto& data_ty = node.m_value->m_res_type; - + // 1. Obtain the type of the `place` variable ::HIR::TypeRef place_type; switch( node.m_type ) @@ -1277,7 +1277,7 @@ namespace { TODO(node.span(), "_Emplace - Placer"); break; } - + // 2. Initialise the place auto place = m_builder.new_temporary( place_type ); auto place__panic = m_builder.new_bb_unlinked(); @@ -1299,13 +1299,13 @@ namespace { TODO(node.span(), "_Emplace - Placer"); break; } - + // TODO: Proper panic handling, including scope destruction m_builder.set_cur_block(place__panic); // TODO: Drop `place` m_builder.end_block( ::MIR::Terminator::make_Diverge({}) ); m_builder.set_cur_block(place__ok); - + // 2. Get `place_raw` auto place_raw__type = ::HIR::TypeRef::new_pointer(::HIR::BorrowType::Unique, node.m_value->m_res_type.clone()); auto place_raw = m_builder.new_temporary( place_raw__type ); @@ -1322,19 +1322,19 @@ namespace { ::make_vec1( mv$(place_refmut) ) })); } - + // TODO: Proper panic handling, including scope destruction m_builder.set_cur_block(place_raw__panic); // TODO: Drop `place` m_builder.end_block( ::MIR::Terminator::make_Diverge({}) ); m_builder.set_cur_block(place_raw__ok); - - + + // 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) ); - + // 3. Return a call to `finalize` ::HIR::Path finalize_path(::HIR::GenericPath {}); switch( node.m_type ) @@ -1348,7 +1348,7 @@ namespace { TODO(node.span(), "_Emplace - Placer"); break; } - + auto res = m_builder.new_temporary( node.m_res_type ); auto res__panic = m_builder.new_bb_unlinked(); auto res__ok = m_builder.new_bb_unlinked(); @@ -1357,17 +1357,17 @@ namespace { res.clone(), mv$(finalize_path), ::make_vec1( mv$(place) ) })); - + // TODO: Proper panic handling, including scope destruction m_builder.set_cur_block(res__panic); // TODO: Should this drop the value written to the rawptr? // - No, becuase it's likely invalid now. Goodbye! m_builder.end_block( ::MIR::Terminator::make_Diverge({}) ); m_builder.set_cur_block(res__ok); - + m_builder.set_result( node.span(), mv$(res) ); } - + void visit(::HIR::ExprNode_TupleVariant& node) override { const Span& sp = node.span(); @@ -1379,7 +1379,7 @@ namespace { this->visit_node_ptr(arg); values.push_back( m_builder.get_result_in_lvalue(arg->span(), arg->m_res_type) ); } - + unsigned int variant_index = ~0u; if( !node.m_is_struct ) { @@ -1390,17 +1390,17 @@ namespace { const auto& enm = m_builder.crate().get_enum_by_path(sp, enum_path); auto var_it = ::std::find_if(enm.m_variants.begin(), enm.m_variants.end(), [&](const auto& x){ return x.first == var_name; }); ASSERT_BUG(sp, var_it != enm.m_variants.end(), "Variant " << node.m_path.m_path << " isn't present"); - + variant_index = var_it - enm.m_variants.begin(); } - + m_builder.set_result( node.span(), ::MIR::RValue::make_Struct({ node.m_path.clone(), variant_index, mv$(values) }) ); } - + void visit(::HIR::ExprNode_CallPath& node) override { TRACE_FUNCTION_F("_CallPath " << node.m_path); @@ -1412,14 +1412,14 @@ namespace { values.push_back( m_builder.get_result_in_lvalue(arg->span(), arg->m_res_type) ); m_builder.moved_lvalue( arg->span(), values.back() ); } - - + + auto panic_block = m_builder.new_bb_unlinked(); auto next_block = m_builder.new_bb_unlinked(); auto res = m_builder.new_temporary( node.m_res_type ); - + bool unconditional_diverge = false; - + // Emit intrinsics as a special call type if( node.m_path.m_data.is_Generic() ) { @@ -1433,13 +1433,13 @@ namespace { mv$(values) })); } - + if( fcn.m_return.m_data.is_Diverge() ) { unconditional_diverge = true; } } - + // If the call wasn't to an intrinsic, emit it as a path if( m_builder.block_active() ) { @@ -1449,11 +1449,11 @@ namespace { mv$(values) })); } - + m_builder.set_cur_block(panic_block); // TODO: Proper panic handling, including scope destruction m_builder.end_block( ::MIR::Terminator::make_Diverge({}) ); - + m_builder.set_cur_block( next_block ); // If the function doesn't return, early-terminate the return block. @@ -1469,16 +1469,16 @@ namespace { } m_builder.set_result( node.span(), mv$(res) ); } - + void visit(::HIR::ExprNode_CallValue& node) override { TRACE_FUNCTION_F("_CallValue " << node.m_value->m_res_type); - + // _CallValue is ONLY valid on function pointers (all others must be desugared) ASSERT_BUG(node.span(), node.m_value->m_res_type.m_data.is_Function(), "Leftover _CallValue on a non-fn()"); this->visit_node_ptr(node.m_value); auto fcn_val = m_builder.get_result_in_lvalue( node.m_value->span(), node.m_value->m_res_type ); - + ::std::vector< ::MIR::LValue> values; values.reserve( node.m_args.size() ); for(auto& arg : node.m_args) @@ -1487,8 +1487,8 @@ namespace { values.push_back( m_builder.get_result_in_lvalue(arg->span(), arg->m_res_type) ); m_builder.moved_lvalue( arg->span(), values.back() ); } - - + + auto panic_block = m_builder.new_bb_unlinked(); auto next_block = m_builder.new_bb_unlinked(); auto res = m_builder.new_temporary( node.m_res_type ); @@ -1497,11 +1497,11 @@ namespace { res.clone(), mv$(fcn_val), mv$(values) })); - + m_builder.set_cur_block(panic_block); // TODO: Proper panic handling m_builder.end_block( ::MIR::Terminator::make_Diverge({}) ); - + m_builder.set_cur_block( next_block ); m_builder.set_result( node.span(), mv$(res) ); } @@ -1515,9 +1515,9 @@ namespace { TRACE_FUNCTION_F("_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); - + 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; @@ -1533,7 +1533,7 @@ namespace { const auto& unm = *node.m_value->m_res_type.m_data.as_Path().binding.as_Union(); 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 }) ); } } @@ -1595,7 +1595,7 @@ namespace { const auto& enm = m_builder.crate().get_enum_by_path(sp, enum_path); auto var_it = ::std::find_if(enm.m_variants.begin(), enm.m_variants.end(), [&](const auto& x){ return x.first == var_name; }); ASSERT_BUG(sp, var_it != enm.m_variants.end(), "Variant " << node.m_path.m_path << " isn't present"); - + variant_index = var_it - enm.m_variants.begin(); } m_builder.set_result( node.span(), ::MIR::RValue::make_Struct({ @@ -1614,13 +1614,13 @@ namespace { auto enum_path = pe.m_path; enum_path.m_components.pop_back(); const auto& var_name = pe.m_path.m_components.back(); - + const auto& enm = m_builder.crate().get_enum_by_path(sp, enum_path); auto var_it = ::std::find_if(enm.m_variants.begin(), enm.m_variants.end(), [&](const auto& x){ return x.first == var_name; }); ASSERT_BUG(sp, var_it != enm.m_variants.end(), "Variant " << pe.m_path << " isn't present"); const auto& var = var_it->second; ASSERT_BUG(sp, var.is_Tuple(), "Variant " << pe.m_path << " isn't a tuple variant"); - + // 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()) ); @@ -1670,7 +1670,7 @@ namespace { BUG(sp, "Unknown param in free function - " << gt); } }; - + // TODO: Obtain function type for this function (i.e. a type that is specifically for this function) auto fcn_ty_data = ::HIR::FunctionType { e.m_unsafe, @@ -1752,7 +1752,7 @@ namespace { TRACE_FUNCTION_F("_Variable - " << node.m_name << " #" << node.m_slot); m_builder.set_result( node.span(), ::MIR::LValue::make_Variable(node.m_slot) ); } - + void visit(::HIR::ExprNode_StructLiteral& node) override { TRACE_FUNCTION_F("_StructLiteral"); @@ -1762,7 +1762,7 @@ namespace { this->visit_node_ptr(node.m_base_value); base_val = m_builder.get_result_in_lvalue(node.m_base_value->span(), node.m_base_value->m_res_type); } - + unsigned int variant_index = ~0u; const ::HIR::t_struct_fields* fields_ptr = nullptr; TU_MATCH(::HIR::TypeRef::TypePathBinding, (node.m_res_type.m_data.as_Path().binding), (e), @@ -1785,12 +1785,12 @@ namespace { ) assert(fields_ptr); const ::HIR::t_struct_fields& fields = *fields_ptr; - + ::std::vector<bool> values_set; ::std::vector< ::MIR::LValue> values; values.resize( fields.size() ); values_set.resize( fields.size() ); - + for(auto& ent : node.m_values) { auto& valnode = ent.second; @@ -1812,7 +1812,7 @@ namespace { // Partial move support will handle dropping the rest? } } - + m_builder.set_result( node.span(), ::MIR::RValue::make_Struct({ node.m_path.clone(), variant_index, @@ -1822,10 +1822,10 @@ namespace { void visit(::HIR::ExprNode_UnionLiteral& node) override { TRACE_FUNCTION_F("_UnionLiteral " << node.m_path); - + 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); - + const auto& unm = *node.m_res_type.m_data.as_Path().binding.as_Union(); auto it = ::std::find_if(unm.m_variants.begin(), unm.m_variants.end(), [&](const auto&v)->auto{ return v.first == node.m_variant_name; }); assert(it != unm.m_variants.end()); @@ -1837,7 +1837,7 @@ namespace { mv$(val) }) ); } - + void visit(::HIR::ExprNode_Tuple& node) override { TRACE_FUNCTION_F("_Tuple"); @@ -1848,12 +1848,12 @@ namespace { this->visit_node_ptr(arg); values.push_back( m_builder.lvalue_or_temp( arg->span(), arg->m_res_type, m_builder.get_result(arg->span()) ) ); } - + m_builder.set_result( node.span(), ::MIR::RValue::make_Tuple({ mv$(values) }) ); } - + void visit(::HIR::ExprNode_ArrayList& node) override { TRACE_FUNCTION_F("_ArrayList"); @@ -1864,28 +1864,28 @@ namespace { this->visit_node_ptr(arg); values.push_back( m_builder.lvalue_or_temp( arg->span(), arg->m_res_type, m_builder.get_result(arg->span()) ) ); } - + m_builder.set_result( node.span(), ::MIR::RValue::make_Array({ mv$(values) }) ); } - + void visit(::HIR::ExprNode_ArraySized& node) override { TRACE_FUNCTION_F("_ArraySized"); this->visit_node_ptr( node.m_val ); auto value = m_builder.lvalue_or_temp( node.span(), node.m_val->m_res_type, m_builder.get_result(node.m_val->span()) ); - + m_builder.set_result( node.span(), ::MIR::RValue::make_SizedArray({ mv$(value), static_cast<unsigned int>(node.m_size_val) }) ); } - + void visit(::HIR::ExprNode_Closure& node) override { TRACE_FUNCTION_F("_Closure - " << node.m_obj_path); - + ::std::vector< ::MIR::LValue> vals; vals.reserve( node.m_captures.size() ); for(auto& arg : node.m_captures) @@ -1893,7 +1893,7 @@ namespace { this->visit_node_ptr(arg); vals.push_back( m_builder.get_result_in_lvalue(arg->span(), arg->m_res_type) ); } - + m_builder.set_result( node.span(), ::MIR::RValue::make_Struct({ node.m_obj_path.clone(), ~0u, @@ -1907,17 +1907,17 @@ namespace { ::MIR::FunctionPointer LowerMIR(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, const ::HIR::ExprPtr& ptr, const ::HIR::Function::args_t& args) { TRACE_FUNCTION; - + ::MIR::Function fcn; fcn.named_variables.reserve(ptr.m_bindings.size()); for(const auto& t : ptr.m_bindings) fcn.named_variables.push_back( t.clone() ); - + // Scope ensures that builder cleanup happens before `fcn` is moved { MirBuilder builder { ptr->span(), resolve, args, fcn }; ExprVisitor_Conv ev { builder, ptr.m_bindings }; - + // 1. Apply destructuring to arguments unsigned int i = 0; for( const auto& arg : args ) @@ -1926,12 +1926,12 @@ namespace { ev.destructure_from(ptr->span(), arg.first, ::MIR::LValue::make_Argument({i})); i ++; } - + // 2. Destructure code ::HIR::ExprNode& root_node = const_cast<::HIR::ExprNode&>(*ptr); root_node.visit( ev ); } - + return ::MIR::FunctionPointer(new ::MIR::Function(mv$(fcn))); } diff --git a/src/mir/from_hir.hpp b/src/mir/from_hir.hpp index caeba6ad..7c83b44f 100644 --- a/src/mir/from_hir.hpp +++ b/src/mir/from_hir.hpp @@ -16,10 +16,10 @@ class MirBuilder; class ScopeHandle { friend class MirBuilder; - + const MirBuilder& m_builder; unsigned int idx; - + ScopeHandle(const MirBuilder& builder, unsigned int idx): m_builder(builder), idx(idx) @@ -43,11 +43,11 @@ enum class VarState { Uninit, // No value assigned yet Moved, // Definitely moved Dropped, // Dropped (out of scope) - + InnerMoved, // The inner has been moved, but the container needs to be dropped //MaybeMovedInner, // Inner possibly has been moved MaybeMoved, // Possibly has been moved - + Init, // Initialised and valid at this point }; extern ::std::ostream& operator<<(::std::ostream& os, VarState x); @@ -57,7 +57,7 @@ struct SplitArm { bool always_early_terminated = false; // Populated on completion ::std::vector<bool> changed_var_states; // Indexed by binding bumber ::std::vector<VarState> var_states; - + ::std::vector<bool> changed_tmp_states; ::std::vector<VarState> tmp_states; }; @@ -80,31 +80,31 @@ TAGGED_UNION(ScopeType, Variables, class MirBuilder { friend class ScopeHandle; - + const Span& m_root_span; const StaticTraitResolve& m_resolve; const ::HIR::Function::args_t& m_args; ::MIR::Function& m_output; - + const ::HIR::SimplePath* m_lang_Box; - + unsigned int m_current_block; bool m_block_active; - + ::MIR::RValue m_result; bool m_result_valid; - + // TODO: Extra information. //::std::vector<VarState> m_arg_states; ::std::vector<VarState> m_variable_states; ::std::vector<VarState> m_temporary_states; - + struct ScopeDef { const Span& span; bool complete = false; ScopeType data; - + ScopeDef(const Span& span): span(span) { @@ -115,27 +115,27 @@ class MirBuilder { } }; - + ::std::vector<ScopeDef> m_scopes; ::std::vector<unsigned int> m_scope_stack; ScopeHandle m_fcn_scope; public: MirBuilder(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::Function::args_t& args, ::MIR::Function& output); ~MirBuilder(); - + const ::HIR::SimplePath* lang_Box() const { return m_lang_Box; } const ::HIR::Crate& crate() const { return m_resolve.m_crate; } const StaticTraitResolve& resolve() const { return m_resolve; } - + //::HIR::TypeRef* is_type_owned_box(::HIR::TypeRef& ty) const { //} /// Check if the passed type is Box<T> and returns a pointer to the T type if so, otherwise nullptr const ::HIR::TypeRef* is_type_owned_box(const ::HIR::TypeRef& ty) const; - + // - Values ::MIR::LValue new_temporary(const ::HIR::TypeRef& ty); ::MIR::LValue lvalue_or_temp(const Span& sp, const ::HIR::TypeRef& ty, ::MIR::RValue val); - + bool has_result() const { return m_result_valid; } @@ -145,7 +145,7 @@ public: ::MIR::LValue get_result_unwrap_lvalue(const Span& sp); /// Obtains the result, copying into a temporary if required ::MIR::LValue get_result_in_lvalue(const Span& sp, const ::HIR::TypeRef& ty); - + // - 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); @@ -153,26 +153,26 @@ public: void push_stmt_drop(const Span& sp, ::MIR::LValue val); // Push a shallow drop (for Box) void push_stmt_drop_shallow(const Span& sp, ::MIR::LValue val); - + // - Block management bool block_active() const { return m_block_active; } - + // Mark a value as initialised (used for Call, because it has to be done after the panic block is populated) void mark_value_assigned(const Span& sp, const ::MIR::LValue& val); - + // Moves control of temporaries up to the next scope void raise_variables(const Span& sp, const ::MIR::LValue& val); void raise_variables(const Span& sp, const ::MIR::RValue& rval); - + void set_cur_block(unsigned int new_block); ::MIR::BasicBlockId pause_cur_block(); void end_block(::MIR::Terminator term); - + ::MIR::BasicBlockId new_bb_linked(); ::MIR::BasicBlockId new_bb_unlinked(); - + // --- Scopes --- ScopeHandle new_scope_var(const Span& sp); ScopeHandle new_scope_temp(const Span& sp); @@ -182,7 +182,7 @@ public: void terminate_scope_early(const Span& sp, const ScopeHandle& ); void end_split_arm(const Span& sp, const ScopeHandle& , bool reachable); void end_split_arm_early(const Span& sp); - + const ScopeHandle& fcn_scope() const { return m_fcn_scope; } @@ -196,10 +196,10 @@ private: void set_variable_state(const Span& sp, unsigned int idx, VarState state); VarState get_temp_state(const Span& sp, unsigned int idx) const; void set_temp_state(const Span& sp, unsigned int idx, VarState state); - + void drop_scope_values(const ScopeDef& sd); void complete_scope(ScopeDef& sd); - + public: void with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::function<void(const ::HIR::TypeRef&)> cb) const; bool lvalue_is_copy(const Span& sp, const ::MIR::LValue& lv) const; diff --git a/src/mir/from_hir_match.cpp b/src/mir/from_hir_match.cpp index f191f3fa..d3c5a5eb 100644 --- a/src/mir/from_hir_match.cpp +++ b/src/mir/from_hir_match.cpp @@ -17,14 +17,14 @@ void MIR_LowerHIR_Match( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNod struct field_path_t { ::std::vector<uint8_t> data; - + size_t size() const { return data.size(); } void push_back(uint8_t v) { data.push_back(v); } void pop_back() { data.pop_back(); } uint8_t& back() { return data.back(); } - + bool operator==(const field_path_t& x) const { return data == x.data; } - + friend ::std::ostream& operator<<(::std::ostream& os, const field_path_t& x) { for(const auto idx : x.data) os << "." << static_cast<unsigned int>(idx); @@ -61,9 +61,9 @@ struct PatternRuleset unsigned int pat_idx; ::std::vector<PatternRule> m_rules; - + static ::Ordering rule_is_before(const PatternRule& l, const PatternRule& r); - + bool is_before(const PatternRuleset& other) const; }; /// Generated code for an arm @@ -88,7 +88,7 @@ struct PatternRulesetBuilder bool m_is_impossible; ::std::vector<PatternRule> m_rules; field_path_t m_field_path; - + PatternRulesetBuilder(const StaticTraitResolve& resolve): m_resolve(resolve), m_is_impossible(false) @@ -97,7 +97,7 @@ struct PatternRulesetBuilder m_lang_Box = &resolve.m_crate.m_lang_items.at("owned_box"); } } - + void append_from_lit(const Span& sp, const ::HIR::Literal& lit, const ::HIR::TypeRef& ty); void append_from(const Span& sp, const ::HIR::Pattern& pat, const ::HIR::TypeRef& ty); void push_rule(PatternRule r); @@ -113,17 +113,17 @@ void MIR_LowerHIR_Match( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNod { // TODO: If any arm moves a non-Copy value, then mark `match_val` as moved TRACE_FUNCTION; - + bool fall_back_on_simple = false; - + auto result_val = builder.new_temporary( node.m_res_type ); auto next_block = builder.new_bb_unlinked(); - + // 1. Stop the current block so we can generate code auto first_cmp_block = builder.new_bb_unlinked(); builder.end_block( ::MIR::Terminator::make_Goto(first_cmp_block) ); - + struct H { static bool is_pattern_move(const Span& sp, const MirBuilder& builder, const ::HIR::Pattern& pat) { if( pat.m_binding.is_valid() ) @@ -221,7 +221,7 @@ void MIR_LowerHIR_Match( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNod return false; } }; - + bool has_move_pattern = false; for(const auto& arm : node.m_arms) { @@ -234,7 +234,7 @@ void MIR_LowerHIR_Match( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNod if( has_move_pattern ) break ; } - + auto match_scope = builder.new_scope_split(node.span()); // Map of arm index to ruleset @@ -245,12 +245,12 @@ void MIR_LowerHIR_Match( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNod DEBUG("ARM " << arm_idx); /*const*/ auto& arm = node.m_arms[arm_idx]; ArmCode ac; - + // Register introduced bindings to be dropped on return/diverge within this scope auto drop_scope = builder.new_scope_var( arm.m_code->span() ); // - Define variables from the first pattern conv.define_vars_from(node.span(), arm.m_patterns.front()); - + for( unsigned int pat_idx = 0; pat_idx < arm.m_patterns.size(); pat_idx ++ ) { const auto& pat = arm.m_patterns[pat_idx]; @@ -266,7 +266,7 @@ void MIR_LowerHIR_Match( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNod DEBUG("ARM PAT (" << arm_idx << "," << pat_idx << ") " << pat << " ==> [" << pat_builder.m_rules << "]"); arm_rules.push_back( PatternRuleset { arm_idx, pat_idx, mv$(pat_builder.m_rules) } ); } - + // - Emit code to destructure the matched pattern ac.destructures.push_back( builder.new_bb_unlinked() ); builder.set_cur_block( ac.destructures.back() ); @@ -274,14 +274,14 @@ void MIR_LowerHIR_Match( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNod builder.pause_cur_block(); // NOTE: Paused block resumed upon successful match } - + // TODO: If this pattern ignores fields with Drop impls, this will lead to leaks. // - Ideally, this would trigger a drop of whatever wasn't already taken by the pattern. if( has_move_pattern ) { builder.moved_lvalue(node.span(), match_val); } - + // Condition // NOTE: Lack of drop due to early exit from this arm isn't an issue. All captures must be Copy // - The above is rustc E0008 "cannot bind by-move into a pattern guard" @@ -291,13 +291,13 @@ void MIR_LowerHIR_Match( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNod ac.has_condition = true; ac.cond_start = builder.new_bb_unlinked(); builder.set_cur_block( ac.cond_start ); - + // TODO: Temp scope. conv.visit_node_ptr( arm.m_cond ); ac.cond_lval = builder.get_result_in_lvalue(arm.m_cond->span(), ::HIR::TypeRef(::HIR::CoreType::Bool)); ac.cond_end = builder.pause_cur_block(); // NOTE: Paused so that later code (which knows what the false branch will be) can end it correctly - + // TODO: What to do with contidionals in the fast model? // > Could split the match on each conditional - separating such that if a conditional fails it can fall into the other compatible branches. fall_back_on_simple = true; @@ -335,10 +335,10 @@ void MIR_LowerHIR_Match( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNod // - Go to the next block builder.end_block( ::MIR::Terminator::make_Goto(next_block) ); } - + arm_code.push_back( mv$(ac) ); } - + // Sort columns of `arm_rules` to maximise effectiveness if( arm_rules[0].m_rules.size() > 1 ) { @@ -354,7 +354,7 @@ void MIR_LowerHIR_Match( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNod } } } - + DEBUG("- Column weights = [" << column_weights << "]"); // - Sort columns such that the largest (most specific) comes first ::std::vector<unsigned> columns_sorted(column_weights.size()); @@ -371,12 +371,12 @@ void MIR_LowerHIR_Match( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNod arm_rule.m_rules = mv$(sorted); } } - + for(const auto& arm_rule : arm_rules) { DEBUG("> (" << arm_rule.arm_idx << ", " << arm_rule.pat_idx << ") - " << arm_rule.m_rules); } - + // TODO: Detect if a rule is ordering-dependent. In this case we currently have to fall back on the simple match code // - A way would be to search for `_` rules with non _ rules following. Would false-positive in some cases, but shouldn't false negative // TODO: Merge equal rulesets if there's one with no condition. @@ -387,7 +387,7 @@ void MIR_LowerHIR_Match( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNod else { MIR_LowerHIR_Match_DecisionTree( builder, conv, node, mv$(match_val), mv$(arm_rules), mv$(arm_code), first_cmp_block ); } - + builder.set_cur_block( next_block ); builder.set_result( node.span(), mv$(result_val) ); builder.terminate_scope( node.span(), mv$(match_scope) ); @@ -439,7 +439,7 @@ void MIR_LowerHIR_Match( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNod else return ::OrdLess; } - + TU_MATCHA( (l,r), (le,re), (Any, return ::OrdEqual; @@ -581,7 +581,7 @@ void PatternRulesetBuilder::append_from_lit(const Span& sp, const ::HIR::Literal (Struct, ASSERT_BUG(sp, lit.is_List(), "Matching struct non-list literal - " << ty << " with " << lit); const auto& list = lit.as_List(); - + 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); @@ -600,7 +600,7 @@ void PatternRulesetBuilder::append_from_lit(const Span& sp, const ::HIR::Literal { ::HIR::TypeRef tmp; const auto& sty_mono = (monomorphise_type_needed(sd[i].ent) ? tmp = monomorph(sd[i].ent) : sd[i].ent); - + this->append_from_lit(sp, list[i], sty_mono); m_field_path.back() ++; } @@ -614,7 +614,7 @@ void PatternRulesetBuilder::append_from_lit(const Span& sp, const ::HIR::Literal const auto& fld_ty = sd[i].second.ent; ::HIR::TypeRef tmp; const auto& sty_mono = (monomorphise_type_needed(fld_ty) ? tmp = monomorph(fld_ty) : fld_ty); - + this->append_from_lit(sp, list[i], sty_mono); m_field_path.back() ++; } @@ -633,14 +633,14 @@ void PatternRulesetBuilder::append_from_lit(const Span& sp, const ::HIR::Literal this->m_resolve.expand_associated_types(sp, rv); return rv; }; - + ASSERT_BUG(sp, var_idx < pbe->m_variants.size(), "Literal refers to a variant out of range"); const auto& var_def = pbe->m_variants.at(var_idx); - + PatternRulesetBuilder sub_builder { this->m_resolve }; sub_builder.m_field_path = m_field_path; sub_builder.m_field_path.push_back(0); - + TU_MATCH( ::HIR::Enum::Variant, (var_def.second), (fields_def), (Unit, ), @@ -654,10 +654,10 @@ void PatternRulesetBuilder::append_from_lit(const Span& sp, const ::HIR::Literal sub_builder.m_field_path.back() = i; const auto& val = list[i]; const auto& ty_tpl = fields_def[i].ent; - + ::HIR::TypeRef tmp; const auto& subty = (monomorphise_type_needed(ty_tpl) ? tmp = monomorph(ty_tpl) : ty_tpl); - + sub_builder.append_from_lit( sp, val, subty ); } ), @@ -669,15 +669,15 @@ void PatternRulesetBuilder::append_from_lit(const Span& sp, const ::HIR::Literal sub_builder.m_field_path.back() = i; const auto& val = list[i]; const auto& ty_tpl = fields_def[i].second.ent; - + ::HIR::TypeRef tmp; const auto& subty = (monomorphise_type_needed(ty_tpl) ? tmp = monomorph(ty_tpl) : ty_tpl); - + sub_builder.append_from_lit( sp, val, subty ); } ) ) - + this->push_rule( PatternRule::make_Variant({ var_idx, mv$(sub_builder.m_rules) }) ); ) ) @@ -697,7 +697,7 @@ void PatternRulesetBuilder::append_from_lit(const Span& sp, const ::HIR::Literal ASSERT_BUG(sp, lit.is_List(), "Matching array with non-list literal - " << lit); const auto& list = lit.as_List(); ASSERT_BUG(sp, e.size_val == list.size(), "Matching array with mismatched literal size - " << e.size_val << " != " << list.size()); - + // Sequential match just like tuples. m_field_path.push_back(0); for(unsigned int i = 0; i < e.size_val; i ++) { @@ -709,7 +709,7 @@ void PatternRulesetBuilder::append_from_lit(const Span& sp, const ::HIR::Literal (Slice, ASSERT_BUG(sp, lit.is_List(), "Matching array with non-list literal - " << lit); const auto& list = lit.as_List(); - + PatternRulesetBuilder sub_builder { this->m_resolve }; sub_builder.m_field_path = m_field_path; sub_builder.m_field_path.push_back(0); @@ -772,7 +772,7 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa throw ""; } }; - + // 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. <GenericT as Foo>::CONST) @@ -790,7 +790,7 @@ 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, @@ -939,7 +939,7 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa return rv; }; const auto& str_data = pbe->m_data; - + if( m_lang_Box && e.path.m_data.as_Generic().m_path == *m_lang_Box ) { const auto& inner_ty = e.path.m_data.as_Generic().m_params.m_types.at(0); @@ -994,7 +994,7 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa { const auto& fld = sd[i]; const auto& fld_pat = pe.sub_patterns[i]; - + ::HIR::TypeRef tmp; const auto& sty_mono = (monomorphise_type_needed(fld.ent) ? tmp = monomorph(fld.ent) : fld.ent); this->append_from(sp, fld_pat, sty_mono); @@ -1025,7 +1025,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); - + 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() ) { @@ -1070,7 +1070,7 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa ), (EnumTuple, const auto& var_def = pe.binding_ptr->m_variants.at(pe.binding_idx); - + const auto& fields_def = var_def.second.as_Tuple(); PatternRulesetBuilder sub_builder { this->m_resolve }; sub_builder.m_field_path = m_field_path; @@ -1080,10 +1080,10 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa sub_builder.m_field_path.back() = i; const auto& subpat = pe.sub_patterns[i]; const auto& ty_tpl = fields_def[i].ent; - + ::HIR::TypeRef tmp; const auto& subty = (monomorphise_type_needed(ty_tpl) ? tmp = monomorph(ty_tpl) : ty_tpl); - + sub_builder.append_from( sp, subpat, subty ); } if( sub_builder.m_is_impossible ) @@ -1111,7 +1111,7 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa for( unsigned int i = 0; i < tmp.size(); i ++ ) { sub_builder.m_field_path.back() = i; - + auto subty = monomorph(fields_def[i].second.ent); if( tmp[i] == ~0u ) { sub_builder.append_from( sp, ::HIR::Pattern(), subty ); @@ -1194,7 +1194,7 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa sub_builder.append_from( sp, subpat, *e.inner ); sub_builder.m_field_path.back() ++; } - + // Encodes length check and sub-pattern rules this->push_rule( PatternRule::make_Slice({ static_cast<unsigned int>(pe.sub_patterns.size()), mv$(sub_builder.m_rules) }) ); ), @@ -1208,14 +1208,14 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa sub_builder.m_field_path.back() ++; } auto leading = mv$(sub_builder.m_rules); - + sub_builder.m_field_path.back() = 0; if( pe.trailing.size() ) { TODO(sp, "SplitSlice on [T] with trailing - " << pat); } auto trailing = mv$(sub_builder.m_rules); - + this->push_rule( PatternRule::make_SplitSlice({ static_cast<unsigned int>(pe.leading.size() + pe.trailing.size()), mv$(leading), mv$(trailing) @@ -1245,7 +1245,7 @@ void PatternRulesetBuilder::append_from(const Span& sp, const ::HIR::Pattern& pa data.reserve(s.size()); for(auto c : s) data.push_back(c); - + this->push_rule( PatternRule::make_Value( mv$(data) ) ); } // TODO: Handle named values @@ -1291,13 +1291,13 @@ namespace { ::MIR::LValue lval = top_val.clone(); ::HIR::TypeRef tmp_ty; const ::HIR::TypeRef* cur_ty = &top_ty; - + // TODO: Cache the correspondance of path->type (lval can be inferred) ASSERT_BUG(sp, field_path_ofs <= field_path.size(), "Field path offset " << field_path_ofs << " is larger than the path [" << field_path << "]"); for(unsigned int i = field_path_ofs; i < field_path.size(); i ++ ) { auto idx = field_path.data[i]; - + TU_MATCHA( (cur_ty->m_data), (e), (Infer, BUG(sp, "Ivar for in match type"); ), (Diverge, BUG(sp, "Diverge in match type"); ), @@ -1421,7 +1421,7 @@ namespace { ) ) } - + out_ty = (cur_ty == &tmp_ty ? mv$(tmp_ty) : cur_ty->clone()); out_val = mv$(lval); } @@ -1435,7 +1435,7 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& void MIR_LowerHIR_Match_Simple( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNode_Match& node, ::MIR::LValue match_val, t_arm_rules arm_rules, ::std::vector<ArmCode> arms_code, ::MIR::BasicBlockId first_cmp_block ) { TRACE_FUNCTION; - + // 1. Generate pattern matches unsigned int rule_idx = 0; builder.set_cur_block( first_cmp_block ); @@ -1443,18 +1443,18 @@ void MIR_LowerHIR_Match_Simple( MirBuilder& builder, MirConverter& conv, ::HIR:: { const auto& arm = node.m_arms[arm_idx]; auto& arm_code = arms_code[arm_idx]; - + auto next_arm_bb = builder.new_bb_unlinked(); - + for( unsigned int i = 0; i < arm.m_patterns.size(); i ++ ) { if( arm_code.destructures[i] == 0 ) continue ; - + const auto& pat_rule = arm_rules[rule_idx]; bool is_last_pat = (i+1 == arm.m_patterns.size()); auto next_pattern_bb = (!is_last_pat ? builder.new_bb_unlinked() : next_arm_bb); - + // 1. Check // - If the ruleset is empty, this is a _ arm over a value if( pat_rule.m_rules.size() > 0 ) @@ -1463,7 +1463,7 @@ void MIR_LowerHIR_Match_Simple( MirBuilder& builder, MirConverter& conv, ::HIR:: } builder.end_block( ::MIR::Terminator::make_Goto(arm_code.destructures[i]) ); builder.set_cur_block( arm_code.destructures[i] ); - + // - Go to code/condition check if( arm_code.has_condition ) { @@ -1473,12 +1473,12 @@ void MIR_LowerHIR_Match_Simple( MirBuilder& builder, MirConverter& conv, ::HIR:: { builder.end_block( ::MIR::Terminator::make_Goto(arm_code.code) ); } - + if( !is_last_pat ) { builder.set_cur_block( next_pattern_bb ); } - + rule_idx ++; } if( arm_code.has_condition ) @@ -1499,17 +1499,17 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& { const auto& rule = rules[rule_idx]; DEBUG("rule = " << rule); - + // Don't emit anything for '_' matches if( rule.is_Any() ) continue ; - + ::MIR::LValue val; ::HIR::TypeRef ity; - + get_ty_and_val(sp, builder.resolve(), top_ty, top_val, rule.field_path, field_path_ofs, ity, val); DEBUG("ty = " << ity << ", val = " << val); - + const auto& ty = ity; TU_MATCHA( (ty.m_data), (te), (Infer, @@ -1524,9 +1524,9 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& case ::HIR::CoreType::Bool: { ASSERT_BUG(sp, rule.is_Bool(), "PatternRule for bool isn't _Bool"); bool test_val = rule.as_Bool(); - + auto succ_bb = builder.new_bb_unlinked(); - + if( test_val ) { builder.end_block( ::MIR::Terminator::make_If({ val.clone(), succ_bb, fail_bb }) ); } @@ -1546,7 +1546,7 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& ), (Value, auto succ_bb = builder.new_bb_unlinked(); - + auto test_lval = builder.lvalue_or_temp(sp, te, ::MIR::Constant(re.as_Uint())); auto cmp_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ val.clone(), ::MIR::eBinOp::EQ, mv$(test_lval) })); builder.end_block( ::MIR::Terminator::make_If({ mv$(cmp_lval), succ_bb, fail_bb }) ); @@ -1568,7 +1568,7 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& ), (Value, auto succ_bb = builder.new_bb_unlinked(); - + auto test_lval = builder.lvalue_or_temp(sp, te, ::MIR::Constant(re.as_Int())); auto cmp_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ val.clone(), ::MIR::eBinOp::EQ, mv$(test_lval) })); builder.end_block( ::MIR::Terminator::make_If({ mv$(cmp_lval), succ_bb, fail_bb }) ); @@ -1586,7 +1586,7 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& ), (Value, auto succ_bb = builder.new_bb_unlinked(); - + auto test_lval = builder.lvalue_or_temp(sp, te, ::MIR::Constant(re.as_Uint())); auto cmp_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ val.clone(), ::MIR::eBinOp::EQ, mv$(test_lval) })); builder.end_block( ::MIR::Terminator::make_If({ mv$(cmp_lval), succ_bb, fail_bb }) ); @@ -1595,19 +1595,19 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& (ValueRange, auto succ_bb = builder.new_bb_unlinked(); auto test_bb_2 = builder.new_bb_unlinked(); - + // IF `val` < `first` : fail_bb auto test_lt_lval = builder.lvalue_or_temp(sp, te, ::MIR::Constant(re.first.as_Uint())); auto cmp_lt_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ val.clone(), ::MIR::eBinOp::LT, mv$(test_lt_lval) })); builder.end_block( ::MIR::Terminator::make_If({ mv$(cmp_lt_lval), fail_bb, test_bb_2 }) ); - + builder.set_cur_block(test_bb_2); - + // IF `val` > `last` : fail_bb auto test_gt_lval = builder.lvalue_or_temp(sp, te, ::MIR::Constant(re.last.as_Uint())); auto cmp_gt_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ val.clone(), ::MIR::eBinOp::GT, mv$(test_gt_lval) })); builder.end_block( ::MIR::Terminator::make_If({ mv$(cmp_gt_lval), fail_bb, succ_bb }) ); - + builder.set_cur_block(succ_bb); ) ) @@ -1619,9 +1619,9 @@ 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(); - + auto succ_bb = builder.new_bb_unlinked(); - + auto test_lval = builder.lvalue_or_temp(sp, ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, ty.clone()), ::MIR::RValue(::MIR::Constant( v.as_StaticString() ))); auto cmp_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ val.clone(), ::MIR::eBinOp::EQ, ::MIR::LValue::make_Deref({box$(test_lval)}) })); builder.end_block( ::MIR::Terminator::make_If({ mv$(cmp_lval), succ_bb, fail_bb }) ); @@ -1659,17 +1659,17 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& ASSERT_BUG(sp, rule.is_Variant(), "Rule for enum isn't Any or Variant"); const auto& re = rule.as_Variant(); unsigned int var_idx = re.idx; - + auto next_bb = builder.new_bb_unlinked(); auto var_count = pbe->m_variants.size(); - + // Generate a switch with only one option different. ::std::vector< ::MIR::BasicBlockId> arms(var_count, fail_bb); arms[var_idx] = next_bb; builder.end_block( ::MIR::Terminator::make_Switch({ val.clone(), mv$(arms) }) ); - + builder.set_cur_block(next_bb); - + if( re.sub_rules.size() > 0 ) { const auto& var_data = pbe->m_variants.at(re.idx).second; @@ -1689,7 +1689,7 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& fake_ty_ents.push_back( monomorph(ve[i].ent) ); } ::HIR::TypeRef fake_tup = ::HIR::TypeRef( mv$(fake_ty_ents) ); - + // Recurse with the new ruleset MIR_LowerHIR_Match_Simple__GeneratePattern(builder, sp, re.sub_rules.data(), re.sub_rules.size(), @@ -1706,7 +1706,7 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& fake_ty_ents.push_back( monomorph(ve[i].second.ent) ); } ::HIR::TypeRef fake_tup = ::HIR::TypeRef( mv$(fake_ty_ents) ); - + // Recurse with the new ruleset MIR_LowerHIR_Match_Simple__GeneratePattern(builder, sp, re.sub_rules.data(), re.sub_rules.size(), @@ -1752,11 +1752,11 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& if( rule.is_Value() ) { ASSERT_BUG(sp, *te.inner == ::HIR::CoreType::U8, "Bytes pattern on non-&[u8]"); auto cloned_val = ::MIR::Constant( rule.as_Value().as_Bytes() ); - + auto succ_bb = builder.new_bb_unlinked(); - + auto inner_val = val.as_Deref().val->clone(); - + auto test_lval = builder.lvalue_or_temp(sp, ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, ty.clone()), ::MIR::RValue(mv$(cloned_val))); auto cmp_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ mv$(inner_val), ::MIR::eBinOp::EQ, mv$(test_lval) })); builder.end_block( ::MIR::Terminator::make_If({ mv$(cmp_lval), succ_bb, fail_bb }) ); @@ -1764,16 +1764,16 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& } else if( rule.is_Slice() ) { const auto& re = rule.as_Slice(); - + // Compare length auto test_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue( ::MIR::Constant::make_Uint(re.len) )); auto len_val = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ val.clone() })); auto cmp_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ mv$(len_val), ::MIR::eBinOp::EQ, mv$(test_lval) })); - + auto len_succ_bb = builder.new_bb_unlinked(); builder.end_block( ::MIR::Terminator::make_If({ mv$(cmp_lval), len_succ_bb, fail_bb }) ); builder.set_cur_block(len_succ_bb); - + // Recurse checking values MIR_LowerHIR_Match_Simple__GeneratePattern(builder, sp, re.sub_rules.data(), re.sub_rules.size(), @@ -1783,22 +1783,22 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& } else if( rule.is_SplitSlice() ) { const auto& re = rule.as_SplitSlice(); - + // Compare length auto test_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue( ::MIR::Constant::make_Uint(re.min_len) )); auto len_val = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ val.clone() })); auto cmp_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ mv$(len_val), ::MIR::eBinOp::LT, mv$(test_lval) })); - + auto len_succ_bb = builder.new_bb_unlinked(); builder.end_block( ::MIR::Terminator::make_If({ mv$(cmp_lval), fail_bb, len_succ_bb }) ); // if len < test : FAIL builder.set_cur_block(len_succ_bb); - + MIR_LowerHIR_Match_Simple__GeneratePattern(builder, sp, re.leading.data(), re.leading.size(), top_ty, top_val, field_path_ofs, fail_bb ); - + if( re.trailing.size() > 0 ) { TODO(sp, "Match over Slice using SplitSlice with trailing - " << rule); @@ -1841,13 +1841,13 @@ struct DecisionTreeNode (Subtree, ::std::unique_ptr<DecisionTreeNode>), (Terminal, unsigned int) ); - + template<typename T> struct Range { T start; T end; - + // `x` starts after this range ends bool operator<(const Range<T>& x) const { return (end < x.start); @@ -1856,7 +1856,7 @@ struct DecisionTreeNode bool operator<(const T& x) const { return (end < x); } - + // `x` ends before this starts, or overlaps bool operator>=(const Range<T>& x) const { return start > x.end || ovelaps(x); @@ -1865,28 +1865,28 @@ struct DecisionTreeNode bool operator>=(const T& x) const { return start > x || contains(x); } - + bool operator>(const Range<T>& x) const { return (start > x.end); } bool operator>(const T& x) const { return (start > x); } - + bool operator==(const Range<T>& x) const { return start == x.start && end == x.end; } bool operator!=(const Range<T>& x) const { return start != x.start || end != x.end; } - + bool contains(const T& x) const { return (start <= x && x <= end); } bool overlaps(const Range<T>& x) const { return (x.start <= start && start <= x.end) || (x.start <= end && end <= x.end); } - + friend ::std::ostream& operator<<(::std::ostream& os, const Range<T>& x) { if( x.start == x.end ) { return os << x.start; @@ -1896,7 +1896,7 @@ struct DecisionTreeNode } } }; - + TAGGED_UNION( Values, Unset, (Unset, struct {}), (Bool, struct { Branch false_branch, true_branch; }), @@ -1910,23 +1910,23 @@ struct DecisionTreeNode //::std::vector< ::std::pair< unsigned int, Branch> > variable_arms; }) ); - + // TODO: Arm specialisation? field_path_t m_field_path; Values m_branches; Branch m_default; - + DecisionTreeNode( field_path_t field_path ): // TODO: This is commented out fo a reason, but I don't know why. //m_field_path( mv$(field_path) ), m_branches(), m_default() {} - + static Branch clone(const Branch& b); static Values clone(const Values& x); DecisionTreeNode clone() const; - + void populate_tree_from_rule(const Span& sp, unsigned int arm_index, const PatternRule* first_rule, unsigned int rule_count) { populate_tree_from_rule(sp, first_rule, rule_count, [sp,arm_index](auto& branch){ TU_MATCHA( (branch), (e), @@ -1951,14 +1951,14 @@ struct DecisionTreeNode } // `and_then` - Closure called after processing the final rule void populate_tree_from_rule(const Span& sp, const PatternRule* first_rule, unsigned int rule_count, ::std::function<void(Branch&)> and_then); - + /// Simplifies the tree by eliminating nodes that don't make a decision void simplify(); /// Propagate the m_default arm's contents to value arms, and vice-versa void propagate_default(); /// HELPER: Unfies the rules from the provided branch with this node void unify_from(const Branch& b); - + ::MIR::LValue get_field(const ::MIR::LValue& base, unsigned int base_depth) const { ::MIR::LValue cur = base.clone(); for(unsigned int i = base_depth; i < m_field_path.size(); i ++ ) { @@ -1972,7 +1972,7 @@ struct DecisionTreeNode } return cur; } - + friend ::std::ostream& operator<<(::std::ostream& os, const Branch& x); friend ::std::ostream& operator<<(::std::ostream& os, const DecisionTreeNode& x); }; @@ -1981,16 +1981,16 @@ struct DecisionTreeGen { MirBuilder& m_builder; const ::std::vector< ::MIR::BasicBlockId>& m_rule_blocks; - + DecisionTreeGen(MirBuilder& builder, const ::std::vector< ::MIR::BasicBlockId >& rule_blocks): m_builder( builder ), m_rule_blocks( rule_blocks ) {} - + ::MIR::BasicBlockId get_block_for_rule(unsigned int rule_index) { return m_rule_blocks.at( rule_index ); } - + void generate_tree_code(const Span& sp, const DecisionTreeNode& node, const ::HIR::TypeRef& ty, const ::MIR::LValue& val) { generate_tree_code(sp, node, ty, 0, val, [&](const auto& n){ DEBUG("node = " << n); @@ -2004,9 +2004,9 @@ struct DecisionTreeGen const ::HIR::TypeRef& ty, unsigned int path_ofs, const ::MIR::LValue& base_val, ::std::function<void(const DecisionTreeNode&)> and_then ); - + void generate_branch(const DecisionTreeNode::Branch& branch, ::std::function<void(const DecisionTreeNode&)> cb); - + void generate_branches_Signed( const Span& sp, const DecisionTreeNode::Branch& default_branch, @@ -2049,7 +2049,7 @@ struct DecisionTreeGen const ::HIR::TypeRef& ty, ::MIR::LValue val, ::std::function<void(const DecisionTreeNode&)> and_then ); - + void generate_branches_Enum( const Span& sp, const DecisionTreeNode::Branch& default_branch, @@ -2077,7 +2077,7 @@ struct DecisionTreeGen void MIR_LowerHIR_Match_DecisionTree( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNode_Match& node, ::MIR::LValue match_val, t_arm_rules arm_rules, ::std::vector<ArmCode> arms_code, ::MIR::BasicBlockId first_cmp_block ) { TRACE_FUNCTION; - + // XXX XXX XXX: The current codegen (below) will generate incorrect code if ordering matters. // ``` // match ("foo", "bar") @@ -2091,14 +2091,14 @@ void MIR_LowerHIR_Match_DecisionTree( MirBuilder& builder, MirConverter& conv, : // TODO: Sort the columns in `arm_rules` to ensure that the most specific rule is parsed first. // - Ordering within a pattern doesn't matter, only the order of arms matters. // - This sort could be designed such that the above case would match correctly? - + DEBUG("- Generating rule bindings"); ::std::vector< ::MIR::BasicBlockId> rule_blocks; for(const auto& rule : arm_rules) { const auto& arm_code = arms_code[rule.arm_idx]; ASSERT_BUG(node.span(), !arm_code.has_condition, "Decision tree doesn't (yet) support conditionals"); - + assert( rule.pat_idx < arm_code.destructures.size() ); // Set the target for when a rule succeeds to the destructuring code for this rule rule_blocks.push_back( arm_code.destructures[rule.pat_idx] ); @@ -2106,8 +2106,8 @@ void MIR_LowerHIR_Match_DecisionTree( MirBuilder& builder, MirConverter& conv, : builder.set_cur_block( rule_blocks.back() ); builder.end_block( ::MIR::Terminator::make_Goto(arm_code.code) ); } - - + + // - Build tree by running each arm's pattern across it DEBUG("- Building decision tree"); DecisionTreeNode root_node({}); @@ -2125,7 +2125,7 @@ void MIR_LowerHIR_Match_DecisionTree( MirBuilder& builder, MirConverter& conv, : root_node.propagate_default(); DEBUG("root_node = " << root_node); // TODO: Pretty print `root_node` - + // - Convert the above decision tree into MIR DEBUG("- Emitting decision tree"); DecisionTreeGen gen { builder, rule_blocks }; @@ -2144,7 +2144,7 @@ DecisionTreeNode MIR_LowerHIR_Match_DecisionTree__MakeTree(const Span& sp, t_arm rules.push_back( arm_rules[i].m_rules ); indexes.push_back(i); } - + return MIR_LowerHIR_Match_DecisionTree__MakeTree_Node(sp, indexes, rules); } DecisionTreeNode MIR_LowerHIR_Match_DecisionTree__MakeTree_Node(const Span& sp, slice<unsigned int> arm_indexes, slice< slice<PaternRule>> arm_rules) @@ -2152,13 +2152,13 @@ DecisionTreeNode MIR_LowerHIR_Match_DecisionTree__MakeTree_Node(const Span& sp, assert( arm_indexes.size() == arm_rules.size() ); assert( arm_rules.size() > 1 ); assert( arm_rules[0].size() > 0 ); - + // 1. Sort list (should it already be sorted?) for(const auto& rules : arm_rules) { ASSERT_BUG(sp, rules.size() != arm_rules[0].size(), ""); } - + // 2. Detect all arms being `_` and move on to the next condition while( ::std::all_of(arm_rules.begin(), arm_rules.end(), [](const auto& r){ return r.m_rules[0].is_Any(); }) ) { @@ -2167,27 +2167,27 @@ DecisionTreeNode MIR_LowerHIR_Match_DecisionTree__MakeTree_Node(const Span& sp, // No rules left? BUG(sp, "Duplicate match arms"); } - + for(auto& rules : arm_rules) { rules = rules.subslice_from(1); } } - + // We have a codition. for(const auto& rules : arm_rules) { ASSERT_BUG(sp, rules[0].is_Any() || rules[0].tag() == arm_rules[0][0].tag(), "Mismatched rules in match"); } - + bool has_any = arm_rules.back()[0].is_Any(); - + // All rules must either be _ or the same type, and can't all be _ switch( arm_rules[0][0].tag() ) { case PatternRule::TAGDEAD: throw ""; case PatternRule::TAG_Any: throw ""; - + case PatternRule::TAG_Variant: break; // TODO: Value and ValueRange can appear together. @@ -2273,7 +2273,7 @@ namespace { return DecisionTreeNode::Branch( box$(DecisionTreeNode( mv$(path) )) ); } - + // Common code for numerics (Int, Uint, and Float) template<typename T> static void from_rule_valuerange( @@ -2284,7 +2284,7 @@ namespace { ASSERT_BUG(sp, ve_start != ve_end, "Range pattern with one value - " << ve_start); ASSERT_BUG(sp, ve_start < ve_end, "Range pattern with a start after the end - " << ve_start << "..." << ve_end); - + TRACE_FUNCTION_F("[" << FMT_CB(os, for(const auto& i:be) os << i.first <<" , ";) << "]"); // - Find the first entry that ends after the new one starts. auto it = ::std::find_if(be.begin(), be.end(), [&](const auto& v){ return v.first.end >= ve_start; }); @@ -2332,7 +2332,7 @@ namespace DEBUG("- Shared head, continue"); //assert(it->first.start == ve_start); assert((it->first.end) < ve_end); - + if( it->first.start != it->first.end ) and_then(it->second); ve_start = it->first.end + 1; @@ -2340,7 +2340,7 @@ namespace } } } - + template<typename T> static void from_rule_value( const Span& sp, @@ -2366,14 +2366,14 @@ void DecisionTreeNode::populate_tree_from_rule(const Span& sp, const PatternRule { assert( rule_count > 0 ); const auto& rule = *first_rule; - + if( m_field_path.size() == 0 ) { m_field_path = rule.field_path; } else { ASSERT_BUG(sp, m_field_path == rule.field_path, "Patterns with mismatched field paths - " << m_field_path << " != " << rule.field_path); } - + #define GET_BRANCHES(fld, var) (({if( fld.is_Unset() ) {\ fld = Values::make_##var({}); \ } \ @@ -2382,7 +2382,7 @@ void DecisionTreeNode::populate_tree_from_rule(const Span& sp, const PatternRule }}), \ fld.as_##var()) - + TU_MATCHA( (rule), (e), (Any, { if( rule_count == 1 ) @@ -2408,7 +2408,7 @@ void DecisionTreeNode::populate_tree_from_rule(const Span& sp, const PatternRule }), (Variant, { auto& be = GET_BRANCHES(m_branches, Variant); - + auto it = ::std::find_if( be.begin(), be.end(), [&](const auto& x){ return x.first >= e.idx; }); // If this variant isn't yet processed, add a new subtree for it if( it == be.end() || it->first != e.idx ) { @@ -2423,7 +2423,7 @@ void DecisionTreeNode::populate_tree_from_rule(const Span& sp, const PatternRule assert( it->second.is_Subtree() ); } auto& subtree = *it->second.as_Subtree(); - + if( e.sub_rules.size() > 0 && rule_count > 1 ) { subtree.populate_tree_from_rule(sp, e.sub_rules.data(), e.sub_rules.size(), [&](auto& branch){ @@ -2455,7 +2455,7 @@ void DecisionTreeNode::populate_tree_from_rule(const Span& sp, const PatternRule }), (Slice, auto& be = GET_BRANCHES(m_branches, Slice); - + auto it = ::std::find_if( be.fixed_arms.begin(), be.fixed_arms.end(), [&](const auto& x){ return x.first >= e.len; } ); if( it == be.fixed_arms.end() || it->first != e.len ) { it = be.fixed_arms.insert(it, ::std::make_pair(e.len, new_branch_subtree(rule.field_path))); @@ -2468,7 +2468,7 @@ void DecisionTreeNode::populate_tree_from_rule(const Span& sp, const PatternRule } assert( it->second.is_Subtree() ); auto& subtree = *it->second.as_Subtree(); - + if( e.sub_rules.size() > 0 && rule_count > 1 ) { subtree.populate_tree_from_rule(sp, e.sub_rules.data(), e.sub_rules.size(), [&](auto& branch){ @@ -2504,7 +2504,7 @@ void DecisionTreeNode::populate_tree_from_rule(const Span& sp, const PatternRule ), (Bool, auto& be = GET_BRANCHES(m_branches, Bool); - + auto& branch = (e ? be.true_branch : be.false_branch); if( branch.is_Unset() ) { branch = new_branch_subtree( rule.field_path ); @@ -2529,7 +2529,7 @@ void DecisionTreeNode::populate_tree_from_rule(const Span& sp, const PatternRule TU_MATCHA( (e), (ve), (Int, auto& be = GET_BRANCHES(m_branches, Signed); - + // TODO: De-duplicate this code between Uint and Float from_rule_value(sp, be, ve, "Signed", rule.field_path, [&](auto& branch) { @@ -2546,7 +2546,7 @@ void DecisionTreeNode::populate_tree_from_rule(const Span& sp, const PatternRule ), (Uint, auto& be = GET_BRANCHES(m_branches, Unsigned); - + from_rule_value(sp, be, ve, "Unsigned", rule.field_path, [&](auto& branch) { if( rule_count > 1 ) { @@ -2562,7 +2562,7 @@ void DecisionTreeNode::populate_tree_from_rule(const Span& sp, const PatternRule ), (Float, auto& be = GET_BRANCHES(m_branches, Float); - + from_rule_value(sp, be, ve, "Float", rule.field_path, [&](auto& branch) { if( rule_count > 1 ) { @@ -2583,7 +2583,7 @@ void DecisionTreeNode::populate_tree_from_rule(const Span& sp, const PatternRule ), (StaticString, auto& be = GET_BRANCHES(m_branches, String); - + auto it = ::std::find_if(be.begin(), be.end(), [&](const auto& v){ return v.first >= ve; }); if( it == be.end() || it->first != ve ) { it = be.insert( it, ::std::make_pair(ve, new_branch_subtree(rule.field_path) ) ); @@ -2609,7 +2609,7 @@ void DecisionTreeNode::populate_tree_from_rule(const Span& sp, const PatternRule ) ), (ValueRange, - + ASSERT_BUG(sp, e.first.tag() == e.last.tag(), ""); TU_MATCHA( (e.first, e.last), (ve_start, ve_end), (Int, @@ -2695,7 +2695,7 @@ void DecisionTreeNode::simplify() ) } }; - + TU_MATCHA( (m_branches), (e), (Unset, H::simplify_branch(m_default); @@ -2742,7 +2742,7 @@ void DecisionTreeNode::simplify() } ) ) - + H::simplify_branch(m_default); } @@ -2762,7 +2762,7 @@ void DecisionTreeNode::propagate_default() ) } }; - + TU_MATCHA( (m_branches), (e), (Unset, ), @@ -2812,7 +2812,7 @@ void DecisionTreeNode::propagate_default() DEBUG("- default"); TU_IFLET(Branch, m_default, Subtree, be, be->propagate_default(); - + if( be->m_default.is_Unset() ) { // Propagate default from value branches TU_MATCHA( (m_branches), (e), @@ -2869,7 +2869,7 @@ namespace { // Terminal, no unify } } - + template<typename T> void unify_from_vals_range(::std::vector< ::std::pair<T, DecisionTreeNode::Branch>>& dst, const ::std::vector< ::std::pair<T, DecisionTreeNode::Branch>>& src) { @@ -2893,7 +2893,7 @@ namespace { } } } - + template<typename T> void unify_from_vals_pt(::std::vector< ::std::pair<T, DecisionTreeNode::Branch>>& dst, const ::std::vector< ::std::pair<T, DecisionTreeNode::Branch>>& src) { @@ -2915,9 +2915,9 @@ namespace { void DecisionTreeNode::unify_from(const Branch& b) { TRACE_FUNCTION_FR(*this << " with " << b, *this); - + assert( b.is_Terminal() || b.is_Subtree() ); - + if( m_default.is_Unset() ) { if( b.is_Terminal() ) { m_default = clone(b); @@ -2926,7 +2926,7 @@ void DecisionTreeNode::unify_from(const Branch& b) m_default = clone(b.as_Subtree()->m_default); } } - + if( b.is_Subtree() && b.as_Subtree()->m_branches.tag() != m_branches.tag() ) { // Is this a bug, or expected (and don't unify in?) DEBUG("TODO - Unify mismatched arms? - " << b.as_Subtree()->m_branches.tag_str() << " and " << m_branches.tag_str()); @@ -2936,7 +2936,7 @@ void DecisionTreeNode::unify_from(const Branch& b) //if( b.is_Subtree() ) { // ASSERT_BUG(Span(), this->m_field_path == b.as_Subtree()->m_field_path, "Unifiying DTNs with mismatched paths - " << this->m_field_path << " != " << b.as_Subtree()->m_field_path); //} - + TU_MATCHA( (m_branches), (dst), (Unset, if( b.is_Subtree() ) { @@ -2948,7 +2948,7 @@ void DecisionTreeNode::unify_from(const Branch& b) ), (Bool, auto* src = (b.is_Subtree() ? &b.as_Subtree()->m_branches.as_Bool() : nullptr); - + unify_branch( dst.false_branch, (src ? src->false_branch : b) ); unify_branch( dst.true_branch , (src ? src->true_branch : b) ); ), @@ -3020,7 +3020,7 @@ void DecisionTreeNode::unify_from(const Branch& b) if( should_unify_subtree ) { auto& sb = b.as_Subtree()->m_branches; ASSERT_BUG(Span(), sb.is_Slice(), "Unifying Slice with " << sb.tag_str()); - + const auto& src = sb.as_Slice(); unify_from_vals_pt(dst.fixed_arms, src.fixed_arms); } @@ -3113,7 +3113,7 @@ void DecisionTreeNode::unify_from(const Branch& b) } ) ) - + os << "* = " << x.m_default; os << " }"; return os; @@ -3132,13 +3132,13 @@ void DecisionTreeGen::generate_tree_code( ) { TRACE_FUNCTION_F("top_ty=" << top_ty << ", field_path_ofs=" << field_path_ofs << ", top_val=" << top_val << ", node=" << node); - + ::MIR::LValue val; ::HIR::TypeRef ty; - + get_ty_and_val(sp, m_builder.resolve(), top_ty, top_val, node.m_field_path, field_path_ofs, ty, val); DEBUG("ty = " << ty << ", val = " << val); - + TU_MATCHA( (ty.m_data), (e), (Infer, BUG(sp, "Ivar for in match type"); ), (Diverge, BUG(sp, "Diverge in match type"); ), @@ -3265,7 +3265,7 @@ void DecisionTreeGen::generate_branch(const DecisionTreeNode::Branch& branch, :: else { assert( branch.is_Subtree() ); const auto& subnode = *branch.as_Subtree(); - + cb(subnode); } } @@ -3279,16 +3279,16 @@ void DecisionTreeGen::generate_branches_Signed( ) { auto default_block = m_builder.new_bb_unlinked(); - + // TODO: Convert into an integer switch w/ offset instead of chained comparisons - + for( const auto& branch : branches ) { auto next_block = (&branch == &branches.back() ? default_block : m_builder.new_bb_unlinked()); - + auto val_start = m_builder.lvalue_or_temp(sp, ty, ::MIR::Constant(branch.first.start)); auto val_end = (branch.first.end == branch.first.start ? val_start.clone() : m_builder.lvalue_or_temp(sp, ty, ::MIR::Constant(branch.first.end))); - + auto cmp_gt_block = m_builder.new_bb_unlinked(); auto val_cmp_lt = m_builder.lvalue_or_temp(sp, ::HIR::TypeRef(::HIR::CoreType::Bool), ::MIR::RValue::make_BinOp({ val.clone(), ::MIR::eBinOp::LT, mv$(val_start) @@ -3300,14 +3300,14 @@ void DecisionTreeGen::generate_branches_Signed( val.clone(), ::MIR::eBinOp::GT, mv$(val_end) }) ); m_builder.end_block( ::MIR::Terminator::make_If({ mv$(val_cmp_gt), next_block, success_block }) ); - + m_builder.set_cur_block( success_block ); this->generate_branch(branch.second, and_then); - + m_builder.set_cur_block( next_block ); } assert( m_builder.block_active() ); - + if( default_branch.is_Unset() ) { // TODO: Emit error if non-exhaustive m_builder.end_block( ::MIR::Terminator::make_Diverge({}) ); @@ -3326,16 +3326,16 @@ void DecisionTreeGen::generate_branches_Unsigned( ) { auto default_block = m_builder.new_bb_unlinked(); - + // TODO: Convert into an integer switch w/ offset instead of chained comparisons - + for( const auto& branch : branches ) { auto next_block = (&branch == &branches.back() ? default_block : m_builder.new_bb_unlinked()); - + auto val_start = m_builder.lvalue_or_temp(sp, ty, ::MIR::Constant(branch.first.start)); auto val_end = (branch.first.end == branch.first.start ? val_start.clone() : m_builder.lvalue_or_temp(sp, ty, ::MIR::Constant(branch.first.end))); - + auto cmp_gt_block = m_builder.new_bb_unlinked(); auto val_cmp_lt = m_builder.lvalue_or_temp(sp, ::HIR::TypeRef(::HIR::CoreType::Bool), ::MIR::RValue::make_BinOp({ val.clone(), ::MIR::eBinOp::LT, mv$(val_start) @@ -3347,14 +3347,14 @@ void DecisionTreeGen::generate_branches_Unsigned( val.clone(), ::MIR::eBinOp::GT, mv$(val_end) }) ); m_builder.end_block( ::MIR::Terminator::make_If({ mv$(val_cmp_gt), next_block, success_block }) ); - + m_builder.set_cur_block( success_block ); this->generate_branch(branch.second, and_then); - + m_builder.set_cur_block( next_block ); } assert( m_builder.block_active() ); - + if( default_branch.is_Unset() ) { // TODO: Emit error if non-exhaustive m_builder.end_block( ::MIR::Terminator::make_Diverge({}) ); @@ -3373,14 +3373,14 @@ void DecisionTreeGen::generate_branches_Float( ) { auto default_block = m_builder.new_bb_unlinked(); - + for( const auto& branch : branches ) { auto next_block = (&branch == &branches.back() ? default_block : m_builder.new_bb_unlinked()); - + auto val_start = m_builder.lvalue_or_temp(sp, ty, ::MIR::Constant(branch.first.start)); auto val_end = (branch.first.end == branch.first.start ? val_start.clone() : m_builder.lvalue_or_temp(sp, ty, ::MIR::Constant(branch.first.end))); - + auto cmp_gt_block = m_builder.new_bb_unlinked(); auto val_cmp_lt = m_builder.lvalue_or_temp(sp, ::HIR::TypeRef(::HIR::CoreType::Bool), ::MIR::RValue::make_BinOp({ val.clone(), ::MIR::eBinOp::LT, mv$(val_start) @@ -3392,14 +3392,14 @@ void DecisionTreeGen::generate_branches_Float( val.clone(), ::MIR::eBinOp::GT, mv$(val_end) }) ); m_builder.end_block( ::MIR::Terminator::make_If({ mv$(val_cmp_gt), next_block, success_block }) ); - + m_builder.set_cur_block( success_block ); this->generate_branch(branch.second, and_then); - + m_builder.set_cur_block( next_block ); } assert( m_builder.block_active() ); - + if( default_branch.is_Unset() ) { ERROR(sp, E0000, "Match over floating point with no `_` arm"); } @@ -3417,16 +3417,16 @@ void DecisionTreeGen::generate_branches_Char( ) { auto default_block = m_builder.new_bb_unlinked(); - + // TODO: Convert into an integer switch w/ offset instead of chained comparisons - + for( const auto& branch : branches ) { auto next_block = (&branch == &branches.back() ? default_block : m_builder.new_bb_unlinked()); - + auto val_start = m_builder.lvalue_or_temp(sp, ty, ::MIR::Constant(branch.first.start)); auto val_end = (branch.first.end == branch.first.start ? val_start.clone() : m_builder.lvalue_or_temp(sp, ty, ::MIR::Constant(branch.first.end))); - + auto cmp_gt_block = m_builder.new_bb_unlinked(); auto val_cmp_lt = m_builder.lvalue_or_temp( sp, ::HIR::TypeRef(::HIR::CoreType::Bool), ::MIR::RValue::make_BinOp({ val.clone(), ::MIR::eBinOp::LT, mv$(val_start) @@ -3438,14 +3438,14 @@ void DecisionTreeGen::generate_branches_Char( val.clone(), ::MIR::eBinOp::GT, mv$(val_end) }) ); m_builder.end_block( ::MIR::Terminator::make_If({ mv$(val_cmp_gt), next_block, success_block }) ); - + m_builder.set_cur_block( success_block ); this->generate_branch(branch.second, and_then); - + m_builder.set_cur_block( next_block ); } assert( m_builder.block_active() ); - + if( default_branch.is_Unset() ) { // TODO: Error if not exhaustive. m_builder.end_block( ::MIR::Terminator::make_Diverge({}) ); @@ -3463,7 +3463,7 @@ void DecisionTreeGen::generate_branches_Bool( ) { //assert( ty.m_data.is_Boolean() ); - + if( default_branch.is_Unset() ) { if( branches.false_branch.is_Unset() || branches.true_branch.is_Unset() ) { @@ -3476,16 +3476,16 @@ void DecisionTreeGen::generate_branches_Bool( // Unreachable default (NOTE: Not an error here) } } - + // Emit an if based on the route taken auto bb_false = m_builder.new_bb_unlinked(); auto bb_true = m_builder.new_bb_unlinked(); m_builder.end_block( ::MIR::Terminator::make_If({ mv$(val), bb_true, bb_false }) ); - + // Recurse into sub-patterns const auto& branch_false = ( !branches.false_branch.is_Unset() ? branches.false_branch : default_branch ); const auto& branch_true = ( !branches. true_branch.is_Unset() ? branches. true_branch : default_branch ); - + m_builder.set_cur_block(bb_true ); this->generate_branch(branch_true , and_then); m_builder.set_cur_block(bb_false); @@ -3505,35 +3505,35 @@ void DecisionTreeGen::generate_branches_Borrow_str( // - rustc emits calls to PartialEq::eq for this and for slices. mrustc could use PartialOrd and fall back to PartialEq if unavaliable? // > Requires crate access here! - A memcmp call is probably better, probably via a binop // NOTE: The below implementation gets the final codegen to call memcmp on the strings by emitting eBinOp::{LT,GT} - + // - Remove the wrapping Deref (which must be there) ASSERT_BUG(sp, val.is_Deref(), "Match over str without a deref - " << val); auto tmp = mv$( *val.as_Deref().val ); val = mv$(tmp); - + auto default_bb = m_builder.new_bb_unlinked(); - + assert( !branches.empty() ); for(const auto& branch : branches) { auto have_val = val.clone(); - + auto next_bb = (&branch == &branches.back() ? default_bb : m_builder.new_bb_unlinked()); - + auto test_val = m_builder.lvalue_or_temp(sp, ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, ::HIR::CoreType::Str), ::MIR::Constant(branch.first) ); auto cmp_gt_bb = m_builder.new_bb_unlinked(); - + auto lt_val = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ have_val.clone(), ::MIR::eBinOp::LT, test_val.clone() }) ); m_builder.end_block( ::MIR::Terminator::make_If({ mv$(lt_val), default_bb, cmp_gt_bb }) ); m_builder.set_cur_block(cmp_gt_bb); - + auto eq_bb = m_builder.new_bb_unlinked(); auto gt_val = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ mv$(have_val), ::MIR::eBinOp::GT, test_val.clone() }) ); m_builder.end_block( ::MIR::Terminator::make_If({ mv$(gt_val), next_bb, eq_bb }) ); m_builder.set_cur_block(eq_bb); - + this->generate_branch(branch.second, and_then); - + m_builder.set_cur_block(next_bb); } this->generate_branch(default_branch, and_then); @@ -3553,7 +3553,7 @@ void DecisionTreeGen::generate_branches_Enum( const auto& variants = enum_ref.m_variants; auto variant_count = variants.size(); bool has_any = ! default_branch.is_Unset(); - + if( branches.size() < variant_count && ! has_any ) { ERROR(sp, E0000, "Non-exhaustive match over " << ty << " - " << branches.size() << " out of " << variant_count << " present"); } @@ -3561,9 +3561,9 @@ void DecisionTreeGen::generate_branches_Enum( //if( branches.size() == variant_count && has_any ) { // ERROR(sp, E0000, "Unreachable _ arm - " << branches.size() << " variants in " << enum_path); //} - + auto any_block = (has_any ? m_builder.new_bb_unlinked() : 0); - + // Emit a switch over the variant ::std::vector< ::MIR::BasicBlockId> variant_blocks; variant_blocks.reserve( variant_count ); @@ -3583,22 +3583,22 @@ void DecisionTreeGen::generate_branches_Enum( variant_blocks.resize( variant_count, any_block ); } bool any_arm_used = ::std::any_of( variant_blocks.begin(), variant_blocks.end(), [any_block](const auto& blk){ return blk == any_block; } ); - + m_builder.end_block( ::MIR::Terminator::make_Switch({ val.clone(), variant_blocks // NOTE: Copies the list, so it can be used lower down }) ); - + // Emit sub-patterns, looping over variants for( const auto& branch : branches ) { auto bb = variant_blocks[branch.first]; const auto& var = variants[branch.first]; DEBUG(branch.first << " " << var.first << " = " << branch.second); - + auto var_lval = ::MIR::LValue::make_Downcast({ box$(val.clone()), branch.first }); - + ::HIR::TypeRef fake_ty; - + TU_MATCHA( (var.second), (e), (Unit, DEBUG("- Unit"); @@ -3628,7 +3628,7 @@ void DecisionTreeGen::generate_branches_Enum( DEBUG("- Struct - " << fake_ty); ) ) - + m_builder.set_cur_block( bb ); if( fake_ty == ::HIR::TypeRef() || fake_ty.m_data.as_Tuple().size() == 0 ) { this->generate_branch(branch.second, and_then); @@ -3640,7 +3640,7 @@ void DecisionTreeGen::generate_branches_Enum( }); } } - + if( any_arm_used ) { DEBUG("_ = " << default_branch); @@ -3668,46 +3668,46 @@ void DecisionTreeGen::generate_branches_Slice( if( default_branch.is_Unset() ) { ERROR(sp, E0000, "Non-exhaustive match over " << ty); } - + // NOTE: Un-deref the slice ASSERT_BUG(sp, val.is_Deref(), "slice matches must be passed a deref"); auto tmp = mv$( *val.as_Deref().val ); val = mv$(tmp); - + auto any_block = m_builder.new_bb_unlinked(); - + // TODO: Select one of three ways of picking the arm: // - Integer switch (unimplemented) // - Binary search // - Sequential comparisons - + auto val_len = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ val.clone() })); - + // TODO: Binary search instead. for( const auto& branch : branches.fixed_arms ) { auto val_des = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::Constant(static_cast<uint64_t>(branch.first))); - + // Special case - final just does equality if( &branch == &branches.fixed_arms.back() ) { auto val_cmp_eq = m_builder.lvalue_or_temp( sp, ::HIR::TypeRef(::HIR::CoreType::Bool), ::MIR::RValue::make_BinOp({ val_len.clone(), ::MIR::eBinOp::EQ, mv$(val_des) }) ); - + auto success_block = m_builder.new_bb_unlinked(); m_builder.end_block( ::MIR::Terminator::make_If({ mv$(val_cmp_eq), any_block, success_block }) ); - + m_builder.set_cur_block( success_block ); this->generate_branch(branch.second, and_then); - + m_builder.set_cur_block( any_block ); } // TODO: Special case for zero (which can't have a LT) else { auto next_block = m_builder.new_bb_unlinked(); - + auto cmp_gt_block = m_builder.new_bb_unlinked(); auto val_cmp_lt = m_builder.lvalue_or_temp( sp, ::HIR::TypeRef(::HIR::CoreType::Bool), ::MIR::RValue::make_BinOp({ val_len.clone(), ::MIR::eBinOp::LT, val_des.clone() @@ -3719,15 +3719,15 @@ void DecisionTreeGen::generate_branches_Slice( val_len.clone(), ::MIR::eBinOp::GT, mv$(val_des) }) ); m_builder.end_block( ::MIR::Terminator::make_If({ mv$(val_cmp_gt), next_block, success_block }) ); - + m_builder.set_cur_block( success_block ); this->generate_branch(branch.second, and_then); - + m_builder.set_cur_block( next_block ); } } assert( m_builder.block_active() ); - + if( default_branch.is_Unset() ) { // TODO: Emit error if non-exhaustive m_builder.end_block( ::MIR::Terminator::make_Diverge({}) ); diff --git a/src/mir/helpers.cpp b/src/mir/helpers.cpp index dc149cd2..027c68b7 100644 --- a/src/mir/helpers.cpp +++ b/src/mir/helpers.cpp @@ -206,7 +206,7 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c MIR_ASSERT(*this, e.variant_index < unm.m_variants.size(), "Variant index out of range"); const auto& variant = unm.m_variants[e.variant_index]; const auto& var_ty = variant.second.ent; - + if( monomorphise_type_needed(var_ty) ) { tmp = monomorphise_type(sp, unm.m_params, te.path.m_data.as_Generic().m_params, variant.second.ent); m_resolve.expand_associated_types(sp, tmp); diff --git a/src/mir/helpers.hpp b/src/mir/helpers.hpp index b0499ec8..40dbd4a3 100644 --- a/src/mir/helpers.hpp +++ b/src/mir/helpers.hpp @@ -40,7 +40,7 @@ public: typedef ::std::vector< ::std::pair< ::HIR::Pattern, ::HIR::TypeRef> > args_t; private: const unsigned int STMT_TERM = ~0u; - + public: const Span& sp; const ::StaticTraitResolve& m_resolve; @@ -51,7 +51,7 @@ private: const args_t& m_args; const ::MIR::Function& m_fcn; const ::HIR::SimplePath* m_lang_Box = nullptr; - + unsigned int bb_idx = 0; unsigned int stmt_idx = 0; @@ -69,7 +69,7 @@ public: m_lang_Box = &m_crate.m_lang_items.at("owned_box"); } } - + void set_cur_stmt(unsigned int bb_idx, unsigned int stmt_idx) { this->bb_idx = bb_idx; this->stmt_idx = stmt_idx; @@ -78,7 +78,7 @@ public: this->bb_idx = bb_idx; this->stmt_idx = STMT_TERM; } - + void print_bug(::std::function<void(::std::ostream& os)> cb) const { print_msg("ERROR", cb); } @@ -86,12 +86,12 @@ public: print_msg("TODO", cb); } void print_msg(const char* tag, ::std::function<void(::std::ostream& os)> cb) const; - + 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* is_type_owned_box(const ::HIR::TypeRef& ty) const; }; diff --git a/src/mir/mir.cpp b/src/mir/mir.cpp index d7ae41cc..f7a5f3e8 100644 --- a/src/mir/mir.cpp +++ b/src/mir/mir.cpp @@ -50,7 +50,7 @@ namespace MIR { ) return os; } - + ::std::ostream& operator<<(::std::ostream& os, const LValue& x) { TU_MATCHA( (x), (e), @@ -116,13 +116,13 @@ namespace MIR { case ::MIR::eBinOp::SUB_OV: os << "SUB_OV"; break; case ::MIR::eBinOp::MUL_OV: os << "MUL_OV"; break; case ::MIR::eBinOp::DIV_OV: os << "DIV_OV"; break; - + case ::MIR::eBinOp::BIT_OR : os << "BIT_OR" ; break; case ::MIR::eBinOp::BIT_AND: os << "BIT_AND"; break; case ::MIR::eBinOp::BIT_XOR: os << "BIT_XOR"; break; case ::MIR::eBinOp::BIT_SHL: os << "BIT_SHL"; break; case ::MIR::eBinOp::BIT_SHR: os << "BIT_SHR"; break; - + case ::MIR::eBinOp::EQ: os << "EQ"; break; case ::MIR::eBinOp::NE: os << "NE"; break; case ::MIR::eBinOp::GT: os << "GT"; break; @@ -159,7 +159,7 @@ namespace MIR { ) return os; } - + ::std::ostream& operator<<(::std::ostream& os, const Terminator& x) { TU_MATCHA( (x), (e), diff --git a/src/mir/mir.hpp b/src/mir/mir.hpp index 1ac8ff78..5a6b83de 100644 --- a/src/mir/mir.hpp +++ b/src/mir/mir.hpp @@ -66,14 +66,14 @@ enum class eBinOp MUL, MUL_OV, DIV, DIV_OV, MOD,// MOD_OV, - + BIT_OR, BIT_AND, BIT_XOR, - + BIT_SHR, BIT_SHL, - + EQ, NE, GT, GE, LT, LE, @@ -222,7 +222,7 @@ class Function public: ::std::vector< ::HIR::TypeRef> named_variables; ::std::vector< ::HIR::TypeRef> temporaries; - + ::std::vector<BasicBlock> blocks; }; diff --git a/src/mir/mir_builder.cpp b/src/mir/mir_builder.cpp index 367c4aa1..cd7ddbcd 100644 --- a/src/mir/mir_builder.cpp +++ b/src/mir/mir_builder.cpp @@ -24,14 +24,14 @@ MirBuilder::MirBuilder(const Span& sp, const StaticTraitResolve& resolve, const if( resolve.m_crate.m_lang_items.count("owned_box") > 0 ) { m_lang_Box = &resolve.m_crate.m_lang_items.at("owned_box"); } - + set_cur_block( new_bb_unlinked() ); m_scopes.push_back( ScopeDef { sp } ); m_scope_stack.push_back( 0 ); - + m_scopes.push_back( ScopeDef { sp, ScopeType::make_Temporaries({}) } ); m_scope_stack.push_back( 1 ); - + m_variable_states.resize( output.named_variables.size(), VarState::Uninit ); } MirBuilder::~MirBuilder() @@ -57,12 +57,12 @@ const ::HIR::TypeRef* MirBuilder::is_type_owned_box(const ::HIR::TypeRef& ty) co return nullptr; } const auto& te = ty.m_data.as_Path(); - + if( ! te.path.m_data.is_Generic() ) { return nullptr; } const auto& pe = te.path.m_data.as_Generic(); - + if( pe.m_path != *m_lang_Box ) { return nullptr; } @@ -101,11 +101,11 @@ void MirBuilder::define_variable(unsigned int idx) { unsigned int rv = m_output.temporaries.size(); DEBUG("DEFINE tmp" << rv << ": " << ty); - + m_output.temporaries.push_back( ty.clone() ); m_temporary_states.push_back( VarState::Uninit ); assert(m_output.temporaries.size() == m_temporary_states.size()); - + ScopeDef* top_scope = nullptr; for(unsigned int i = m_scope_stack.size(); i --; ) { @@ -179,7 +179,7 @@ void MirBuilder::push_stmt_assign(const Span& sp, ::MIR::LValue dst, ::MIR::RVal 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, ""); - + TU_MATCHA( (val), (e), (Use, this->moved_lvalue(sp, e); @@ -248,7 +248,7 @@ void MirBuilder::push_stmt_assign(const Span& sp, ::MIR::LValue dst, ::MIR::RVal this->moved_lvalue(sp, val); ) ) - + // Drop target if populated mark_value_assigned(sp, dst); m_output.blocks.at(m_current_block).statements.push_back( ::MIR::Statement::make_Assign({ mv$(dst), mv$(val) }) ); @@ -257,25 +257,25 @@ void MirBuilder::push_stmt_drop(const Span& sp, ::MIR::LValue val) { 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 return ; } - + m_output.blocks.at(m_current_block).statements.push_back( ::MIR::Statement::make_Drop({ ::MIR::eDropKind::DEEP, mv$(val) }) ); } void MirBuilder::push_stmt_drop_shallow(const Span& sp, ::MIR::LValue val) { 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 //if( lvalue_is_copy(sp, val) ) { // // Don't emit a drop for Copy values // return ; //} - + m_output.blocks.at(m_current_block).statements.push_back( ::MIR::Statement::make_Drop({ ::MIR::eDropKind::SHALLOW, mv$(val) }) ); } @@ -353,7 +353,7 @@ void MirBuilder::raise_variables(const Span& sp, const ::MIR::LValue& val) while( scope_it != m_scope_stack.rend() ) { auto& scope_def = m_scopes.at(*scope_it); - + TU_IFLET( ScopeType, scope_def.data, Variables, e, auto tmp_it = ::std::find( e.vars.begin(), e.vars.end(), idx ); if( tmp_it != e.vars.end() ) @@ -371,11 +371,11 @@ void MirBuilder::raise_variables(const Span& sp, const ::MIR::LValue& val) return ; } ++scope_it; - + while( scope_it != m_scope_stack.rend() ) { auto& scope_def = m_scopes.at(*scope_it); - + TU_IFLET( ScopeType, scope_def.data, Variables, e, e.vars.push_back( idx ); DEBUG("- to " << *scope_it); @@ -383,7 +383,7 @@ void MirBuilder::raise_variables(const Span& sp, const ::MIR::LValue& val) ) ++scope_it; } - + DEBUG("- top"); ), (Temporary, @@ -392,7 +392,7 @@ void MirBuilder::raise_variables(const Span& sp, const ::MIR::LValue& val) while( scope_it != m_scope_stack.rend() ) { auto& scope_def = m_scopes.at(*scope_it); - + TU_IFLET( ScopeType, scope_def.data, Temporaries, e, auto tmp_it = ::std::find( e.temporaries.begin(), e.temporaries.end(), idx ); if( tmp_it != e.temporaries.end() ) @@ -410,11 +410,11 @@ void MirBuilder::raise_variables(const Span& sp, const ::MIR::LValue& val) return ; } ++scope_it; - + while( scope_it != m_scope_stack.rend() ) { auto& scope_def = m_scopes.at(*scope_it); - + TU_IFLET( ScopeType, scope_def.data, Temporaries, e, e.temporaries.push_back( idx ); DEBUG("- to " << *scope_it); @@ -422,7 +422,7 @@ void MirBuilder::raise_variables(const Span& sp, const ::MIR::LValue& val) ) ++scope_it; } - + DEBUG("- top"); ) ) @@ -571,42 +571,42 @@ void MirBuilder::terminate_scope(const Span& sp, ScopeHandle scope, bool emit_cl BUG(sp, "Terminating scope not on the stack - scope " << scope.idx); BUG(sp, "Terminating scope " << scope.idx << " when not at top of stack, " << (m_scope_stack.end() - it - 1) << " scopes in the way"); } - + auto& scope_def = m_scopes.at(scope.idx); ASSERT_BUG( sp, scope_def.complete == false, "Terminating scope which is already terminated" ); - + if( emit_cleanup ) { // 2. Emit drops for all non-moved variables (share with below) drop_scope_values(scope_def); } - + // 3. Pop scope (last because `drop_scope_values` uses the stack) m_scope_stack.pop_back(); - + complete_scope(scope_def); } void MirBuilder::terminate_scope_early(const Span& sp, const ScopeHandle& scope) { DEBUG("EARLY scope " << scope.idx); - + // 1. Ensure that this block is in the stack auto it = ::std::find( m_scope_stack.begin(), m_scope_stack.end(), scope.idx ); if( it == m_scope_stack.end() ) { BUG(sp, "Early-terminating scope not on the stack"); } unsigned int slot = it - m_scope_stack.begin(); - + bool is_conditional = false; for(unsigned int i = m_scope_stack.size(); i-- > slot; ) { auto idx = m_scope_stack[i]; auto& scope_def = m_scopes.at( idx ); - + // If a conditional block is hit, prevent full termination of the rest if( scope_def.data.is_Split() || scope_def.data.is_Loop() ) is_conditional = true; - + if( !is_conditional ) { DEBUG("Complete scope " << idx); drop_scope_values(scope_def); @@ -616,7 +616,7 @@ void MirBuilder::terminate_scope_early(const Span& sp, const ScopeHandle& scope) else { // Mark patial within this scope? DEBUG("Drop part of scope " << idx); - + // Emit drops for dropped values within this scope drop_scope_values(scope_def); // Inform the scope that it's been early-exited @@ -633,9 +633,9 @@ void MirBuilder::end_split_arm(const Span& sp, const ScopeHandle& handle, bool r ASSERT_BUG(sp, sd.data.is_Split(), ""); auto& sd_split = sd.data.as_Split(); ASSERT_BUG(sp, !sd_split.arms.empty(), ""); - + sd_split.arms.back().always_early_terminated = /*sd_split.arms.back().has_early_terminated &&*/ !reachable; - + // HACK: If this arm's end is reachable, convert InnerMoved (shallow drop) variable states to Moved // - I'm not 100% sure this is the correct place for calling drop. if( reachable ) @@ -651,7 +651,7 @@ void MirBuilder::end_split_arm(const Span& sp, const ScopeHandle& handle, bool r } } } - + sd_split.arms.push_back( {} ); } void MirBuilder::end_split_arm_early(const Span& sp) @@ -666,13 +666,13 @@ void MirBuilder::end_split_arm_early(const Span& sp) m_scope_stack.pop_back(); complete_scope(scope_def); } - + if( !m_scope_stack.empty() && m_scopes.at( m_scope_stack.back() ).data.is_Split() ) { auto& sd = m_scopes[ m_scope_stack.back() ]; auto& sd_split = sd.data.as_Split(); sd_split.arms.back().has_early_terminated = true; - + const auto& vss = sd_split.arms.back().var_states; for(unsigned int i = 0; i < vss.size(); i ++ ) { @@ -688,7 +688,7 @@ void MirBuilder::end_split_arm_early(const Span& sp) void MirBuilder::complete_scope(ScopeDef& sd) { sd.complete = true; - + TU_MATCHA( (sd.data), (e), (Temporaries, DEBUG("Temporaries " << e.temporaries); @@ -702,16 +702,16 @@ void MirBuilder::complete_scope(ScopeDef& sd) (Split, ) ) - + // No macro for better debug output. if( sd.data.is_Split() ) { auto& e = sd.data.as_Split(); - + assert( e.arms.size() > 1 ); TRACE_FUNCTION_F("Split - " << (e.arms.size() - 1) << " arms"); e.arms.pop_back(); - + // Merge all arms and apply upwards size_t var_count = 0; size_t tmp_count = 0; @@ -720,18 +720,18 @@ void MirBuilder::complete_scope(ScopeDef& sd) var_count = ::std::max(var_count, arm.var_states.size()); tmp_count = ::std::max(tmp_count, arm.tmp_states.size()); } - + struct StateMerger { ::std::vector<bool> m_changed; ::std::vector<VarState> m_new_states; - + StateMerger(size_t var_count): m_changed(var_count), m_new_states(var_count) { } - + void merge_arm_state(const Span& sp, unsigned int i, bool has_changed, VarState new_state) { assert(i < this->m_new_states.size()); @@ -828,7 +828,7 @@ void MirBuilder::complete_scope(ScopeDef& sd) } } }; - + StateMerger sm_var { var_count }; StateMerger sm_tmp { tmp_count }; for(const auto& arm : e.arms) @@ -841,7 +841,7 @@ void MirBuilder::complete_scope(ScopeDef& sd) { sm_var.merge_arm_state(sd.span, i, arm.changed_var_states[i], arm.var_states[i]); } - + DEBUG(">TMP<"); assert( arm.changed_tmp_states.size() == arm.tmp_states.size() ); for(unsigned int i = 0; i < arm.tmp_states.size(); i ++ ) @@ -849,7 +849,7 @@ void MirBuilder::complete_scope(ScopeDef& sd) sm_tmp.merge_arm_state(sd.span, i, arm.changed_tmp_states[i], arm.tmp_states[i]); } } - + for(unsigned int i = 0; i < var_count; i ++ ) { if( sm_var.m_changed[i] ) @@ -1083,7 +1083,7 @@ VarState MirBuilder::get_variable_state(const Span& sp, unsigned int idx) const ) ) } - + ASSERT_BUG(sp, idx < m_variable_states.size(), "Variable " << idx << " out of range for state table"); return m_variable_states[idx]; } @@ -1114,7 +1114,7 @@ void MirBuilder::set_variable_state(const Span& sp, unsigned int idx, VarState s ) ) } - + ASSERT_BUG(sp, idx < m_variable_states.size(), "Variable " << idx << " out of range for state table"); m_variable_states[idx] = state; } @@ -1142,7 +1142,7 @@ VarState MirBuilder::get_temp_state(const Span& sp, unsigned int idx) const } } } - + ASSERT_BUG(sp, idx < m_temporary_states.size(), "Temporary " << idx << " out of range for state table"); return m_temporary_states[idx]; } @@ -1173,7 +1173,7 @@ void MirBuilder::set_temp_state(const Span& sp, unsigned int idx, VarState state return ; } } - + ASSERT_BUG(sp, idx < m_temporary_states.size(), "Temporary " << idx << " out of range for state table"); m_temporary_states[idx] = state; } diff --git a/src/mir/mir_ptr.hpp b/src/mir/mir_ptr.hpp index 583b155b..9133dd44 100644 --- a/src/mir/mir_ptr.hpp +++ b/src/mir/mir_ptr.hpp @@ -19,7 +19,7 @@ public: FunctionPointer(): ptr(nullptr) {} FunctionPointer(::MIR::Function* p): ptr(p) {} FunctionPointer(FunctionPointer&& x): ptr(x.ptr) { x.ptr = nullptr; } - + ~FunctionPointer() { reset(); } @@ -29,14 +29,14 @@ public: x.ptr = nullptr; return *this; } - + 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; } - + operator bool() const { return ptr != nullptr; } }; diff --git a/src/mir/optimise.cpp b/src/mir/optimise.cpp index 601b1b18..bb9536b0 100644 --- a/src/mir/optimise.cpp +++ b/src/mir/optimise.cpp @@ -31,7 +31,7 @@ namespace { // Make sure we don't infinite loop if( bb == target.terminator.as_Goto() ) return bb; - + auto rv = get_new_target(state, target.terminator.as_Goto()); DEBUG(bb << " => " << rv); return rv; @@ -44,7 +44,7 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path static Span sp; TRACE_FUNCTION_F(path); ::MIR::TypeResolve state { sp, resolve, FMT_CB(ss, ss << path;), ret_type, args, fcn }; - + // >> Replace targets that point to a block that is just a goto for(auto& block : fcn.blocks) { @@ -74,7 +74,7 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path ) ) } - + // >> Merge blocks where a block goto-s to a single-use block. { ::std::vector<unsigned int> uses( fcn.blocks.size() ); @@ -106,7 +106,7 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path ) ) } - + unsigned int i = 0; for(auto& block : fcn.blocks) { @@ -116,9 +116,9 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path if( uses[tgt] != 1 ) break ; DEBUG("Append bb " << tgt << " to bb" << i); - + assert( &fcn.blocks[tgt] != &block ); - + for(auto& stmt : fcn.blocks[tgt].statements) block.statements.push_back( mv$(stmt) ); block.terminator = mv$( fcn.blocks[tgt].terminator ); @@ -126,17 +126,17 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path i ++; } } - + // >> Combine Duplicate Blocks // TODO: - + // >> Propagate dead assignments // TODO: This requires kowing that doing so has no effect. // - Can use little heristics like a Call pointing to an assignment of its RV // - Count the read/write count of a variable, if it's 1,1 then this optimisation is correct. // - If the count is read=*,write=1 and the write is of an argument, replace with the argument. - + // GC pass on blocks and variables // - Find unused blocks, then delete and rewrite all references. { @@ -147,7 +147,7 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path { auto bb = to_visit.back(); to_visit.pop_back(); visited[bb] = true; - + const auto& block = fcn.blocks[bb]; TU_MATCHA( (block.terminator), (e), (Incomplete, @@ -181,7 +181,7 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path ) ) } - + ::std::vector<unsigned int> rewrite_table; for(unsigned int i = 0, j = 0; i < fcn.blocks.size(); i ++) { @@ -192,7 +192,7 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path rewrite_table.push_back(~0u); } } - + auto it = fcn.blocks.begin(); for(unsigned int i = 0; i < visited.size(); i ++) { @@ -230,7 +230,7 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path e.panic_block = rewrite_table[e.panic_block]; ) ) - + ++it; } } diff --git a/src/mir/visit_crate_mir.cpp b/src/mir/visit_crate_mir.cpp index 4cd1fddc..ba4acf8e 100644 --- a/src/mir/visit_crate_mir.cpp +++ b/src/mir/visit_crate_mir.cpp @@ -36,7 +36,7 @@ void MIR::OuterVisitor::visit_function(::HIR::ItemPath p, ::HIR::Function& item) DEBUG("Function code " << p); // TODO: Get span without needing hir/expr.hpp static Span sp; - + // Replace ErasedType instances in `ret_type` const auto& ret_type = item.m_return; auto ret_type_v = clone_ty_with(sp, ret_type, [&](const auto& tpl, auto& rv) { @@ -71,10 +71,10 @@ void MIR::OuterVisitor::visit_constant(::HIR::ItemPath p, ::HIR::Constant& item) void MIR::OuterVisitor::visit_enum(::HIR::ItemPath p, ::HIR::Enum& item) { auto _ = this->m_resolve.set_item_generics(item.m_params); - + // TODO: Use a different type depding on repr() auto enum_type = ::HIR::TypeRef(::HIR::CoreType::Isize); - + for(auto& var : item.m_variants) { TU_IFLET(::HIR::Enum::Variant, var.second, Value, e, diff --git a/src/mir/visit_crate_mir.hpp b/src/mir/visit_crate_mir.hpp index e6964545..d01f5ab3 100644 --- a/src/mir/visit_crate_mir.hpp +++ b/src/mir/visit_crate_mir.hpp @@ -24,9 +24,9 @@ public: m_resolve(crate), m_cb(cb) {} - + void visit_expr(::HIR::ExprPtr& exp) override; - + void visit_type(::HIR::TypeRef& ty) override; // ------ @@ -36,7 +36,7 @@ public: void visit_static(::HIR::ItemPath p, ::HIR::Static& item) override; void visit_constant(::HIR::ItemPath p, ::HIR::Constant& item) override; void visit_enum(::HIR::ItemPath p, ::HIR::Enum& item) override; - + // Boilerplate void visit_trait(::HIR::ItemPath p, ::HIR::Trait& item) override; void visit_type_impl(::HIR::TypeImpl& impl) override; diff --git a/src/parse/common.hpp b/src/parse/common.hpp index 57d6f24d..613290f2 100644 --- a/src/parse/common.hpp +++ b/src/parse/common.hpp @@ -1,70 +1,70 @@ -/*
- * MRustC - Rust Compiler
- * - By John Hodge (Mutabah/thePowersGang)
- *
- * parse/common.hpp
- * - Common definitions used by the parser
- */
-#ifndef PARSE_COMMON_HPP_INCLUDED
-#define PARSE_COMMON_HPP_INCLUDED
-#include <iostream>
-#include "tokenstream.hpp"
-#include "../ast/ast.hpp"
-
-#define GET_TOK(tok, lex) ((tok = lex.getToken()).type())
-#define PUTBACK(tok, lex) lex.putback( ::std::move(tok) )
-#define LOOK_AHEAD(lex) (lex.lookahead(0))
-#define GET_CHECK_TOK(tok, lex, exp) do {\
- if((tok = lex.getToken()).type() != exp) { \
- DEBUG("GET_CHECK_TOK " << __FILE__ << ":" << __LINE__); \
- throw ParseError::Unexpected(lex, tok, Token(exp));\
- }\
-} while(0)
-#define CHECK_TOK(tok, exp) do {\
- if(tok.type() != exp) { \
- DEBUG("CHECK_TOK " << __FILE__ << ":" << __LINE__); \
- throw ParseError::Unexpected(lex, tok, Token(exp));\
- } \
-} while(0)
-
-// --- path.cpp
-enum eParsePathGenericMode
-{
- PATH_GENERIC_NONE,
- PATH_GENERIC_EXPR,
- PATH_GENERIC_TYPE
-};
-extern AST::Path Parse_Path(TokenStream& lex, eParsePathGenericMode generic_mode); // Auto-determines
-extern AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generic_mode);
-extern ::std::vector<AST::PathNode> Parse_PathNodes(TokenStream& lex, eParsePathGenericMode generic_mode);
-extern AST::PathParams Parse_Path_GenericList(TokenStream& lex);
-
-
-extern ::std::vector< ::std::string> Parse_HRB(TokenStream& lex);
-extern AST::MetaItem Parse_MetaItem(TokenStream& lex);
-extern ::AST::MacroInvocation Parse_MacroInvocation(ProtoSpan ps, ::std::string name, TokenStream& lex);
-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 void Parse_Mod_Item(TokenStream& lex, AST::Module& mod, AST::MetaItems 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::MetaItems meta_items);
-extern void Parse_ModRoot_Items(TokenStream& lex, AST::Module& mod);
-
-
-extern AST::Expr Parse_Expr(TokenStream& lex);
-extern AST::Expr Parse_ExprBlock(TokenStream& lex);
-extern AST::ExprNodeP Parse_Expr0(TokenStream& lex);
-extern AST::ExprNodeP Parse_ExprVal(TokenStream& lex);
-extern AST::ExprNodeP Parse_ExprBlockNode(TokenStream& lex, bool is_unsafe=false);
-extern AST::ExprNodeP Parse_ExprBlockLine(TokenStream& lex, bool *add_silence);
-extern AST::ExprNodeP Parse_ExprBlockLine_WithItems(TokenStream& lex, ::std::shared_ptr<AST::Module>& local_mod, bool& add_silence_if_end);
-extern AST::ExprNodeP Parse_Stmt(TokenStream& lex);
-
-// unwrapped = Exclude the enclosing brackets (used by macro parse code)
-extern TokenTree Parse_TT(TokenStream& lex, bool unwrapped);
-
-
-extern bool Parse_IsTokValue(eTokenType tok_type);
-
-#endif // PARSE_COMMON_HPP_INCLUDED
+/* + * MRustC - Rust Compiler + * - By John Hodge (Mutabah/thePowersGang) + * + * parse/common.hpp + * - Common definitions used by the parser + */ +#ifndef PARSE_COMMON_HPP_INCLUDED +#define PARSE_COMMON_HPP_INCLUDED +#include <iostream> +#include "tokenstream.hpp" +#include "../ast/ast.hpp" + +#define GET_TOK(tok, lex) ((tok = lex.getToken()).type()) +#define PUTBACK(tok, lex) lex.putback( ::std::move(tok) ) +#define LOOK_AHEAD(lex) (lex.lookahead(0)) +#define GET_CHECK_TOK(tok, lex, exp) do {\ + if((tok = lex.getToken()).type() != exp) { \ + DEBUG("GET_CHECK_TOK " << __FILE__ << ":" << __LINE__); \ + throw ParseError::Unexpected(lex, tok, Token(exp));\ + }\ +} while(0) +#define CHECK_TOK(tok, exp) do {\ + if(tok.type() != exp) { \ + DEBUG("CHECK_TOK " << __FILE__ << ":" << __LINE__); \ + throw ParseError::Unexpected(lex, tok, Token(exp));\ + } \ +} while(0) + +// --- path.cpp +enum eParsePathGenericMode +{ + PATH_GENERIC_NONE, + PATH_GENERIC_EXPR, + PATH_GENERIC_TYPE +}; +extern AST::Path Parse_Path(TokenStream& lex, eParsePathGenericMode generic_mode); // Auto-determines +extern AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generic_mode); +extern ::std::vector<AST::PathNode> Parse_PathNodes(TokenStream& lex, eParsePathGenericMode generic_mode); +extern AST::PathParams Parse_Path_GenericList(TokenStream& lex); + + +extern ::std::vector< ::std::string> Parse_HRB(TokenStream& lex); +extern AST::MetaItem Parse_MetaItem(TokenStream& lex); +extern ::AST::MacroInvocation Parse_MacroInvocation(ProtoSpan ps, ::std::string name, TokenStream& lex); +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 void Parse_Mod_Item(TokenStream& lex, AST::Module& mod, AST::MetaItems 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::MetaItems meta_items); +extern void Parse_ModRoot_Items(TokenStream& lex, AST::Module& mod); + + +extern AST::Expr Parse_Expr(TokenStream& lex); +extern AST::Expr Parse_ExprBlock(TokenStream& lex); +extern AST::ExprNodeP Parse_Expr0(TokenStream& lex); +extern AST::ExprNodeP Parse_ExprVal(TokenStream& lex); +extern AST::ExprNodeP Parse_ExprBlockNode(TokenStream& lex, bool is_unsafe=false); +extern AST::ExprNodeP Parse_ExprBlockLine(TokenStream& lex, bool *add_silence); +extern AST::ExprNodeP Parse_ExprBlockLine_WithItems(TokenStream& lex, ::std::shared_ptr<AST::Module>& local_mod, bool& add_silence_if_end); +extern AST::ExprNodeP Parse_Stmt(TokenStream& lex); + +// unwrapped = Exclude the enclosing brackets (used by macro parse code) +extern TokenTree Parse_TT(TokenStream& lex, bool unwrapped); + + +extern bool Parse_IsTokValue(eTokenType tok_type); + +#endif // PARSE_COMMON_HPP_INCLUDED diff --git a/src/parse/expr.cpp b/src/parse/expr.cpp index c71d2b4a..eb82bae7 100644 --- a/src/parse/expr.cpp +++ b/src/parse/expr.cpp @@ -1,1301 +1,1301 @@ -/*
- * MRustC - Rust Compiler
- * - By John Hodge (Mutabah/thePowersGang)
- *
- * parse/expr.cpp
- * - Expression (i.e. code) parsing
- *
- * Start points:
- * - Parse_ExprBlockNode : Parses a block
- * - Parse_Stmt : Parse a single statement
- * - Parse_Expr0 : Parse a single expression
- */
-#include "parseerror.hpp"
-#include <ast/ast.hpp>
-#include <ast/expr.hpp>
-#include "common.hpp"
-#include <iostream>
-#include "tokentree.hpp"
-#include "interpolated_fragment.hpp"
-
-using AST::ExprNode;
-using AST::ExprNodeP;
-static inline ExprNodeP mk_exprnodep(const TokenStream& lex, AST::ExprNode* en){en->set_pos(lex.getPosition()); return ExprNodeP(en); }
-#define NEWNODE(type, ...) mk_exprnodep(lex, new type(__VA_ARGS__))
-
-//ExprNodeP Parse_ExprBlockNode(TokenStream& lex, bool is_unsafe=false); // common.hpp
-//ExprNodeP Parse_ExprBlockLine_WithItems(TokenStream& lex, ::std::shared_ptr<AST::Module>& local_mod, bool& add_silence_if_end);
-//ExprNodeP Parse_ExprBlockLine(TokenStream& lex, bool *add_silence);
-ExprNodeP Parse_ExprBlockLine_Stmt(TokenStream& lex, bool& has_semicolon);
-//ExprNodeP Parse_Stmt(TokenStream& lex); // common.hpp
-ExprNodeP Parse_Stmt_Let(TokenStream& lex);
-ExprNodeP Parse_Expr0(TokenStream& lex);
-ExprNodeP Parse_IfStmt(TokenStream& lex);
-ExprNodeP Parse_WhileStmt(TokenStream& lex, ::std::string lifetime);
-ExprNodeP Parse_ForStmt(TokenStream& lex, ::std::string lifetime);
-ExprNodeP Parse_Expr_Match(TokenStream& lex);
-ExprNodeP Parse_Expr1(TokenStream& lex);
-ExprNodeP Parse_ExprMacro(TokenStream& lex, Token tok);
-
-AST::Expr Parse_Expr(TokenStream& lex)
-{
- return ::AST::Expr( Parse_Expr0(lex) );
-}
-
-AST::Expr Parse_ExprBlock(TokenStream& lex)
-{
- return ::AST::Expr( Parse_ExprBlockNode(lex) );
-}
-
-ExprNodeP Parse_ExprBlockNode(TokenStream& lex, bool is_unsafe/*=false*/)
-{
- TRACE_FUNCTION;
- Token tok;
-
- bool yields_final_value = true;
- ::std::vector<ExprNodeP> nodes;
-
- ::std::shared_ptr<AST::Module> local_mod;
-
- GET_CHECK_TOK(tok, lex, TOK_BRACE_OPEN);
-
- while( LOOK_AHEAD(lex) != TOK_BRACE_CLOSE )
- {
- DEBUG("tok = " << tok);
-
- // NOTE: Doc comments can appear within a function and apply to the function
- // TODO: Use these attributes
- while( GET_TOK(tok, lex) == TOK_CATTR_OPEN )
- {
- /*node_attrs.push_back(*/ Parse_MetaItem(lex) /*)*/;
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- }
- PUTBACK(tok, lex);
- if( LOOK_AHEAD(lex) == TOK_BRACE_CLOSE )
- break;
-
- bool add_silence_if_end = false;
- auto rv = Parse_ExprBlockLine_WithItems(lex, local_mod, add_silence_if_end);
- if( rv )
- {
- // Set to TRUE if there was no semicolon after a statement
- if( LOOK_AHEAD(lex) == TOK_BRACE_CLOSE && add_silence_if_end )
- {
- DEBUG("End of block, and add_silence_if_end == true - doesn't yeild");
- yields_final_value = false;
- // Since the next token is TOK_BRACE_CLOSE, the loop will terminate
- }
- nodes.push_back( mv$(rv) );
- }
- else {
- assert( !add_silence_if_end );
- }
- }
- GET_CHECK_TOK(tok, lex, TOK_BRACE_CLOSE);
-
- return NEWNODE( AST::ExprNode_Block, is_unsafe, yields_final_value, mv$(nodes), mv$(local_mod) );
-}
-
-/// Parse a single line in a block, handling items added to the local module
-///
-/// - If an item was parsed, this returns an empty ExprNodeP
-ExprNodeP Parse_ExprBlockLine_WithItems(TokenStream& lex, ::std::shared_ptr<AST::Module>& local_mod, bool& add_silence_if_end)
-{
- Token tok;
-
- AST::MetaItems item_attrs;
- while( GET_TOK(tok, lex) == TOK_ATTR_OPEN )
- {
- item_attrs.push_back( Parse_MetaItem(lex) );
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- }
-
- switch(tok.type())
- {
- // Items:
- case TOK_RWORD_PUB:
- // NOTE: Allowed, but doesn't do much
- case TOK_RWORD_TYPE:
- case TOK_RWORD_USE:
- case TOK_RWORD_EXTERN:
- case TOK_RWORD_CONST:
- case TOK_RWORD_STATIC:
- case TOK_RWORD_STRUCT:
- case TOK_RWORD_ENUM:
- case TOK_RWORD_TRAIT:
- case TOK_RWORD_IMPL:
- case TOK_RWORD_FN:
- case TOK_RWORD_MOD:
- PUTBACK(tok, lex);
- if( !local_mod ) {
- local_mod = lex.parse_state().get_current_mod().add_anon();
- }
- Parse_Mod_Item(lex, *local_mod, mv$(item_attrs));
- return ExprNodeP();
- // 'unsafe' - Check if the next token isn't a `{`, if so it's an item. Otherwise, fall through
- case TOK_RWORD_UNSAFE:
- if( LOOK_AHEAD(lex) != TOK_BRACE_OPEN )
- {
- PUTBACK(tok, lex);
- if( !local_mod ) {
- local_mod = lex.parse_state().get_current_mod().add_anon();
- }
- Parse_Mod_Item(lex, *local_mod, mv$(item_attrs));
- return ExprNodeP();
- }
- // fall
- default: {
- PUTBACK(tok, lex);
- auto rv = Parse_ExprBlockLine(lex, &add_silence_if_end);
- if( rv ) {
- rv->set_attrs( mv$(item_attrs) );
- }
- else if( item_attrs.m_items.size() > 0 ) {
- // TODO: Is this an error? - Attributes on a expression that didn't yeild a node.
- }
- else {
- }
- return rv;
- } break;
- }
-}
-
-/// Parse a single line from a block
-///
-/// Handles:
-/// - Block-level constructs (with lifetime annotations)
-/// - use/extern/const/let
-ExprNodeP Parse_ExprBlockLine(TokenStream& lex, bool *add_silence)
-{
- Token tok;
- ExprNodeP ret;
-
- if( GET_TOK(tok, lex) == TOK_LIFETIME )
- {
- // Lifetimes can only precede loops... and blocks?
- ::std::string lifetime = tok.str();
- GET_CHECK_TOK(tok, lex, TOK_COLON);
-
- switch( GET_TOK(tok, lex) )
- {
- case TOK_RWORD_LOOP:
- return NEWNODE( AST::ExprNode_Loop, lifetime, Parse_ExprBlockNode(lex) );
- case TOK_RWORD_WHILE:
- return Parse_WhileStmt(lex, lifetime);
- case TOK_RWORD_FOR:
- return Parse_ForStmt(lex, lifetime);
- //case TOK_RWORD_IF:
- // return Parse_IfStmt(lex);
- //case TOK_RWORD_MATCH:
- // return Parse_Expr_Match(lex);
- //case TOK_BRACE_OPEN:
- // PUTBACK(tok, lex);
- // return Parse_ExprBlockNode(lex);
-
- default:
- throw ParseError::Unexpected(lex, tok);
- }
- }
- else
- {
- switch( tok.type() )
- {
- case TOK_INTERPOLATED_BLOCK:
- return tok.take_frag_node();
- case TOK_SEMICOLON:
- // Return a NULL expression, nothing here.
- return nullptr;
-
- // let binding
- case TOK_RWORD_LET:
- ret = Parse_Stmt_Let(lex);
- GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
- return ret;
-
- // Blocks that don't need semicolons
- // NOTE: If these are followed by a small set of tokens (`.` and `?`) then they are actually the start of an expression
- // HACK: Parse here, but if the next token is one of the set store in a TOK_INTERPOLATED_EXPR and invoke the statement parser
- case TOK_RWORD_LOOP:
- ret = NEWNODE( AST::ExprNode_Loop, "", Parse_ExprBlockNode(lex) );
- if(0)
- case TOK_RWORD_WHILE:
- ret = Parse_WhileStmt(lex, "");
- if(0)
- case TOK_RWORD_FOR:
- ret = Parse_ForStmt(lex, "");
- if(0)
- case TOK_RWORD_IF:
- ret = Parse_IfStmt(lex);
- if(0)
- case TOK_RWORD_MATCH:
- ret = Parse_Expr_Match(lex);
- if(0)
- case TOK_RWORD_UNSAFE:
- ret = Parse_ExprBlockNode(lex, true);
- if(0)
- case TOK_BRACE_OPEN:
- { PUTBACK(tok, lex); ret = Parse_ExprBlockNode(lex); }
-
- 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);
- }
-
- if( LOOK_AHEAD(lex) == TOK_SEMICOLON ) {
- GET_TOK(tok, lex);
- *add_silence = true;
- }
-
- return ret;
-
- // Flow control
- case TOK_RWORD_RETURN:
- case TOK_RWORD_CONTINUE:
- case TOK_RWORD_BREAK: {
- PUTBACK(tok, lex);
- auto ret = Parse_Stmt(lex);
- if( LOOK_AHEAD(lex) == TOK_EOF ) {
- }
- else if( GET_TOK(tok, lex) != TOK_SEMICOLON ) {
- CHECK_TOK(tok, TOK_BRACE_CLOSE);
- PUTBACK(tok, lex);
- }
- else {
- // return/continue/break don't need silencing
- }
- return ret;
- }
-
- case TOK_MACRO:
- // If a braced macro invocation is the first part of a statement, don't expect a semicolon
- if( LOOK_AHEAD(lex) == TOK_BRACE_OPEN || (lex.lookahead(0) == TOK_IDENT && lex.lookahead(1) == TOK_BRACE_OPEN) ) {
- return Parse_ExprMacro(lex, tok);
- }
- // Fall through to the statement code
- default:
- PUTBACK(tok, lex);
- return Parse_ExprBlockLine_Stmt(lex, *add_silence);
- }
- }
-}
-
-ExprNodeP Parse_ExprBlockLine_Stmt(TokenStream& lex, bool& has_semicolon)
-{
- Token tok;
- auto ret = Parse_Stmt(lex);
- // If this expression statement wasn't followed by a semicolon, then it's yielding its value out of the block.
- // - I.e. The block should be ending
- if( GET_TOK(tok, lex) != TOK_SEMICOLON ) {
- // - Allow TOK_EOF for macro expansion.
- if( tok.type() == TOK_EOF )
- ;
- else
- CHECK_TOK(tok, TOK_BRACE_CLOSE);
- PUTBACK(tok, lex);
- }
- else {
- has_semicolon = true;
- }
- return ret;
-}
-
-/// While loop (either as a statement, or as part of an expression)
-ExprNodeP Parse_WhileStmt(TokenStream& lex, ::std::string lifetime)
-{
- Token tok;
-
- if( GET_TOK(tok, lex) == TOK_RWORD_LET ) {
- auto pat = Parse_Pattern(lex, true); // Refutable pattern
- GET_CHECK_TOK(tok, lex, TOK_EQUAL);
- ExprNodeP val;
- {
- SET_PARSE_FLAG(lex, disallow_struct_literal);
- val = Parse_Expr0(lex);
- }
- return NEWNODE( AST::ExprNode_Loop, lifetime, AST::ExprNode_Loop::WHILELET,
- ::std::move(pat), ::std::move(val), Parse_ExprBlockNode(lex) );
- }
- else {
- PUTBACK(tok, lex);
- ExprNodeP cnd;
- {
- SET_PARSE_FLAG(lex, disallow_struct_literal);
- cnd = Parse_Expr1(lex);
- }
- return NEWNODE( AST::ExprNode_Loop, lifetime, ::std::move(cnd), Parse_ExprBlockNode(lex) );
- }
-}
-/// For loop (either as a statement, or as part of an expression)
-ExprNodeP Parse_ForStmt(TokenStream& lex, ::std::string lifetime)
-{
- Token tok;
-
- // Irrefutable pattern
- AST::Pattern pat = Parse_Pattern(lex, false);
- GET_CHECK_TOK(tok, lex, TOK_RWORD_IN);
- ExprNodeP val;
- {
- SET_PARSE_FLAG(lex, disallow_struct_literal);
- val = Parse_Expr0(lex);
- }
- return NEWNODE( AST::ExprNode_Loop, lifetime, AST::ExprNode_Loop::FOR,
- ::std::move(pat), ::std::move(val), Parse_ExprBlockNode(lex) );
-}
-/// Parse an 'if' statement
-// Note: TOK_RWORD_IF has already been eaten
-ExprNodeP Parse_IfStmt(TokenStream& lex)
-{
- TRACE_FUNCTION;
-
- Token tok;
- ExprNodeP cond;
- AST::Pattern pat;
- bool if_let = false;
-
- {
- SET_PARSE_FLAG(lex, disallow_struct_literal);
- if( GET_TOK(tok, lex) == TOK_RWORD_LET ) {
- if_let = true;
- // Refutable pattern
- pat = Parse_Pattern(lex, true);
- GET_CHECK_TOK(tok, lex, TOK_EQUAL);
- cond = Parse_Expr0(lex);
- }
- else {
- PUTBACK(tok, lex);
- cond = Parse_Expr0(lex);
- }
- }
-
- // Contents
- ExprNodeP code = Parse_ExprBlockNode(lex);
-
- // Handle else:
- ExprNodeP altcode;
- if( GET_TOK(tok, lex) == TOK_RWORD_ELSE )
- {
- // Recurse for 'else if'
- if( GET_TOK(tok, lex) == TOK_RWORD_IF ) {
- altcode = Parse_IfStmt(lex);
- }
- // - or get block
- else {
- PUTBACK(tok, lex);
- altcode = Parse_ExprBlockNode(lex);
- }
- }
- // - or nothing
- else {
- PUTBACK(tok, lex);
- }
-
- if( if_let )
- return NEWNODE( AST::ExprNode_IfLet, ::std::move(pat), ::std::move(cond), ::std::move(code), ::std::move(altcode) );
- else
- return NEWNODE( AST::ExprNode_If, ::std::move(cond), ::std::move(code), ::std::move(altcode) );
-}
-/// "match" block
-ExprNodeP Parse_Expr_Match(TokenStream& lex)
-{
- TRACE_FUNCTION;
- Token tok;
-
- CLEAR_PARSE_FLAG(lex, disallow_struct_literal);
- // 1. Get expression
- ExprNodeP switch_val;
- {
- SET_PARSE_FLAG(lex, disallow_struct_literal);
- switch_val = Parse_Expr1(lex);
- }
- //ASSERT(lex, !CHECK_PARSE_FLAG(lex, disallow_struct_literal) );
- GET_CHECK_TOK(tok, lex, TOK_BRACE_OPEN);
-
- ::std::vector< AST::ExprNode_Match_Arm > arms;
- do {
- if( GET_TOK(tok, lex) == TOK_BRACE_CLOSE )
- break;
- PUTBACK(tok, lex);
- AST::ExprNode_Match_Arm arm;
-
- ::AST::MetaItems arm_attrs;
- while( LOOK_AHEAD(lex) == TOK_ATTR_OPEN ) {
- GET_TOK(tok, lex);
- arm_attrs.push_back( Parse_MetaItem(lex) );
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- }
- arm.m_attrs = mv$(arm_attrs);
-
- do {
- // Refutable pattern
- arm.m_patterns.push_back( Parse_Pattern(lex, true) );
- } while( GET_TOK(tok, lex) == TOK_PIPE );
-
- if( tok.type() == TOK_RWORD_IF )
- {
- arm.m_cond = Parse_Expr1(lex);
- GET_TOK(tok, lex);
- }
- CHECK_TOK(tok, TOK_FATARROW);
-
- arm.m_code = Parse_Stmt(lex);
-
- arms.push_back( ::std::move(arm) );
-
- if( GET_TOK(tok, lex) == TOK_COMMA )
- continue;
- PUTBACK(tok, lex);
-
- } while( 1 );
- CHECK_TOK(tok, TOK_BRACE_CLOSE);
-
- return NEWNODE( AST::ExprNode_Match, ::std::move(switch_val), ::std::move(arms) );
-}
-
-/// Parses the 'stmt' fragment specifier
-/// - Flow control
-/// - Expressions
-ExprNodeP Parse_Stmt(TokenStream& lex)
-{
- TRACE_FUNCTION;
- Token tok;
-
- switch(GET_TOK(tok, lex))
- {
- case TOK_INTERPOLATED_STMT:
- return tok.take_frag_node();
- // Duplicated here for the :stmt pattern fragment.
- case TOK_RWORD_LET:
- return Parse_Stmt_Let(lex);
- case TOK_RWORD_RETURN: {
- ExprNodeP val;
- switch(LOOK_AHEAD(lex))
- {
- case TOK_SEMICOLON:
- case TOK_COMMA:
- case TOK_BRACE_CLOSE:
- case TOK_PAREN_CLOSE:
- case TOK_SQUARE_CLOSE:
- break;
- default:
- val = Parse_Expr0(lex);
- break;
- }
- return NEWNODE( AST::ExprNode_Flow, AST::ExprNode_Flow::RETURN, "", ::std::move(val) );
- }
- case TOK_RWORD_CONTINUE:
- case TOK_RWORD_BREAK:
- {
- AST::ExprNode_Flow::Type type;
- switch(tok.type())
- {
- case TOK_RWORD_CONTINUE: type = AST::ExprNode_Flow::CONTINUE; break;
- case TOK_RWORD_BREAK: type = AST::ExprNode_Flow::BREAK; break;
- default: throw ParseError::BugCheck(/*lex,*/ "continue/break");
- }
- ::std::string lifetime;
- if( GET_TOK(tok, lex) == TOK_LIFETIME )
- {
- lifetime = tok.str();
- GET_TOK(tok, lex);
- }
- ExprNodeP val;
- switch(tok.type())
- {
- case TOK_SEMICOLON:
- case TOK_COMMA:
- case TOK_BRACE_OPEN:
- case TOK_BRACE_CLOSE:
- case TOK_PAREN_CLOSE:
- case TOK_SQUARE_CLOSE:
- PUTBACK(tok, lex);
- break;
- default:
- PUTBACK(tok, lex);
- val = Parse_Expr1(lex);
- break;
- }
- return NEWNODE( AST::ExprNode_Flow, type, lifetime, ::std::move(val) );
- }
- case TOK_BRACE_OPEN:
- PUTBACK(tok, lex);
- return Parse_ExprBlockNode(lex);
- default:
- PUTBACK(tok, lex);
- return Parse_Expr0(lex);
- }
-}
-
-ExprNodeP Parse_Stmt_Let(TokenStream& lex)
-{
- Token tok;
- AST::Pattern pat = Parse_Pattern(lex, false); // irrefutable
- TypeRef type { lex.getPosition() };
- if( GET_TOK(tok, lex) == TOK_COLON ) {
- type = Parse_Type(lex);
- GET_TOK(tok, lex);
- }
- ExprNodeP val;
- if( tok.type() == TOK_EQUAL ) {
- val = Parse_Expr0(lex);
- }
- else {
- PUTBACK(tok, lex);
- }
- return NEWNODE( AST::ExprNode_LetBinding, ::std::move(pat), mv$(type), ::std::move(val) );
-}
-
-::std::vector<ExprNodeP> Parse_ParenList(TokenStream& lex)
-{
- TRACE_FUNCTION;
- Token tok;
-
- CLEAR_PARSE_FLAG(lex, disallow_struct_literal);
-
- ::std::vector<ExprNodeP> rv;
- GET_CHECK_TOK(tok, lex, TOK_PAREN_OPEN);
- if( GET_TOK(tok, lex) != TOK_PAREN_CLOSE )
- {
- PUTBACK(tok, lex);
- do {
- if( LOOK_AHEAD(lex) == TOK_PAREN_CLOSE ) {
- GET_TOK(tok, lex);
- break;
- }
- rv.push_back( Parse_Expr0(lex) );
- } while( GET_TOK(tok, lex) == TOK_COMMA );
- CHECK_TOK(tok, TOK_PAREN_CLOSE);
- }
- return rv;
-}
-
-// 0: Assign
-ExprNodeP Parse_Expr0(TokenStream& lex)
-{
- //TRACE_FUNCTION;
- Token tok;
-
- ::AST::MetaItems expr_attrs;
- while( LOOK_AHEAD(lex) == TOK_ATTR_OPEN )
- {
- GET_TOK(tok, lex);
- expr_attrs.push_back( Parse_MetaItem(lex) );
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- }
-
- ExprNodeP rv = Parse_Expr1(lex);
- auto op = AST::ExprNode_Assign::NONE;
- switch( GET_TOK(tok, lex) )
- {
- case TOK_PLUS_EQUAL:
- op = AST::ExprNode_Assign::ADD; if(0)
- case TOK_DASH_EQUAL:
- op = AST::ExprNode_Assign::SUB; if(0)
- case TOK_STAR_EQUAL:
- op = AST::ExprNode_Assign::MUL; if(0)
- case TOK_SLASH_EQUAL:
- op = AST::ExprNode_Assign::DIV; if(0)
- case TOK_PERCENT_EQUAL:
- op = AST::ExprNode_Assign::MOD; if(0)
-
- case TOK_AMP_EQUAL:
- op = AST::ExprNode_Assign::AND; if(0)
- case TOK_PIPE_EQUAL:
- op = AST::ExprNode_Assign::OR ; if(0)
- case TOK_CARET_EQUAL:
- op = AST::ExprNode_Assign::XOR; if(0)
-
- case TOK_DOUBLE_GT_EQUAL:
- op = AST::ExprNode_Assign::SHR; if(0)
- case TOK_DOUBLE_LT_EQUAL:
- op = AST::ExprNode_Assign::SHL; if(0)
-
- case TOK_EQUAL:
- op = AST::ExprNode_Assign::NONE;
- rv = NEWNODE( AST::ExprNode_Assign, op, ::std::move(rv), Parse_Expr0(lex) );
- rv->set_attrs(mv$(expr_attrs));
- return rv;
-
- default:
- PUTBACK(tok, lex);
- rv->set_attrs(mv$(expr_attrs));
- return rv;
- }
-}
-
-
-#define LEFTASSOC(cur, _next, cases) \
-ExprNodeP _next(TokenStream& lex); \
-ExprNodeP cur(TokenStream& lex) \
-{ \
- ExprNodeP (*next)(TokenStream&) = _next;\
- ExprNodeP rv = next(lex); \
- while(true) \
- { \
- Token tok; \
- switch((tok = lex.getToken()).type()) \
- { \
- cases \
- default: \
- /*::std::cout << "<<" << #cur << ::std::endl; */\
- PUTBACK(tok, lex); \
- return rv; \
- } \
- } \
-}
-bool Parse_IsTokValue(eTokenType tok_type)
-{
- switch( tok_type )
- {
- case TOK_DOUBLE_COLON:
- case TOK_IDENT:
- case TOK_INTEGER:
- case TOK_FLOAT:
- case TOK_STRING:
- case TOK_RWORD_TRUE:
- case TOK_RWORD_FALSE:
- case TOK_RWORD_SELF:
- case TOK_RWORD_SUPER:
- case TOK_RWORD_BOX:
- case TOK_RWORD_IN:
- case TOK_PAREN_OPEN:
- case TOK_SQUARE_OPEN:
-
- case TOK_MACRO:
-
- case TOK_PIPE:
- case TOK_EXCLAM:
- case TOK_DASH:
- case TOK_STAR:
- case TOK_AMP:
- return true;
- default:
- return false;
- }
-
-}
-ExprNodeP Parse_Expr1_1(TokenStream& lex);
-// Very evil handling for '..'
-ExprNodeP Parse_Expr1(TokenStream& lex)
-{
- Token tok;
- ExprNodeP (*next)(TokenStream&) = Parse_Expr1_1;
- ExprNodeP left, right;
-
- // Inclusive range to a value
- if( GET_TOK(tok, lex) == TOK_TRIPLE_DOT ) {
- right = next(lex);
- return NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::RANGE_INC, nullptr, mv$(right) );
- }
- else {
- PUTBACK(tok, lex);
- }
-
- // Exclusive ranges
- // - If NOT `.. <VAL>`, parse a leading value
- if( GET_TOK(tok, lex) != TOK_DOUBLE_DOT )
- {
- PUTBACK(tok, lex);
-
- left = next(lex);
-
- // - If NOT `<VAL> ..`, return the value
- if( GET_TOK(tok, lex) != TOK_DOUBLE_DOT )
- {
- PUTBACK(tok, lex);
- return ::std::move(left);
- }
- }
- assert( tok.type() == TOK_DOUBLE_DOT );
- // If the next token is part of a value, parse that value
- if( Parse_IsTokValue( LOOK_AHEAD(lex) ) )
- {
- right = next(lex);
- }
- else
- {
- // Otherwise, leave `right` as nullptr
- }
-
- return NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::RANGE, ::std::move(left), ::std::move(right) );
-}
-// TODO: Is this left associative?
-LEFTASSOC(Parse_Expr1_1, Parse_Expr1_5,
- case TOK_TRIPLE_DOT:
- rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::RANGE_INC, mv$(rv), next(lex) );
- break;
-)
-// 1: Bool OR
-LEFTASSOC(Parse_Expr1_5, Parse_Expr2,
- case TOK_DOUBLE_PIPE:
- rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::BOOLOR, ::std::move(rv), next(lex));
- break;
-)
-// 2: Bool AND
-LEFTASSOC(Parse_Expr2, Parse_Expr3,
- case TOK_DOUBLE_AMP:
- rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::BOOLAND, ::std::move(rv), next(lex));
- break;
-)
-// 3: (In)Equality
-LEFTASSOC(Parse_Expr3, Parse_Expr4,
- case TOK_DOUBLE_EQUAL:
- rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::CMPEQU, ::std::move(rv), next(lex));
- break;
- case TOK_EXCLAM_EQUAL:
- rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::CMPNEQU, ::std::move(rv), next(lex));
- break;
-)
-// 4: Comparisons
-LEFTASSOC(Parse_Expr4, Parse_Expr5,
- case TOK_LT:
- rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::CMPLT, ::std::move(rv), next(lex));
- break;
- case TOK_GT:
- rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::CMPGT, ::std::move(rv), next(lex));
- break;
- case TOK_LTE:
- rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::CMPLTE, ::std::move(rv), next(lex));
- break;
- case TOK_GTE:
- rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::CMPGTE, ::std::move(rv), next(lex));
- break;
-)
-// 5: Bit OR
-LEFTASSOC(Parse_Expr5, Parse_Expr6,
- case TOK_PIPE:
- rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::BITOR, ::std::move(rv), next(lex));
- break;
-)
-// 6: Bit XOR
-LEFTASSOC(Parse_Expr6, Parse_Expr7,
- case TOK_CARET:
- rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::BITXOR, ::std::move(rv), next(lex));
- break;
-)
-// 7: Bit AND
-LEFTASSOC(Parse_Expr7, Parse_Expr8,
- case TOK_AMP:
- rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::BITAND, ::std::move(rv), next(lex));
- break;
-)
-// 8: Bit Shifts
-LEFTASSOC(Parse_Expr8, Parse_Expr9,
- case TOK_DOUBLE_LT:
- rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::SHL, ::std::move(rv), next(lex));
- break;
- case TOK_DOUBLE_GT:
- rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::SHR, ::std::move(rv), next(lex));
- break;
-)
-// 9: Add / Subtract
-LEFTASSOC(Parse_Expr9, Parse_Expr10,
- case TOK_PLUS:
- rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::ADD, ::std::move(rv), next(lex));
- break;
- case TOK_DASH:
- rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::SUB, ::std::move(rv), next(lex));
- break;
-)
-// 10: Times / Divide / Modulo
-LEFTASSOC(Parse_Expr10, Parse_Expr11,
- case TOK_STAR:
- rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::MULTIPLY, ::std::move(rv), next(lex));
- break;
- case TOK_SLASH:
- rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::DIVIDE, ::std::move(rv), next(lex));
- break;
- case TOK_PERCENT:
- rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::MODULO, ::std::move(rv), next(lex));
- break;
-)
-// 11: Cast
-LEFTASSOC(Parse_Expr11, Parse_Expr12,
- case TOK_RWORD_AS:
- rv = NEWNODE( AST::ExprNode_Cast, ::std::move(rv), Parse_Type(lex, false) );
- break;
-)
-// 12: Type Ascription
-ExprNodeP Parse_Expr13(TokenStream& lex);
-ExprNodeP Parse_Expr12(TokenStream& lex)
-{
- Token tok;
- auto rv = Parse_Expr13(lex);
- if(GET_TOK(tok, lex) == TOK_COLON)
- {
- rv = NEWNODE( AST::ExprNode_TypeAnnotation, mv$(rv), Parse_Type(lex) );
- }
- else
- {
- PUTBACK(tok, lex);
- }
- return rv;
-}
-// 13: Unaries
-ExprNodeP Parse_ExprFC(TokenStream& lex);
-ExprNodeP Parse_Expr13(TokenStream& lex)
-{
- Token tok;
- switch(GET_TOK(tok, lex))
- {
- case TOK_DASH:
- return NEWNODE( AST::ExprNode_UniOp, AST::ExprNode_UniOp::NEGATE, Parse_Expr12(lex) );
- case TOK_EXCLAM:
- return NEWNODE( AST::ExprNode_UniOp, AST::ExprNode_UniOp::INVERT, Parse_Expr12(lex) );
- case TOK_STAR:
- return NEWNODE( AST::ExprNode_Deref, Parse_Expr12(lex) );
- case TOK_RWORD_BOX:
- return NEWNODE( AST::ExprNode_UniOp, AST::ExprNode_UniOp::BOX, Parse_Expr12(lex) );
- case TOK_RWORD_IN: {
- ExprNodeP dest;
- {
- SET_PARSE_FLAG(lex, disallow_struct_literal);
- dest = Parse_Expr1(lex);
- }
- auto val = Parse_ExprBlockNode(lex);
- return NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::PLACE_IN, mv$(dest), mv$(val));
- }
- case TOK_DOUBLE_AMP:
- // HACK: Split && into & &
- lex.putback( Token(TOK_AMP) );
- case TOK_AMP:
- if( GET_TOK(tok, lex) == TOK_RWORD_MUT )
- return NEWNODE( AST::ExprNode_UniOp, AST::ExprNode_UniOp::REFMUT, Parse_Expr12(lex) );
- else {
- PUTBACK(tok, lex);
- return NEWNODE( AST::ExprNode_UniOp, AST::ExprNode_UniOp::REF, Parse_Expr12(lex) );
- }
- default:
- PUTBACK(tok, lex);
- return Parse_ExprFC(lex);
- }
-}
-
-ExprNodeP Parse_ExprVal(TokenStream& lex);
-ExprNodeP Parse_ExprFC(TokenStream& lex)
-{
- ExprNodeP val = Parse_ExprVal(lex);
- while(true)
- {
- Token tok;
- switch(GET_TOK(tok, lex))
- {
- case TOK_QMARK:
- val = NEWNODE( AST::ExprNode_UniOp, AST::ExprNode_UniOp::QMARK, mv$(val) );
- break;
-
- case TOK_PAREN_OPEN:
- // Expression method call
- PUTBACK(tok, lex);
- val = NEWNODE( AST::ExprNode_CallObject, ::std::move(val), Parse_ParenList(lex) );
- break;
- case TOK_SQUARE_OPEN:
- val = NEWNODE( AST::ExprNode_Index, ::std::move(val), Parse_Expr0(lex) );
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- break;
- case TOK_DOT:
- // Field access / method call
- // TODO: What about tuple indexing?
- switch(GET_TOK(tok, lex))
- {
- case TOK_IDENT: {
- AST::PathNode path( mv$(tok.str()) , {});
- switch( GET_TOK(tok, lex) )
- {
- case TOK_PAREN_OPEN:
- PUTBACK(tok, lex);
- val = NEWNODE( AST::ExprNode_CallMethod, ::std::move(val), ::std::move(path), Parse_ParenList(lex) );
- break;
- case TOK_DOUBLE_COLON:
- GET_CHECK_TOK(tok, lex, TOK_LT);
- path.args() = Parse_Path_GenericList(lex);
- val = NEWNODE( AST::ExprNode_CallMethod, ::std::move(val), ::std::move(path), Parse_ParenList(lex) );
- break;
- default:
- val = NEWNODE( AST::ExprNode_Field, ::std::move(val), ::std::string(path.name()) );
- PUTBACK(tok, lex);
- break;
- }
- break; }
- case TOK_INTEGER:
- val = NEWNODE( AST::ExprNode_Field, ::std::move(val), FMT(tok.intval()) );
- break;
- default:
- throw ParseError::Unexpected(lex, mv$(tok));
- }
- break;
- default:
- PUTBACK(tok, lex);
- return val;
- }
- }
-}
-
-ExprNodeP Parse_ExprVal_StructLiteral(TokenStream& lex, AST::Path path)
-{
- TRACE_FUNCTION;
- Token tok;
-
- // #![feature(relaxed_adts)]
- if( LOOK_AHEAD(lex) == TOK_INTEGER )
- {
- ::std::map<unsigned int, ExprNodeP> nodes;
- while( GET_TOK(tok, lex) == TOK_INTEGER )
- {
- unsigned int ofs = tok.intval();
- GET_CHECK_TOK(tok, lex, TOK_COLON);
- ExprNodeP val = Parse_Stmt(lex);
- if( ! nodes.insert( ::std::make_pair(ofs, mv$(val)) ).second ) {
- ERROR(lex.getPosition(), E0000, "Duplicate index");
- }
-
- if( GET_TOK(tok,lex) == TOK_BRACE_CLOSE )
- break;
- CHECK_TOK(tok, TOK_COMMA);
- }
- CHECK_TOK(tok, TOK_BRACE_CLOSE);
-
- ::std::vector<ExprNodeP> items;
- unsigned int i = 0;
- for(auto& p : nodes)
- {
- if( p.first != i ) {
- ERROR(lex.getPosition(), E0000, "Missing index " << i);
- }
- items.push_back( mv$(p.second) );
- i ++;
- }
-
- return NEWNODE( AST::ExprNode_CallPath, mv$(path), mv$(items) );
- }
-
- // Braced structure literal
- // - A series of 0 or more pairs of <ident>: <expr>,
- // - '..' <expr>
- ::std::vector< ::std::pair< ::std::string, ::std::unique_ptr<AST::ExprNode>> > items;
- while( GET_TOK(tok, lex) == TOK_IDENT )
- {
- auto name = mv$(tok.str());
- GET_CHECK_TOK(tok, lex, TOK_COLON);
- ExprNodeP val = Parse_Stmt(lex);
- items.push_back( ::std::make_pair(::std::move(name), ::std::move(val)) );
-
- if( GET_TOK(tok,lex) == TOK_BRACE_CLOSE )
- break;
- CHECK_TOK(tok, TOK_COMMA);
- }
- ExprNodeP base_val;
- if( tok.type() == TOK_DOUBLE_DOT )
- {
- // default
- base_val = Parse_Expr0(lex);
- GET_TOK(tok, lex);
- }
- CHECK_TOK(tok, TOK_BRACE_CLOSE);
-
- return NEWNODE( AST::ExprNode_StructLiteral, path, ::std::move(base_val), ::std::move(items) );
-}
-
-ExprNodeP Parse_ExprVal_Closure(TokenStream& lex, bool is_move)
-{
- TRACE_FUNCTION;
- Token tok;
-
- ::std::vector< ::std::pair<AST::Pattern, TypeRef> > args;
-
- while( GET_TOK(tok, lex) != TOK_PIPE )
- {
- PUTBACK(tok, lex);
- // Irrefutable pattern
- AST::Pattern pat = Parse_Pattern(lex, false);
-
- TypeRef type { lex.getPosition() };
- if( GET_TOK(tok, lex) == TOK_COLON )
- type = Parse_Type(lex);
- else
- PUTBACK(tok, lex);
-
- args.push_back( ::std::make_pair( ::std::move(pat), ::std::move(type) ) );
-
- if( GET_TOK(tok, lex) != TOK_COMMA )
- break;
- }
- CHECK_TOK(tok, TOK_PIPE);
-
- auto rt = TypeRef(lex.getPosition());
- if( GET_TOK(tok, lex) == TOK_THINARROW ) {
-
- if( GET_TOK(tok, lex) == TOK_EXCLAM ) {
- rt = TypeRef(TypeRef::TagInvalid(), Span(tok.get_pos()));
- }
- else {
- PUTBACK(tok, lex);
- rt = Parse_Type(lex);
- }
- }
- else
- PUTBACK(tok, lex);
-
- auto code = Parse_Expr0(lex);
-
- return NEWNODE( AST::ExprNode_Closure, ::std::move(args), ::std::move(rt), ::std::move(code), is_move );
-}
-
-ExprNodeP Parse_ExprVal(TokenStream& lex)
-{
- TRACE_FUNCTION;
-
- Token tok;
- AST::Path path;
- switch( GET_TOK(tok, lex) )
- {
- case TOK_BRACE_OPEN:
- PUTBACK(tok, lex);
- return Parse_ExprBlockNode(lex);
-
- case TOK_INTERPOLATED_EXPR:
- case TOK_INTERPOLATED_BLOCK:
- return tok.take_frag_node();
-
-
- // TODO: Return/break/continue/... here?
- case TOK_RWORD_RETURN:
- case TOK_RWORD_CONTINUE:
- case TOK_RWORD_BREAK:
- PUTBACK(tok, lex);
- return Parse_Stmt(lex);
-
- case TOK_RWORD_LOOP:
- return NEWNODE( AST::ExprNode_Loop, "", Parse_ExprBlockNode(lex) );
- case TOK_RWORD_WHILE:
- return Parse_WhileStmt(lex, "");
- case TOK_RWORD_FOR:
- return Parse_ForStmt(lex, "");
- case TOK_RWORD_MATCH:
- return Parse_Expr_Match(lex);
- case TOK_RWORD_IF:
- return Parse_IfStmt(lex);
- case TOK_RWORD_UNSAFE:
- return Parse_ExprBlockNode(lex, true);
-
- // UFCS
- case TOK_DOUBLE_LT:
- case TOK_LT:
- PUTBACK(tok, lex);
- path = Parse_Path(lex, PATH_GENERIC_EXPR);
- // Skip down to method
- if(0)
- case TOK_RWORD_SELF:
- {
- if( LOOK_AHEAD(lex) != TOK_DOUBLE_COLON ) {
- return NEWNODE( AST::ExprNode_NamedValue, AST::Path(AST::Path::TagLocal(), "self") );
- }
- else
- {
- PUTBACK(tok, lex);
- path = Parse_Path(lex, PATH_GENERIC_EXPR);
- }
- }
- if(0)
- case TOK_RWORD_SUPER:
- {
- PUTBACK(tok, lex);
- path = Parse_Path(lex, PATH_GENERIC_EXPR);
- }
- if(0)
- case TOK_IDENT:
- // Get path
- {
- PUTBACK(tok, lex);
- path = Parse_Path(lex, false, PATH_GENERIC_EXPR);
- }
- if(0)
- case TOK_INTERPOLATED_PATH:
- {
- path = mv$(tok.frag_path());
- }
- if(0)
- case TOK_DOUBLE_COLON:
- path = Parse_Path(lex, true, PATH_GENERIC_EXPR);
- // SKIP TARGET
- switch( GET_TOK(tok, lex) )
- {
- case TOK_PAREN_OPEN:
- // Function call
- PUTBACK(tok, lex);
- return NEWNODE( AST::ExprNode_CallPath, ::std::move(path), Parse_ParenList(lex) );
- case TOK_BRACE_OPEN:
- if( !CHECK_PARSE_FLAG(lex, disallow_struct_literal) )
- return Parse_ExprVal_StructLiteral(lex, ::std::move(path));
- else
- DEBUG("Not parsing struct literal");
- default:
- // Value
- PUTBACK(tok, lex);
- return NEWNODE( AST::ExprNode_NamedValue, ::std::move(path) );
- }
- case TOK_RWORD_MOVE:
- // TODO: Annotate closure as move
- GET_TOK(tok, lex);
- if(tok.type() == TOK_PIPE)
- return Parse_ExprVal_Closure(lex, true);
- else if(tok.type() == TOK_DOUBLE_PIPE) {
- lex.putback(Token(TOK_PIPE));
- return Parse_ExprVal_Closure(lex, true);
- }
- else {
- CHECK_TOK(tok, TOK_PIPE);
- }
- case TOK_DOUBLE_PIPE:
- lex.putback(Token(TOK_PIPE));
- case TOK_PIPE:
- return Parse_ExprVal_Closure(lex, false);
- case TOK_INTEGER:
- return NEWNODE( AST::ExprNode_Integer, tok.intval(), tok.datatype() );
- case TOK_FLOAT:
- return NEWNODE( AST::ExprNode_Float, tok.floatval(), tok.datatype() );
- case TOK_STRING:
- return NEWNODE( AST::ExprNode_String, tok.str() );
- case TOK_BYTESTRING:
- return NEWNODE( AST::ExprNode_ByteString, tok.str() );
- case TOK_RWORD_TRUE:
- return NEWNODE( AST::ExprNode_Bool, true );
- case TOK_RWORD_FALSE:
- return NEWNODE( AST::ExprNode_Bool, false );
- case TOK_PAREN_OPEN:
- if( GET_TOK(tok, lex) == TOK_PAREN_CLOSE )
- {
- DEBUG("Unit");
- return NEWNODE( AST::ExprNode_Tuple, ::std::vector<ExprNodeP>() );
- }
- else
- {
- CLEAR_PARSE_FLAG(lex, disallow_struct_literal);
- PUTBACK(tok, lex);
-
- ExprNodeP rv = Parse_Expr0(lex);
- if( GET_TOK(tok, lex) == TOK_COMMA ) {
- ::std::vector<ExprNodeP> ents;
- ents.push_back( ::std::move(rv) );
- do {
- if( GET_TOK(tok, lex) == TOK_PAREN_CLOSE )
- break;
- PUTBACK(tok, lex);
- ents.push_back( Parse_Expr0(lex) );
- } while( GET_TOK(tok, lex) == TOK_COMMA );
- rv = NEWNODE( AST::ExprNode_Tuple, ::std::move(ents) );
- }
- CHECK_TOK(tok, TOK_PAREN_CLOSE);
- return rv;
- }
- case TOK_SQUARE_OPEN:
- if( GET_TOK(tok, lex) == TOK_SQUARE_CLOSE )
- {
- // Empty literal
- return NEWNODE( AST::ExprNode_Array, ::std::vector<ExprNodeP>() );
- }
- else
- {
- PUTBACK(tok, lex);
- auto first = Parse_Expr0(lex);
- if( GET_TOK(tok, lex) == TOK_SEMICOLON )
- {
- // Repetiion
- auto count = Parse_Expr0(lex);
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- return NEWNODE( AST::ExprNode_Array, ::std::move(first), ::std::move(count) );
- }
- else
- {
- ::std::vector<ExprNodeP> items;
- items.push_back( ::std::move(first) );
- while( tok.type() == TOK_COMMA )
- {
- if( GET_TOK(tok, lex) == TOK_SQUARE_CLOSE )
- break;
- else
- PUTBACK(tok, lex);
- items.push_back( Parse_Expr0(lex) );
- GET_TOK(tok, lex);
- }
- CHECK_TOK(tok, TOK_SQUARE_CLOSE);
- return NEWNODE( AST::ExprNode_Array, ::std::move(items) );
- }
- }
- throw ParseError::BugCheck(lex, "Array literal fell");
- case TOK_MACRO:
- return Parse_ExprMacro(lex, mv$(tok));
- default:
- throw ParseError::Unexpected(lex, tok);
- }
-}
-ExprNodeP Parse_ExprMacro(TokenStream& lex, Token tok)
-{
- ::std::string name = tok.str();
- ::std::string ident;
- if( GET_TOK(tok, lex) == TOK_IDENT ) {
- ident = mv$(tok.str());
- }
- else {
- PUTBACK(tok, lex);
- }
- TokenTree tt = Parse_TT(lex, true);
- if( tt.is_token() ) {
- throw ParseError::Unexpected(lex, tt.tok());
- }
- return NEWNODE(AST::ExprNode_Macro, mv$(name), mv$(ident), mv$(tt));
-}
-
-// Token Tree Parsing
-TokenTree Parse_TT(TokenStream& lex, bool unwrapped)
-{
- TokenTree rv;
- TRACE_FUNCTION_FR("", rv);
-
- Token tok = lex.getToken();
- eTokenType closer = TOK_PAREN_CLOSE;
- switch(tok.type())
- {
- case TOK_PAREN_OPEN:
- closer = TOK_PAREN_CLOSE;
- break;
- case TOK_SQUARE_OPEN:
- closer = TOK_SQUARE_CLOSE;
- break;
- case TOK_BRACE_OPEN:
- closer = TOK_BRACE_CLOSE;
- break;
- // HACK! mrustc parses #[ and #![ as composite tokens
- // TODO: Split these into their component tokens.
- case TOK_ATTR_OPEN:
- case TOK_CATTR_OPEN:
- if( unwrapped )
- throw ParseError::Unexpected(lex, tok);
- closer = TOK_SQUARE_CLOSE;
- break;
-
- case TOK_EOF:
- case TOK_NULL:
- case TOK_PAREN_CLOSE:
- case TOK_SQUARE_CLOSE:
- case TOK_BRACE_CLOSE:
- throw ParseError::Unexpected(lex, tok);
- default:
- rv = TokenTree(lex.getHygiene(), mv$(tok) );
- return rv;
- }
-
- ::std::vector<TokenTree> items;
- if( !unwrapped )
- items.push_back( TokenTree(lex.getHygiene(), mv$(tok)) );
- while(GET_TOK(tok, lex) != closer && tok.type() != TOK_EOF)
- {
- if( tok.type() == TOK_NULL )
- throw ParseError::Unexpected(lex, tok);
- PUTBACK(tok, lex);
- items.push_back(Parse_TT(lex, false));
- }
- if( !unwrapped )
- items.push_back( TokenTree(lex.getHygiene(), mv$(tok)) );
- rv = TokenTree(lex.getHygiene(), mv$(items));
- return rv;
-}
+/* + * MRustC - Rust Compiler + * - By John Hodge (Mutabah/thePowersGang) + * + * parse/expr.cpp + * - Expression (i.e. code) parsing + * + * Start points: + * - Parse_ExprBlockNode : Parses a block + * - Parse_Stmt : Parse a single statement + * - Parse_Expr0 : Parse a single expression + */ +#include "parseerror.hpp" +#include <ast/ast.hpp> +#include <ast/expr.hpp> +#include "common.hpp" +#include <iostream> +#include "tokentree.hpp" +#include "interpolated_fragment.hpp" + +using AST::ExprNode; +using AST::ExprNodeP; +static inline ExprNodeP mk_exprnodep(const TokenStream& lex, AST::ExprNode* en){en->set_pos(lex.getPosition()); return ExprNodeP(en); } +#define NEWNODE(type, ...) mk_exprnodep(lex, new type(__VA_ARGS__)) + +//ExprNodeP Parse_ExprBlockNode(TokenStream& lex, bool is_unsafe=false); // common.hpp +//ExprNodeP Parse_ExprBlockLine_WithItems(TokenStream& lex, ::std::shared_ptr<AST::Module>& local_mod, bool& add_silence_if_end); +//ExprNodeP Parse_ExprBlockLine(TokenStream& lex, bool *add_silence); +ExprNodeP Parse_ExprBlockLine_Stmt(TokenStream& lex, bool& has_semicolon); +//ExprNodeP Parse_Stmt(TokenStream& lex); // common.hpp +ExprNodeP Parse_Stmt_Let(TokenStream& lex); +ExprNodeP Parse_Expr0(TokenStream& lex); +ExprNodeP Parse_IfStmt(TokenStream& lex); +ExprNodeP Parse_WhileStmt(TokenStream& lex, ::std::string lifetime); +ExprNodeP Parse_ForStmt(TokenStream& lex, ::std::string lifetime); +ExprNodeP Parse_Expr_Match(TokenStream& lex); +ExprNodeP Parse_Expr1(TokenStream& lex); +ExprNodeP Parse_ExprMacro(TokenStream& lex, Token tok); + +AST::Expr Parse_Expr(TokenStream& lex) +{ + return ::AST::Expr( Parse_Expr0(lex) ); +} + +AST::Expr Parse_ExprBlock(TokenStream& lex) +{ + return ::AST::Expr( Parse_ExprBlockNode(lex) ); +} + +ExprNodeP Parse_ExprBlockNode(TokenStream& lex, bool is_unsafe/*=false*/) +{ + TRACE_FUNCTION; + Token tok; + + bool yields_final_value = true; + ::std::vector<ExprNodeP> nodes; + + ::std::shared_ptr<AST::Module> local_mod; + + GET_CHECK_TOK(tok, lex, TOK_BRACE_OPEN); + + while( LOOK_AHEAD(lex) != TOK_BRACE_CLOSE ) + { + DEBUG("tok = " << tok); + + // NOTE: Doc comments can appear within a function and apply to the function + // TODO: Use these attributes + while( GET_TOK(tok, lex) == TOK_CATTR_OPEN ) + { + /*node_attrs.push_back(*/ Parse_MetaItem(lex) /*)*/; + GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE); + } + PUTBACK(tok, lex); + if( LOOK_AHEAD(lex) == TOK_BRACE_CLOSE ) + break; + + bool add_silence_if_end = false; + auto rv = Parse_ExprBlockLine_WithItems(lex, local_mod, add_silence_if_end); + if( rv ) + { + // Set to TRUE if there was no semicolon after a statement + if( LOOK_AHEAD(lex) == TOK_BRACE_CLOSE && add_silence_if_end ) + { + DEBUG("End of block, and add_silence_if_end == true - doesn't yeild"); + yields_final_value = false; + // Since the next token is TOK_BRACE_CLOSE, the loop will terminate + } + nodes.push_back( mv$(rv) ); + } + else { + assert( !add_silence_if_end ); + } + } + GET_CHECK_TOK(tok, lex, TOK_BRACE_CLOSE); + + return NEWNODE( AST::ExprNode_Block, is_unsafe, yields_final_value, mv$(nodes), mv$(local_mod) ); +} + +/// Parse a single line in a block, handling items added to the local module +/// +/// - If an item was parsed, this returns an empty ExprNodeP +ExprNodeP Parse_ExprBlockLine_WithItems(TokenStream& lex, ::std::shared_ptr<AST::Module>& local_mod, bool& add_silence_if_end) +{ + Token tok; + + AST::MetaItems item_attrs; + while( GET_TOK(tok, lex) == TOK_ATTR_OPEN ) + { + item_attrs.push_back( Parse_MetaItem(lex) ); + GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE); + } + + switch(tok.type()) + { + // Items: + case TOK_RWORD_PUB: + // NOTE: Allowed, but doesn't do much + case TOK_RWORD_TYPE: + case TOK_RWORD_USE: + case TOK_RWORD_EXTERN: + case TOK_RWORD_CONST: + case TOK_RWORD_STATIC: + case TOK_RWORD_STRUCT: + case TOK_RWORD_ENUM: + case TOK_RWORD_TRAIT: + case TOK_RWORD_IMPL: + case TOK_RWORD_FN: + case TOK_RWORD_MOD: + PUTBACK(tok, lex); + if( !local_mod ) { + local_mod = lex.parse_state().get_current_mod().add_anon(); + } + Parse_Mod_Item(lex, *local_mod, mv$(item_attrs)); + return ExprNodeP(); + // 'unsafe' - Check if the next token isn't a `{`, if so it's an item. Otherwise, fall through + case TOK_RWORD_UNSAFE: + if( LOOK_AHEAD(lex) != TOK_BRACE_OPEN ) + { + PUTBACK(tok, lex); + if( !local_mod ) { + local_mod = lex.parse_state().get_current_mod().add_anon(); + } + Parse_Mod_Item(lex, *local_mod, mv$(item_attrs)); + return ExprNodeP(); + } + // fall + default: { + PUTBACK(tok, lex); + auto rv = Parse_ExprBlockLine(lex, &add_silence_if_end); + if( rv ) { + rv->set_attrs( mv$(item_attrs) ); + } + else if( item_attrs.m_items.size() > 0 ) { + // TODO: Is this an error? - Attributes on a expression that didn't yeild a node. + } + else { + } + return rv; + } break; + } +} + +/// Parse a single line from a block +/// +/// Handles: +/// - Block-level constructs (with lifetime annotations) +/// - use/extern/const/let +ExprNodeP Parse_ExprBlockLine(TokenStream& lex, bool *add_silence) +{ + Token tok; + ExprNodeP ret; + + if( GET_TOK(tok, lex) == TOK_LIFETIME ) + { + // Lifetimes can only precede loops... and blocks? + ::std::string lifetime = tok.str(); + GET_CHECK_TOK(tok, lex, TOK_COLON); + + switch( GET_TOK(tok, lex) ) + { + case TOK_RWORD_LOOP: + return NEWNODE( AST::ExprNode_Loop, lifetime, Parse_ExprBlockNode(lex) ); + case TOK_RWORD_WHILE: + return Parse_WhileStmt(lex, lifetime); + case TOK_RWORD_FOR: + return Parse_ForStmt(lex, lifetime); + //case TOK_RWORD_IF: + // return Parse_IfStmt(lex); + //case TOK_RWORD_MATCH: + // return Parse_Expr_Match(lex); + //case TOK_BRACE_OPEN: + // PUTBACK(tok, lex); + // return Parse_ExprBlockNode(lex); + + default: + throw ParseError::Unexpected(lex, tok); + } + } + else + { + switch( tok.type() ) + { + case TOK_INTERPOLATED_BLOCK: + return tok.take_frag_node(); + case TOK_SEMICOLON: + // Return a NULL expression, nothing here. + return nullptr; + + // let binding + case TOK_RWORD_LET: + ret = Parse_Stmt_Let(lex); + GET_CHECK_TOK(tok, lex, TOK_SEMICOLON); + return ret; + + // Blocks that don't need semicolons + // NOTE: If these are followed by a small set of tokens (`.` and `?`) then they are actually the start of an expression + // HACK: Parse here, but if the next token is one of the set store in a TOK_INTERPOLATED_EXPR and invoke the statement parser + case TOK_RWORD_LOOP: + ret = NEWNODE( AST::ExprNode_Loop, "", Parse_ExprBlockNode(lex) ); + if(0) + case TOK_RWORD_WHILE: + ret = Parse_WhileStmt(lex, ""); + if(0) + case TOK_RWORD_FOR: + ret = Parse_ForStmt(lex, ""); + if(0) + case TOK_RWORD_IF: + ret = Parse_IfStmt(lex); + if(0) + case TOK_RWORD_MATCH: + ret = Parse_Expr_Match(lex); + if(0) + case TOK_RWORD_UNSAFE: + ret = Parse_ExprBlockNode(lex, true); + if(0) + case TOK_BRACE_OPEN: + { PUTBACK(tok, lex); ret = Parse_ExprBlockNode(lex); } + + 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); + } + + if( LOOK_AHEAD(lex) == TOK_SEMICOLON ) { + GET_TOK(tok, lex); + *add_silence = true; + } + + return ret; + + // Flow control + case TOK_RWORD_RETURN: + case TOK_RWORD_CONTINUE: + case TOK_RWORD_BREAK: { + PUTBACK(tok, lex); + auto ret = Parse_Stmt(lex); + if( LOOK_AHEAD(lex) == TOK_EOF ) { + } + else if( GET_TOK(tok, lex) != TOK_SEMICOLON ) { + CHECK_TOK(tok, TOK_BRACE_CLOSE); + PUTBACK(tok, lex); + } + else { + // return/continue/break don't need silencing + } + return ret; + } + + case TOK_MACRO: + // If a braced macro invocation is the first part of a statement, don't expect a semicolon + if( LOOK_AHEAD(lex) == TOK_BRACE_OPEN || (lex.lookahead(0) == TOK_IDENT && lex.lookahead(1) == TOK_BRACE_OPEN) ) { + return Parse_ExprMacro(lex, tok); + } + // Fall through to the statement code + default: + PUTBACK(tok, lex); + return Parse_ExprBlockLine_Stmt(lex, *add_silence); + } + } +} + +ExprNodeP Parse_ExprBlockLine_Stmt(TokenStream& lex, bool& has_semicolon) +{ + Token tok; + auto ret = Parse_Stmt(lex); + // If this expression statement wasn't followed by a semicolon, then it's yielding its value out of the block. + // - I.e. The block should be ending + if( GET_TOK(tok, lex) != TOK_SEMICOLON ) { + // - Allow TOK_EOF for macro expansion. + if( tok.type() == TOK_EOF ) + ; + else + CHECK_TOK(tok, TOK_BRACE_CLOSE); + PUTBACK(tok, lex); + } + else { + has_semicolon = true; + } + return ret; +} + +/// While loop (either as a statement, or as part of an expression) +ExprNodeP Parse_WhileStmt(TokenStream& lex, ::std::string lifetime) +{ + Token tok; + + if( GET_TOK(tok, lex) == TOK_RWORD_LET ) { + auto pat = Parse_Pattern(lex, true); // Refutable pattern + GET_CHECK_TOK(tok, lex, TOK_EQUAL); + ExprNodeP val; + { + SET_PARSE_FLAG(lex, disallow_struct_literal); + val = Parse_Expr0(lex); + } + return NEWNODE( AST::ExprNode_Loop, lifetime, AST::ExprNode_Loop::WHILELET, + ::std::move(pat), ::std::move(val), Parse_ExprBlockNode(lex) ); + } + else { + PUTBACK(tok, lex); + ExprNodeP cnd; + { + SET_PARSE_FLAG(lex, disallow_struct_literal); + cnd = Parse_Expr1(lex); + } + return NEWNODE( AST::ExprNode_Loop, lifetime, ::std::move(cnd), Parse_ExprBlockNode(lex) ); + } +} +/// For loop (either as a statement, or as part of an expression) +ExprNodeP Parse_ForStmt(TokenStream& lex, ::std::string lifetime) +{ + Token tok; + + // Irrefutable pattern + AST::Pattern pat = Parse_Pattern(lex, false); + GET_CHECK_TOK(tok, lex, TOK_RWORD_IN); + ExprNodeP val; + { + SET_PARSE_FLAG(lex, disallow_struct_literal); + val = Parse_Expr0(lex); + } + return NEWNODE( AST::ExprNode_Loop, lifetime, AST::ExprNode_Loop::FOR, + ::std::move(pat), ::std::move(val), Parse_ExprBlockNode(lex) ); +} +/// Parse an 'if' statement +// Note: TOK_RWORD_IF has already been eaten +ExprNodeP Parse_IfStmt(TokenStream& lex) +{ + TRACE_FUNCTION; + + Token tok; + ExprNodeP cond; + AST::Pattern pat; + bool if_let = false; + + { + SET_PARSE_FLAG(lex, disallow_struct_literal); + if( GET_TOK(tok, lex) == TOK_RWORD_LET ) { + if_let = true; + // Refutable pattern + pat = Parse_Pattern(lex, true); + GET_CHECK_TOK(tok, lex, TOK_EQUAL); + cond = Parse_Expr0(lex); + } + else { + PUTBACK(tok, lex); + cond = Parse_Expr0(lex); + } + } + + // Contents + ExprNodeP code = Parse_ExprBlockNode(lex); + + // Handle else: + ExprNodeP altcode; + if( GET_TOK(tok, lex) == TOK_RWORD_ELSE ) + { + // Recurse for 'else if' + if( GET_TOK(tok, lex) == TOK_RWORD_IF ) { + altcode = Parse_IfStmt(lex); + } + // - or get block + else { + PUTBACK(tok, lex); + altcode = Parse_ExprBlockNode(lex); + } + } + // - or nothing + else { + PUTBACK(tok, lex); + } + + if( if_let ) + return NEWNODE( AST::ExprNode_IfLet, ::std::move(pat), ::std::move(cond), ::std::move(code), ::std::move(altcode) ); + else + return NEWNODE( AST::ExprNode_If, ::std::move(cond), ::std::move(code), ::std::move(altcode) ); +} +/// "match" block +ExprNodeP Parse_Expr_Match(TokenStream& lex) +{ + TRACE_FUNCTION; + Token tok; + + CLEAR_PARSE_FLAG(lex, disallow_struct_literal); + // 1. Get expression + ExprNodeP switch_val; + { + SET_PARSE_FLAG(lex, disallow_struct_literal); + switch_val = Parse_Expr1(lex); + } + //ASSERT(lex, !CHECK_PARSE_FLAG(lex, disallow_struct_literal) ); + GET_CHECK_TOK(tok, lex, TOK_BRACE_OPEN); + + ::std::vector< AST::ExprNode_Match_Arm > arms; + do { + if( GET_TOK(tok, lex) == TOK_BRACE_CLOSE ) + break; + PUTBACK(tok, lex); + AST::ExprNode_Match_Arm arm; + + ::AST::MetaItems arm_attrs; + while( LOOK_AHEAD(lex) == TOK_ATTR_OPEN ) { + GET_TOK(tok, lex); + arm_attrs.push_back( Parse_MetaItem(lex) ); + GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE); + } + arm.m_attrs = mv$(arm_attrs); + + do { + // Refutable pattern + arm.m_patterns.push_back( Parse_Pattern(lex, true) ); + } while( GET_TOK(tok, lex) == TOK_PIPE ); + + if( tok.type() == TOK_RWORD_IF ) + { + arm.m_cond = Parse_Expr1(lex); + GET_TOK(tok, lex); + } + CHECK_TOK(tok, TOK_FATARROW); + + arm.m_code = Parse_Stmt(lex); + + arms.push_back( ::std::move(arm) ); + + if( GET_TOK(tok, lex) == TOK_COMMA ) + continue; + PUTBACK(tok, lex); + + } while( 1 ); + CHECK_TOK(tok, TOK_BRACE_CLOSE); + + return NEWNODE( AST::ExprNode_Match, ::std::move(switch_val), ::std::move(arms) ); +} + +/// Parses the 'stmt' fragment specifier +/// - Flow control +/// - Expressions +ExprNodeP Parse_Stmt(TokenStream& lex) +{ + TRACE_FUNCTION; + Token tok; + + switch(GET_TOK(tok, lex)) + { + case TOK_INTERPOLATED_STMT: + return tok.take_frag_node(); + // Duplicated here for the :stmt pattern fragment. + case TOK_RWORD_LET: + return Parse_Stmt_Let(lex); + case TOK_RWORD_RETURN: { + ExprNodeP val; + switch(LOOK_AHEAD(lex)) + { + case TOK_SEMICOLON: + case TOK_COMMA: + case TOK_BRACE_CLOSE: + case TOK_PAREN_CLOSE: + case TOK_SQUARE_CLOSE: + break; + default: + val = Parse_Expr0(lex); + break; + } + return NEWNODE( AST::ExprNode_Flow, AST::ExprNode_Flow::RETURN, "", ::std::move(val) ); + } + case TOK_RWORD_CONTINUE: + case TOK_RWORD_BREAK: + { + AST::ExprNode_Flow::Type type; + switch(tok.type()) + { + case TOK_RWORD_CONTINUE: type = AST::ExprNode_Flow::CONTINUE; break; + case TOK_RWORD_BREAK: type = AST::ExprNode_Flow::BREAK; break; + default: throw ParseError::BugCheck(/*lex,*/ "continue/break"); + } + ::std::string lifetime; + if( GET_TOK(tok, lex) == TOK_LIFETIME ) + { + lifetime = tok.str(); + GET_TOK(tok, lex); + } + ExprNodeP val; + switch(tok.type()) + { + case TOK_SEMICOLON: + case TOK_COMMA: + case TOK_BRACE_OPEN: + case TOK_BRACE_CLOSE: + case TOK_PAREN_CLOSE: + case TOK_SQUARE_CLOSE: + PUTBACK(tok, lex); + break; + default: + PUTBACK(tok, lex); + val = Parse_Expr1(lex); + break; + } + return NEWNODE( AST::ExprNode_Flow, type, lifetime, ::std::move(val) ); + } + case TOK_BRACE_OPEN: + PUTBACK(tok, lex); + return Parse_ExprBlockNode(lex); + default: + PUTBACK(tok, lex); + return Parse_Expr0(lex); + } +} + +ExprNodeP Parse_Stmt_Let(TokenStream& lex) +{ + Token tok; + AST::Pattern pat = Parse_Pattern(lex, false); // irrefutable + TypeRef type { lex.getPosition() }; + if( GET_TOK(tok, lex) == TOK_COLON ) { + type = Parse_Type(lex); + GET_TOK(tok, lex); + } + ExprNodeP val; + if( tok.type() == TOK_EQUAL ) { + val = Parse_Expr0(lex); + } + else { + PUTBACK(tok, lex); + } + return NEWNODE( AST::ExprNode_LetBinding, ::std::move(pat), mv$(type), ::std::move(val) ); +} + +::std::vector<ExprNodeP> Parse_ParenList(TokenStream& lex) +{ + TRACE_FUNCTION; + Token tok; + + CLEAR_PARSE_FLAG(lex, disallow_struct_literal); + + ::std::vector<ExprNodeP> rv; + GET_CHECK_TOK(tok, lex, TOK_PAREN_OPEN); + if( GET_TOK(tok, lex) != TOK_PAREN_CLOSE ) + { + PUTBACK(tok, lex); + do { + if( LOOK_AHEAD(lex) == TOK_PAREN_CLOSE ) { + GET_TOK(tok, lex); + break; + } + rv.push_back( Parse_Expr0(lex) ); + } while( GET_TOK(tok, lex) == TOK_COMMA ); + CHECK_TOK(tok, TOK_PAREN_CLOSE); + } + return rv; +} + +// 0: Assign +ExprNodeP Parse_Expr0(TokenStream& lex) +{ + //TRACE_FUNCTION; + Token tok; + + ::AST::MetaItems expr_attrs; + while( LOOK_AHEAD(lex) == TOK_ATTR_OPEN ) + { + GET_TOK(tok, lex); + expr_attrs.push_back( Parse_MetaItem(lex) ); + GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE); + } + + ExprNodeP rv = Parse_Expr1(lex); + auto op = AST::ExprNode_Assign::NONE; + switch( GET_TOK(tok, lex) ) + { + case TOK_PLUS_EQUAL: + op = AST::ExprNode_Assign::ADD; if(0) + case TOK_DASH_EQUAL: + op = AST::ExprNode_Assign::SUB; if(0) + case TOK_STAR_EQUAL: + op = AST::ExprNode_Assign::MUL; if(0) + case TOK_SLASH_EQUAL: + op = AST::ExprNode_Assign::DIV; if(0) + case TOK_PERCENT_EQUAL: + op = AST::ExprNode_Assign::MOD; if(0) + + case TOK_AMP_EQUAL: + op = AST::ExprNode_Assign::AND; if(0) + case TOK_PIPE_EQUAL: + op = AST::ExprNode_Assign::OR ; if(0) + case TOK_CARET_EQUAL: + op = AST::ExprNode_Assign::XOR; if(0) + + case TOK_DOUBLE_GT_EQUAL: + op = AST::ExprNode_Assign::SHR; if(0) + case TOK_DOUBLE_LT_EQUAL: + op = AST::ExprNode_Assign::SHL; if(0) + + case TOK_EQUAL: + op = AST::ExprNode_Assign::NONE; + rv = NEWNODE( AST::ExprNode_Assign, op, ::std::move(rv), Parse_Expr0(lex) ); + rv->set_attrs(mv$(expr_attrs)); + return rv; + + default: + PUTBACK(tok, lex); + rv->set_attrs(mv$(expr_attrs)); + return rv; + } +} + + +#define LEFTASSOC(cur, _next, cases) \ +ExprNodeP _next(TokenStream& lex); \ +ExprNodeP cur(TokenStream& lex) \ +{ \ + ExprNodeP (*next)(TokenStream&) = _next;\ + ExprNodeP rv = next(lex); \ + while(true) \ + { \ + Token tok; \ + switch((tok = lex.getToken()).type()) \ + { \ + cases \ + default: \ + /*::std::cout << "<<" << #cur << ::std::endl; */\ + PUTBACK(tok, lex); \ + return rv; \ + } \ + } \ +} +bool Parse_IsTokValue(eTokenType tok_type) +{ + switch( tok_type ) + { + case TOK_DOUBLE_COLON: + case TOK_IDENT: + case TOK_INTEGER: + case TOK_FLOAT: + case TOK_STRING: + case TOK_RWORD_TRUE: + case TOK_RWORD_FALSE: + case TOK_RWORD_SELF: + case TOK_RWORD_SUPER: + case TOK_RWORD_BOX: + case TOK_RWORD_IN: + case TOK_PAREN_OPEN: + case TOK_SQUARE_OPEN: + + case TOK_MACRO: + + case TOK_PIPE: + case TOK_EXCLAM: + case TOK_DASH: + case TOK_STAR: + case TOK_AMP: + return true; + default: + return false; + } + +} +ExprNodeP Parse_Expr1_1(TokenStream& lex); +// Very evil handling for '..' +ExprNodeP Parse_Expr1(TokenStream& lex) +{ + Token tok; + ExprNodeP (*next)(TokenStream&) = Parse_Expr1_1; + ExprNodeP left, right; + + // Inclusive range to a value + if( GET_TOK(tok, lex) == TOK_TRIPLE_DOT ) { + right = next(lex); + return NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::RANGE_INC, nullptr, mv$(right) ); + } + else { + PUTBACK(tok, lex); + } + + // Exclusive ranges + // - If NOT `.. <VAL>`, parse a leading value + if( GET_TOK(tok, lex) != TOK_DOUBLE_DOT ) + { + PUTBACK(tok, lex); + + left = next(lex); + + // - If NOT `<VAL> ..`, return the value + if( GET_TOK(tok, lex) != TOK_DOUBLE_DOT ) + { + PUTBACK(tok, lex); + return ::std::move(left); + } + } + assert( tok.type() == TOK_DOUBLE_DOT ); + // If the next token is part of a value, parse that value + if( Parse_IsTokValue( LOOK_AHEAD(lex) ) ) + { + right = next(lex); + } + else + { + // Otherwise, leave `right` as nullptr + } + + return NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::RANGE, ::std::move(left), ::std::move(right) ); +} +// TODO: Is this left associative? +LEFTASSOC(Parse_Expr1_1, Parse_Expr1_5, + case TOK_TRIPLE_DOT: + rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::RANGE_INC, mv$(rv), next(lex) ); + break; +) +// 1: Bool OR +LEFTASSOC(Parse_Expr1_5, Parse_Expr2, + case TOK_DOUBLE_PIPE: + rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::BOOLOR, ::std::move(rv), next(lex)); + break; +) +// 2: Bool AND +LEFTASSOC(Parse_Expr2, Parse_Expr3, + case TOK_DOUBLE_AMP: + rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::BOOLAND, ::std::move(rv), next(lex)); + break; +) +// 3: (In)Equality +LEFTASSOC(Parse_Expr3, Parse_Expr4, + case TOK_DOUBLE_EQUAL: + rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::CMPEQU, ::std::move(rv), next(lex)); + break; + case TOK_EXCLAM_EQUAL: + rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::CMPNEQU, ::std::move(rv), next(lex)); + break; +) +// 4: Comparisons +LEFTASSOC(Parse_Expr4, Parse_Expr5, + case TOK_LT: + rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::CMPLT, ::std::move(rv), next(lex)); + break; + case TOK_GT: + rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::CMPGT, ::std::move(rv), next(lex)); + break; + case TOK_LTE: + rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::CMPLTE, ::std::move(rv), next(lex)); + break; + case TOK_GTE: + rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::CMPGTE, ::std::move(rv), next(lex)); + break; +) +// 5: Bit OR +LEFTASSOC(Parse_Expr5, Parse_Expr6, + case TOK_PIPE: + rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::BITOR, ::std::move(rv), next(lex)); + break; +) +// 6: Bit XOR +LEFTASSOC(Parse_Expr6, Parse_Expr7, + case TOK_CARET: + rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::BITXOR, ::std::move(rv), next(lex)); + break; +) +// 7: Bit AND +LEFTASSOC(Parse_Expr7, Parse_Expr8, + case TOK_AMP: + rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::BITAND, ::std::move(rv), next(lex)); + break; +) +// 8: Bit Shifts +LEFTASSOC(Parse_Expr8, Parse_Expr9, + case TOK_DOUBLE_LT: + rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::SHL, ::std::move(rv), next(lex)); + break; + case TOK_DOUBLE_GT: + rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::SHR, ::std::move(rv), next(lex)); + break; +) +// 9: Add / Subtract +LEFTASSOC(Parse_Expr9, Parse_Expr10, + case TOK_PLUS: + rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::ADD, ::std::move(rv), next(lex)); + break; + case TOK_DASH: + rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::SUB, ::std::move(rv), next(lex)); + break; +) +// 10: Times / Divide / Modulo +LEFTASSOC(Parse_Expr10, Parse_Expr11, + case TOK_STAR: + rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::MULTIPLY, ::std::move(rv), next(lex)); + break; + case TOK_SLASH: + rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::DIVIDE, ::std::move(rv), next(lex)); + break; + case TOK_PERCENT: + rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::MODULO, ::std::move(rv), next(lex)); + break; +) +// 11: Cast +LEFTASSOC(Parse_Expr11, Parse_Expr12, + case TOK_RWORD_AS: + rv = NEWNODE( AST::ExprNode_Cast, ::std::move(rv), Parse_Type(lex, false) ); + break; +) +// 12: Type Ascription +ExprNodeP Parse_Expr13(TokenStream& lex); +ExprNodeP Parse_Expr12(TokenStream& lex) +{ + Token tok; + auto rv = Parse_Expr13(lex); + if(GET_TOK(tok, lex) == TOK_COLON) + { + rv = NEWNODE( AST::ExprNode_TypeAnnotation, mv$(rv), Parse_Type(lex) ); + } + else + { + PUTBACK(tok, lex); + } + return rv; +} +// 13: Unaries +ExprNodeP Parse_ExprFC(TokenStream& lex); +ExprNodeP Parse_Expr13(TokenStream& lex) +{ + Token tok; + switch(GET_TOK(tok, lex)) + { + case TOK_DASH: + return NEWNODE( AST::ExprNode_UniOp, AST::ExprNode_UniOp::NEGATE, Parse_Expr12(lex) ); + case TOK_EXCLAM: + return NEWNODE( AST::ExprNode_UniOp, AST::ExprNode_UniOp::INVERT, Parse_Expr12(lex) ); + case TOK_STAR: + return NEWNODE( AST::ExprNode_Deref, Parse_Expr12(lex) ); + case TOK_RWORD_BOX: + return NEWNODE( AST::ExprNode_UniOp, AST::ExprNode_UniOp::BOX, Parse_Expr12(lex) ); + case TOK_RWORD_IN: { + ExprNodeP dest; + { + SET_PARSE_FLAG(lex, disallow_struct_literal); + dest = Parse_Expr1(lex); + } + auto val = Parse_ExprBlockNode(lex); + return NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::PLACE_IN, mv$(dest), mv$(val)); + } + case TOK_DOUBLE_AMP: + // HACK: Split && into & & + lex.putback( Token(TOK_AMP) ); + case TOK_AMP: + if( GET_TOK(tok, lex) == TOK_RWORD_MUT ) + return NEWNODE( AST::ExprNode_UniOp, AST::ExprNode_UniOp::REFMUT, Parse_Expr12(lex) ); + else { + PUTBACK(tok, lex); + return NEWNODE( AST::ExprNode_UniOp, AST::ExprNode_UniOp::REF, Parse_Expr12(lex) ); + } + default: + PUTBACK(tok, lex); + return Parse_ExprFC(lex); + } +} + +ExprNodeP Parse_ExprVal(TokenStream& lex); +ExprNodeP Parse_ExprFC(TokenStream& lex) +{ + ExprNodeP val = Parse_ExprVal(lex); + while(true) + { + Token tok; + switch(GET_TOK(tok, lex)) + { + case TOK_QMARK: + val = NEWNODE( AST::ExprNode_UniOp, AST::ExprNode_UniOp::QMARK, mv$(val) ); + break; + + case TOK_PAREN_OPEN: + // Expression method call + PUTBACK(tok, lex); + val = NEWNODE( AST::ExprNode_CallObject, ::std::move(val), Parse_ParenList(lex) ); + break; + case TOK_SQUARE_OPEN: + val = NEWNODE( AST::ExprNode_Index, ::std::move(val), Parse_Expr0(lex) ); + GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE); + break; + case TOK_DOT: + // Field access / method call + // TODO: What about tuple indexing? + switch(GET_TOK(tok, lex)) + { + case TOK_IDENT: { + AST::PathNode path( mv$(tok.str()) , {}); + switch( GET_TOK(tok, lex) ) + { + case TOK_PAREN_OPEN: + PUTBACK(tok, lex); + val = NEWNODE( AST::ExprNode_CallMethod, ::std::move(val), ::std::move(path), Parse_ParenList(lex) ); + break; + case TOK_DOUBLE_COLON: + GET_CHECK_TOK(tok, lex, TOK_LT); + path.args() = Parse_Path_GenericList(lex); + val = NEWNODE( AST::ExprNode_CallMethod, ::std::move(val), ::std::move(path), Parse_ParenList(lex) ); + break; + default: + val = NEWNODE( AST::ExprNode_Field, ::std::move(val), ::std::string(path.name()) ); + PUTBACK(tok, lex); + break; + } + break; } + case TOK_INTEGER: + val = NEWNODE( AST::ExprNode_Field, ::std::move(val), FMT(tok.intval()) ); + break; + default: + throw ParseError::Unexpected(lex, mv$(tok)); + } + break; + default: + PUTBACK(tok, lex); + return val; + } + } +} + +ExprNodeP Parse_ExprVal_StructLiteral(TokenStream& lex, AST::Path path) +{ + TRACE_FUNCTION; + Token tok; + + // #![feature(relaxed_adts)] + if( LOOK_AHEAD(lex) == TOK_INTEGER ) + { + ::std::map<unsigned int, ExprNodeP> nodes; + while( GET_TOK(tok, lex) == TOK_INTEGER ) + { + unsigned int ofs = tok.intval(); + GET_CHECK_TOK(tok, lex, TOK_COLON); + ExprNodeP val = Parse_Stmt(lex); + if( ! nodes.insert( ::std::make_pair(ofs, mv$(val)) ).second ) { + ERROR(lex.getPosition(), E0000, "Duplicate index"); + } + + if( GET_TOK(tok,lex) == TOK_BRACE_CLOSE ) + break; + CHECK_TOK(tok, TOK_COMMA); + } + CHECK_TOK(tok, TOK_BRACE_CLOSE); + + ::std::vector<ExprNodeP> items; + unsigned int i = 0; + for(auto& p : nodes) + { + if( p.first != i ) { + ERROR(lex.getPosition(), E0000, "Missing index " << i); + } + items.push_back( mv$(p.second) ); + i ++; + } + + return NEWNODE( AST::ExprNode_CallPath, mv$(path), mv$(items) ); + } + + // Braced structure literal + // - A series of 0 or more pairs of <ident>: <expr>, + // - '..' <expr> + ::std::vector< ::std::pair< ::std::string, ::std::unique_ptr<AST::ExprNode>> > items; + while( GET_TOK(tok, lex) == TOK_IDENT ) + { + auto name = mv$(tok.str()); + GET_CHECK_TOK(tok, lex, TOK_COLON); + ExprNodeP val = Parse_Stmt(lex); + items.push_back( ::std::make_pair(::std::move(name), ::std::move(val)) ); + + if( GET_TOK(tok,lex) == TOK_BRACE_CLOSE ) + break; + CHECK_TOK(tok, TOK_COMMA); + } + ExprNodeP base_val; + if( tok.type() == TOK_DOUBLE_DOT ) + { + // default + base_val = Parse_Expr0(lex); + GET_TOK(tok, lex); + } + CHECK_TOK(tok, TOK_BRACE_CLOSE); + + return NEWNODE( AST::ExprNode_StructLiteral, path, ::std::move(base_val), ::std::move(items) ); +} + +ExprNodeP Parse_ExprVal_Closure(TokenStream& lex, bool is_move) +{ + TRACE_FUNCTION; + Token tok; + + ::std::vector< ::std::pair<AST::Pattern, TypeRef> > args; + + while( GET_TOK(tok, lex) != TOK_PIPE ) + { + PUTBACK(tok, lex); + // Irrefutable pattern + AST::Pattern pat = Parse_Pattern(lex, false); + + TypeRef type { lex.getPosition() }; + if( GET_TOK(tok, lex) == TOK_COLON ) + type = Parse_Type(lex); + else + PUTBACK(tok, lex); + + args.push_back( ::std::make_pair( ::std::move(pat), ::std::move(type) ) ); + + if( GET_TOK(tok, lex) != TOK_COMMA ) + break; + } + CHECK_TOK(tok, TOK_PIPE); + + auto rt = TypeRef(lex.getPosition()); + if( GET_TOK(tok, lex) == TOK_THINARROW ) { + + if( GET_TOK(tok, lex) == TOK_EXCLAM ) { + rt = TypeRef(TypeRef::TagInvalid(), Span(tok.get_pos())); + } + else { + PUTBACK(tok, lex); + rt = Parse_Type(lex); + } + } + else + PUTBACK(tok, lex); + + auto code = Parse_Expr0(lex); + + return NEWNODE( AST::ExprNode_Closure, ::std::move(args), ::std::move(rt), ::std::move(code), is_move ); +} + +ExprNodeP Parse_ExprVal(TokenStream& lex) +{ + TRACE_FUNCTION; + + Token tok; + AST::Path path; + switch( GET_TOK(tok, lex) ) + { + case TOK_BRACE_OPEN: + PUTBACK(tok, lex); + return Parse_ExprBlockNode(lex); + + case TOK_INTERPOLATED_EXPR: + case TOK_INTERPOLATED_BLOCK: + return tok.take_frag_node(); + + + // TODO: Return/break/continue/... here? + case TOK_RWORD_RETURN: + case TOK_RWORD_CONTINUE: + case TOK_RWORD_BREAK: + PUTBACK(tok, lex); + return Parse_Stmt(lex); + + case TOK_RWORD_LOOP: + return NEWNODE( AST::ExprNode_Loop, "", Parse_ExprBlockNode(lex) ); + case TOK_RWORD_WHILE: + return Parse_WhileStmt(lex, ""); + case TOK_RWORD_FOR: + return Parse_ForStmt(lex, ""); + case TOK_RWORD_MATCH: + return Parse_Expr_Match(lex); + case TOK_RWORD_IF: + return Parse_IfStmt(lex); + case TOK_RWORD_UNSAFE: + return Parse_ExprBlockNode(lex, true); + + // UFCS + case TOK_DOUBLE_LT: + case TOK_LT: + PUTBACK(tok, lex); + path = Parse_Path(lex, PATH_GENERIC_EXPR); + // Skip down to method + if(0) + case TOK_RWORD_SELF: + { + if( LOOK_AHEAD(lex) != TOK_DOUBLE_COLON ) { + return NEWNODE( AST::ExprNode_NamedValue, AST::Path(AST::Path::TagLocal(), "self") ); + } + else + { + PUTBACK(tok, lex); + path = Parse_Path(lex, PATH_GENERIC_EXPR); + } + } + if(0) + case TOK_RWORD_SUPER: + { + PUTBACK(tok, lex); + path = Parse_Path(lex, PATH_GENERIC_EXPR); + } + if(0) + case TOK_IDENT: + // Get path + { + PUTBACK(tok, lex); + path = Parse_Path(lex, false, PATH_GENERIC_EXPR); + } + if(0) + case TOK_INTERPOLATED_PATH: + { + path = mv$(tok.frag_path()); + } + if(0) + case TOK_DOUBLE_COLON: + path = Parse_Path(lex, true, PATH_GENERIC_EXPR); + // SKIP TARGET + switch( GET_TOK(tok, lex) ) + { + case TOK_PAREN_OPEN: + // Function call + PUTBACK(tok, lex); + return NEWNODE( AST::ExprNode_CallPath, ::std::move(path), Parse_ParenList(lex) ); + case TOK_BRACE_OPEN: + if( !CHECK_PARSE_FLAG(lex, disallow_struct_literal) ) + return Parse_ExprVal_StructLiteral(lex, ::std::move(path)); + else + DEBUG("Not parsing struct literal"); + default: + // Value + PUTBACK(tok, lex); + return NEWNODE( AST::ExprNode_NamedValue, ::std::move(path) ); + } + case TOK_RWORD_MOVE: + // TODO: Annotate closure as move + GET_TOK(tok, lex); + if(tok.type() == TOK_PIPE) + return Parse_ExprVal_Closure(lex, true); + else if(tok.type() == TOK_DOUBLE_PIPE) { + lex.putback(Token(TOK_PIPE)); + return Parse_ExprVal_Closure(lex, true); + } + else { + CHECK_TOK(tok, TOK_PIPE); + } + case TOK_DOUBLE_PIPE: + lex.putback(Token(TOK_PIPE)); + case TOK_PIPE: + return Parse_ExprVal_Closure(lex, false); + case TOK_INTEGER: + return NEWNODE( AST::ExprNode_Integer, tok.intval(), tok.datatype() ); + case TOK_FLOAT: + return NEWNODE( AST::ExprNode_Float, tok.floatval(), tok.datatype() ); + case TOK_STRING: + return NEWNODE( AST::ExprNode_String, tok.str() ); + case TOK_BYTESTRING: + return NEWNODE( AST::ExprNode_ByteString, tok.str() ); + case TOK_RWORD_TRUE: + return NEWNODE( AST::ExprNode_Bool, true ); + case TOK_RWORD_FALSE: + return NEWNODE( AST::ExprNode_Bool, false ); + case TOK_PAREN_OPEN: + if( GET_TOK(tok, lex) == TOK_PAREN_CLOSE ) + { + DEBUG("Unit"); + return NEWNODE( AST::ExprNode_Tuple, ::std::vector<ExprNodeP>() ); + } + else + { + CLEAR_PARSE_FLAG(lex, disallow_struct_literal); + PUTBACK(tok, lex); + + ExprNodeP rv = Parse_Expr0(lex); + if( GET_TOK(tok, lex) == TOK_COMMA ) { + ::std::vector<ExprNodeP> ents; + ents.push_back( ::std::move(rv) ); + do { + if( GET_TOK(tok, lex) == TOK_PAREN_CLOSE ) + break; + PUTBACK(tok, lex); + ents.push_back( Parse_Expr0(lex) ); + } while( GET_TOK(tok, lex) == TOK_COMMA ); + rv = NEWNODE( AST::ExprNode_Tuple, ::std::move(ents) ); + } + CHECK_TOK(tok, TOK_PAREN_CLOSE); + return rv; + } + case TOK_SQUARE_OPEN: + if( GET_TOK(tok, lex) == TOK_SQUARE_CLOSE ) + { + // Empty literal + return NEWNODE( AST::ExprNode_Array, ::std::vector<ExprNodeP>() ); + } + else + { + PUTBACK(tok, lex); + auto first = Parse_Expr0(lex); + if( GET_TOK(tok, lex) == TOK_SEMICOLON ) + { + // Repetiion + auto count = Parse_Expr0(lex); + GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE); + return NEWNODE( AST::ExprNode_Array, ::std::move(first), ::std::move(count) ); + } + else + { + ::std::vector<ExprNodeP> items; + items.push_back( ::std::move(first) ); + while( tok.type() == TOK_COMMA ) + { + if( GET_TOK(tok, lex) == TOK_SQUARE_CLOSE ) + break; + else + PUTBACK(tok, lex); + items.push_back( Parse_Expr0(lex) ); + GET_TOK(tok, lex); + } + CHECK_TOK(tok, TOK_SQUARE_CLOSE); + return NEWNODE( AST::ExprNode_Array, ::std::move(items) ); + } + } + throw ParseError::BugCheck(lex, "Array literal fell"); + case TOK_MACRO: + return Parse_ExprMacro(lex, mv$(tok)); + default: + throw ParseError::Unexpected(lex, tok); + } +} +ExprNodeP Parse_ExprMacro(TokenStream& lex, Token tok) +{ + ::std::string name = tok.str(); + ::std::string ident; + if( GET_TOK(tok, lex) == TOK_IDENT ) { + ident = mv$(tok.str()); + } + else { + PUTBACK(tok, lex); + } + TokenTree tt = Parse_TT(lex, true); + if( tt.is_token() ) { + throw ParseError::Unexpected(lex, tt.tok()); + } + return NEWNODE(AST::ExprNode_Macro, mv$(name), mv$(ident), mv$(tt)); +} + +// Token Tree Parsing +TokenTree Parse_TT(TokenStream& lex, bool unwrapped) +{ + TokenTree rv; + TRACE_FUNCTION_FR("", rv); + + Token tok = lex.getToken(); + eTokenType closer = TOK_PAREN_CLOSE; + switch(tok.type()) + { + case TOK_PAREN_OPEN: + closer = TOK_PAREN_CLOSE; + break; + case TOK_SQUARE_OPEN: + closer = TOK_SQUARE_CLOSE; + break; + case TOK_BRACE_OPEN: + closer = TOK_BRACE_CLOSE; + break; + // HACK! mrustc parses #[ and #![ as composite tokens + // TODO: Split these into their component tokens. + case TOK_ATTR_OPEN: + case TOK_CATTR_OPEN: + if( unwrapped ) + throw ParseError::Unexpected(lex, tok); + closer = TOK_SQUARE_CLOSE; + break; + + case TOK_EOF: + case TOK_NULL: + case TOK_PAREN_CLOSE: + case TOK_SQUARE_CLOSE: + case TOK_BRACE_CLOSE: + throw ParseError::Unexpected(lex, tok); + default: + rv = TokenTree(lex.getHygiene(), mv$(tok) ); + return rv; + } + + ::std::vector<TokenTree> items; + if( !unwrapped ) + items.push_back( TokenTree(lex.getHygiene(), mv$(tok)) ); + while(GET_TOK(tok, lex) != closer && tok.type() != TOK_EOF) + { + if( tok.type() == TOK_NULL ) + throw ParseError::Unexpected(lex, tok); + PUTBACK(tok, lex); + items.push_back(Parse_TT(lex, false)); + } + if( !unwrapped ) + items.push_back( TokenTree(lex.getHygiene(), mv$(tok)) ); + rv = TokenTree(lex.getHygiene(), mv$(items)); + return rv; +} diff --git a/src/parse/interpolated_fragment.hpp b/src/parse/interpolated_fragment.hpp index b0be2efe..a3e72816 100644 --- a/src/parse/interpolated_fragment.hpp +++ b/src/parse/interpolated_fragment.hpp @@ -25,18 +25,18 @@ public: PAT, PATH, TYPE, - + EXPR, STMT, BLOCK, - + META, ITEM, } m_type; - + // Owned type-pruned pointer void* m_ptr; - + InterpolatedFragment(InterpolatedFragment&& ); InterpolatedFragment& operator=(InterpolatedFragment&& ); //InterpolatedFragment(const InterpolatedFragment& ); @@ -48,9 +48,9 @@ public: InterpolatedFragment(::AST::Named<AST::Item> ); ~InterpolatedFragment(); InterpolatedFragment(Type , ::AST::ExprNode*); - + TokenTree& as_tt() { assert(m_type == TT); return *reinterpret_cast<TokenTree*>(m_ptr); } const TokenTree& as_tt() const { assert(m_type == TT); return *reinterpret_cast<TokenTree*>(m_ptr); } - + friend ::std::ostream& operator<<(::std::ostream& os, const InterpolatedFragment& x); }; diff --git a/src/parse/lex.cpp b/src/parse/lex.cpp index dfd2a2d3..9b09b1d4 100644 --- a/src/parse/lex.cpp +++ b/src/parse/lex.cpp @@ -275,7 +275,7 @@ Token Lexer::getTokenInt() try { Codepoint ch = this->getc(); - + if( ch == '#' && m_line == 1 && m_line_ofs == 1 ) { switch( (ch = this->getc()).v ) { @@ -326,8 +326,8 @@ Token Lexer::getTokenInt() DEC, HEX, } num_mode = DEC; - - + + // Handle integers/floats uint64_t val = 0; if( ch == '0' ) { @@ -390,7 +390,7 @@ Token Lexer::getTokenInt() if( ch == '.' ) { ch = this->getc(); - + // Double/Triple Dot if( ch == '.' ) { @@ -403,7 +403,7 @@ Token Lexer::getTokenInt() } return Token(val, CORETYPE_ANY); } - + // Single dot followed by a non-digit, could be a float or an integer with a method/field access if( !ch.isdigit() ) { @@ -428,8 +428,8 @@ Token Lexer::getTokenInt() } if( num_mode != DEC ) TODO(this->getPosition(), "Non-decimal floats"); - - + + this->ungetc(); double fval = this->parseFloat(val); if( issym(ch = this->getc()) ) @@ -441,7 +441,7 @@ Token Lexer::getTokenInt() ch = this->getc(); } this->ungetc(); - + if(0) ; else if(suffix == "f32") num_type = CORETYPE_F32; else if(suffix == "f64") num_type = CORETYPE_F64; @@ -464,7 +464,7 @@ Token Lexer::getTokenInt() ch = this->getc(); } this->ungetc(); - + if(0) ; else if(suffix == "i8") num_type = CORETYPE_I8; else if(suffix == "i16") num_type = CORETYPE_I16; @@ -495,13 +495,13 @@ Token Lexer::getTokenInt() is_byte = true; ch = this->getc(); } - + if(ch == 'r') { return this->getTokenInt_RawString(is_byte); } else { assert(is_byte); - + // Byte string if( ch == '"' ) { ::std::string str; @@ -579,7 +579,7 @@ Token Lexer::getTokenInt() while(true) { ch = this->getc(); - + if( ch == '/' ) { str += ch; ch = this->getc(); @@ -704,7 +704,7 @@ Token Lexer::getTokenInt_RawString(bool is_byte) catch( Lexer::EndOfFile e ) { throw ParseError::Generic(*this, "EOF reached in raw string"); } - + if( terminating_hashes > 0 ) { assert(terminating_hashes > 0); @@ -715,7 +715,7 @@ Token Lexer::getTokenInt_RawString(bool is_byte) terminating_hashes += 1; } terminating_hashes = 0; - + this->ungetc(); } else { @@ -800,9 +800,9 @@ double Lexer::parseFloat(uint64_t whole) } this->ungetc(); buf[ofs] = 0; - + DEBUG("buf = " << buf << ", ch = '" << ch << "'"); - + return ::std::strtod(buf, NULL); } @@ -920,7 +920,7 @@ Codepoint Lexer::getc_cp() // Two bytes uint8_t e1 = this->getc_byte(); if( (e1 & 0xC0) != 0x80 ) return {0xFFFE}; - + uint32_t outval = ((v1 & 0x1F) << 6) | ((e1 & 0x3F) <<0) @@ -933,7 +933,7 @@ Codepoint Lexer::getc_cp() if( (e1 & 0xC0) != 0x80 ) return {0xFFFE}; uint8_t e2 = this->getc_byte(); if( (e2 & 0xC0) != 0x80 ) return {0xFFFE}; - + uint32_t outval = ((v1 & 0x0F) << 12) | ((e1 & 0x3F) << 6) @@ -949,7 +949,7 @@ Codepoint Lexer::getc_cp() if( (e2 & 0xC0) != 0x80 ) return {0xFFFE}; uint8_t e3 = this->getc_byte(); if( (e3 & 0xC0) != 0x80 ) return {0xFFFE}; - + uint32_t outval = ((v1 & 0x07) << 18) | ((e1 & 0x3F) << 12) @@ -1004,7 +1004,7 @@ bool Codepoint::isxdigit() const { s += (char)cp.v; } else if( cp.v < (0x1F+1)<<(1*6) ) { - + s += (char)(0xC0 | ((cp.v >> 6) & 0x1F)); s += (char)(0x80 | ((cp.v >> 0) & 0x3F)); } diff --git a/src/parse/lex.hpp b/src/parse/lex.hpp index 572846da..871ab29a 100644 --- a/src/parse/lex.hpp +++ b/src/parse/lex.hpp @@ -40,7 +40,7 @@ class Lexer: bool m_last_char_valid; Codepoint m_last_char; Token m_next_token; // Used when lexing generated two tokens - + Ident::Hygiene m_hygiene; public: Lexer(const ::std::string& filename); @@ -51,7 +51,7 @@ public: private: Token getTokenInt(); - + signed int getSymbol(); Token getTokenInt_RawString(bool is_byte); Token getTokenInt_Identifier(Codepoint ch, Codepoint ch2='\0'); diff --git a/src/parse/parseerror.cpp b/src/parse/parseerror.cpp index 116776a5..3c5d41fe 100644 --- a/src/parse/parseerror.cpp +++ b/src/parse/parseerror.cpp @@ -1,91 +1,91 @@ -/*
- * MRustC - Rust Compiler
- * - By John Hodge (Mutabah/thePowersGang)
- *
- * parse/parseerror.cpp
- * - Exceptions thrown for different types of parsing errors
- */
-#include "parseerror.hpp"
-#include <iostream>
-
-CompileError::Base::~Base() throw()
-{
-}
-
-CompileError::Generic::Generic(::std::string message):
- m_message(message)
-{
- ::std::cout << "Generic(" << message << ")" << ::std::endl;
-}
-CompileError::Generic::Generic(const TokenStream& lex, ::std::string message)
-{
- ::std::cout << lex.getPosition() << ": Generic(" << message << ")" << ::std::endl;
-}
-
-CompileError::BugCheck::BugCheck(const TokenStream& lex, ::std::string message):
- m_message(message)
-{
- ::std::cout << lex.getPosition() << "BugCheck(" << message << ")" << ::std::endl;
-}
-CompileError::BugCheck::BugCheck(::std::string message):
- m_message(message)
-{
- ::std::cout << "BugCheck(" << message << ")" << ::std::endl;
-}
-
-CompileError::Todo::Todo(::std::string message):
- m_message(message)
-{
- ::std::cout << "Todo(" << message << ")" << ::std::endl;
-}
-CompileError::Todo::Todo(const TokenStream& lex, ::std::string message):
- m_message(message)
-{
- ::std::cout << lex.getPosition() << ": Todo(" << message << ")" << ::std::endl;
-}
-CompileError::Todo::~Todo() throw()
-{
-}
-
-ParseError::BadChar::BadChar(const TokenStream& lex, char character)
-{
- ::std::cout << lex.getPosition() << ": BadChar(" << character << ")" << ::std::endl;
-}
-ParseError::BadChar::~BadChar() throw()
-{
-}
-
-ParseError::Unexpected::Unexpected(const TokenStream& lex, const Token& tok)//:
-// m_tok( mv$(tok) )
-{
- auto pos = tok.get_pos();
- if(pos.filename == "")
- pos = lex.getPosition();
- ::std::cout << pos << ": Unexpected(" << tok << ")" << ::std::endl;
-}
-ParseError::Unexpected::Unexpected(const TokenStream& lex, const Token& tok, Token exp)//:
-// m_tok( mv$(tok) )
-{
- auto pos = tok.get_pos();
- if(pos.filename == "")
- pos = lex.getPosition();
- ::std::cout << pos << ": Unexpected(" << tok << ", " << exp << ")" << ::std::endl;
-}
-ParseError::Unexpected::Unexpected(const TokenStream& lex, const Token& tok, ::std::vector<eTokenType> exp)
-{
- auto pos = tok.get_pos();
- if(pos.filename == "")
- pos = lex.getPosition();
- ::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;
-}
-ParseError::Unexpected::~Unexpected() throw()
-{
-}
+/* + * MRustC - Rust Compiler + * - By John Hodge (Mutabah/thePowersGang) + * + * parse/parseerror.cpp + * - Exceptions thrown for different types of parsing errors + */ +#include "parseerror.hpp" +#include <iostream> + +CompileError::Base::~Base() throw() +{ +} + +CompileError::Generic::Generic(::std::string message): + m_message(message) +{ + ::std::cout << "Generic(" << message << ")" << ::std::endl; +} +CompileError::Generic::Generic(const TokenStream& lex, ::std::string message) +{ + ::std::cout << lex.getPosition() << ": Generic(" << message << ")" << ::std::endl; +} + +CompileError::BugCheck::BugCheck(const TokenStream& lex, ::std::string message): + m_message(message) +{ + ::std::cout << lex.getPosition() << "BugCheck(" << message << ")" << ::std::endl; +} +CompileError::BugCheck::BugCheck(::std::string message): + m_message(message) +{ + ::std::cout << "BugCheck(" << message << ")" << ::std::endl; +} + +CompileError::Todo::Todo(::std::string message): + m_message(message) +{ + ::std::cout << "Todo(" << message << ")" << ::std::endl; +} +CompileError::Todo::Todo(const TokenStream& lex, ::std::string message): + m_message(message) +{ + ::std::cout << lex.getPosition() << ": Todo(" << message << ")" << ::std::endl; +} +CompileError::Todo::~Todo() throw() +{ +} + +ParseError::BadChar::BadChar(const TokenStream& lex, char character) +{ + ::std::cout << lex.getPosition() << ": BadChar(" << character << ")" << ::std::endl; +} +ParseError::BadChar::~BadChar() throw() +{ +} + +ParseError::Unexpected::Unexpected(const TokenStream& lex, const Token& tok)//: +// m_tok( mv$(tok) ) +{ + auto pos = tok.get_pos(); + if(pos.filename == "") + pos = lex.getPosition(); + ::std::cout << pos << ": Unexpected(" << tok << ")" << ::std::endl; +} +ParseError::Unexpected::Unexpected(const TokenStream& lex, const Token& tok, Token exp)//: +// m_tok( mv$(tok) ) +{ + auto pos = tok.get_pos(); + if(pos.filename == "") + pos = lex.getPosition(); + ::std::cout << pos << ": Unexpected(" << tok << ", " << exp << ")" << ::std::endl; +} +ParseError::Unexpected::Unexpected(const TokenStream& lex, const Token& tok, ::std::vector<eTokenType> exp) +{ + auto pos = tok.get_pos(); + if(pos.filename == "") + pos = lex.getPosition(); + ::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; +} +ParseError::Unexpected::~Unexpected() throw() +{ +} diff --git a/src/parse/parseerror.hpp b/src/parse/parseerror.hpp index 0a00f60a..d6bcab6b 100644 --- a/src/parse/parseerror.hpp +++ b/src/parse/parseerror.hpp @@ -1,40 +1,40 @@ -#ifndef PARSEERROR_HPP_INCLUDED
-#define PARSEERROR_HPP_INCLUDED
-
-#include <stdexcept>
-#include "tokenstream.hpp"
-#include <compile_error.hpp>
-
-namespace ParseError {
-
-using CompileError::Generic;
-using CompileError::BugCheck;
-using CompileError::Todo;
-
-class BadChar:
- public CompileError::Base
-{
- //char m_char;
-public:
- BadChar(const TokenStream& lex, char character);
- virtual ~BadChar() throw ();
-
-};
-
-class Unexpected:
- public CompileError::Base
-{
- Token m_tok;
-public:
- Unexpected(const TokenStream& lex, const Token& tok);
- Unexpected(const TokenStream& lex, const Token& tok, Token exp);
- Unexpected(const TokenStream& lex, const Token& tok, ::std::vector<eTokenType> exp);
- virtual ~Unexpected() throw ();
-
-};
-
-#define ASSERT(lex, cnd) do { if( !(cnd) ) throw CompileError::BugCheck(lex, "Assertion failed: " __FILE__ " - " #cnd); } while(0)
-
-}
-
-#endif // PARSEERROR_HPP_INCLUDED
+#ifndef PARSEERROR_HPP_INCLUDED +#define PARSEERROR_HPP_INCLUDED + +#include <stdexcept> +#include "tokenstream.hpp" +#include <compile_error.hpp> + +namespace ParseError { + +using CompileError::Generic; +using CompileError::BugCheck; +using CompileError::Todo; + +class BadChar: + public CompileError::Base +{ + //char m_char; +public: + BadChar(const TokenStream& lex, char character); + virtual ~BadChar() throw (); + +}; + +class Unexpected: + public CompileError::Base +{ + Token m_tok; +public: + Unexpected(const TokenStream& lex, const Token& tok); + Unexpected(const TokenStream& lex, const Token& tok, Token exp); + Unexpected(const TokenStream& lex, const Token& tok, ::std::vector<eTokenType> exp); + virtual ~Unexpected() throw (); + +}; + +#define ASSERT(lex, cnd) do { if( !(cnd) ) throw CompileError::BugCheck(lex, "Assertion failed: " __FILE__ " - " #cnd); } while(0) + +} + +#endif // PARSEERROR_HPP_INCLUDED diff --git a/src/parse/paths.cpp b/src/parse/paths.cpp index e600e51e..360c630f 100644 --- a/src/parse/paths.cpp +++ b/src/parse/paths.cpp @@ -17,17 +17,17 @@ AST::PathParams Parse_Path_GenericList(TokenStream& lex); AST::Path Parse_Path(TokenStream& lex, eParsePathGenericMode generic_mode) { TRACE_FUNCTION_F("generic_mode="<<generic_mode); - + Token tok; switch( GET_TOK(tok, lex) ) { case TOK_INTERPOLATED_PATH: return mv$(tok.frag_path()); - + case TOK_RWORD_SELF: GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON); return Parse_Path(lex, false, generic_mode); - + case TOK_RWORD_SUPER: { GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON); unsigned int count = 1; @@ -38,10 +38,10 @@ AST::Path Parse_Path(TokenStream& lex, eParsePathGenericMode generic_mode) } return AST::Path(AST::Path::TagSuper(), count, Parse_PathNodes(lex, generic_mode)); } - + case TOK_DOUBLE_COLON: return Parse_Path(lex, true, generic_mode); - + case TOK_DOUBLE_LT: lex.putback( Token(TOK_LT) ); case TOK_LT: { @@ -69,7 +69,7 @@ AST::Path Parse_Path(TokenStream& lex, eParsePathGenericMode generic_mode) return AST::Path(AST::Path::TagUfcs(), mv$(ty), AST::Path(), Parse_PathNodes(lex, generic_mode)); } throw ""; } - + default: PUTBACK(tok, lex); return Parse_Path(lex, false, generic_mode); @@ -102,7 +102,7 @@ AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generi ::std::vector<AST::PathNode> Parse_PathNodes(TokenStream& lex, eParsePathGenericMode generic_mode) { TRACE_FUNCTION_F("generic_mode="<<generic_mode); - + Token tok; ::std::vector<AST::PathNode> ret; @@ -122,7 +122,7 @@ AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generi // HACK! Handle breaking << into < < if( tok.type() == TOK_DOUBLE_LT ) lex.putback( Token(TOK_LT) ); - + // Type-mode generics "::path::to::Type<A,B>" params = Parse_Path_GenericList(lex); GET_TOK(tok, lex); @@ -146,7 +146,7 @@ AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generi } while( GET_TOK(tok, lex) == TOK_COMMA ); } CHECK_TOK(tok, TOK_PAREN_CLOSE); - + TypeRef ret_type = TypeRef( TypeRef::TagUnit(), Span(tok.get_pos()) ); if( GET_TOK(tok, lex) == TOK_THINARROW ) { ret_type = Parse_Type(lex, false); @@ -155,14 +155,14 @@ AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generi PUTBACK(tok, lex); } DEBUG("- Fn("<<args<<")->"<<ret_type<<""); - + // Encode into path, by converting Fn(A,B)->C into Fn<(A,B),Ret=C> 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) ) ) }; - + GET_TOK(tok, lex); } else @@ -179,7 +179,7 @@ AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generi // HACK! Handle breaking << into < < if( tok.type() == TOK_DOUBLE_LT ) lex.putback( Token(TOK_LT) ); - + // Expr-mode generics "::path::to::function::<Type1,Type2>(arg1, arg2)" params = Parse_Path_GenericList(lex); if( GET_TOK(tok, lex) != TOK_DOUBLE_COLON ) { @@ -205,7 +205,7 @@ AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generi ::std::vector<TypeRef> types; ::std::vector< ::std::string> lifetimes; ::std::vector< ::std::pair< ::std::string, 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 ) { GET_TOK(tok, lex); @@ -244,7 +244,7 @@ AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generi else { CHECK_TOK(tok, TOK_GT); } - + return ::AST::PathParams { mv$( lifetimes ), mv$( types ), diff --git a/src/parse/pattern.cpp b/src/parse/pattern.cpp index b0149ddb..699e7fae 100644 --- a/src/parse/pattern.cpp +++ b/src/parse/pattern.cpp @@ -42,7 +42,7 @@ AST::Pattern Parse_Pattern(TokenStream& lex, bool is_refutable) Token tok; tok = lex.getToken(); - + if( tok.type() == TOK_MACRO ) { return AST::Pattern( AST::Pattern::TagMacro(), box$(Parse_MacroInvocation(ps, tok.str(), lex))); @@ -51,7 +51,7 @@ AST::Pattern Parse_Pattern(TokenStream& lex, bool is_refutable) { return mv$(tok.frag_pattern()); } - + bool expect_bind = false; auto bind_type = AST::PatternBinding::Type::MOVE; bool is_mut = false; @@ -80,7 +80,7 @@ AST::Pattern Parse_Pattern(TokenStream& lex, bool is_refutable) { // Fall through } - + AST::PatternBinding binding; // If a 'ref' or 'mut' annotation was seen, the next name must be a binding name if( expect_bind ) @@ -94,7 +94,7 @@ AST::Pattern Parse_Pattern(TokenStream& lex, bool is_refutable) return AST::Pattern(AST::Pattern::TagBind(), mv$(bind_name), bind_type, is_mut); } binding = AST::PatternBinding( mv$(bind_name), bind_type, is_mut ); - + // '@' consumed, move on to next token GET_TOK(tok, lex); } @@ -138,7 +138,7 @@ AST::Pattern Parse_Pattern(TokenStream& lex, bool is_refutable) { // Otherwise, fall through } - + PUTBACK(tok, lex); auto pat = Parse_PatternReal(lex, is_refutable); pat.binding() = mv$(binding); @@ -159,13 +159,13 @@ AST::Pattern Parse_PatternReal(TokenStream& lex, bool is_refutable) if( !ret.data().is_Value() ) throw ParseError::Generic(lex, "Using '...' with a non-value on left"); auto& ret_v = ret.data().as_Value(); - + auto right_pat = Parse_PatternReal1(lex, is_refutable); if( !right_pat.data().is_Value() ) throw ParseError::Generic(lex, "Using '...' with a non-value on right"); auto rightval = mv$( right_pat.data().as_Value().start ); ret_v.end = mv$(rightval); - + return ret; } else @@ -177,10 +177,10 @@ AST::Pattern Parse_PatternReal(TokenStream& lex, bool is_refutable) AST::Pattern Parse_PatternReal1(TokenStream& lex, bool is_refutable) { TRACE_FUNCTION; - + Token tok; AST::Path path; - + switch( GET_TOK(tok, lex) ) { case TOK_UNDERSCORE: @@ -260,7 +260,7 @@ AST::Pattern Parse_PatternReal1(TokenStream& lex, bool is_refutable) TODO(lex.getPosition(), "Convert :expr into a pattern value - " << *e); } } break; - + case TOK_PAREN_OPEN: return AST::Pattern( AST::Pattern::TagTuple(), Parse_PatternTuple(lex, is_refutable) ); case TOK_SQUARE_OPEN: @@ -272,7 +272,7 @@ AST::Pattern Parse_PatternReal1(TokenStream& lex, bool is_refutable) AST::Pattern Parse_PatternReal_Path(TokenStream& lex, AST::Path path, bool is_refutable) { Token tok; - + switch( GET_TOK(tok, lex) ) { case TOK_PAREN_OPEN: @@ -289,12 +289,12 @@ AST::Pattern Parse_PatternReal_Slice(TokenStream& lex, bool is_refutable) { auto sp = lex.start_span(); Token tok; - + ::std::vector< ::AST::Pattern> leading; ::std::vector< ::AST::Pattern> trailing; ::AST::PatternBinding inner_binding; bool is_split = false; - + while(GET_TOK(tok, lex) != TOK_SQUARE_CLOSE) { bool has_binding = true; @@ -316,11 +316,11 @@ AST::Pattern Parse_PatternReal_Slice(TokenStream& lex, bool is_refutable) else { has_binding = false; } - + if( has_binding ) { if(is_split) ERROR(lex.end_span(sp), E0000, "Multiple instances of .. in a slice pattern"); - + inner_binding = mv$(binding); is_split = true; GET_TOK(tok, lex); // TOK_DOUBLE_DOT @@ -334,12 +334,12 @@ AST::Pattern Parse_PatternReal_Slice(TokenStream& lex, bool is_refutable) trailing.push_back( Parse_Pattern(lex, is_refutable) ); } } - + if( GET_TOK(tok, lex) != TOK_COMMA ) break; } CHECK_TOK(tok, TOK_SQUARE_CLOSE); - + if( is_split ) { return ::AST::Pattern( ::AST::Pattern::Data::make_SplitSlice({ mv$(leading), mv$(inner_binding), mv$(trailing) }) ); @@ -357,34 +357,34 @@ AST::Pattern Parse_PatternReal_Slice(TokenStream& lex, bool is_refutable) TRACE_FUNCTION; auto sp = lex.start_span(); Token tok; - + ::std::vector<AST::Pattern> leading; while( LOOK_AHEAD(lex) != TOK_PAREN_CLOSE && LOOK_AHEAD(lex) != TOK_DOUBLE_DOT ) { leading.push_back( Parse_Pattern(lex, is_refutable) ); - + if( GET_TOK(tok, lex) != TOK_COMMA ) { CHECK_TOK(tok, TOK_PAREN_CLOSE); return AST::Pattern::TuplePat { mv$(leading), false, {} }; } } - + if( LOOK_AHEAD(lex) != TOK_DOUBLE_DOT ) { GET_TOK(tok, lex); - + CHECK_TOK(tok, TOK_PAREN_CLOSE); return AST::Pattern::TuplePat { mv$(leading), false, {} }; } GET_CHECK_TOK(tok, lex, TOK_DOUBLE_DOT); - + ::std::vector<AST::Pattern> trailing; if( GET_TOK(tok, lex) == TOK_COMMA ) { while( LOOK_AHEAD(lex) != TOK_PAREN_CLOSE ) { trailing.push_back( Parse_Pattern(lex, is_refutable) ); - + if( GET_TOK(tok, lex) != TOK_COMMA ) { PUTBACK(tok, lex); break; @@ -392,7 +392,7 @@ AST::Pattern Parse_PatternReal_Slice(TokenStream& lex, bool is_refutable) } GET_TOK(tok, lex); } - + CHECK_TOK(tok, TOK_PAREN_CLOSE); return ::AST::Pattern::TuplePat { mv$(leading), true, mv$(trailing) }; } @@ -401,7 +401,7 @@ AST::Pattern Parse_PatternStruct(TokenStream& lex, AST::Path path, bool is_refut { TRACE_FUNCTION; Token tok; - + // #![feature(relaxed_adts)] if( LOOK_AHEAD(lex) == TOK_INTEGER ) { @@ -415,7 +415,7 @@ AST::Pattern Parse_PatternStruct(TokenStream& lex, AST::Path path, bool is_refut if( ! pats.insert( ::std::make_pair(ofs, mv$(val)) ).second ) { ERROR(lex.getPosition(), E0000, "Duplicate index"); } - + if( GET_TOK(tok,lex) == TOK_BRACE_CLOSE ) break; CHECK_TOK(tok, TOK_COMMA); @@ -425,7 +425,7 @@ AST::Pattern Parse_PatternStruct(TokenStream& lex, AST::Path path, bool is_refut GET_TOK(tok, lex); } CHECK_TOK(tok, TOK_BRACE_CLOSE); - + bool has_split = false; ::std::vector<AST::Pattern> leading; ::std::vector<AST::Pattern> trailing; @@ -447,10 +447,10 @@ AST::Pattern Parse_PatternStruct(TokenStream& lex, AST::Path path, bool is_refut } i ++; } - + return AST::Pattern(AST::Pattern::TagNamedTuple(), mv$(path), AST::Pattern::TuplePat { mv$(leading), has_split, mv$(trailing) }); } - + bool is_exhaustive = true; ::std::vector< ::std::pair< ::std::string, AST::Pattern> > subpats; do { @@ -463,7 +463,7 @@ AST::Pattern Parse_PatternStruct(TokenStream& lex, AST::Path path, bool is_refut GET_TOK(tok, lex); break; } - + bool is_short_bind = false; bool is_box = false; auto bind_type = AST::PatternBinding::Type::MOVE; @@ -489,12 +489,12 @@ AST::Pattern Parse_PatternStruct(TokenStream& lex, AST::Path path, bool is_refut is_short_bind = true; GET_TOK(tok, lex); } - + CHECK_TOK(tok, TOK_IDENT); auto field_ident = lex.get_ident(mv$(tok)); ::std::string field_name; GET_TOK(tok, lex); - + AST::Pattern pat; if( is_short_bind || tok.type() != TOK_COLON ) { PUTBACK(tok, lex); @@ -511,11 +511,11 @@ AST::Pattern Parse_PatternStruct(TokenStream& lex, AST::Path path, bool is_refut field_name = mv$(field_ident.name); pat = Parse_Pattern(lex, is_refutable); } - + subpats.push_back( ::std::make_pair(mv$(field_name), mv$(pat)) ); } while( GET_TOK(tok, lex) == TOK_COMMA ); CHECK_TOK(tok, TOK_BRACE_CLOSE); - + return AST::Pattern(AST::Pattern::TagStruct(), ::std::move(path), ::std::move(subpats), is_exhaustive); } diff --git a/src/parse/root.cpp b/src/parse/root.cpp index 5a244543..e5f5b5f4 100644 --- a/src/parse/root.cpp +++ b/src/parse/root.cpp @@ -1,1879 +1,1879 @@ -/*
- * MRustC - Rust Compiler
- * - By John Hodge (Mutabah/thePowersGang)
- *
- * parse/root.cpp
- * - Parsing at the module level (highest-level parsing)
- *
- * Entrypoint:
- * - Parse_Crate : Handles crate attrbutes, and passes on to Parse_ModRoot
- * - Parse_ModRoot
- */
-#include <ast/ast.hpp>
-#include <ast/crate.hpp>
-#include "parseerror.hpp"
-#include "common.hpp"
-#include <cassert>
-#include <hir/hir.hpp> // ABI_RUST - TODO: Move elsewhere?
-#include <expand/cfg.hpp> // check_cfg - for `mod nonexistant;`
-#include <fstream> // Used by directory path
-#include "lex.hpp" // New file lexer
-
-template<typename T>
-Spanned<T> get_spanned(TokenStream& lex, ::std::function<T()> f) {
- auto ps = lex.start_span();
- auto v = f();
- return Spanned<T> {
- lex.end_span(ps),
- mv$(v)
- };
-}
-#define GET_SPANNED(type, lex, val) get_spanned< type >(lex, [&](){ return val; })
-
-// Check the next two tokens
-#define LOOKAHEAD2(lex, tok1, tok2) ((lex).lookahead(0) == (tok1) && (lex).lookahead(1) == (tok2))
-
-::std::string dirname(::std::string input) {
- while( input.size() > 0 && input.back() != '/' ) {
- input.pop_back();
- }
- return input;
-}
-
-AST::MetaItem Parse_MetaItem(TokenStream& lex);
-void Parse_ModRoot(TokenStream& lex, AST::Module& mod, AST::MetaItems& mod_attrs);
-
-::std::vector< ::std::string> Parse_HRB(TokenStream& lex)
-{
- TRACE_FUNCTION;
- Token tok;
-
- ::std::vector< ::std::string> lifetimes;
- GET_CHECK_TOK(tok, lex, TOK_LT);
- do {
- GET_TOK(tok, lex);
-
- ::AST::MetaItems attrs;
- while(tok.type() == TOK_ATTR_OPEN)
- {
- attrs.push_back( Parse_MetaItem(lex) );
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- GET_TOK(tok, lex);
- }
- (void)attrs; // TODO: Attributes on generic params
-
- switch(tok.type())
- {
- case TOK_LIFETIME:
- lifetimes.push_back(tok.str());
- break;
- default:
- throw ParseError::Unexpected(lex, tok, Token(TOK_LIFETIME));
- }
- } while( GET_TOK(tok, lex) == TOK_COMMA );
- CHECK_TOK(tok, TOK_GT);
- return lifetimes;
-}
-/// Parse type parameters in a definition
-void Parse_TypeBound(TokenStream& lex, AST::GenericParams& ret, TypeRef checked_type, ::std::vector< ::std::string> lifetimes = {})
-{
- TRACE_FUNCTION;
- Token tok;
-
- do
- {
- ::std::vector< ::std::string> hrls;
- if(GET_TOK(tok, lex) == TOK_LIFETIME) {
- ret.add_bound(AST::GenericBound::make_TypeLifetime( {
- checked_type.clone(), tok.str()
- } ));
- }
- else if( tok.type() == TOK_QMARK ) {
- ret.add_bound(AST::GenericBound::make_MaybeTrait( {
- checked_type.clone(), Parse_Path(lex, PATH_GENERIC_TYPE)
- } ));
- }
- else {
- if( tok.type() == TOK_RWORD_FOR )
- {
- hrls = Parse_HRB(lex);
- }
- else {
- PUTBACK(tok, lex);
- }
- (void)hrls; // TODO: HRLs
-
- ret.add_bound( AST::GenericBound::make_IsTrait({
- checked_type.clone(), mv$(lifetimes), Parse_Path(lex, PATH_GENERIC_TYPE)
- }) );
- }
- } while( GET_TOK(tok, lex) == TOK_PLUS );
- PUTBACK(tok, lex);
-}
-
-/// Parse type parameters within '<' and '>' (definition)
-AST::GenericParams Parse_GenericParams(TokenStream& lex)
-{
- TRACE_FUNCTION;
-
- AST::GenericParams ret;
- Token tok;
- do {
- if( GET_TOK(tok, lex) == TOK_GT ) {
- break ;
- }
-
- ::AST::MetaItems attrs;
- while(tok.type() == TOK_ATTR_OPEN)
- {
- attrs.push_back( Parse_MetaItem(lex) );
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- GET_TOK(tok, lex);
- }
- (void)attrs; // TODO: Attributes on generic params
-
- if( tok.type() == TOK_IDENT )
- {
- // TODO: Hygine
- ::std::string param_name = mv$(tok.str());
- ret.add_ty_param( AST::TypeParam( param_name ) );
-
- auto param_ty = TypeRef(lex.getPosition(), param_name);
- if( GET_TOK(tok, lex) == TOK_COLON )
- {
- Parse_TypeBound(lex, ret, mv$(param_ty));
- GET_TOK(tok, lex);
- }
-
- if( tok.type() == TOK_EQUAL )
- {
- ret.ty_params().back().setDefault( Parse_Type(lex) );
- GET_TOK(tok, lex);
- }
- }
- else if( tok.type() == TOK_LIFETIME )
- {
- // TODO: Should lifetimes have hygine?
- ::std::string param_name = tok.str();
- ret.add_lft_param( param_name );
- if( GET_TOK(tok, lex) == TOK_COLON )
- {
- do {
- GET_CHECK_TOK(tok, lex, TOK_LIFETIME);
- ret.add_bound(AST::GenericBound::make_Lifetime( {param_name, tok.str()} ));
- } while( GET_TOK(tok, lex) == TOK_PLUS );
- }
- }
- else
- {
- throw ParseError::Unexpected(lex, tok, {TOK_IDENT, TOK_LIFETIME});
- }
- } while( tok.type() == TOK_COMMA );
- PUTBACK(tok, lex);
- return ret;
-}
-
-
-/// Parse the contents of a 'where' clause
-void Parse_WhereClause(TokenStream& lex, AST::GenericParams& params)
-{
- TRACE_FUNCTION;
- Token tok;
-
- do {
- GET_TOK(tok, lex);
- if( tok.type() == TOK_BRACE_OPEN ) {
- break;
- }
-
- if( tok.type() == TOK_LIFETIME )
- {
- auto lhs = mv$(tok.str());
- GET_CHECK_TOK(tok, lex, TOK_COLON);
- do {
- GET_CHECK_TOK(tok, lex, TOK_LIFETIME);
- auto rhs = mv$(tok.str());
- params.add_bound( AST::GenericBound::make_Lifetime({lhs, rhs}) );
- } while( GET_TOK(tok, lex) == TOK_PLUS );
- PUTBACK(tok, lex);
- }
- // Higher-ranked types/lifetimes
- else if( tok.type() == TOK_RWORD_FOR )
- {
- ::std::vector< ::std::string> lifetimes = Parse_HRB(lex);
-
- TypeRef type = Parse_Type(lex);
- GET_CHECK_TOK(tok, lex, TOK_COLON);
- Parse_TypeBound(lex,params, mv$(type), mv$(lifetimes));
- }
- else
- {
- PUTBACK(tok, lex);
- TypeRef type = Parse_Type(lex);
- GET_CHECK_TOK(tok, lex, TOK_COLON);
- Parse_TypeBound(lex, params, mv$(type));
- }
- } while( GET_TOK(tok, lex) == TOK_COMMA );
- PUTBACK(tok, lex);
-}
-
-// Parse a single function argument
-::std::pair< AST::Pattern, TypeRef> Parse_Function_Arg(TokenStream& lex, bool expect_named)
-{
- TRACE_FUNCTION_F("expect_named = " << expect_named);
- Token tok;
-
- AST::Pattern pat;
-
- // If any of the following
- // - Expecting a named parameter (i.e. defining a function in root or impl)
- // - Next token is an underscore (only valid as a pattern here)
- // - Next token is 'mut' (a mutable parameter slot)
- // - Next two are <ident> ':' (a trivial named parameter)
- // NOTE: When not expecting a named param, destructuring patterns are not allowed
- if( expect_named
- || LOOK_AHEAD(lex) == TOK_UNDERSCORE
- || LOOK_AHEAD(lex) == TOK_RWORD_MUT
- || (LOOK_AHEAD(lex) == TOK_IDENT && lex.lookahead(1) == TOK_COLON)
- )
- {
- // Function args can't be refuted
- pat = Parse_Pattern(lex, false);
- GET_CHECK_TOK(tok, lex, TOK_COLON);
- }
-
- TypeRef type = Parse_Type(lex);
-
-
- return ::std::make_pair( ::std::move(pat), ::std::move(type) );
-}
-
-/// Parse a function definition (after the 'fn <name>')
-AST::Function Parse_FunctionDef(TokenStream& lex, ::std::string abi, bool allow_self, bool can_be_prototype, bool is_unsafe, bool is_const)
-{
- TRACE_FUNCTION;
- ProtoSpan ps = lex.start_span();
-
- Token tok;
-
- // Parameters
- AST::GenericParams params;
- if( GET_TOK(tok, lex) == TOK_LT )
- {
- params = Parse_GenericParams(lex);
- GET_CHECK_TOK(tok, lex, TOK_GT);
- }
- else {
- PUTBACK(tok, lex);
- }
-
- AST::Function::Arglist args;
-
- GET_CHECK_TOK(tok, lex, TOK_PAREN_OPEN);
- GET_TOK(tok, lex);
-
- // Handle self
- if( tok.type() == TOK_AMP )
- {
- // By-reference method?
- // TODO: If a lifetime is seen (and not a prototype), it is definitely a self binding
-
- unsigned int ofs = 0;
- if( lex.lookahead(0) == TOK_LIFETIME )
- ofs ++;
-
- if( lex.lookahead(ofs) == TOK_RWORD_SELF || (lex.lookahead(ofs) == TOK_RWORD_MUT && lex.lookahead(ofs+1) == TOK_RWORD_SELF) )
- {
- auto ps = lex.start_span();
- ::std::string lifetime;
- if( GET_TOK(tok, lex) == TOK_LIFETIME ) {
- lifetime = tok.str();
- GET_TOK(tok, lex);
- }
- auto ty_sp = lex.end_span(ps);
-
- if( tok.type() == TOK_RWORD_MUT )
- {
- GET_CHECK_TOK(tok, lex, TOK_RWORD_SELF);
- args.push_back( ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "self"), TypeRef(TypeRef::TagReference(), ty_sp, true, TypeRef(ty_sp, "Self", 0xFFFF))) );
- }
- else
- {
- args.push_back( ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "self"), TypeRef(TypeRef::TagReference(), ty_sp, false, TypeRef(ty_sp, "Self", 0xFFFF))) );
- }
- DEBUG("TODO: UFCS / self lifetimes");
- if( allow_self == false )
- throw ParseError::Generic(lex, "Self binding not expected");
- //args.push_back( ::std::make_pair(
- // AST::Pattern(),
- // TypeRef(TypeRef::TagReference(), lifetime, (fcn_class == AST::Function::CLASS_MUTMETHOD), )
- //) );
-
- // Prime tok for next step
- GET_TOK(tok, lex);
- }
- else
- {
- // Unbound method
- }
- }
- else if( tok.type() == TOK_RWORD_MUT )
- {
- if( LOOK_AHEAD(lex) == TOK_RWORD_SELF )
- {
- GET_TOK(tok, lex);
- if( allow_self == false )
- throw ParseError::Generic(lex, "Self binding not expected");
- TypeRef ty = TypeRef( lex.getPosition(), "Self", 0xFFFF );
- if( GET_TOK(tok, lex) == TOK_COLON ) {
- // Typed mut self
- ty = Parse_Type(lex);
- }
- else {
- PUTBACK(tok, lex);
- }
- args.push_back( ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "self"), mv$(ty)) );
- GET_TOK(tok, lex);
- }
- }
- else if( tok.type() == TOK_RWORD_SELF )
- {
- // By-value method
- if( allow_self == false )
- throw ParseError::Generic(lex, "Self binding not expected");
- TypeRef ty = TypeRef( lex.getPosition(), "Self", 0xFFFF );
- if( GET_TOK(tok, lex) == TOK_COLON ) {
- // Typed mut self
- ty = Parse_Type(lex);
- }
- else {
- PUTBACK(tok, lex);
- }
- args.push_back( ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "self"), mv$(ty)) );
- GET_TOK(tok, lex);
- }
- else
- {
- // Unbound method
- }
-
- bool is_variadic = false;
- if( tok.type() != TOK_PAREN_CLOSE )
- {
- // Comma after self
- if( args.size() )
- {
- CHECK_TOK(tok, TOK_COMMA);
- }
- else {
- PUTBACK(tok, lex);
- }
-
- // Argument list
- do {
- if( LOOK_AHEAD(lex) == TOK_PAREN_CLOSE ) {
- GET_TOK(tok, lex);
- break;
- }
- if( LOOK_AHEAD(lex) == TOK_TRIPLE_DOT ) {
- GET_TOK(tok, lex);
- is_variadic = true;
- GET_TOK(tok, lex);
- break;
- }
- args.push_back( Parse_Function_Arg(lex, !can_be_prototype) );
- } while( GET_TOK(tok, lex) == TOK_COMMA );
- CHECK_TOK(tok, TOK_PAREN_CLOSE);
- }
- else {
- // Eat 'tok', negative comparison
- }
-
- TypeRef ret_type = TypeRef(TypeRef::TagUnit(), Span(tok.get_pos()));
- if( GET_TOK(tok, lex) == TOK_THINARROW )
- {
- // Return type
- ret_type = Parse_Type(lex);
- }
- else
- {
- PUTBACK(tok, lex);
- }
-
- if( GET_TOK(tok, lex) == TOK_RWORD_WHERE )
- {
- Parse_WhereClause(lex, params);
- }
- else {
- PUTBACK(tok, lex);
- }
-
- return AST::Function(lex.end_span(ps), mv$(params), mv$(abi), is_unsafe, is_const, is_variadic, mv$(ret_type), mv$(args));
-}
-
-AST::Function Parse_FunctionDefWithCode(TokenStream& lex, ::std::string abi, bool allow_self, bool is_unsafe, bool is_const)
-{
- Token tok;
- auto ret = Parse_FunctionDef(lex, abi, allow_self, false, is_unsafe, is_const);
- GET_CHECK_TOK(tok, lex, TOK_BRACE_OPEN);
- PUTBACK(tok, lex);
- ret.set_code( Parse_ExprBlock(lex) );
- return ret;
-}
-
-AST::TypeAlias Parse_TypeAlias(TokenStream& lex)
-{
- TRACE_FUNCTION;
-
- Token tok;
-
- // Params
- AST::GenericParams params;
- if( GET_TOK(tok, lex) == TOK_LT )
- {
- params = Parse_GenericParams(lex);
- GET_CHECK_TOK(tok, lex, TOK_GT);
- GET_TOK(tok, lex);
- }
-
- if( tok.type() == TOK_RWORD_WHERE )
- {
- Parse_WhereClause(lex, params);
- GET_TOK(tok, lex);
- }
- CHECK_TOK(tok, TOK_EQUAL);
-
- // Type
- TypeRef type = Parse_Type(lex);
- GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
-
- return AST::TypeAlias( ::std::move(params), ::std::move(type) );
-}
-
-AST::Struct Parse_Struct(TokenStream& lex, const AST::MetaItems& meta_items)
-{
- TRACE_FUNCTION;
-
- Token tok;
-
- tok = lex.getToken();
- AST::GenericParams params;
- if( tok.type() == TOK_LT )
- {
- params = Parse_GenericParams(lex);
- GET_CHECK_TOK(tok, lex, TOK_GT);
- if(GET_TOK(tok, lex) == TOK_RWORD_WHERE)
- {
- Parse_WhereClause(lex, params);
- tok = lex.getToken();
- }
- }
- if(tok.type() == TOK_PAREN_OPEN)
- {
- // Tuple structs
- ::std::vector<AST::TupleItem> refs;
- while(GET_TOK(tok, lex) != TOK_PAREN_CLOSE)
- {
- AST::MetaItems item_attrs;
- while( tok.type() == TOK_ATTR_OPEN )
- {
- item_attrs.push_back( Parse_MetaItem(lex) );
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- GET_TOK(tok, lex);
- }
- SET_ATTRS(lex, item_attrs);
-
- bool is_pub = false;
- if(tok.type() == TOK_RWORD_PUB)
- is_pub = true;
- else
- PUTBACK(tok, lex);
-
- refs.push_back( AST::TupleItem( mv$(item_attrs), is_pub, Parse_Type(lex) ) );
- if( GET_TOK(tok, lex) != TOK_COMMA )
- break;
- }
- CHECK_TOK(tok, TOK_PAREN_CLOSE);
-
- if(LOOK_AHEAD(lex) == TOK_RWORD_WHERE)
- {
- GET_TOK(tok, lex);
- Parse_WhereClause(lex, params);
- }
- GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
- //if( refs.size() == 0 )
- // WARNING( , W000, "Use 'struct Name;' instead of 'struct Name();' ... ning-nong");
- return AST::Struct(mv$(params), mv$(refs));
- }
- else if(tok.type() == TOK_SEMICOLON)
- {
- // Unit-like struct
- return AST::Struct(mv$(params), ::std::vector<AST::TupleItem>());
- }
- else if(tok.type() == TOK_BRACE_OPEN)
- {
- ::std::vector<AST::StructItem> items;
- while( GET_TOK(tok, lex) != TOK_BRACE_CLOSE )
- {
- AST::MetaItems item_attrs;
- while( tok.type() == TOK_ATTR_OPEN )
- {
- item_attrs.push_back( Parse_MetaItem(lex) );
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- GET_TOK(tok, lex);
- }
- SET_ATTRS(lex, item_attrs);
-
- bool is_pub = false;
- if(tok.type() == TOK_RWORD_PUB) {
- is_pub = true;
- GET_TOK(tok, lex);
- }
-
- CHECK_TOK(tok, TOK_IDENT);
- auto name = mv$(tok.str());
- GET_CHECK_TOK(tok, lex, TOK_COLON);
- TypeRef type = Parse_Type(lex);
-
- items.push_back( AST::StructItem( mv$(item_attrs), is_pub, mv$(name), mv$(type) ) );
- if(GET_TOK(tok, lex) == TOK_BRACE_CLOSE)
- break;
- CHECK_TOK(tok, TOK_COMMA);
- }
- //if( items.size() == 0 )
- // WARNING( , W000, "Use 'struct Name;' instead of 'struct Nam { };' ... ning-nong");
- return AST::Struct(::std::move(params), ::std::move(items));
- }
- else
- {
- throw ParseError::Unexpected(lex, tok);
- }
-}
-
-AST::Trait Parse_TraitDef(TokenStream& lex, const AST::MetaItems& meta_items)
-{
- TRACE_FUNCTION;
-
- Token tok;
-
- AST::GenericParams params;
- if( GET_TOK(tok, lex) == TOK_LT )
- {
- params = Parse_GenericParams(lex);
- GET_CHECK_TOK(tok, lex, TOK_GT);
- tok = lex.getToken();
- }
-
- // Trait bounds "trait Trait : 'lifetime + OtherTrait + OtherTrait2"
- ::std::vector<Spanned<AST::Path> > supertraits;
- if(tok.type() == TOK_COLON)
- {
- do {
- if( GET_TOK(tok, lex) == TOK_LIFETIME ) {
- // TODO: Need a better way of indiciating 'static than just an invalid path
- supertraits.push_back( make_spanned( Span(tok.get_pos()), AST::Path() ) );
- }
- else {
- PUTBACK(tok, lex);
- supertraits.push_back( GET_SPANNED(::AST::Path, lex, Parse_Path(lex, PATH_GENERIC_TYPE)) );
- }
- } while( GET_TOK(tok, lex) == TOK_PLUS );
- }
-
- // TODO: Support "for Sized?"
- if(tok.type() == TOK_RWORD_WHERE)
- {
- //if( params.ty_params().size() == 0 )
- // throw ParseError::Generic("Where clause with no generic params");
- Parse_WhereClause(lex, params);
- tok = lex.getToken();
- }
-
-
- AST::Trait trait( mv$(params), mv$(supertraits) );
-
- CHECK_TOK(tok, TOK_BRACE_OPEN);
- while( GET_TOK(tok, lex) != TOK_BRACE_CLOSE )
- {
-
- AST::MetaItems item_attrs;
- while( tok.type() == TOK_ATTR_OPEN )
- {
- item_attrs.push_back( Parse_MetaItem(lex) );
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- GET_TOK(tok, lex);
- }
- SET_ATTRS(lex, item_attrs);
-
- auto ps = lex.start_span();
- if( tok.type() == TOK_MACRO ) {
- auto inv = Parse_MacroInvocation( ps, mv$(tok.str()), lex );
- // - Silently consume ';' after the macro
- if( GET_TOK(tok, lex) != TOK_SEMICOLON )
- PUTBACK(tok, lex);
-
- trait.items().push_back( AST::Named<AST::Item>("", AST::Item(mv$(inv)), false) );
- continue ;
- }
-
- 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);
-
- // TODO: Attributes on associated statics
- trait.add_static( mv$(name), ::AST::Static(AST::Static::STATIC, mv$(ty), val)/*, mv$(item_attrs)*/ );
- 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);
-
- // TODO: Attributes on associated constants
- trait.add_static( mv$(name), ::AST::Static(AST::Static::CONST, mv$(ty), val)/*, mv$(item_attrs)*/ );
- 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.getPosition(), "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.getPosition() );
- 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), ::std::move(default_type) );
- trait.items().back().data.as_Type().params() = mv$(atype_params);
- break; }
-
- // Functions (possibly unsafe)
- // TODO: Const?
- 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);
- fcn.set_code( Parse_ExprBlock(lex) );
- }
- else if( tok.type() == TOK_SEMICOLON )
- {
- // Accept it
- }
- else
- {
- throw ParseError::Unexpected(lex, tok);
- }
- // TODO: Store `item_attrs`
- trait.add_function( ::std::move(name), /*mv$(item_attrs),*/ ::std::move(fcn) );
- break; }
- default:
- throw ParseError::Unexpected(lex, tok);
- }
- }
-
- return trait;
-}
-
-AST::Enum Parse_EnumDef(TokenStream& lex, const AST::MetaItems& meta_items)
-{
- TRACE_FUNCTION;
-
- Token tok;
-
- tok = lex.getToken();
- // Type params supporting "where"
- AST::GenericParams params;
- if( tok.type() == TOK_LT )
- {
- params = Parse_GenericParams(lex);
- GET_CHECK_TOK(tok, lex, TOK_GT);
- if(GET_TOK(tok, lex) == TOK_RWORD_WHERE)
- {
- Parse_WhereClause(lex, params);
- tok = lex.getToken();
- }
- }
-
- // Body
- CHECK_TOK(tok, TOK_BRACE_OPEN);
- ::std::vector<AST::EnumVariant> variants;
- while( GET_TOK(tok, lex) != TOK_BRACE_CLOSE )
- {
- auto sp = lex.start_span();
-
- AST::MetaItems item_attrs;
- while( tok.type() == TOK_ATTR_OPEN )
- {
- item_attrs.push_back( Parse_MetaItem(lex) );
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- GET_TOK(tok, lex);
- }
- SET_ATTRS(lex, item_attrs);
-
- CHECK_TOK(tok, TOK_IDENT);
- ::std::string name = mv$(tok.str());
- if( GET_TOK(tok, lex) == TOK_PAREN_OPEN )
- {
- ::std::vector<TypeRef> types;
- // Get type list
- do
- {
- if(LOOK_AHEAD(lex) == TOK_PAREN_CLOSE)
- {
- GET_TOK(tok, lex);
- break;
- }
-
- AST::MetaItems field_attrs;
- while( LOOK_AHEAD(lex) == TOK_ATTR_OPEN )
- {
- GET_TOK(tok, lex);
- field_attrs.push_back( Parse_MetaItem(lex) );
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- }
-
- types.push_back( Parse_Type(lex) );
- } while( GET_TOK(tok, lex) == TOK_COMMA );
- CHECK_TOK(tok, TOK_PAREN_CLOSE);
- GET_TOK(tok, lex);
- variants.push_back( AST::EnumVariant(mv$(item_attrs), mv$(name), mv$(types)) );
- }
- else if( tok.type() == TOK_BRACE_OPEN )
- {
- ::std::vector<::AST::StructItem> fields;
- do
- {
- if(LOOK_AHEAD(lex) == TOK_BRACE_CLOSE)
- {
- GET_TOK(tok, lex);
- break;
- }
-
- AST::MetaItems field_attrs;
- while( LOOK_AHEAD(lex) == TOK_ATTR_OPEN )
- {
- GET_TOK(tok, lex);
- field_attrs.push_back( Parse_MetaItem(lex) );
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- }
-
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = mv$(tok.str());
- 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)) );
- } while( GET_TOK(tok, lex) == TOK_COMMA );
- CHECK_TOK(tok, TOK_BRACE_CLOSE);
- GET_TOK(tok, lex);
-
- variants.push_back( AST::EnumVariant(mv$(item_attrs), mv$(name), mv$(fields)) );
- }
- else if( tok.type() == TOK_EQUAL )
- {
- auto node = Parse_Expr(lex);
- variants.push_back( AST::EnumVariant(mv$(item_attrs), mv$(name), mv$(node)) );
- GET_TOK(tok, lex);
- }
- else
- {
- variants.push_back( AST::EnumVariant(mv$(item_attrs), mv$(name), ::AST::Expr()) );
- }
-
- if( tok.type() != TOK_COMMA )
- break;
- }
- CHECK_TOK(tok, TOK_BRACE_CLOSE);
-
-
- return AST::Enum( mv$(params), mv$(variants) );
-}
-
-::AST::Union Parse_Union(TokenStream& lex, AST::MetaItems& meta_items)
-{
- Token tok;
-
- TRACE_FUNCTION;
-
- AST::GenericParams params;
- if( GET_TOK(tok, lex) == TOK_LT )
- {
- params = Parse_GenericParams(lex);
- GET_CHECK_TOK(tok, lex, TOK_GT);
- if(GET_TOK(tok, lex) == TOK_RWORD_WHERE)
- {
- Parse_WhereClause(lex, params);
- tok = lex.getToken();
- }
- }
-
- ::std::vector< ::AST::StructItem> variants;
-
- CHECK_TOK(tok, TOK_BRACE_OPEN);
- do {
- if( LOOK_AHEAD(lex) == TOK_BRACE_CLOSE ) {
- GET_TOK(tok, lex);
- break ;
- }
-
- AST::MetaItems item_attrs;
- while( LOOK_AHEAD(lex) == TOK_ATTR_OPEN )
- {
- GET_TOK(tok, lex);
- item_attrs.push_back( Parse_MetaItem(lex) );
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- }
- SET_ATTRS(lex, item_attrs);
-
- bool is_pub = false;
- if( LOOK_AHEAD(lex) == TOK_RWORD_PUB ) {
- is_pub = true;
- GET_TOK(tok, lex);
- }
-
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = mv$(tok.str());
- GET_CHECK_TOK(tok, lex, TOK_COLON);
-
- auto ty = Parse_Type(lex);
-
- variants.push_back( ::AST::StructItem( mv$(item_attrs), is_pub, mv$(name), mv$(ty) ) );
-
- } while( GET_TOK(tok, lex) == TOK_COMMA );
- CHECK_TOK(tok, TOK_BRACE_CLOSE);
-
- return ::AST::Union( mv$(params), mv$(variants) );
-}
-
-/// Parse a meta-item declaration (either #![ or #[)
-AST::MetaItem Parse_MetaItem(TokenStream& lex)
-{
- TRACE_FUNCTION;
- Token tok;
- GET_TOK(tok, lex);
-
- if( tok.type() == TOK_INTERPOLATED_META ) {
- return mv$(tok.frag_meta());
- }
-
- CHECK_TOK(tok, TOK_IDENT);
- ::std::string name = mv$(tok.str());
- switch(GET_TOK(tok, lex))
- {
- case TOK_EQUAL:
- GET_CHECK_TOK(tok, lex, TOK_STRING);
- return AST::MetaItem(name, tok.str());
- case TOK_PAREN_OPEN: {
- ::std::vector<AST::MetaItem> items;
- do {
- if(LOOK_AHEAD(lex) == TOK_PAREN_CLOSE) {
- GET_TOK(tok, lex);
- break;
- }
- items.push_back(Parse_MetaItem(lex));
- } while(GET_TOK(tok, lex) == TOK_COMMA);
- CHECK_TOK(tok, TOK_PAREN_CLOSE);
- return AST::MetaItem(name, mv$(items)); }
- default:
- PUTBACK(tok, lex);
- return AST::MetaItem(name);
- }
-}
-
-::AST::Item Parse_Impl(TokenStream& lex, AST::MetaItems attrs, bool is_unsafe=false)
-{
- TRACE_FUNCTION;
- Token tok;
- auto ps = lex.start_span();
-
- AST::GenericParams params;
- // 1. (optional) type parameters
- if( GET_TOK(tok, lex) == TOK_LT )
- {
- params = Parse_GenericParams(lex);
- GET_CHECK_TOK(tok, lex, TOK_GT);
- }
- else {
- PUTBACK(tok, lex);
- }
- // 2. Either a trait name (with type params), or the type to impl
-
- Spanned<AST::Path> trait_path;
-
- // - Handle negative impls specially, which must be a trait
- // "impl !Trait for Type {}"
- if( GET_TOK(tok, lex) == TOK_EXCLAM )
- {
- trait_path = GET_SPANNED(::AST::Path, lex, Parse_Path(lex, PATH_GENERIC_TYPE));
- GET_CHECK_TOK(tok, lex, TOK_RWORD_FOR);
- auto impl_type = Parse_Type(lex, true);
-
- if( GET_TOK(tok, lex) == TOK_RWORD_WHERE )
- {
- Parse_WhereClause(lex, params);
- GET_TOK(tok, lex);
- }
- CHECK_TOK(tok, TOK_BRACE_OPEN);
- // negative impls can't have any content
- GET_CHECK_TOK(tok, lex, TOK_BRACE_CLOSE);
-
- return ::AST::Item::make_NegImpl( AST::ImplDef(lex.end_span(ps), mv$(attrs), mv$(params), mv$(trait_path), mv$(impl_type) ) );
- }
-
- // - Don't care which at this stage
- PUTBACK(tok, lex);
-
- auto impl_type = Parse_Type(lex, true);
-
- if( GET_TOK(tok, lex) == TOK_RWORD_FOR )
- {
- // Trickery! All traits parse as valid types, so this works.
- if( !impl_type.is_path() )
- throw ParseError::Generic(lex, "Trait was not a path");
- trait_path = Spanned< AST::Path> {
- impl_type.span(),
- mv$(impl_type.path())
- };
- // Implementing a trait for another type, get the target type
- if( GET_TOK(tok, lex) == TOK_DOUBLE_DOT )
- {
- // Default impl
- impl_type = TypeRef(TypeRef::TagInvalid(), lex.getPosition());
- }
- else
- {
- PUTBACK(tok, lex);
- impl_type = Parse_Type(lex, true);
- }
- }
- else {
- PUTBACK(tok, lex);
- }
-
- // Where clause
- if( GET_TOK(tok, lex) == TOK_RWORD_WHERE )
- {
- Parse_WhereClause(lex, params);
- }
- else {
- PUTBACK(tok, lex);
- }
- GET_CHECK_TOK(tok, lex, TOK_BRACE_OPEN);
-
- while( LOOK_AHEAD(lex) == TOK_CATTR_OPEN )
- {
- GET_TOK(tok, lex);
- attrs.push_back( Parse_MetaItem(lex) );
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- }
-
- AST::Impl impl( AST::ImplDef( lex.end_span(ps), mv$(attrs), mv$(params), mv$(trait_path), mv$(impl_type) ) );
-
- // A sequence of method implementations
- while( GET_TOK(tok, lex) != TOK_BRACE_CLOSE )
- {
- auto ps = lex.start_span();
- if( tok.type() == TOK_MACRO )
- {
- impl.add_macro_invocation( Parse_MacroInvocation( ps, mv$(tok.str()), lex ) );
- // - Silently consume ';' after the macro
- if( GET_TOK(tok, lex) != TOK_SEMICOLON )
- PUTBACK(tok, lex);
- }
- else
- {
- PUTBACK(tok, lex);
- Parse_Impl_Item(lex, impl);
- }
- }
-
- return ::AST::Item::make_Impl( mv$(impl) );
-}
-
-void Parse_Impl_Item(TokenStream& lex, AST::Impl& impl)
-{
- TRACE_FUNCTION;
- Token tok;
-
- GET_TOK(tok, lex);
-
- AST::MetaItems item_attrs;
- while( tok.type() == TOK_ATTR_OPEN )
- {
- item_attrs.push_back( Parse_MetaItem(lex) );
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- GET_TOK(tok, lex);
- }
- SET_ATTRS(lex, item_attrs);
-
- auto ps = lex.start_span();
-
- bool is_public = false;
- if(tok.type() == TOK_RWORD_PUB) {
- is_public = true;
- GET_TOK(tok, lex);
- }
-
- bool is_specialisable = false;
- if( tok.type() == TOK_IDENT && tok.str() == "default" ) {
- is_specialisable = true;
- GET_TOK(tok, lex);
- }
-
- ::std::string abi = ABI_RUST;
- bool fn_is_unsafe = false;
- bool fn_is_const = false;
- switch(tok.type())
- {
- case TOK_RWORD_TYPE: {
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = mv$(tok.str());
- 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);
- break; }
- case TOK_RWORD_UNSAFE:
- fn_is_unsafe = true;
- GET_TOK(tok, lex);
- if( tok.type() == TOK_RWORD_CONST )
- case TOK_RWORD_CONST:
- {
- GET_TOK(tok, lex);
- if( tok.type() != TOK_RWORD_FN && tok.type() != TOK_RWORD_UNSAFE && !fn_is_unsafe )
- {
- CHECK_TOK(tok, 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_EQUAL);
- auto val = Parse_Expr(lex);
- GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
-
- auto i = ::AST::Static(AST::Static::CONST, mv$(ty), mv$(val));
- // TODO: Attributes on associated constants
- impl.add_static( is_public, is_specialisable, mv$(name), mv$(i) /*, mv$(item_attrs)*/ );
- break ;
- }
- else if( tok.type() == TOK_RWORD_UNSAFE )
- {
- fn_is_unsafe = true;
- GET_CHECK_TOK(tok, lex, TOK_RWORD_FN);
- }
- fn_is_const = true;
- }
- if( tok.type() == TOK_RWORD_EXTERN )
- // FALL
- 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);
- // FALL
- 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());
- DEBUG("Function " << name);
- // - Self allowed, can't be prototype-form
- auto fcn = Parse_FunctionDefWithCode(lex, abi, true, fn_is_unsafe, fn_is_const);
- impl.add_function(is_public, is_specialisable, mv$(name), mv$(fcn));
- break; }
-
- default:
- throw ParseError::Unexpected(lex, tok);
- }
-
- impl.items().back().data->span = lex.end_span(ps);
- impl.items().back().data->attrs = mv$(item_attrs); // Empty for functions
-}
-
-AST::ExternBlock Parse_ExternBlock(TokenStream& lex, ::std::string abi, ::AST::MetaItems& block_attrs)
-{
- TRACE_FUNCTION;
- Token tok;
-
- while( GET_TOK(tok, lex) == TOK_CATTR_OPEN )
- {
- block_attrs.push_back( Parse_MetaItem(lex) );
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- }
- PUTBACK(tok, lex);
-
- AST::ExternBlock rv { abi };
-
- while( GET_TOK(tok, lex) != TOK_BRACE_CLOSE )
- {
- AST::MetaItems meta_items;
- while( tok.type() == TOK_ATTR_OPEN )
- {
- meta_items.push_back( Parse_MetaItem(lex) );
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- GET_TOK(tok, lex);
- }
- SET_ATTRS(lex, meta_items);
-
- auto ps = lex.start_span();
-
- bool is_public = false;
- if( tok.type() == TOK_RWORD_PUB ) {
- is_public = true;
- GET_TOK(tok, lex);
- }
- switch(tok.type())
- {
- case TOK_RWORD_FN: {
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = mv$(tok.str());
- // 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) );
- GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
-
- i.attrs = mv$(meta_items);
- i.span = lex.end_span(ps);
-
- rv.add_item( AST::Named<AST::Item> { mv$(name), mv$(i), is_public } );
- break; }
- case TOK_RWORD_STATIC: {
- bool is_mut = false;
- if( GET_TOK(tok, lex) == TOK_RWORD_MUT )
- is_mut = true;
- else
- PUTBACK(tok, lex);
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = mv$(tok.str());
- GET_CHECK_TOK(tok, lex, TOK_COLON);
- auto type = Parse_Type(lex);
- GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
-
- auto i = ::AST::Item(::AST::Static( (is_mut ? ::AST::Static::MUT : ::AST::Static::STATIC), mv$(type), ::AST::Expr() ));
- i.attrs = mv$(meta_items);
- i.span = lex.end_span(ps);
- rv.add_item( AST::Named<AST::Item> { mv$(name), mv$(i), is_public } );
- break; }
- default:
- throw ParseError::Unexpected(lex, tok, {TOK_RWORD_FN, TOK_RWORD_STATIC});
- }
- }
-
- return rv;
-}
-
-void Parse_Use_Wildcard(Span sp, AST::Path base_path, ::std::function<void(AST::UseStmt, ::std::string)> fcn)
-{
- 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<void(AST::UseStmt, ::std::string)> 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 {
- CHECK_TOK(tok, TOK_IDENT);
- path = base_path + AST::PathNode(tok.str(), {});
- name = mv$(tok.str());
- }
-
- if( GET_TOK(tok, lex) == TOK_RWORD_AS ) {
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- name = mv$(tok.str());
- }
- else {
- PUTBACK(tok, lex);
- }
- fcn(AST::UseStmt(lex.end_span(ps), mv$(path)), mv$(name));
- } while( GET_TOK(tok, lex) == TOK_COMMA );
- PUTBACK(tok, lex);
-}
-
-void Parse_Use(TokenStream& lex, ::std::function<void(AST::UseStmt, ::std::string)> fcn)
-{
- TRACE_FUNCTION;
-
- Token tok;
- AST::Path path = AST::Path("", {});
- ::std::vector<AST::PathNode> nodes;
- ProtoSpan span_start = lex.start_span();
-
- switch( GET_TOK(tok, lex) )
- {
- case TOK_RWORD_SELF:
- path = AST::Path( AST::Path::TagSelf(), {} ); // relative path
- break;
- case TOK_RWORD_SUPER: {
- unsigned int count = 1;
- while( LOOK_AHEAD(lex) == TOK_DOUBLE_COLON && lex.lookahead(1) == TOK_RWORD_SUPER ) {
- GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON);
- GET_CHECK_TOK(tok, lex, TOK_RWORD_SUPER);
- count += 1;
- }
- path = AST::Path( AST::Path::TagSuper(), count, {} );
- break; }
- case TOK_IDENT:
- path.append( AST::PathNode(mv$(tok.str()), {}) );
- break;
- // Leading :: is allowed and ignored for the $crate feature
- case TOK_DOUBLE_COLON:
- // Absolute path
- // HACK! mrustc emits $crate as `::"crate-name"`
- if( LOOK_AHEAD(lex) == TOK_STRING )
- {
- GET_CHECK_TOK(tok, lex, TOK_STRING);
- path = ::AST::Path(tok.str(), {});
- GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON);
- }
- else {
- PUTBACK(tok, lex);
- }
- break;
- case TOK_BRACE_OPEN:
- Parse_Use_Set(lex, span_start, path, fcn);
- GET_CHECK_TOK(tok, lex, TOK_BRACE_CLOSE);
- return;
- default:
- throw ParseError::Unexpected(lex, tok);
- }
- while( GET_TOK(tok, lex) == TOK_DOUBLE_COLON )
- {
- if( GET_TOK(tok, lex) == TOK_IDENT )
- {
- path.append( AST::PathNode( mv$(tok.str()), {}) );
- }
- else
- {
- //path.set_span( lex.end_span(span_start) );
- switch( tok.type() )
- {
- case TOK_BRACE_OPEN:
- Parse_Use_Set(lex, span_start, mv$(path), fcn);
- GET_CHECK_TOK(tok, lex, TOK_BRACE_CLOSE);
- break ;
- case TOK_STAR:
- Parse_Use_Wildcard( lex.end_span(span_start), mv$(path), fcn );
- break ;
- default:
- throw ParseError::Unexpected(lex, tok);
- }
- // early return - This branch is either the end of the use statement, or a syntax error
- return ;
- }
- }
- //path.set_span( lex.end_span(span_start) );
-
- ::std::string name;
- // This should only be allowed if the last token was an ident
- // - Above checks ensure this
- if( tok.type() == TOK_RWORD_AS )
- {
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- name = mv$(tok.str());
- }
- else
- {
- PUTBACK(tok, lex);
- assert(path.nodes().size() > 0);
- name = path.nodes().back().name();
- }
-
- fcn( AST::UseStmt(lex.end_span(span_start), mv$(path)), name);
-}
-
-
-::AST::MacroInvocation Parse_MacroInvocation(ProtoSpan span_start, ::std::string name, TokenStream& lex)
-{
- Token tok;
- ::std::string ident;
- if( GET_TOK(tok, lex) == TOK_IDENT ) {
- ident = mv$(tok.str());
- }
- else {
- PUTBACK(tok, lex);
- }
- DEBUG("name=" << name << ", ident=" << ident);
- TokenTree tt = Parse_TT(lex, true);
- return ::AST::MacroInvocation( lex.end_span(span_start), mv$(name), mv$(ident), mv$(tt));
-}
-
-::AST::Named<::AST::Item> Parse_Mod_Item_S(TokenStream& lex, const AST::Module::FileInfo& mod_fileinfo, const ::AST::Path& mod_path, AST::MetaItems meta_items)
-{
- TRACE_FUNCTION_F("mod_path="<<mod_path<<", meta_items="<<meta_items);
- Token tok;
-
- while( LOOK_AHEAD(lex) == TOK_ATTR_OPEN /* || LOOKAHEAD2(lex, TOK_HASH, TOK_SQUARE_OPEN) */ )
- {
- // Attributes!
- GET_CHECK_TOK(tok, lex, TOK_ATTR_OPEN);
- meta_items.push_back( Parse_MetaItem(lex) );
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- }
-
- if( LOOK_AHEAD(lex) == TOK_INTERPOLATED_ITEM ) {
- GET_TOK(tok, lex);
- auto rv = tok.take_frag_item();
- // Transfer new attributes onto the item
- for(auto& mi : meta_items.m_items)
- rv.data.attrs.m_items.push_back( mv$(mi) );
- return rv;
- }
-
- auto ps = lex.start_span();
-
- ::std::string item_name;
- ::AST::Item item_data;
-
- if( LOOK_AHEAD(lex) == TOK_MACRO ) {
- GET_TOK(tok, lex);
-
- ::std::string name = mv$(tok.str());
- bool is_braced = (LOOK_AHEAD(lex) == TOK_BRACE_OPEN || LOOKAHEAD2(lex, TOK_IDENT, TOK_BRACE_OPEN));
- item_data = ::AST::Item( Parse_MacroInvocation( ps, mv$(name), lex ) );
-
- if( !is_braced ) {
- // - Consume the ';' after the macro
- GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
- }
-
- item_data.attrs = mv$(meta_items);
- item_data.span = lex.end_span(ps);
-
- return ::AST::Named< ::AST::Item> { "", mv$(item_data), false };
- }
-
- bool is_public = false;
- if( GET_TOK(tok, lex) == TOK_RWORD_PUB ) {
- is_public = true;
- }
- else {
- PUTBACK(tok, lex);
- }
-
- 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.getPosition(), "Encode multi-item use statements as a single Item");
- item_data = ::AST::Item(mv$(p));
- item_name = mv$(s);
- });
- assert( !item_data.is_None() );
- GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
- break;
-
- case TOK_RWORD_EXTERN:
- switch( GET_TOK(tok, lex) )
- {
- // `extern "<ABI>" fn ...`
- // `extern "<ABI>" { ...`
- case TOK_STRING: {
- ::std::string abi = tok.str();
- switch(GET_TOK(tok, lex))
- {
- // `extern "<ABI>" fn ...`
- case TOK_RWORD_FN: {
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
- item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, abi, false, false,false) );
- break; }
- // `extern "ABI" {`
- case TOK_BRACE_OPEN:
- item_name = "";
- item_data = ::AST::Item( Parse_ExternBlock(lex, mv$(abi), meta_items) );
- break;
- default:
- throw ParseError::Unexpected(lex, tok, {TOK_RWORD_FN, TOK_BRACE_OPEN});
- }
- break; }
- // `extern fn ...`
- case TOK_RWORD_FN:
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
- item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, "C", false, false,false) );
- break;
-
- // NOTE: `extern { ...` is handled in caller
- case TOK_BRACE_OPEN:
- item_name = "";
- item_data = ::AST::Item( Parse_ExternBlock(lex, "C", meta_items) );
- break;
-
- // `extern crate "crate-name" as crate_name;`
- // `extern crate crate_name;`
- // `extern crate crate_name as other_name;`
- case TOK_RWORD_CRATE:
- switch( GET_TOK(tok, lex) )
- {
- // `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() });
- GET_CHECK_TOK(tok, lex, TOK_RWORD_AS);
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
- break;
- // `extern crate crate_name;`
- // `extern crate crate_name as other_name;`
- case TOK_IDENT:
- item_name = mv$(tok.str());
- 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());
- }
- else {
- PUTBACK(tok, lex);
- item_data = ::AST::Item::make_Crate({ item_name });
- }
- break;
- default:
- throw ParseError::Unexpected(lex, tok, {TOK_STRING, TOK_IDENT});
- }
- GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
- break;
- default:
- throw ParseError::Unexpected(lex, tok, {TOK_STRING, TOK_RWORD_FN, TOK_BRACE_OPEN, TOK_RWORD_CRATE});
- }
- break;
-
- // `const NAME`
- // `const [unsafe] fn`
- case TOK_RWORD_CONST:
- switch( GET_TOK(tok, lex) )
- {
- case TOK_IDENT: {
- item_name = mv$(tok.str());
-
- GET_CHECK_TOK(tok, lex, TOK_COLON);
- TypeRef type = Parse_Type(lex);
- GET_CHECK_TOK(tok, lex, TOK_EQUAL);
- AST::Expr val = Parse_Expr(lex);
- GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
- item_data = ::AST::Item( ::AST::Static(AST::Static::CONST, mv$(type), mv$(val)) );
- break; }
- 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_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());
- // - self not allowed, not prototype
- item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, ABI_RUST, false, false,true/*unsafe,const*/) );
- break;
- default:
- throw ParseError::Unexpected(lex, tok, {TOK_IDENT, TOK_RWORD_FN});
- }
- break;
- // `static NAME`
- // `static mut NAME`
- case TOK_RWORD_STATIC: {
- bool is_mut = false;
- if(GET_TOK(tok, lex) == TOK_RWORD_MUT) {
- is_mut = true;
- GET_TOK(tok, lex);
- }
- CHECK_TOK(tok, TOK_IDENT);
- item_name = mv$(tok.str());
-
- GET_CHECK_TOK(tok, lex, TOK_COLON);
- TypeRef type = Parse_Type(lex);
-
- GET_CHECK_TOK(tok, lex, TOK_EQUAL);
-
- AST::Expr val = Parse_Expr(lex);
-
- GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
- item_data = ::AST::Item( ::AST::Static( (is_mut ? AST::Static::MUT : AST::Static::STATIC), mv$(type), mv$(val)) );
- break; }
-
- // `unsafe fn`
- // `unsafe trait`
- // `unsafe impl`
- case TOK_RWORD_UNSAFE:
- meta_items.push_back( AST::MetaItem("#UNSAFE") );
- switch(GET_TOK(tok, lex))
- {
- // `unsafe extern fn`
- case TOK_RWORD_EXTERN: {
- ::std::string abi = "C";
- if(GET_TOK(tok, lex) == TOK_STRING) {
- abi = mv$(tok.str());
- }
- else {
- PUTBACK(tok, lex);
- }
- GET_CHECK_TOK(tok, lex, TOK_RWORD_FN);
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
- 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());
- // - 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());
- // TODO: Mark as unsafe
- meta_items.push_back( AST::MetaItem("#UNSAFE") );
- item_data = ::AST::Item( Parse_TraitDef(lex, meta_items) );
- break;
- // `unsafe impl`
- case TOK_RWORD_IMPL:
- return ::AST::Named< ::AST::Item> { "", Parse_Impl(lex, mv$(meta_items), true), false };
- default:
- throw ParseError::Unexpected(lex, tok, {TOK_RWORD_FN, TOK_RWORD_TRAIT, TOK_RWORD_IMPL});
- }
- break;
- // `fn`
- case TOK_RWORD_FN:
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
- // - 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_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_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_data = ::AST::Item( Parse_EnumDef(lex, meta_items) );
- break;
- // Contextual keywords
- case TOK_IDENT:
- if( tok.str() == "union" ) {
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
- item_data = ::AST::Item( Parse_Union(lex, meta_items) );
- }
- else {
- throw ParseError::Unexpected(lex, tok);
- }
- break;
- // `impl`
- case TOK_RWORD_IMPL:
- return ::AST::Named< ::AST::Item> { "", Parse_Impl(lex, mv$(meta_items)), false };
- // `trait`
- case TOK_RWORD_TRAIT:
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
- item_data = ::AST::Item( Parse_TraitDef(lex, meta_items) );
- break;
-
- case TOK_RWORD_MOD: {
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = mv$(tok.str());
- DEBUG("Sub module '" << name << "'");
- AST::Module submod( mod_path + name );
-
- // Rules for external files (/ path handling):
- // - IF using stdin (path='-') - Disallow and propagate '-' as path
- // - IF a #[path] attribute was passed, allow
- // - IF in crate root or mod.rs, allow (input flag)
- // - else, disallow and set flag
- ::std::string path_attr = (meta_items.has("path") ? meta_items.get("path")->string() : "");
-
- //submod.m_file_info = get_submod_file(lex.end_span(ps), mod_fileinfo, name, path_attr, LOOK_AHEAD(lex) == TOK_SEMICOLON);
-
- ::std::string sub_path;
- bool sub_file_controls_dir = true;
- if( mod_fileinfo.path == "-" ) {
- if( path_attr.size() ) {
- ERROR(lex.getPosition(), E0000, "Cannot load module from file when reading stdin");
- }
- sub_path = "-";
- }
- else if( path_attr.size() > 0 )
- {
- sub_path = dirname(mod_fileinfo.path) + path_attr;
- }
- else if( mod_fileinfo.controls_dir )
- {
- sub_path = dirname(mod_fileinfo.path) + name;
- }
- else
- {
- sub_path = mod_fileinfo.path;
- sub_file_controls_dir = false;
- }
- DEBUG("Mod '" << name << "', sub_path = " << sub_path);
-
- 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::MetaItems& attrs)
- {
- for(const auto& at : attrs.m_items) {
- if( at.name() == "cfg" && !check_cfg(attrs.m_span, at) ) {
- return false;
- }
- }
- return true;
- }
- };
-
- switch( GET_TOK(tok, lex) )
- {
- case TOK_BRACE_OPEN:
- submod.m_file_info.path = sub_path + "/";
- Parse_ModRoot(lex, submod, meta_items);
- GET_CHECK_TOK(tok, lex, TOK_BRACE_CLOSE);
- break;
- case TOK_SEMICOLON:
- if( sub_path == "-" ) {
- ERROR(lex.getPosition(), E0000, "Cannot load module from file when reading stdin");
- }
- else if( path_attr.size() == 0 && ! mod_fileinfo.controls_dir )
- {
- ERROR(lex.getPosition(), 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
- {
- ::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.getPosition(), E0000, "Both modname.rs and modname/mod.rs exist");
- }
- else if( ifs_dir.is_open() )
- {
- // Load from dir
- submod.m_file_info.path = newpath_dir + "mod.rs";
- }
- else if( ifs_file.is_open() )
- {
- submod.m_file_info.path = newpath_file;
- }
- else
- {
- // Can't find file
- ERROR(lex.getPosition(), E0000, "Can't find file for '" << name << "' in '" << mod_fileinfo.path << "'");
- }
- 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);
- }
- break;
- default:
- throw ParseError::Generic("Expected { or ; after module name");
- }
- item_name = mv$(name);
- item_data = ::AST::Item( mv$(submod) );
- break; }
-
- default:
- throw ParseError::Unexpected(lex, tok);
- }
-
- item_data.attrs = mv$(meta_items);
- item_data.span = lex.end_span(ps);
-
- return ::AST::Named< ::AST::Item> { mv$(item_name), mv$(item_data), is_public };
-}
-
-void Parse_Mod_Item(TokenStream& lex, AST::Module& mod, AST::MetaItems meta_items)
-{
- SET_MODULE(lex, mod);
- lex.parse_state().parent_attrs = &meta_items;
-
- //TRACE_FUNCTION;
- Token tok;
-
- // `use ...`
- if( LOOK_AHEAD(lex) == TOK_RWORD_USE || (lex.lookahead(0) == TOK_RWORD_PUB && lex.lookahead(1) == TOK_RWORD_USE) )
- {
- bool is_public = false;
- if( GET_TOK(tok, lex) == TOK_RWORD_PUB ) {
- is_public = true;
- GET_TOK(tok, lex);
- }
-
- 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)) );
- }
-}
-
-void Parse_ModRoot_Items(TokenStream& lex, AST::Module& mod)
-{
- Token tok;
-
- for(;;)
- {
- // Check 1 - End of module (either via a closing brace, or EOF)
- switch(GET_TOK(tok, lex))
- {
- case TOK_BRACE_CLOSE:
- case TOK_EOF:
- PUTBACK(tok, lex);
- return;
- default:
- PUTBACK(tok, lex);
- break;
- }
-
- // Attributes on the following item
- AST::MetaItems meta_items;
- while( GET_TOK(tok, lex) == TOK_ATTR_OPEN )
- {
- meta_items.push_back( Parse_MetaItem(lex) );
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- }
- PUTBACK(tok, lex);
- DEBUG("meta_items = " << meta_items);
-
- Parse_Mod_Item(lex, mod, mv$(meta_items));
- }
-}
-
-void Parse_ModRoot(TokenStream& lex, AST::Module& mod, AST::MetaItems& mod_attrs)
-{
- TRACE_FUNCTION;
-
- Token tok;
-
- // Attributes on module/crate (will continue loop)
- while( GET_TOK(tok, lex) == TOK_CATTR_OPEN )
- {
- AST::MetaItem item = Parse_MetaItem(lex);
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
-
- mod_attrs.push_back( mv$(item) );
- }
- PUTBACK(tok, lex);
-
- Parse_ModRoot_Items(lex, mod);
-}
-
-AST::Crate Parse_Crate(::std::string mainfile)
-{
- Token tok;
-
- Lexer lex(mainfile);
-
- size_t p = mainfile.find_last_of('/');
- ::std::string mainpath = (p != ::std::string::npos ? ::std::string(mainfile.begin(), mainfile.begin()+p+1) : "./");
-
- AST::Crate crate;
-
- crate.root_module().m_file_info.path = mainpath;
- crate.root_module().m_file_info.controls_dir = true;
-
- Parse_ModRoot(lex, crate.root_module(), crate.m_attrs);
-
- return crate;
-}
+/* + * MRustC - Rust Compiler + * - By John Hodge (Mutabah/thePowersGang) + * + * parse/root.cpp + * - Parsing at the module level (highest-level parsing) + * + * Entrypoint: + * - Parse_Crate : Handles crate attrbutes, and passes on to Parse_ModRoot + * - Parse_ModRoot + */ +#include <ast/ast.hpp> +#include <ast/crate.hpp> +#include "parseerror.hpp" +#include "common.hpp" +#include <cassert> +#include <hir/hir.hpp> // ABI_RUST - TODO: Move elsewhere? +#include <expand/cfg.hpp> // check_cfg - for `mod nonexistant;` +#include <fstream> // Used by directory path +#include "lex.hpp" // New file lexer + +template<typename T> +Spanned<T> get_spanned(TokenStream& lex, ::std::function<T()> f) { + auto ps = lex.start_span(); + auto v = f(); + return Spanned<T> { + lex.end_span(ps), + mv$(v) + }; +} +#define GET_SPANNED(type, lex, val) get_spanned< type >(lex, [&](){ return val; }) + +// Check the next two tokens +#define LOOKAHEAD2(lex, tok1, tok2) ((lex).lookahead(0) == (tok1) && (lex).lookahead(1) == (tok2)) + +::std::string dirname(::std::string input) { + while( input.size() > 0 && input.back() != '/' ) { + input.pop_back(); + } + return input; +} + +AST::MetaItem Parse_MetaItem(TokenStream& lex); +void Parse_ModRoot(TokenStream& lex, AST::Module& mod, AST::MetaItems& mod_attrs); + +::std::vector< ::std::string> Parse_HRB(TokenStream& lex) +{ + TRACE_FUNCTION; + Token tok; + + ::std::vector< ::std::string> lifetimes; + GET_CHECK_TOK(tok, lex, TOK_LT); + do { + GET_TOK(tok, lex); + + ::AST::MetaItems attrs; + while(tok.type() == TOK_ATTR_OPEN) + { + attrs.push_back( Parse_MetaItem(lex) ); + GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE); + GET_TOK(tok, lex); + } + (void)attrs; // TODO: Attributes on generic params + + switch(tok.type()) + { + case TOK_LIFETIME: + lifetimes.push_back(tok.str()); + break; + default: + throw ParseError::Unexpected(lex, tok, Token(TOK_LIFETIME)); + } + } while( GET_TOK(tok, lex) == TOK_COMMA ); + CHECK_TOK(tok, TOK_GT); + return lifetimes; +} +/// Parse type parameters in a definition +void Parse_TypeBound(TokenStream& lex, AST::GenericParams& ret, TypeRef checked_type, ::std::vector< ::std::string> lifetimes = {}) +{ + TRACE_FUNCTION; + Token tok; + + do + { + ::std::vector< ::std::string> hrls; + if(GET_TOK(tok, lex) == TOK_LIFETIME) { + ret.add_bound(AST::GenericBound::make_TypeLifetime( { + checked_type.clone(), tok.str() + } )); + } + else if( tok.type() == TOK_QMARK ) { + ret.add_bound(AST::GenericBound::make_MaybeTrait( { + checked_type.clone(), Parse_Path(lex, PATH_GENERIC_TYPE) + } )); + } + else { + if( tok.type() == TOK_RWORD_FOR ) + { + hrls = Parse_HRB(lex); + } + else { + PUTBACK(tok, lex); + } + (void)hrls; // TODO: HRLs + + ret.add_bound( AST::GenericBound::make_IsTrait({ + checked_type.clone(), mv$(lifetimes), Parse_Path(lex, PATH_GENERIC_TYPE) + }) ); + } + } while( GET_TOK(tok, lex) == TOK_PLUS ); + PUTBACK(tok, lex); +} + +/// Parse type parameters within '<' and '>' (definition) +AST::GenericParams Parse_GenericParams(TokenStream& lex) +{ + TRACE_FUNCTION; + + AST::GenericParams ret; + Token tok; + do { + if( GET_TOK(tok, lex) == TOK_GT ) { + break ; + } + + ::AST::MetaItems attrs; + while(tok.type() == TOK_ATTR_OPEN) + { + attrs.push_back( Parse_MetaItem(lex) ); + GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE); + GET_TOK(tok, lex); + } + (void)attrs; // TODO: Attributes on generic params + + if( tok.type() == TOK_IDENT ) + { + // TODO: Hygine + ::std::string param_name = mv$(tok.str()); + ret.add_ty_param( AST::TypeParam( param_name ) ); + + auto param_ty = TypeRef(lex.getPosition(), param_name); + if( GET_TOK(tok, lex) == TOK_COLON ) + { + Parse_TypeBound(lex, ret, mv$(param_ty)); + GET_TOK(tok, lex); + } + + if( tok.type() == TOK_EQUAL ) + { + ret.ty_params().back().setDefault( Parse_Type(lex) ); + GET_TOK(tok, lex); + } + } + else if( tok.type() == TOK_LIFETIME ) + { + // TODO: Should lifetimes have hygine? + ::std::string param_name = tok.str(); + ret.add_lft_param( param_name ); + if( GET_TOK(tok, lex) == TOK_COLON ) + { + do { + GET_CHECK_TOK(tok, lex, TOK_LIFETIME); + ret.add_bound(AST::GenericBound::make_Lifetime( {param_name, tok.str()} )); + } while( GET_TOK(tok, lex) == TOK_PLUS ); + } + } + else + { + throw ParseError::Unexpected(lex, tok, {TOK_IDENT, TOK_LIFETIME}); + } + } while( tok.type() == TOK_COMMA ); + PUTBACK(tok, lex); + return ret; +} + + +/// Parse the contents of a 'where' clause +void Parse_WhereClause(TokenStream& lex, AST::GenericParams& params) +{ + TRACE_FUNCTION; + Token tok; + + do { + GET_TOK(tok, lex); + if( tok.type() == TOK_BRACE_OPEN ) { + break; + } + + if( tok.type() == TOK_LIFETIME ) + { + auto lhs = mv$(tok.str()); + GET_CHECK_TOK(tok, lex, TOK_COLON); + do { + GET_CHECK_TOK(tok, lex, TOK_LIFETIME); + auto rhs = mv$(tok.str()); + params.add_bound( AST::GenericBound::make_Lifetime({lhs, rhs}) ); + } while( GET_TOK(tok, lex) == TOK_PLUS ); + PUTBACK(tok, lex); + } + // Higher-ranked types/lifetimes + else if( tok.type() == TOK_RWORD_FOR ) + { + ::std::vector< ::std::string> lifetimes = Parse_HRB(lex); + + TypeRef type = Parse_Type(lex); + GET_CHECK_TOK(tok, lex, TOK_COLON); + Parse_TypeBound(lex,params, mv$(type), mv$(lifetimes)); + } + else + { + PUTBACK(tok, lex); + TypeRef type = Parse_Type(lex); + GET_CHECK_TOK(tok, lex, TOK_COLON); + Parse_TypeBound(lex, params, mv$(type)); + } + } while( GET_TOK(tok, lex) == TOK_COMMA ); + PUTBACK(tok, lex); +} + +// Parse a single function argument +::std::pair< AST::Pattern, TypeRef> Parse_Function_Arg(TokenStream& lex, bool expect_named) +{ + TRACE_FUNCTION_F("expect_named = " << expect_named); + Token tok; + + AST::Pattern pat; + + // If any of the following + // - Expecting a named parameter (i.e. defining a function in root or impl) + // - Next token is an underscore (only valid as a pattern here) + // - Next token is 'mut' (a mutable parameter slot) + // - Next two are <ident> ':' (a trivial named parameter) + // NOTE: When not expecting a named param, destructuring patterns are not allowed + if( expect_named + || LOOK_AHEAD(lex) == TOK_UNDERSCORE + || LOOK_AHEAD(lex) == TOK_RWORD_MUT + || (LOOK_AHEAD(lex) == TOK_IDENT && lex.lookahead(1) == TOK_COLON) + ) + { + // Function args can't be refuted + pat = Parse_Pattern(lex, false); + GET_CHECK_TOK(tok, lex, TOK_COLON); + } + + TypeRef type = Parse_Type(lex); + + + return ::std::make_pair( ::std::move(pat), ::std::move(type) ); +} + +/// Parse a function definition (after the 'fn <name>') +AST::Function Parse_FunctionDef(TokenStream& lex, ::std::string abi, bool allow_self, bool can_be_prototype, bool is_unsafe, bool is_const) +{ + TRACE_FUNCTION; + ProtoSpan ps = lex.start_span(); + + Token tok; + + // Parameters + AST::GenericParams params; + if( GET_TOK(tok, lex) == TOK_LT ) + { + params = Parse_GenericParams(lex); + GET_CHECK_TOK(tok, lex, TOK_GT); + } + else { + PUTBACK(tok, lex); + } + + AST::Function::Arglist args; + + GET_CHECK_TOK(tok, lex, TOK_PAREN_OPEN); + GET_TOK(tok, lex); + + // Handle self + if( tok.type() == TOK_AMP ) + { + // By-reference method? + // TODO: If a lifetime is seen (and not a prototype), it is definitely a self binding + + unsigned int ofs = 0; + if( lex.lookahead(0) == TOK_LIFETIME ) + ofs ++; + + if( lex.lookahead(ofs) == TOK_RWORD_SELF || (lex.lookahead(ofs) == TOK_RWORD_MUT && lex.lookahead(ofs+1) == TOK_RWORD_SELF) ) + { + auto ps = lex.start_span(); + ::std::string lifetime; + if( GET_TOK(tok, lex) == TOK_LIFETIME ) { + lifetime = tok.str(); + GET_TOK(tok, lex); + } + auto ty_sp = lex.end_span(ps); + + if( tok.type() == TOK_RWORD_MUT ) + { + GET_CHECK_TOK(tok, lex, TOK_RWORD_SELF); + args.push_back( ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "self"), TypeRef(TypeRef::TagReference(), ty_sp, true, TypeRef(ty_sp, "Self", 0xFFFF))) ); + } + else + { + args.push_back( ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "self"), TypeRef(TypeRef::TagReference(), ty_sp, false, TypeRef(ty_sp, "Self", 0xFFFF))) ); + } + DEBUG("TODO: UFCS / self lifetimes"); + if( allow_self == false ) + throw ParseError::Generic(lex, "Self binding not expected"); + //args.push_back( ::std::make_pair( + // AST::Pattern(), + // TypeRef(TypeRef::TagReference(), lifetime, (fcn_class == AST::Function::CLASS_MUTMETHOD), ) + //) ); + + // Prime tok for next step + GET_TOK(tok, lex); + } + else + { + // Unbound method + } + } + else if( tok.type() == TOK_RWORD_MUT ) + { + if( LOOK_AHEAD(lex) == TOK_RWORD_SELF ) + { + GET_TOK(tok, lex); + if( allow_self == false ) + throw ParseError::Generic(lex, "Self binding not expected"); + TypeRef ty = TypeRef( lex.getPosition(), "Self", 0xFFFF ); + if( GET_TOK(tok, lex) == TOK_COLON ) { + // Typed mut self + ty = Parse_Type(lex); + } + else { + PUTBACK(tok, lex); + } + args.push_back( ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "self"), mv$(ty)) ); + GET_TOK(tok, lex); + } + } + else if( tok.type() == TOK_RWORD_SELF ) + { + // By-value method + if( allow_self == false ) + throw ParseError::Generic(lex, "Self binding not expected"); + TypeRef ty = TypeRef( lex.getPosition(), "Self", 0xFFFF ); + if( GET_TOK(tok, lex) == TOK_COLON ) { + // Typed mut self + ty = Parse_Type(lex); + } + else { + PUTBACK(tok, lex); + } + args.push_back( ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "self"), mv$(ty)) ); + GET_TOK(tok, lex); + } + else + { + // Unbound method + } + + bool is_variadic = false; + if( tok.type() != TOK_PAREN_CLOSE ) + { + // Comma after self + if( args.size() ) + { + CHECK_TOK(tok, TOK_COMMA); + } + else { + PUTBACK(tok, lex); + } + + // Argument list + do { + if( LOOK_AHEAD(lex) == TOK_PAREN_CLOSE ) { + GET_TOK(tok, lex); + break; + } + if( LOOK_AHEAD(lex) == TOK_TRIPLE_DOT ) { + GET_TOK(tok, lex); + is_variadic = true; + GET_TOK(tok, lex); + break; + } + args.push_back( Parse_Function_Arg(lex, !can_be_prototype) ); + } while( GET_TOK(tok, lex) == TOK_COMMA ); + CHECK_TOK(tok, TOK_PAREN_CLOSE); + } + else { + // Eat 'tok', negative comparison + } + + TypeRef ret_type = TypeRef(TypeRef::TagUnit(), Span(tok.get_pos())); + if( GET_TOK(tok, lex) == TOK_THINARROW ) + { + // Return type + ret_type = Parse_Type(lex); + } + else + { + PUTBACK(tok, lex); + } + + if( GET_TOK(tok, lex) == TOK_RWORD_WHERE ) + { + Parse_WhereClause(lex, params); + } + else { + PUTBACK(tok, lex); + } + + return AST::Function(lex.end_span(ps), mv$(params), mv$(abi), is_unsafe, is_const, is_variadic, mv$(ret_type), mv$(args)); +} + +AST::Function Parse_FunctionDefWithCode(TokenStream& lex, ::std::string abi, bool allow_self, bool is_unsafe, bool is_const) +{ + Token tok; + auto ret = Parse_FunctionDef(lex, abi, allow_self, false, is_unsafe, is_const); + GET_CHECK_TOK(tok, lex, TOK_BRACE_OPEN); + PUTBACK(tok, lex); + ret.set_code( Parse_ExprBlock(lex) ); + return ret; +} + +AST::TypeAlias Parse_TypeAlias(TokenStream& lex) +{ + TRACE_FUNCTION; + + Token tok; + + // Params + AST::GenericParams params; + if( GET_TOK(tok, lex) == TOK_LT ) + { + params = Parse_GenericParams(lex); + GET_CHECK_TOK(tok, lex, TOK_GT); + GET_TOK(tok, lex); + } + + if( tok.type() == TOK_RWORD_WHERE ) + { + Parse_WhereClause(lex, params); + GET_TOK(tok, lex); + } + CHECK_TOK(tok, TOK_EQUAL); + + // Type + TypeRef type = Parse_Type(lex); + GET_CHECK_TOK(tok, lex, TOK_SEMICOLON); + + return AST::TypeAlias( ::std::move(params), ::std::move(type) ); +} + +AST::Struct Parse_Struct(TokenStream& lex, const AST::MetaItems& meta_items) +{ + TRACE_FUNCTION; + + Token tok; + + tok = lex.getToken(); + AST::GenericParams params; + if( tok.type() == TOK_LT ) + { + params = Parse_GenericParams(lex); + GET_CHECK_TOK(tok, lex, TOK_GT); + if(GET_TOK(tok, lex) == TOK_RWORD_WHERE) + { + Parse_WhereClause(lex, params); + tok = lex.getToken(); + } + } + if(tok.type() == TOK_PAREN_OPEN) + { + // Tuple structs + ::std::vector<AST::TupleItem> refs; + while(GET_TOK(tok, lex) != TOK_PAREN_CLOSE) + { + AST::MetaItems item_attrs; + while( tok.type() == TOK_ATTR_OPEN ) + { + item_attrs.push_back( Parse_MetaItem(lex) ); + GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE); + GET_TOK(tok, lex); + } + SET_ATTRS(lex, item_attrs); + + bool is_pub = false; + if(tok.type() == TOK_RWORD_PUB) + is_pub = true; + else + PUTBACK(tok, lex); + + refs.push_back( AST::TupleItem( mv$(item_attrs), is_pub, Parse_Type(lex) ) ); + if( GET_TOK(tok, lex) != TOK_COMMA ) + break; + } + CHECK_TOK(tok, TOK_PAREN_CLOSE); + + if(LOOK_AHEAD(lex) == TOK_RWORD_WHERE) + { + GET_TOK(tok, lex); + Parse_WhereClause(lex, params); + } + GET_CHECK_TOK(tok, lex, TOK_SEMICOLON); + //if( refs.size() == 0 ) + // WARNING( , W000, "Use 'struct Name;' instead of 'struct Name();' ... ning-nong"); + return AST::Struct(mv$(params), mv$(refs)); + } + else if(tok.type() == TOK_SEMICOLON) + { + // Unit-like struct + return AST::Struct(mv$(params), ::std::vector<AST::TupleItem>()); + } + else if(tok.type() == TOK_BRACE_OPEN) + { + ::std::vector<AST::StructItem> items; + while( GET_TOK(tok, lex) != TOK_BRACE_CLOSE ) + { + AST::MetaItems item_attrs; + while( tok.type() == TOK_ATTR_OPEN ) + { + item_attrs.push_back( Parse_MetaItem(lex) ); + GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE); + GET_TOK(tok, lex); + } + SET_ATTRS(lex, item_attrs); + + bool is_pub = false; + if(tok.type() == TOK_RWORD_PUB) { + is_pub = true; + GET_TOK(tok, lex); + } + + CHECK_TOK(tok, TOK_IDENT); + auto name = mv$(tok.str()); + GET_CHECK_TOK(tok, lex, TOK_COLON); + TypeRef type = Parse_Type(lex); + + items.push_back( AST::StructItem( mv$(item_attrs), is_pub, mv$(name), mv$(type) ) ); + if(GET_TOK(tok, lex) == TOK_BRACE_CLOSE) + break; + CHECK_TOK(tok, TOK_COMMA); + } + //if( items.size() == 0 ) + // WARNING( , W000, "Use 'struct Name;' instead of 'struct Nam { };' ... ning-nong"); + return AST::Struct(::std::move(params), ::std::move(items)); + } + else + { + throw ParseError::Unexpected(lex, tok); + } +} + +AST::Trait Parse_TraitDef(TokenStream& lex, const AST::MetaItems& meta_items) +{ + TRACE_FUNCTION; + + Token tok; + + AST::GenericParams params; + if( GET_TOK(tok, lex) == TOK_LT ) + { + params = Parse_GenericParams(lex); + GET_CHECK_TOK(tok, lex, TOK_GT); + tok = lex.getToken(); + } + + // Trait bounds "trait Trait : 'lifetime + OtherTrait + OtherTrait2" + ::std::vector<Spanned<AST::Path> > supertraits; + if(tok.type() == TOK_COLON) + { + do { + if( GET_TOK(tok, lex) == TOK_LIFETIME ) { + // TODO: Need a better way of indiciating 'static than just an invalid path + supertraits.push_back( make_spanned( Span(tok.get_pos()), AST::Path() ) ); + } + else { + PUTBACK(tok, lex); + supertraits.push_back( GET_SPANNED(::AST::Path, lex, Parse_Path(lex, PATH_GENERIC_TYPE)) ); + } + } while( GET_TOK(tok, lex) == TOK_PLUS ); + } + + // TODO: Support "for Sized?" + if(tok.type() == TOK_RWORD_WHERE) + { + //if( params.ty_params().size() == 0 ) + // throw ParseError::Generic("Where clause with no generic params"); + Parse_WhereClause(lex, params); + tok = lex.getToken(); + } + + + AST::Trait trait( mv$(params), mv$(supertraits) ); + + CHECK_TOK(tok, TOK_BRACE_OPEN); + while( GET_TOK(tok, lex) != TOK_BRACE_CLOSE ) + { + + AST::MetaItems item_attrs; + while( tok.type() == TOK_ATTR_OPEN ) + { + item_attrs.push_back( Parse_MetaItem(lex) ); + GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE); + GET_TOK(tok, lex); + } + SET_ATTRS(lex, item_attrs); + + auto ps = lex.start_span(); + if( tok.type() == TOK_MACRO ) { + auto inv = Parse_MacroInvocation( ps, mv$(tok.str()), lex ); + // - Silently consume ';' after the macro + if( GET_TOK(tok, lex) != TOK_SEMICOLON ) + PUTBACK(tok, lex); + + trait.items().push_back( AST::Named<AST::Item>("", AST::Item(mv$(inv)), false) ); + continue ; + } + + 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); + + // TODO: Attributes on associated statics + trait.add_static( mv$(name), ::AST::Static(AST::Static::STATIC, mv$(ty), val)/*, mv$(item_attrs)*/ ); + 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); + + // TODO: Attributes on associated constants + trait.add_static( mv$(name), ::AST::Static(AST::Static::CONST, mv$(ty), val)/*, mv$(item_attrs)*/ ); + 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.getPosition(), "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.getPosition() ); + 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), ::std::move(default_type) ); + trait.items().back().data.as_Type().params() = mv$(atype_params); + break; } + + // Functions (possibly unsafe) + // TODO: Const? + 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); + fcn.set_code( Parse_ExprBlock(lex) ); + } + else if( tok.type() == TOK_SEMICOLON ) + { + // Accept it + } + else + { + throw ParseError::Unexpected(lex, tok); + } + // TODO: Store `item_attrs` + trait.add_function( ::std::move(name), /*mv$(item_attrs),*/ ::std::move(fcn) ); + break; } + default: + throw ParseError::Unexpected(lex, tok); + } + } + + return trait; +} + +AST::Enum Parse_EnumDef(TokenStream& lex, const AST::MetaItems& meta_items) +{ + TRACE_FUNCTION; + + Token tok; + + tok = lex.getToken(); + // Type params supporting "where" + AST::GenericParams params; + if( tok.type() == TOK_LT ) + { + params = Parse_GenericParams(lex); + GET_CHECK_TOK(tok, lex, TOK_GT); + if(GET_TOK(tok, lex) == TOK_RWORD_WHERE) + { + Parse_WhereClause(lex, params); + tok = lex.getToken(); + } + } + + // Body + CHECK_TOK(tok, TOK_BRACE_OPEN); + ::std::vector<AST::EnumVariant> variants; + while( GET_TOK(tok, lex) != TOK_BRACE_CLOSE ) + { + auto sp = lex.start_span(); + + AST::MetaItems item_attrs; + while( tok.type() == TOK_ATTR_OPEN ) + { + item_attrs.push_back( Parse_MetaItem(lex) ); + GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE); + GET_TOK(tok, lex); + } + SET_ATTRS(lex, item_attrs); + + CHECK_TOK(tok, TOK_IDENT); + ::std::string name = mv$(tok.str()); + if( GET_TOK(tok, lex) == TOK_PAREN_OPEN ) + { + ::std::vector<TypeRef> types; + // Get type list + do + { + if(LOOK_AHEAD(lex) == TOK_PAREN_CLOSE) + { + GET_TOK(tok, lex); + break; + } + + AST::MetaItems field_attrs; + while( LOOK_AHEAD(lex) == TOK_ATTR_OPEN ) + { + GET_TOK(tok, lex); + field_attrs.push_back( Parse_MetaItem(lex) ); + GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE); + } + + types.push_back( Parse_Type(lex) ); + } while( GET_TOK(tok, lex) == TOK_COMMA ); + CHECK_TOK(tok, TOK_PAREN_CLOSE); + GET_TOK(tok, lex); + variants.push_back( AST::EnumVariant(mv$(item_attrs), mv$(name), mv$(types)) ); + } + else if( tok.type() == TOK_BRACE_OPEN ) + { + ::std::vector<::AST::StructItem> fields; + do + { + if(LOOK_AHEAD(lex) == TOK_BRACE_CLOSE) + { + GET_TOK(tok, lex); + break; + } + + AST::MetaItems field_attrs; + while( LOOK_AHEAD(lex) == TOK_ATTR_OPEN ) + { + GET_TOK(tok, lex); + field_attrs.push_back( Parse_MetaItem(lex) ); + GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE); + } + + GET_CHECK_TOK(tok, lex, TOK_IDENT); + auto name = mv$(tok.str()); + 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)) ); + } while( GET_TOK(tok, lex) == TOK_COMMA ); + CHECK_TOK(tok, TOK_BRACE_CLOSE); + GET_TOK(tok, lex); + + variants.push_back( AST::EnumVariant(mv$(item_attrs), mv$(name), mv$(fields)) ); + } + else if( tok.type() == TOK_EQUAL ) + { + auto node = Parse_Expr(lex); + variants.push_back( AST::EnumVariant(mv$(item_attrs), mv$(name), mv$(node)) ); + GET_TOK(tok, lex); + } + else + { + variants.push_back( AST::EnumVariant(mv$(item_attrs), mv$(name), ::AST::Expr()) ); + } + + if( tok.type() != TOK_COMMA ) + break; + } + CHECK_TOK(tok, TOK_BRACE_CLOSE); + + + return AST::Enum( mv$(params), mv$(variants) ); +} + +::AST::Union Parse_Union(TokenStream& lex, AST::MetaItems& meta_items) +{ + Token tok; + + TRACE_FUNCTION; + + AST::GenericParams params; + if( GET_TOK(tok, lex) == TOK_LT ) + { + params = Parse_GenericParams(lex); + GET_CHECK_TOK(tok, lex, TOK_GT); + if(GET_TOK(tok, lex) == TOK_RWORD_WHERE) + { + Parse_WhereClause(lex, params); + tok = lex.getToken(); + } + } + + ::std::vector< ::AST::StructItem> variants; + + CHECK_TOK(tok, TOK_BRACE_OPEN); + do { + if( LOOK_AHEAD(lex) == TOK_BRACE_CLOSE ) { + GET_TOK(tok, lex); + break ; + } + + AST::MetaItems item_attrs; + while( LOOK_AHEAD(lex) == TOK_ATTR_OPEN ) + { + GET_TOK(tok, lex); + item_attrs.push_back( Parse_MetaItem(lex) ); + GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE); + } + SET_ATTRS(lex, item_attrs); + + bool is_pub = false; + if( LOOK_AHEAD(lex) == TOK_RWORD_PUB ) { + is_pub = true; + GET_TOK(tok, lex); + } + + GET_CHECK_TOK(tok, lex, TOK_IDENT); + auto name = mv$(tok.str()); + GET_CHECK_TOK(tok, lex, TOK_COLON); + + auto ty = Parse_Type(lex); + + variants.push_back( ::AST::StructItem( mv$(item_attrs), is_pub, mv$(name), mv$(ty) ) ); + + } while( GET_TOK(tok, lex) == TOK_COMMA ); + CHECK_TOK(tok, TOK_BRACE_CLOSE); + + return ::AST::Union( mv$(params), mv$(variants) ); +} + +/// Parse a meta-item declaration (either #![ or #[) +AST::MetaItem Parse_MetaItem(TokenStream& lex) +{ + TRACE_FUNCTION; + Token tok; + GET_TOK(tok, lex); + + if( tok.type() == TOK_INTERPOLATED_META ) { + return mv$(tok.frag_meta()); + } + + CHECK_TOK(tok, TOK_IDENT); + ::std::string name = mv$(tok.str()); + switch(GET_TOK(tok, lex)) + { + case TOK_EQUAL: + GET_CHECK_TOK(tok, lex, TOK_STRING); + return AST::MetaItem(name, tok.str()); + case TOK_PAREN_OPEN: { + ::std::vector<AST::MetaItem> items; + do { + if(LOOK_AHEAD(lex) == TOK_PAREN_CLOSE) { + GET_TOK(tok, lex); + break; + } + items.push_back(Parse_MetaItem(lex)); + } while(GET_TOK(tok, lex) == TOK_COMMA); + CHECK_TOK(tok, TOK_PAREN_CLOSE); + return AST::MetaItem(name, mv$(items)); } + default: + PUTBACK(tok, lex); + return AST::MetaItem(name); + } +} + +::AST::Item Parse_Impl(TokenStream& lex, AST::MetaItems attrs, bool is_unsafe=false) +{ + TRACE_FUNCTION; + Token tok; + auto ps = lex.start_span(); + + AST::GenericParams params; + // 1. (optional) type parameters + if( GET_TOK(tok, lex) == TOK_LT ) + { + params = Parse_GenericParams(lex); + GET_CHECK_TOK(tok, lex, TOK_GT); + } + else { + PUTBACK(tok, lex); + } + // 2. Either a trait name (with type params), or the type to impl + + Spanned<AST::Path> trait_path; + + // - Handle negative impls specially, which must be a trait + // "impl !Trait for Type {}" + if( GET_TOK(tok, lex) == TOK_EXCLAM ) + { + trait_path = GET_SPANNED(::AST::Path, lex, Parse_Path(lex, PATH_GENERIC_TYPE)); + GET_CHECK_TOK(tok, lex, TOK_RWORD_FOR); + auto impl_type = Parse_Type(lex, true); + + if( GET_TOK(tok, lex) == TOK_RWORD_WHERE ) + { + Parse_WhereClause(lex, params); + GET_TOK(tok, lex); + } + CHECK_TOK(tok, TOK_BRACE_OPEN); + // negative impls can't have any content + GET_CHECK_TOK(tok, lex, TOK_BRACE_CLOSE); + + return ::AST::Item::make_NegImpl( AST::ImplDef(lex.end_span(ps), mv$(attrs), mv$(params), mv$(trait_path), mv$(impl_type) ) ); + } + + // - Don't care which at this stage + PUTBACK(tok, lex); + + auto impl_type = Parse_Type(lex, true); + + if( GET_TOK(tok, lex) == TOK_RWORD_FOR ) + { + // Trickery! All traits parse as valid types, so this works. + if( !impl_type.is_path() ) + throw ParseError::Generic(lex, "Trait was not a path"); + trait_path = Spanned< AST::Path> { + impl_type.span(), + mv$(impl_type.path()) + }; + // Implementing a trait for another type, get the target type + if( GET_TOK(tok, lex) == TOK_DOUBLE_DOT ) + { + // Default impl + impl_type = TypeRef(TypeRef::TagInvalid(), lex.getPosition()); + } + else + { + PUTBACK(tok, lex); + impl_type = Parse_Type(lex, true); + } + } + else { + PUTBACK(tok, lex); + } + + // Where clause + if( GET_TOK(tok, lex) == TOK_RWORD_WHERE ) + { + Parse_WhereClause(lex, params); + } + else { + PUTBACK(tok, lex); + } + GET_CHECK_TOK(tok, lex, TOK_BRACE_OPEN); + + while( LOOK_AHEAD(lex) == TOK_CATTR_OPEN ) + { + GET_TOK(tok, lex); + attrs.push_back( Parse_MetaItem(lex) ); + GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE); + } + + AST::Impl impl( AST::ImplDef( lex.end_span(ps), mv$(attrs), mv$(params), mv$(trait_path), mv$(impl_type) ) ); + + // A sequence of method implementations + while( GET_TOK(tok, lex) != TOK_BRACE_CLOSE ) + { + auto ps = lex.start_span(); + if( tok.type() == TOK_MACRO ) + { + impl.add_macro_invocation( Parse_MacroInvocation( ps, mv$(tok.str()), lex ) ); + // - Silently consume ';' after the macro + if( GET_TOK(tok, lex) != TOK_SEMICOLON ) + PUTBACK(tok, lex); + } + else + { + PUTBACK(tok, lex); + Parse_Impl_Item(lex, impl); + } + } + + return ::AST::Item::make_Impl( mv$(impl) ); +} + +void Parse_Impl_Item(TokenStream& lex, AST::Impl& impl) +{ + TRACE_FUNCTION; + Token tok; + + GET_TOK(tok, lex); + + AST::MetaItems item_attrs; + while( tok.type() == TOK_ATTR_OPEN ) + { + item_attrs.push_back( Parse_MetaItem(lex) ); + GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE); + GET_TOK(tok, lex); + } + SET_ATTRS(lex, item_attrs); + + auto ps = lex.start_span(); + + bool is_public = false; + if(tok.type() == TOK_RWORD_PUB) { + is_public = true; + GET_TOK(tok, lex); + } + + bool is_specialisable = false; + if( tok.type() == TOK_IDENT && tok.str() == "default" ) { + is_specialisable = true; + GET_TOK(tok, lex); + } + + ::std::string abi = ABI_RUST; + bool fn_is_unsafe = false; + bool fn_is_const = false; + switch(tok.type()) + { + case TOK_RWORD_TYPE: { + GET_CHECK_TOK(tok, lex, TOK_IDENT); + auto name = mv$(tok.str()); + 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); + break; } + case TOK_RWORD_UNSAFE: + fn_is_unsafe = true; + GET_TOK(tok, lex); + if( tok.type() == TOK_RWORD_CONST ) + case TOK_RWORD_CONST: + { + GET_TOK(tok, lex); + if( tok.type() != TOK_RWORD_FN && tok.type() != TOK_RWORD_UNSAFE && !fn_is_unsafe ) + { + CHECK_TOK(tok, 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_EQUAL); + auto val = Parse_Expr(lex); + GET_CHECK_TOK(tok, lex, TOK_SEMICOLON); + + auto i = ::AST::Static(AST::Static::CONST, mv$(ty), mv$(val)); + // TODO: Attributes on associated constants + impl.add_static( is_public, is_specialisable, mv$(name), mv$(i) /*, mv$(item_attrs)*/ ); + break ; + } + else if( tok.type() == TOK_RWORD_UNSAFE ) + { + fn_is_unsafe = true; + GET_CHECK_TOK(tok, lex, TOK_RWORD_FN); + } + fn_is_const = true; + } + if( tok.type() == TOK_RWORD_EXTERN ) + // FALL + 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); + // FALL + 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()); + DEBUG("Function " << name); + // - Self allowed, can't be prototype-form + auto fcn = Parse_FunctionDefWithCode(lex, abi, true, fn_is_unsafe, fn_is_const); + impl.add_function(is_public, is_specialisable, mv$(name), mv$(fcn)); + break; } + + default: + throw ParseError::Unexpected(lex, tok); + } + + impl.items().back().data->span = lex.end_span(ps); + impl.items().back().data->attrs = mv$(item_attrs); // Empty for functions +} + +AST::ExternBlock Parse_ExternBlock(TokenStream& lex, ::std::string abi, ::AST::MetaItems& block_attrs) +{ + TRACE_FUNCTION; + Token tok; + + while( GET_TOK(tok, lex) == TOK_CATTR_OPEN ) + { + block_attrs.push_back( Parse_MetaItem(lex) ); + GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE); + } + PUTBACK(tok, lex); + + AST::ExternBlock rv { abi }; + + while( GET_TOK(tok, lex) != TOK_BRACE_CLOSE ) + { + AST::MetaItems meta_items; + while( tok.type() == TOK_ATTR_OPEN ) + { + meta_items.push_back( Parse_MetaItem(lex) ); + GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE); + GET_TOK(tok, lex); + } + SET_ATTRS(lex, meta_items); + + auto ps = lex.start_span(); + + bool is_public = false; + if( tok.type() == TOK_RWORD_PUB ) { + is_public = true; + GET_TOK(tok, lex); + } + switch(tok.type()) + { + case TOK_RWORD_FN: { + GET_CHECK_TOK(tok, lex, TOK_IDENT); + auto name = mv$(tok.str()); + // 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) ); + GET_CHECK_TOK(tok, lex, TOK_SEMICOLON); + + i.attrs = mv$(meta_items); + i.span = lex.end_span(ps); + + rv.add_item( AST::Named<AST::Item> { mv$(name), mv$(i), is_public } ); + break; } + case TOK_RWORD_STATIC: { + bool is_mut = false; + if( GET_TOK(tok, lex) == TOK_RWORD_MUT ) + is_mut = true; + else + PUTBACK(tok, lex); + GET_CHECK_TOK(tok, lex, TOK_IDENT); + auto name = mv$(tok.str()); + GET_CHECK_TOK(tok, lex, TOK_COLON); + auto type = Parse_Type(lex); + GET_CHECK_TOK(tok, lex, TOK_SEMICOLON); + + auto i = ::AST::Item(::AST::Static( (is_mut ? ::AST::Static::MUT : ::AST::Static::STATIC), mv$(type), ::AST::Expr() )); + i.attrs = mv$(meta_items); + i.span = lex.end_span(ps); + rv.add_item( AST::Named<AST::Item> { mv$(name), mv$(i), is_public } ); + break; } + default: + throw ParseError::Unexpected(lex, tok, {TOK_RWORD_FN, TOK_RWORD_STATIC}); + } + } + + return rv; +} + +void Parse_Use_Wildcard(Span sp, AST::Path base_path, ::std::function<void(AST::UseStmt, ::std::string)> fcn) +{ + 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<void(AST::UseStmt, ::std::string)> 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 { + CHECK_TOK(tok, TOK_IDENT); + path = base_path + AST::PathNode(tok.str(), {}); + name = mv$(tok.str()); + } + + if( GET_TOK(tok, lex) == TOK_RWORD_AS ) { + GET_CHECK_TOK(tok, lex, TOK_IDENT); + name = mv$(tok.str()); + } + else { + PUTBACK(tok, lex); + } + fcn(AST::UseStmt(lex.end_span(ps), mv$(path)), mv$(name)); + } while( GET_TOK(tok, lex) == TOK_COMMA ); + PUTBACK(tok, lex); +} + +void Parse_Use(TokenStream& lex, ::std::function<void(AST::UseStmt, ::std::string)> fcn) +{ + TRACE_FUNCTION; + + Token tok; + AST::Path path = AST::Path("", {}); + ::std::vector<AST::PathNode> nodes; + ProtoSpan span_start = lex.start_span(); + + switch( GET_TOK(tok, lex) ) + { + case TOK_RWORD_SELF: + path = AST::Path( AST::Path::TagSelf(), {} ); // relative path + break; + case TOK_RWORD_SUPER: { + unsigned int count = 1; + while( LOOK_AHEAD(lex) == TOK_DOUBLE_COLON && lex.lookahead(1) == TOK_RWORD_SUPER ) { + GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON); + GET_CHECK_TOK(tok, lex, TOK_RWORD_SUPER); + count += 1; + } + path = AST::Path( AST::Path::TagSuper(), count, {} ); + break; } + case TOK_IDENT: + path.append( AST::PathNode(mv$(tok.str()), {}) ); + break; + // Leading :: is allowed and ignored for the $crate feature + case TOK_DOUBLE_COLON: + // Absolute path + // HACK! mrustc emits $crate as `::"crate-name"` + if( LOOK_AHEAD(lex) == TOK_STRING ) + { + GET_CHECK_TOK(tok, lex, TOK_STRING); + path = ::AST::Path(tok.str(), {}); + GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON); + } + else { + PUTBACK(tok, lex); + } + break; + case TOK_BRACE_OPEN: + Parse_Use_Set(lex, span_start, path, fcn); + GET_CHECK_TOK(tok, lex, TOK_BRACE_CLOSE); + return; + default: + throw ParseError::Unexpected(lex, tok); + } + while( GET_TOK(tok, lex) == TOK_DOUBLE_COLON ) + { + if( GET_TOK(tok, lex) == TOK_IDENT ) + { + path.append( AST::PathNode( mv$(tok.str()), {}) ); + } + else + { + //path.set_span( lex.end_span(span_start) ); + switch( tok.type() ) + { + case TOK_BRACE_OPEN: + Parse_Use_Set(lex, span_start, mv$(path), fcn); + GET_CHECK_TOK(tok, lex, TOK_BRACE_CLOSE); + break ; + case TOK_STAR: + Parse_Use_Wildcard( lex.end_span(span_start), mv$(path), fcn ); + break ; + default: + throw ParseError::Unexpected(lex, tok); + } + // early return - This branch is either the end of the use statement, or a syntax error + return ; + } + } + //path.set_span( lex.end_span(span_start) ); + + ::std::string name; + // This should only be allowed if the last token was an ident + // - Above checks ensure this + if( tok.type() == TOK_RWORD_AS ) + { + GET_CHECK_TOK(tok, lex, TOK_IDENT); + name = mv$(tok.str()); + } + else + { + PUTBACK(tok, lex); + assert(path.nodes().size() > 0); + name = path.nodes().back().name(); + } + + fcn( AST::UseStmt(lex.end_span(span_start), mv$(path)), name); +} + + +::AST::MacroInvocation Parse_MacroInvocation(ProtoSpan span_start, ::std::string name, TokenStream& lex) +{ + Token tok; + ::std::string ident; + if( GET_TOK(tok, lex) == TOK_IDENT ) { + ident = mv$(tok.str()); + } + else { + PUTBACK(tok, lex); + } + DEBUG("name=" << name << ", ident=" << ident); + TokenTree tt = Parse_TT(lex, true); + return ::AST::MacroInvocation( lex.end_span(span_start), mv$(name), mv$(ident), mv$(tt)); +} + +::AST::Named<::AST::Item> Parse_Mod_Item_S(TokenStream& lex, const AST::Module::FileInfo& mod_fileinfo, const ::AST::Path& mod_path, AST::MetaItems meta_items) +{ + TRACE_FUNCTION_F("mod_path="<<mod_path<<", meta_items="<<meta_items); + Token tok; + + while( LOOK_AHEAD(lex) == TOK_ATTR_OPEN /* || LOOKAHEAD2(lex, TOK_HASH, TOK_SQUARE_OPEN) */ ) + { + // Attributes! + GET_CHECK_TOK(tok, lex, TOK_ATTR_OPEN); + meta_items.push_back( Parse_MetaItem(lex) ); + GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE); + } + + if( LOOK_AHEAD(lex) == TOK_INTERPOLATED_ITEM ) { + GET_TOK(tok, lex); + auto rv = tok.take_frag_item(); + // Transfer new attributes onto the item + for(auto& mi : meta_items.m_items) + rv.data.attrs.m_items.push_back( mv$(mi) ); + return rv; + } + + auto ps = lex.start_span(); + + ::std::string item_name; + ::AST::Item item_data; + + if( LOOK_AHEAD(lex) == TOK_MACRO ) { + GET_TOK(tok, lex); + + ::std::string name = mv$(tok.str()); + bool is_braced = (LOOK_AHEAD(lex) == TOK_BRACE_OPEN || LOOKAHEAD2(lex, TOK_IDENT, TOK_BRACE_OPEN)); + item_data = ::AST::Item( Parse_MacroInvocation( ps, mv$(name), lex ) ); + + if( !is_braced ) { + // - Consume the ';' after the macro + GET_CHECK_TOK(tok, lex, TOK_SEMICOLON); + } + + item_data.attrs = mv$(meta_items); + item_data.span = lex.end_span(ps); + + return ::AST::Named< ::AST::Item> { "", mv$(item_data), false }; + } + + bool is_public = false; + if( GET_TOK(tok, lex) == TOK_RWORD_PUB ) { + is_public = true; + } + else { + PUTBACK(tok, lex); + } + + 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.getPosition(), "Encode multi-item use statements as a single Item"); + item_data = ::AST::Item(mv$(p)); + item_name = mv$(s); + }); + assert( !item_data.is_None() ); + GET_CHECK_TOK(tok, lex, TOK_SEMICOLON); + break; + + case TOK_RWORD_EXTERN: + switch( GET_TOK(tok, lex) ) + { + // `extern "<ABI>" fn ...` + // `extern "<ABI>" { ...` + case TOK_STRING: { + ::std::string abi = tok.str(); + switch(GET_TOK(tok, lex)) + { + // `extern "<ABI>" fn ...` + case TOK_RWORD_FN: { + GET_CHECK_TOK(tok, lex, TOK_IDENT); + item_name = mv$(tok.str()); + item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, abi, false, false,false) ); + break; } + // `extern "ABI" {` + case TOK_BRACE_OPEN: + item_name = ""; + item_data = ::AST::Item( Parse_ExternBlock(lex, mv$(abi), meta_items) ); + break; + default: + throw ParseError::Unexpected(lex, tok, {TOK_RWORD_FN, TOK_BRACE_OPEN}); + } + break; } + // `extern fn ...` + case TOK_RWORD_FN: + GET_CHECK_TOK(tok, lex, TOK_IDENT); + item_name = mv$(tok.str()); + item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, "C", false, false,false) ); + break; + + // NOTE: `extern { ...` is handled in caller + case TOK_BRACE_OPEN: + item_name = ""; + item_data = ::AST::Item( Parse_ExternBlock(lex, "C", meta_items) ); + break; + + // `extern crate "crate-name" as crate_name;` + // `extern crate crate_name;` + // `extern crate crate_name as other_name;` + case TOK_RWORD_CRATE: + switch( GET_TOK(tok, lex) ) + { + // `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() }); + GET_CHECK_TOK(tok, lex, TOK_RWORD_AS); + GET_CHECK_TOK(tok, lex, TOK_IDENT); + item_name = mv$(tok.str()); + break; + // `extern crate crate_name;` + // `extern crate crate_name as other_name;` + case TOK_IDENT: + item_name = mv$(tok.str()); + 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()); + } + else { + PUTBACK(tok, lex); + item_data = ::AST::Item::make_Crate({ item_name }); + } + break; + default: + throw ParseError::Unexpected(lex, tok, {TOK_STRING, TOK_IDENT}); + } + GET_CHECK_TOK(tok, lex, TOK_SEMICOLON); + break; + default: + throw ParseError::Unexpected(lex, tok, {TOK_STRING, TOK_RWORD_FN, TOK_BRACE_OPEN, TOK_RWORD_CRATE}); + } + break; + + // `const NAME` + // `const [unsafe] fn` + case TOK_RWORD_CONST: + switch( GET_TOK(tok, lex) ) + { + case TOK_IDENT: { + item_name = mv$(tok.str()); + + GET_CHECK_TOK(tok, lex, TOK_COLON); + TypeRef type = Parse_Type(lex); + GET_CHECK_TOK(tok, lex, TOK_EQUAL); + AST::Expr val = Parse_Expr(lex); + GET_CHECK_TOK(tok, lex, TOK_SEMICOLON); + item_data = ::AST::Item( ::AST::Static(AST::Static::CONST, mv$(type), mv$(val)) ); + break; } + 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_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()); + // - self not allowed, not prototype + item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, ABI_RUST, false, false,true/*unsafe,const*/) ); + break; + default: + throw ParseError::Unexpected(lex, tok, {TOK_IDENT, TOK_RWORD_FN}); + } + break; + // `static NAME` + // `static mut NAME` + case TOK_RWORD_STATIC: { + bool is_mut = false; + if(GET_TOK(tok, lex) == TOK_RWORD_MUT) { + is_mut = true; + GET_TOK(tok, lex); + } + CHECK_TOK(tok, TOK_IDENT); + item_name = mv$(tok.str()); + + GET_CHECK_TOK(tok, lex, TOK_COLON); + TypeRef type = Parse_Type(lex); + + GET_CHECK_TOK(tok, lex, TOK_EQUAL); + + AST::Expr val = Parse_Expr(lex); + + GET_CHECK_TOK(tok, lex, TOK_SEMICOLON); + item_data = ::AST::Item( ::AST::Static( (is_mut ? AST::Static::MUT : AST::Static::STATIC), mv$(type), mv$(val)) ); + break; } + + // `unsafe fn` + // `unsafe trait` + // `unsafe impl` + case TOK_RWORD_UNSAFE: + meta_items.push_back( AST::MetaItem("#UNSAFE") ); + switch(GET_TOK(tok, lex)) + { + // `unsafe extern fn` + case TOK_RWORD_EXTERN: { + ::std::string abi = "C"; + if(GET_TOK(tok, lex) == TOK_STRING) { + abi = mv$(tok.str()); + } + else { + PUTBACK(tok, lex); + } + GET_CHECK_TOK(tok, lex, TOK_RWORD_FN); + GET_CHECK_TOK(tok, lex, TOK_IDENT); + item_name = mv$(tok.str()); + 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()); + // - 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()); + // TODO: Mark as unsafe + meta_items.push_back( AST::MetaItem("#UNSAFE") ); + item_data = ::AST::Item( Parse_TraitDef(lex, meta_items) ); + break; + // `unsafe impl` + case TOK_RWORD_IMPL: + return ::AST::Named< ::AST::Item> { "", Parse_Impl(lex, mv$(meta_items), true), false }; + default: + throw ParseError::Unexpected(lex, tok, {TOK_RWORD_FN, TOK_RWORD_TRAIT, TOK_RWORD_IMPL}); + } + break; + // `fn` + case TOK_RWORD_FN: + GET_CHECK_TOK(tok, lex, TOK_IDENT); + item_name = mv$(tok.str()); + // - 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_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_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_data = ::AST::Item( Parse_EnumDef(lex, meta_items) ); + break; + // Contextual keywords + case TOK_IDENT: + if( tok.str() == "union" ) { + GET_CHECK_TOK(tok, lex, TOK_IDENT); + item_name = mv$(tok.str()); + item_data = ::AST::Item( Parse_Union(lex, meta_items) ); + } + else { + throw ParseError::Unexpected(lex, tok); + } + break; + // `impl` + case TOK_RWORD_IMPL: + return ::AST::Named< ::AST::Item> { "", Parse_Impl(lex, mv$(meta_items)), false }; + // `trait` + case TOK_RWORD_TRAIT: + GET_CHECK_TOK(tok, lex, TOK_IDENT); + item_name = mv$(tok.str()); + item_data = ::AST::Item( Parse_TraitDef(lex, meta_items) ); + break; + + case TOK_RWORD_MOD: { + GET_CHECK_TOK(tok, lex, TOK_IDENT); + auto name = mv$(tok.str()); + DEBUG("Sub module '" << name << "'"); + AST::Module submod( mod_path + name ); + + // Rules for external files (/ path handling): + // - IF using stdin (path='-') - Disallow and propagate '-' as path + // - IF a #[path] attribute was passed, allow + // - IF in crate root or mod.rs, allow (input flag) + // - else, disallow and set flag + ::std::string path_attr = (meta_items.has("path") ? meta_items.get("path")->string() : ""); + + //submod.m_file_info = get_submod_file(lex.end_span(ps), mod_fileinfo, name, path_attr, LOOK_AHEAD(lex) == TOK_SEMICOLON); + + ::std::string sub_path; + bool sub_file_controls_dir = true; + if( mod_fileinfo.path == "-" ) { + if( path_attr.size() ) { + ERROR(lex.getPosition(), E0000, "Cannot load module from file when reading stdin"); + } + sub_path = "-"; + } + else if( path_attr.size() > 0 ) + { + sub_path = dirname(mod_fileinfo.path) + path_attr; + } + else if( mod_fileinfo.controls_dir ) + { + sub_path = dirname(mod_fileinfo.path) + name; + } + else + { + sub_path = mod_fileinfo.path; + sub_file_controls_dir = false; + } + DEBUG("Mod '" << name << "', sub_path = " << sub_path); + + 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::MetaItems& attrs) + { + for(const auto& at : attrs.m_items) { + if( at.name() == "cfg" && !check_cfg(attrs.m_span, at) ) { + return false; + } + } + return true; + } + }; + + switch( GET_TOK(tok, lex) ) + { + case TOK_BRACE_OPEN: + submod.m_file_info.path = sub_path + "/"; + Parse_ModRoot(lex, submod, meta_items); + GET_CHECK_TOK(tok, lex, TOK_BRACE_CLOSE); + break; + case TOK_SEMICOLON: + if( sub_path == "-" ) { + ERROR(lex.getPosition(), E0000, "Cannot load module from file when reading stdin"); + } + else if( path_attr.size() == 0 && ! mod_fileinfo.controls_dir ) + { + ERROR(lex.getPosition(), 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 + { + ::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.getPosition(), E0000, "Both modname.rs and modname/mod.rs exist"); + } + else if( ifs_dir.is_open() ) + { + // Load from dir + submod.m_file_info.path = newpath_dir + "mod.rs"; + } + else if( ifs_file.is_open() ) + { + submod.m_file_info.path = newpath_file; + } + else + { + // Can't find file + ERROR(lex.getPosition(), E0000, "Can't find file for '" << name << "' in '" << mod_fileinfo.path << "'"); + } + 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); + } + break; + default: + throw ParseError::Generic("Expected { or ; after module name"); + } + item_name = mv$(name); + item_data = ::AST::Item( mv$(submod) ); + break; } + + default: + throw ParseError::Unexpected(lex, tok); + } + + item_data.attrs = mv$(meta_items); + item_data.span = lex.end_span(ps); + + return ::AST::Named< ::AST::Item> { mv$(item_name), mv$(item_data), is_public }; +} + +void Parse_Mod_Item(TokenStream& lex, AST::Module& mod, AST::MetaItems meta_items) +{ + SET_MODULE(lex, mod); + lex.parse_state().parent_attrs = &meta_items; + + //TRACE_FUNCTION; + Token tok; + + // `use ...` + if( LOOK_AHEAD(lex) == TOK_RWORD_USE || (lex.lookahead(0) == TOK_RWORD_PUB && lex.lookahead(1) == TOK_RWORD_USE) ) + { + bool is_public = false; + if( GET_TOK(tok, lex) == TOK_RWORD_PUB ) { + is_public = true; + GET_TOK(tok, lex); + } + + 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)) ); + } +} + +void Parse_ModRoot_Items(TokenStream& lex, AST::Module& mod) +{ + Token tok; + + for(;;) + { + // Check 1 - End of module (either via a closing brace, or EOF) + switch(GET_TOK(tok, lex)) + { + case TOK_BRACE_CLOSE: + case TOK_EOF: + PUTBACK(tok, lex); + return; + default: + PUTBACK(tok, lex); + break; + } + + // Attributes on the following item + AST::MetaItems meta_items; + while( GET_TOK(tok, lex) == TOK_ATTR_OPEN ) + { + meta_items.push_back( Parse_MetaItem(lex) ); + GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE); + } + PUTBACK(tok, lex); + DEBUG("meta_items = " << meta_items); + + Parse_Mod_Item(lex, mod, mv$(meta_items)); + } +} + +void Parse_ModRoot(TokenStream& lex, AST::Module& mod, AST::MetaItems& mod_attrs) +{ + TRACE_FUNCTION; + + Token tok; + + // Attributes on module/crate (will continue loop) + while( GET_TOK(tok, lex) == TOK_CATTR_OPEN ) + { + AST::MetaItem item = Parse_MetaItem(lex); + GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE); + + mod_attrs.push_back( mv$(item) ); + } + PUTBACK(tok, lex); + + Parse_ModRoot_Items(lex, mod); +} + +AST::Crate Parse_Crate(::std::string mainfile) +{ + Token tok; + + Lexer lex(mainfile); + + size_t p = mainfile.find_last_of('/'); + ::std::string mainpath = (p != ::std::string::npos ? ::std::string(mainfile.begin(), mainfile.begin()+p+1) : "./"); + + AST::Crate crate; + + crate.root_module().m_file_info.path = mainpath; + crate.root_module().m_file_info.controls_dir = true; + + Parse_ModRoot(lex, crate.root_module(), crate.m_attrs); + + return crate; +} diff --git a/src/parse/token.cpp b/src/parse/token.cpp index 95adf594..13af2043 100644 --- a/src/parse/token.cpp +++ b/src/parse/token.cpp @@ -38,7 +38,7 @@ Token::~Token() default: break; } - + } Token::Token(): @@ -87,7 +87,7 @@ Token::Token(const InterpolatedFragment& frag) m_type = TOK_INTERPOLATED_STMT; if(0) case InterpolatedFragment::BLOCK: m_type = TOK_INTERPOLATED_BLOCK; - + m_data = reinterpret_cast<const AST::ExprNode*>(frag.m_ptr)->clone().release(); break; case InterpolatedFragment::META: @@ -125,7 +125,7 @@ Token::Token(TagTakeIP, InterpolatedFragment frag) m_type = TOK_INTERPOLATED_STMT; if(0) case InterpolatedFragment::BLOCK: m_type = TOK_INTERPOLATED_BLOCK; - + m_data = reinterpret_cast<AST::ExprNode*>(frag.m_ptr); frag.m_ptr = nullptr; break; @@ -160,7 +160,7 @@ Token Token::clone() const { Token rv(m_type); rv.m_pos = m_pos; - + assert( m_data.tag() != Data::TAGDEAD ); TU_MATCH(Data, (m_data), (e), (None, @@ -254,7 +254,7 @@ enum eTokenType Token::typefromstr(const ::std::string& s) struct EscapedString { const ::std::string& s; EscapedString(const ::std::string& s): s(s) {} - + friend ::std::ostream& operator<<(::std::ostream& os, const EscapedString& x) { for(auto b : x.s) { switch(b) @@ -284,7 +284,7 @@ struct EscapedString { { switch(m_type) { - case TOK_NULL: return "/*null*/"; + case TOK_NULL: return "/*null*/"; case TOK_EOF: return "/*eof*/"; case TOK_NEWLINE: return "\n"; diff --git a/src/parse/token.hpp b/src/parse/token.hpp index 3e7f7c24..0fcf0ed7 100644 --- a/src/parse/token.hpp +++ b/src/parse/token.hpp @@ -26,7 +26,7 @@ public: RcString filename; unsigned int line; unsigned int ofs; - + Position(): filename(""), line(0), @@ -71,11 +71,11 @@ class Token: }), (Fragment, void*) ); - + enum eTokenType m_type; Data m_data; Position m_pos; - + public: virtual ~Token(); Token(); @@ -95,7 +95,7 @@ public: } Token(const Token& t); Token clone() const; - + Token(enum eTokenType type); Token(enum eTokenType type, ::std::string str); Token(uint64_t val, enum eCoreType datatype); @@ -110,14 +110,14 @@ public: 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;)) } uint64_t intval() const { return m_data.as_Integer().m_intval; } double floatval() const { return m_data.as_Float().m_floatval; } - + TypeRef& frag_type() { assert(m_type == TOK_INTERPOLATED_TYPE); return *reinterpret_cast<TypeRef*>( m_data.as_Fragment() ); } AST::Path& frag_path() { assert(m_type == TOK_INTERPOLATED_PATH); return *reinterpret_cast<AST::Path*>( m_data.as_Fragment() ); } AST::Pattern& frag_pattern() { assert(m_type == TOK_INTERPOLATED_PATTERN); return *reinterpret_cast<AST::Pattern*>( m_data.as_Fragment() ); } AST::MetaItem& frag_meta() { assert(m_type == TOK_INTERPOLATED_META); return *reinterpret_cast<AST::MetaItem*>( m_data.as_Fragment() ); } ::std::unique_ptr<AST::ExprNode> take_frag_node(); ::AST::Named<AST::Item> take_frag_item(); - + bool operator==(const Token& r) const { if(type() != r.type()) return false; @@ -133,13 +133,13 @@ public: bool operator!=(const Token& r) const { return !(*this == r); } ::std::string to_str() const; - + void set_pos(Position pos) { m_pos = pos; } const Position& get_pos() const { return m_pos; } - + static const char* typestr(enum eTokenType type); static eTokenType typefromstr(const ::std::string& s); - + SERIALISABLE_PROTOTYPES(); friend ::std::ostream& operator<<(::std::ostream& os, const Token& tok); diff --git a/src/parse/tokenstream.cpp b/src/parse/tokenstream.cpp index 0182e548..9a961a04 100644 --- a/src/parse/tokenstream.cpp +++ b/src/parse/tokenstream.cpp @@ -73,17 +73,17 @@ void TokenStream::putback(Token tok) eTokenType TokenStream::lookahead(unsigned int i) { const unsigned int MAX_LOOKAHEAD = 3; - + if( m_cache_valid ) { if( i == 0 ) return m_cache.type(); i --; } - + if( i >= MAX_LOOKAHEAD ) throw ParseError::BugCheck("Excessive lookahead"); - + while( i >= m_lookahead.size() ) { DEBUG("lookahead - read #" << m_lookahead.size()); @@ -91,7 +91,7 @@ eTokenType TokenStream::lookahead(unsigned int i) auto hygiene = this->realGetHygiene(); m_lookahead.push_back( ::std::make_pair(mv$(tok), mv$(hygiene)) ); } - + DEBUG("lookahead(" << i << ") = " << m_lookahead[i]); return m_lookahead[i].first.type(); } diff --git a/src/parse/tokenstream.hpp b/src/parse/tokenstream.hpp index ae737d0d..85fc62e2 100644 --- a/src/parse/tokenstream.hpp +++ b/src/parse/tokenstream.hpp @@ -26,15 +26,15 @@ struct ParseState bool disallow_struct_literal = false; // A debugging hook that disables expansion of macros bool no_expand_macros = false; - + ::AST::Module* module = nullptr; ::AST::MetaItems* parent_attrs = nullptr; - + ::AST::Module& get_current_mod() { assert(this->module); return *this->module; } - + friend ::std::ostream& operator<<(::std::ostream& os, const ParseState& ps) { os << "ParseState {"; if(ps.disallow_struct_literal) os << " disallow_struct_literal"; @@ -47,7 +47,7 @@ struct ParseState class TokenStream { friend class TTLexer; // needs access to internals to know what was consumed - + bool m_cache_valid; Token m_cache; Ident::Hygiene m_hygiene; @@ -59,17 +59,17 @@ public: Token getToken(); void putback(Token tok); eTokenType lookahead(unsigned int count); - + virtual Position getPosition() const = 0; Ident::Hygiene getHygiene() const; - + ParseState& parse_state() { return m_parse_state; } - + ProtoSpan start_span() const; Span end_span(ProtoSpan ps) const; - + Ident get_ident(Token tok) const; - + protected: virtual Token realGetToken() = 0; virtual Ident::Hygiene realGetHygiene() const = 0; diff --git a/src/parse/tokentree.hpp b/src/parse/tokentree.hpp index 8472ec7f..26e23876 100644 --- a/src/parse/tokentree.hpp +++ b/src/parse/tokentree.hpp @@ -1,61 +1,61 @@ -/*
- * MRustC - Rust Compiler
- * - By John Hodge (Mutabah/thePowersGang)
- *
- * parse/tokentree.hpp
- * - Token Trees (groups of tokens
- */
-#ifndef TOKENTREE_HPP_INCLUDED
-#define TOKENTREE_HPP_INCLUDED
-
-#include "token.hpp"
-#include <ident.hpp>
-#include <vector>
-
-class TokenTree
-{
- Ident::Hygiene m_hygiene;
- Token m_tok;
- ::std::vector<TokenTree> m_subtrees;
-public:
- virtual ~TokenTree() {}
- TokenTree() {}
- TokenTree(TokenTree&&) = default;
- TokenTree& operator=(TokenTree&&) = default;
- TokenTree(enum eTokenType ty):
- m_tok( Token(ty) )
- {
- }
- TokenTree(Token tok):
- m_tok( ::std::move(tok) )
- {
- }
- TokenTree(Ident::Hygiene hygiene, Token tok):
- m_hygiene( ::std::move(hygiene) ),
- m_tok( ::std::move(tok) )
- {
- }
- TokenTree(Ident::Hygiene hygiene, ::std::vector<TokenTree> subtrees):
- m_hygiene( ::std::move(hygiene) ),
- m_subtrees( ::std::move(subtrees) )
- {
- }
-
- TokenTree clone() const;
-
- bool is_token() const {
- return m_tok.type() != TOK_NULL;
- }
- unsigned int size() const {
- return m_subtrees.size();
- }
- const TokenTree& operator[](unsigned int idx) const { return m_subtrees[idx]; }
- TokenTree& operator[](unsigned int idx) { return m_subtrees[idx]; }
- const Token& tok() const { return m_tok; }
- Token& tok() { return m_tok; }
- const Ident::Hygiene& hygiene() const { return m_hygiene; }
-
- friend ::std::ostream& operator<<(::std::ostream& os, const TokenTree& tt);
-};
-
-#endif // TOKENTREE_HPP_INCLUDED
+/* + * MRustC - Rust Compiler + * - By John Hodge (Mutabah/thePowersGang) + * + * parse/tokentree.hpp + * - Token Trees (groups of tokens + */ +#ifndef TOKENTREE_HPP_INCLUDED +#define TOKENTREE_HPP_INCLUDED + +#include "token.hpp" +#include <ident.hpp> +#include <vector> + +class TokenTree +{ + Ident::Hygiene m_hygiene; + Token m_tok; + ::std::vector<TokenTree> m_subtrees; +public: + virtual ~TokenTree() {} + TokenTree() {} + TokenTree(TokenTree&&) = default; + TokenTree& operator=(TokenTree&&) = default; + TokenTree(enum eTokenType ty): + m_tok( Token(ty) ) + { + } + TokenTree(Token tok): + m_tok( ::std::move(tok) ) + { + } + TokenTree(Ident::Hygiene hygiene, Token tok): + m_hygiene( ::std::move(hygiene) ), + m_tok( ::std::move(tok) ) + { + } + TokenTree(Ident::Hygiene hygiene, ::std::vector<TokenTree> subtrees): + m_hygiene( ::std::move(hygiene) ), + m_subtrees( ::std::move(subtrees) ) + { + } + + TokenTree clone() const; + + bool is_token() const { + return m_tok.type() != TOK_NULL; + } + unsigned int size() const { + return m_subtrees.size(); + } + const TokenTree& operator[](unsigned int idx) const { return m_subtrees[idx]; } + TokenTree& operator[](unsigned int idx) { return m_subtrees[idx]; } + const Token& tok() const { return m_tok; } + Token& tok() { return m_tok; } + const Ident::Hygiene& hygiene() const { return m_hygiene; } + + friend ::std::ostream& operator<<(::std::ostream& os, const TokenTree& tt); +}; + +#endif // TOKENTREE_HPP_INCLUDED diff --git a/src/parse/ttstream.hpp b/src/parse/ttstream.hpp index 575178ac..946cca5f 100644 --- a/src/parse/ttstream.hpp +++ b/src/parse/ttstream.hpp @@ -21,7 +21,7 @@ public: ~TTStream(); TTStream& operator=(const TTStream& x) { m_stack = x.m_stack; return *this; } - + Position getPosition() const override; protected: @@ -44,7 +44,7 @@ public: TTStreamO& operator=(const TTStreamO& x) { m_stack = x.m_stack; return *this; } TTStreamO& operator=(TTStreamO&& x) = default; - + Position getPosition() const override; protected: diff --git a/src/parse/types.cpp b/src/parse/types.cpp index 4cd9d755..cb664f79 100644 --- a/src/parse/types.cpp +++ b/src/parse/types.cpp @@ -32,7 +32,7 @@ TypeRef Parse_Type_Int(TokenStream& lex, bool allow_trait_list) auto ps = lex.start_span(); Token tok; - + switch( GET_TOK(tok, lex) ) { case TOK_INTERPOLATED_TYPE: @@ -45,7 +45,7 @@ TypeRef Parse_Type_Int(TokenStream& lex, bool allow_trait_list) // '_' = Wildcard (type inferrence variable) case TOK_UNDERSCORE: return TypeRef(Span(tok.get_pos())); - + // 'unsafe' - An unsafe function type case TOK_RWORD_UNSAFE: // 'extern' - A function type with an ABI @@ -54,10 +54,10 @@ TypeRef Parse_Type_Int(TokenStream& lex, bool allow_trait_list) case TOK_RWORD_FN: PUTBACK(tok, lex); return Parse_Type_Fn(lex); - + case TOK_RWORD_IMPL: return Parse_Type_ErasedType(lex, allow_trait_list); - + // '<' - An associated type cast case TOK_LT: case TOK_DOUBLE_LT: { @@ -65,7 +65,7 @@ TypeRef Parse_Type_Int(TokenStream& lex, bool allow_trait_list) auto path = Parse_Path(lex, PATH_GENERIC_TYPE); return TypeRef(TypeRef::TagPath(), lex.end_span(ps), mv$(path)); } - // + // case TOK_RWORD_FOR: { auto hrls = Parse_HRB(lex); switch(LOOK_AHEAD(lex)) @@ -156,14 +156,14 @@ TypeRef Parse_Type_Int(TokenStream& lex, bool allow_trait_list) throw ParseError::Unexpected(lex, tok/*, "; or ]"*/); } } - + // '(' - Tuple (or lifetime bounded trait) case TOK_PAREN_OPEN: { DEBUG("Tuple"); if( GET_TOK(tok, lex) == TOK_PAREN_CLOSE ) return TypeRef(TypeRef::TagTuple(), lex.end_span(ps), {}); PUTBACK(tok, lex); - + TypeRef inner = Parse_Type(lex, true); if( LOOK_AHEAD(lex) == TOK_PAREN_CLOSE ) { @@ -198,12 +198,12 @@ TypeRef Parse_Type_Fn(TokenStream& lex, ::std::vector<::std::string> hrls) // TODO: HRLs TRACE_FUNCTION; Token tok; - + ::std::string abi = ""; bool is_unsafe = false; - + GET_TOK(tok, lex); - + if( tok.type() == TOK_RWORD_UNSAFE ) { is_unsafe = true; @@ -231,7 +231,7 @@ TypeRef Parse_Type_Fn(TokenStream& lex, ::std::vector<::std::string> hrls) if( LOOK_AHEAD(lex) == TOK_TRIPLE_DOT ) { GET_TOK(tok, lex); is_variadic = true; - break; + break; } // Handle `ident: ` if( lex.lookahead(0) == TOK_IDENT && lex.lookahead(1) == TOK_COLON ) { @@ -245,7 +245,7 @@ TypeRef Parse_Type_Fn(TokenStream& lex, ::std::vector<::std::string> hrls) } } GET_CHECK_TOK(tok, lex, TOK_PAREN_CLOSE); - + TypeRef ret_type = TypeRef(TypeRef::TagUnit(), Span(tok.get_pos())); if( GET_TOK(tok, lex) == TOK_THINARROW ) { @@ -254,7 +254,7 @@ TypeRef Parse_Type_Fn(TokenStream& lex, ::std::vector<::std::string> hrls) else { PUTBACK(tok, lex); } - + return TypeRef(TypeRef::TagFunction(), lex.end_span(ps), is_unsafe, mv$(abi), mv$(args), is_variadic, mv$(ret_type)); } @@ -263,7 +263,7 @@ TypeRef Parse_Type_Path(TokenStream& lex, ::std::vector<::std::string> hrls, boo Token tok; auto ps = lex.start_span(); - + if( ! allow_trait_list ) { return TypeRef(TypeRef::TagPath(), lex.end_span(ps), Parse_Path(lex, PATH_GENERIC_TYPE)); @@ -307,7 +307,7 @@ TypeRef Parse_Type_ErasedType(TokenStream& lex, bool allow_trait_list) traits.push_back( Parse_Path(lex, PATH_GENERIC_TYPE) ); } while( GET_TOK(tok, lex) == TOK_PLUS ); PUTBACK(tok, lex); - + if( lifetimes.size() ) DEBUG("TODO: Lifetime bounds on erased types"); return TypeRef(lex.end_span(ps), TypeData::make_ErasedType({ {}, mv$(traits) })); diff --git a/src/resolve/absolute.cpp b/src/resolve/absolute.cpp index 0b9c2476..db85ed3f 100644 --- a/src/resolve/absolute.cpp +++ b/src/resolve/absolute.cpp @@ -20,7 +20,7 @@ struct GenericSlot Method, } level; unsigned short index; - + unsigned int to_binding() const { if(level == Level::Method && index != 0xFFFF) { return (unsigned int)index + 256; @@ -63,7 +63,7 @@ struct Context unsigned int m_var_count; unsigned int m_block_level; bool m_frozen_bind_set; - + Context(const ::AST::Crate& crate, const ::AST::Module& mod): m_crate(crate), m_mod(mod), @@ -71,11 +71,11 @@ struct Context m_block_level(0), m_frozen_bind_set( false ) {} - + void push(const ::AST::GenericParams& params, GenericSlot::Level level, bool has_self=false) { auto e = Ent::make_Generic({}); auto& data = e.as_Generic(); - + if( has_self ) { //assert( level == GenericSlot::Level::Top ); data.types.push_back( Named<GenericSlot> { "Self", GenericSlot { level, 0xFFFF } } ); @@ -90,7 +90,7 @@ struct Context if( params.lft_params().size() > 0 ) { //TODO(Span(), "resolve/absolute.cpp - Context::push(GenericParams) - Lifetime params - " << params); } - + m_name_context.push_back(mv$(e)); } void pop(const ::AST::GenericParams& , bool has_self=false) { @@ -111,7 +111,7 @@ struct Context BUG(Span(), "resolve/absolute.cpp - Context::pop(GenericParams) - Mismatched pop"); m_name_context.pop_back(); } - + class RootBlockScope { friend struct Context; Context& ctxt; @@ -133,7 +133,7 @@ struct Context RootBlockScope clear_rootblock() { return RootBlockScope(*this, ~0u); } - + void push_self(const TypeRef& tr) { m_name_context.push_back( Ent::make_ConcreteSelf(&tr) ); } @@ -224,7 +224,7 @@ struct Context } m_block_level -= 1; } - + /// Indicate that a multiple-pattern binding is started void start_patbind() { assert( m_block_level > 0 ); @@ -239,8 +239,8 @@ struct Context void end_patbind() { m_frozen_bind_set = false; } - - + + enum class LookupMode { Namespace, Type, @@ -292,7 +292,7 @@ struct Context } } break; - + case LookupMode::Type: //if( name == "IntoIterator" ) { // DEBUG("lookup_in_mod(mod="<<mod.path()<<")"); @@ -406,14 +406,14 @@ struct Context ) ) } - + // Top-level module DEBUG("- Top module (" << m_mod.path() << ")"); ::AST::Path rv; if( this->lookup_in_mod(m_mod, name, mode, rv) ) { return rv; } - + DEBUG("- Primitives"); switch(mode) { @@ -429,7 +429,7 @@ struct Context default: break; } - + return AST::Path(); } @@ -468,10 +468,10 @@ struct Context ) ) } - + ERROR(sp, E0000, "Unable to find local " << (mode == LookupMode::Variable ? "variable" : "type") << " '" << name << "'"); } - + /// Clones the context, including only the module-level items (i.e. just the Module entries) Context clone_mod() const { auto rv = Context(this->m_crate, this->m_mod); @@ -543,18 +543,18 @@ void Resolve_Absolute_Path_BindUFCS(Context& context, const Span& sp, Context::L nodes.erase( nodes.begin() ); path = ::AST::Path( ::AST::Path::TagUfcs(), TypeRef(span, mv$(inner_path)), ::AST::Path(), mv$(nodes) ); } - + const auto& ufcs = path.m_class.as_UFCS(); if( ufcs.nodes.size() == 0 ) { - + if( mode == Context::LookupMode::Type && ufcs.trait && *ufcs.trait == ::AST::Path() ) { return ; } - + BUG(sp, "UFCS with no nodes encountered - " << path); } const auto& node = ufcs.nodes.at(0); - + if( ufcs.trait && ufcs.trait->is_valid() ) { // Trait is specified, definitely a trait item @@ -567,7 +567,7 @@ void Resolve_Absolute_Path_BindUFCS(Context& context, const Span& sp, Context::L return ; assert( pb.as_Trait().trait_ ); const auto& tr = *pb.as_Trait().trait_; - + switch(mode) { case Context::LookupMode::Pattern: @@ -637,18 +637,18 @@ namespace { const auto& path_abs = path.m_class.as_Absolute(); auto type_path = ::AST::Path( path ); type_path.m_class.as_Absolute().nodes.resize( i+1 ); - + auto new_path = ::AST::Path(::AST::Path::TagUfcs(), ::TypeRef(sp, mv$(type_path)), ::AST::Path()); for( unsigned int j = i+1; j < path_abs.nodes.size(); j ++ ) new_path.nodes().push_back( mv$(path_abs.nodes[j]) ); - + return new_path; } AST::Path split_replace_into_ufcs_path(const Span& sp, AST::Path path, unsigned int i, const AST::Path& ty_path_tpl) { auto& path_abs = path.m_class.as_Absolute(); auto& n = path_abs.nodes[i]; - + auto type_path = ::AST::Path(ty_path_tpl); if( ! n.args().is_empty() ) { type_path.nodes().back().args() = mv$(n.args()); @@ -656,10 +656,10 @@ namespace { auto new_path = ::AST::Path(::AST::Path::TagUfcs(), ::TypeRef(sp, mv$(type_path)), ::AST::Path()); for( unsigned int j = i+1; j < path_abs.nodes.size(); j ++ ) new_path.nodes().push_back( mv$(path_abs.nodes[j]) ); - + return new_path; } - + void Resolve_Absolute_Path_BindAbsolute__hir_from_import(Context& context, const Span& sp, bool is_value, AST::Path& path, const ::HIR::SimplePath& p) { TRACE_FUNCTION_FR("path="<<path<<", p="<<p, path); @@ -671,7 +671,7 @@ namespace { auto it = hmod->m_mod_items.find(name); if( it == hmod->m_mod_items.end() ) ERROR(sp, E0000, "Couldn't find path component '" << name << "' of " << p); - + TU_MATCH_DEF(::HIR::TypeItem, (it->second->ent), (e), ( TODO(sp, "Unknown item type in path - " << i << " " << p << " - " << it->second->ent.tag_str()); @@ -685,7 +685,7 @@ namespace { ASSERT_BUG(sp, it != e.m_variants.end(), "Extern crate import path points to non-present variant - " << p); unsigned int var_idx = it - e.m_variants.begin(); auto pb = ::AST::PathBinding::make_EnumVar({nullptr, var_idx, &e}); - + // Construct output path (with same set of parameters) AST::Path rv( p.m_crate_name, {} ); rv.nodes().reserve( p.m_components.size() ); @@ -694,7 +694,7 @@ namespace { rv.nodes().back().args() = mv$( path.nodes().back().args() ); rv.bind( mv$(pb) ); path = mv$(rv); - + return ; ), (Module, @@ -702,9 +702,9 @@ namespace { ) ) } - + ::AST::PathBinding pb; - + const auto& name = p.m_components.back(); if( is_value ) { @@ -763,7 +763,7 @@ namespace { ) ) } - + // Construct output path (with same set of parameters) AST::Path rv( p.m_crate_name, {} ); rv.nodes().reserve( p.m_components.size() ); @@ -773,12 +773,12 @@ namespace { rv.bind( mv$(pb) ); path = mv$(rv); } - + void Resolve_Absolute_Path_BindAbsolute__hir_from(Context& context, const Span& sp, Context::LookupMode& mode, ::AST::Path& path, const AST::ExternCrate& crate, unsigned int start) { TRACE_FUNCTION_FR(path << " start=" << start, path); auto& path_abs = path.m_class.as_Absolute(); - + if( path_abs.nodes.empty() ) { switch(mode) { @@ -789,7 +789,7 @@ namespace { TODO(sp, ""); } } - + const ::HIR::Module* hmod = &crate.m_hir->m_root_module; for(unsigned int i = start; i < path_abs.nodes.size() - 1; i ++ ) { @@ -798,7 +798,7 @@ namespace { auto it = hmod->m_mod_items.find(n.name()); 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, // - Update path then restart @@ -830,7 +830,7 @@ namespace { } } trait_path.bind( ::AST::PathBinding::make_Trait({nullptr, &e}) ); - + ::AST::Path new_path; const auto& next_node = path_abs.nodes[i+1]; // If the named item can't be found in the trait, fall back to it being a type binding @@ -847,7 +847,7 @@ namespace { found = (e.m_values.find( next_node.name() ) != e.m_values.end()); break; } - + if( !found ) { new_path = ::AST::Path(::AST::Path::TagUfcs(), ::TypeRef(sp, mv$(trait_path))); } @@ -856,7 +856,7 @@ namespace { } for( unsigned int j = i+1; j < path_abs.nodes.size(); j ++ ) new_path.nodes().push_back( mv$(path_abs.nodes[j]) ); - + path = mv$(new_path); return Resolve_Absolute_Path_BindUFCS(context, sp, mode, path); ), @@ -881,7 +881,7 @@ namespace { for( const auto& var : e.m_variants ) { if( var.first == last_node.name() ) { - + if( i != path_abs.nodes.size() - 2 ) { ERROR(sp, E0000, "Unexpected enum in path " << path); } @@ -889,7 +889,7 @@ namespace { if( ! n.args().is_empty() ) { ERROR(sp, E0000, "Type parameters were not expected here (enum params go on the variant)"); } - + path.bind( ::AST::PathBinding::make_EnumVar({nullptr, static_cast<unsigned int>(&var - &*e.m_variants.begin()), &e}) ); path = split_into_crate(sp, mv$(path), start, crate.m_name); return; @@ -901,7 +901,7 @@ namespace { ) ) } - + const auto& name = path_abs.nodes.back().name(); switch(mode) { @@ -942,7 +942,7 @@ namespace { } } break; - + case Context::LookupMode::Pattern: { auto v = hmod->m_mod_items.find(name); @@ -1028,14 +1028,14 @@ void Resolve_Absolute_Path_BindAbsolute(Context& context, const Span& sp, Contex { TRACE_FUNCTION_FR("path = " << path, path); auto& path_abs = path.m_class.as_Absolute(); - + if( path_abs.crate != "" ) { // TODO: Handle items from other crates (back-converting HIR paths) Resolve_Absolute_Path_BindAbsolute__hir_from(context, sp, mode, path, context.m_crate.m_extern_crates.at(path_abs.crate), 0); return ; } - - + + const ::AST::Module* mod = &context.m_crate.m_root_module; for(unsigned int i = 0; i < path_abs.nodes.size() - 1; i ++ ) { @@ -1045,11 +1045,11 @@ void Resolve_Absolute_Path_BindAbsolute(Context& context, const Span& sp, Contex if( ! n.args().is_empty() ) { ERROR(sp, E0000, "Type parameters were not expected here"); } - + if( n.name() == "#" ) { TODO(sp, "magic module"); } - + char c; unsigned int idx; ::std::stringstream ss( n.name() ); @@ -1067,7 +1067,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), ( ERROR(sp, E0000, "Encountered non-namespace item '" << n.name() << "' ("<<name_ref.path<<") in path " << path); @@ -1143,7 +1143,7 @@ void Resolve_Absolute_Path_BindAbsolute(Context& context, const Span& sp, Contex } for( unsigned int j = i+1; j < path_abs.nodes.size(); j ++ ) new_path.nodes().push_back( mv$(path_abs.nodes[j]) ); - + path = mv$(new_path); return Resolve_Absolute_Path_BindUFCS(context, sp, mode, path); ), @@ -1164,7 +1164,7 @@ void Resolve_Absolute_Path_BindAbsolute(Context& context, const Span& sp, Contex const auto& last_node = path_abs.nodes.back(); for( const auto& var : e.enum_->variants() ) { if( var.m_name == last_node.name() ) { - + if( i != path_abs.nodes.size() - 2 ) { ERROR(sp, E0000, "Unexpected enum in path " << path); } @@ -1172,12 +1172,12 @@ void Resolve_Absolute_Path_BindAbsolute(Context& context, const Span& sp, Contex if( ! n.args().is_empty() ) { ERROR(sp, E0000, "Type parameters were not expected here (enum params go on the variant)"); } - + path.bind_enum_var(*e.enum_, var.m_name); return; } } - + path = split_replace_into_ufcs_path(sp, mv$(path), i, name_ref.path); return Resolve_Absolute_Path_BindUFCS(context, sp, mode, path); } @@ -1210,14 +1210,14 @@ void Resolve_Absolute_Path_BindAbsolute(Context& context, const Span& sp, Contex ) } } - + // Set binding to binding of node in last module ::AST::Path tmp; if( ! Context::lookup_in_mod(*mod, path_abs.nodes.back().name(), mode, tmp) ) { ERROR(sp, E0000, "Couldn't find " << Context::lookup_mode_msg(mode) << " '" << path_abs.nodes.back().name() << "' of " << path); } assert( ! tmp.binding().is_Unbound() ); - + // Replaces the path with the one returned by `lookup_in_mod`, ensuring that `use` aliases are eliminated DEBUG("Replace " << path << " with " << tmp); auto args = mv$(path.nodes().back().args()); @@ -1235,7 +1235,7 @@ void Resolve_Absolute_Path_BindAbsolute(Context& context, const Span& sp, Contex void Resolve_Absolute_Path(/*const*/ Context& context, const Span& sp, Context::LookupMode mode, ::AST::Path& path) { TRACE_FUNCTION_FR("mode = " << mode << ", path = " << path, path); - + TU_MATCH(::AST::Path::Class, (path.m_class), (e), (Invalid, BUG(sp, "Attempted resolution of invalid path"); @@ -1270,7 +1270,7 @@ void Resolve_Absolute_Path(/*const*/ Context& context, const Span& sp, Context:: if( !pe.module_ ) { assert( pe.hir ); const auto& mod = *pe.hir; - + switch( e.nodes.size() == 2 ? mode : Context::LookupMode::Namespace ) { case Context::LookupMode::Namespace: @@ -1321,11 +1321,11 @@ void Resolve_Absolute_Path(/*const*/ Context& context, const Span& sp, Context:: auto ct = coretype_fromstring(e.nodes[0].name()); p = ::AST::Path( ::AST::Path::TagUfcs(), TypeRef(Span("-",0,0,0,0), ct), ::AST::Path(), ::std::vector< ::AST::PathNode>() ); } - + DEBUG("Primitive module hack yeilded " << p); ) } - + if( e.nodes.size() > 1 ) { // Only primitive types turn `Local` paths @@ -1355,7 +1355,7 @@ void Resolve_Absolute_Path(/*const*/ Context& context, const Span& sp, Context:: } path = mv$(p); } - + if( !path.is_trivial() ) Resolve_Absolute_PathNodes(context, sp, path.nodes()); ), @@ -1372,7 +1372,7 @@ void Resolve_Absolute_Path(/*const*/ Context& context, const Span& sp, Context:: 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] == '#' ) start_len --; - + // - Create a new path ::AST::Path np("", {}); auto& np_nodes = np.nodes(); @@ -1381,10 +1381,10 @@ void Resolve_Absolute_Path(/*const*/ Context& context, const Span& sp, Context:: np_nodes.push_back( mp_nodes[i] ); for(auto& en : e.nodes) np_nodes.push_back( mv$(en) ); - + if( !path.is_trivial() ) Resolve_Absolute_PathNodes(context, sp, np_nodes); - + path = mv$(np); ), (Absolute, @@ -1398,11 +1398,11 @@ void Resolve_Absolute_Path(/*const*/ Context& context, const Span& sp, Context:: if( e.trait && *e.trait != ::AST::Path() ) { Resolve_Absolute_Path(context, sp, Context::LookupMode::Type, *e.trait); } - + Resolve_Absolute_PathNodes(context, sp, e.nodes); ) ) - + DEBUG("path = " << path); // TODO: Should this be deferred until the HIR? // - Doing it here so the HIR lowering has a bit more information @@ -1424,7 +1424,7 @@ void Resolve_Absolute_Path(/*const*/ Context& context, const Span& sp, Context:: Resolve_Absolute_Path_BindUFCS(context, sp, mode, path); ) ) - + // TODO: Expand default type parameters? // - Helps with cases like PartialOrd<Self>, but hinders when the default is a hint (in expressions) } @@ -1495,7 +1495,7 @@ void Resolve_Absolute_Type(Context& context, TypeRef& type) } assert( ufcs.nodes.size() == 1); ) - + TU_IFLET(::AST::PathBinding, e.path.binding(), Trait, be, auto ty = ::TypeRef( type.span(), {}, ::make_vec1(mv$(e.path)) ); type = mv$(ty); @@ -1534,12 +1534,12 @@ void Resolve_Absolute_ExprNode(Context& context, ::AST::ExprNode& node) public AST::NodeVisitorDef { Context& context; - + NV(Context& context): context(context) { } - + void visit(AST::ExprNode_Block& node) override { DEBUG("ExprNode_Block"); if( node.m_local_mod ) { @@ -1556,7 +1556,7 @@ void Resolve_Absolute_ExprNode(Context& context, ::AST::ExprNode& node) this->context.pop( *node.m_local_mod ); } } - + void visit(AST::ExprNode_Match& node) override { DEBUG("ExprNode_Match"); node.m_val->visit( *this ); @@ -1579,12 +1579,12 @@ void Resolve_Absolute_ExprNode(Context& context, ::AST::ExprNode& node) else { Resolve_Absolute_Pattern(this->context, true, arm.m_patterns[0]); } - + if(arm.m_cond) arm.m_cond->visit( *this ); assert( arm.m_code ); arm.m_code->visit( *this ); - + this->context.pop_block(); } } @@ -1606,7 +1606,7 @@ void Resolve_Absolute_ExprNode(Context& context, ::AST::ExprNode& node) node.m_code->visit( *this ); this->context.pop_block(); } - + void visit(AST::ExprNode_LetBinding& node) override { DEBUG("ExprNode_LetBinding"); Resolve_Absolute_Type(this->context, node.m_type); @@ -1616,14 +1616,14 @@ void Resolve_Absolute_ExprNode(Context& context, ::AST::ExprNode& node) void visit(AST::ExprNode_IfLet& node) override { DEBUG("ExprNode_IfLet"); node.m_value->visit( *this ); - + this->context.push_block(); Resolve_Absolute_Pattern(this->context, true, node.m_pattern); - + assert( node.m_true ); node.m_true->visit( *this ); this->context.pop_block(); - + if(node.m_false) node.m_false->visit(*this); } @@ -1653,17 +1653,17 @@ void Resolve_Absolute_ExprNode(Context& context, ::AST::ExprNode& node) } void visit(AST::ExprNode_Closure& node) override { DEBUG("ExprNode_Closure"); - + Resolve_Absolute_Type(this->context, node.m_return); - + this->context.push_block(); for( auto& arg : node.m_args ) { Resolve_Absolute_Type(this->context, arg.second); Resolve_Absolute_Pattern(this->context, false, arg.first); } - + node.m_code->visit(*this); - + this->context.pop_block(); } } expr_iter(context); @@ -1744,7 +1744,7 @@ void Resolve_Absolute_Pattern(Context& context, bool allow_refutable, ::AST::Pa } else { auto name = mv$( e.name ); - + pat = ::AST::Pattern(::AST::Pattern::TagBind(), mv$(name)); pat.binding().m_slot = context.push_var( pat.span(), pat.binding().m_name ); } @@ -1828,32 +1828,32 @@ void Resolve_Absolute_ImplItems(Context& item_context, ::AST::NamedList< ::AST: assert( e.params().lft_params().size() == 0 ); item_context.push( e.params(), GenericSlot::Level::Method, true ); Resolve_Absolute_Generic(item_context, e.params()); - + Resolve_Absolute_Type( item_context, e.type() ); - + item_context.pop( e.params(), true ); ), (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() ); ), (Static, @@ -1891,9 +1891,9 @@ void Resolve_Absolute_ImplItems(Context& item_context, ::std::vector< ::AST::Im assert( e.params().lft_params().size() == 0 ); item_context.push( e.params(), GenericSlot::Level::Method, true ); Resolve_Absolute_Generic(item_context, e.params()); - + Resolve_Absolute_Type( item_context, e.type() ); - + item_context.pop( e.params(), true ); ), (Function, @@ -1925,9 +1925,9 @@ void Resolve_Absolute_Function(Context& item_context, ::AST::Function& fcn) for(auto& arg : fcn.args()) { Resolve_Absolute_Pattern( item_context, false, arg.first ); } - + Resolve_Absolute_Expr( item_context, fcn.code() ); - + item_context.pop_block(); } @@ -1944,7 +1944,7 @@ void Resolve_Absolute_Struct(Context& item_context, ::AST::Struct& e) { item_context.push( e.params(), GenericSlot::Level::Top ); Resolve_Absolute_Generic(item_context, e.params()); - + TU_MATCH(::AST::StructData, (e.m_data), (s), (Tuple, for(auto& field : s.ents) { @@ -1957,25 +1957,25 @@ void Resolve_Absolute_Struct(Context& item_context, ::AST::Struct& e) } ) ) - + item_context.pop( e.params() ); } void Resolve_Absolute_Union(Context& item_context, ::AST::Union& e) { item_context.push( e.m_params, GenericSlot::Level::Top ); Resolve_Absolute_Generic(item_context, e.m_params); - + for(auto& field : e.m_variants) { Resolve_Absolute_Type(item_context, field.m_type); } - + item_context.pop( e.m_params ); } void Resolve_Absolute_Trait(Context& item_context, ::AST::Trait& e) { item_context.push( e.params(), GenericSlot::Level::Top, true ); Resolve_Absolute_Generic(item_context, e.params()); - + for(auto& st : e.supertraits()) { if( !st.ent.is_valid() ) { DEBUG("- ST 'static"); @@ -1985,16 +1985,16 @@ void Resolve_Absolute_Trait(Context& item_context, ::AST::Trait& e) Resolve_Absolute_Path(item_context, st.sp, Context::LookupMode::Type, st.ent); } } - + Resolve_Absolute_ImplItems(item_context, e.items()); - + item_context.pop( e.params(), true ); } void Resolve_Absolute_Enum(Context& item_context, ::AST::Enum& e) { item_context.push( e.params(), GenericSlot::Level::Top ); Resolve_Absolute_Generic(item_context, e.params()); - + for(auto& variant : e.variants()) { TU_MATCH(::AST::EnumVariantData, (variant.m_data), (s), @@ -2014,7 +2014,7 @@ void Resolve_Absolute_Enum(Context& item_context, ::AST::Enum& e) ) ) } - + item_context.pop( e.params() ); } @@ -2024,7 +2024,7 @@ void Resolve_Absolute_Mod(const ::AST::Crate& crate, ::AST::Module& mod) { void Resolve_Absolute_Mod( Context item_context, ::AST::Module& mod ) { TRACE_FUNCTION_F("(mod="<<mod.path()<<")"); - + for( auto& i : mod.items() ) { TU_MATCH(AST::Item, (i.data), (e), @@ -2062,13 +2062,13 @@ void Resolve_Absolute_Mod( Context item_context, ::AST::Module& mod ) Resolve_Absolute_Generic(item_context, def.params()); assert( def.trait().ent.is_valid() ); Resolve_Absolute_Path(item_context, def.trait().sp, Context::LookupMode::Type, def.trait().ent); - + if( e.items().size() != 0 ) { ERROR(def.span(), E0000, "impl Trait for .. with methods"); } - + item_context.pop(def.params()); - + const_cast< ::AST::Trait*>(def.trait().ent.binding().as_Trait().trait_)->set_is_marker(); } else @@ -2076,14 +2076,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_ImplItems(item_context, e.items()); - + item_context.pop(def.params()); item_context.pop_self( def.type() ); } @@ -2093,14 +2093,14 @@ void Resolve_Absolute_Mod( Context item_context, ::AST::Module& mod ) item_context.push_self( impl_def.type() ); item_context.push(impl_def.params(), GenericSlot::Level::Top); Resolve_Absolute_Generic(item_context, impl_def.params()); - + Resolve_Absolute_Type(item_context, impl_def.type()); if( !impl_def.trait().ent.is_valid() ) BUG(impl_def.span(), "Encountered negative impl with no trait"); Resolve_Absolute_Path(item_context, impl_def.trait().sp, Context::LookupMode::Type, impl_def.trait().ent); - + // No items - + item_context.pop(impl_def.params()); item_context.pop_self( impl_def.type() ); ), @@ -2123,9 +2123,9 @@ void Resolve_Absolute_Mod( Context item_context, ::AST::Module& mod ) DEBUG("Type - " << i.name); item_context.push( e.params(), GenericSlot::Level::Top, true ); Resolve_Absolute_Generic(item_context, e.params()); - + Resolve_Absolute_Type( item_context, e.type() ); - + item_context.pop( e.params(), true ); ), (Struct, @@ -2146,7 +2146,7 @@ void Resolve_Absolute_Mod( Context item_context, ::AST::Module& mod ) ) ) } - + // - Run through the indexed items and fix up those paths static Span sp; DEBUG("mod = " << mod.path()); diff --git a/src/resolve/index.cpp b/src/resolve/index.cpp index c0276695..b65bea6f 100644 --- a/src/resolve/index.cpp +++ b/src/resolve/index.cpp @@ -53,11 +53,11 @@ 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) { auto& list = get_mod_index(mod, location); - + bool was_import = (ir != mod.path() + name); if( list.count(name) > 0 ) { - if( error_on_collision ) + if( error_on_collision ) { ERROR(sp, E0000, "Duplicate definition of name '" << name << "' in " << location << " scope (" << mod.path() << ")"); } @@ -99,7 +99,7 @@ void Resolve_Index_Module_Base(const AST::Crate& crate, AST::Module& mod) { ::AST::Path p = mod.path() + i.name; //DEBUG("- p = " << p << " : " << ::AST::Item::tag_to_str(i.data.tag())); - + TU_MATCH(AST::Item, (i.data), (e), (None, ), @@ -112,7 +112,7 @@ void Resolve_Index_Module_Base(const AST::Crate& crate, AST::Module& mod) ), (NegImpl, ), - + (Use, // Skip for now ), @@ -162,7 +162,7 @@ void Resolve_Index_Module_Base(const AST::Crate& crate, AST::Module& mod) ) ) } - + bool has_pub_wildcard = false; // Named imports for( const auto& i : mod.items() ) @@ -173,7 +173,7 @@ void Resolve_Index_Module_Base(const AST::Crate& crate, AST::Module& mod) if( i.name != "" ) { // 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<AST::Item>& i, const AST::PathBinding& pb, bool allow_collide) @@ -194,14 +194,14 @@ void Resolve_Index_Module_Base(const AST::Crate& crate, AST::Module& mod) (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 @@ -258,9 +258,9 @@ void Resolve_Index_Module_Base(const AST::Crate& crate, AST::Module& mod) } } } - + mod.m_index_populated = (has_pub_wildcard ? 1 : 2); - + // Handle child modules for( auto& i : mod.items() ) { @@ -326,7 +326,7 @@ void Resolve_Index_Module_Wildcard__glob_in_hir_mod(const Span& sp, const AST::C if( ve.ent.is_Import() ) { const auto& spath = ve.ent.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 ++) { @@ -390,7 +390,7 @@ void Resolve_Index_Module_Wildcard(AST::Crate& crate, AST::Module& mod, bool han if( ! i.data.is_Use() ) continue ; const auto& i_data = i.data.as_Use(); - + if( i.name == "" && i.is_pub == handle_pub ) { const auto& sp = i_data.sp; @@ -414,7 +414,7 @@ void Resolve_Index_Module_Wildcard(AST::Crate& crate, AST::Module& mod, bool han (StructMethod, BUG(sp, "Import was bound to struct method"); ), - + (Crate, DEBUG("Glob crate " << i_data.path); const auto& hmod = e.crate_->m_hir->m_root_module; @@ -476,7 +476,7 @@ void Resolve_Index_Module_Wildcard(AST::Crate& crate, AST::Module& mod, bool han else { _add_item_value( sp, mod, ev.m_name, i.is_pub, mv$(p), false ); } - + idx += 1; } } @@ -495,7 +495,7 @@ void Resolve_Index_Module_Wildcard(AST::Crate& crate, AST::Module& mod, bool han else { _add_item_value( sp, mod, ev.first, i.is_pub, mv$(p), false ); } - + idx += 1; } } @@ -503,10 +503,10 @@ void Resolve_Index_Module_Wildcard(AST::Crate& crate, AST::Module& mod, bool han ) } } - + // handle_pub == true first, leading to full resoltion no matter what mod.m_index_populated = 2; - + // Handle child modules for( auto& i : mod.items() ) { @@ -538,7 +538,7 @@ void Resolve_Index_Module_Normalise_Path_ext(const ::AST::Crate& crate, const Sp // path.nodes().erase( path.nodes().begin() + i ); //} while( --i > 0 ); - + for(unsigned int i = start; i < info.nodes.size() - 1; i ++) { auto it = hmod->m_mod_items.find( info.nodes[i].name() ); @@ -575,7 +575,7 @@ void Resolve_Index_Module_Normalise_Path_ext(const ::AST::Crate& crate, const Sp ) } const auto& lastnode = info.nodes.back(); - + switch(loc) { case IndexName::Type: @@ -606,7 +606,7 @@ void Resolve_Index_Module_Normalise_Path_ext(const ::AST::Crate& crate, const Sp } } break; } - + ERROR(sp, E0000, "Couldn't find final node of path " << path); } @@ -619,17 +619,17 @@ bool Resolve_Index_Module_Normalise_Path(const ::AST::Crate& crate, const Span& Resolve_Index_Module_Normalise_Path_ext(crate, sp, path, loc, crate.m_extern_crates.at(info.crate), 0); return false; } - + const ::AST::Module* mod = &crate.m_root_module; for( unsigned int i = 0; i < info.nodes.size() - 1; i ++ ) { const auto& node = info.nodes[i]; - + auto it = mod->m_namespace_items.find( node.name() ); if( it == mod->m_namespace_items.end() ) ERROR(sp, E0000, "Couldn't find node " << i << " of path " << path); const auto& ie = it->second; - + if( ie.is_import ) { // Need to replace all nodes up to and including the current with the import path auto new_path = ie.path; @@ -658,10 +658,10 @@ bool Resolve_Index_Module_Normalise_Path(const ::AST::Crate& crate, const Span& ) } } - + const auto& node = info.nodes.back(); - - + + // TODO: Use get_mod_index instead. const ::AST::Module::IndexEnt* ie_p = nullptr; switch(loc) @@ -685,7 +685,7 @@ bool Resolve_Index_Module_Normalise_Path(const ::AST::Crate& crate, const Span& if( !ie_p ) ERROR(sp, E0000, "Couldn't find final node of path " << path); const auto& ie = *ie_p; - + if( ie.is_import ) { // TODO: Prevent infinite recursion if the user does something dumb path = ::AST::Path(ie.path); @@ -706,7 +706,7 @@ void Resolve_Index_Module_Normalise(const ::AST::Crate& crate, const Span& mod_s Resolve_Index_Module_Normalise(crate, item.data.span, e); ) } - + DEBUG("Index for " << mod.path()); for( auto& ent : mod.m_namespace_items ) { Resolve_Index_Module_Normalise_Path(crate, mod_span, ent.second.path, IndexName::Namespace); @@ -730,7 +730,7 @@ void Resolve_Index(AST::Crate& crate) Resolve_Index_Module_Wildcard(crate, crate.m_root_module, true); // - Add all private glob imported items Resolve_Index_Module_Wildcard(crate, crate.m_root_module, false); - + // - Normalise the index (ensuring all paths point directly to the item) Resolve_Index_Module_Normalise(crate, Span(), crate.m_root_module); } diff --git a/src/resolve/use.cpp b/src/resolve/use.cpp index 0196108f..55c949b8 100644 --- a/src/resolve/use.cpp +++ b/src/resolve/use.cpp @@ -89,22 +89,22 @@ void Resolve_Use(::AST::Crate& crate) void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path path, slice< const ::AST::Module* > parent_modules) { TRACE_FUNCTION_F("path = " << path); - + for(auto& use_stmt : mod.items()) { if( ! use_stmt.data.is_Use() ) continue ; auto& use_stmt_data = use_stmt.data.as_Use(); - + const Span& span = use_stmt_data.sp; use_stmt_data.path = Resolve_Use_AbsolutisePath(span, path, mv$(use_stmt_data.path)); if( !use_stmt_data.path.m_class.is_Absolute() ) BUG(span, "Use path is not absolute after absolutisation"); - + // 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) ); DEBUG("'" << use_stmt.name << "' = " << use_stmt_data.path); - + // - If doing a glob, ensure the item type is valid if( use_stmt.name == "" ) { @@ -158,18 +158,18 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path { const AST::Crate& crate; ::std::vector< const AST::Module* > parent_modules; - + NV(const AST::Crate& crate, const AST::Module& cur_module): crate(crate), parent_modules() { parent_modules.push_back( &cur_module ); } - + void visit(AST::ExprNode_Block& node) override { if( node.m_local_mod ) { Resolve_Use_Mod(this->crate, *node.m_local_mod, node.m_local_mod->path(), this->parent_modules); - + parent_modules.push_back(&*node.m_local_mod); } AST::NodeVisitorDef::visit(node); @@ -178,7 +178,7 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path } } } expr_iter(crate, mod); - + // TODO: Check that all code blocks are covered by these // - NOTE: Handle anon modules by iterating code (allowing correct item mappings) for(auto& i : mod.items()) @@ -264,13 +264,13 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path assert( mod.anon_mods()[idx] ); return ::AST::PathBinding::make_Module({&*mod.anon_mods()[idx]}); } - + // Seach for the name defined in the module. for( const auto& item : mod.items() ) { if( item.data.is_None() ) continue ; - + if( item.name == des_item_name ) { //if( allow != Lookup::Any ) // DEBUG(mod.path() << " " << des_item_name << " " << item.data.tag_str()); @@ -305,7 +305,7 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path if( allow != Lookup::Value ) return ::AST::PathBinding::make_Trait({&e}); ), - + (Function, if( allow != Lookup::Type ) return ::AST::PathBinding::make_Function({&e}); @@ -335,7 +335,7 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path ) } } - + // Imports for( const auto& imp : mod.items() ) { @@ -406,7 +406,7 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path else { //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()); @@ -463,7 +463,7 @@ void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path namespace { const ::HIR::Module* get_hir_mod_by_path(const Span& sp, const ::AST::Crate& crate, const ::HIR::SimplePath& path); - + const void* get_hir_modenum_by_path(const Span& sp, const ::AST::Crate& crate, const ::HIR::SimplePath& path, bool& is_enum) { const auto* hmod = &crate.m_extern_crates.at( path.m_crate_name ).m_hir->m_root_module; @@ -533,7 +533,7 @@ namespace { ERROR(span, E0000, "Encountered enum at unexpected location in import"); } const auto& name = nodes[i].name(); - + auto it2 = ::std::find_if( enm.m_variants.begin(), enm.m_variants.end(), [&](const auto& x){ return x.first == name; } ); if( it2 == enm.m_variants.end() ) { ERROR(span, E0000, "Unable to find variant " << path); @@ -553,7 +553,7 @@ namespace { ERROR(span, E0000, "Encountered enum at unexpected location in import"); } const auto& name = nodes[i].name(); - + auto it2 = ::std::find_if( e.m_variants.begin(), e.m_variants.end(), [&](const auto& x){ return x.first == name; } ); if( it2 == e.m_variants.end() ) { ERROR(span, E0000, "Unable to find variant " << path); @@ -648,7 +648,7 @@ namespace { ) } } - + return ::AST::PathBinding::make_Unbound({}); } ::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) @@ -660,20 +660,20 @@ namespace { { TRACE_FUNCTION_F(path); //::AST::Path rv; - + // If the path is directly referring to an external crate - call __ext if( path.m_class.is_Absolute() && path.m_class.as_Absolute().crate != "" ) { const auto& path_abs = path.m_class.as_Absolute(); - + return Resolve_Use_GetBinding__ext(span, crate, path, crate.m_extern_crates.at( path_abs.crate ), 0, allow); } - + const AST::Module* mod = &crate.m_root_module; const auto& nodes = path.nodes(); for( unsigned int i = 0; i < nodes.size()-1; i ++ ) { // TODO: If this came from an import, return the real path? - + //rv = Resolve_Use_CanoniseAndBind_Mod(span, crate, *mod, mv$(rv), nodes[i].name(), parent_modules, Lookup::Type); //const auto& b = rv.binding(); auto b = Resolve_Use_GetBinding_Mod(span, crate, *mod, nodes[i].name(), parent_modules, Lookup::Type); @@ -691,7 +691,7 @@ namespace { if( i != nodes.size() - 1 ) { ERROR(span, E0000, "Encountered enum at unexpected location in import"); } - + const auto& node2 = nodes[i]; int variant_index = -1; for( unsigned int j = 0; j < enum_.variants().size(); j ++ ) @@ -704,12 +704,12 @@ namespace { if( variant_index < 0 ) { ERROR(span, E0000, "Unknown enum variant '" << node2.name() << "'"); } - + return ::AST::PathBinding::make_EnumVar({&enum_, static_cast<unsigned int>(variant_index)}); ), (Module, ASSERT_BUG(span, e.module_ || e.hir, "nullptr module pointer in node " << i << " of " << path); - if( !e.module_ ) + if( !e.module_ ) { assert(e.hir); // TODO: Mangle the original path (or return a new path somehow) @@ -719,7 +719,7 @@ namespace { ) ) } - + assert(mod); return Resolve_Use_GetBinding_Mod(span, crate, *mod, nodes.back().name(), parent_modules, allow); } diff --git a/src/serialise.cpp b/src/serialise.cpp index 5c57da9f..e79d4025 100644 --- a/src/serialise.cpp +++ b/src/serialise.cpp @@ -146,13 +146,13 @@ size_t Deserialiser_TextTree::start_array() char c = getc(); if( c != '[' ) throw DeserialiseFailure("start_array", "no ["); - + eat_ws(); if( peekc() == ']' ) { DEBUG("len = 0"); return 0; } - + size_t len; m_is >> len; if( !m_is.good() ) @@ -218,13 +218,13 @@ void Deserialiser_TextTree::item(double& v) void Deserialiser_TextTree::item(::std::string& s) { eat_ws(); - + ::std::string rv; char c = getc(); DEBUG("c = '"<<c<<"'"); if( c != '"' ) throw DeserialiseFailure("item(::std::string)", "no open \""); - + while(peekc() != '"') { char c = getc(); @@ -233,7 +233,7 @@ void Deserialiser_TextTree::item(::std::string& s) rv.push_back(c); } getc(); // eat " - + DEBUG("rv = '"<<rv<<"'"); s = rv; } diff --git a/src/trans/codegen.cpp b/src/trans/codegen.cpp index 3f188dbf..28b8501c 100644 --- a/src/trans/codegen.cpp +++ b/src/trans/codegen.cpp @@ -18,7 +18,7 @@ void Trans_Codegen(const ::std::string& outfile, const ::HIR::Crate& crate, cons { static Span sp; auto codegen = Trans_Codegen_GetGeneratorC(crate, outfile); - + // 1. Emit structure/type definitions. // - Emit in the order they're needed. for(const auto& ty : list.m_types) @@ -40,7 +40,7 @@ void Trans_Codegen(const ::std::string& outfile, const ::HIR::Crate& crate, cons ) codegen->emit_type(ty); } - + // 2. Emit function prototypes for(const auto& ent : list.m_functions) { @@ -59,7 +59,7 @@ void Trans_Codegen(const ::std::string& outfile, const ::HIR::Crate& crate, cons DEBUG("STATIC " << ent.first); assert(ent.second->ptr); const auto& stat = *ent.second->ptr; - + if( stat.m_value_res.is_Invalid() ) { codegen->emit_static_ext(ent.first, stat, ent.second->pp); @@ -69,17 +69,17 @@ void Trans_Codegen(const ::std::string& outfile, const ::HIR::Crate& crate, cons codegen->emit_static_local(ent.first, stat, ent.second->pp); } } - + for(const auto& ent : list.m_vtables) { const auto& trait = ent.first.m_data.as_UfcsKnown().trait; const auto& type = *ent.first.m_data.as_UfcsKnown().type; DEBUG("VTABLE " << trait << " for " << type); - + codegen->emit_vtable(ent.first, crate.get_trait_by_path(Span(), trait.m_path)); } - - + + // 4. Emit function code for(const auto& ent : list.m_functions) { @@ -109,7 +109,7 @@ void Trans_Codegen(const ::std::string& outfile, const ::HIR::Crate& crate, cons } } } - + codegen->finalise(); } diff --git a/src/trans/codegen.hpp b/src/trans/codegen.hpp index b93f9d5d..e14a8e81 100644 --- a/src/trans/codegen.hpp +++ b/src/trans/codegen.hpp @@ -13,7 +13,7 @@ namespace HIR { class TypeRef; class Path; class GenericPath; - + class Function; class Static; } @@ -27,22 +27,22 @@ class CodeGenerator public: virtual ~CodeGenerator() {} virtual void finalise() {} - + // Called on all types directly mentioned (e.g. variables, arguments, and fields) // - Inner-most types are visited first. virtual void emit_type(const ::HIR::TypeRef& ) {} - + // Called when a TypeRef::Path is encountered (after visiting inner types) virtual void emit_struct(const Span& sp, const ::HIR::GenericPath& p, const ::HIR::Struct& item) {} virtual void emit_union(const Span& sp, const ::HIR::GenericPath& p, const ::HIR::Union& item) {} virtual void emit_enum(const Span& sp, const ::HIR::GenericPath& p, const ::HIR::Enum& item) {} - + virtual void emit_vtable(const ::HIR::Path& p, const ::HIR::Trait& trait) {} - + virtual void emit_static_ext(const ::HIR::Path& p, const ::HIR::Static& item, const Trans_Params& params) {} virtual void emit_static_proto(const ::HIR::Path& p, const ::HIR::Static& item, const Trans_Params& params) {} virtual void emit_static_local(const ::HIR::Path& p, const ::HIR::Static& item, const Trans_Params& params) {} - + virtual void emit_function_ext(const ::HIR::Path& p, const ::HIR::Function& item, const Trans_Params& params) {} virtual void emit_function_proto(const ::HIR::Path& p, const ::HIR::Function& item, const Trans_Params& params) {} virtual void emit_function_code(const ::HIR::Path& p, const ::HIR::Function& item, const Trans_Params& params, const ::MIR::FunctionPointer& code) {} diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 0552d118..37acb33b 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -23,7 +23,7 @@ namespace { Slice, TraitObject, }; - + const ::HIR::Crate& m_crate; ::StaticTraitResolve m_resolve; ::std::ofstream m_of; @@ -55,7 +55,7 @@ namespace { << "\n" ; } - + ~CodeGenerator_C() {} void finalise() override @@ -67,7 +67,7 @@ namespace { << ");\n" << "}\n"; } - + void emit_type(const ::HIR::TypeRef& ty) override { TU_IFLET( ::HIR::TypeRef::Data, ty.m_data, Tuple, te, @@ -109,10 +109,10 @@ namespace { ) else { } - + m_of << "tTYPEID __typeid_" << Trans_Mangle(ty) << ";\n"; } - + void emit_struct(const Span& sp, const ::HIR::GenericPath& p, const ::HIR::Struct& item) override { ::HIR::TypeRef tmp; @@ -179,25 +179,25 @@ namespace { m_of << "\treturn rv;\n"; m_of << "}\n"; ) - + auto struct_ty = ::HIR::TypeRef(p.clone(), &item); auto drop_glue_path = ::HIR::Path(struct_ty.clone(), "#drop_glue"); auto struct_ty_ptr = ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Owned, struct_ty.clone()); ::MIR::TypeResolve mir_res { sp, m_resolve, FMT_CB(ss, ss << drop_glue_path;), struct_ty_ptr, {}, *(::MIR::Function*)nullptr }; m_mir_res = &mir_res; // - Drop Glue - + if( item.m_markings.has_drop_impl ) { m_of << "tUNIT " << Trans_Mangle( ::HIR::Path(struct_ty.clone(), m_resolve.m_lang_Drop, "drop") ) << "(struct s_" << Trans_Mangle(p) << "*rv);\n"; } - + m_of << "void " << Trans_Mangle(drop_glue_path) << "(struct s_" << Trans_Mangle(p) << "* rv) {\n"; - + // If this type has an impl of Drop, call that impl if( item.m_markings.has_drop_impl ) { m_of << "\t" << Trans_Mangle( ::HIR::Path(struct_ty.clone(), m_resolve.m_lang_Drop, "drop") ) << "(rv);\n"; } - + auto self = ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Return({})) }); auto fld_lv = ::MIR::LValue::make_Field({ box$(self), 0 }); TU_MATCHA( (item.m_data), (e), @@ -208,7 +208,7 @@ namespace { { const auto& fld = e[i]; fld_lv.as_Field().field_index = i; - + emit_destructor_call(fld_lv, monomorph(fld.ent), true); } ), @@ -217,7 +217,7 @@ namespace { { const auto& fld = e[i].second; fld_lv.as_Field().field_index = i; - + emit_destructor_call(fld_lv, monomorph(fld.ent), true); } ) @@ -277,9 +277,9 @@ namespace { } m_of << "\t} DATA;\n"; m_of << "};\n"; - + // TODO: Constructors for tuple variants - + // --- // - Drop Glue // --- @@ -288,24 +288,24 @@ namespace { auto struct_ty_ptr = ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Owned, struct_ty.clone()); ::MIR::TypeResolve mir_res { sp, m_resolve, FMT_CB(ss, ss << drop_glue_path;), struct_ty_ptr, {}, *(::MIR::Function*)nullptr }; m_mir_res = &mir_res; - - + + if( item.m_markings.has_drop_impl ) { m_of << "void " << Trans_Mangle( ::HIR::Path(struct_ty.clone(), m_resolve.m_lang_Drop, "drop") ) << "(struct e_" << Trans_Mangle(p) << "*rv);\n"; } - + m_of << "void " << Trans_Mangle(drop_glue_path) << "(struct e_" << Trans_Mangle(p) << "* rv) {\n"; - + // If this type has an impl of Drop, call that impl if( item.m_markings.has_drop_impl ) { m_of << "\t" << Trans_Mangle( ::HIR::Path(struct_ty.clone(), m_resolve.m_lang_Drop, "drop") ) << "(rv);\n"; } - + auto self = ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Return({})) }); auto fld_lv = ::MIR::LValue::make_Field({ box$(::MIR::LValue::make_Downcast({ box$(self), 0 })), 0 }); - + m_of << "\tswitch(rv->TAG) {\n"; for(unsigned int var_idx = 0; var_idx < item.m_variants.size(); var_idx ++) { @@ -323,7 +323,7 @@ namespace { { fld_lv.as_Field().field_index = i; const auto& fld = e[i]; - + emit_destructor_call(fld_lv, monomorph(fld.ent), false); } m_of << "\tbreak;\n"; @@ -343,7 +343,7 @@ namespace { m_of << "\t}\n"; m_of << "}\n"; } - + void emit_static_ext(const ::HIR::Path& p, const ::HIR::Static& item, const Trans_Params& params) override { TRACE_FUNCTION_F(p); @@ -357,7 +357,7 @@ namespace { void emit_static_local(const ::HIR::Path& p, const ::HIR::Static& item, const Trans_Params& params) override { TRACE_FUNCTION_F(p); - + auto type = params.monomorph(m_crate, item.m_type); emit_ctype( type, FMT_CB(ss, ss << Trans_Mangle(p);) ); m_of << " = "; @@ -481,13 +481,13 @@ namespace { ) ) } - + void emit_vtable(const ::HIR::Path& p, const ::HIR::Trait& trait) override { static Span sp; const auto& trait_path = p.m_data.as_UfcsKnown().trait; const auto& type = *p.m_data.as_UfcsKnown().type; - + { auto vtable_sp = trait_path.m_path; vtable_sp.m_components.back() += "#vtable"; @@ -499,13 +499,13 @@ namespace { } const auto& vtable_ref = m_crate.get_struct_by_path(sp, vtable_sp); ::HIR::TypeRef vtable_ty( ::HIR::GenericPath(mv$(vtable_sp), mv$(vtable_params)), &vtable_ref ); - + emit_ctype(vtable_ty); m_of << " " << Trans_Mangle(p) << " = {\n"; } auto monomorph_cb_trait = monomorphise_type_get_cb(sp, &type, &trait_path.m_params, nullptr); - + // TODO: Alignment and destructor for(unsigned int i = 0; i < trait.m_value_indexes.size(); i ++ ) { @@ -515,10 +515,10 @@ namespace { { if( m.second.first != i ) continue ; - + //ASSERT_BUG(sp, tr.m_values.at(m.first).is_Function(), "TODO: Handle generating vtables with non-function items"); DEBUG("- " << m.second.first << " = " << m.second.second << " :: " << m.first); - + auto gpath = monomorphise_genericpath_with(sp, m.second.second, monomorph_cb_trait, false); // NOTE: `void*` cast avoids mismatched pointer type errors due to the receiver being &mut()/&() in the vtable m_of << "\t(void*)" << Trans_Mangle( ::HIR::Path(type.clone(), mv$(gpath), m.first) ); @@ -527,7 +527,7 @@ namespace { m_of << "\n"; m_of << "\t};\n"; } - + void emit_function_ext(const ::HIR::Path& p, const ::HIR::Function& item, const Trans_Params& params) override { m_of << "// extern \"" << item.m_abi << "\" " << p << "\n"; @@ -552,12 +552,12 @@ namespace { { static Span sp; TRACE_FUNCTION_F(p); - + ::MIR::TypeResolve::args_t arg_types; for(const auto& ent : item.m_args) arg_types.push_back(::std::make_pair( ::HIR::Pattern{}, params.monomorph(m_crate, ent.second) )); ::HIR::TypeRef ret_type = params.monomorph(m_crate, item.m_return); - + ::MIR::TypeResolve mir_res { sp, m_resolve, FMT_CB(ss, ss << p;), ret_type, arg_types, *code }; m_mir_res = &mir_res; @@ -582,15 +582,15 @@ namespace { for(unsigned int i = 0; i < code->blocks.size(); i ++) { TRACE_FUNCTION_F(p << " bb" << i); - + if( code->blocks[i].statements.size() == 0 && code->blocks[i].terminator.is_Diverge() ) { DEBUG("- Diverge only, omitting"); m_of << "bb" << i << ": _Unwind_Resume(); // Diverge\n"; continue ; } - + m_of << "bb" << i << ":\n"; - + for(const auto& stmt : code->blocks[i].statements) { mir_res.set_cur_stmt(i, (&stmt - &code->blocks[i].statements.front())); @@ -601,7 +601,7 @@ namespace { // TODO: Emit destructor calls ::HIR::TypeRef tmp; const auto& ty = mir_res.get_lvalue_type(tmp, e.slot); - + if( e.kind == ::MIR::eDropKind::SHALLOW ) { // TODO: Shallow drops are only valid on owned_box } @@ -665,7 +665,7 @@ namespace { m_of << "\\" << (unsigned int)v; } m_of << "\"" << ::std::dec; - + m_of << ";\n\t"; emit_lvalue(e.dst); m_of << ".META = " << c.size(); @@ -729,7 +729,7 @@ namespace { m_of << "/* PhandomData cast */\n"; continue ; } - + emit_lvalue(e.dst); m_of << " = "; m_of << "("; emit_ctype(ve.type); m_of << ")"; @@ -771,7 +771,7 @@ namespace { case ::MIR::eBinOp::MUL: m_of << " * "; break; case ::MIR::eBinOp::DIV: m_of << " / "; break; case ::MIR::eBinOp::MOD: m_of << " % "; break; - + case ::MIR::eBinOp::BIT_OR: m_of << " | "; break; case ::MIR::eBinOp::BIT_AND: m_of << " & "; break; case ::MIR::eBinOp::BIT_XOR: m_of << " ^ "; break; @@ -783,7 +783,7 @@ namespace { case ::MIR::eBinOp::GE: m_of << " >= "; break; case ::MIR::eBinOp::LT: m_of << " < " ; break; case ::MIR::eBinOp::LE: m_of << " <= "; break; - + case ::MIR::eBinOp::ADD_OV: case ::MIR::eBinOp::SUB_OV: case ::MIR::eBinOp::MUL_OV: @@ -857,14 +857,14 @@ namespace { if(ve.vals.size() > 0) m_of << ";\n\t"; } - + for(unsigned int j = 0; j < ve.vals.size(); j ++) { // HACK: Don't emit assignment of PhantomData ::HIR::TypeRef tmp; if( m_resolve.is_type_phantom_data( mir_res.get_lvalue_type(tmp, ve.vals[j])) ) continue ; - + if( j != 0 ) m_of << ";\n\t"; emit_lvalue(e.dst); if(ve.variant_idx != ~0u) @@ -879,7 +879,7 @@ namespace { m_of << "\n"; } } - + mir_res.set_cur_stmt_term(i); DEBUG("- " << code->blocks[i].terminator); TU_MATCHA( (code->blocks[i].terminator), (e), @@ -913,7 +913,7 @@ namespace { { const auto& name = e.fcn.as_Intrinsic().name; const auto& params = e.fcn.as_Intrinsic().params; - + struct H { static const char* get_atomic_ordering(const ::MIR::TypeResolve& mir_res, const ::std::string& name, size_t prefix_len) { if( name.size() < prefix_len ) @@ -1120,7 +1120,7 @@ namespace { m_of << "\tgoto bb" << e.ret_block << ";\n"; break ; } - + TU_MATCHA( (e.fcn), (e2), (Value, { @@ -1199,7 +1199,7 @@ namespace { } )); } - + void emit_destructor_call(const ::MIR::LValue& slot, const ::HIR::TypeRef& ty, bool unsized_valid) { TU_MATCHA( (ty.m_data), (te), @@ -1209,7 +1209,7 @@ namespace { (ErasedType, ), (Closure, ), (Generic, ), - + // Nothing (Primitive, ), @@ -1267,7 +1267,7 @@ namespace { ) ) } - + const ::HIR::Literal& get_literal_for_const(const ::HIR::Path& path) { TU_MATCHA( (path.m_data), (pe), @@ -1288,7 +1288,7 @@ namespace { ) throw ""; } - + void assign_from_literal(::std::function<void()> emit_dst, const ::HIR::TypeRef& ty, const ::HIR::Literal& lit) { //TRACE_FUNCTION_F("ty=" << ty << ", lit=" << lit); @@ -1440,7 +1440,7 @@ namespace { ) ) } - + void emit_lvalue(const ::MIR::LValue& val) { TU_MATCHA( (val), (e), (Variable, @@ -1543,10 +1543,10 @@ namespace { case ::HIR::CoreType::I32: m_of << "int32_t"; break; case ::HIR::CoreType::U64: m_of << "uint64_t"; break; case ::HIR::CoreType::I64: m_of << "int64_t"; break; - + case ::HIR::CoreType::F32: m_of << "float"; break; case ::HIR::CoreType::F64: m_of << "double"; break; - + case ::HIR::CoreType::Bool: m_of << "bool"; break; case ::HIR::CoreType::Char: m_of << "CHAR"; break; case ::HIR::CoreType::Str: @@ -1619,7 +1619,7 @@ namespace { ) ) } - + MetadataType metadata_type(const ::HIR::TypeRef& ty) { if( ty == ::HIR::CoreType::Str || ty.m_data.is_Slice() ) { @@ -1658,7 +1658,7 @@ namespace { return MetadataType::None; } } - + void emit_ctype_ptr(const ::HIR::TypeRef& inner_ty, ::FmtLambda inner) { if( inner_ty.m_data.is_Array() ) { emit_ctype(inner_ty, FMT_CB(ss, ss << "(*" << inner << ")";)); @@ -1679,7 +1679,7 @@ namespace { } } } - + int is_dst(const ::HIR::TypeRef& ty) const { if( ty == ::HIR::CoreType::Str ) diff --git a/src/trans/enumerate.cpp b/src/trans/enumerate.cpp index dc886f50..78270b7b 100644 --- a/src/trans/enumerate.cpp +++ b/src/trans/enumerate.cpp @@ -27,35 +27,35 @@ void Trans_Enumerate_FillFrom_Literal(TransList& out, const ::HIR::Crate& crate, TransList Trans_Enumerate_Main(const ::HIR::Crate& crate) { static Span sp; - + TransList rv; - + // "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); - + auto* ptr = rv.add_function(start_path); assert(ptr); Trans_Enumerate_FillFrom(rv, crate, fcn, *ptr); } - + // user entrypoint { auto main_path = ::HIR::SimplePath("", {"main"}); const auto& fcn = crate.get_function_by_path(sp, main_path); - + auto* ptr = rv.add_function(main_path); assert(ptr); Trans_Enumerate_FillFrom(rv, crate, fcn, *ptr); } - + // TODO: Search the trans list for external functions that refer to a named symbol, search for that defined elsewhere. // - Not needed yet, there's a slow hack elsewhere Trans_Enumerate_Types(rv, crate); - + return rv; } @@ -97,11 +97,11 @@ namespace { TransList Trans_Enumerate_Public(const ::HIR::Crate& crate) { TransList rv; - + Trans_Enumerate_Public_Mod(rv, crate, crate.m_root_module, ::HIR::SimplePath("",{})); - + Trans_Enumerate_Types(rv, crate); - + return rv; } @@ -111,22 +111,22 @@ namespace { template<typename T> bool operator()(const T* lhs, const T* rhs) const { return *lhs < *rhs; } }; - + struct TypeVisitor { const ::HIR::Crate& m_crate; ::StaticTraitResolve m_resolve; ::std::vector< ::HIR::TypeRef>& out_list; - + ::std::set< ::HIR::TypeRef> visited; ::std::set< const ::HIR::TypeRef*, PtrComp> active_set; - + TypeVisitor(const ::HIR::Crate& crate, ::std::vector< ::HIR::TypeRef>& out_list): m_crate(crate), m_resolve(crate), out_list(out_list) {} - + void visit_struct(const ::HIR::GenericPath& path, const ::HIR::Struct& item) { static Span sp; ::HIR::TypeRef tmp; @@ -188,19 +188,19 @@ namespace { ) } } - + void visit_type(const ::HIR::TypeRef& ty) { // Already done if( visited.find(ty) != visited.end() ) return ; - + if( active_set.find(&ty) != active_set.end() ) { // TODO: Handle recursion return ; } active_set.insert( &ty ); - + TU_MATCHA( (ty.m_data), (te), // Impossible (Infer, @@ -236,7 +236,7 @@ namespace { static Span sp; // Ensure that the data trait's vtable is present 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_ref = m_crate.get_struct_by_path(sp, vtable_ty_spath); @@ -249,8 +249,8 @@ namespace { vtable_params.m_types.resize(idx+1); vtable_params.m_types[idx] = ty_b.second.clone(); } - - + + visit_type( ::HIR::TypeRef( ::HIR::GenericPath(vtable_ty_spath, mv$(vtable_params)), &vtable_ref ) ); ), (Array, @@ -276,7 +276,7 @@ namespace { ) ) active_set.erase( active_set.find(&ty) ); - + visited.insert( ty.clone() ); out_list.push_back( ty.clone() ); DEBUG("Add type " << ty); @@ -299,11 +299,11 @@ void Trans_Enumerate_Types(TransList& out, const ::HIR::Crate& crate) assert(ent.second->ptr); const auto& fcn = *ent.second->ptr; const auto& pp = ent.second->pp; - + tv.visit_type( pp.monomorph(crate, fcn.m_return) ); for(const auto& arg : fcn.m_args) tv.visit_type( pp.monomorph(crate, arg.second) ); - + if( fcn.m_code.m_mir ) { const auto& mir = *fcn.m_code.m_mir; @@ -319,10 +319,10 @@ void Trans_Enumerate_Types(TransList& out, const ::HIR::Crate& crate) assert(ent.second->ptr); const auto& stat = *ent.second->ptr; const auto& pp = ent.second->pp; - + tv.visit_type( pp.monomorph(crate, stat.m_type) ); } - + constructors_added = false; for(unsigned int i = types_count; i < out.m_types.size(); i ++ ) { @@ -345,12 +345,12 @@ void Trans_Enumerate_Types(TransList& out, const ::HIR::Crate& crate) ) ) ASSERT_BUG(Span(), markings_ptr, "Path binding not set correctly - " << ty); - + if( markings_ptr->has_drop_impl ) { // Add the Drop impl to the codegen list Trans_Enumerate_FillFrom_Path(out, crate, ::HIR::Path( ty.clone(), crate.get_lang_item_path(Span(), "drop"), "drop"), {}); - + constructors_added = true; } } @@ -377,7 +377,7 @@ namespace { else { mod = &crate.m_root_module; } - + for( unsigned int i = 0; i < path.m_components.size() - 1; i ++ ) { const auto& pc = path.m_components[i]; @@ -399,12 +399,12 @@ namespace { ) ) } - + auto it = mod->m_value_items.find( path.m_components.back() ); if( it == mod->m_value_items.end() ) { return EntPtr {}; } - + TU_MATCH( ::HIR::ValueItem, (it->second->ent), (e), (Import, ), @@ -430,7 +430,7 @@ namespace { { TRACE_FUNCTION_F(path); StaticTraitResolve resolve { crate }; - + TU_MATCH(::HIR::Path::Data, (path.m_data), (e), (Generic, return get_ent_simplepath(sp, crate, e.m_path); @@ -463,13 +463,13 @@ namespace { ), (UfcsKnown, EntPtr rv; - + // Obtain trait pointer (for default impl and to know what the item type is) const auto& trait_ref = crate.get_trait_by_path(sp, e.trait.m_path); auto trait_vi_it = trait_ref.m_values.find(e.item); ASSERT_BUG(sp, trait_vi_it != trait_ref.m_values.end(), "Couldn't find item " << e.item << " in trait " << e.trait.m_path); const auto& trait_vi = trait_vi_it->second; - + bool is_dynamic = false; ::std::vector<::HIR::TypeRef> best_impl_params; const ::HIR::TraitImpl* best_impl = nullptr; @@ -485,7 +485,7 @@ namespace { 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() == e.trait.m_params.m_types.size(), "Trait parameter count mismatch " << impl.m_trait_args << " vs " << e.trait.m_params); - + if( best_impl == nullptr || impl.more_specific_than(*best_impl) ) { best_impl = &impl; bool is_spec = false; @@ -529,7 +529,7 @@ namespace { const auto& impl = *best_impl; impl_pp.m_types = mv$(best_impl_params); - + TU_MATCHA( (trait_vi), (ve), (Constant, TODO(sp, "Associated constant"); ), (Static, @@ -784,7 +784,7 @@ void Trans_Enumerate_FillFrom_VTable(TransList& out, const ::HIR::Crate& crate, const auto& type = *vtable_path.m_data.as_UfcsKnown().type; const auto& trait_path = vtable_path.m_data.as_UfcsKnown().trait; const auto& tr = crate.get_trait_by_path(Span(), trait_path.m_path); - + auto monomorph_cb_trait = monomorphise_type_get_cb(sp, &type, &trait_path.m_params, nullptr); for(const auto& m : tr.m_value_indexes) { @@ -832,7 +832,7 @@ namespace { } ) } - + for(const auto& ti : mod.m_mod_items) { TU_IFLET( ::HIR::TypeItem, ti.second->ent, Module, i, @@ -840,7 +840,7 @@ namespace { return rv; ) } - + return nullptr; } ::HIR::Function* find_function_by_link_name(const ::HIR::Crate& crate, const char* name, ::HIR::SimplePath& out_path) diff --git a/src/trans/mangling.cpp b/src/trans/mangling.cpp index ef41abed..c14b1b29 100644 --- a/src/trans/mangling.cpp +++ b/src/trans/mangling.cpp @@ -187,7 +187,7 @@ namespace { BUG(Span(), "Closure during trans - " << ty); ) ) - + throw ""; } diff --git a/src/trans/monomorphise.cpp b/src/trans/monomorphise.cpp index d129eae9..03623855 100644 --- a/src/trans/monomorphise.cpp +++ b/src/trans/monomorphise.cpp @@ -60,9 +60,9 @@ namespace { { static Span sp; TRACE_FUNCTION; - + ::MIR::Function output; - + // 1. Monomorphise locals and temporaries output.named_variables.reserve( tpl->named_variables.size() ); for(const auto& var : tpl->named_variables) @@ -76,13 +76,13 @@ namespace { DEBUG("- var" << output.temporaries.size()); output.temporaries.push_back( params.monomorph(crate, ty) ); } - + // 2. Monomorphise all paths output.blocks.reserve( tpl->blocks.size() ); for(const auto& block : tpl->blocks) { ::std::vector< ::MIR::Statement> statements; - + TRACE_FUNCTION_F("bb" << output.blocks.size()); statements.reserve( block.statements.size() ); for(const auto& stmt : block.statements) @@ -101,7 +101,7 @@ namespace { { const auto& e = stmt.as_Assign(); DEBUG("- " << e.dst << " = " << e.src); - + ::MIR::RValue rval; TU_MATCHA( (e.src), (se), (Use, @@ -213,16 +213,16 @@ namespace { }); ) ) - + statements.push_back( ::MIR::Statement::make_Assign({ monomorph_LValue(crate, params, e.dst), mv$(rval) }) ); } } - + ::MIR::Terminator terminator; - + DEBUG("> " << block.terminator); TU_MATCHA( (block.terminator), (e), (Incomplete, @@ -278,9 +278,9 @@ namespace { }); ) ) - + output.blocks.push_back( ::MIR::BasicBlock { mv$(statements), mv$(terminator) } ); } - + return ::MIR::FunctionPointer( box$(output).release() ); } diff --git a/src/trans/trans_list.hpp b/src/trans/trans_list.hpp index 0ff2745c..e80a2b6e 100644 --- a/src/trans/trans_list.hpp +++ b/src/trans/trans_list.hpp @@ -23,18 +23,18 @@ struct Trans_Params ::HIR::PathParams pp_method; ::HIR::PathParams pp_impl; ::HIR::TypeRef self_type; - + Trans_Params() {} Trans_Params(const Span& sp): sp(sp) {} - + t_cb_generic get_cb() const; ::HIR::TypeRef monomorph(const ::HIR::Crate& crate, const ::HIR::TypeRef& p) const; ::HIR::Path monomorph(const ::HIR::Crate& crate, const ::HIR::Path& p) const; ::HIR::GenericPath monomorph(const ::HIR::Crate& crate, const ::HIR::GenericPath& p) const; ::HIR::PathParams monomorph(const ::HIR::Crate& crate, const ::HIR::PathParams& p) const; - + bool has_types() const { return pp_method.m_types.size() > 0 || pp_impl.m_types.size() > 0; } @@ -57,7 +57,7 @@ public: ::std::map< ::HIR::Path, ::std::unique_ptr<TransList_Function> > m_functions; ::std::map< ::HIR::Path, ::std::unique_ptr<TransList_Static> > m_statics; ::std::map< ::HIR::Path, Trans_Params> m_vtables; - + ::std::vector< ::HIR::TypeRef> m_types; TransList_Function* add_function(::HIR::Path p); |