/* * Convert all paths in AST into absolute form (or to the relevant local item) * - NOTE: This is the core of the 'resolve' pass. * * After complete there should be no: * - Relative/super/self paths * - MaybeBind patterns */ #include #include #include struct GenericSlot { enum class Level { Top, Method, } level; unsigned short index; }; template struct Named { ::std::string name; Val value; }; struct Context { TAGGED_UNION(Ent, Module, (Module, struct { const ::AST::Module* mod; }), (ConcreteSelf, const TypeRef* ), (VarBlock, struct { unsigned int level; // "Map" of names to function-level variable slots ::std::vector< Named< unsigned int > > variables; }), (Generic, struct { // Map of names to slots ::std::vector< Named< GenericSlot > > types; ::std::vector< Named< GenericSlot > > constants; ::std::vector< Named< GenericSlot > > lifetimes; }) ); const ::AST::Crate& m_crate; const ::AST::Module& m_mod; ::std::vector m_name_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), m_var_count(0), 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 { "Self", GenericSlot { level, 0xFFFF } } ); } if( params.ty_params().size() > 0 ) { const auto& typs = params.ty_params(); for(unsigned int i = 0; i < typs.size(); i ++ ) { data.types.push_back( Named { typs[i].name(), GenericSlot { level, static_cast(i) } } ); } } 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& ) { if( !m_name_context.back().is_Generic() ) BUG(Span(), "resolve/absolute.cpp - Context::pop(GenericParams) - Mismatched pop"); m_name_context.pop_back(); } void push(const ::AST::Module& mod) { m_name_context.push_back( Ent::make_Module({ &mod }) ); } void pop(const ::AST::Module& mod) { if( !m_name_context.back().is_Module() ) BUG(Span(), "resolve/absolute.cpp - Context::pop(GenericParams) - Mismatched pop"); m_name_context.pop_back(); } void push_self(const TypeRef& tr) { m_name_context.push_back( Ent::make_ConcreteSelf(&tr) ); } void pop_self(const TypeRef& tr) { TU_IFLET(Ent, m_name_context.back(), ConcreteSelf, e, m_name_context.pop_back(); ) else { BUG(Span(), "resolve/absolute.cpp - Context::pop(TypeRef) - Mismatched pop"); } } void push_block() { m_block_level += 1; } unsigned int push_var(const ::std::string& name) { // TODO: Handle avoiding duplicate bindings in a pattern if( m_frozen_bind_set ) { if( !m_name_context.back().is_VarBlock() ) { BUG(Span(), "resolve/absolute.cpp - Context::push_var - No block"); } auto& vb = m_name_context.back().as_VarBlock(); for( const auto& v : vb.variables ) { // TODO: Error when a binding is used twice or not at all if( v.name == name ) { return v.value; } } ERROR(Span(), E0000, "Mismatched bindings in pattern"); } else { assert( m_block_level > 0 ); if( !m_name_context.back().is_VarBlock() ) { m_name_context.push_back( Ent::make_VarBlock({ m_block_level, {} }) ); } m_name_context.back().as_VarBlock().variables.push_back( Named { name, m_var_count } ); m_var_count += 1; return m_var_count - 1; } } void pop_block() { assert( m_block_level > 0 ); if( m_name_context.back().is_VarBlock() ) { if( m_name_context.back().as_VarBlock().level == m_block_level ) { m_name_context.pop_back(); } } m_block_level -= 1; } /// Indicate that a multiple-pattern binding is started void start_patbind() { assert( m_block_level > 0 ); m_name_context.push_back( Ent::make_VarBlock({ m_block_level, {} }) ); assert( m_frozen_bind_set == false ); } /// Freeze the set of pattern bindings void freeze_patbind() { m_frozen_bind_set = true; } /// End a multiple-pattern binding state (unfreeze really) void end_patbind() { m_frozen_bind_set = false; } enum class LookupMode { Namespace, Type, Constant, Pattern, Variable, }; AST::Path lookup_mod(const Span& sp, const ::std::string& name) const { return this->lookup(sp, name, LookupMode::Namespace); } AST::Path lookup_type(const Span& sp, const ::std::string& name) const { return this->lookup(sp, name, LookupMode::Type); } AST::Path lookup_constant(const Span& sp, const ::std::string& name) const { return this->lookup(sp, name, LookupMode::Constant); } AST::Path lookup_value(const Span& sp, const ::std::string& name) const { return this->lookup(sp, name, LookupMode::Variable); } AST::Path lookup(const Span& sp, const ::std::string& name, LookupMode mode) const { auto rv = this->lookup_opt(name, mode); if( !rv.is_valid() ) { switch(mode) { case LookupMode::Namespace: ERROR(sp, E0000, "Couldn't find path component '" << name << "'"); case LookupMode::Type: ERROR(sp, E0000, "Couldn't find type name '" << name << "'"); case LookupMode::Pattern: ERROR(sp, E0000, "Couldn't find pattern name '" << name << "'"); case LookupMode::Constant: ERROR(sp, E0000, "Couldn't find constant name '" << name << "'"); case LookupMode::Variable: ERROR(sp, E0000, "Couldn't find variable name '" << name << "'"); } } return rv; } bool lookup_in_mod(const ::AST::Module& mod, const ::std::string& name, LookupMode mode, ::AST::Path& path) const { switch(mode) { case LookupMode::Namespace: { auto v = mod.m_namespace_items.find(name); if( v != mod.m_namespace_items.end() ) { path = ::AST::Path( v->second.path ); return true; } } { auto v = mod.m_type_items.find(name); if( v != mod.m_type_items.end() ) { path = ::AST::Path( v->second.path ); return true; } } break; case LookupMode::Type: //if( name == "SizeHint" ) { // DEBUG("lookup_in_mod(mod="<second.path ); return true; } } break; case LookupMode::Pattern: { auto v = mod.m_type_items.find(name); if( v != mod.m_type_items.end() ) { const auto& b = v->second.path.binding(); switch( b.tag() ) { case ::AST::PathBinding::TAG_Struct: path = ::AST::Path( v->second.path ); return true; default: break; } } } { auto v = mod.m_value_items.find(name); if( v != mod.m_value_items.end() ) { const auto& b = v->second.path.binding(); switch( b.tag() ) { case ::AST::PathBinding::TAG_EnumVar: case ::AST::PathBinding::TAG_Static: path = ::AST::Path( v->second.path ); return true; default: break; } } } break; case LookupMode::Constant: case LookupMode::Variable: { auto v = mod.m_value_items.find(name); if( v != mod.m_value_items.end() ) { path = ::AST::Path( v->second.path ); return true; } } break; } return false; } AST::Path lookup_opt(const ::std::string& name, LookupMode mode) const { for(auto it = m_name_context.rbegin(); it != m_name_context.rend(); ++ it) { TU_MATCH(Ent, (*it), (e), (Module, ::AST::Path rv; if( this->lookup_in_mod(*e.mod, name, mode, rv) ) { return rv; } ), (ConcreteSelf, if( ( mode == LookupMode::Type || mode == LookupMode::Namespace ) && name == "Self" ) { return ::AST::Path( ::AST::Path::TagUfcs(), *e, ::std::vector< ::AST::PathNode>() ); } ), (VarBlock, if( mode != LookupMode::Variable ) { // ignore } else { for( auto it2 = e.variables.rbegin(); it2 != e.variables.rend(); ++ it2 ) { if( it2->name == name ) { ::AST::Path rv(name); rv.bind_variable( it2->value ); return rv; } } } ), (Generic, if( mode == LookupMode::Type || mode == LookupMode::Namespace ) { for( auto it2 = e.types.rbegin(); it2 != e.types.rend(); ++ it2 ) { if( it2->name == name ) { ::AST::Path rv(name); rv.bind_variable( it2->value.index * (it2->value.level == GenericSlot::Level::Method ? 256 : 0) ); return rv; } } } else { // ignore. // TODO: Integer generics } ) ) } // Top-level module ::AST::Path rv; if( this->lookup_in_mod(m_mod, name, mode, rv) ) { return rv; } // Look up primitive types auto ct = coretype_fromstring(name); if( ct != CORETYPE_INVAL ) { return ::AST::Path( ::AST::Path::TagUfcs(), TypeRef(Span(), ct), ::std::vector< ::AST::PathNode>() ); } return AST::Path(); } /// 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); for(const auto& v : m_name_context) { TU_IFLET(Ent, v, Module, e, rv.m_name_context.push_back( Ent::make_Module(e) ); ) } return rv; } }; ::std::ostream& operator<<(::std::ostream& os, const Context::LookupMode& v) { switch(v) { case Context::LookupMode::Namespace:os << "Namespace"; break; case Context::LookupMode::Type: os << "Type"; break; case Context::LookupMode::Pattern: os << "Pattern"; break; case Context::LookupMode::Constant: os << "Constant"; break; case Context::LookupMode::Variable: os << "Variable"; break; } return os; } void Resolve_Absolute_Path(/*const*/ Context& context, const Span& sp, Context::LookupMode mode, ::AST::Path& path); void Resolve_Absolute_Type(Context& context, TypeRef& type); void Resolve_Absolute_Expr(Context& context, ::AST::Expr& expr); void Resolve_Absolute_Expr(Context& context, ::AST::ExprNode& node); void Resolve_Absolute_Pattern(Context& context, bool allow_refutable, ::AST::Pattern& pat); void Resolve_Absolute_Mod(const ::AST::Crate& crate, ::AST::Module& mod); void Resolve_Absolute_Mod( Context item_context, ::AST::Module& mod ); void Resolve_Absolute_PathNodes(/*const*/ Context& context, const Span& sp, ::std::vector< ::AST::PathNode >& nodes) { for(auto& node : nodes) { for(auto& arg : node.args()) { Resolve_Absolute_Type(context, arg); } } } void Resolve_Absolute_Path(/*const*/ Context& context, const Span& sp, Context::LookupMode mode, ::AST::Path& path) { DEBUG("mode = " << mode << ", path = " << path); TU_MATCH(::AST::Path::Class, (path.m_class), (e), (Invalid, BUG(sp, "Attempted resolution of invalid path"); ), (Local, // Nothing to do (TODO: Check that it's valid?) ), (Relative, DEBUG("- Relative"); if(e.nodes.size() == 0) BUG(sp, "Resolve_Absolute_Path - Relative path with no nodes"); if(e.nodes.size() > 1) { // Look up type auto p = context.lookup(sp, e.nodes[0].name(), Context::LookupMode::Namespace); DEBUG("Found type/mod - " << p); if( e.nodes.size() > 1 ) { if( p.m_class.is_Local() ) { p = ::AST::Path( ::AST::Path::TagUfcs(), TypeRef(sp, mv$(p)) ); } if( e.nodes[0].args().size() > 0 ) { assert( p.nodes().size() > 0 ); assert( p.nodes().back().args().size() == 0 ); p.nodes().back().args() = mv$( e.nodes[0].args() ); } for( unsigned int i = 1; i < e.nodes.size(); i ++ ) { p.nodes().push_back( mv$(e.nodes[i]) ); } } path = mv$(p); } else { // Look up value auto p = context.lookup(sp, e.nodes[0].name(), mode); DEBUG("Found val - " << p); path = mv$(p); } if( !path.is_trivial() ) Resolve_Absolute_PathNodes(context, Span(), path.nodes()); ), (Self, DEBUG("- Self"); TODO(sp, "Resolve_Absolute_Path - Self-relative paths - " << path); ), (Super, DEBUG("- Super"); // - Determine how many components of the `self` path to use const auto& mp_nodes = context.m_mod.path().nodes(); assert( e.count >= 1 ); unsigned int start_len = e.count > mp_nodes.size() ? 0 : mp_nodes.size() - e.count; // - Create a new path ::AST::Path np("", {}); auto& np_nodes = np.nodes(); np_nodes.reserve( start_len + e.nodes.size() ); for(unsigned int i = 0; i < start_len; i ++ ) np_nodes.push_back( mp_nodes[i] ); for(auto& en : e.nodes) np_nodes.push_back( mv$(en) ); // TODO: Resolve to the actual item? if( !path.is_trivial() ) Resolve_Absolute_PathNodes(context, Span(), np_nodes); path = mv$(np); ), (Absolute, DEBUG("- Absolute"); // Nothing to do (TODO: Bind?) ), (UFCS, DEBUG("- UFCS"); Resolve_Absolute_Type(context, *e.type); if( e.trait ) { Resolve_Absolute_Path(context, Span(), Context::LookupMode::Type, *e.trait); } Resolve_Absolute_PathNodes(context, Span(), e.nodes); ) ) } void Resolve_Absolute_Type(Context& context, TypeRef& type) { const auto& sp = type.span(); TU_MATCH(TypeData, (type.m_data), (e), (None, // ! type ), (Any, // _ type ), (Unit, ), (Macro, BUG(sp, "Resolve_Absolute_Type - Encountered an unexpanded macro"); ), (Primitive, ), (Function, Resolve_Absolute_Type(context, *e.info.m_rettype); for(auto& t : e.info.m_arg_types) { Resolve_Absolute_Type(context, t); } ), (Tuple, for(auto& t : e.inner_types) Resolve_Absolute_Type(context, t); ), (Borrow, Resolve_Absolute_Type(context, *e.inner); ), (Pointer, Resolve_Absolute_Type(context, *e.inner); ), (Array, Resolve_Absolute_Type(context, *e.inner); if( e.size ) { // TODO: Prevent variables from being picked as the array size Resolve_Absolute_Expr(context, *e.size); } ), (Generic, // TODO: Should this be bound to the relevant index, or just leave as-is? ), (Path, Resolve_Absolute_Path(context, type.span(), Context::LookupMode::Type, e.path); ), (TraitObject, //context.push_lifetimes( e.hrls ); for(auto& trait : e.traits) { Resolve_Absolute_Path(context, type.span(), Context::LookupMode::Type, trait); } //context.pop_lifetimes(); ) ) } void Resolve_Absolute_Expr(Context& context, ::AST::Expr& expr) { if( expr.is_valid() ) { Resolve_Absolute_Expr(context, expr.node()); } } void Resolve_Absolute_Expr(Context& context, ::AST::ExprNode& node) { TRACE_FUNCTION_F(""); struct NV: 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 ) { this->context.push( *node.m_local_mod ); // Clone just the module stack part of the current context Resolve_Absolute_Mod(this->context.clone_mod(), *node.m_local_mod); } this->context.push_block(); AST::NodeVisitorDef::visit(node); this->context.pop_block(); if( node.m_local_mod ) { this->context.pop( *node.m_local_mod ); } } void visit(AST::ExprNode_Match& node) override { DEBUG("ExprNode_Match"); node.m_val->visit( *this ); for( auto& arm : node.m_arms ) { this->context.push_block(); if( arm.m_patterns.size() > 1 ) { // TODO: Save the context, ensure that each arm results in the same state. // - Or just an equivalent state // OR! Have a mode in the context that handles multiple bindings. this->context.start_patbind(); for( auto& pat : arm.m_patterns ) { Resolve_Absolute_Pattern(this->context, true, pat); this->context.freeze_patbind(); } this->context.end_patbind(); // Requires ensuring that the binding set is the same. } 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(); } } void visit(AST::ExprNode_Loop& node) override { AST::NodeVisitorDef::visit(node.m_cond); this->context.push_block(); switch( node.m_type ) { case ::AST::ExprNode_Loop::LOOP: break; case ::AST::ExprNode_Loop::WHILE: break; case ::AST::ExprNode_Loop::WHILELET: case ::AST::ExprNode_Loop::FOR: Resolve_Absolute_Pattern(this->context, true, node.m_pattern); break; } 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); AST::NodeVisitorDef::visit(node); Resolve_Absolute_Pattern(this->context, false, node.m_pat); } 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 ); if(node.m_false) node.m_false->visit(*this); this->context.pop_block(); } void visit(AST::ExprNode_StructLiteral& node) override { DEBUG("ExprNode_StructLiteral"); Resolve_Absolute_Path(this->context, Span(node.get_pos()), Context::LookupMode::Type, node.m_path); AST::NodeVisitorDef::visit(node); } void visit(AST::ExprNode_CallPath& node) override { DEBUG("ExprNode_CallPath"); Resolve_Absolute_Path(this->context, Span(node.get_pos()), Context::LookupMode::Variable, node.m_path); AST::NodeVisitorDef::visit(node); } void visit(AST::ExprNode_NamedValue& node) override { DEBUG("ExprNode_NamedValue"); Resolve_Absolute_Path(this->context, Span(node.get_pos()), Context::LookupMode::Variable, node.m_path); } void visit(AST::ExprNode_Cast& node) override { DEBUG("ExprNode_Cast"); Resolve_Absolute_Type(this->context, node.m_type); AST::NodeVisitorDef::visit(node); } void visit(AST::ExprNode_Closure& node) override { DEBUG("ExprNode_Closure"); Resolve_Absolute_Type(this->context, node.m_return); 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); } } expr_iter(context); node.visit( expr_iter ); } void Resolve_Absolute_Generic(Context& context, ::AST::GenericParams& params) { for( auto& bound : params.bounds() ) { TU_MATCH(::AST::GenericBound, (bound), (e), (Lifetime, // TODO: Link lifetime names to params ), (TypeLifetime, Resolve_Absolute_Type(context, e.type); ), (IsTrait, Resolve_Absolute_Type(context, e.type); Resolve_Absolute_Path(context, Span(), Context::LookupMode::Type, e.trait); ), (MaybeTrait, Resolve_Absolute_Type(context, e.type); Resolve_Absolute_Path(context, Span(), Context::LookupMode::Type, e.trait); ), (NotTrait, Resolve_Absolute_Type(context, e.type); Resolve_Absolute_Path(context, Span(), Context::LookupMode::Type, e.trait); ), (Equality, Resolve_Absolute_Type(context, e.type); Resolve_Absolute_Type(context, e.replacement); ) ) } } // Locals shouldn't be possible, as they'd end up as MaybeBind. Will assert the path class. void Resolve_Absolute_PatternValue(/*const*/ Context& context, ::AST::Pattern::Value& val) { TU_MATCH(::AST::Pattern::Value, (val), (e), (Invalid, ), (Integer, ), (String, ), (Named, //assert( ! e.is_trivial() ); Resolve_Absolute_Path(context, Span(), Context::LookupMode::Constant, e); ) ) } void Resolve_Absolute_Pattern(Context& context, bool allow_refutable, ::AST::Pattern& pat) { TRACE_FUNCTION_F("allow_refutable = " << allow_refutable << ", pat = " << pat); if( pat.binding() != "" ) { if( !pat.data().is_Any() && ! allow_refutable ) TODO(Span(), "Resolve_Absolute_Pattern - Encountered bound destructuring pattern"); // TODO: Record the local variable number in the binding context.push_var( pat.binding() ); } TU_MATCH( ::AST::Pattern::Data, (pat.data()), (e), (MaybeBind, assert( pat.binding() == "" ); if( allow_refutable ) { auto name = mv$( e.name ); // Attempt to resolve the name in the current namespace, and if it fails, it's a binding auto p = context.lookup_opt( name, Context::LookupMode::Constant ); if( p.is_valid() ) { pat = ::AST::Pattern(::AST::Pattern::TagValue(), ::AST::Pattern::Value::make_Named(mv$(p))); } else { pat = ::AST::Pattern(::AST::Pattern::TagBind(), mv$(name)); // TODO: Record the local variable number in the binding context.push_var( pat.binding() ); } } else { TODO(Span(), "Resolve_Absolute_Pattern - Encountered MaybeBind in irrefutable context - replace with binding"); } ), (Macro, BUG(Span(), "Resolve_Absolute_Pattern - Encountered Macro"); ), (Any, // Ignore '_' ), (Box, Resolve_Absolute_Pattern(context, allow_refutable, *e.sub); ), (Ref, Resolve_Absolute_Pattern(context, allow_refutable, *e.sub); ), (Value, if( ! allow_refutable ) BUG(Span(), "Resolve_Absolute_Pattern - Enountered refutable pattern where only irrefutable allowed"); Resolve_Absolute_PatternValue(context, e.start); Resolve_Absolute_PatternValue(context, e.end); ), (Tuple, for(auto& sp : e.sub_patterns) Resolve_Absolute_Pattern(context, allow_refutable, sp); ), (StructTuple, // TODO: This isn't a type lookup, it's a pattern lookup (allowing imported enum variants, e.g. `Some(_)` to work) Resolve_Absolute_Path(context, Span(), Context::LookupMode::Pattern, e.path); for(auto& sp : e.sub_patterns) Resolve_Absolute_Pattern(context, allow_refutable, sp); ), (Struct, Resolve_Absolute_Path(context, Span(), Context::LookupMode::Type, e.path); for(auto& sp : e.sub_patterns) Resolve_Absolute_Pattern(context, allow_refutable, sp.second); ), (Slice, if( !allow_refutable ) BUG(Span(), "Resolve_Absolute_Pattern - Enountered refutable pattern where only irrefutable allowed"); for(auto& sp : e.leading) Resolve_Absolute_Pattern(context, allow_refutable, sp); if( e.extra_bind != "" && e.extra_bind != "_" ) { context.push_var( e.extra_bind ); } for(auto& sp : e.trailing) Resolve_Absolute_Pattern(context, allow_refutable, sp); ) ) } void Resolve_Absolute_ImplItems(Context& item_context, ::AST::NamedList< ::AST::Item >& items) { TRACE_FUNCTION_F(""); for(auto& i : items) { TU_MATCH(AST::Item, (i.data), (e), (None, ), (Module, BUG(Span(), "Resolve_Absolute_ImplItems - Module");), (Crate , BUG(Span(), "Resolve_Absolute_ImplItems - Crate");), (Enum , BUG(Span(), "Resolve_Absolute_ImplItems - Enum");), (Trait , BUG(Span(), "Resolve_Absolute_ImplItems - Trait");), (Struct, BUG(Span(), "Resolve_Absolute_ImplItems - Struct");), (Type, DEBUG("Type - " << i.name); assert( e.params().ty_params().size() == 0 ); assert( e.params().lft_params().size() == 0 ); //item_context.push( e.params(), GenericSlot::Level::Method ); Resolve_Absolute_Generic(item_context, e.params()); Resolve_Absolute_Type( item_context, e.type() ); //item_context.pop( e.params() ); ), (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 ); 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, DEBUG("Static - " << i.name); TODO(Span(), "Resolve_Absolute_ImplItems - Static"); ) ) } } void Resolve_Absolute_Mod(const ::AST::Crate& crate, ::AST::Module& mod) { Resolve_Absolute_Mod( Context { crate, mod }, mod ); } void Resolve_Absolute_Mod( Context item_context, ::AST::Module& mod ) { TRACE_FUNCTION_F("(mod="<