// 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-expr.h" #include "rust-ast-resolve-stmt.h" #include "rust-ast-resolve-struct-expr-field.h" #include "rust-ast-verify-assignee.h" #include "rust-ast-resolve-type.h" #include "rust-ast-resolve-pattern.h" #include "rust-ast-resolve-path.h" namespace Rust { namespace Resolver { void ResolveExpr::go (AST::Expr *expr, const CanonicalPath &prefix, const CanonicalPath &canonical_prefix) { ResolveExpr resolver (prefix, canonical_prefix); expr->accept_vis (resolver); } void ResolveExpr::visit (AST::TupleIndexExpr &expr) { ResolveExpr::go (expr.get_tuple_expr ().get (), prefix, canonical_prefix); } void ResolveExpr::visit (AST::TupleExpr &expr) { if (expr.is_unit ()) return; for (auto &elem : expr.get_tuple_elems ()) ResolveExpr::go (elem.get (), prefix, canonical_prefix); } void ResolveExpr::visit (AST::PathInExpression &expr) { ResolvePath::go (&expr); } void ResolveExpr::visit (AST::QualifiedPathInExpression &expr) { ResolvePath::go (&expr); } void ResolveExpr::visit (AST::ReturnExpr &expr) { if (expr.has_returned_expr ()) ResolveExpr::go (expr.get_returned_expr ().get (), prefix, canonical_prefix); } void ResolveExpr::visit (AST::CallExpr &expr) { ResolveExpr::go (expr.get_function_expr ().get (), prefix, canonical_prefix); for (auto ¶m : expr.get_params ()) ResolveExpr::go (param.get (), prefix, canonical_prefix); } void ResolveExpr::visit (AST::MethodCallExpr &expr) { ResolveExpr::go (expr.get_receiver_expr ().get (), prefix, canonical_prefix); if (expr.get_method_name ().has_generic_args ()) { AST::GenericArgs &args = expr.get_method_name ().get_generic_args (); ResolveGenericArgs::go (args, prefix, canonical_prefix); } auto const &in_params = expr.get_params (); for (auto ¶m : in_params) ResolveExpr::go (param.get (), prefix, canonical_prefix); } void ResolveExpr::visit (AST::AssignmentExpr &expr) { ResolveExpr::go (expr.get_left_expr ().get (), prefix, canonical_prefix); ResolveExpr::go (expr.get_right_expr ().get (), prefix, canonical_prefix); // need to verify the assignee VerifyAsignee::go (expr.get_left_expr ().get ()); } void ResolveExpr::visit (AST::IdentifierExpr &expr) { if (resolver->get_name_scope ().lookup ( CanonicalPath::new_seg (expr.get_node_id (), expr.as_string ()), &resolved_node)) { resolver->insert_resolved_name (expr.get_node_id (), resolved_node); } else if (resolver->get_type_scope ().lookup ( CanonicalPath::new_seg (expr.get_node_id (), expr.as_string ()), &resolved_node)) { resolver->insert_resolved_type (expr.get_node_id (), resolved_node); } else { rust_error_at (expr.get_locus (), "failed to find name: %s", expr.as_string ().c_str ()); } } void ResolveExpr::visit (AST::ArithmeticOrLogicalExpr &expr) { ResolveExpr::go (expr.get_left_expr ().get (), prefix, canonical_prefix); ResolveExpr::go (expr.get_right_expr ().get (), prefix, canonical_prefix); } void ResolveExpr::visit (AST::CompoundAssignmentExpr &expr) { ResolveExpr::go (expr.get_left_expr ().get (), prefix, canonical_prefix); ResolveExpr::go (expr.get_right_expr ().get (), prefix, canonical_prefix); // need to verify the assignee VerifyAsignee::go (expr.get_left_expr ().get ()); } void ResolveExpr::visit (AST::ComparisonExpr &expr) { ResolveExpr::go (expr.get_left_expr ().get (), prefix, canonical_prefix); ResolveExpr::go (expr.get_right_expr ().get (), prefix, canonical_prefix); } void ResolveExpr::visit (AST::LazyBooleanExpr &expr) { ResolveExpr::go (expr.get_left_expr ().get (), prefix, canonical_prefix); ResolveExpr::go (expr.get_right_expr ().get (), prefix, canonical_prefix); } void ResolveExpr::visit (AST::NegationExpr &expr) { ResolveExpr::go (expr.get_negated_expr ().get (), prefix, canonical_prefix); } void ResolveExpr::visit (AST::TypeCastExpr &expr) { ResolveType::go (expr.get_type_to_cast_to ().get ()); ResolveExpr::go (expr.get_casted_expr ().get (), prefix, canonical_prefix); } void ResolveExpr::visit (AST::IfExpr &expr) { ResolveExpr::go (expr.get_condition_expr ().get (), prefix, canonical_prefix); ResolveExpr::go (expr.get_if_block ().get (), prefix, canonical_prefix); } void ResolveExpr::visit (AST::IfExprConseqElse &expr) { ResolveExpr::go (expr.get_condition_expr ().get (), prefix, canonical_prefix); ResolveExpr::go (expr.get_if_block ().get (), prefix, canonical_prefix); ResolveExpr::go (expr.get_else_block ().get (), prefix, canonical_prefix); } void ResolveExpr::visit (AST::IfExprConseqIf &expr) { ResolveExpr::go (expr.get_condition_expr ().get (), prefix, canonical_prefix); ResolveExpr::go (expr.get_if_block ().get (), prefix, canonical_prefix); ResolveExpr::go (expr.get_conseq_if_expr ().get (), prefix, canonical_prefix); } void ResolveExpr::visit (AST::IfLetExpr &expr) { ResolveExpr::go (expr.get_value_expr ().get (), prefix, canonical_prefix); NodeId scope_node_id = expr.get_node_id (); resolver->get_name_scope ().push (scope_node_id); resolver->get_type_scope ().push (scope_node_id); resolver->get_label_scope ().push (scope_node_id); resolver->push_new_name_rib (resolver->get_name_scope ().peek ()); resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); resolver->push_new_label_rib (resolver->get_type_scope ().peek ()); for (auto &pattern : expr.get_patterns ()) { PatternDeclaration::go (pattern.get (), Rib::ItemType::Var); } ResolveExpr::go (expr.get_if_block ().get (), prefix, canonical_prefix); resolver->get_name_scope ().pop (); resolver->get_type_scope ().pop (); resolver->get_label_scope ().pop (); } void ResolveExpr::visit (AST::BlockExpr &expr) { NodeId scope_node_id = expr.get_node_id (); resolver->get_name_scope ().push (scope_node_id); resolver->get_type_scope ().push (scope_node_id); resolver->get_label_scope ().push (scope_node_id); resolver->push_new_name_rib (resolver->get_name_scope ().peek ()); resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); resolver->push_new_label_rib (resolver->get_type_scope ().peek ()); for (auto &s : expr.get_statements ()) { if (s->is_item ()) ResolveStmt::go (s.get (), prefix, canonical_prefix, CanonicalPath::create_empty ()); } for (auto &s : expr.get_statements ()) { if (!s->is_item ()) ResolveStmt::go (s.get (), prefix, canonical_prefix, CanonicalPath::create_empty ()); } if (expr.has_tail_expr ()) ResolveExpr::go (expr.get_tail_expr ().get (), prefix, canonical_prefix); resolver->get_name_scope ().pop (); resolver->get_type_scope ().pop (); resolver->get_label_scope ().pop (); } void ResolveExpr::visit (AST::UnsafeBlockExpr &expr) { expr.get_block_expr ()->accept_vis (*this); } void ResolveExpr::visit (AST::ArrayElemsValues &elems) { for (auto &elem : elems.get_values ()) ResolveExpr::go (elem.get (), prefix, canonical_prefix); } void ResolveExpr::visit (AST::ArrayExpr &expr) { expr.get_array_elems ()->accept_vis (*this); } void ResolveExpr::visit (AST::ArrayIndexExpr &expr) { ResolveExpr::go (expr.get_array_expr ().get (), prefix, canonical_prefix); ResolveExpr::go (expr.get_index_expr ().get (), prefix, canonical_prefix); } void ResolveExpr::visit (AST::ArrayElemsCopied &expr) { ResolveExpr::go (expr.get_num_copies ().get (), prefix, canonical_prefix); ResolveExpr::go (expr.get_elem_to_copy ().get (), prefix, canonical_prefix); } // this this an empty struct constructor like 'S {}' void ResolveExpr::visit (AST::StructExprStruct &struct_expr) { ResolveExpr::go (&struct_expr.get_struct_name (), prefix, canonical_prefix); } // this this a struct constructor with fields void ResolveExpr::visit (AST::StructExprStructFields &struct_expr) { ResolveExpr::go (&struct_expr.get_struct_name (), prefix, canonical_prefix); if (struct_expr.has_struct_base ()) { AST::StructBase &base = struct_expr.get_struct_base (); ResolveExpr::go (base.get_base_struct ().get (), prefix, canonical_prefix); } auto const &struct_fields = struct_expr.get_fields (); for (auto &struct_field : struct_fields) { ResolveStructExprField::go (struct_field.get (), prefix, canonical_prefix); } } void ResolveExpr::visit (AST::GroupedExpr &expr) { ResolveExpr::go (expr.get_expr_in_parens ().get (), prefix, canonical_prefix); } void ResolveExpr::visit (AST::FieldAccessExpr &expr) { ResolveExpr::go (expr.get_receiver_expr ().get (), prefix, canonical_prefix); } void ResolveExpr::visit (AST::LoopExpr &expr) { if (expr.has_loop_label ()) { auto label = expr.get_loop_label (); if (label.get_lifetime ().get_lifetime_type () != AST::Lifetime::LifetimeType::NAMED) { rust_error_at (label.get_locus (), "Labels must be a named lifetime value"); return; } auto label_name = label.get_lifetime ().get_lifetime_name (); auto label_lifetime_node_id = label.get_lifetime ().get_node_id (); resolver->get_label_scope ().insert ( CanonicalPath::new_seg (expr.get_node_id (), label_name), label_lifetime_node_id, label.get_locus (), false, Rib::ItemType::Label, [&] (const CanonicalPath &, NodeId, Location locus) -> void { rust_error_at (label.get_locus (), "label redefined multiple times"); rust_error_at (locus, "was defined here"); }); } ResolveExpr::go (expr.get_loop_block ().get (), prefix, canonical_prefix); } void ResolveExpr::visit (AST::BreakExpr &expr) { if (expr.has_label ()) { auto label = expr.get_label (); if (label.get_lifetime_type () != AST::Lifetime::LifetimeType::NAMED) { rust_error_at (label.get_locus (), "Labels must be a named lifetime value"); return; } NodeId resolved_node = UNKNOWN_NODEID; if (!resolver->get_label_scope ().lookup ( CanonicalPath::new_seg (label.get_node_id (), label.get_lifetime_name ()), &resolved_node)) { rust_error_at (expr.get_label ().get_locus (), "failed to resolve label"); return; } resolver->insert_resolved_label (label.get_node_id (), resolved_node); } if (expr.has_break_expr ()) ResolveExpr::go (expr.get_break_expr ().get (), prefix, canonical_prefix); } void ResolveExpr::visit (AST::WhileLoopExpr &expr) { if (expr.has_loop_label ()) { auto label = expr.get_loop_label (); if (label.get_lifetime ().get_lifetime_type () != AST::Lifetime::LifetimeType::NAMED) { rust_error_at (label.get_locus (), "Labels must be a named lifetime value"); return; } auto label_name = label.get_lifetime ().get_lifetime_name (); auto label_lifetime_node_id = label.get_lifetime ().get_node_id (); resolver->get_label_scope ().insert ( CanonicalPath::new_seg (label.get_node_id (), label_name), label_lifetime_node_id, label.get_locus (), false, Rib::ItemType::Label, [&] (const CanonicalPath &, NodeId, Location locus) -> void { rust_error_at (label.get_locus (), "label redefined multiple times"); rust_error_at (locus, "was defined here"); }); } ResolveExpr::go (expr.get_predicate_expr ().get (), prefix, canonical_prefix); ResolveExpr::go (expr.get_loop_block ().get (), prefix, canonical_prefix); } void ResolveExpr::visit (AST::ForLoopExpr &expr) { if (expr.has_loop_label ()) { auto label = expr.get_loop_label (); if (label.get_lifetime ().get_lifetime_type () != AST::Lifetime::LifetimeType::NAMED) { rust_error_at (label.get_locus (), "Labels must be a named lifetime value"); return; } auto label_name = label.get_lifetime ().get_lifetime_name (); auto label_lifetime_node_id = label.get_lifetime ().get_node_id (); resolver->get_label_scope ().insert ( CanonicalPath::new_seg (label.get_node_id (), label_name), label_lifetime_node_id, label.get_locus (), false, Rib::ItemType::Label, [&] (const CanonicalPath &, NodeId, Location locus) -> void { rust_error_at (label.get_locus (), "label redefined multiple times"); rust_error_at (locus, "was defined here"); }); } // this needs a new rib to contain the pattern NodeId scope_node_id = expr.get_node_id (); resolver->get_name_scope ().push (scope_node_id); resolver->get_type_scope ().push (scope_node_id); resolver->get_label_scope ().push (scope_node_id); resolver->push_new_name_rib (resolver->get_name_scope ().peek ()); resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); resolver->push_new_label_rib (resolver->get_type_scope ().peek ()); // resolve the expression PatternDeclaration::go (expr.get_pattern ().get (), Rib::ItemType::Var); ResolveExpr::go (expr.get_iterator_expr ().get (), prefix, canonical_prefix); ResolveExpr::go (expr.get_loop_block ().get (), prefix, canonical_prefix); // done resolver->get_name_scope ().pop (); resolver->get_type_scope ().pop (); resolver->get_label_scope ().pop (); } void ResolveExpr::visit (AST::ContinueExpr &expr) { if (expr.has_label ()) { auto label = expr.get_label (); if (label.get_lifetime_type () != AST::Lifetime::LifetimeType::NAMED) { rust_error_at (label.get_locus (), "Labels must be a named lifetime value"); return; } NodeId resolved_node = UNKNOWN_NODEID; if (!resolver->get_label_scope ().lookup ( CanonicalPath::new_seg (label.get_node_id (), label.get_lifetime_name ()), &resolved_node)) { rust_error_at (expr.get_label ().get_locus (), "failed to resolve label"); return; } resolver->insert_resolved_label (label.get_node_id (), resolved_node); } } void ResolveExpr::visit (AST::BorrowExpr &expr) { ResolveExpr::go (expr.get_borrowed_expr ().get (), prefix, canonical_prefix); } void ResolveExpr::visit (AST::DereferenceExpr &expr) { ResolveExpr::go (expr.get_dereferenced_expr ().get (), prefix, canonical_prefix); } void ResolveExpr::visit (AST::MatchExpr &expr) { ResolveExpr::go (expr.get_scrutinee_expr ().get (), prefix, canonical_prefix); for (auto &match_case : expr.get_match_cases ()) { // each arm is in its own scope NodeId scope_node_id = match_case.get_node_id (); resolver->get_name_scope ().push (scope_node_id); resolver->get_type_scope ().push (scope_node_id); resolver->get_label_scope ().push (scope_node_id); resolver->push_new_name_rib (resolver->get_name_scope ().peek ()); resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); resolver->push_new_label_rib (resolver->get_type_scope ().peek ()); // resolve AST::MatchArm &arm = match_case.get_arm (); if (arm.has_match_arm_guard ()) ResolveExpr::go (arm.get_guard_expr ().get (), prefix, canonical_prefix); // insert any possible new patterns for (auto &pattern : arm.get_patterns ()) { PatternDeclaration::go (pattern.get (), Rib::ItemType::Var); } // resolve the body ResolveExpr::go (match_case.get_expr ().get (), prefix, canonical_prefix); // done resolver->get_name_scope ().pop (); resolver->get_type_scope ().pop (); resolver->get_label_scope ().pop (); } } void ResolveExpr::visit (AST::RangeFromToExpr &expr) { ResolveExpr::go (expr.get_from_expr ().get (), prefix, canonical_prefix); ResolveExpr::go (expr.get_to_expr ().get (), prefix, canonical_prefix); } void ResolveExpr::visit (AST::RangeFromExpr &expr) { ResolveExpr::go (expr.get_from_expr ().get (), prefix, canonical_prefix); } void ResolveExpr::visit (AST::RangeToExpr &expr) { ResolveExpr::go (expr.get_to_expr ().get (), prefix, canonical_prefix); } void ResolveExpr::visit (AST::RangeFullExpr &) { // nothing to do } void ResolveExpr::visit (AST::RangeFromToInclExpr &expr) { ResolveExpr::go (expr.get_from_expr ().get (), prefix, canonical_prefix); ResolveExpr::go (expr.get_to_expr ().get (), prefix, canonical_prefix); } void ResolveExpr::visit (AST::ClosureExprInner &expr) { NodeId scope_node_id = expr.get_node_id (); resolver->get_name_scope ().push (scope_node_id); resolver->get_type_scope ().push (scope_node_id); resolver->get_label_scope ().push (scope_node_id); resolver->push_new_name_rib (resolver->get_name_scope ().peek ()); resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); resolver->push_new_label_rib (resolver->get_type_scope ().peek ()); for (auto &p : expr.get_params ()) { resolve_closure_param (p); } resolver->push_closure_context (expr.get_node_id ()); ResolveExpr::go (expr.get_definition_expr ().get (), prefix, canonical_prefix); resolver->pop_closure_context (); resolver->get_name_scope ().pop (); resolver->get_type_scope ().pop (); resolver->get_label_scope ().pop (); } void ResolveExpr::visit (AST::ClosureExprInnerTyped &expr) { NodeId scope_node_id = expr.get_node_id (); resolver->get_name_scope ().push (scope_node_id); resolver->get_type_scope ().push (scope_node_id); resolver->get_label_scope ().push (scope_node_id); resolver->push_new_name_rib (resolver->get_name_scope ().peek ()); resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); resolver->push_new_label_rib (resolver->get_type_scope ().peek ()); for (auto &p : expr.get_params ()) { resolve_closure_param (p); } ResolveType::go (expr.get_return_type ().get ()); resolver->push_closure_context (expr.get_node_id ()); ResolveExpr::go (expr.get_definition_block ().get (), prefix, canonical_prefix); resolver->pop_closure_context (); resolver->get_name_scope ().pop (); resolver->get_type_scope ().pop (); resolver->get_label_scope ().pop (); } void ResolveExpr::resolve_closure_param (AST::ClosureParam ¶m) { PatternDeclaration::go (param.get_pattern ().get (), Rib::ItemType::Param); if (param.has_type_given ()) ResolveType::go (param.get_type ().get ()); } ResolveExpr::ResolveExpr (const CanonicalPath &prefix, const CanonicalPath &canonical_prefix) : ResolverBase (), prefix (prefix), canonical_prefix (canonical_prefix) {} } // namespace Resolver } // namespace Rust