// Copyright (C) 2020-2021 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-lower.h" #include "rust-ast-lower-item.h" #include "rust-ast-lower-implitem.h" #include "rust-ast-lower-expr.h" #include "rust-ast-lower-block.h" #include "rust-ast-lower-type.h" namespace Rust { namespace HIR { ASTLowering::ASTLowering (AST::Crate &astCrate) : astCrate (astCrate) {} ASTLowering::~ASTLowering () {} HIR::Crate ASTLowering::Resolve (AST::Crate &astCrate) { ASTLowering resolver (astCrate); return resolver.go (); } HIR::Crate ASTLowering::go () { std::vector > items; for (auto it = astCrate.items.begin (); it != astCrate.items.end (); it++) { auto translated = ASTLoweringItem::translate (it->get ()); if (translated != nullptr) items.push_back (std::unique_ptr (translated)); } auto mappings = Analysis::Mappings::get (); auto crate_num = mappings->get_current_crate (); Analysis::NodeMapping mapping (crate_num, UNKNOWN_NODEID, mappings->get_next_hir_id (crate_num), UNKNOWN_LOCAL_DEFID); return HIR::Crate (std::move (items), astCrate.get_inner_attrs (), mapping); } // rust-ast-lower-block.h void ASTLoweringBlock::visit (AST::BlockExpr &expr) { std::vector > block_stmts; bool block_did_terminate = false; for (auto &s : expr.get_statements ()) { if (block_did_terminate) rust_warning_at (s->get_locus (), 0, "unreachable statement"); bool terminated = false; auto translated_stmt = ASTLoweringStmt::translate (s.get (), &terminated); block_stmts.push_back (std::unique_ptr (translated_stmt)); block_did_terminate |= terminated; } if (expr.has_tail_expr () && block_did_terminate) { // warning unreachable tail expressions rust_warning_at (expr.get_tail_expr ()->get_locus (), 0, "unreachable expression"); } HIR::ExprWithoutBlock *tail_expr = nullptr; if (expr.has_tail_expr ()) { bool terminated = false; tail_expr = (HIR::ExprWithoutBlock *) ASTLoweringExpr::translate (expr.get_tail_expr ().get (), &terminated); block_did_terminate |= terminated; } bool tail_reachable = !block_did_terminate; auto crate_num = mappings->get_current_crate (); Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), mappings->get_next_hir_id (crate_num), UNKNOWN_LOCAL_DEFID); translated = new HIR::BlockExpr (mapping, std::move (block_stmts), std::unique_ptr (tail_expr), tail_reachable, expr.get_inner_attrs (), expr.get_outer_attrs (), expr.get_locus ()); terminated = block_did_terminate; } void ASTLoweringIfBlock::visit (AST::IfExpr &expr) { bool ignored_terminated = false; HIR::Expr *condition = ASTLoweringExpr::translate (expr.get_condition_expr ().get (), &ignored_terminated); HIR::BlockExpr *block = ASTLoweringBlock::translate (expr.get_if_block ().get (), &ignored_terminated); auto crate_num = mappings->get_current_crate (); Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), mappings->get_next_hir_id (crate_num), UNKNOWN_LOCAL_DEFID); translated = new HIR::IfExpr (mapping, std::unique_ptr (condition), std::unique_ptr (block), expr.get_locus ()); } void ASTLoweringIfBlock::visit (AST::IfExprConseqElse &expr) { HIR::Expr *condition = ASTLoweringExpr::translate (expr.get_condition_expr ().get ()); bool if_block_terminated = false; bool else_block_termianted = false; HIR::BlockExpr *if_block = ASTLoweringBlock::translate (expr.get_if_block ().get (), &if_block_terminated); HIR::BlockExpr *else_block = ASTLoweringBlock::translate (expr.get_else_block ().get (), &else_block_termianted); terminated = if_block_terminated && else_block_termianted; auto crate_num = mappings->get_current_crate (); Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), mappings->get_next_hir_id (crate_num), UNKNOWN_LOCAL_DEFID); translated = new HIR::IfExprConseqElse (mapping, std::unique_ptr (condition), std::unique_ptr (if_block), std::unique_ptr (else_block), expr.get_locus ()); } void ASTLoweringIfBlock::visit (AST::IfExprConseqIf &expr) { HIR::Expr *condition = ASTLoweringExpr::translate (expr.get_condition_expr ().get ()); bool ignored_terminated = false; HIR::BlockExpr *block = ASTLoweringBlock::translate (expr.get_if_block ().get (), &ignored_terminated); HIR::IfExpr *conseq_if_expr = ASTLoweringIfBlock::translate (expr.get_conseq_if_expr ().get (), &ignored_terminated); auto crate_num = mappings->get_current_crate (); Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), mappings->get_next_hir_id (crate_num), UNKNOWN_LOCAL_DEFID); translated = new HIR::IfExprConseqIf (mapping, std::unique_ptr (condition), std::unique_ptr (block), std::unique_ptr (conseq_if_expr), expr.get_locus ()); } // rust-ast-lower-struct-field-expr.h void ASTLowerStructExprField::visit (AST::StructExprFieldIdentifierValue &field) { HIR::Expr *value = ASTLoweringExpr::translate (field.get_value ().get ()); auto crate_num = mappings->get_current_crate (); Analysis::NodeMapping mapping (crate_num, field.get_node_id (), mappings->get_next_hir_id (crate_num), UNKNOWN_LOCAL_DEFID); translated = new HIR::StructExprFieldIdentifierValue ( mapping, field.get_field_name (), std::unique_ptr (value), field.get_locus ()); } void ASTLowerStructExprField::visit (AST::StructExprFieldIndexValue &field) { HIR::Expr *value = ASTLoweringExpr::translate (field.get_value ().get ()); auto crate_num = mappings->get_current_crate (); Analysis::NodeMapping mapping (crate_num, field.get_node_id (), mappings->get_next_hir_id (crate_num), UNKNOWN_LOCAL_DEFID); translated = new HIR::StructExprFieldIndexValue (mapping, field.get_index (), std::unique_ptr (value), field.get_locus ()); } void ASTLowerStructExprField::visit (AST::StructExprFieldIdentifier &field) { auto crate_num = mappings->get_current_crate (); Analysis::NodeMapping mapping (crate_num, field.get_node_id (), mappings->get_next_hir_id (crate_num), UNKNOWN_LOCAL_DEFID); translated = new HIR::StructExprFieldIdentifier (mapping, field.get_field_name (), field.get_locus ()); } // rust-ast-lower-block.h void ASTLoweringExprWithBlock::visit (AST::WhileLoopExpr &expr) { HIR::BlockExpr *loop_block = ASTLoweringBlock::translate (expr.get_loop_block ().get (), &terminated); HIR::LoopLabel loop_label = lower_loop_label (expr.get_loop_label ()); HIR::Expr *loop_condition = ASTLoweringExpr::translate (expr.get_predicate_expr ().get (), &terminated); auto crate_num = mappings->get_current_crate (); Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), mappings->get_next_hir_id (crate_num), UNKNOWN_LOCAL_DEFID); translated = new HIR::WhileLoopExpr (mapping, std::unique_ptr (loop_condition), std::unique_ptr (loop_block), expr.get_locus (), std::move (loop_label), expr.get_outer_attrs ()); } // rust-ast-lower-expr.h void ASTLowerPathInExpression::visit (AST::PathInExpression &expr) { std::vector path_segments; expr.iterate_path_segments ([&] (AST::PathExprSegment &s) mutable -> bool { path_segments.push_back (lower_path_expr_seg (s)); // insert the mappings for the segment HIR::PathExprSegment *lowered_seg = &path_segments.back (); mappings->insert_hir_path_expr_seg ( lowered_seg->get_mappings ().get_crate_num (), lowered_seg->get_mappings ().get_hirid (), lowered_seg); return true; }); auto crate_num = mappings->get_current_crate (); Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), mappings->get_next_hir_id (crate_num), UNKNOWN_LOCAL_DEFID); translated = new HIR::PathInExpression (mapping, std::move (path_segments), expr.get_locus (), expr.opening_scope_resolution ()); } HIR::QualifiedPathType ASTLoweringBase::lower_qual_path_type (AST::QualifiedPathType &qualified_type) { HIR::Type *type = ASTLoweringType::translate (qualified_type.get_type ().get ()); HIR::TypePath *trait = qualified_type.has_as_clause () ? ASTLowerTypePath::translate (qualified_type.get_as_type_path ()) : nullptr; auto crate_num = mappings->get_current_crate (); Analysis::NodeMapping mapping (crate_num, qualified_type.get_node_id (), mappings->get_next_hir_id (crate_num), UNKNOWN_LOCAL_DEFID); return HIR::QualifiedPathType (mapping, std::unique_ptr (type), std::unique_ptr (trait), qualified_type.get_locus ()); } void ASTLowerQualPathInExpression::visit (AST::QualifiedPathInExpression &expr) { HIR::QualifiedPathType qual_path_type = lower_qual_path_type (expr.get_qualified_path_type ()); std::vector path_segments; expr.iterate_path_segments ([&] (AST::PathExprSegment &s) mutable -> bool { path_segments.push_back (lower_path_expr_seg (s)); // insert the mappings for the segment HIR::PathExprSegment *lowered_seg = &path_segments.back (); mappings->insert_hir_path_expr_seg ( lowered_seg->get_mappings ().get_crate_num (), lowered_seg->get_mappings ().get_hirid (), lowered_seg); return true; }); auto crate_num = mappings->get_current_crate (); Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), mappings->get_next_hir_id (crate_num), UNKNOWN_LOCAL_DEFID); translated = new HIR::QualifiedPathInExpression (mapping, qual_path_type, std::move (path_segments), expr.get_locus (), expr.get_outer_attrs ()); } // rust-ast-lower-base.h std::vector > ASTLoweringBase::lower_generic_params ( std::vector > ¶ms) { std::vector > lowered; for (auto &ast_param : params) { auto hir_param = ASTLowerGenericParam::translate (ast_param.get ()); lowered.push_back (std::unique_ptr (hir_param)); } return lowered; } HIR::PathExprSegment ASTLoweringBase::lower_path_expr_seg (AST::PathExprSegment &s) { auto crate_num = mappings->get_current_crate (); Analysis::NodeMapping mapping (crate_num, s.get_node_id (), mappings->get_next_hir_id (crate_num), UNKNOWN_LOCAL_DEFID); return HIR::PathExprSegment ( std::move (mapping), HIR::PathIdentSegment (s.get_ident_segment ().as_string ()), s.get_locus (), s.has_generic_args () ? lower_generic_args (s.get_generic_args ()) : HIR::GenericArgs::create_empty ()); } HIR::GenericArgsBinding ASTLoweringBase::lower_binding (AST::GenericArgsBinding &binding) { HIR::Type *lowered_type = ASTLoweringType::translate (binding.get_type ().get ()); return HIR::GenericArgsBinding (binding.get_identifier (), std::unique_ptr (lowered_type), binding.get_locus ()); } HIR::GenericArgs ASTLoweringBase::lower_generic_args (AST::GenericArgs &args) { std::vector binding_args; for (auto &binding : args.get_binding_args ()) { HIR::GenericArgsBinding b = lower_binding (binding); binding_args.push_back (std::move (b)); } std::vector lifetime_args; for (auto &lifetime : args.get_lifetime_args ()) { HIR::Lifetime l = lower_lifetime (lifetime); lifetime_args.push_back (std::move (l)); } std::vector > type_args; for (auto &type : args.get_type_args ()) { HIR::Type *t = ASTLoweringType::translate (type.get ()); type_args.push_back (std::unique_ptr (t)); } return HIR::GenericArgs (std::move (lifetime_args), std::move (type_args), std::move (binding_args), args.get_locus ()); } HIR::SelfParam ASTLoweringBase::lower_self (AST::SelfParam &self) { auto crate_num = mappings->get_current_crate (); Analysis::NodeMapping mapping (crate_num, self.get_node_id (), mappings->get_next_hir_id (crate_num), mappings->get_next_localdef_id (crate_num)); if (self.has_type ()) { HIR::Type *type = ASTLoweringType::translate (self.get_type ().get ()); return HIR::SelfParam (mapping, std::unique_ptr (type), self.get_is_mut (), self.get_locus ()); } else if (!self.get_has_ref ()) { return HIR::SelfParam (mapping, std::unique_ptr (nullptr), self.get_is_mut (), self.get_locus ()); } AST::Lifetime l = self.get_lifetime (); return HIR::SelfParam (mapping, lower_lifetime (l), self.get_is_mut (), self.get_locus ()); } void ASTLowerTypePath::visit (AST::TypePathSegmentGeneric &segment) { std::vector binding_args; // TODO std::string segment_name = segment.get_ident_segment ().as_string (); bool has_separating_scope_resolution = segment.get_separating_scope_resolution (); std::vector lifetime_args; for (auto &lifetime : segment.get_generic_args ().get_lifetime_args ()) { HIR::Lifetime l = lower_lifetime (lifetime); lifetime_args.push_back (std::move (l)); } std::vector > type_args; for (auto &type : segment.get_generic_args ().get_type_args ()) { HIR::Type *t = ASTLoweringType::translate (type.get ()); type_args.push_back (std::unique_ptr (t)); } auto crate_num = mappings->get_current_crate (); auto hirid = mappings->get_next_hir_id (crate_num); Analysis::NodeMapping mapping (crate_num, segment.get_node_id (), hirid, UNKNOWN_LOCAL_DEFID); translated_segment = new HIR::TypePathSegmentGeneric ( std::move (mapping), segment_name, has_separating_scope_resolution, std::move (lifetime_args), std::move (type_args), std::move (binding_args), segment.get_locus ()); } void ASTLowerQualifiedPathInType::visit (AST::QualifiedPathInType &path) { auto crate_num = mappings->get_current_crate (); auto hirid = mappings->get_next_hir_id (crate_num); Analysis::NodeMapping qual_mappings ( crate_num, path.get_qualified_path_type ().get_node_id (), hirid, UNKNOWN_LOCAL_DEFID); HIR::Type *qual_type = ASTLoweringType::translate ( path.get_qualified_path_type ().get_type ().get ()); HIR::TypePath *qual_trait = ASTLowerTypePath::translate ( path.get_qualified_path_type ().get_as_type_path ()); HIR::QualifiedPathType qual_path_type ( qual_mappings, std::unique_ptr (qual_type), std::unique_ptr (qual_trait), path.get_qualified_path_type ().get_locus ()); translated_segment = nullptr; path.get_associated_segment ()->accept_vis (*this); if (translated_segment == nullptr) { rust_fatal_error (path.get_associated_segment ()->get_locus (), "failed to translate AST TypePathSegment"); return; } std::unique_ptr associated_segment (translated_segment); std::vector > translated_segments; for (auto &seg : path.get_segments ()) { translated_segment = nullptr; seg->accept_vis (*this); if (translated_segment == nullptr) { rust_fatal_error (seg->get_locus (), "failed to translte AST TypePathSegment"); } translated_segments.push_back ( std::unique_ptr (translated_segment)); } Analysis::NodeMapping mapping (crate_num, path.get_node_id (), hirid, mappings->get_next_localdef_id (crate_num)); translated = new HIR::QualifiedPathInType (std::move (mapping), std::move (qual_path_type), std::move (associated_segment), std::move (translated_segments), path.get_locus ()); mappings->insert_hir_type (crate_num, hirid, translated); } void ASTLoweringType::visit (AST::TraitObjectTypeOneBound &type) { std::vector > bounds; HIR::TypeParamBound *translated_bound = ASTLoweringTypeBounds::translate (&type.get_trait_bound ()); bounds.push_back (std::unique_ptr (translated_bound)); auto crate_num = mappings->get_current_crate (); Analysis::NodeMapping mapping (crate_num, type.get_node_id (), mappings->get_next_hir_id (crate_num), mappings->get_next_localdef_id (crate_num)); translated = new HIR::TraitObjectType (mapping, std::move (bounds), type.get_locus (), type.is_dyn ()); mappings->insert_hir_type (mapping.get_crate_num (), mapping.get_hirid (), translated); } void ASTLoweringType::visit (AST::TraitObjectType &type) { std::vector > bounds; for (auto &bound : type.get_type_param_bounds ()) { HIR::TypeParamBound *translated_bound = ASTLoweringTypeBounds::translate (bound.get ()); bounds.push_back ( std::unique_ptr (translated_bound)); } auto crate_num = mappings->get_current_crate (); Analysis::NodeMapping mapping (crate_num, type.get_node_id (), mappings->get_next_hir_id (crate_num), mappings->get_next_localdef_id (crate_num)); translated = new HIR::TraitObjectType (mapping, std::move (bounds), type.get_locus (), type.is_dyn ()); mappings->insert_hir_type (mapping.get_crate_num (), mapping.get_hirid (), translated); } // rust-ast-lower-base HIR::Type * ASTLoweringBase::lower_type_no_bounds (AST::TypeNoBounds *type) { return ASTLoweringType::translate (type); } HIR::TypeParamBound * ASTLoweringBase::lower_bound (AST::TypeParamBound *bound) { return ASTLoweringTypeBounds::translate (bound); } /* Checks whether the name of a field already exists. Returns true and produces an error if so. */ bool struct_field_name_exists (std::vector &fields, HIR::StructField &new_field) { for (auto &field : fields) { if (field.get_field_name ().compare (new_field.get_field_name ()) == 0) { RichLocation r (new_field.get_locus ()); r.add_range (field.get_locus ()); rust_error_at (r, "duplicate field name %qs", field.get_field_name ().c_str ()); return true; } } return false; } } // namespace HIR } // namespace Rust