// 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
// <http://www.gnu.org/licenses/>.
#include "rust-ast-lower-base.h"
#include "rust-ast-lower-type.h"
#include "rust-ast-lower-pattern.h"
#include "rust-ast-lower-extern.h"
namespace Rust {
namespace HIR {
void
ASTLoweringBase::visit (AST::Token &)
{}
void
ASTLoweringBase::visit (AST::DelimTokenTree &)
{}
void
ASTLoweringBase::visit (AST::AttrInputMetaItemContainer &)
{}
//  void ASTLoweringBase::visit(MetaItemmeta_item) {}
//  void vsit(Stmtstmt) {}
//  void ASTLoweringBase::visit(Exprexpr) {}
void
ASTLoweringBase::visit (AST::IdentifierExpr &)
{}
//  void ASTLoweringBase::visit(Patternpattern) {}
//  void ASTLoweringBase::visit(Typetype) {}
//  void ASTLoweringBase::visit(TypeParamBoundtype_param_bound) {}
void
ASTLoweringBase::visit (AST::Lifetime &)
{}
//  void ASTLoweringBase::visit(GenericParamgeneric_param) {}
void
ASTLoweringBase::visit (AST::LifetimeParam &)
{}
void
ASTLoweringBase::visit (AST::ConstGenericParam &)
{}
//  void ASTLoweringBase::visit(TraitItemtrait_item) {}
//  void ASTLoweringBase::visit(InherentImplIteminherent_impl_item) {}
//  void ASTLoweringBase::visit(TraitImplItemtrait_impl_item) {}
// rust-path.h
void
ASTLoweringBase::visit (AST::PathInExpression &)
{}
void
ASTLoweringBase::visit (AST::TypePathSegment &)
{}
void
ASTLoweringBase::visit (AST::TypePathSegmentGeneric &)
{}
void
ASTLoweringBase::visit (AST::TypePathSegmentFunction &)
{}
void
ASTLoweringBase::visit (AST::TypePath &)
{}
void
ASTLoweringBase::visit (AST::QualifiedPathInExpression &)
{}
void
ASTLoweringBase::visit (AST::QualifiedPathInType &)
{}
// rust-expr.h
void
ASTLoweringBase::visit (AST::LiteralExpr &)
{}
void
ASTLoweringBase::visit (AST::AttrInputLiteral &)
{}
void
ASTLoweringBase::visit (AST::MetaItemLitExpr &)
{}
void
ASTLoweringBase::visit (AST::MetaItemPathLit &)
{}
void
ASTLoweringBase::visit (AST::BorrowExpr &)
{}
void
ASTLoweringBase::visit (AST::DereferenceExpr &)
{}
void
ASTLoweringBase::visit (AST::ErrorPropagationExpr &)
{}
void
ASTLoweringBase::visit (AST::NegationExpr &)
{}
void
ASTLoweringBase::visit (AST::ArithmeticOrLogicalExpr &)
{}
void
ASTLoweringBase::visit (AST::ComparisonExpr &)
{}
void
ASTLoweringBase::visit (AST::LazyBooleanExpr &)
{}
void
ASTLoweringBase::visit (AST::TypeCastExpr &)
{}
void
ASTLoweringBase::visit (AST::AssignmentExpr &)
{}
void
ASTLoweringBase::visit (AST::CompoundAssignmentExpr &)
{}
void
ASTLoweringBase::visit (AST::GroupedExpr &)
{}
//  void ASTLoweringBase::visit(ArrayElemselems) {}
void
ASTLoweringBase::visit (AST::ArrayElemsValues &)
{}
void
ASTLoweringBase::visit (AST::ArrayElemsCopied &)
{}
void
ASTLoweringBase::visit (AST::ArrayExpr &)
{}
void
ASTLoweringBase::visit (AST::ArrayIndexExpr &)
{}
void
ASTLoweringBase::visit (AST::TupleExpr &)
{}
void
ASTLoweringBase::visit (AST::TupleIndexExpr &)
{}
void
ASTLoweringBase::visit (AST::StructExprStruct &)
{}
//  void ASTLoweringBase::visit(StructExprFieldfield) {}
void
ASTLoweringBase::visit (AST::StructExprFieldIdentifier &)
{}
void
ASTLoweringBase::visit (AST::StructExprFieldIdentifierValue &)
{}
void
ASTLoweringBase::visit (AST::StructExprFieldIndexValue &)
{}
void
ASTLoweringBase::visit (AST::StructExprStructFields &)
{}
void
ASTLoweringBase::visit (AST::StructExprStructBase &)
{}
void
ASTLoweringBase::visit (AST::CallExpr &)
{}
void
ASTLoweringBase::visit (AST::MethodCallExpr &)
{}
void
ASTLoweringBase::visit (AST::FieldAccessExpr &)
{}
void
ASTLoweringBase::visit (AST::ClosureExprInner &)
{}
void
ASTLoweringBase::visit (AST::BlockExpr &)
{}
void
ASTLoweringBase::visit (AST::ClosureExprInnerTyped &)
{}
void
ASTLoweringBase::visit (AST::ContinueExpr &)
{}
void
ASTLoweringBase::visit (AST::BreakExpr &)
{}
void
ASTLoweringBase::visit (AST::RangeFromToExpr &)
{}
void
ASTLoweringBase::visit (AST::RangeFromExpr &)
{}
void
ASTLoweringBase::visit (AST::RangeToExpr &)
{}
void
ASTLoweringBase::visit (AST::RangeFullExpr &)
{}
void
ASTLoweringBase::visit (AST::RangeFromToInclExpr &)
{}
void
ASTLoweringBase::visit (AST::RangeToInclExpr &)
{}
void
ASTLoweringBase::visit (AST::ReturnExpr &)
{}
void
ASTLoweringBase::visit (AST::UnsafeBlockExpr &)
{}
void
ASTLoweringBase::visit (AST::LoopExpr &)
{}
void
ASTLoweringBase::visit (AST::WhileLoopExpr &)
{}
void
ASTLoweringBase::visit (AST::WhileLetLoopExpr &)
{}
void
ASTLoweringBase::visit (AST::ForLoopExpr &)
{}
void
ASTLoweringBase::visit (AST::IfExpr &)
{}
void
ASTLoweringBase::visit (AST::IfExprConseqElse &)
{}
void
ASTLoweringBase::visit (AST::IfExprConseqIf &)
{}
void
ASTLoweringBase::visit (AST::IfExprConseqIfLet &)
{}
void
ASTLoweringBase::visit (AST::IfLetExpr &)
{}
void
ASTLoweringBase::visit (AST::IfLetExprConseqElse &)
{}
void
ASTLoweringBase::visit (AST::IfLetExprConseqIf &)
{}
void
ASTLoweringBase::visit (AST::IfLetExprConseqIfLet &)
{}
//  void ASTLoweringBase::visit(MatchCasematch_case) {}
// void ASTLoweringBase:: (AST::MatchCaseBlockExpr &) {}
// void ASTLoweringBase:: (AST::MatchCaseExpr &) {}
void
ASTLoweringBase::visit (AST::MatchExpr &)
{}
void
ASTLoweringBase::visit (AST::AwaitExpr &)
{}
void
ASTLoweringBase::visit (AST::AsyncBlockExpr &)
{}
// rust-item.h
void
ASTLoweringBase::visit (AST::TypeParam &)
{}
//  void ASTLoweringBase::visit(WhereClauseItemitem) {}
void
ASTLoweringBase::visit (AST::LifetimeWhereClauseItem &)
{}
void
ASTLoweringBase::visit (AST::TypeBoundWhereClauseItem &)
{}
void
ASTLoweringBase::visit (AST::Method &)
{}
void
ASTLoweringBase::visit (AST::Module &)
{}
void
ASTLoweringBase::visit (AST::ExternCrate &)
{}
//  void ASTLoweringBase::visit(UseTreeuse_tree) {}
void
ASTLoweringBase::visit (AST::UseTreeGlob &)
{}
void
ASTLoweringBase::visit (AST::UseTreeList &)
{}
void
ASTLoweringBase::visit (AST::UseTreeRebind &)
{}
void
ASTLoweringBase::visit (AST::UseDeclaration &)
{}
void
ASTLoweringBase::visit (AST::Function &)
{}
void
ASTLoweringBase::visit (AST::TypeAlias &)
{}
void
ASTLoweringBase::visit (AST::StructStruct &)
{}
void
ASTLoweringBase::visit (AST::TupleStruct &)
{}
void
ASTLoweringBase::visit (AST::EnumItem &)
{}
void
ASTLoweringBase::visit (AST::EnumItemTuple &)
{}
void
ASTLoweringBase::visit (AST::EnumItemStruct &)
{}
void
ASTLoweringBase::visit (AST::EnumItemDiscriminant &)
{}
void
ASTLoweringBase::visit (AST::Enum &)
{}
void
ASTLoweringBase::visit (AST::Union &)
{}
void
ASTLoweringBase::visit (AST::ConstantItem &)
{}
void
ASTLoweringBase::visit (AST::StaticItem &)
{}
void
ASTLoweringBase::visit (AST::TraitItemFunc &)
{}
void
ASTLoweringBase::visit (AST::TraitItemMethod &)
{}
void
ASTLoweringBase::visit (AST::TraitItemConst &)
{}
void
ASTLoweringBase::visit (AST::TraitItemType &)
{}
void
ASTLoweringBase::visit (AST::Trait &)
{}
void
ASTLoweringBase::visit (AST::InherentImpl &)
{}
void
ASTLoweringBase::visit (AST::TraitImpl &)
{}
//  void ASTLoweringBase::visit(ExternalItemitem) {}
void
ASTLoweringBase::visit (AST::ExternalStaticItem &)
{}
void
ASTLoweringBase::visit (AST::ExternalFunctionItem &)
{}
void
ASTLoweringBase::visit (AST::ExternBlock &)
{}
// rust-macro.h
void
ASTLoweringBase::visit (AST::MacroMatchFragment &)
{}
void
ASTLoweringBase::visit (AST::MacroMatchRepetition &)
{}
void
ASTLoweringBase::visit (AST::MacroMatcher &)
{}
void
ASTLoweringBase::visit (AST::MacroRulesDefinition &)
{}
void
ASTLoweringBase::visit (AST::MacroInvocation &)
{}
void
ASTLoweringBase::visit (AST::MetaItemPath &)
{}
void
ASTLoweringBase::visit (AST::MetaItemSeq &)
{}
void
ASTLoweringBase::visit (AST::MetaWord &)
{}
void
ASTLoweringBase::visit (AST::MetaNameValueStr &)
{}
void
ASTLoweringBase::visit (AST::MetaListPaths &)
{}
void
ASTLoweringBase::visit (AST::MetaListNameValueStr &)
{}
// rust-pattern.h
void
ASTLoweringBase::visit (AST::LiteralPattern &)
{}
void
ASTLoweringBase::visit (AST::IdentifierPattern &)
{}
void
ASTLoweringBase::visit (AST::WildcardPattern &)
{}
//  void ASTLoweringBase::visit(RangePatternBoundbound) {}
void
ASTLoweringBase::visit (AST::RangePatternBoundLiteral &)
{}
void
ASTLoweringBase::visit (AST::RangePatternBoundPath &)
{}
void
ASTLoweringBase::visit (AST::RangePatternBoundQualPath &)
{}
void
ASTLoweringBase::visit (AST::RangePattern &)
{}
void
ASTLoweringBase::visit (AST::ReferencePattern &)
{}
//  void ASTLoweringBase::visit(StructPatternFieldfield) {}
void
ASTLoweringBase::visit (AST::StructPatternFieldTuplePat &)
{}
void
ASTLoweringBase::visit (AST::StructPatternFieldIdentPat &)
{}
void
ASTLoweringBase::visit (AST::StructPatternFieldIdent &)
{}
void
ASTLoweringBase::visit (AST::StructPattern &)
{}
//  void ASTLoweringBase::visit(TupleStructItemstuple_items) {}
void
ASTLoweringBase::visit (AST::TupleStructItemsNoRange &)
{}
void
ASTLoweringBase::visit (AST::TupleStructItemsRange &)
{}
void
ASTLoweringBase::visit (AST::TupleStructPattern &)
{}
//  void ASTLoweringBase::visit(TuplePatternItemstuple_items) {}
void
ASTLoweringBase::visit (AST::TuplePatternItemsMultiple &)
{}
void
ASTLoweringBase::visit (AST::TuplePatternItemsRanged &)
{}
void
ASTLoweringBase::visit (AST::TuplePattern &)
{}
void
ASTLoweringBase::visit (AST::GroupedPattern &)
{}
void
ASTLoweringBase::visit (AST::SlicePattern &)
{}
void
ASTLoweringBase::visit (AST::AltPattern &)
{}
// rust-stmt.h
void
ASTLoweringBase::visit (AST::EmptyStmt &)
{}
void
ASTLoweringBase::visit (AST::LetStmt &)
{}
void
ASTLoweringBase::visit (AST::ExprStmtWithoutBlock &)
{}
void
ASTLoweringBase::visit (AST::ExprStmtWithBlock &)
{}
// rust-type.h
void
ASTLoweringBase::visit (AST::TraitBound &)
{}
void
ASTLoweringBase::visit (AST::ImplTraitType &)
{}
void
ASTLoweringBase::visit (AST::TraitObjectType &)
{}
void
ASTLoweringBase::visit (AST::ParenthesisedType &)
{}
void
ASTLoweringBase::visit (AST::ImplTraitTypeOneBound &)
{}
void
ASTLoweringBase::visit (AST::TraitObjectTypeOneBound &)
{}
void
ASTLoweringBase::visit (AST::TupleType &)
{}
void
ASTLoweringBase::visit (AST::NeverType &)
{}
void
ASTLoweringBase::visit (AST::RawPointerType &)
{}
void
ASTLoweringBase::visit (AST::ReferenceType &)
{}
void
ASTLoweringBase::visit (AST::ArrayType &)
{}
void
ASTLoweringBase::visit (AST::SliceType &)
{}
void
ASTLoweringBase::visit (AST::InferredType &)
{}
void
ASTLoweringBase::visit (AST::BareFunctionType &)
{}
HIR::Lifetime
ASTLoweringBase::lower_lifetime (AST::Lifetime &lifetime)
{
  auto crate_num = mappings->get_current_crate ();
  Analysis::NodeMapping mapping (crate_num, lifetime.get_node_id (),
				 mappings->get_next_hir_id (crate_num),
				 UNKNOWN_LOCAL_DEFID);
  mappings->insert_node_to_hir (mapping.get_nodeid (), mapping.get_hirid ());
  return HIR::Lifetime (mapping, lifetime.get_lifetime_type (),
			lifetime.get_lifetime_name (), lifetime.get_locus ());
}
HIR::LoopLabel
ASTLoweringBase::lower_loop_label (AST::LoopLabel &loop_label)
{
  HIR::Lifetime life = lower_lifetime (loop_label.get_lifetime ());
  auto crate_num = mappings->get_current_crate ();
  Analysis::NodeMapping mapping (crate_num, loop_label.get_node_id (),
				 mappings->get_next_hir_id (crate_num),
				 UNKNOWN_LOCAL_DEFID);
  mappings->insert_node_to_hir (mapping.get_nodeid (), mapping.get_hirid ());
  return HIR::LoopLabel (mapping, std::move (life), loop_label.get_locus ());
}
std::vector<std::unique_ptr<HIR::GenericParam>>
ASTLoweringBase::lower_generic_params (
  std::vector<std::unique_ptr<AST::GenericParam>> ¶ms)
{
  std::vector<std::unique_ptr<HIR::GenericParam>> lowered;
  for (auto &ast_param : params)
    {
      auto hir_param = ASTLowerGenericParam::translate (ast_param.get ());
      lowered.push_back (std::unique_ptr<HIR::GenericParam> (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<HIR::Type> (lowered_type),
				  binding.get_locus ());
}
HIR::GenericArgs
ASTLoweringBase::lower_generic_args (AST::GenericArgs &args)
{
  std::vector<HIR::GenericArgsBinding> binding_args;
  for (auto &binding : args.get_binding_args ())
    {
      HIR::GenericArgsBinding b = lower_binding (binding);
      binding_args.push_back (std::move (b));
    }
  std::vector<HIR::Lifetime> lifetime_args;
  for (auto &lifetime : args.get_lifetime_args ())
    {
      HIR::Lifetime l = lower_lifetime (lifetime);
      lifetime_args.push_back (std::move (l));
    }
  std::vector<std::unique_ptr<HIR::Type>> type_args;
  std::vector<HIR::ConstGenericArg> const_args;
  for (auto &arg : args.get_generic_args ())
    {
      switch (arg.get_kind ())
	{
	  case AST::GenericArg::Kind::Type: {
	    auto type = ASTLoweringType::translate (arg.get_type ().get ());
	    type_args.emplace_back (std::unique_ptr<HIR::Type> (type));
	    break;
	  }
	  case AST::GenericArg::Kind::Const: {
	    auto expr
	      = ASTLoweringExpr::translate (arg.get_expression ().get ());
	    const_args.emplace_back (
	      HIR::ConstGenericArg (std::unique_ptr<HIR::Expr> (expr),
				    expr->get_locus ()));
	    break;
	  }
	default:
	  gcc_unreachable ();
	}
    }
  return HIR::GenericArgs (std::move (lifetime_args), std::move (type_args),
			   std::move (binding_args), std::move (const_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<HIR::Type> (type),
			     self.get_is_mut (), self.get_locus ());
    }
  else if (!self.get_has_ref ())
    {
      return HIR::SelfParam (mapping, std::unique_ptr<HIR::Type> (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 ());
}
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<HIR::StructField> &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;
}
HIR::FunctionQualifiers
ASTLoweringBase::lower_qualifiers (const AST::FunctionQualifiers &qualifiers)
{
  Unsafety unsafety
    = qualifiers.is_unsafe () ? Unsafety::Unsafe : Unsafety::Normal;
  bool has_extern = qualifiers.is_extern ();
  ABI abi = ABI::RUST;
  if (qualifiers.has_abi ())
    {
      const std::string &extern_abi = qualifiers.get_extern_abi ();
      abi = get_abi_from_string (extern_abi);
      if (has_extern && abi == ABI::UNKNOWN)
	rust_error_at (qualifiers.get_locus (), "unknown ABI option");
    }
  return HIR::FunctionQualifiers (qualifiers.get_const_status (), unsafety,
				  has_extern, abi);
}
void
ASTLoweringBase::handle_outer_attributes (const ItemWrapper &item)
{
  for (const auto &attr : item.get_outer_attrs ())
    {
      const auto &str_path = attr.get_path ().as_string ();
      if (!is_known_attribute (str_path))
	{
	  rust_error_at (attr.get_locus (), "unknown attribute");
	  continue;
	}
      bool is_lang_item = str_path.compare ("lang") == 0
			  && attr.has_attr_input ()
			  && attr.get_attr_input ().get_attr_input_type ()
			       == AST::AttrInput::AttrInputType::LITERAL;
      bool is_doc_item = str_path.compare ("doc") == 0;
      if (is_doc_item)
	handle_doc_item_attribute (item, attr);
      else if (is_lang_item)
	handle_lang_item_attribute (item, attr);
      else if (!attribute_handled_in_another_pass (str_path))
	{
	  rust_error_at (attr.get_locus (), "unhandled attribute: [%s]",
			 attr.get_path ().as_string ().c_str ());
	}
    }
}
void
ASTLoweringBase::handle_doc_item_attribute (const ItemWrapper &,
					    const AST::Attribute &attr)
{
  auto simple_doc_comment = attr.has_attr_input ()
			    && attr.get_attr_input ().get_attr_input_type ()
				 == AST::AttrInput::AttrInputType::LITERAL;
  if (simple_doc_comment)
    return;
  const AST::AttrInput &input = attr.get_attr_input ();
  bool is_token_tree
    = input.get_attr_input_type () == AST::AttrInput::AttrInputType::TOKEN_TREE;
  rust_assert (is_token_tree);
  const auto &option = static_cast<const AST::DelimTokenTree &> (input);
  AST::AttrInputMetaItemContainer *meta_item = option.parse_to_meta_item ();
  // TODO: add actual and complete checks for the doc attributes
  //
  // FIXME: Move this to the AttributeChecker visitor
  rust_assert (meta_item);
}
void
ASTLoweringBase::handle_lang_item_attribute (const ItemWrapper &item,
					     const AST::Attribute &attr)
{
  auto &literal = static_cast<AST::AttrInputLiteral &> (attr.get_attr_input ());
  const auto &lang_item_type_str = literal.get_literal ().as_string ();
  auto lang_item_type = Analysis::RustLangItem::Parse (lang_item_type_str);
  if (lang_item_type == Analysis::RustLangItem::ItemType::UNKNOWN)
    {
      rust_error_at (attr.get_locus (), "unknown lang item");
      return;
    }
  mappings->insert_lang_item (lang_item_type,
			      item.get_mappings ().get_defid ());
}
bool
ASTLoweringBase::is_known_attribute (const std::string &attribute_path) const
{
  const auto &lookup = attr_mappings->lookup_builtin (attribute_path);
  return !lookup.is_error ();
}
bool
ASTLoweringBase::attribute_handled_in_another_pass (
  const std::string &attribute_path) const
{
  const auto &lookup = attr_mappings->lookup_builtin (attribute_path);
  if (lookup.is_error ())
    return false;
  if (lookup.handler == Analysis::CompilerPass::UNKNOWN)
    return false;
  return lookup.handler != Analysis::CompilerPass::HIR_LOWERING;
}
std::unique_ptr<HIR::TuplePatternItems>
ASTLoweringBase::lower_tuple_pattern_multiple (
  AST::TuplePatternItemsMultiple &pattern)
{
  std::vector<std::unique_ptr<HIR::Pattern>> patterns;
  for (auto &p : pattern.get_patterns ())
    {
      HIR::Pattern *translated = ASTLoweringPattern::translate (p.get ());
      patterns.push_back (std::unique_ptr<HIR::Pattern> (translated));
    }
  return std::unique_ptr<HIR::TuplePatternItems> (
    new HIR::TuplePatternItemsMultiple (std::move (patterns)));
}
std::unique_ptr<TuplePatternItems>
ASTLoweringBase::lower_tuple_pattern_ranged (
  AST::TuplePatternItemsRanged &pattern)
{
  std::vector<std::unique_ptr<HIR::Pattern>> lower_patterns;
  std::vector<std::unique_ptr<HIR::Pattern>> upper_patterns;
  for (auto &p : pattern.get_lower_patterns ())
    {
      HIR::Pattern *translated = ASTLoweringPattern::translate (p.get ());
      lower_patterns.push_back (std::unique_ptr<HIR::Pattern> (translated));
    }
  for (auto &p : pattern.get_upper_patterns ())
    {
      HIR::Pattern *translated = ASTLoweringPattern::translate (p.get ());
      upper_patterns.push_back (std::unique_ptr<HIR::Pattern> (translated));
    }
  return std::unique_ptr<HIR::TuplePatternItems> (
    new HIR::TuplePatternItemsRanged (std::move (lower_patterns),
				      std::move (upper_patterns)));
}
std::unique_ptr<HIR::RangePatternBound>
ASTLoweringBase::lower_range_pattern_bound (AST::RangePatternBound *bound)
{
  std::unique_ptr<HIR::RangePatternBound> hir_bound = nullptr;
  switch (bound->get_bound_type ())
    {
      case AST::RangePatternBound::RangePatternBoundType::LITERAL: {
	AST::RangePatternBoundLiteral &ref
	  = *static_cast<AST::RangePatternBoundLiteral *> (bound);
	HIR::Literal literal = lower_literal (ref.get_literal ());
	hir_bound = std::unique_ptr<HIR::RangePatternBound> (
	  new HIR::RangePatternBoundLiteral (literal, ref.get_locus (),
					     ref.get_has_minus ()));
      }
      break;
      case AST::RangePatternBound::RangePatternBoundType::PATH: {
	AST::RangePatternBoundPath &ref
	  = *static_cast<AST::RangePatternBoundPath *> (bound);
	HIR::PathInExpression *path
	  = ASTLowerPathInExpression::translate (&ref.get_path ());
	hir_bound = std::unique_ptr<HIR::RangePatternBound> (
	  new HIR::RangePatternBoundPath (*path));
      }
      break;
      case AST::RangePatternBound::RangePatternBoundType::QUALPATH: {
	AST::RangePatternBoundQualPath &ref
	  = *static_cast<AST::RangePatternBoundQualPath *> (bound);
	HIR::QualifiedPathInExpression *qualpath
	  = ASTLowerQualPathInExpression::translate (
	    &ref.get_qualified_path ());
	hir_bound = std::unique_ptr<HIR::RangePatternBound> (
	  new HIR::RangePatternBoundQualPath (*qualpath));
      }
      break;
    }
  return hir_bound;
}
HIR::Literal
ASTLoweringBase::lower_literal (const AST::Literal &literal)
{
  HIR::Literal::LitType type = HIR::Literal::LitType::CHAR;
  switch (literal.get_lit_type ())
    {
    case AST::Literal::LitType::CHAR:
      type = HIR::Literal::LitType::CHAR;
      break;
    case AST::Literal::LitType::STRING:
      type = HIR::Literal::LitType::STRING;
      break;
    case AST::Literal::LitType::BYTE:
      type = HIR::Literal::LitType::BYTE;
      break;
    case AST::Literal::LitType::BYTE_STRING:
      type = HIR::Literal::LitType::BYTE_STRING;
      break;
    case AST::Literal::LitType::INT:
      type = HIR::Literal::LitType::INT;
      break;
    case AST::Literal::LitType::FLOAT:
      type = HIR::Literal::LitType::FLOAT;
      break;
    case AST::Literal::LitType::BOOL:
      type = HIR::Literal::LitType::BOOL;
      break;
    case AST::Literal::LitType::ERROR:
      gcc_unreachable ();
      break;
    }
  return HIR::Literal (literal.as_string (), type, literal.get_type_hint ());
}
HIR::ExternBlock *
ASTLoweringBase::lower_extern_block (AST::ExternBlock &extern_block)
{
  HIR::Visibility vis = translate_visibility (extern_block.get_visibility ());
  auto crate_num = mappings->get_current_crate ();
  Analysis::NodeMapping mapping (crate_num, extern_block.get_node_id (),
				 mappings->get_next_hir_id (crate_num),
				 mappings->get_next_localdef_id (crate_num));
  std::vector<std::unique_ptr<HIR::ExternalItem>> extern_items;
  for (auto &item : extern_block.get_extern_items ())
    {
      if (item->is_marked_for_strip ())
	continue;
      HIR::ExternalItem *lowered
	= ASTLoweringExternItem::translate (item.get (), mapping.get_hirid ());
      extern_items.push_back (std::unique_ptr<HIR::ExternalItem> (lowered));
    }
  ABI abi = ABI::RUST;
  if (extern_block.has_abi ())
    {
      const std::string &extern_abi = extern_block.get_abi ();
      abi = get_abi_from_string (extern_abi);
      if (abi == ABI::UNKNOWN)
	rust_error_at (extern_block.get_locus (), "unknown ABI option");
    }
  HIR::ExternBlock *hir_extern_block
    = new HIR::ExternBlock (mapping, abi, std::move (extern_items),
			    std::move (vis), extern_block.get_inner_attrs (),
			    extern_block.get_outer_attrs (),
			    extern_block.get_locus ());
  mappings->insert_hir_extern_block (hir_extern_block);
  return hir_extern_block;
}
} // namespace HIR
} // namespace Rust