// Copyright (C) 2020-2023 Free Software Foundation, Inc. // This file is part of GCC. // GCC is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free // Software Foundation; either version 3, or (at your option) any later // version. // GCC is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // You should have received a copy of the GNU General Public License // along with GCC; see the file COPYING3. If not see // . #include "rust-ast-resolve-path.h" #include "rust-ast-resolve-type.h" #include "rust-path.h" namespace Rust { namespace Resolver { ResolvePath::ResolvePath () : ResolverBase () {} void ResolvePath::go (AST::PathInExpression *expr) { ResolvePath resolver; resolver.resolve_path (expr); } void ResolvePath::go (AST::QualifiedPathInExpression *expr) { ResolvePath resolver; resolver.resolve_path (expr); } void ResolvePath::go (AST::SimplePath *expr) { ResolvePath resolver; resolver.resolve_path (expr); } void ResolvePath::resolve_path (AST::PathInExpression *expr) { NodeId resolved_node_id = UNKNOWN_NODEID; NodeId module_scope_id = resolver->peek_current_module_scope (); NodeId previous_resolved_node_id = module_scope_id; for (size_t i = 0; i < expr->get_segments ().size (); i++) { auto &segment = expr->get_segments ().at (i); const AST::PathIdentSegment &ident_seg = segment.get_ident_segment (); bool is_first_segment = i == 0; resolved_node_id = UNKNOWN_NODEID; bool in_middle_of_path = i > 0; if (in_middle_of_path && segment.is_lower_self_seg ()) { // error[E0433]: failed to resolve: `self` in paths can only be used // in start position rust_error_at (segment.get_locus (), "failed to resolve: %<%s%> in paths can only be used " "in start position", segment.as_string ().c_str ()); return; } NodeId crate_scope_id = resolver->peek_crate_module_scope (); if (segment.is_crate_path_seg ()) { // what is the current crate scope node id? module_scope_id = crate_scope_id; previous_resolved_node_id = module_scope_id; resolver->insert_resolved_name (segment.get_node_id (), module_scope_id); continue; } else if (segment.is_super_path_seg ()) { if (module_scope_id == crate_scope_id) { rust_error_at (segment.get_locus (), "cannot use % at the crate scope"); return; } module_scope_id = resolver->peek_parent_module_scope (); previous_resolved_node_id = module_scope_id; resolver->insert_resolved_name (segment.get_node_id (), module_scope_id); continue; } // resolve any generic args if (segment.has_generic_args ()) ResolveGenericArgs::go (segment.get_generic_args ()); // logic is awkward here there are a few cases // // T::Default // mod::foo::impl_item // super::super::module::item // self // self::foo // self::foo::baz // // T::Default we can only resolve the T and cant do anything about Default // its dependant on associated types // // mod::foo::impl_item // we can resolve mod::foo but nothing about impl_item but we need to // _always resolve generic arguments // // self is a simple single lookup // // we have module_scope_id for the next module_scope to lookup // resolved_node_id is the thing we have resolve this segment to // // new algo? // we can only use module resolution when the previous segment is either // unknown or equal to this module_scope_id // // can only use old resolution when previous segment is unkown if (is_first_segment) { // name scope first NodeId resolved_node = UNKNOWN_NODEID; const CanonicalPath path = CanonicalPath::new_seg (segment.get_node_id (), ident_seg.as_string ()); if (resolver->get_name_scope ().lookup (path, &resolved_node)) { resolver->insert_resolved_name (segment.get_node_id (), resolved_node); resolved_node_id = resolved_node; } // check the type scope else if (resolver->get_type_scope ().lookup (path, &resolved_node)) { resolver->insert_resolved_type (segment.get_node_id (), resolved_node); resolved_node_id = resolved_node; } else if (segment.is_lower_self_seg ()) { module_scope_id = crate_scope_id; previous_resolved_node_id = module_scope_id; resolver->insert_resolved_name (segment.get_node_id (), module_scope_id); continue; } else { // no error handling here since we might be able to resolve via // the module hierarchy and handle errors at the end } } if (resolved_node_id == UNKNOWN_NODEID && previous_resolved_node_id == module_scope_id) { Optional resolved_child = mappings->lookup_module_child (module_scope_id, ident_seg.as_string ()); if (resolved_child.is_some ()) { NodeId resolved_node = resolved_child->get_node_id (); if (resolver->get_name_scope ().decl_was_declared_here ( resolved_node)) { resolved_node_id = resolved_node; resolver->insert_resolved_name (segment.get_node_id (), resolved_node); } else if (resolver->get_type_scope ().decl_was_declared_here ( resolved_node)) { resolved_node_id = resolved_node; resolver->insert_resolved_type (segment.get_node_id (), resolved_node); } else { rust_error_at (segment.get_locus (), "Cannot find path %<%s%> in this scope", segment.as_string ().c_str ()); return; } } } bool did_resolve_segment = resolved_node_id != UNKNOWN_NODEID; if (did_resolve_segment) { if (mappings->node_is_module (resolved_node_id) || mappings->node_is_crate (resolved_node_id)) { module_scope_id = resolved_node_id; } previous_resolved_node_id = resolved_node_id; } else if (is_first_segment) { rust_error_at (segment.get_locus (), "Cannot find path %<%s%> in this scope", segment.as_string ().c_str ()); return; } } resolved_node = resolved_node_id; if (resolved_node_id != UNKNOWN_NODEID) { // name scope first if (resolver->get_name_scope ().decl_was_declared_here (resolved_node_id)) { resolver->insert_resolved_name (expr->get_node_id (), resolved_node_id); } // check the type scope else if (resolver->get_type_scope ().decl_was_declared_here ( resolved_node_id)) { resolver->insert_resolved_type (expr->get_node_id (), resolved_node_id); } else { gcc_unreachable (); } } } void ResolvePath::resolve_path (AST::QualifiedPathInExpression *expr) { AST::QualifiedPathType &root_segment = expr->get_qualified_path_type (); ResolveType::go (root_segment.get_type ().get ()); if (root_segment.has_as_clause ()) ResolveType::go (&root_segment.get_as_type_path ()); for (auto &segment : expr->get_segments ()) { // we cant actually do anything with the segment itself since this is all // the job of the type system to figure it out but we can resolve any // generic arguments used if (segment.has_generic_args ()) ResolveGenericArgs::go (segment.get_generic_args ()); } } void ResolvePath::resolve_path (AST::SimplePath *expr) { NodeId crate_scope_id = resolver->peek_crate_module_scope (); NodeId module_scope_id = resolver->peek_current_module_scope (); NodeId resolved_node_id = UNKNOWN_NODEID; for (size_t i = 0; i < expr->get_segments ().size (); i++) { auto &segment = expr->get_segments ().at (i); bool is_first_segment = i == 0; resolved_node_id = UNKNOWN_NODEID; if (segment.is_crate_path_seg ()) { // what is the current crate scope node id? module_scope_id = crate_scope_id; resolver->insert_resolved_name (segment.get_node_id (), module_scope_id); continue; } else if (segment.is_super_path_seg ()) { if (module_scope_id == crate_scope_id) { rust_error_at (segment.get_locus (), "cannot use % at the crate scope"); return; } module_scope_id = resolver->peek_parent_module_scope (); resolver->insert_resolved_name (segment.get_node_id (), module_scope_id); continue; } Optional resolved_child = mappings->lookup_module_child (module_scope_id, segment.get_segment_name ()); if (resolved_child.is_some ()) { NodeId resolved_node = resolved_child->get_node_id (); if (resolver->get_name_scope ().decl_was_declared_here ( resolved_node)) { resolved_node_id = resolved_node; resolver->insert_resolved_name (segment.get_node_id (), resolved_node); } else if (resolver->get_type_scope ().decl_was_declared_here ( resolved_node)) { resolved_node_id = resolved_node; resolver->insert_resolved_type (segment.get_node_id (), resolved_node); } else { rust_error_at (segment.get_locus (), "Cannot find path %<%s%> in this scope", segment.as_string ().c_str ()); return; } } if (resolved_node_id == UNKNOWN_NODEID && is_first_segment) { // name scope first NodeId resolved_node = UNKNOWN_NODEID; const CanonicalPath path = CanonicalPath::new_seg (segment.get_node_id (), segment.get_segment_name ()); if (resolver->get_name_scope ().lookup (path, &resolved_node)) { resolved_node_id = resolved_node; resolver->insert_resolved_name (segment.get_node_id (), resolved_node); } // check the type scope else if (resolver->get_type_scope ().lookup (path, &resolved_node)) { resolved_node_id = resolved_node; resolver->insert_resolved_type (segment.get_node_id (), resolved_node); } } if (resolved_node_id == UNKNOWN_NODEID) { rust_error_at (segment.get_locus (), "cannot find simple path segment %<%s%> in this scope", segment.as_string ().c_str ()); return; } if (mappings->node_is_module (resolved_node_id)) { module_scope_id = resolved_node_id; } } resolved_node = resolved_node_id; if (resolved_node_id != UNKNOWN_NODEID) { // name scope first if (resolver->get_name_scope ().decl_was_declared_here (resolved_node_id)) { resolver->insert_resolved_name (expr->get_node_id (), resolved_node_id); } // check the type scope else if (resolver->get_type_scope ().decl_was_declared_here ( resolved_node_id)) { resolver->insert_resolved_type (expr->get_node_id (), resolved_node_id); } else { gcc_unreachable (); } } } } // namespace Resolver } // namespace Rust