summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Hodge <tpg@mutabah.net>2015-09-19 18:16:36 +0800
committerJohn Hodge <tpg@mutabah.net>2015-09-19 18:16:36 +0800
commite6738ed57d644572e7cbefa6d68a4118935a5f80 (patch)
treea38b823d4b3771b045239a2f811eb63824a1032c
parent03e211d6eeb3f8f3c6f0b22f77c2074e81443952 (diff)
downloadmrust-e6738ed57d644572e7cbefa6d68a4118935a5f80.tar.gz
Disable UFCS resolve (due to ordering issues), fix Self handling
-rw-r--r--Makefile8
-rw-r--r--src/ast/path.cpp23
-rw-r--r--src/ast/path.hpp3
-rw-r--r--src/convert/ast_iterate.cpp40
-rw-r--r--src/convert/ast_iterate.hpp5
-rw-r--r--src/convert/resolve.cpp172
-rw-r--r--src/include/span.hpp3
-rw-r--r--src/main.cpp5
-rw-r--r--src/parse/root.cpp1
-rw-r--r--src/types.hpp1
10 files changed, 210 insertions, 51 deletions
diff --git a/Makefile b/Makefile
index ce0209b8..9dfd6eb3 100644
--- a/Makefile
+++ b/Makefile
@@ -28,6 +28,8 @@ OBJ += convert/resolve.o convert/typecheck_bounds.o convert/typecheck_params.o c
OBJ += convert/flatten.o convert/render.o
OBJ += synexts/derive.o synexts/lang_item.o
+PCHS := ast/ast.hpp
+
OBJ := $(addprefix $(OBJDIR),$(OBJ))
@@ -64,6 +66,12 @@ $(OBJDIR)%.o: src/%.cpp
@echo [CXX] -o $@
$V$(CXX) -o $@ -c $< $(CXXFLAGS) $(CPPFLAGS) -MMD -MP -MF $@.dep
+src/main.cpp: $(PCHS:%=src/%.gch)
+
+%.hpp.gch: %.hpp
+ @echo [CXX] -o $@
+ $V$(CXX) -std=c++11 -o $@ $< $(CPPFLAGS) -MMD -MP -MF $@.dep
+
-include $(OBJ:%=%.dep)
# vim: noexpandtab ts=4
diff --git a/src/ast/path.cpp b/src/ast/path.cpp
index 247a6b2b..8fe42527 100644
--- a/src/ast/path.cpp
+++ b/src/ast/path.cpp
@@ -115,6 +115,24 @@ AST::Path::Path(const Path& x):
)
)
+ memcpy(&m_binding, &x.m_binding, sizeof(PathBinding));
+ //TU_MATCH(PathBinding, (x.m_binding), (ent),
+ //(Unbound, m_binding = PathBinding::make_Unbound({}); ),
+ //(Module, os << "Module"; ),
+ //(Trait, os << "Trait"; ),
+ //(Struct, os << "Struct"; ),
+ //(Enum, os << "Enum"; ),
+ //(Static, os << "Static"; ),
+ //(Function, os << "Function";),
+ //(EnumVar, os << "EnumVar(" << i.idx << ")"; ),
+ //(TypeAlias, os << "TypeAlias";),
+ //(StructMethod, os << "StructMethod"; ),
+ //(TraitMethod, os << "TraitMethod"; ),
+ //
+ //(TypeParameter, os << "TypeParameter(" << i.level << " # " << i.idx << ")"; ),
+ //(Variable, os << "Variable(" << i.slot << ")"; )
+ //)
+
DEBUG("clone, x = " << x << ", this = " << *this );
}
@@ -454,7 +472,7 @@ void Path::resolve_ufcs(const Crate& root_crate, bool expect_params)
void Path::resolve_ufcs_trait(const AST::Path& trait_path, AST::PathNode& node)
{
if( !trait_path.m_binding.is_Trait() )
- throw ParseError::Generic("Path::resolve_ufcs - Trait in UFCS path is not a trait");
+ ERROR(trait_path.span(), E0000, "Trait in UFCS path is not a trait");
const auto& trait_def = *trait_path.m_binding.as_Trait().trait_;
// Check that the requested item exists within the trait, and bind to that item
@@ -843,7 +861,6 @@ void Path::print_pretty(::std::ostream& os) const
#endif
os << n;
}
- os << "/*" << path.m_binding << "*/";
),
(UFCS,
os << "/*ufcs*/<" << *ent.type << " as " << *ent.trait << ">";
@@ -851,7 +868,7 @@ void Path::print_pretty(::std::ostream& os) const
os << "::" << n;
)
)
- os << "/*[" << path.span().filename << ":" << path.span().start_line << "]*/";
+ os << "/*" << path.m_binding << " [" << path.span().filename << ":" << path.span().start_line << "]*/";
#else
switch(path.m_class)
{
diff --git a/src/ast/path.hpp b/src/ast/path.hpp
index 9e190453..d0cc5648 100644
--- a/src/ast/path.hpp
+++ b/src/ast/path.hpp
@@ -145,7 +145,8 @@ public:
m_crate = mv$(x.m_crate);
m_class = mv$(x.m_class);
//m_span = mv$(x.m_span);
- x.m_binding = mv$(x.m_binding);
+ m_binding = mv$(x.m_binding);
+ //DEBUG("Path, " << x);
return *this;
}
diff --git a/src/convert/ast_iterate.cpp b/src/convert/ast_iterate.cpp
index cdb927e6..2946fd63 100644
--- a/src/convert/ast_iterate.cpp
+++ b/src/convert/ast_iterate.cpp
@@ -70,16 +70,22 @@ void CASTIterator::handle_params(AST::TypeParams& params)
(IsTrait,
handle_type(ent.type);
// TODO: Define HRLs
+ push_self(ent.type);
handle_path(ent.trait, CASTIterator::MODE_TYPE);
+ pop_self();
),
(MaybeTrait,
handle_type(ent.type);
+ push_self(ent.type);
handle_path(ent.trait, CASTIterator::MODE_TYPE);
+ pop_self();
// TODO: Process trait, ensuring that it's a valid lang item
),
(NotTrait,
handle_type(ent.type);
+ push_self(ent.type);
handle_path(ent.trait, CASTIterator::MODE_TYPE);
+ pop_self();
),
(Equality,
handle_type(ent.type);
@@ -347,24 +353,24 @@ void CASTIterator::handle_function(AST::Path path, AST::Function& fcn)
void CASTIterator::handle_impl_def(AST::ImplDef& impl)
{
- // First, so that handle_params can use it
- local_type("Self", impl.type());
-
// Generic params
handle_params( impl.params() );
+ // Type
+ handle_type( impl.type() );
+
+ push_self(impl.type());
+
// Trait
if( impl.trait() != AST::Path() )
handle_path( impl.trait(), MODE_TYPE );
- // Type
- handle_type( impl.type() );
}
void CASTIterator::handle_impl(AST::Path modpath, AST::Impl& impl)
{
start_scope();
- handle_impl_def(impl.def());
+ handle_impl_def(impl.def());
// Associated types
for( auto& at : impl.types() )
@@ -380,6 +386,7 @@ void CASTIterator::handle_impl(AST::Path modpath, AST::Impl& impl)
handle_function(AST::Path(AST::Path::TagRelative(), { AST::PathNode(fcn.name) }), fcn.data);
}
+ pop_self();
end_scope();
}
@@ -405,14 +412,21 @@ void CASTIterator::handle_enum(AST::Path path, AST::Enum& enm)
void CASTIterator::handle_trait(AST::Path path, AST::Trait& trait)
{
start_scope();
- local_type("Self", TypeRef(TypeRef::TagArg(), "Self"));
+ push_self(path, trait);
handle_params( trait.params() );
- //local_type("Self", TypeRef(path));
- //local_type("Self", TypeRef(TypeRef::TagArg(), "Self"));
+ for( auto& st : trait.supertraits() ) {
+ if( st.m_class.is_Invalid() ) {
+ // An invalid path is used for 'static
+ }
+ else {
+ handle_path(st, MODE_TYPE);
+ }
+ }
for( auto& fcn : trait.functions() )
handle_function( path + fcn.name, fcn.data );
+ pop_self();
end_scope();
}
void CASTIterator::handle_alias(AST::Path path, AST::TypeAlias& alias)
@@ -422,3 +436,11 @@ void CASTIterator::handle_alias(AST::Path path, AST::TypeAlias& alias)
handle_type( alias.type() );
end_scope();
}
+void CASTIterator::push_self() {
+}
+void CASTIterator::push_self(AST::Path path, const AST::Trait& trait) {
+}
+void CASTIterator::push_self(TypeRef real_type) {
+}
+void CASTIterator::pop_self() {
+}
diff --git a/src/convert/ast_iterate.hpp b/src/convert/ast_iterate.hpp
index 14537b10..4b271bfb 100644
--- a/src/convert/ast_iterate.hpp
+++ b/src/convert/ast_iterate.hpp
@@ -54,6 +54,11 @@ public:
virtual void handle_enum(AST::Path path, AST::Enum& enm);
virtual void handle_trait(AST::Path path, AST::Trait& trait);
virtual void handle_alias(AST::Path path, AST::TypeAlias& alias);
+
+ virtual void push_self();
+ virtual void push_self(AST::Path path, const AST::Trait& trait);
+ virtual void push_self(TypeRef real_type);
+ virtual void pop_self();
private:
void handle_impl_def(AST::ImplDef& impl);
diff --git a/src/convert/resolve.cpp b/src/convert/resolve.cpp
index bdbf1854..38808831 100644
--- a/src/convert/resolve.cpp
+++ b/src/convert/resolve.cpp
@@ -16,6 +16,11 @@
class CPathResolver:
public CASTIterator
{
+ const AST::Crate& m_crate;
+ AST::Module* m_module;
+ AST::Path m_module_path;
+
+
struct LocalItem
{
enum Type {
@@ -43,10 +48,8 @@ class CPathResolver:
return os << "var '" << x.name << "'";
}
};
- const AST::Crate& m_crate;
- AST::Module* m_module;
- AST::Path m_module_path;
::std::vector< LocalItem > m_locals;
+
struct Scope {
unsigned int module_idx;
AST::Module *module; // can be NULL
@@ -56,7 +59,19 @@ class CPathResolver:
::std::vector< ::std::pair<AST::Path, const AST::Trait&> > traits;
};
::std::vector<Scope> m_scope_stack;
- ::std::vector< TypeRef > m_self_type;
+
+
+ TAGGED_UNION(SelfType, None,
+ (None, ()),
+ (Type, (
+ TypeRef type;
+ )),
+ (Trait, (
+ AST::Path path;
+ const AST::Trait* trait;
+ ))
+ );
+ ::std::vector<SelfType> m_self_type;
friend class CResolvePaths_NodeVisitor;
@@ -106,6 +121,19 @@ public:
bool find_super_mod_item(AST::Path& path, const ::std::string& name);
bool find_type_param(const ::std::string& name);
+ virtual void push_self() override {
+ m_self_type.push_back( SelfType::make_None({}) );
+ }
+ virtual void push_self(AST::Path path, const AST::Trait& trait) override {
+ m_self_type.push_back( SelfType::make_Trait( {path, &trait} ) );
+ }
+ virtual void push_self(TypeRef real_type) override {
+ m_self_type.push_back( SelfType::make_Type( {real_type} ) );
+ }
+ virtual void pop_self() override {
+ m_self_type.pop_back();
+ }
+
// TODO: Handle a block and obtain the local module (if any)
private:
void handle_path_int(AST::Path& path, CASTIterator::PathMode mode);
@@ -393,6 +421,7 @@ bool lookup_path_in_module(const AST::Crate& crate, const AST::Module& module, c
/// Perform path resolution within a generic definition block
void CPathResolver::handle_params(AST::TypeParams& params)
{
+ TRACE_FUNCTION;
// Parameters
DEBUG("params");
for( auto& param : params.ty_params() )
@@ -405,6 +434,8 @@ void CPathResolver::handle_params(AST::TypeParams& params)
DEBUG("Bounds");
for( auto& bound : params.bounds() )
{
+ DEBUG("- Bound " << bound);
+
TU_MATCH(AST::GenericBound, (bound), (ent),
(Lifetime,
{}
@@ -414,21 +445,22 @@ void CPathResolver::handle_params(AST::TypeParams& params)
),
(IsTrait,
handle_type(ent.type);
- m_self_type.push_back( TypeRef() );
+ // TODO: Should 'Self' in this trait be ent.type?
+ push_self(ent.type);
handle_path(ent.trait, MODE_TYPE);
- m_self_type.pop_back();
+ pop_self();
),
(MaybeTrait,
handle_type(ent.type);
- m_self_type.push_back( TypeRef() );
+ push_self();
handle_path(ent.trait, MODE_TYPE);
- m_self_type.pop_back();
+ pop_self();
),
(NotTrait,
handle_type(ent.type);
- m_self_type.push_back( TypeRef() );
+ push_self();
handle_path(ent.trait, MODE_TYPE);
- m_self_type.pop_back();
+ pop_self();
),
(Equality,
handle_type(ent.type);
@@ -480,7 +512,7 @@ void CPathResolver::handle_path(AST::Path& path, CASTIterator::PathMode mode)
)
}
void CPathResolver::handle_path_int(AST::Path& path, CASTIterator::PathMode mode)
-{
+{
// Convert to absolute
// - This means converting all partial forms (i.e. not UFCS, Variable, or Absolute)
switch( path.class_tag() )
@@ -565,7 +597,7 @@ void CPathResolver::handle_path_int(AST::Path& path, CASTIterator::PathMode mode
// - If there are more nodes, replace with a UFCS block
{
auto tp = this->find_type_param(path[0].name());
- if( tp != false /*nullptr*/ )
+ if( tp != false /*nullptr*/ || path[0].name() == "Self" )
{
if(path.size() > 1) {
// Repalce with UFCS
@@ -633,14 +665,16 @@ void CPathResolver::handle_path_ufcs(AST::Path& path, CASTIterator::PathMode mod
assert(path.m_class.is_UFCS());
auto& info = path.m_class.as_UFCS();
TRACE_FUNCTION_F("info={< " << *info.type << " as " << *info.trait << ">::" << info.nodes << "}");
- const ::std::string& item_name = info.nodes[0].name();
// 1. Handle sub-types
handle_type(*info.type);
handle_type(*info.trait);
// 2. Handle wildcard traits (locate in inherent impl, or from an in-scope trait)
+ // TODO: Disabled, as it requires having all traits (semi) path resolved, so that trait resolution works cleanly
if( info.trait->is_wildcard() )
{
- DEBUG("Searching for impls when trait is _ (trait = " << *info.trait << ")");
+ #if 0
+ const ::std::string& item_name = info.nodes[0].name();
+ DEBUG("Searching for matching trait for '"<<item_name<<"' on type " << *info.type);
// Search applicable type parameters for known implementations
@@ -649,10 +683,32 @@ void CPathResolver::handle_path_ufcs(AST::Path& path, CASTIterator::PathMode mod
::std::vector<TypeRef> params;
if( info.type->is_type_param() && info.type->type_param() == "Self" )
{
+ DEBUG("Checking Self trait and sub-traits");
// TODO: What is "Self" here? May want to use `GenericBound`s to replace Self with the actual type when possible.
// In which case, Self will refer to "implementor of this trait".
// - Look up applicable traits for this type, using bounds (basically same as next)
- throw ParseError::Todo("CPathResolver::handle_path_ufcs - Handle '<Self as _>::...'");
+ assert( !m_self_type.empty() );
+ assert( m_self_type.back().is_Trait() );
+ AST::Path p = m_self_type.back().as_Trait().path;
+ handle_path(p, MODE_TYPE);
+ AST::Trait& t = *const_cast<AST::Trait*>(m_self_type.back().as_Trait().trait);
+
+ bool is_method;
+ AST::Path found_trait_path;
+ if( this->find_trait_item(p, t, item_name, is_method, found_trait_path) ) {
+ if( is_method ) {
+ if( info.nodes.size() != 1 )
+ ERROR(path.span(), E0000, "CPathResolver::handle_path_ufcs - Sub-nodes to method");
+ }
+ else {
+ if( info.nodes.size() != 1 )
+ throw ParseError::Todo("CPathResolver::handle_path_ufcs - Sub nodes on associated type");
+ }
+ *info.trait = TypeRef( mv$(found_trait_path) );
+ }
+ else {
+ ERROR(path.span(), E0000, "Cannot find item '" << item_name << "' on Self");
+ }
}
else if( info.type->is_type_param() )
{
@@ -703,6 +759,7 @@ void CPathResolver::handle_path_ufcs(AST::Path& path, CASTIterator::PathMode mod
}
else
{
+ DEBUG("(maybe) known type");
// Iterate all inherent impls
for( auto impl : m_crate.find_inherent_impls(*info.type) ) {
IF_OPTION_SOME(item, impl.find_named_item(item_name), {
@@ -733,13 +790,19 @@ void CPathResolver::handle_path_ufcs(AST::Path& path, CASTIterator::PathMode mod
throw ParseError::Todo("CPathResolver::handle_path_ufcs - UFCS, find trait");
}
+
+ path.resolve(m_crate);
+ #endif
+ }
+ else {
+ // 3. Call resolve to attempt binding
+ path.resolve(m_crate);
}
- // 3. Call resolve to attempt binding
- path.resolve(m_crate);
}
bool CPathResolver::find_trait_item(const AST::Path& path, AST::Trait& trait, const ::std::string& item_name, bool& out_is_method, AST::Path& out_trait_path)
{
+ TRACE_FUNCTION_F("path=" << path << ", trait=..., item_name=" << item_name);
{
const auto& fcns = trait.functions();
//DEBUG("fcns = " << fcns);
@@ -747,8 +810,8 @@ bool CPathResolver::find_trait_item(const AST::Path& path, AST::Trait& trait, co
if( it != fcns.end() ) {
// Found it.
out_is_method = true;
- DEBUG("&out_trait_path = " << &out_trait_path);
out_trait_path = AST::Path(path);
+ DEBUG("Fcn, out_trait_path = " << out_trait_path);
return true;
}
}
@@ -759,14 +822,30 @@ bool CPathResolver::find_trait_item(const AST::Path& path, AST::Trait& trait, co
// Found it.
out_is_method = false;
out_trait_path = AST::Path(path);
+ DEBUG("Ty, out_trait_path = " << out_trait_path << " path=" << path);
return true;
}
}
for( auto& st : trait.supertraits() ) {
- assert(st.is_bound());
- if( this->find_trait_item(st, *const_cast<AST::Trait*>(st.binding().as_Trait().trait_), item_name, out_is_method, out_trait_path) )
+ if(!st.is_bound()) {
+ handle_path(st, MODE_TYPE);
+ //BUG(st.span(), "Supertrait path '"<<st<<"' of '"<<path<<"' is not bound");
+ }
+ AST::Trait& super_t = *const_cast<AST::Trait*>(st.binding().as_Trait().trait_);
+ if( this->find_trait_item(st, super_t, item_name, out_is_method, out_trait_path) ) {
+ DEBUG("path = " << path << ", super_t.params() = " << super_t.params() << ", out_trait_path = " << out_trait_path);
+ //
+ out_trait_path.resolve_args([&](const char* name) {
+ int idx = trait.params().find_name(name);
+ if(idx < 0)
+ ERROR(st.span(), E0000, "Parameter " << name << " not found");
+ const auto& tr = path.nodes().back().args().at(idx);
+ DEBUG("Replacing '" << name << "' with " << tr);
+ return tr;
+ });
return true;
+ }
}
return false;
@@ -865,11 +944,25 @@ void CPathResolver::handle_type(TypeRef& type)
else if( name == "Self" )
{
// If the name was "Self", but Self isn't already defined... then we need to make it an arg?
- ERROR(type.path().span(), E0000, "Unexpected 'Self'");
-
- TypeRef nt = TypeRef(TypeRef::TagArg(), "Self");
- nt.set_span(type.span());
- type = nt;
+ if( this->m_self_type.empty() || this->m_self_type.back().is_None() ) {
+ ERROR(type.path().span(), E0000, "Unexpected 'Self'");
+ }
+ else {
+ TU_MATCH(SelfType, (this->m_self_type.back()), (ent),
+ (None,
+ assert(!"");
+ ),
+ (Type,
+ type = ent.type;
+ return ;
+ ),
+ (Trait,
+ // TODO: Need to have the trait encoded in the type. To avoid interpolation and bad replacement
+ // - Would also reduce the need to look at the m_self_type stack
+ type = TypeRef(TypeRef::TagArg(), "Self");
+ )
+ )
+ }
}
else
{
@@ -880,14 +973,25 @@ void CPathResolver::handle_type(TypeRef& type)
{
const auto& name = type.type_param();
auto opt_local = lookup_local(LocalItem::TYPE, name);
- /*if( name == "Self" )
+ if( name == "Self" )
{
- // Good as it is
- // - TODO: Allow replacing this with the real Self (e.g. in an impl block)
- // - NEED to annotate with the relevant impl block, and with other bounds
- // > So that you can handle 'where Self: Sized' etc
+ if( m_self_type.empty() ) {
+ ERROR(type.span(), E0000, "Self type not set");
+ }
+ TU_MATCH(SelfType, (m_self_type.back()), (ent),
+ (None,
+ ERROR(type.span(), E0000, "Self type not set");
+ ),
+ (Type,
+ type = ent.type;
+ return ;
+ ),
+ (Trait,
+ // Valid...
+ )
+ )
}
- else*/ if( opt_local.is_some() )
+ else if( opt_local.is_some() )
{
type = opt_local.unwrap().tr;
}
@@ -965,11 +1069,11 @@ void CPathResolver::handle_module(AST::Path path, AST::Module& mod)
}
void CPathResolver::handle_trait(AST::Path path, AST::Trait& trait)
{
+ path.resolve(m_crate);
+
// Handle local
- for( auto& st : trait.supertraits() ) {
- handle_path(st, MODE_TYPE);
- }
m_scope_stack.back().traits.push_back( ::std::pair<AST::Path, const AST::Trait&>(path, trait) );
+ CASTIterator::handle_trait(path, trait);
}
void CPathResolver::handle_function(AST::Path path, AST::Function& fcn)
{
diff --git a/src/include/span.hpp b/src/include/span.hpp
index c8c61627..452f37ba 100644
--- a/src/include/span.hpp
+++ b/src/include/span.hpp
@@ -52,5 +52,6 @@ struct Span
void note(::std::function<void(::std::ostream&)> msg) const;
};
-#define ERROR(span, code, msg) do { (span).error(code, [](::std::ostream& os) { os << msg; }); throw ::std::runtime_error("Error fell through" #code); } while(0)
+#define ERROR(span, code, msg) do { (span).error(code, [&](::std::ostream& os) { os << msg; }); throw ::std::runtime_error("Error fell through" #code); } while(0)
+#define BUG(span, msg) do { (span).bug([&](::std::ostream& os) { os << msg; }); throw ::std::runtime_error("Bug fell through"); } while(0)
diff --git a/src/main.cpp b/src/main.cpp
index 6515685a..e883b7ac 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -45,13 +45,12 @@ Rv CompilePhase(const char *name, Fcn f) {
g_cur_phase = name;
auto rv = f();
g_cur_phase = "";
+ ::std::cout << name << ": DONE" << ::std::endl;
return rv;
}
template <typename Fcn>
void CompilePhaseV(const char *name, Fcn f) {
- g_cur_phase = name;
- f();
- g_cur_phase = "";
+ CompilePhase<int>(name, [&]() { f(); return 0; });
}
/// main!
diff --git a/src/parse/root.cpp b/src/parse/root.cpp
index 422f036e..d0bf795c 100644
--- a/src/parse/root.cpp
+++ b/src/parse/root.cpp
@@ -227,6 +227,7 @@ AST::Function Parse_FunctionDef(TokenStream& lex, ::std::string abi, AST::MetaIt
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 )
diff --git a/src/types.hpp b/src/types.hpp
index 5bb257c7..90f9ee3b 100644
--- a/src/types.hpp
+++ b/src/types.hpp
@@ -103,6 +103,7 @@ public:
TypeData m_data;
TypeRef(TypeRef&& other) noexcept:
+ //m_span( mv$(other.m_span) ),
m_data( mv$(other.m_data) )
{}