summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_ast_lowering
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_ast_lowering')
-rw-r--r--compiler/rustc_ast_lowering/Cargo.toml23
-rw-r--r--compiler/rustc_ast_lowering/src/asm.rs485
-rw-r--r--compiler/rustc_ast_lowering/src/block.rs122
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs1914
-rw-r--r--compiler/rustc_ast_lowering/src/index.rs346
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs1513
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs2501
-rw-r--r--compiler/rustc_ast_lowering/src/lifetime_collector.rs115
-rw-r--r--compiler/rustc_ast_lowering/src/pat.rs350
-rw-r--r--compiler/rustc_ast_lowering/src/path.rs406
10 files changed, 7775 insertions, 0 deletions
diff --git a/compiler/rustc_ast_lowering/Cargo.toml b/compiler/rustc_ast_lowering/Cargo.toml
new file mode 100644
index 000000000..39ba62ef2
--- /dev/null
+++ b/compiler/rustc_ast_lowering/Cargo.toml
@@ -0,0 +1,23 @@
+[package]
+name = "rustc_ast_lowering"
+version = "0.0.0"
+edition = "2021"
+
+[lib]
+doctest = false
+
+[dependencies]
+rustc_arena = { path = "../rustc_arena" }
+tracing = "0.1"
+rustc_ast_pretty = { path = "../rustc_ast_pretty" }
+rustc_hir = { path = "../rustc_hir" }
+rustc_target = { path = "../rustc_target" }
+rustc_data_structures = { path = "../rustc_data_structures" }
+rustc_index = { path = "../rustc_index" }
+rustc_middle = { path = "../rustc_middle" }
+rustc_query_system = { path = "../rustc_query_system" }
+rustc_span = { path = "../rustc_span" }
+rustc_errors = { path = "../rustc_errors" }
+rustc_session = { path = "../rustc_session" }
+rustc_ast = { path = "../rustc_ast" }
+smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs
new file mode 100644
index 000000000..4166b4fc2
--- /dev/null
+++ b/compiler/rustc_ast_lowering/src/asm.rs
@@ -0,0 +1,485 @@
+use crate::{ImplTraitContext, ImplTraitPosition, ParamMode, ResolverAstLoweringExt};
+
+use super::LoweringContext;
+
+use rustc_ast::ptr::P;
+use rustc_ast::*;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_errors::struct_span_err;
+use rustc_hir as hir;
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::definitions::DefPathData;
+use rustc_session::parse::feature_err;
+use rustc_span::{sym, Span};
+use rustc_target::asm;
+use std::collections::hash_map::Entry;
+use std::fmt::Write;
+
+impl<'a, 'hir> LoweringContext<'a, 'hir> {
+ pub(crate) fn lower_inline_asm(
+ &mut self,
+ sp: Span,
+ asm: &InlineAsm,
+ ) -> &'hir hir::InlineAsm<'hir> {
+ // Rustdoc needs to support asm! from foreign architectures: don't try
+ // lowering the register constraints in this case.
+ let asm_arch =
+ if self.tcx.sess.opts.actually_rustdoc { None } else { self.tcx.sess.asm_arch };
+ if asm_arch.is_none() && !self.tcx.sess.opts.actually_rustdoc {
+ struct_span_err!(
+ self.tcx.sess,
+ sp,
+ E0472,
+ "inline assembly is unsupported on this target"
+ )
+ .emit();
+ }
+ if let Some(asm_arch) = asm_arch {
+ // Inline assembly is currently only stable for these architectures.
+ let is_stable = matches!(
+ asm_arch,
+ asm::InlineAsmArch::X86
+ | asm::InlineAsmArch::X86_64
+ | asm::InlineAsmArch::Arm
+ | asm::InlineAsmArch::AArch64
+ | asm::InlineAsmArch::RiscV32
+ | asm::InlineAsmArch::RiscV64
+ );
+ if !is_stable && !self.tcx.features().asm_experimental_arch {
+ feature_err(
+ &self.tcx.sess.parse_sess,
+ sym::asm_experimental_arch,
+ sp,
+ "inline assembly is not stable yet on this architecture",
+ )
+ .emit();
+ }
+ }
+ if asm.options.contains(InlineAsmOptions::ATT_SYNTAX)
+ && !matches!(asm_arch, Some(asm::InlineAsmArch::X86 | asm::InlineAsmArch::X86_64))
+ && !self.tcx.sess.opts.actually_rustdoc
+ {
+ self.tcx
+ .sess
+ .struct_span_err(sp, "the `att_syntax` option is only supported on x86")
+ .emit();
+ }
+ if asm.options.contains(InlineAsmOptions::MAY_UNWIND) && !self.tcx.features().asm_unwind {
+ feature_err(
+ &self.tcx.sess.parse_sess,
+ sym::asm_unwind,
+ sp,
+ "the `may_unwind` option is unstable",
+ )
+ .emit();
+ }
+
+ let mut clobber_abis = FxHashMap::default();
+ if let Some(asm_arch) = asm_arch {
+ for (abi_name, abi_span) in &asm.clobber_abis {
+ match asm::InlineAsmClobberAbi::parse(asm_arch, &self.tcx.sess.target, *abi_name) {
+ Ok(abi) => {
+ // If the abi was already in the list, emit an error
+ match clobber_abis.get(&abi) {
+ Some((prev_name, prev_sp)) => {
+ let mut err = self.tcx.sess.struct_span_err(
+ *abi_span,
+ &format!("`{}` ABI specified multiple times", prev_name),
+ );
+ err.span_label(*prev_sp, "previously specified here");
+
+ // Multiple different abi names may actually be the same ABI
+ // If the specified ABIs are not the same name, alert the user that they resolve to the same ABI
+ let source_map = self.tcx.sess.source_map();
+ if source_map.span_to_snippet(*prev_sp)
+ != source_map.span_to_snippet(*abi_span)
+ {
+ err.note("these ABIs are equivalent on the current target");
+ }
+
+ err.emit();
+ }
+ None => {
+ clobber_abis.insert(abi, (abi_name, *abi_span));
+ }
+ }
+ }
+ Err(&[]) => {
+ self.tcx
+ .sess
+ .struct_span_err(
+ *abi_span,
+ "`clobber_abi` is not supported on this target",
+ )
+ .emit();
+ }
+ Err(supported_abis) => {
+ let mut err = self
+ .tcx
+ .sess
+ .struct_span_err(*abi_span, "invalid ABI for `clobber_abi`");
+ let mut abis = format!("`{}`", supported_abis[0]);
+ for m in &supported_abis[1..] {
+ let _ = write!(abis, ", `{}`", m);
+ }
+ err.note(&format!(
+ "the following ABIs are supported on this target: {}",
+ abis
+ ));
+ err.emit();
+ }
+ }
+ }
+ }
+
+ // Lower operands to HIR. We use dummy register classes if an error
+ // occurs during lowering because we still need to be able to produce a
+ // valid HIR.
+ let sess = self.tcx.sess;
+ let mut operands: Vec<_> = asm
+ .operands
+ .iter()
+ .map(|(op, op_sp)| {
+ let lower_reg = |reg| match reg {
+ InlineAsmRegOrRegClass::Reg(s) => {
+ asm::InlineAsmRegOrRegClass::Reg(if let Some(asm_arch) = asm_arch {
+ asm::InlineAsmReg::parse(asm_arch, s).unwrap_or_else(|e| {
+ let msg = format!("invalid register `{}`: {}", s, e);
+ sess.struct_span_err(*op_sp, &msg).emit();
+ asm::InlineAsmReg::Err
+ })
+ } else {
+ asm::InlineAsmReg::Err
+ })
+ }
+ InlineAsmRegOrRegClass::RegClass(s) => {
+ asm::InlineAsmRegOrRegClass::RegClass(if let Some(asm_arch) = asm_arch {
+ asm::InlineAsmRegClass::parse(asm_arch, s).unwrap_or_else(|e| {
+ let msg = format!("invalid register class `{}`: {}", s, e);
+ sess.struct_span_err(*op_sp, &msg).emit();
+ asm::InlineAsmRegClass::Err
+ })
+ } else {
+ asm::InlineAsmRegClass::Err
+ })
+ }
+ };
+
+ let op = match *op {
+ InlineAsmOperand::In { reg, ref expr } => hir::InlineAsmOperand::In {
+ reg: lower_reg(reg),
+ expr: self.lower_expr_mut(expr),
+ },
+ InlineAsmOperand::Out { reg, late, ref expr } => hir::InlineAsmOperand::Out {
+ reg: lower_reg(reg),
+ late,
+ expr: expr.as_ref().map(|expr| self.lower_expr_mut(expr)),
+ },
+ InlineAsmOperand::InOut { reg, late, ref expr } => {
+ hir::InlineAsmOperand::InOut {
+ reg: lower_reg(reg),
+ late,
+ expr: self.lower_expr_mut(expr),
+ }
+ }
+ InlineAsmOperand::SplitInOut { reg, late, ref in_expr, ref out_expr } => {
+ hir::InlineAsmOperand::SplitInOut {
+ reg: lower_reg(reg),
+ late,
+ in_expr: self.lower_expr_mut(in_expr),
+ out_expr: out_expr.as_ref().map(|expr| self.lower_expr_mut(expr)),
+ }
+ }
+ InlineAsmOperand::Const { ref anon_const } => {
+ if !self.tcx.features().asm_const {
+ feature_err(
+ &sess.parse_sess,
+ sym::asm_const,
+ *op_sp,
+ "const operands for inline assembly are unstable",
+ )
+ .emit();
+ }
+ hir::InlineAsmOperand::Const {
+ anon_const: self.lower_anon_const(anon_const),
+ }
+ }
+ InlineAsmOperand::Sym { ref sym } => {
+ if !self.tcx.features().asm_sym {
+ feature_err(
+ &sess.parse_sess,
+ sym::asm_sym,
+ *op_sp,
+ "sym operands for inline assembly are unstable",
+ )
+ .emit();
+ }
+
+ let static_def_id = self
+ .resolver
+ .get_partial_res(sym.id)
+ .filter(|res| res.unresolved_segments() == 0)
+ .and_then(|res| {
+ if let Res::Def(DefKind::Static(_), def_id) = res.base_res() {
+ Some(def_id)
+ } else {
+ None
+ }
+ });
+
+ if let Some(def_id) = static_def_id {
+ let path = self.lower_qpath(
+ sym.id,
+ &sym.qself,
+ &sym.path,
+ ParamMode::Optional,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+ );
+ hir::InlineAsmOperand::SymStatic { path, def_id }
+ } else {
+ // Replace the InlineAsmSym AST node with an
+ // Expr using the name node id.
+ let expr = Expr {
+ id: sym.id,
+ kind: ExprKind::Path(sym.qself.clone(), sym.path.clone()),
+ span: *op_sp,
+ attrs: AttrVec::new(),
+ tokens: None,
+ };
+
+ // Wrap the expression in an AnonConst.
+ let parent_def_id = self.current_hir_id_owner;
+ let node_id = self.next_node_id();
+ self.create_def(parent_def_id, node_id, DefPathData::AnonConst);
+ let anon_const = AnonConst { id: node_id, value: P(expr) };
+ hir::InlineAsmOperand::SymFn {
+ anon_const: self.lower_anon_const(&anon_const),
+ }
+ }
+ }
+ };
+ (op, self.lower_span(*op_sp))
+ })
+ .collect();
+
+ // Validate template modifiers against the register classes for the operands
+ for p in &asm.template {
+ if let InlineAsmTemplatePiece::Placeholder {
+ operand_idx,
+ modifier: Some(modifier),
+ span: placeholder_span,
+ } = *p
+ {
+ let op_sp = asm.operands[operand_idx].1;
+ match &operands[operand_idx].0 {
+ hir::InlineAsmOperand::In { reg, .. }
+ | hir::InlineAsmOperand::Out { reg, .. }
+ | hir::InlineAsmOperand::InOut { reg, .. }
+ | hir::InlineAsmOperand::SplitInOut { reg, .. } => {
+ let class = reg.reg_class();
+ if class == asm::InlineAsmRegClass::Err {
+ continue;
+ }
+ let valid_modifiers = class.valid_modifiers(asm_arch.unwrap());
+ if !valid_modifiers.contains(&modifier) {
+ let mut err = sess.struct_span_err(
+ placeholder_span,
+ "invalid asm template modifier for this register class",
+ );
+ err.span_label(placeholder_span, "template modifier");
+ err.span_label(op_sp, "argument");
+ if !valid_modifiers.is_empty() {
+ let mut mods = format!("`{}`", valid_modifiers[0]);
+ for m in &valid_modifiers[1..] {
+ let _ = write!(mods, ", `{}`", m);
+ }
+ err.note(&format!(
+ "the `{}` register class supports \
+ the following template modifiers: {}",
+ class.name(),
+ mods
+ ));
+ } else {
+ err.note(&format!(
+ "the `{}` register class does not support template modifiers",
+ class.name()
+ ));
+ }
+ err.emit();
+ }
+ }
+ hir::InlineAsmOperand::Const { .. } => {
+ let mut err = sess.struct_span_err(
+ placeholder_span,
+ "asm template modifiers are not allowed for `const` arguments",
+ );
+ err.span_label(placeholder_span, "template modifier");
+ err.span_label(op_sp, "argument");
+ err.emit();
+ }
+ hir::InlineAsmOperand::SymFn { .. }
+ | hir::InlineAsmOperand::SymStatic { .. } => {
+ let mut err = sess.struct_span_err(
+ placeholder_span,
+ "asm template modifiers are not allowed for `sym` arguments",
+ );
+ err.span_label(placeholder_span, "template modifier");
+ err.span_label(op_sp, "argument");
+ err.emit();
+ }
+ }
+ }
+ }
+
+ let mut used_input_regs = FxHashMap::default();
+ let mut used_output_regs = FxHashMap::default();
+
+ for (idx, &(ref op, op_sp)) in operands.iter().enumerate() {
+ if let Some(reg) = op.reg() {
+ let reg_class = reg.reg_class();
+ if reg_class == asm::InlineAsmRegClass::Err {
+ continue;
+ }
+
+ // Some register classes can only be used as clobbers. This
+ // means that we disallow passing a value in/out of the asm and
+ // require that the operand name an explicit register, not a
+ // register class.
+ if reg_class.is_clobber_only(asm_arch.unwrap()) && !op.is_clobber() {
+ let msg = format!(
+ "register class `{}` can only be used as a clobber, \
+ not as an input or output",
+ reg_class.name()
+ );
+ sess.struct_span_err(op_sp, &msg).emit();
+ continue;
+ }
+
+ // Check for conflicts between explicit register operands.
+ if let asm::InlineAsmRegOrRegClass::Reg(reg) = reg {
+ let (input, output) = match op {
+ hir::InlineAsmOperand::In { .. } => (true, false),
+
+ // Late output do not conflict with inputs, but normal outputs do
+ hir::InlineAsmOperand::Out { late, .. } => (!late, true),
+
+ hir::InlineAsmOperand::InOut { .. }
+ | hir::InlineAsmOperand::SplitInOut { .. } => (true, true),
+
+ hir::InlineAsmOperand::Const { .. }
+ | hir::InlineAsmOperand::SymFn { .. }
+ | hir::InlineAsmOperand::SymStatic { .. } => {
+ unreachable!()
+ }
+ };
+
+ // Flag to output the error only once per operand
+ let mut skip = false;
+ reg.overlapping_regs(|r| {
+ let mut check = |used_regs: &mut FxHashMap<asm::InlineAsmReg, usize>,
+ input| {
+ match used_regs.entry(r) {
+ Entry::Occupied(o) => {
+ if skip {
+ return;
+ }
+ skip = true;
+
+ let idx2 = *o.get();
+ let &(ref op2, op_sp2) = &operands[idx2];
+ let Some(asm::InlineAsmRegOrRegClass::Reg(reg2)) = op2.reg() else {
+ unreachable!();
+ };
+
+ let msg = format!(
+ "register `{}` conflicts with register `{}`",
+ reg.name(),
+ reg2.name()
+ );
+ let mut err = sess.struct_span_err(op_sp, &msg);
+ err.span_label(op_sp, &format!("register `{}`", reg.name()));
+ err.span_label(op_sp2, &format!("register `{}`", reg2.name()));
+
+ match (op, op2) {
+ (
+ hir::InlineAsmOperand::In { .. },
+ hir::InlineAsmOperand::Out { late, .. },
+ )
+ | (
+ hir::InlineAsmOperand::Out { late, .. },
+ hir::InlineAsmOperand::In { .. },
+ ) => {
+ assert!(!*late);
+ let out_op_sp = if input { op_sp2 } else { op_sp };
+ let msg = "use `lateout` instead of \
+ `out` to avoid conflict";
+ err.span_help(out_op_sp, msg);
+ }
+ _ => {}
+ }
+
+ err.emit();
+ }
+ Entry::Vacant(v) => {
+ if r == reg {
+ v.insert(idx);
+ }
+ }
+ }
+ };
+ if input {
+ check(&mut used_input_regs, true);
+ }
+ if output {
+ check(&mut used_output_regs, false);
+ }
+ });
+ }
+ }
+ }
+
+ // If a clobber_abi is specified, add the necessary clobbers to the
+ // operands list.
+ let mut clobbered = FxHashSet::default();
+ for (abi, (_, abi_span)) in clobber_abis {
+ for &clobber in abi.clobbered_regs() {
+ // Don't emit a clobber for a register already clobbered
+ if clobbered.contains(&clobber) {
+ continue;
+ }
+
+ let mut output_used = false;
+ clobber.overlapping_regs(|reg| {
+ if used_output_regs.contains_key(&reg) {
+ output_used = true;
+ }
+ });
+
+ if !output_used {
+ operands.push((
+ hir::InlineAsmOperand::Out {
+ reg: asm::InlineAsmRegOrRegClass::Reg(clobber),
+ late: true,
+ expr: None,
+ },
+ self.lower_span(abi_span),
+ ));
+ clobbered.insert(clobber);
+ }
+ }
+ }
+
+ let operands = self.arena.alloc_from_iter(operands);
+ let template = self.arena.alloc_from_iter(asm.template.iter().cloned());
+ let template_strs = self.arena.alloc_from_iter(
+ asm.template_strs
+ .iter()
+ .map(|(sym, snippet, span)| (*sym, *snippet, self.lower_span(*span))),
+ );
+ let line_spans =
+ self.arena.alloc_from_iter(asm.line_spans.iter().map(|span| self.lower_span(*span)));
+ let hir_asm =
+ hir::InlineAsm { template, template_strs, operands, options: asm.options, line_spans };
+ self.arena.alloc(hir_asm)
+ }
+}
diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs
new file mode 100644
index 000000000..7cbfe143b
--- /dev/null
+++ b/compiler/rustc_ast_lowering/src/block.rs
@@ -0,0 +1,122 @@
+use crate::{ImplTraitContext, ImplTraitPosition, LoweringContext};
+use rustc_ast::{Block, BlockCheckMode, Local, LocalKind, Stmt, StmtKind};
+use rustc_hir as hir;
+use rustc_session::parse::feature_err;
+use rustc_span::sym;
+
+use smallvec::SmallVec;
+
+impl<'a, 'hir> LoweringContext<'a, 'hir> {
+ pub(super) fn lower_block(
+ &mut self,
+ b: &Block,
+ targeted_by_break: bool,
+ ) -> &'hir hir::Block<'hir> {
+ self.arena.alloc(self.lower_block_noalloc(b, targeted_by_break))
+ }
+
+ pub(super) fn lower_block_noalloc(
+ &mut self,
+ b: &Block,
+ targeted_by_break: bool,
+ ) -> hir::Block<'hir> {
+ let (stmts, expr) = self.lower_stmts(&b.stmts);
+ let rules = self.lower_block_check_mode(&b.rules);
+ let hir_id = self.lower_node_id(b.id);
+ hir::Block { hir_id, stmts, expr, rules, span: self.lower_span(b.span), targeted_by_break }
+ }
+
+ fn lower_stmts(
+ &mut self,
+ mut ast_stmts: &[Stmt],
+ ) -> (&'hir [hir::Stmt<'hir>], Option<&'hir hir::Expr<'hir>>) {
+ let mut stmts = SmallVec::<[hir::Stmt<'hir>; 8]>::new();
+ let mut expr = None;
+ while let [s, tail @ ..] = ast_stmts {
+ match s.kind {
+ StmtKind::Local(ref local) => {
+ let hir_id = self.lower_node_id(s.id);
+ let local = self.lower_local(local);
+ self.alias_attrs(hir_id, local.hir_id);
+ let kind = hir::StmtKind::Local(local);
+ let span = self.lower_span(s.span);
+ stmts.push(hir::Stmt { hir_id, kind, span });
+ }
+ StmtKind::Item(ref it) => {
+ stmts.extend(self.lower_item_ref(it).into_iter().enumerate().map(
+ |(i, item_id)| {
+ let hir_id = match i {
+ 0 => self.lower_node_id(s.id),
+ _ => self.next_id(),
+ };
+ let kind = hir::StmtKind::Item(item_id);
+ let span = self.lower_span(s.span);
+ hir::Stmt { hir_id, kind, span }
+ },
+ ));
+ }
+ StmtKind::Expr(ref e) => {
+ let e = self.lower_expr(e);
+ if tail.is_empty() {
+ expr = Some(e);
+ } else {
+ let hir_id = self.lower_node_id(s.id);
+ self.alias_attrs(hir_id, e.hir_id);
+ let kind = hir::StmtKind::Expr(e);
+ let span = self.lower_span(s.span);
+ stmts.push(hir::Stmt { hir_id, kind, span });
+ }
+ }
+ StmtKind::Semi(ref e) => {
+ let e = self.lower_expr(e);
+ let hir_id = self.lower_node_id(s.id);
+ self.alias_attrs(hir_id, e.hir_id);
+ let kind = hir::StmtKind::Semi(e);
+ let span = self.lower_span(s.span);
+ stmts.push(hir::Stmt { hir_id, kind, span });
+ }
+ StmtKind::Empty => {}
+ StmtKind::MacCall(..) => panic!("shouldn't exist here"),
+ }
+ ast_stmts = &ast_stmts[1..];
+ }
+ (self.arena.alloc_from_iter(stmts), expr)
+ }
+
+ fn lower_local(&mut self, l: &Local) -> &'hir hir::Local<'hir> {
+ let ty = l
+ .ty
+ .as_ref()
+ .map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Variable)));
+ let init = l.kind.init().map(|init| self.lower_expr(init));
+ let hir_id = self.lower_node_id(l.id);
+ let pat = self.lower_pat(&l.pat);
+ let els = if let LocalKind::InitElse(_, els) = &l.kind {
+ if !self.tcx.features().let_else {
+ feature_err(
+ &self.tcx.sess.parse_sess,
+ sym::let_else,
+ l.span,
+ "`let...else` statements are unstable",
+ )
+ .emit();
+ }
+ Some(self.lower_block(els, false))
+ } else {
+ None
+ };
+ let span = self.lower_span(l.span);
+ let source = hir::LocalSource::Normal;
+ self.lower_attrs(hir_id, &l.attrs);
+ self.arena.alloc(hir::Local { hir_id, ty, pat, init, els, span, source })
+ }
+
+ fn lower_block_check_mode(&mut self, b: &BlockCheckMode) -> hir::BlockCheckMode {
+ match *b {
+ BlockCheckMode::Default => hir::BlockCheckMode::DefaultBlock,
+ BlockCheckMode::Unsafe(u) => {
+ hir::BlockCheckMode::UnsafeBlock(self.lower_unsafe_source(u))
+ }
+ }
+ }
+}
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
new file mode 100644
index 000000000..fb6715ff1
--- /dev/null
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -0,0 +1,1914 @@
+use super::ResolverAstLoweringExt;
+use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs};
+use crate::{FnDeclKind, ImplTraitPosition};
+
+use rustc_ast::attr;
+use rustc_ast::ptr::P as AstP;
+use rustc_ast::*;
+use rustc_data_structures::stack::ensure_sufficient_stack;
+use rustc_data_structures::thin_vec::ThinVec;
+use rustc_errors::struct_span_err;
+use rustc_hir as hir;
+use rustc_hir::def::Res;
+use rustc_hir::definitions::DefPathData;
+use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned};
+use rustc_span::symbol::{sym, Ident};
+use rustc_span::DUMMY_SP;
+
+impl<'hir> LoweringContext<'_, 'hir> {
+ fn lower_exprs(&mut self, exprs: &[AstP<Expr>]) -> &'hir [hir::Expr<'hir>] {
+ self.arena.alloc_from_iter(exprs.iter().map(|x| self.lower_expr_mut(x)))
+ }
+
+ pub(super) fn lower_expr(&mut self, e: &Expr) -> &'hir hir::Expr<'hir> {
+ self.arena.alloc(self.lower_expr_mut(e))
+ }
+
+ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
+ ensure_sufficient_stack(|| {
+ let kind = match e.kind {
+ ExprKind::Box(ref inner) => hir::ExprKind::Box(self.lower_expr(inner)),
+ ExprKind::Array(ref exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)),
+ ExprKind::ConstBlock(ref anon_const) => {
+ let anon_const = self.lower_anon_const(anon_const);
+ hir::ExprKind::ConstBlock(anon_const)
+ }
+ ExprKind::Repeat(ref expr, ref count) => {
+ let expr = self.lower_expr(expr);
+ let count = self.lower_array_length(count);
+ hir::ExprKind::Repeat(expr, count)
+ }
+ ExprKind::Tup(ref elts) => hir::ExprKind::Tup(self.lower_exprs(elts)),
+ ExprKind::Call(ref f, ref args) => {
+ if e.attrs.get(0).map_or(false, |a| a.has_name(sym::rustc_box)) {
+ if let [inner] = &args[..] && e.attrs.len() == 1 {
+ let kind = hir::ExprKind::Box(self.lower_expr(&inner));
+ let hir_id = self.lower_node_id(e.id);
+ return hir::Expr { hir_id, kind, span: self.lower_span(e.span) };
+ } else {
+ self.tcx.sess
+ .struct_span_err(
+ e.span,
+ "#[rustc_box] requires precisely one argument \
+ and no other attributes are allowed",
+ )
+ .emit();
+ hir::ExprKind::Err
+ }
+ } else if let Some(legacy_args) = self.resolver.legacy_const_generic_args(f) {
+ self.lower_legacy_const_generics((**f).clone(), args.clone(), &legacy_args)
+ } else {
+ let f = self.lower_expr(f);
+ hir::ExprKind::Call(f, self.lower_exprs(args))
+ }
+ }
+ ExprKind::MethodCall(ref seg, ref args, span) => {
+ let hir_seg = self.arena.alloc(self.lower_path_segment(
+ e.span,
+ seg,
+ ParamMode::Optional,
+ ParenthesizedGenericArgs::Err,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+ ));
+ let args = self.lower_exprs(args);
+ hir::ExprKind::MethodCall(hir_seg, args, self.lower_span(span))
+ }
+ ExprKind::Binary(binop, ref lhs, ref rhs) => {
+ let binop = self.lower_binop(binop);
+ let lhs = self.lower_expr(lhs);
+ let rhs = self.lower_expr(rhs);
+ hir::ExprKind::Binary(binop, lhs, rhs)
+ }
+ ExprKind::Unary(op, ref ohs) => {
+ let op = self.lower_unop(op);
+ let ohs = self.lower_expr(ohs);
+ hir::ExprKind::Unary(op, ohs)
+ }
+ ExprKind::Lit(ref l) => {
+ hir::ExprKind::Lit(respan(self.lower_span(l.span), l.kind.clone()))
+ }
+ ExprKind::Cast(ref expr, ref ty) => {
+ let expr = self.lower_expr(expr);
+ let ty =
+ self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
+ hir::ExprKind::Cast(expr, ty)
+ }
+ ExprKind::Type(ref expr, ref ty) => {
+ let expr = self.lower_expr(expr);
+ let ty =
+ self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
+ hir::ExprKind::Type(expr, ty)
+ }
+ ExprKind::AddrOf(k, m, ref ohs) => {
+ let ohs = self.lower_expr(ohs);
+ hir::ExprKind::AddrOf(k, m, ohs)
+ }
+ ExprKind::Let(ref pat, ref scrutinee, span) => {
+ hir::ExprKind::Let(self.arena.alloc(hir::Let {
+ hir_id: self.next_id(),
+ span: self.lower_span(span),
+ pat: self.lower_pat(pat),
+ ty: None,
+ init: self.lower_expr(scrutinee),
+ }))
+ }
+ ExprKind::If(ref cond, ref then, ref else_opt) => {
+ self.lower_expr_if(cond, then, else_opt.as_deref())
+ }
+ ExprKind::While(ref cond, ref body, opt_label) => {
+ self.with_loop_scope(e.id, |this| {
+ let span =
+ this.mark_span_with_reason(DesugaringKind::WhileLoop, e.span, None);
+ this.lower_expr_while_in_loop_scope(span, cond, body, opt_label)
+ })
+ }
+ ExprKind::Loop(ref body, opt_label) => self.with_loop_scope(e.id, |this| {
+ hir::ExprKind::Loop(
+ this.lower_block(body, false),
+ this.lower_label(opt_label),
+ hir::LoopSource::Loop,
+ DUMMY_SP,
+ )
+ }),
+ ExprKind::TryBlock(ref body) => self.lower_expr_try_block(body),
+ ExprKind::Match(ref expr, ref arms) => hir::ExprKind::Match(
+ self.lower_expr(expr),
+ self.arena.alloc_from_iter(arms.iter().map(|x| self.lower_arm(x))),
+ hir::MatchSource::Normal,
+ ),
+ ExprKind::Async(capture_clause, closure_node_id, ref block) => self
+ .make_async_expr(
+ capture_clause,
+ closure_node_id,
+ None,
+ block.span,
+ hir::AsyncGeneratorKind::Block,
+ |this| this.with_new_scopes(|this| this.lower_block_expr(block)),
+ ),
+ ExprKind::Await(ref expr) => {
+ let span = if expr.span.hi() < e.span.hi() {
+ expr.span.shrink_to_hi().with_hi(e.span.hi())
+ } else {
+ // this is a recovered `await expr`
+ e.span
+ };
+ self.lower_expr_await(span, expr)
+ }
+ ExprKind::Closure(
+ ref binder,
+ capture_clause,
+ asyncness,
+ movability,
+ ref decl,
+ ref body,
+ fn_decl_span,
+ ) => {
+ if let Async::Yes { closure_id, .. } = asyncness {
+ self.lower_expr_async_closure(
+ binder,
+ capture_clause,
+ e.id,
+ closure_id,
+ decl,
+ body,
+ fn_decl_span,
+ )
+ } else {
+ self.lower_expr_closure(
+ binder,
+ capture_clause,
+ e.id,
+ movability,
+ decl,
+ body,
+ fn_decl_span,
+ )
+ }
+ }
+ ExprKind::Block(ref blk, opt_label) => {
+ let opt_label = self.lower_label(opt_label);
+ hir::ExprKind::Block(self.lower_block(blk, opt_label.is_some()), opt_label)
+ }
+ ExprKind::Assign(ref el, ref er, span) => {
+ self.lower_expr_assign(el, er, span, e.span)
+ }
+ ExprKind::AssignOp(op, ref el, ref er) => hir::ExprKind::AssignOp(
+ self.lower_binop(op),
+ self.lower_expr(el),
+ self.lower_expr(er),
+ ),
+ ExprKind::Field(ref el, ident) => {
+ hir::ExprKind::Field(self.lower_expr(el), self.lower_ident(ident))
+ }
+ ExprKind::Index(ref el, ref er) => {
+ hir::ExprKind::Index(self.lower_expr(el), self.lower_expr(er))
+ }
+ ExprKind::Range(Some(ref e1), Some(ref e2), RangeLimits::Closed) => {
+ self.lower_expr_range_closed(e.span, e1, e2)
+ }
+ ExprKind::Range(ref e1, ref e2, lims) => {
+ self.lower_expr_range(e.span, e1.as_deref(), e2.as_deref(), lims)
+ }
+ ExprKind::Underscore => {
+ self.tcx
+ .sess.struct_span_err(
+ e.span,
+ "in expressions, `_` can only be used on the left-hand side of an assignment",
+ )
+ .span_label(e.span, "`_` not allowed here")
+ .emit();
+ hir::ExprKind::Err
+ }
+ ExprKind::Path(ref qself, ref path) => {
+ let qpath = self.lower_qpath(
+ e.id,
+ qself,
+ path,
+ ParamMode::Optional,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+ );
+ hir::ExprKind::Path(qpath)
+ }
+ ExprKind::Break(opt_label, ref opt_expr) => {
+ let opt_expr = opt_expr.as_ref().map(|x| self.lower_expr(x));
+ hir::ExprKind::Break(self.lower_jump_destination(e.id, opt_label), opt_expr)
+ }
+ ExprKind::Continue(opt_label) => {
+ hir::ExprKind::Continue(self.lower_jump_destination(e.id, opt_label))
+ }
+ ExprKind::Ret(ref e) => {
+ let e = e.as_ref().map(|x| self.lower_expr(x));
+ hir::ExprKind::Ret(e)
+ }
+ ExprKind::Yeet(ref sub_expr) => self.lower_expr_yeet(e.span, sub_expr.as_deref()),
+ ExprKind::InlineAsm(ref asm) => {
+ hir::ExprKind::InlineAsm(self.lower_inline_asm(e.span, asm))
+ }
+ ExprKind::Struct(ref se) => {
+ let rest = match &se.rest {
+ StructRest::Base(e) => Some(self.lower_expr(e)),
+ StructRest::Rest(sp) => {
+ self.tcx
+ .sess
+ .struct_span_err(*sp, "base expression required after `..`")
+ .span_label(*sp, "add a base expression here")
+ .emit();
+ Some(&*self.arena.alloc(self.expr_err(*sp)))
+ }
+ StructRest::None => None,
+ };
+ hir::ExprKind::Struct(
+ self.arena.alloc(self.lower_qpath(
+ e.id,
+ &se.qself,
+ &se.path,
+ ParamMode::Optional,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+ )),
+ self.arena
+ .alloc_from_iter(se.fields.iter().map(|x| self.lower_expr_field(x))),
+ rest,
+ )
+ }
+ ExprKind::Yield(ref opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()),
+ ExprKind::Err => hir::ExprKind::Err,
+ ExprKind::Try(ref sub_expr) => self.lower_expr_try(e.span, sub_expr),
+ ExprKind::Paren(ref ex) => {
+ let mut ex = self.lower_expr_mut(ex);
+ // Include parens in span, but only if it is a super-span.
+ if e.span.contains(ex.span) {
+ ex.span = self.lower_span(e.span);
+ }
+ // Merge attributes into the inner expression.
+ if !e.attrs.is_empty() {
+ let old_attrs =
+ self.attrs.get(&ex.hir_id.local_id).map(|la| *la).unwrap_or(&[]);
+ self.attrs.insert(
+ ex.hir_id.local_id,
+ &*self.arena.alloc_from_iter(
+ e.attrs
+ .iter()
+ .map(|a| self.lower_attr(a))
+ .chain(old_attrs.iter().cloned()),
+ ),
+ );
+ }
+ return ex;
+ }
+
+ // Desugar `ExprForLoop`
+ // from: `[opt_ident]: for <pat> in <head> <body>`
+ ExprKind::ForLoop(ref pat, ref head, ref body, opt_label) => {
+ return self.lower_expr_for(e, pat, head, body, opt_label);
+ }
+ ExprKind::MacCall(_) => panic!("{:?} shouldn't exist here", e.span),
+ };
+
+ let hir_id = self.lower_node_id(e.id);
+ self.lower_attrs(hir_id, &e.attrs);
+ hir::Expr { hir_id, kind, span: self.lower_span(e.span) }
+ })
+ }
+
+ fn lower_unop(&mut self, u: UnOp) -> hir::UnOp {
+ match u {
+ UnOp::Deref => hir::UnOp::Deref,
+ UnOp::Not => hir::UnOp::Not,
+ UnOp::Neg => hir::UnOp::Neg,
+ }
+ }
+
+ fn lower_binop(&mut self, b: BinOp) -> hir::BinOp {
+ Spanned {
+ node: match b.node {
+ BinOpKind::Add => hir::BinOpKind::Add,
+ BinOpKind::Sub => hir::BinOpKind::Sub,
+ BinOpKind::Mul => hir::BinOpKind::Mul,
+ BinOpKind::Div => hir::BinOpKind::Div,
+ BinOpKind::Rem => hir::BinOpKind::Rem,
+ BinOpKind::And => hir::BinOpKind::And,
+ BinOpKind::Or => hir::BinOpKind::Or,
+ BinOpKind::BitXor => hir::BinOpKind::BitXor,
+ BinOpKind::BitAnd => hir::BinOpKind::BitAnd,
+ BinOpKind::BitOr => hir::BinOpKind::BitOr,
+ BinOpKind::Shl => hir::BinOpKind::Shl,
+ BinOpKind::Shr => hir::BinOpKind::Shr,
+ BinOpKind::Eq => hir::BinOpKind::Eq,
+ BinOpKind::Lt => hir::BinOpKind::Lt,
+ BinOpKind::Le => hir::BinOpKind::Le,
+ BinOpKind::Ne => hir::BinOpKind::Ne,
+ BinOpKind::Ge => hir::BinOpKind::Ge,
+ BinOpKind::Gt => hir::BinOpKind::Gt,
+ },
+ span: self.lower_span(b.span),
+ }
+ }
+
+ fn lower_legacy_const_generics(
+ &mut self,
+ mut f: Expr,
+ args: Vec<AstP<Expr>>,
+ legacy_args_idx: &[usize],
+ ) -> hir::ExprKind<'hir> {
+ let ExprKind::Path(None, ref mut path) = f.kind else {
+ unreachable!();
+ };
+
+ // Split the arguments into const generics and normal arguments
+ let mut real_args = vec![];
+ let mut generic_args = vec![];
+ for (idx, arg) in args.into_iter().enumerate() {
+ if legacy_args_idx.contains(&idx) {
+ let parent_def_id = self.current_hir_id_owner;
+ let node_id = self.next_node_id();
+
+ // Add a definition for the in-band const def.
+ self.create_def(parent_def_id, node_id, DefPathData::AnonConst);
+
+ let anon_const = AnonConst { id: node_id, value: arg };
+ generic_args.push(AngleBracketedArg::Arg(GenericArg::Const(anon_const)));
+ } else {
+ real_args.push(arg);
+ }
+ }
+
+ // Add generic args to the last element of the path.
+ let last_segment = path.segments.last_mut().unwrap();
+ assert!(last_segment.args.is_none());
+ last_segment.args = Some(AstP(GenericArgs::AngleBracketed(AngleBracketedArgs {
+ span: DUMMY_SP,
+ args: generic_args,
+ })));
+
+ // Now lower everything as normal.
+ let f = self.lower_expr(&f);
+ hir::ExprKind::Call(f, self.lower_exprs(&real_args))
+ }
+
+ fn lower_expr_if(
+ &mut self,
+ cond: &Expr,
+ then: &Block,
+ else_opt: Option<&Expr>,
+ ) -> hir::ExprKind<'hir> {
+ let lowered_cond = self.lower_expr(cond);
+ let new_cond = self.manage_let_cond(lowered_cond);
+ let then_expr = self.lower_block_expr(then);
+ if let Some(rslt) = else_opt {
+ hir::ExprKind::If(new_cond, self.arena.alloc(then_expr), Some(self.lower_expr(rslt)))
+ } else {
+ hir::ExprKind::If(new_cond, self.arena.alloc(then_expr), None)
+ }
+ }
+
+ // If `cond` kind is `let`, returns `let`. Otherwise, wraps and returns `cond`
+ // in a temporary block.
+ fn manage_let_cond(&mut self, cond: &'hir hir::Expr<'hir>) -> &'hir hir::Expr<'hir> {
+ fn has_let_expr<'hir>(expr: &'hir hir::Expr<'hir>) -> bool {
+ match expr.kind {
+ hir::ExprKind::Binary(_, lhs, rhs) => has_let_expr(lhs) || has_let_expr(rhs),
+ hir::ExprKind::Let(..) => true,
+ _ => false,
+ }
+ }
+ if has_let_expr(cond) {
+ cond
+ } else {
+ let reason = DesugaringKind::CondTemporary;
+ let span_block = self.mark_span_with_reason(reason, cond.span, None);
+ self.expr_drop_temps(span_block, cond, AttrVec::new())
+ }
+ }
+
+ // We desugar: `'label: while $cond $body` into:
+ //
+ // ```
+ // 'label: loop {
+ // if { let _t = $cond; _t } {
+ // $body
+ // }
+ // else {
+ // break;
+ // }
+ // }
+ // ```
+ //
+ // Wrap in a construct equivalent to `{ let _t = $cond; _t }`
+ // to preserve drop semantics since `while $cond { ... }` does not
+ // let temporaries live outside of `cond`.
+ fn lower_expr_while_in_loop_scope(
+ &mut self,
+ span: Span,
+ cond: &Expr,
+ body: &Block,
+ opt_label: Option<Label>,
+ ) -> hir::ExprKind<'hir> {
+ let lowered_cond = self.with_loop_condition_scope(|t| t.lower_expr(cond));
+ let new_cond = self.manage_let_cond(lowered_cond);
+ let then = self.lower_block_expr(body);
+ let expr_break = self.expr_break(span, ThinVec::new());
+ let stmt_break = self.stmt_expr(span, expr_break);
+ let else_blk = self.block_all(span, arena_vec![self; stmt_break], None);
+ let else_expr = self.arena.alloc(self.expr_block(else_blk, ThinVec::new()));
+ let if_kind = hir::ExprKind::If(new_cond, self.arena.alloc(then), Some(else_expr));
+ let if_expr = self.expr(span, if_kind, ThinVec::new());
+ let block = self.block_expr(self.arena.alloc(if_expr));
+ let span = self.lower_span(span.with_hi(cond.span.hi()));
+ let opt_label = self.lower_label(opt_label);
+ hir::ExprKind::Loop(block, opt_label, hir::LoopSource::While, span)
+ }
+
+ /// Desugar `try { <stmts>; <expr> }` into `{ <stmts>; ::std::ops::Try::from_output(<expr>) }`,
+ /// `try { <stmts>; }` into `{ <stmts>; ::std::ops::Try::from_output(()) }`
+ /// and save the block id to use it as a break target for desugaring of the `?` operator.
+ fn lower_expr_try_block(&mut self, body: &Block) -> hir::ExprKind<'hir> {
+ self.with_catch_scope(body.id, |this| {
+ let mut block = this.lower_block_noalloc(body, true);
+
+ // Final expression of the block (if present) or `()` with span at the end of block
+ let (try_span, tail_expr) = if let Some(expr) = block.expr.take() {
+ (
+ this.mark_span_with_reason(
+ DesugaringKind::TryBlock,
+ expr.span,
+ this.allow_try_trait.clone(),
+ ),
+ expr,
+ )
+ } else {
+ let try_span = this.mark_span_with_reason(
+ DesugaringKind::TryBlock,
+ this.tcx.sess.source_map().end_point(body.span),
+ this.allow_try_trait.clone(),
+ );
+
+ (try_span, this.expr_unit(try_span))
+ };
+
+ let ok_wrapped_span =
+ this.mark_span_with_reason(DesugaringKind::TryBlock, tail_expr.span, None);
+
+ // `::std::ops::Try::from_output($tail_expr)`
+ block.expr = Some(this.wrap_in_try_constructor(
+ hir::LangItem::TryTraitFromOutput,
+ try_span,
+ tail_expr,
+ ok_wrapped_span,
+ ));
+
+ hir::ExprKind::Block(this.arena.alloc(block), None)
+ })
+ }
+
+ fn wrap_in_try_constructor(
+ &mut self,
+ lang_item: hir::LangItem,
+ method_span: Span,
+ expr: &'hir hir::Expr<'hir>,
+ overall_span: Span,
+ ) -> &'hir hir::Expr<'hir> {
+ let constructor = self.arena.alloc(self.expr_lang_item_path(
+ method_span,
+ lang_item,
+ ThinVec::new(),
+ None,
+ ));
+ self.expr_call(overall_span, constructor, std::slice::from_ref(expr))
+ }
+
+ fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'hir> {
+ let pat = self.lower_pat(&arm.pat);
+ let guard = arm.guard.as_ref().map(|cond| {
+ if let ExprKind::Let(ref pat, ref scrutinee, span) = cond.kind {
+ hir::Guard::IfLet(self.arena.alloc(hir::Let {
+ hir_id: self.next_id(),
+ span: self.lower_span(span),
+ pat: self.lower_pat(pat),
+ ty: None,
+ init: self.lower_expr(scrutinee),
+ }))
+ } else {
+ hir::Guard::If(self.lower_expr(cond))
+ }
+ });
+ let hir_id = self.next_id();
+ self.lower_attrs(hir_id, &arm.attrs);
+ hir::Arm {
+ hir_id,
+ pat,
+ guard,
+ body: self.lower_expr(&arm.body),
+ span: self.lower_span(arm.span),
+ }
+ }
+
+ /// Lower an `async` construct to a generator that is then wrapped so it implements `Future`.
+ ///
+ /// This results in:
+ ///
+ /// ```text
+ /// std::future::from_generator(static move? |_task_context| -> <ret_ty> {
+ /// <body>
+ /// })
+ /// ```
+ pub(super) fn make_async_expr(
+ &mut self,
+ capture_clause: CaptureBy,
+ closure_node_id: NodeId,
+ ret_ty: Option<AstP<Ty>>,
+ span: Span,
+ async_gen_kind: hir::AsyncGeneratorKind,
+ body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
+ ) -> hir::ExprKind<'hir> {
+ let output = match ret_ty {
+ Some(ty) => hir::FnRetTy::Return(
+ self.lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::AsyncBlock)),
+ ),
+ None => hir::FnRetTy::DefaultReturn(self.lower_span(span)),
+ };
+
+ // Resume argument type. We let the compiler infer this to simplify the lowering. It is
+ // fully constrained by `future::from_generator`.
+ let input_ty = hir::Ty {
+ hir_id: self.next_id(),
+ kind: hir::TyKind::Infer,
+ span: self.lower_span(span),
+ };
+
+ // The closure/generator `FnDecl` takes a single (resume) argument of type `input_ty`.
+ let fn_decl = self.arena.alloc(hir::FnDecl {
+ inputs: arena_vec![self; input_ty],
+ output,
+ c_variadic: false,
+ implicit_self: hir::ImplicitSelfKind::None,
+ });
+
+ // Lower the argument pattern/ident. The ident is used again in the `.await` lowering.
+ let (pat, task_context_hid) = self.pat_ident_binding_mode(
+ span,
+ Ident::with_dummy_span(sym::_task_context),
+ hir::BindingAnnotation::Mutable,
+ );
+ let param = hir::Param {
+ hir_id: self.next_id(),
+ pat,
+ ty_span: self.lower_span(span),
+ span: self.lower_span(span),
+ };
+ let params = arena_vec![self; param];
+
+ let body = self.lower_body(move |this| {
+ this.generator_kind = Some(hir::GeneratorKind::Async(async_gen_kind));
+
+ let old_ctx = this.task_context;
+ this.task_context = Some(task_context_hid);
+ let res = body(this);
+ this.task_context = old_ctx;
+ (params, res)
+ });
+
+ // `static |_task_context| -> <ret_ty> { body }`:
+ let generator_kind = {
+ let c = self.arena.alloc(hir::Closure {
+ binder: hir::ClosureBinder::Default,
+ capture_clause,
+ bound_generic_params: &[],
+ fn_decl,
+ body,
+ fn_decl_span: self.lower_span(span),
+ movability: Some(hir::Movability::Static),
+ });
+
+ hir::ExprKind::Closure(c)
+ };
+ let generator = hir::Expr {
+ hir_id: self.lower_node_id(closure_node_id),
+ kind: generator_kind,
+ span: self.lower_span(span),
+ };
+
+ // `future::from_generator`:
+ let unstable_span =
+ self.mark_span_with_reason(DesugaringKind::Async, span, self.allow_gen_future.clone());
+ let gen_future = self.expr_lang_item_path(
+ unstable_span,
+ hir::LangItem::FromGenerator,
+ ThinVec::new(),
+ None,
+ );
+
+ // `future::from_generator(generator)`:
+ hir::ExprKind::Call(self.arena.alloc(gen_future), arena_vec![self; generator])
+ }
+
+ /// Desugar `<expr>.await` into:
+ /// ```ignore (pseudo-rust)
+ /// match ::std::future::IntoFuture::into_future(<expr>) {
+ /// mut __awaitee => loop {
+ /// match unsafe { ::std::future::Future::poll(
+ /// <::std::pin::Pin>::new_unchecked(&mut __awaitee),
+ /// ::std::future::get_context(task_context),
+ /// ) } {
+ /// ::std::task::Poll::Ready(result) => break result,
+ /// ::std::task::Poll::Pending => {}
+ /// }
+ /// task_context = yield ();
+ /// }
+ /// }
+ /// ```
+ fn lower_expr_await(&mut self, dot_await_span: Span, expr: &Expr) -> hir::ExprKind<'hir> {
+ let full_span = expr.span.to(dot_await_span);
+ match self.generator_kind {
+ Some(hir::GeneratorKind::Async(_)) => {}
+ Some(hir::GeneratorKind::Gen) | None => {
+ let mut err = struct_span_err!(
+ self.tcx.sess,
+ dot_await_span,
+ E0728,
+ "`await` is only allowed inside `async` functions and blocks"
+ );
+ err.span_label(dot_await_span, "only allowed inside `async` functions and blocks");
+ if let Some(item_sp) = self.current_item {
+ err.span_label(item_sp, "this is not `async`");
+ }
+ err.emit();
+ }
+ }
+ let span = self.mark_span_with_reason(DesugaringKind::Await, dot_await_span, None);
+ let gen_future_span = self.mark_span_with_reason(
+ DesugaringKind::Await,
+ full_span,
+ self.allow_gen_future.clone(),
+ );
+ let expr = self.lower_expr_mut(expr);
+ let expr_hir_id = expr.hir_id;
+
+ // Note that the name of this binding must not be changed to something else because
+ // debuggers and debugger extensions expect it to be called `__awaitee`. They use
+ // this name to identify what is being awaited by a suspended async functions.
+ let awaitee_ident = Ident::with_dummy_span(sym::__awaitee);
+ let (awaitee_pat, awaitee_pat_hid) =
+ self.pat_ident_binding_mode(span, awaitee_ident, hir::BindingAnnotation::Mutable);
+
+ let task_context_ident = Ident::with_dummy_span(sym::_task_context);
+
+ // unsafe {
+ // ::std::future::Future::poll(
+ // ::std::pin::Pin::new_unchecked(&mut __awaitee),
+ // ::std::future::get_context(task_context),
+ // )
+ // }
+ let poll_expr = {
+ let awaitee = self.expr_ident(span, awaitee_ident, awaitee_pat_hid);
+ let ref_mut_awaitee = self.expr_mut_addr_of(span, awaitee);
+ let task_context = if let Some(task_context_hid) = self.task_context {
+ self.expr_ident_mut(span, task_context_ident, task_context_hid)
+ } else {
+ // Use of `await` outside of an async context, we cannot use `task_context` here.
+ self.expr_err(span)
+ };
+ let new_unchecked = self.expr_call_lang_item_fn_mut(
+ span,
+ hir::LangItem::PinNewUnchecked,
+ arena_vec![self; ref_mut_awaitee],
+ Some(expr_hir_id),
+ );
+ let get_context = self.expr_call_lang_item_fn_mut(
+ gen_future_span,
+ hir::LangItem::GetContext,
+ arena_vec![self; task_context],
+ Some(expr_hir_id),
+ );
+ let call = self.expr_call_lang_item_fn(
+ span,
+ hir::LangItem::FuturePoll,
+ arena_vec![self; new_unchecked, get_context],
+ Some(expr_hir_id),
+ );
+ self.arena.alloc(self.expr_unsafe(call))
+ };
+
+ // `::std::task::Poll::Ready(result) => break result`
+ let loop_node_id = self.next_node_id();
+ let loop_hir_id = self.lower_node_id(loop_node_id);
+ let ready_arm = {
+ let x_ident = Ident::with_dummy_span(sym::result);
+ let (x_pat, x_pat_hid) = self.pat_ident(gen_future_span, x_ident);
+ let x_expr = self.expr_ident(gen_future_span, x_ident, x_pat_hid);
+ let ready_field = self.single_pat_field(gen_future_span, x_pat);
+ let ready_pat = self.pat_lang_item_variant(
+ span,
+ hir::LangItem::PollReady,
+ ready_field,
+ Some(expr_hir_id),
+ );
+ let break_x = self.with_loop_scope(loop_node_id, move |this| {
+ let expr_break =
+ hir::ExprKind::Break(this.lower_loop_destination(None), Some(x_expr));
+ this.arena.alloc(this.expr(gen_future_span, expr_break, ThinVec::new()))
+ });
+ self.arm(ready_pat, break_x)
+ };
+
+ // `::std::task::Poll::Pending => {}`
+ let pending_arm = {
+ let pending_pat = self.pat_lang_item_variant(
+ span,
+ hir::LangItem::PollPending,
+ &[],
+ Some(expr_hir_id),
+ );
+ let empty_block = self.expr_block_empty(span);
+ self.arm(pending_pat, empty_block)
+ };
+
+ let inner_match_stmt = {
+ let match_expr = self.expr_match(
+ span,
+ poll_expr,
+ arena_vec![self; ready_arm, pending_arm],
+ hir::MatchSource::AwaitDesugar,
+ );
+ self.stmt_expr(span, match_expr)
+ };
+
+ // task_context = yield ();
+ let yield_stmt = {
+ let unit = self.expr_unit(span);
+ let yield_expr = self.expr(
+ span,
+ hir::ExprKind::Yield(unit, hir::YieldSource::Await { expr: Some(expr_hir_id) }),
+ ThinVec::new(),
+ );
+ let yield_expr = self.arena.alloc(yield_expr);
+
+ if let Some(task_context_hid) = self.task_context {
+ let lhs = self.expr_ident(span, task_context_ident, task_context_hid);
+ let assign = self.expr(
+ span,
+ hir::ExprKind::Assign(lhs, yield_expr, self.lower_span(span)),
+ AttrVec::new(),
+ );
+ self.stmt_expr(span, assign)
+ } else {
+ // Use of `await` outside of an async context. Return `yield_expr` so that we can
+ // proceed with type checking.
+ self.stmt(span, hir::StmtKind::Semi(yield_expr))
+ }
+ };
+
+ let loop_block = self.block_all(span, arena_vec![self; inner_match_stmt, yield_stmt], None);
+
+ // loop { .. }
+ let loop_expr = self.arena.alloc(hir::Expr {
+ hir_id: loop_hir_id,
+ kind: hir::ExprKind::Loop(
+ loop_block,
+ None,
+ hir::LoopSource::Loop,
+ self.lower_span(span),
+ ),
+ span: self.lower_span(span),
+ });
+
+ // mut __awaitee => loop { ... }
+ let awaitee_arm = self.arm(awaitee_pat, loop_expr);
+
+ // `match ::std::future::IntoFuture::into_future(<expr>) { ... }`
+ let into_future_span = self.mark_span_with_reason(
+ DesugaringKind::Await,
+ dot_await_span,
+ self.allow_into_future.clone(),
+ );
+ let into_future_expr = self.expr_call_lang_item_fn(
+ into_future_span,
+ hir::LangItem::IntoFutureIntoFuture,
+ arena_vec![self; expr],
+ Some(expr_hir_id),
+ );
+
+ // match <into_future_expr> {
+ // mut __awaitee => loop { .. }
+ // }
+ hir::ExprKind::Match(
+ into_future_expr,
+ arena_vec![self; awaitee_arm],
+ hir::MatchSource::AwaitDesugar,
+ )
+ }
+
+ fn lower_expr_closure(
+ &mut self,
+ binder: &ClosureBinder,
+ capture_clause: CaptureBy,
+ closure_id: NodeId,
+ movability: Movability,
+ decl: &FnDecl,
+ body: &Expr,
+ fn_decl_span: Span,
+ ) -> hir::ExprKind<'hir> {
+ let (binder_clause, generic_params) = self.lower_closure_binder(binder);
+
+ let (body_id, generator_option) = self.with_new_scopes(move |this| {
+ let prev = this.current_item;
+ this.current_item = Some(fn_decl_span);
+ let mut generator_kind = None;
+ let body_id = this.lower_fn_body(decl, |this| {
+ let e = this.lower_expr_mut(body);
+ generator_kind = this.generator_kind;
+ e
+ });
+ let generator_option =
+ this.generator_movability_for_fn(&decl, fn_decl_span, generator_kind, movability);
+ this.current_item = prev;
+ (body_id, generator_option)
+ });
+
+ let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);
+ // Lower outside new scope to preserve `is_in_loop_condition`.
+ let fn_decl = self.lower_fn_decl(decl, None, FnDeclKind::Closure, None);
+
+ let c = self.arena.alloc(hir::Closure {
+ binder: binder_clause,
+ capture_clause,
+ bound_generic_params,
+ fn_decl,
+ body: body_id,
+ fn_decl_span: self.lower_span(fn_decl_span),
+ movability: generator_option,
+ });
+
+ hir::ExprKind::Closure(c)
+ }
+
+ fn generator_movability_for_fn(
+ &mut self,
+ decl: &FnDecl,
+ fn_decl_span: Span,
+ generator_kind: Option<hir::GeneratorKind>,
+ movability: Movability,
+ ) -> Option<hir::Movability> {
+ match generator_kind {
+ Some(hir::GeneratorKind::Gen) => {
+ if decl.inputs.len() > 1 {
+ struct_span_err!(
+ self.tcx.sess,
+ fn_decl_span,
+ E0628,
+ "too many parameters for a generator (expected 0 or 1 parameters)"
+ )
+ .emit();
+ }
+ Some(movability)
+ }
+ Some(hir::GeneratorKind::Async(_)) => {
+ panic!("non-`async` closure body turned `async` during lowering");
+ }
+ None => {
+ if movability == Movability::Static {
+ struct_span_err!(
+ self.tcx.sess,
+ fn_decl_span,
+ E0697,
+ "closures cannot be static"
+ )
+ .emit();
+ }
+ None
+ }
+ }
+ }
+
+ fn lower_closure_binder<'c>(
+ &mut self,
+ binder: &'c ClosureBinder,
+ ) -> (hir::ClosureBinder, &'c [GenericParam]) {
+ let (binder, params) = match binder {
+ ClosureBinder::NotPresent => (hir::ClosureBinder::Default, &[][..]),
+ &ClosureBinder::For { span, ref generic_params } => {
+ let span = self.lower_span(span);
+ (hir::ClosureBinder::For { span }, &**generic_params)
+ }
+ };
+
+ (binder, params)
+ }
+
+ fn lower_expr_async_closure(
+ &mut self,
+ binder: &ClosureBinder,
+ capture_clause: CaptureBy,
+ closure_id: NodeId,
+ inner_closure_id: NodeId,
+ decl: &FnDecl,
+ body: &Expr,
+ fn_decl_span: Span,
+ ) -> hir::ExprKind<'hir> {
+ if let &ClosureBinder::For { span, .. } = binder {
+ self.tcx.sess.span_err(
+ span,
+ "`for<...>` binders on `async` closures are not currently supported",
+ );
+ }
+
+ let (binder_clause, generic_params) = self.lower_closure_binder(binder);
+
+ let outer_decl =
+ FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) };
+
+ let body = self.with_new_scopes(|this| {
+ // FIXME(cramertj): allow `async` non-`move` closures with arguments.
+ if capture_clause == CaptureBy::Ref && !decl.inputs.is_empty() {
+ struct_span_err!(
+ this.tcx.sess,
+ fn_decl_span,
+ E0708,
+ "`async` non-`move` closures with parameters are not currently supported",
+ )
+ .help(
+ "consider using `let` statements to manually capture \
+ variables by reference before entering an `async move` closure",
+ )
+ .emit();
+ }
+
+ // Transform `async |x: u8| -> X { ... }` into
+ // `|x: u8| future_from_generator(|| -> X { ... })`.
+ let body_id = this.lower_fn_body(&outer_decl, |this| {
+ let async_ret_ty =
+ if let FnRetTy::Ty(ty) = &decl.output { Some(ty.clone()) } else { None };
+ let async_body = this.make_async_expr(
+ capture_clause,
+ inner_closure_id,
+ async_ret_ty,
+ body.span,
+ hir::AsyncGeneratorKind::Closure,
+ |this| this.with_new_scopes(|this| this.lower_expr_mut(body)),
+ );
+ this.expr(fn_decl_span, async_body, ThinVec::new())
+ });
+ body_id
+ });
+
+ let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);
+
+ // We need to lower the declaration outside the new scope, because we
+ // have to conserve the state of being inside a loop condition for the
+ // closure argument types.
+ let fn_decl = self.lower_fn_decl(&outer_decl, None, FnDeclKind::Closure, None);
+
+ let c = self.arena.alloc(hir::Closure {
+ binder: binder_clause,
+ capture_clause,
+ bound_generic_params,
+ fn_decl,
+ body,
+ fn_decl_span: self.lower_span(fn_decl_span),
+ movability: None,
+ });
+ hir::ExprKind::Closure(c)
+ }
+
+ /// Destructure the LHS of complex assignments.
+ /// For instance, lower `(a, b) = t` to `{ let (lhs1, lhs2) = t; a = lhs1; b = lhs2; }`.
+ fn lower_expr_assign(
+ &mut self,
+ lhs: &Expr,
+ rhs: &Expr,
+ eq_sign_span: Span,
+ whole_span: Span,
+ ) -> hir::ExprKind<'hir> {
+ // Return early in case of an ordinary assignment.
+ fn is_ordinary(lower_ctx: &mut LoweringContext<'_, '_>, lhs: &Expr) -> bool {
+ match &lhs.kind {
+ ExprKind::Array(..)
+ | ExprKind::Struct(..)
+ | ExprKind::Tup(..)
+ | ExprKind::Underscore => false,
+ // Check for tuple struct constructor.
+ ExprKind::Call(callee, ..) => lower_ctx.extract_tuple_struct_path(callee).is_none(),
+ ExprKind::Paren(e) => {
+ match e.kind {
+ // We special-case `(..)` for consistency with patterns.
+ ExprKind::Range(None, None, RangeLimits::HalfOpen) => false,
+ _ => is_ordinary(lower_ctx, e),
+ }
+ }
+ _ => true,
+ }
+ }
+ if is_ordinary(self, lhs) {
+ return hir::ExprKind::Assign(
+ self.lower_expr(lhs),
+ self.lower_expr(rhs),
+ self.lower_span(eq_sign_span),
+ );
+ }
+
+ let mut assignments = vec![];
+
+ // The LHS becomes a pattern: `(lhs1, lhs2)`.
+ let pat = self.destructure_assign(lhs, eq_sign_span, &mut assignments);
+ let rhs = self.lower_expr(rhs);
+
+ // Introduce a `let` for destructuring: `let (lhs1, lhs2) = t`.
+ let destructure_let = self.stmt_let_pat(
+ None,
+ whole_span,
+ Some(rhs),
+ pat,
+ hir::LocalSource::AssignDesugar(self.lower_span(eq_sign_span)),
+ );
+
+ // `a = lhs1; b = lhs2;`.
+ let stmts = self
+ .arena
+ .alloc_from_iter(std::iter::once(destructure_let).chain(assignments.into_iter()));
+
+ // Wrap everything in a block.
+ hir::ExprKind::Block(&self.block_all(whole_span, stmts, None), None)
+ }
+
+ /// If the given expression is a path to a tuple struct, returns that path.
+ /// It is not a complete check, but just tries to reject most paths early
+ /// if they are not tuple structs.
+ /// Type checking will take care of the full validation later.
+ fn extract_tuple_struct_path<'a>(
+ &mut self,
+ expr: &'a Expr,
+ ) -> Option<(&'a Option<QSelf>, &'a Path)> {
+ if let ExprKind::Path(qself, path) = &expr.kind {
+ // Does the path resolve to something disallowed in a tuple struct/variant pattern?
+ if let Some(partial_res) = self.resolver.get_partial_res(expr.id) {
+ if partial_res.unresolved_segments() == 0
+ && !partial_res.base_res().expected_in_tuple_struct_pat()
+ {
+ return None;
+ }
+ }
+ return Some((qself, path));
+ }
+ None
+ }
+
+ /// If the given expression is a path to a unit struct, returns that path.
+ /// It is not a complete check, but just tries to reject most paths early
+ /// if they are not unit structs.
+ /// Type checking will take care of the full validation later.
+ fn extract_unit_struct_path<'a>(
+ &mut self,
+ expr: &'a Expr,
+ ) -> Option<(&'a Option<QSelf>, &'a Path)> {
+ if let ExprKind::Path(qself, path) = &expr.kind {
+ // Does the path resolve to something disallowed in a unit struct/variant pattern?
+ if let Some(partial_res) = self.resolver.get_partial_res(expr.id) {
+ if partial_res.unresolved_segments() == 0
+ && !partial_res.base_res().expected_in_unit_struct_pat()
+ {
+ return None;
+ }
+ }
+ return Some((qself, path));
+ }
+ None
+ }
+
+ /// Convert the LHS of a destructuring assignment to a pattern.
+ /// Each sub-assignment is recorded in `assignments`.
+ fn destructure_assign(
+ &mut self,
+ lhs: &Expr,
+ eq_sign_span: Span,
+ assignments: &mut Vec<hir::Stmt<'hir>>,
+ ) -> &'hir hir::Pat<'hir> {
+ self.arena.alloc(self.destructure_assign_mut(lhs, eq_sign_span, assignments))
+ }
+
+ fn destructure_assign_mut(
+ &mut self,
+ lhs: &Expr,
+ eq_sign_span: Span,
+ assignments: &mut Vec<hir::Stmt<'hir>>,
+ ) -> hir::Pat<'hir> {
+ match &lhs.kind {
+ // Underscore pattern.
+ ExprKind::Underscore => {
+ return self.pat_without_dbm(lhs.span, hir::PatKind::Wild);
+ }
+ // Slice patterns.
+ ExprKind::Array(elements) => {
+ let (pats, rest) =
+ self.destructure_sequence(elements, "slice", eq_sign_span, assignments);
+ let slice_pat = if let Some((i, span)) = rest {
+ let (before, after) = pats.split_at(i);
+ hir::PatKind::Slice(
+ before,
+ Some(self.arena.alloc(self.pat_without_dbm(span, hir::PatKind::Wild))),
+ after,
+ )
+ } else {
+ hir::PatKind::Slice(pats, None, &[])
+ };
+ return self.pat_without_dbm(lhs.span, slice_pat);
+ }
+ // Tuple structs.
+ ExprKind::Call(callee, args) => {
+ if let Some((qself, path)) = self.extract_tuple_struct_path(callee) {
+ let (pats, rest) = self.destructure_sequence(
+ args,
+ "tuple struct or variant",
+ eq_sign_span,
+ assignments,
+ );
+ let qpath = self.lower_qpath(
+ callee.id,
+ qself,
+ path,
+ ParamMode::Optional,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+ );
+ // Destructure like a tuple struct.
+ let tuple_struct_pat =
+ hir::PatKind::TupleStruct(qpath, pats, rest.map(|r| r.0));
+ return self.pat_without_dbm(lhs.span, tuple_struct_pat);
+ }
+ }
+ // Unit structs and enum variants.
+ ExprKind::Path(..) => {
+ if let Some((qself, path)) = self.extract_unit_struct_path(lhs) {
+ let qpath = self.lower_qpath(
+ lhs.id,
+ qself,
+ path,
+ ParamMode::Optional,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+ );
+ // Destructure like a unit struct.
+ let unit_struct_pat = hir::PatKind::Path(qpath);
+ return self.pat_without_dbm(lhs.span, unit_struct_pat);
+ }
+ }
+ // Structs.
+ ExprKind::Struct(se) => {
+ let field_pats = self.arena.alloc_from_iter(se.fields.iter().map(|f| {
+ let pat = self.destructure_assign(&f.expr, eq_sign_span, assignments);
+ hir::PatField {
+ hir_id: self.next_id(),
+ ident: self.lower_ident(f.ident),
+ pat,
+ is_shorthand: f.is_shorthand,
+ span: self.lower_span(f.span),
+ }
+ }));
+ let qpath = self.lower_qpath(
+ lhs.id,
+ &se.qself,
+ &se.path,
+ ParamMode::Optional,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+ );
+ let fields_omitted = match &se.rest {
+ StructRest::Base(e) => {
+ self.tcx
+ .sess
+ .struct_span_err(
+ e.span,
+ "functional record updates are not allowed in destructuring \
+ assignments",
+ )
+ .span_suggestion(
+ e.span,
+ "consider removing the trailing pattern",
+ "",
+ rustc_errors::Applicability::MachineApplicable,
+ )
+ .emit();
+ true
+ }
+ StructRest::Rest(_) => true,
+ StructRest::None => false,
+ };
+ let struct_pat = hir::PatKind::Struct(qpath, field_pats, fields_omitted);
+ return self.pat_without_dbm(lhs.span, struct_pat);
+ }
+ // Tuples.
+ ExprKind::Tup(elements) => {
+ let (pats, rest) =
+ self.destructure_sequence(elements, "tuple", eq_sign_span, assignments);
+ let tuple_pat = hir::PatKind::Tuple(pats, rest.map(|r| r.0));
+ return self.pat_without_dbm(lhs.span, tuple_pat);
+ }
+ ExprKind::Paren(e) => {
+ // We special-case `(..)` for consistency with patterns.
+ if let ExprKind::Range(None, None, RangeLimits::HalfOpen) = e.kind {
+ let tuple_pat = hir::PatKind::Tuple(&[], Some(0));
+ return self.pat_without_dbm(lhs.span, tuple_pat);
+ } else {
+ return self.destructure_assign_mut(e, eq_sign_span, assignments);
+ }
+ }
+ _ => {}
+ }
+ // Treat all other cases as normal lvalue.
+ let ident = Ident::new(sym::lhs, self.lower_span(lhs.span));
+ let (pat, binding) = self.pat_ident_mut(lhs.span, ident);
+ let ident = self.expr_ident(lhs.span, ident, binding);
+ let assign =
+ hir::ExprKind::Assign(self.lower_expr(lhs), ident, self.lower_span(eq_sign_span));
+ let expr = self.expr(lhs.span, assign, ThinVec::new());
+ assignments.push(self.stmt_expr(lhs.span, expr));
+ pat
+ }
+
+ /// Destructure a sequence of expressions occurring on the LHS of an assignment.
+ /// Such a sequence occurs in a tuple (struct)/slice.
+ /// Return a sequence of corresponding patterns, and the index and the span of `..` if it
+ /// exists.
+ /// Each sub-assignment is recorded in `assignments`.
+ fn destructure_sequence(
+ &mut self,
+ elements: &[AstP<Expr>],
+ ctx: &str,
+ eq_sign_span: Span,
+ assignments: &mut Vec<hir::Stmt<'hir>>,
+ ) -> (&'hir [hir::Pat<'hir>], Option<(usize, Span)>) {
+ let mut rest = None;
+ let elements =
+ self.arena.alloc_from_iter(elements.iter().enumerate().filter_map(|(i, e)| {
+ // Check for `..` pattern.
+ if let ExprKind::Range(None, None, RangeLimits::HalfOpen) = e.kind {
+ if let Some((_, prev_span)) = rest {
+ self.ban_extra_rest_pat(e.span, prev_span, ctx);
+ } else {
+ rest = Some((i, e.span));
+ }
+ None
+ } else {
+ Some(self.destructure_assign_mut(e, eq_sign_span, assignments))
+ }
+ }));
+ (elements, rest)
+ }
+
+ /// Desugar `<start>..=<end>` into `std::ops::RangeInclusive::new(<start>, <end>)`.
+ fn lower_expr_range_closed(&mut self, span: Span, e1: &Expr, e2: &Expr) -> hir::ExprKind<'hir> {
+ let e1 = self.lower_expr_mut(e1);
+ let e2 = self.lower_expr_mut(e2);
+ let fn_path =
+ hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, self.lower_span(span), None);
+ let fn_expr =
+ self.arena.alloc(self.expr(span, hir::ExprKind::Path(fn_path), ThinVec::new()));
+ hir::ExprKind::Call(fn_expr, arena_vec![self; e1, e2])
+ }
+
+ fn lower_expr_range(
+ &mut self,
+ span: Span,
+ e1: Option<&Expr>,
+ e2: Option<&Expr>,
+ lims: RangeLimits,
+ ) -> hir::ExprKind<'hir> {
+ use rustc_ast::RangeLimits::*;
+
+ let lang_item = match (e1, e2, lims) {
+ (None, None, HalfOpen) => hir::LangItem::RangeFull,
+ (Some(..), None, HalfOpen) => hir::LangItem::RangeFrom,
+ (None, Some(..), HalfOpen) => hir::LangItem::RangeTo,
+ (Some(..), Some(..), HalfOpen) => hir::LangItem::Range,
+ (None, Some(..), Closed) => hir::LangItem::RangeToInclusive,
+ (Some(..), Some(..), Closed) => unreachable!(),
+ (_, None, Closed) => self.diagnostic().span_fatal(span, "inclusive range with no end"),
+ };
+
+ let fields = self.arena.alloc_from_iter(
+ e1.iter().map(|e| (sym::start, e)).chain(e2.iter().map(|e| (sym::end, e))).map(
+ |(s, e)| {
+ let expr = self.lower_expr(&e);
+ let ident = Ident::new(s, self.lower_span(e.span));
+ self.expr_field(ident, expr, e.span)
+ },
+ ),
+ );
+
+ hir::ExprKind::Struct(
+ self.arena.alloc(hir::QPath::LangItem(lang_item, self.lower_span(span), None)),
+ fields,
+ None,
+ )
+ }
+
+ fn lower_label(&self, opt_label: Option<Label>) -> Option<Label> {
+ let label = opt_label?;
+ Some(Label { ident: self.lower_ident(label.ident) })
+ }
+
+ fn lower_loop_destination(&mut self, destination: Option<(NodeId, Label)>) -> hir::Destination {
+ let target_id = match destination {
+ Some((id, _)) => {
+ if let Some(loop_id) = self.resolver.get_label_res(id) {
+ Ok(self.lower_node_id(loop_id))
+ } else {
+ Err(hir::LoopIdError::UnresolvedLabel)
+ }
+ }
+ None => self
+ .loop_scope
+ .map(|id| Ok(self.lower_node_id(id)))
+ .unwrap_or(Err(hir::LoopIdError::OutsideLoopScope)),
+ };
+ let label = self.lower_label(destination.map(|(_, label)| label));
+ hir::Destination { label, target_id }
+ }
+
+ fn lower_jump_destination(&mut self, id: NodeId, opt_label: Option<Label>) -> hir::Destination {
+ if self.is_in_loop_condition && opt_label.is_none() {
+ hir::Destination {
+ label: None,
+ target_id: Err(hir::LoopIdError::UnlabeledCfInWhileCondition),
+ }
+ } else {
+ self.lower_loop_destination(opt_label.map(|label| (id, label)))
+ }
+ }
+
+ fn with_catch_scope<T>(&mut self, catch_id: NodeId, f: impl FnOnce(&mut Self) -> T) -> T {
+ let old_scope = self.catch_scope.replace(catch_id);
+ let result = f(self);
+ self.catch_scope = old_scope;
+ result
+ }
+
+ fn with_loop_scope<T>(&mut self, loop_id: NodeId, f: impl FnOnce(&mut Self) -> T) -> T {
+ // We're no longer in the base loop's condition; we're in another loop.
+ let was_in_loop_condition = self.is_in_loop_condition;
+ self.is_in_loop_condition = false;
+
+ let old_scope = self.loop_scope.replace(loop_id);
+ let result = f(self);
+ self.loop_scope = old_scope;
+
+ self.is_in_loop_condition = was_in_loop_condition;
+
+ result
+ }
+
+ fn with_loop_condition_scope<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> T {
+ let was_in_loop_condition = self.is_in_loop_condition;
+ self.is_in_loop_condition = true;
+
+ let result = f(self);
+
+ self.is_in_loop_condition = was_in_loop_condition;
+
+ result
+ }
+
+ fn lower_expr_field(&mut self, f: &ExprField) -> hir::ExprField<'hir> {
+ hir::ExprField {
+ hir_id: self.next_id(),
+ ident: self.lower_ident(f.ident),
+ expr: self.lower_expr(&f.expr),
+ span: self.lower_span(f.span),
+ is_shorthand: f.is_shorthand,
+ }
+ }
+
+ fn lower_expr_yield(&mut self, span: Span, opt_expr: Option<&Expr>) -> hir::ExprKind<'hir> {
+ match self.generator_kind {
+ Some(hir::GeneratorKind::Gen) => {}
+ Some(hir::GeneratorKind::Async(_)) => {
+ struct_span_err!(
+ self.tcx.sess,
+ span,
+ E0727,
+ "`async` generators are not yet supported"
+ )
+ .emit();
+ }
+ None => self.generator_kind = Some(hir::GeneratorKind::Gen),
+ }
+
+ let expr =
+ opt_expr.as_ref().map(|x| self.lower_expr(x)).unwrap_or_else(|| self.expr_unit(span));
+
+ hir::ExprKind::Yield(expr, hir::YieldSource::Yield)
+ }
+
+ /// Desugar `ExprForLoop` from: `[opt_ident]: for <pat> in <head> <body>` into:
+ /// ```ignore (pseudo-rust)
+ /// {
+ /// let result = match IntoIterator::into_iter(<head>) {
+ /// mut iter => {
+ /// [opt_ident]: loop {
+ /// match Iterator::next(&mut iter) {
+ /// None => break,
+ /// Some(<pat>) => <body>,
+ /// };
+ /// }
+ /// }
+ /// };
+ /// result
+ /// }
+ /// ```
+ fn lower_expr_for(
+ &mut self,
+ e: &Expr,
+ pat: &Pat,
+ head: &Expr,
+ body: &Block,
+ opt_label: Option<Label>,
+ ) -> hir::Expr<'hir> {
+ let head = self.lower_expr_mut(head);
+ let pat = self.lower_pat(pat);
+ let for_span =
+ self.mark_span_with_reason(DesugaringKind::ForLoop, self.lower_span(e.span), None);
+ let head_span = self.mark_span_with_reason(DesugaringKind::ForLoop, head.span, None);
+ let pat_span = self.mark_span_with_reason(DesugaringKind::ForLoop, pat.span, None);
+
+ // `None => break`
+ let none_arm = {
+ let break_expr =
+ self.with_loop_scope(e.id, |this| this.expr_break_alloc(for_span, ThinVec::new()));
+ let pat = self.pat_none(for_span);
+ self.arm(pat, break_expr)
+ };
+
+ // Some(<pat>) => <body>,
+ let some_arm = {
+ let some_pat = self.pat_some(pat_span, pat);
+ let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false));
+ let body_expr = self.arena.alloc(self.expr_block(body_block, ThinVec::new()));
+ self.arm(some_pat, body_expr)
+ };
+
+ // `mut iter`
+ let iter = Ident::with_dummy_span(sym::iter);
+ let (iter_pat, iter_pat_nid) =
+ self.pat_ident_binding_mode(head_span, iter, hir::BindingAnnotation::Mutable);
+
+ // `match Iterator::next(&mut iter) { ... }`
+ let match_expr = {
+ let iter = self.expr_ident(head_span, iter, iter_pat_nid);
+ let ref_mut_iter = self.expr_mut_addr_of(head_span, iter);
+ let next_expr = self.expr_call_lang_item_fn(
+ head_span,
+ hir::LangItem::IteratorNext,
+ arena_vec![self; ref_mut_iter],
+ None,
+ );
+ let arms = arena_vec![self; none_arm, some_arm];
+
+ self.expr_match(head_span, next_expr, arms, hir::MatchSource::ForLoopDesugar)
+ };
+ let match_stmt = self.stmt_expr(for_span, match_expr);
+
+ let loop_block = self.block_all(for_span, arena_vec![self; match_stmt], None);
+
+ // `[opt_ident]: loop { ... }`
+ let kind = hir::ExprKind::Loop(
+ loop_block,
+ self.lower_label(opt_label),
+ hir::LoopSource::ForLoop,
+ self.lower_span(for_span.with_hi(head.span.hi())),
+ );
+ let loop_expr =
+ self.arena.alloc(hir::Expr { hir_id: self.lower_node_id(e.id), kind, span: for_span });
+
+ // `mut iter => { ... }`
+ let iter_arm = self.arm(iter_pat, loop_expr);
+
+ // `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
+ let into_iter_expr = {
+ self.expr_call_lang_item_fn(
+ head_span,
+ hir::LangItem::IntoIterIntoIter,
+ arena_vec![self; head],
+ None,
+ )
+ };
+
+ let match_expr = self.arena.alloc(self.expr_match(
+ for_span,
+ into_iter_expr,
+ arena_vec![self; iter_arm],
+ hir::MatchSource::ForLoopDesugar,
+ ));
+
+ let attrs: Vec<_> = e.attrs.iter().map(|a| self.lower_attr(a)).collect();
+
+ // This is effectively `{ let _result = ...; _result }`.
+ // The construct was introduced in #21984 and is necessary to make sure that
+ // temporaries in the `head` expression are dropped and do not leak to the
+ // surrounding scope of the `match` since the `match` is not a terminating scope.
+ //
+ // Also, add the attributes to the outer returned expr node.
+ self.expr_drop_temps_mut(for_span, match_expr, attrs.into())
+ }
+
+ /// Desugar `ExprKind::Try` from: `<expr>?` into:
+ /// ```ignore (pseudo-rust)
+ /// match Try::branch(<expr>) {
+ /// ControlFlow::Continue(val) => #[allow(unreachable_code)] val,,
+ /// ControlFlow::Break(residual) =>
+ /// #[allow(unreachable_code)]
+ /// // If there is an enclosing `try {...}`:
+ /// break 'catch_target Try::from_residual(residual),
+ /// // Otherwise:
+ /// return Try::from_residual(residual),
+ /// }
+ /// ```
+ fn lower_expr_try(&mut self, span: Span, sub_expr: &Expr) -> hir::ExprKind<'hir> {
+ let unstable_span = self.mark_span_with_reason(
+ DesugaringKind::QuestionMark,
+ span,
+ self.allow_try_trait.clone(),
+ );
+ let try_span = self.tcx.sess.source_map().end_point(span);
+ let try_span = self.mark_span_with_reason(
+ DesugaringKind::QuestionMark,
+ try_span,
+ self.allow_try_trait.clone(),
+ );
+
+ // `Try::branch(<expr>)`
+ let scrutinee = {
+ // expand <expr>
+ let sub_expr = self.lower_expr_mut(sub_expr);
+
+ self.expr_call_lang_item_fn(
+ unstable_span,
+ hir::LangItem::TryTraitBranch,
+ arena_vec![self; sub_expr],
+ None,
+ )
+ };
+
+ // `#[allow(unreachable_code)]`
+ let attr = {
+ // `allow(unreachable_code)`
+ let allow = {
+ let allow_ident = Ident::new(sym::allow, self.lower_span(span));
+ let uc_ident = Ident::new(sym::unreachable_code, self.lower_span(span));
+ let uc_nested = attr::mk_nested_word_item(uc_ident);
+ attr::mk_list_item(allow_ident, vec![uc_nested])
+ };
+ attr::mk_attr_outer(allow)
+ };
+ let attrs = vec![attr];
+
+ // `ControlFlow::Continue(val) => #[allow(unreachable_code)] val,`
+ let continue_arm = {
+ let val_ident = Ident::with_dummy_span(sym::val);
+ let (val_pat, val_pat_nid) = self.pat_ident(span, val_ident);
+ let val_expr = self.arena.alloc(self.expr_ident_with_attrs(
+ span,
+ val_ident,
+ val_pat_nid,
+ ThinVec::from(attrs.clone()),
+ ));
+ let continue_pat = self.pat_cf_continue(unstable_span, val_pat);
+ self.arm(continue_pat, val_expr)
+ };
+
+ // `ControlFlow::Break(residual) =>
+ // #[allow(unreachable_code)]
+ // return Try::from_residual(residual),`
+ let break_arm = {
+ let residual_ident = Ident::with_dummy_span(sym::residual);
+ let (residual_local, residual_local_nid) = self.pat_ident(try_span, residual_ident);
+ let residual_expr = self.expr_ident_mut(try_span, residual_ident, residual_local_nid);
+ let from_residual_expr = self.wrap_in_try_constructor(
+ hir::LangItem::TryTraitFromResidual,
+ try_span,
+ self.arena.alloc(residual_expr),
+ unstable_span,
+ );
+ let thin_attrs = ThinVec::from(attrs);
+ let ret_expr = if let Some(catch_node) = self.catch_scope {
+ let target_id = Ok(self.lower_node_id(catch_node));
+ self.arena.alloc(self.expr(
+ try_span,
+ hir::ExprKind::Break(
+ hir::Destination { label: None, target_id },
+ Some(from_residual_expr),
+ ),
+ thin_attrs,
+ ))
+ } else {
+ self.arena.alloc(self.expr(
+ try_span,
+ hir::ExprKind::Ret(Some(from_residual_expr)),
+ thin_attrs,
+ ))
+ };
+
+ let break_pat = self.pat_cf_break(try_span, residual_local);
+ self.arm(break_pat, ret_expr)
+ };
+
+ hir::ExprKind::Match(
+ scrutinee,
+ arena_vec![self; break_arm, continue_arm],
+ hir::MatchSource::TryDesugar,
+ )
+ }
+
+ /// Desugar `ExprKind::Yeet` from: `do yeet <expr>` into:
+ /// ```rust
+ /// // If there is an enclosing `try {...}`:
+ /// break 'catch_target FromResidual::from_residual(Yeet(residual)),
+ /// // Otherwise:
+ /// return FromResidual::from_residual(Yeet(residual)),
+ /// ```
+ /// But to simplify this, there's a `from_yeet` lang item function which
+ /// handles the combined `FromResidual::from_residual(Yeet(residual))`.
+ fn lower_expr_yeet(&mut self, span: Span, sub_expr: Option<&Expr>) -> hir::ExprKind<'hir> {
+ // The expression (if present) or `()` otherwise.
+ let (yeeted_span, yeeted_expr) = if let Some(sub_expr) = sub_expr {
+ (sub_expr.span, self.lower_expr(sub_expr))
+ } else {
+ (self.mark_span_with_reason(DesugaringKind::YeetExpr, span, None), self.expr_unit(span))
+ };
+
+ let unstable_span = self.mark_span_with_reason(
+ DesugaringKind::YeetExpr,
+ span,
+ self.allow_try_trait.clone(),
+ );
+
+ let from_yeet_expr = self.wrap_in_try_constructor(
+ hir::LangItem::TryTraitFromYeet,
+ unstable_span,
+ yeeted_expr,
+ yeeted_span,
+ );
+
+ if let Some(catch_node) = self.catch_scope {
+ let target_id = Ok(self.lower_node_id(catch_node));
+ hir::ExprKind::Break(hir::Destination { label: None, target_id }, Some(from_yeet_expr))
+ } else {
+ hir::ExprKind::Ret(Some(from_yeet_expr))
+ }
+ }
+
+ // =========================================================================
+ // Helper methods for building HIR.
+ // =========================================================================
+
+ /// Wrap the given `expr` in a terminating scope using `hir::ExprKind::DropTemps`.
+ ///
+ /// In terms of drop order, it has the same effect as wrapping `expr` in
+ /// `{ let _t = $expr; _t }` but should provide better compile-time performance.
+ ///
+ /// The drop order can be important in e.g. `if expr { .. }`.
+ pub(super) fn expr_drop_temps(
+ &mut self,
+ span: Span,
+ expr: &'hir hir::Expr<'hir>,
+ attrs: AttrVec,
+ ) -> &'hir hir::Expr<'hir> {
+ self.arena.alloc(self.expr_drop_temps_mut(span, expr, attrs))
+ }
+
+ pub(super) fn expr_drop_temps_mut(
+ &mut self,
+ span: Span,
+ expr: &'hir hir::Expr<'hir>,
+ attrs: AttrVec,
+ ) -> hir::Expr<'hir> {
+ self.expr(span, hir::ExprKind::DropTemps(expr), attrs)
+ }
+
+ fn expr_match(
+ &mut self,
+ span: Span,
+ arg: &'hir hir::Expr<'hir>,
+ arms: &'hir [hir::Arm<'hir>],
+ source: hir::MatchSource,
+ ) -> hir::Expr<'hir> {
+ self.expr(span, hir::ExprKind::Match(arg, arms, source), ThinVec::new())
+ }
+
+ fn expr_break(&mut self, span: Span, attrs: AttrVec) -> hir::Expr<'hir> {
+ let expr_break = hir::ExprKind::Break(self.lower_loop_destination(None), None);
+ self.expr(span, expr_break, attrs)
+ }
+
+ fn expr_break_alloc(&mut self, span: Span, attrs: AttrVec) -> &'hir hir::Expr<'hir> {
+ let expr_break = self.expr_break(span, attrs);
+ self.arena.alloc(expr_break)
+ }
+
+ fn expr_mut_addr_of(&mut self, span: Span, e: &'hir hir::Expr<'hir>) -> hir::Expr<'hir> {
+ self.expr(
+ span,
+ hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Mut, e),
+ ThinVec::new(),
+ )
+ }
+
+ fn expr_unit(&mut self, sp: Span) -> &'hir hir::Expr<'hir> {
+ self.arena.alloc(self.expr(sp, hir::ExprKind::Tup(&[]), ThinVec::new()))
+ }
+
+ fn expr_call_mut(
+ &mut self,
+ span: Span,
+ e: &'hir hir::Expr<'hir>,
+ args: &'hir [hir::Expr<'hir>],
+ ) -> hir::Expr<'hir> {
+ self.expr(span, hir::ExprKind::Call(e, args), ThinVec::new())
+ }
+
+ fn expr_call(
+ &mut self,
+ span: Span,
+ e: &'hir hir::Expr<'hir>,
+ args: &'hir [hir::Expr<'hir>],
+ ) -> &'hir hir::Expr<'hir> {
+ self.arena.alloc(self.expr_call_mut(span, e, args))
+ }
+
+ fn expr_call_lang_item_fn_mut(
+ &mut self,
+ span: Span,
+ lang_item: hir::LangItem,
+ args: &'hir [hir::Expr<'hir>],
+ hir_id: Option<hir::HirId>,
+ ) -> hir::Expr<'hir> {
+ let path =
+ self.arena.alloc(self.expr_lang_item_path(span, lang_item, ThinVec::new(), hir_id));
+ self.expr_call_mut(span, path, args)
+ }
+
+ fn expr_call_lang_item_fn(
+ &mut self,
+ span: Span,
+ lang_item: hir::LangItem,
+ args: &'hir [hir::Expr<'hir>],
+ hir_id: Option<hir::HirId>,
+ ) -> &'hir hir::Expr<'hir> {
+ self.arena.alloc(self.expr_call_lang_item_fn_mut(span, lang_item, args, hir_id))
+ }
+
+ fn expr_lang_item_path(
+ &mut self,
+ span: Span,
+ lang_item: hir::LangItem,
+ attrs: AttrVec,
+ hir_id: Option<hir::HirId>,
+ ) -> hir::Expr<'hir> {
+ self.expr(
+ span,
+ hir::ExprKind::Path(hir::QPath::LangItem(lang_item, self.lower_span(span), hir_id)),
+ attrs,
+ )
+ }
+
+ pub(super) fn expr_ident(
+ &mut self,
+ sp: Span,
+ ident: Ident,
+ binding: hir::HirId,
+ ) -> &'hir hir::Expr<'hir> {
+ self.arena.alloc(self.expr_ident_mut(sp, ident, binding))
+ }
+
+ pub(super) fn expr_ident_mut(
+ &mut self,
+ sp: Span,
+ ident: Ident,
+ binding: hir::HirId,
+ ) -> hir::Expr<'hir> {
+ self.expr_ident_with_attrs(sp, ident, binding, ThinVec::new())
+ }
+
+ fn expr_ident_with_attrs(
+ &mut self,
+ span: Span,
+ ident: Ident,
+ binding: hir::HirId,
+ attrs: AttrVec,
+ ) -> hir::Expr<'hir> {
+ let expr_path = hir::ExprKind::Path(hir::QPath::Resolved(
+ None,
+ self.arena.alloc(hir::Path {
+ span: self.lower_span(span),
+ res: Res::Local(binding),
+ segments: arena_vec![self; hir::PathSegment::from_ident(ident)],
+ }),
+ ));
+
+ self.expr(span, expr_path, attrs)
+ }
+
+ fn expr_unsafe(&mut self, expr: &'hir hir::Expr<'hir>) -> hir::Expr<'hir> {
+ let hir_id = self.next_id();
+ let span = expr.span;
+ self.expr(
+ span,
+ hir::ExprKind::Block(
+ self.arena.alloc(hir::Block {
+ stmts: &[],
+ expr: Some(expr),
+ hir_id,
+ rules: hir::BlockCheckMode::UnsafeBlock(hir::UnsafeSource::CompilerGenerated),
+ span: self.lower_span(span),
+ targeted_by_break: false,
+ }),
+ None,
+ ),
+ ThinVec::new(),
+ )
+ }
+
+ fn expr_block_empty(&mut self, span: Span) -> &'hir hir::Expr<'hir> {
+ let blk = self.block_all(span, &[], None);
+ let expr = self.expr_block(blk, ThinVec::new());
+ self.arena.alloc(expr)
+ }
+
+ pub(super) fn expr_block(
+ &mut self,
+ b: &'hir hir::Block<'hir>,
+ attrs: AttrVec,
+ ) -> hir::Expr<'hir> {
+ self.expr(b.span, hir::ExprKind::Block(b, None), attrs)
+ }
+
+ pub(super) fn expr(
+ &mut self,
+ span: Span,
+ kind: hir::ExprKind<'hir>,
+ attrs: AttrVec,
+ ) -> hir::Expr<'hir> {
+ let hir_id = self.next_id();
+ self.lower_attrs(hir_id, &attrs);
+ hir::Expr { hir_id, kind, span: self.lower_span(span) }
+ }
+
+ fn expr_field(
+ &mut self,
+ ident: Ident,
+ expr: &'hir hir::Expr<'hir>,
+ span: Span,
+ ) -> hir::ExprField<'hir> {
+ hir::ExprField {
+ hir_id: self.next_id(),
+ ident,
+ span: self.lower_span(span),
+ expr,
+ is_shorthand: false,
+ }
+ }
+
+ fn arm(&mut self, pat: &'hir hir::Pat<'hir>, expr: &'hir hir::Expr<'hir>) -> hir::Arm<'hir> {
+ hir::Arm {
+ hir_id: self.next_id(),
+ pat,
+ guard: None,
+ span: self.lower_span(expr.span),
+ body: expr,
+ }
+ }
+}
diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs
new file mode 100644
index 000000000..d5af74d47
--- /dev/null
+++ b/compiler/rustc_ast_lowering/src/index.rs
@@ -0,0 +1,346 @@
+use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::sorted_map::SortedMap;
+use rustc_hir as hir;
+use rustc_hir::def_id::LocalDefId;
+use rustc_hir::definitions;
+use rustc_hir::intravisit::{self, Visitor};
+use rustc_hir::*;
+use rustc_index::vec::{Idx, IndexVec};
+use rustc_middle::span_bug;
+use rustc_session::Session;
+use rustc_span::source_map::SourceMap;
+use rustc_span::{Span, DUMMY_SP};
+
+use tracing::debug;
+
+/// A visitor that walks over the HIR and collects `Node`s into a HIR map.
+pub(super) struct NodeCollector<'a, 'hir> {
+ /// Source map
+ source_map: &'a SourceMap,
+ bodies: &'a SortedMap<ItemLocalId, &'hir Body<'hir>>,
+
+ /// Outputs
+ nodes: IndexVec<ItemLocalId, Option<ParentedNode<'hir>>>,
+ parenting: FxHashMap<LocalDefId, ItemLocalId>,
+
+ /// The parent of this node
+ parent_node: hir::ItemLocalId,
+
+ owner: LocalDefId,
+
+ definitions: &'a definitions::Definitions,
+}
+
+#[tracing::instrument(level = "debug", skip(sess, definitions, bodies))]
+pub(super) fn index_hir<'hir>(
+ sess: &Session,
+ definitions: &definitions::Definitions,
+ item: hir::OwnerNode<'hir>,
+ bodies: &SortedMap<ItemLocalId, &'hir Body<'hir>>,
+) -> (IndexVec<ItemLocalId, Option<ParentedNode<'hir>>>, FxHashMap<LocalDefId, ItemLocalId>) {
+ let mut nodes = IndexVec::new();
+ // This node's parent should never be accessed: the owner's parent is computed by the
+ // hir_owner_parent query. Make it invalid (= ItemLocalId::MAX) to force an ICE whenever it is
+ // used.
+ nodes.push(Some(ParentedNode { parent: ItemLocalId::INVALID, node: item.into() }));
+ let mut collector = NodeCollector {
+ source_map: sess.source_map(),
+ definitions,
+ owner: item.def_id(),
+ parent_node: ItemLocalId::new(0),
+ nodes,
+ bodies,
+ parenting: FxHashMap::default(),
+ };
+
+ match item {
+ OwnerNode::Crate(citem) => {
+ collector.visit_mod(&citem, citem.spans.inner_span, hir::CRATE_HIR_ID)
+ }
+ OwnerNode::Item(item) => collector.visit_item(item),
+ OwnerNode::TraitItem(item) => collector.visit_trait_item(item),
+ OwnerNode::ImplItem(item) => collector.visit_impl_item(item),
+ OwnerNode::ForeignItem(item) => collector.visit_foreign_item(item),
+ };
+
+ (collector.nodes, collector.parenting)
+}
+
+impl<'a, 'hir> NodeCollector<'a, 'hir> {
+ #[tracing::instrument(level = "debug", skip(self))]
+ fn insert(&mut self, span: Span, hir_id: HirId, node: Node<'hir>) {
+ debug_assert_eq!(self.owner, hir_id.owner);
+ debug_assert_ne!(hir_id.local_id.as_u32(), 0);
+
+ // Make sure that the DepNode of some node coincides with the HirId
+ // owner of that node.
+ if cfg!(debug_assertions) {
+ if hir_id.owner != self.owner {
+ span_bug!(
+ span,
+ "inconsistent DepNode at `{:?}` for `{:?}`: \
+ current_dep_node_owner={} ({:?}), hir_id.owner={} ({:?})",
+ self.source_map.span_to_diagnostic_string(span),
+ node,
+ self.definitions.def_path(self.owner).to_string_no_crate_verbose(),
+ self.owner,
+ self.definitions.def_path(hir_id.owner).to_string_no_crate_verbose(),
+ hir_id.owner,
+ )
+ }
+ }
+
+ self.nodes.insert(hir_id.local_id, ParentedNode { parent: self.parent_node, node: node });
+ }
+
+ fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_node_id: HirId, f: F) {
+ debug_assert_eq!(parent_node_id.owner, self.owner);
+ let parent_node = self.parent_node;
+ self.parent_node = parent_node_id.local_id;
+ f(self);
+ self.parent_node = parent_node;
+ }
+
+ fn insert_nested(&mut self, item: LocalDefId) {
+ self.parenting.insert(item, self.parent_node);
+ }
+}
+
+impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
+ /// Because we want to track parent items and so forth, enable
+ /// deep walking so that we walk nested items in the context of
+ /// their outer items.
+
+ fn visit_nested_item(&mut self, item: ItemId) {
+ debug!("visit_nested_item: {:?}", item);
+ self.insert_nested(item.def_id);
+ }
+
+ fn visit_nested_trait_item(&mut self, item_id: TraitItemId) {
+ self.insert_nested(item_id.def_id);
+ }
+
+ fn visit_nested_impl_item(&mut self, item_id: ImplItemId) {
+ self.insert_nested(item_id.def_id);
+ }
+
+ fn visit_nested_foreign_item(&mut self, foreign_id: ForeignItemId) {
+ self.insert_nested(foreign_id.def_id);
+ }
+
+ fn visit_nested_body(&mut self, id: BodyId) {
+ debug_assert_eq!(id.hir_id.owner, self.owner);
+ let body = self.bodies[&id.hir_id.local_id];
+ self.visit_body(body);
+ }
+
+ fn visit_param(&mut self, param: &'hir Param<'hir>) {
+ let node = Node::Param(param);
+ self.insert(param.pat.span, param.hir_id, node);
+ self.with_parent(param.hir_id, |this| {
+ intravisit::walk_param(this, param);
+ });
+ }
+
+ #[tracing::instrument(level = "debug", skip(self))]
+ fn visit_item(&mut self, i: &'hir Item<'hir>) {
+ debug_assert_eq!(i.def_id, self.owner);
+ self.with_parent(i.hir_id(), |this| {
+ if let ItemKind::Struct(ref struct_def, _) = i.kind {
+ // If this is a tuple or unit-like struct, register the constructor.
+ if let Some(ctor_hir_id) = struct_def.ctor_hir_id() {
+ this.insert(i.span, ctor_hir_id, Node::Ctor(struct_def));
+ }
+ }
+ intravisit::walk_item(this, i);
+ });
+ }
+
+ #[tracing::instrument(level = "debug", skip(self))]
+ fn visit_foreign_item(&mut self, fi: &'hir ForeignItem<'hir>) {
+ debug_assert_eq!(fi.def_id, self.owner);
+ self.with_parent(fi.hir_id(), |this| {
+ intravisit::walk_foreign_item(this, fi);
+ });
+ }
+
+ fn visit_generic_param(&mut self, param: &'hir GenericParam<'hir>) {
+ self.insert(param.span, param.hir_id, Node::GenericParam(param));
+ intravisit::walk_generic_param(self, param);
+ }
+
+ fn visit_const_param_default(&mut self, param: HirId, ct: &'hir AnonConst) {
+ self.with_parent(param, |this| {
+ intravisit::walk_const_param_default(this, ct);
+ })
+ }
+
+ #[tracing::instrument(level = "debug", skip(self))]
+ fn visit_trait_item(&mut self, ti: &'hir TraitItem<'hir>) {
+ debug_assert_eq!(ti.def_id, self.owner);
+ self.with_parent(ti.hir_id(), |this| {
+ intravisit::walk_trait_item(this, ti);
+ });
+ }
+
+ #[tracing::instrument(level = "debug", skip(self))]
+ fn visit_impl_item(&mut self, ii: &'hir ImplItem<'hir>) {
+ debug_assert_eq!(ii.def_id, self.owner);
+ self.with_parent(ii.hir_id(), |this| {
+ intravisit::walk_impl_item(this, ii);
+ });
+ }
+
+ fn visit_pat(&mut self, pat: &'hir Pat<'hir>) {
+ self.insert(pat.span, pat.hir_id, Node::Pat(pat));
+
+ self.with_parent(pat.hir_id, |this| {
+ intravisit::walk_pat(this, pat);
+ });
+ }
+
+ fn visit_arm(&mut self, arm: &'hir Arm<'hir>) {
+ let node = Node::Arm(arm);
+
+ self.insert(arm.span, arm.hir_id, node);
+
+ self.with_parent(arm.hir_id, |this| {
+ intravisit::walk_arm(this, arm);
+ });
+ }
+
+ fn visit_anon_const(&mut self, constant: &'hir AnonConst) {
+ self.insert(DUMMY_SP, constant.hir_id, Node::AnonConst(constant));
+
+ self.with_parent(constant.hir_id, |this| {
+ intravisit::walk_anon_const(this, constant);
+ });
+ }
+
+ fn visit_expr(&mut self, expr: &'hir Expr<'hir>) {
+ self.insert(expr.span, expr.hir_id, Node::Expr(expr));
+
+ self.with_parent(expr.hir_id, |this| {
+ intravisit::walk_expr(this, expr);
+ });
+ }
+
+ fn visit_stmt(&mut self, stmt: &'hir Stmt<'hir>) {
+ self.insert(stmt.span, stmt.hir_id, Node::Stmt(stmt));
+
+ self.with_parent(stmt.hir_id, |this| {
+ intravisit::walk_stmt(this, stmt);
+ });
+ }
+
+ fn visit_path_segment(&mut self, path_span: Span, path_segment: &'hir PathSegment<'hir>) {
+ if let Some(hir_id) = path_segment.hir_id {
+ self.insert(path_span, hir_id, Node::PathSegment(path_segment));
+ }
+ intravisit::walk_path_segment(self, path_span, path_segment);
+ }
+
+ fn visit_ty(&mut self, ty: &'hir Ty<'hir>) {
+ self.insert(ty.span, ty.hir_id, Node::Ty(ty));
+
+ self.with_parent(ty.hir_id, |this| {
+ intravisit::walk_ty(this, ty);
+ });
+ }
+
+ fn visit_infer(&mut self, inf: &'hir InferArg) {
+ self.insert(inf.span, inf.hir_id, Node::Infer(inf));
+
+ self.with_parent(inf.hir_id, |this| {
+ intravisit::walk_inf(this, inf);
+ });
+ }
+
+ fn visit_trait_ref(&mut self, tr: &'hir TraitRef<'hir>) {
+ self.insert(tr.path.span, tr.hir_ref_id, Node::TraitRef(tr));
+
+ self.with_parent(tr.hir_ref_id, |this| {
+ intravisit::walk_trait_ref(this, tr);
+ });
+ }
+
+ fn visit_fn(
+ &mut self,
+ fk: intravisit::FnKind<'hir>,
+ fd: &'hir FnDecl<'hir>,
+ b: BodyId,
+ s: Span,
+ id: HirId,
+ ) {
+ assert_eq!(self.owner, id.owner);
+ assert_eq!(self.parent_node, id.local_id);
+ intravisit::walk_fn(self, fk, fd, b, s, id);
+ }
+
+ fn visit_block(&mut self, block: &'hir Block<'hir>) {
+ self.insert(block.span, block.hir_id, Node::Block(block));
+ self.with_parent(block.hir_id, |this| {
+ intravisit::walk_block(this, block);
+ });
+ }
+
+ fn visit_local(&mut self, l: &'hir Local<'hir>) {
+ self.insert(l.span, l.hir_id, Node::Local(l));
+ self.with_parent(l.hir_id, |this| {
+ intravisit::walk_local(this, l);
+ })
+ }
+
+ fn visit_lifetime(&mut self, lifetime: &'hir Lifetime) {
+ self.insert(lifetime.span, lifetime.hir_id, Node::Lifetime(lifetime));
+ }
+
+ fn visit_variant(&mut self, v: &'hir Variant<'hir>, g: &'hir Generics<'hir>, item_id: HirId) {
+ self.insert(v.span, v.id, Node::Variant(v));
+ self.with_parent(v.id, |this| {
+ // Register the constructor of this variant.
+ if let Some(ctor_hir_id) = v.data.ctor_hir_id() {
+ this.insert(v.span, ctor_hir_id, Node::Ctor(&v.data));
+ }
+ intravisit::walk_variant(this, v, g, item_id);
+ });
+ }
+
+ fn visit_field_def(&mut self, field: &'hir FieldDef<'hir>) {
+ self.insert(field.span, field.hir_id, Node::Field(field));
+ self.with_parent(field.hir_id, |this| {
+ intravisit::walk_field_def(this, field);
+ });
+ }
+
+ fn visit_assoc_type_binding(&mut self, type_binding: &'hir TypeBinding<'hir>) {
+ self.insert(type_binding.span, type_binding.hir_id, Node::TypeBinding(type_binding));
+ self.with_parent(type_binding.hir_id, |this| {
+ intravisit::walk_assoc_type_binding(this, type_binding)
+ })
+ }
+
+ fn visit_trait_item_ref(&mut self, ii: &'hir TraitItemRef) {
+ // Do not visit the duplicate information in TraitItemRef. We want to
+ // map the actual nodes, not the duplicate ones in the *Ref.
+ let TraitItemRef { id, ident: _, kind: _, span: _ } = *ii;
+
+ self.visit_nested_trait_item(id);
+ }
+
+ fn visit_impl_item_ref(&mut self, ii: &'hir ImplItemRef) {
+ // Do not visit the duplicate information in ImplItemRef. We want to
+ // map the actual nodes, not the duplicate ones in the *Ref.
+ let ImplItemRef { id, ident: _, kind: _, span: _, trait_item_def_id: _ } = *ii;
+
+ self.visit_nested_impl_item(id);
+ }
+
+ fn visit_foreign_item_ref(&mut self, fi: &'hir ForeignItemRef) {
+ // Do not visit the duplicate information in ForeignItemRef. We want to
+ // map the actual nodes, not the duplicate ones in the *Ref.
+ let ForeignItemRef { id, ident: _, span: _ } = *fi;
+
+ self.visit_nested_foreign_item(id);
+ }
+}
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
new file mode 100644
index 000000000..ee4c0036f
--- /dev/null
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -0,0 +1,1513 @@
+use super::ResolverAstLoweringExt;
+use super::{AstOwner, ImplTraitContext, ImplTraitPosition};
+use super::{FnDeclKind, LoweringContext, ParamMode};
+
+use rustc_ast::ptr::P;
+use rustc_ast::visit::AssocCtxt;
+use rustc_ast::*;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::sorted_map::SortedMap;
+use rustc_errors::struct_span_err;
+use rustc_hir as hir;
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
+use rustc_hir::PredicateOrigin;
+use rustc_index::vec::{Idx, IndexVec};
+use rustc_middle::ty::{DefIdTree, ResolverAstLowering, TyCtxt};
+use rustc_span::source_map::DesugaringKind;
+use rustc_span::symbol::{kw, sym, Ident};
+use rustc_span::Span;
+use rustc_target::spec::abi;
+use smallvec::{smallvec, SmallVec};
+
+use std::iter;
+
+pub(super) struct ItemLowerer<'a, 'hir> {
+ pub(super) tcx: TyCtxt<'hir>,
+ pub(super) resolver: &'a mut ResolverAstLowering,
+ pub(super) ast_index: &'a IndexVec<LocalDefId, AstOwner<'a>>,
+ pub(super) owners: &'a mut IndexVec<LocalDefId, hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>>>,
+}
+
+/// When we have a ty alias we *may* have two where clauses. To give the best diagnostics, we set the span
+/// to the where clause that is preferred, if it exists. Otherwise, it sets the span to the other where
+/// clause if it exists.
+fn add_ty_alias_where_clause(
+ generics: &mut ast::Generics,
+ mut where_clauses: (TyAliasWhereClause, TyAliasWhereClause),
+ prefer_first: bool,
+) {
+ if !prefer_first {
+ where_clauses = (where_clauses.1, where_clauses.0);
+ }
+ if where_clauses.0.0 || !where_clauses.1.0 {
+ generics.where_clause.has_where_token = where_clauses.0.0;
+ generics.where_clause.span = where_clauses.0.1;
+ } else {
+ generics.where_clause.has_where_token = where_clauses.1.0;
+ generics.where_clause.span = where_clauses.1.1;
+ }
+}
+
+impl<'a, 'hir> ItemLowerer<'a, 'hir> {
+ fn with_lctx(
+ &mut self,
+ owner: NodeId,
+ f: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::OwnerNode<'hir>,
+ ) {
+ let mut lctx = LoweringContext {
+ // Pseudo-globals.
+ tcx: self.tcx,
+ resolver: self.resolver,
+ arena: self.tcx.hir_arena,
+
+ // HirId handling.
+ bodies: Vec::new(),
+ attrs: SortedMap::default(),
+ children: FxHashMap::default(),
+ current_hir_id_owner: CRATE_DEF_ID,
+ item_local_id_counter: hir::ItemLocalId::new(0),
+ node_id_to_local_id: Default::default(),
+ local_id_to_def_id: SortedMap::new(),
+ trait_map: Default::default(),
+
+ // Lowering state.
+ catch_scope: None,
+ loop_scope: None,
+ is_in_loop_condition: false,
+ is_in_trait_impl: false,
+ is_in_dyn_type: false,
+ generator_kind: None,
+ task_context: None,
+ current_item: None,
+ impl_trait_defs: Vec::new(),
+ impl_trait_bounds: Vec::new(),
+ allow_try_trait: Some([sym::try_trait_v2, sym::yeet_desugar_details][..].into()),
+ allow_gen_future: Some([sym::gen_future][..].into()),
+ allow_into_future: Some([sym::into_future][..].into()),
+ };
+ lctx.with_hir_id_owner(owner, |lctx| f(lctx));
+
+ for (def_id, info) in lctx.children {
+ self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom);
+ debug_assert!(matches!(self.owners[def_id], hir::MaybeOwner::Phantom));
+ self.owners[def_id] = info;
+ }
+ }
+
+ pub(super) fn lower_node(
+ &mut self,
+ def_id: LocalDefId,
+ ) -> hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>> {
+ self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom);
+ if let hir::MaybeOwner::Phantom = self.owners[def_id] {
+ let node = self.ast_index[def_id];
+ match node {
+ AstOwner::NonOwner => {}
+ AstOwner::Crate(c) => self.lower_crate(c),
+ AstOwner::Item(item) => self.lower_item(item),
+ AstOwner::AssocItem(item, ctxt) => self.lower_assoc_item(item, ctxt),
+ AstOwner::ForeignItem(item) => self.lower_foreign_item(item),
+ }
+ }
+
+ self.owners[def_id]
+ }
+
+ #[instrument(level = "debug", skip(self, c))]
+ fn lower_crate(&mut self, c: &Crate) {
+ debug_assert_eq!(self.resolver.node_id_to_def_id[&CRATE_NODE_ID], CRATE_DEF_ID);
+ self.with_lctx(CRATE_NODE_ID, |lctx| {
+ let module = lctx.lower_mod(&c.items, &c.spans);
+ lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs);
+ hir::OwnerNode::Crate(lctx.arena.alloc(module))
+ })
+ }
+
+ #[instrument(level = "debug", skip(self))]
+ fn lower_item(&mut self, item: &Item) {
+ self.with_lctx(item.id, |lctx| hir::OwnerNode::Item(lctx.lower_item(item)))
+ }
+
+ fn lower_assoc_item(&mut self, item: &AssocItem, ctxt: AssocCtxt) {
+ let def_id = self.resolver.node_id_to_def_id[&item.id];
+
+ let parent_id = self.tcx.local_parent(def_id);
+ let parent_hir = self.lower_node(parent_id).unwrap();
+ self.with_lctx(item.id, |lctx| {
+ // Evaluate with the lifetimes in `params` in-scope.
+ // This is used to track which lifetimes have already been defined,
+ // and which need to be replicated when lowering an async fn.
+ match parent_hir.node().expect_item().kind {
+ hir::ItemKind::Impl(hir::Impl { ref of_trait, .. }) => {
+ lctx.is_in_trait_impl = of_trait.is_some();
+ }
+ _ => {}
+ };
+
+ match ctxt {
+ AssocCtxt::Trait => hir::OwnerNode::TraitItem(lctx.lower_trait_item(item)),
+ AssocCtxt::Impl => hir::OwnerNode::ImplItem(lctx.lower_impl_item(item)),
+ }
+ })
+ }
+
+ fn lower_foreign_item(&mut self, item: &ForeignItem) {
+ self.with_lctx(item.id, |lctx| hir::OwnerNode::ForeignItem(lctx.lower_foreign_item(item)))
+ }
+}
+
+impl<'hir> LoweringContext<'_, 'hir> {
+ pub(super) fn lower_mod(&mut self, items: &[P<Item>], spans: &ModSpans) -> hir::Mod<'hir> {
+ hir::Mod {
+ spans: hir::ModSpans {
+ inner_span: self.lower_span(spans.inner_span),
+ inject_use_span: self.lower_span(spans.inject_use_span),
+ },
+ item_ids: self.arena.alloc_from_iter(items.iter().flat_map(|x| self.lower_item_ref(x))),
+ }
+ }
+
+ pub(super) fn lower_item_ref(&mut self, i: &Item) -> SmallVec<[hir::ItemId; 1]> {
+ let mut node_ids = smallvec![hir::ItemId { def_id: self.local_def_id(i.id) }];
+ if let ItemKind::Use(ref use_tree) = &i.kind {
+ self.lower_item_id_use_tree(use_tree, i.id, &mut node_ids);
+ }
+ node_ids
+ }
+
+ fn lower_item_id_use_tree(
+ &mut self,
+ tree: &UseTree,
+ base_id: NodeId,
+ vec: &mut SmallVec<[hir::ItemId; 1]>,
+ ) {
+ match tree.kind {
+ UseTreeKind::Nested(ref nested_vec) => {
+ for &(ref nested, id) in nested_vec {
+ vec.push(hir::ItemId { def_id: self.local_def_id(id) });
+ self.lower_item_id_use_tree(nested, id, vec);
+ }
+ }
+ UseTreeKind::Glob => {}
+ UseTreeKind::Simple(_, id1, id2) => {
+ for (_, &id) in
+ iter::zip(self.expect_full_res_from_use(base_id).skip(1), &[id1, id2])
+ {
+ vec.push(hir::ItemId { def_id: self.local_def_id(id) });
+ }
+ }
+ }
+ }
+
+ fn lower_item(&mut self, i: &Item) -> &'hir hir::Item<'hir> {
+ let mut ident = i.ident;
+ let vis_span = self.lower_span(i.vis.span);
+ let hir_id = self.lower_node_id(i.id);
+ let attrs = self.lower_attrs(hir_id, &i.attrs);
+ let kind = self.lower_item_kind(i.span, i.id, hir_id, &mut ident, attrs, vis_span, &i.kind);
+ let item = hir::Item {
+ def_id: hir_id.expect_owner(),
+ ident: self.lower_ident(ident),
+ kind,
+ vis_span,
+ span: self.lower_span(i.span),
+ };
+ self.arena.alloc(item)
+ }
+
+ fn lower_item_kind(
+ &mut self,
+ span: Span,
+ id: NodeId,
+ hir_id: hir::HirId,
+ ident: &mut Ident,
+ attrs: Option<&'hir [Attribute]>,
+ vis_span: Span,
+ i: &ItemKind,
+ ) -> hir::ItemKind<'hir> {
+ match *i {
+ ItemKind::ExternCrate(orig_name) => hir::ItemKind::ExternCrate(orig_name),
+ ItemKind::Use(ref use_tree) => {
+ // Start with an empty prefix.
+ let prefix = Path { segments: vec![], span: use_tree.span, tokens: None };
+
+ self.lower_use_tree(use_tree, &prefix, id, vis_span, ident, attrs)
+ }
+ ItemKind::Static(ref t, m, ref e) => {
+ let (ty, body_id) = self.lower_const_item(t, span, e.as_deref());
+ hir::ItemKind::Static(ty, m, body_id)
+ }
+ ItemKind::Const(_, ref t, ref e) => {
+ let (ty, body_id) = self.lower_const_item(t, span, e.as_deref());
+ hir::ItemKind::Const(ty, body_id)
+ }
+ ItemKind::Fn(box Fn {
+ sig: FnSig { ref decl, header, span: fn_sig_span },
+ ref generics,
+ ref body,
+ ..
+ }) => {
+ self.with_new_scopes(|this| {
+ this.current_item = Some(ident.span);
+
+ // Note: we don't need to change the return type from `T` to
+ // `impl Future<Output = T>` here because lower_body
+ // only cares about the input argument patterns in the function
+ // declaration (decl), not the return types.
+ let asyncness = header.asyncness;
+ let body_id =
+ this.lower_maybe_async_body(span, &decl, asyncness, body.as_deref());
+
+ let itctx = ImplTraitContext::Universal;
+ let (generics, decl) = this.lower_generics(generics, id, itctx, |this| {
+ let ret_id = asyncness.opt_return_id();
+ this.lower_fn_decl(&decl, Some(id), FnDeclKind::Fn, ret_id)
+ });
+ let sig = hir::FnSig {
+ decl,
+ header: this.lower_fn_header(header),
+ span: this.lower_span(fn_sig_span),
+ };
+ hir::ItemKind::Fn(sig, generics, body_id)
+ })
+ }
+ ItemKind::Mod(_, ref mod_kind) => match mod_kind {
+ ModKind::Loaded(items, _, spans) => {
+ hir::ItemKind::Mod(self.lower_mod(items, spans))
+ }
+ ModKind::Unloaded => panic!("`mod` items should have been loaded by now"),
+ },
+ ItemKind::ForeignMod(ref fm) => hir::ItemKind::ForeignMod {
+ abi: fm.abi.map_or(abi::Abi::FALLBACK, |abi| self.lower_abi(abi)),
+ items: self
+ .arena
+ .alloc_from_iter(fm.items.iter().map(|x| self.lower_foreign_item_ref(x))),
+ },
+ ItemKind::GlobalAsm(ref asm) => {
+ hir::ItemKind::GlobalAsm(self.lower_inline_asm(span, asm))
+ }
+ ItemKind::TyAlias(box TyAlias {
+ ref generics,
+ where_clauses,
+ ty: Some(ref ty),
+ ..
+ }) => {
+ // We lower
+ //
+ // type Foo = impl Trait
+ //
+ // to
+ //
+ // type Foo = Foo1
+ // opaque type Foo1: Trait
+ let mut generics = generics.clone();
+ add_ty_alias_where_clause(&mut generics, where_clauses, true);
+ let (generics, ty) = self.lower_generics(
+ &generics,
+ id,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+ |this| this.lower_ty(ty, ImplTraitContext::TypeAliasesOpaqueTy),
+ );
+ hir::ItemKind::TyAlias(ty, generics)
+ }
+ ItemKind::TyAlias(box TyAlias {
+ ref generics, ref where_clauses, ty: None, ..
+ }) => {
+ let mut generics = generics.clone();
+ add_ty_alias_where_clause(&mut generics, *where_clauses, true);
+ let (generics, ty) = self.lower_generics(
+ &generics,
+ id,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+ |this| this.arena.alloc(this.ty(span, hir::TyKind::Err)),
+ );
+ hir::ItemKind::TyAlias(ty, generics)
+ }
+ ItemKind::Enum(ref enum_definition, ref generics) => {
+ let (generics, variants) = self.lower_generics(
+ generics,
+ id,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+ |this| {
+ this.arena.alloc_from_iter(
+ enum_definition.variants.iter().map(|x| this.lower_variant(x)),
+ )
+ },
+ );
+ hir::ItemKind::Enum(hir::EnumDef { variants }, generics)
+ }
+ ItemKind::Struct(ref struct_def, ref generics) => {
+ let (generics, struct_def) = self.lower_generics(
+ generics,
+ id,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+ |this| this.lower_variant_data(hir_id, struct_def),
+ );
+ hir::ItemKind::Struct(struct_def, generics)
+ }
+ ItemKind::Union(ref vdata, ref generics) => {
+ let (generics, vdata) = self.lower_generics(
+ generics,
+ id,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+ |this| this.lower_variant_data(hir_id, vdata),
+ );
+ hir::ItemKind::Union(vdata, generics)
+ }
+ ItemKind::Impl(box Impl {
+ unsafety,
+ polarity,
+ defaultness,
+ constness,
+ generics: ref ast_generics,
+ of_trait: ref trait_ref,
+ self_ty: ref ty,
+ items: ref impl_items,
+ }) => {
+ // Lower the "impl header" first. This ordering is important
+ // for in-band lifetimes! Consider `'a` here:
+ //
+ // impl Foo<'a> for u32 {
+ // fn method(&'a self) { .. }
+ // }
+ //
+ // Because we start by lowering the `Foo<'a> for u32`
+ // part, we will add `'a` to the list of generics on
+ // the impl. When we then encounter it later in the
+ // method, it will not be considered an in-band
+ // lifetime to be added, but rather a reference to a
+ // parent lifetime.
+ let itctx = ImplTraitContext::Universal;
+ let (generics, (trait_ref, lowered_ty)) =
+ self.lower_generics(ast_generics, id, itctx, |this| {
+ let trait_ref = trait_ref.as_ref().map(|trait_ref| {
+ this.lower_trait_ref(
+ trait_ref,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Trait),
+ )
+ });
+
+ let lowered_ty = this
+ .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
+
+ (trait_ref, lowered_ty)
+ });
+
+ let new_impl_items = self
+ .arena
+ .alloc_from_iter(impl_items.iter().map(|item| self.lower_impl_item_ref(item)));
+
+ // `defaultness.has_value()` is never called for an `impl`, always `true` in order
+ // to not cause an assertion failure inside the `lower_defaultness` function.
+ let has_val = true;
+ let (defaultness, defaultness_span) = self.lower_defaultness(defaultness, has_val);
+ let polarity = match polarity {
+ ImplPolarity::Positive => ImplPolarity::Positive,
+ ImplPolarity::Negative(s) => ImplPolarity::Negative(self.lower_span(s)),
+ };
+ hir::ItemKind::Impl(self.arena.alloc(hir::Impl {
+ unsafety: self.lower_unsafety(unsafety),
+ polarity,
+ defaultness,
+ defaultness_span,
+ constness: self.lower_constness(constness),
+ generics,
+ of_trait: trait_ref,
+ self_ty: lowered_ty,
+ items: new_impl_items,
+ }))
+ }
+ ItemKind::Trait(box Trait {
+ is_auto,
+ unsafety,
+ ref generics,
+ ref bounds,
+ ref items,
+ }) => {
+ let (generics, (unsafety, items, bounds)) = self.lower_generics(
+ generics,
+ id,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+ |this| {
+ let bounds = this.lower_param_bounds(
+ bounds,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
+ );
+ let items = this.arena.alloc_from_iter(
+ items.iter().map(|item| this.lower_trait_item_ref(item)),
+ );
+ let unsafety = this.lower_unsafety(unsafety);
+ (unsafety, items, bounds)
+ },
+ );
+ hir::ItemKind::Trait(is_auto, unsafety, generics, bounds, items)
+ }
+ ItemKind::TraitAlias(ref generics, ref bounds) => {
+ let (generics, bounds) = self.lower_generics(
+ generics,
+ id,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+ |this| {
+ this.lower_param_bounds(
+ bounds,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
+ )
+ },
+ );
+ hir::ItemKind::TraitAlias(generics, bounds)
+ }
+ ItemKind::MacroDef(MacroDef { ref body, macro_rules }) => {
+ let body = P(self.lower_mac_args(body));
+ let macro_kind = self.resolver.decl_macro_kind(self.local_def_id(id));
+ hir::ItemKind::Macro(ast::MacroDef { body, macro_rules }, macro_kind)
+ }
+ ItemKind::MacCall(..) => {
+ panic!("`TyMac` should have been expanded by now")
+ }
+ }
+ }
+
+ fn lower_const_item(
+ &mut self,
+ ty: &Ty,
+ span: Span,
+ body: Option<&Expr>,
+ ) -> (&'hir hir::Ty<'hir>, hir::BodyId) {
+ let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
+ (ty, self.lower_const_body(span, body))
+ }
+
+ #[instrument(level = "debug", skip(self))]
+ fn lower_use_tree(
+ &mut self,
+ tree: &UseTree,
+ prefix: &Path,
+ id: NodeId,
+ vis_span: Span,
+ ident: &mut Ident,
+ attrs: Option<&'hir [Attribute]>,
+ ) -> hir::ItemKind<'hir> {
+ let path = &tree.prefix;
+ let segments = prefix.segments.iter().chain(path.segments.iter()).cloned().collect();
+
+ match tree.kind {
+ UseTreeKind::Simple(rename, id1, id2) => {
+ *ident = tree.ident();
+
+ // First, apply the prefix to the path.
+ let mut path = Path { segments, span: path.span, tokens: None };
+
+ // Correctly resolve `self` imports.
+ if path.segments.len() > 1
+ && path.segments.last().unwrap().ident.name == kw::SelfLower
+ {
+ let _ = path.segments.pop();
+ if rename.is_none() {
+ *ident = path.segments.last().unwrap().ident;
+ }
+ }
+
+ let mut resolutions = self.expect_full_res_from_use(id).fuse();
+ // We want to return *something* from this function, so hold onto the first item
+ // for later.
+ let ret_res = self.lower_res(resolutions.next().unwrap_or(Res::Err));
+
+ // Here, we are looping over namespaces, if they exist for the definition
+ // being imported. We only handle type and value namespaces because we
+ // won't be dealing with macros in the rest of the compiler.
+ // Essentially a single `use` which imports two names is desugared into
+ // two imports.
+ for new_node_id in [id1, id2] {
+ let new_id = self.local_def_id(new_node_id);
+ let Some(res) = resolutions.next() else {
+ // Associate an HirId to both ids even if there is no resolution.
+ let _old = self.children.insert(
+ new_id,
+ hir::MaybeOwner::NonOwner(hir::HirId::make_owner(new_id)),
+ );
+ debug_assert!(_old.is_none());
+ continue;
+ };
+ let ident = *ident;
+ let mut path = path.clone();
+ for seg in &mut path.segments {
+ seg.id = self.next_node_id();
+ }
+ let span = path.span;
+
+ self.with_hir_id_owner(new_node_id, |this| {
+ let res = this.lower_res(res);
+ let path = this.lower_path_extra(res, &path, ParamMode::Explicit);
+ let kind = hir::ItemKind::Use(path, hir::UseKind::Single);
+ if let Some(attrs) = attrs {
+ this.attrs.insert(hir::ItemLocalId::new(0), attrs);
+ }
+
+ let item = hir::Item {
+ def_id: new_id,
+ ident: this.lower_ident(ident),
+ kind,
+ vis_span,
+ span: this.lower_span(span),
+ };
+ hir::OwnerNode::Item(this.arena.alloc(item))
+ });
+ }
+
+ let path = self.lower_path_extra(ret_res, &path, ParamMode::Explicit);
+ hir::ItemKind::Use(path, hir::UseKind::Single)
+ }
+ UseTreeKind::Glob => {
+ let path = self.lower_path(
+ id,
+ &Path { segments, span: path.span, tokens: None },
+ ParamMode::Explicit,
+ );
+ hir::ItemKind::Use(path, hir::UseKind::Glob)
+ }
+ UseTreeKind::Nested(ref trees) => {
+ // Nested imports are desugared into simple imports.
+ // So, if we start with
+ //
+ // ```
+ // pub(x) use foo::{a, b};
+ // ```
+ //
+ // we will create three items:
+ //
+ // ```
+ // pub(x) use foo::a;
+ // pub(x) use foo::b;
+ // pub(x) use foo::{}; // <-- this is called the `ListStem`
+ // ```
+ //
+ // The first two are produced by recursively invoking
+ // `lower_use_tree` (and indeed there may be things
+ // like `use foo::{a::{b, c}}` and so forth). They
+ // wind up being directly added to
+ // `self.items`. However, the structure of this
+ // function also requires us to return one item, and
+ // for that we return the `{}` import (called the
+ // `ListStem`).
+
+ let prefix = Path { segments, span: prefix.span.to(path.span), tokens: None };
+
+ // Add all the nested `PathListItem`s to the HIR.
+ for &(ref use_tree, id) in trees {
+ let new_hir_id = self.local_def_id(id);
+
+ let mut prefix = prefix.clone();
+
+ // Give the segments new node-ids since they are being cloned.
+ for seg in &mut prefix.segments {
+ seg.id = self.next_node_id();
+ }
+
+ // Each `use` import is an item and thus are owners of the
+ // names in the path. Up to this point the nested import is
+ // the current owner, since we want each desugared import to
+ // own its own names, we have to adjust the owner before
+ // lowering the rest of the import.
+ self.with_hir_id_owner(id, |this| {
+ let mut ident = *ident;
+
+ let kind =
+ this.lower_use_tree(use_tree, &prefix, id, vis_span, &mut ident, attrs);
+ if let Some(attrs) = attrs {
+ this.attrs.insert(hir::ItemLocalId::new(0), attrs);
+ }
+
+ let item = hir::Item {
+ def_id: new_hir_id,
+ ident: this.lower_ident(ident),
+ kind,
+ vis_span,
+ span: this.lower_span(use_tree.span),
+ };
+ hir::OwnerNode::Item(this.arena.alloc(item))
+ });
+ }
+
+ let res = self.expect_full_res_from_use(id).next().unwrap_or(Res::Err);
+ let res = self.lower_res(res);
+ let path = self.lower_path_extra(res, &prefix, ParamMode::Explicit);
+ hir::ItemKind::Use(path, hir::UseKind::ListStem)
+ }
+ }
+ }
+
+ fn lower_foreign_item(&mut self, i: &ForeignItem) -> &'hir hir::ForeignItem<'hir> {
+ let hir_id = self.lower_node_id(i.id);
+ let def_id = hir_id.expect_owner();
+ self.lower_attrs(hir_id, &i.attrs);
+ let item = hir::ForeignItem {
+ def_id,
+ ident: self.lower_ident(i.ident),
+ kind: match i.kind {
+ ForeignItemKind::Fn(box Fn { ref sig, ref generics, .. }) => {
+ let fdec = &sig.decl;
+ let itctx = ImplTraitContext::Universal;
+ let (generics, (fn_dec, fn_args)) =
+ self.lower_generics(generics, i.id, itctx, |this| {
+ (
+ // Disallow `impl Trait` in foreign items.
+ this.lower_fn_decl(fdec, None, FnDeclKind::ExternFn, None),
+ this.lower_fn_params_to_names(fdec),
+ )
+ });
+
+ hir::ForeignItemKind::Fn(fn_dec, fn_args, generics)
+ }
+ ForeignItemKind::Static(ref t, m, _) => {
+ let ty =
+ self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
+ hir::ForeignItemKind::Static(ty, m)
+ }
+ ForeignItemKind::TyAlias(..) => hir::ForeignItemKind::Type,
+ ForeignItemKind::MacCall(_) => panic!("macro shouldn't exist here"),
+ },
+ vis_span: self.lower_span(i.vis.span),
+ span: self.lower_span(i.span),
+ };
+ self.arena.alloc(item)
+ }
+
+ fn lower_foreign_item_ref(&mut self, i: &ForeignItem) -> hir::ForeignItemRef {
+ hir::ForeignItemRef {
+ id: hir::ForeignItemId { def_id: self.local_def_id(i.id) },
+ ident: self.lower_ident(i.ident),
+ span: self.lower_span(i.span),
+ }
+ }
+
+ fn lower_variant(&mut self, v: &Variant) -> hir::Variant<'hir> {
+ let id = self.lower_node_id(v.id);
+ self.lower_attrs(id, &v.attrs);
+ hir::Variant {
+ id,
+ data: self.lower_variant_data(id, &v.data),
+ disr_expr: v.disr_expr.as_ref().map(|e| self.lower_anon_const(e)),
+ ident: self.lower_ident(v.ident),
+ span: self.lower_span(v.span),
+ }
+ }
+
+ fn lower_variant_data(
+ &mut self,
+ parent_id: hir::HirId,
+ vdata: &VariantData,
+ ) -> hir::VariantData<'hir> {
+ match *vdata {
+ VariantData::Struct(ref fields, recovered) => hir::VariantData::Struct(
+ self.arena
+ .alloc_from_iter(fields.iter().enumerate().map(|f| self.lower_field_def(f))),
+ recovered,
+ ),
+ VariantData::Tuple(ref fields, id) => {
+ let ctor_id = self.lower_node_id(id);
+ self.alias_attrs(ctor_id, parent_id);
+ hir::VariantData::Tuple(
+ self.arena.alloc_from_iter(
+ fields.iter().enumerate().map(|f| self.lower_field_def(f)),
+ ),
+ ctor_id,
+ )
+ }
+ VariantData::Unit(id) => {
+ let ctor_id = self.lower_node_id(id);
+ self.alias_attrs(ctor_id, parent_id);
+ hir::VariantData::Unit(ctor_id)
+ }
+ }
+ }
+
+ fn lower_field_def(&mut self, (index, f): (usize, &FieldDef)) -> hir::FieldDef<'hir> {
+ let ty = if let TyKind::Path(ref qself, ref path) = f.ty.kind {
+ let t = self.lower_path_ty(
+ &f.ty,
+ qself,
+ path,
+ ParamMode::ExplicitNamed, // no `'_` in declarations (Issue #61124)
+ ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+ );
+ self.arena.alloc(t)
+ } else {
+ self.lower_ty(&f.ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type))
+ };
+ let hir_id = self.lower_node_id(f.id);
+ self.lower_attrs(hir_id, &f.attrs);
+ hir::FieldDef {
+ span: self.lower_span(f.span),
+ hir_id,
+ ident: match f.ident {
+ Some(ident) => self.lower_ident(ident),
+ // FIXME(jseyfried): positional field hygiene.
+ None => Ident::new(sym::integer(index), self.lower_span(f.span)),
+ },
+ vis_span: self.lower_span(f.vis.span),
+ ty,
+ }
+ }
+
+ fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> {
+ let hir_id = self.lower_node_id(i.id);
+ let trait_item_def_id = hir_id.expect_owner();
+
+ let (generics, kind, has_default) = match i.kind {
+ AssocItemKind::Const(_, ref ty, ref default) => {
+ let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
+ let body = default.as_ref().map(|x| self.lower_const_body(i.span, Some(x)));
+ (hir::Generics::empty(), hir::TraitItemKind::Const(ty, body), body.is_some())
+ }
+ AssocItemKind::Fn(box Fn { ref sig, ref generics, body: None, .. }) => {
+ let names = self.lower_fn_params_to_names(&sig.decl);
+ let (generics, sig) =
+ self.lower_method_sig(generics, sig, i.id, FnDeclKind::Trait, None);
+ (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)), false)
+ }
+ AssocItemKind::Fn(box Fn { ref sig, ref generics, body: Some(ref body), .. }) => {
+ let asyncness = sig.header.asyncness;
+ let body_id =
+ self.lower_maybe_async_body(i.span, &sig.decl, asyncness, Some(&body));
+ let (generics, sig) = self.lower_method_sig(
+ generics,
+ sig,
+ i.id,
+ FnDeclKind::Trait,
+ asyncness.opt_return_id(),
+ );
+ (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)), true)
+ }
+ AssocItemKind::TyAlias(box TyAlias {
+ ref generics,
+ where_clauses,
+ ref bounds,
+ ref ty,
+ ..
+ }) => {
+ let mut generics = generics.clone();
+ add_ty_alias_where_clause(&mut generics, where_clauses, false);
+ let (generics, kind) = self.lower_generics(
+ &generics,
+ i.id,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+ |this| {
+ let ty = ty.as_ref().map(|x| {
+ this.lower_ty(x, ImplTraitContext::Disallowed(ImplTraitPosition::Type))
+ });
+ hir::TraitItemKind::Type(
+ this.lower_param_bounds(
+ bounds,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+ ),
+ ty,
+ )
+ },
+ );
+ (generics, kind, ty.is_some())
+ }
+ AssocItemKind::MacCall(..) => panic!("macro item shouldn't exist at this point"),
+ };
+
+ self.lower_attrs(hir_id, &i.attrs);
+ let item = hir::TraitItem {
+ def_id: trait_item_def_id,
+ ident: self.lower_ident(i.ident),
+ generics,
+ kind,
+ span: self.lower_span(i.span),
+ defaultness: hir::Defaultness::Default { has_value: has_default },
+ };
+ self.arena.alloc(item)
+ }
+
+ fn lower_trait_item_ref(&mut self, i: &AssocItem) -> hir::TraitItemRef {
+ let kind = match &i.kind {
+ AssocItemKind::Const(..) => hir::AssocItemKind::Const,
+ AssocItemKind::TyAlias(..) => hir::AssocItemKind::Type,
+ AssocItemKind::Fn(box Fn { sig, .. }) => {
+ hir::AssocItemKind::Fn { has_self: sig.decl.has_self() }
+ }
+ AssocItemKind::MacCall(..) => unimplemented!(),
+ };
+ let id = hir::TraitItemId { def_id: self.local_def_id(i.id) };
+ hir::TraitItemRef {
+ id,
+ ident: self.lower_ident(i.ident),
+ span: self.lower_span(i.span),
+ kind,
+ }
+ }
+
+ /// Construct `ExprKind::Err` for the given `span`.
+ pub(crate) fn expr_err(&mut self, span: Span) -> hir::Expr<'hir> {
+ self.expr(span, hir::ExprKind::Err, AttrVec::new())
+ }
+
+ fn lower_impl_item(&mut self, i: &AssocItem) -> &'hir hir::ImplItem<'hir> {
+ // Since `default impl` is not yet implemented, this is always true in impls.
+ let has_value = true;
+ let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value);
+
+ let (generics, kind) = match &i.kind {
+ AssocItemKind::Const(_, ty, expr) => {
+ let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
+ (
+ hir::Generics::empty(),
+ hir::ImplItemKind::Const(ty, self.lower_const_body(i.span, expr.as_deref())),
+ )
+ }
+ AssocItemKind::Fn(box Fn { sig, generics, body, .. }) => {
+ self.current_item = Some(i.span);
+ let asyncness = sig.header.asyncness;
+ let body_id =
+ self.lower_maybe_async_body(i.span, &sig.decl, asyncness, body.as_deref());
+ let (generics, sig) = self.lower_method_sig(
+ generics,
+ sig,
+ i.id,
+ if self.is_in_trait_impl { FnDeclKind::Impl } else { FnDeclKind::Inherent },
+ asyncness.opt_return_id(),
+ );
+
+ (generics, hir::ImplItemKind::Fn(sig, body_id))
+ }
+ AssocItemKind::TyAlias(box TyAlias { generics, where_clauses, ty, .. }) => {
+ let mut generics = generics.clone();
+ add_ty_alias_where_clause(&mut generics, *where_clauses, false);
+ self.lower_generics(
+ &generics,
+ i.id,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+ |this| match ty {
+ None => {
+ let ty = this.arena.alloc(this.ty(i.span, hir::TyKind::Err));
+ hir::ImplItemKind::TyAlias(ty)
+ }
+ Some(ty) => {
+ let ty = this.lower_ty(ty, ImplTraitContext::TypeAliasesOpaqueTy);
+ hir::ImplItemKind::TyAlias(ty)
+ }
+ },
+ )
+ }
+ AssocItemKind::MacCall(..) => panic!("`TyMac` should have been expanded by now"),
+ };
+
+ let hir_id = self.lower_node_id(i.id);
+ self.lower_attrs(hir_id, &i.attrs);
+ let item = hir::ImplItem {
+ def_id: hir_id.expect_owner(),
+ ident: self.lower_ident(i.ident),
+ generics,
+ kind,
+ vis_span: self.lower_span(i.vis.span),
+ span: self.lower_span(i.span),
+ defaultness,
+ };
+ self.arena.alloc(item)
+ }
+
+ fn lower_impl_item_ref(&mut self, i: &AssocItem) -> hir::ImplItemRef {
+ hir::ImplItemRef {
+ id: hir::ImplItemId { def_id: self.local_def_id(i.id) },
+ ident: self.lower_ident(i.ident),
+ span: self.lower_span(i.span),
+ kind: match &i.kind {
+ AssocItemKind::Const(..) => hir::AssocItemKind::Const,
+ AssocItemKind::TyAlias(..) => hir::AssocItemKind::Type,
+ AssocItemKind::Fn(box Fn { sig, .. }) => {
+ hir::AssocItemKind::Fn { has_self: sig.decl.has_self() }
+ }
+ AssocItemKind::MacCall(..) => unimplemented!(),
+ },
+ trait_item_def_id: self.resolver.get_partial_res(i.id).map(|r| r.base_res().def_id()),
+ }
+ }
+
+ fn lower_defaultness(
+ &self,
+ d: Defaultness,
+ has_value: bool,
+ ) -> (hir::Defaultness, Option<Span>) {
+ match d {
+ Defaultness::Default(sp) => {
+ (hir::Defaultness::Default { has_value }, Some(self.lower_span(sp)))
+ }
+ Defaultness::Final => {
+ assert!(has_value);
+ (hir::Defaultness::Final, None)
+ }
+ }
+ }
+
+ fn record_body(
+ &mut self,
+ params: &'hir [hir::Param<'hir>],
+ value: hir::Expr<'hir>,
+ ) -> hir::BodyId {
+ let body = hir::Body { generator_kind: self.generator_kind, params, value };
+ let id = body.id();
+ debug_assert_eq!(id.hir_id.owner, self.current_hir_id_owner);
+ self.bodies.push((id.hir_id.local_id, self.arena.alloc(body)));
+ id
+ }
+
+ pub(super) fn lower_body(
+ &mut self,
+ f: impl FnOnce(&mut Self) -> (&'hir [hir::Param<'hir>], hir::Expr<'hir>),
+ ) -> hir::BodyId {
+ let prev_gen_kind = self.generator_kind.take();
+ let task_context = self.task_context.take();
+ let (parameters, result) = f(self);
+ let body_id = self.record_body(parameters, result);
+ self.task_context = task_context;
+ self.generator_kind = prev_gen_kind;
+ body_id
+ }
+
+ fn lower_param(&mut self, param: &Param) -> hir::Param<'hir> {
+ let hir_id = self.lower_node_id(param.id);
+ self.lower_attrs(hir_id, &param.attrs);
+ hir::Param {
+ hir_id,
+ pat: self.lower_pat(&param.pat),
+ ty_span: self.lower_span(param.ty.span),
+ span: self.lower_span(param.span),
+ }
+ }
+
+ pub(super) fn lower_fn_body(
+ &mut self,
+ decl: &FnDecl,
+ body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
+ ) -> hir::BodyId {
+ self.lower_body(|this| {
+ (
+ this.arena.alloc_from_iter(decl.inputs.iter().map(|x| this.lower_param(x))),
+ body(this),
+ )
+ })
+ }
+
+ fn lower_fn_body_block(
+ &mut self,
+ span: Span,
+ decl: &FnDecl,
+ body: Option<&Block>,
+ ) -> hir::BodyId {
+ self.lower_fn_body(decl, |this| this.lower_block_expr_opt(span, body))
+ }
+
+ fn lower_block_expr_opt(&mut self, span: Span, block: Option<&Block>) -> hir::Expr<'hir> {
+ match block {
+ Some(block) => self.lower_block_expr(block),
+ None => self.expr_err(span),
+ }
+ }
+
+ pub(super) fn lower_const_body(&mut self, span: Span, expr: Option<&Expr>) -> hir::BodyId {
+ self.lower_body(|this| {
+ (
+ &[],
+ match expr {
+ Some(expr) => this.lower_expr_mut(expr),
+ None => this.expr_err(span),
+ },
+ )
+ })
+ }
+
+ fn lower_maybe_async_body(
+ &mut self,
+ span: Span,
+ decl: &FnDecl,
+ asyncness: Async,
+ body: Option<&Block>,
+ ) -> hir::BodyId {
+ let closure_id = match asyncness {
+ Async::Yes { closure_id, .. } => closure_id,
+ Async::No => return self.lower_fn_body_block(span, decl, body),
+ };
+
+ self.lower_body(|this| {
+ let mut parameters: Vec<hir::Param<'_>> = Vec::new();
+ let mut statements: Vec<hir::Stmt<'_>> = Vec::new();
+
+ // Async function parameters are lowered into the closure body so that they are
+ // captured and so that the drop order matches the equivalent non-async functions.
+ //
+ // from:
+ //
+ // async fn foo(<pattern>: <ty>, <pattern>: <ty>, <pattern>: <ty>) {
+ // <body>
+ // }
+ //
+ // into:
+ //
+ // fn foo(__arg0: <ty>, __arg1: <ty>, __arg2: <ty>) {
+ // async move {
+ // let __arg2 = __arg2;
+ // let <pattern> = __arg2;
+ // let __arg1 = __arg1;
+ // let <pattern> = __arg1;
+ // let __arg0 = __arg0;
+ // let <pattern> = __arg0;
+ // drop-temps { <body> } // see comments later in fn for details
+ // }
+ // }
+ //
+ // If `<pattern>` is a simple ident, then it is lowered to a single
+ // `let <pattern> = <pattern>;` statement as an optimization.
+ //
+ // Note that the body is embedded in `drop-temps`; an
+ // equivalent desugaring would be `return { <body>
+ // };`. The key point is that we wish to drop all the
+ // let-bound variables and temporaries created in the body
+ // (and its tail expression!) before we drop the
+ // parameters (c.f. rust-lang/rust#64512).
+ for (index, parameter) in decl.inputs.iter().enumerate() {
+ let parameter = this.lower_param(parameter);
+ let span = parameter.pat.span;
+
+ // Check if this is a binding pattern, if so, we can optimize and avoid adding a
+ // `let <pat> = __argN;` statement. In this case, we do not rename the parameter.
+ let (ident, is_simple_parameter) = match parameter.pat.kind {
+ hir::PatKind::Binding(
+ hir::BindingAnnotation::Unannotated | hir::BindingAnnotation::Mutable,
+ _,
+ ident,
+ _,
+ ) => (ident, true),
+ // For `ref mut` or wildcard arguments, we can't reuse the binding, but
+ // we can keep the same name for the parameter.
+ // This lets rustdoc render it correctly in documentation.
+ hir::PatKind::Binding(_, _, ident, _) => (ident, false),
+ hir::PatKind::Wild => {
+ (Ident::with_dummy_span(rustc_span::symbol::kw::Underscore), false)
+ }
+ _ => {
+ // Replace the ident for bindings that aren't simple.
+ let name = format!("__arg{}", index);
+ let ident = Ident::from_str(&name);
+
+ (ident, false)
+ }
+ };
+
+ let desugared_span = this.mark_span_with_reason(DesugaringKind::Async, span, None);
+
+ // Construct a parameter representing `__argN: <ty>` to replace the parameter of the
+ // async function.
+ //
+ // If this is the simple case, this parameter will end up being the same as the
+ // original parameter, but with a different pattern id.
+ let stmt_attrs = this.attrs.get(&parameter.hir_id.local_id).copied();
+ let (new_parameter_pat, new_parameter_id) = this.pat_ident(desugared_span, ident);
+ let new_parameter = hir::Param {
+ hir_id: parameter.hir_id,
+ pat: new_parameter_pat,
+ ty_span: this.lower_span(parameter.ty_span),
+ span: this.lower_span(parameter.span),
+ };
+
+ if is_simple_parameter {
+ // If this is the simple case, then we only insert one statement that is
+ // `let <pat> = <pat>;`. We re-use the original argument's pattern so that
+ // `HirId`s are densely assigned.
+ let expr = this.expr_ident(desugared_span, ident, new_parameter_id);
+ let stmt = this.stmt_let_pat(
+ stmt_attrs,
+ desugared_span,
+ Some(expr),
+ parameter.pat,
+ hir::LocalSource::AsyncFn,
+ );
+ statements.push(stmt);
+ } else {
+ // If this is not the simple case, then we construct two statements:
+ //
+ // ```
+ // let __argN = __argN;
+ // let <pat> = __argN;
+ // ```
+ //
+ // The first statement moves the parameter into the closure and thus ensures
+ // that the drop order is correct.
+ //
+ // The second statement creates the bindings that the user wrote.
+
+ // Construct the `let mut __argN = __argN;` statement. It must be a mut binding
+ // because the user may have specified a `ref mut` binding in the next
+ // statement.
+ let (move_pat, move_id) = this.pat_ident_binding_mode(
+ desugared_span,
+ ident,
+ hir::BindingAnnotation::Mutable,
+ );
+ let move_expr = this.expr_ident(desugared_span, ident, new_parameter_id);
+ let move_stmt = this.stmt_let_pat(
+ None,
+ desugared_span,
+ Some(move_expr),
+ move_pat,
+ hir::LocalSource::AsyncFn,
+ );
+
+ // Construct the `let <pat> = __argN;` statement. We re-use the original
+ // parameter's pattern so that `HirId`s are densely assigned.
+ let pattern_expr = this.expr_ident(desugared_span, ident, move_id);
+ let pattern_stmt = this.stmt_let_pat(
+ stmt_attrs,
+ desugared_span,
+ Some(pattern_expr),
+ parameter.pat,
+ hir::LocalSource::AsyncFn,
+ );
+
+ statements.push(move_stmt);
+ statements.push(pattern_stmt);
+ };
+
+ parameters.push(new_parameter);
+ }
+
+ let body_span = body.map_or(span, |b| b.span);
+ let async_expr = this.make_async_expr(
+ CaptureBy::Value,
+ closure_id,
+ None,
+ body_span,
+ hir::AsyncGeneratorKind::Fn,
+ |this| {
+ // Create a block from the user's function body:
+ let user_body = this.lower_block_expr_opt(body_span, body);
+
+ // Transform into `drop-temps { <user-body> }`, an expression:
+ let desugared_span =
+ this.mark_span_with_reason(DesugaringKind::Async, user_body.span, None);
+ let user_body = this.expr_drop_temps(
+ desugared_span,
+ this.arena.alloc(user_body),
+ AttrVec::new(),
+ );
+
+ // As noted above, create the final block like
+ //
+ // ```
+ // {
+ // let $param_pattern = $raw_param;
+ // ...
+ // drop-temps { <user-body> }
+ // }
+ // ```
+ let body = this.block_all(
+ desugared_span,
+ this.arena.alloc_from_iter(statements),
+ Some(user_body),
+ );
+
+ this.expr_block(body, AttrVec::new())
+ },
+ );
+
+ (
+ this.arena.alloc_from_iter(parameters),
+ this.expr(body_span, async_expr, AttrVec::new()),
+ )
+ })
+ }
+
+ fn lower_method_sig(
+ &mut self,
+ generics: &Generics,
+ sig: &FnSig,
+ id: NodeId,
+ kind: FnDeclKind,
+ is_async: Option<NodeId>,
+ ) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) {
+ let header = self.lower_fn_header(sig.header);
+ let itctx = ImplTraitContext::Universal;
+ let (generics, decl) = self.lower_generics(generics, id, itctx, |this| {
+ this.lower_fn_decl(&sig.decl, Some(id), kind, is_async)
+ });
+ (generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) })
+ }
+
+ fn lower_fn_header(&mut self, h: FnHeader) -> hir::FnHeader {
+ hir::FnHeader {
+ unsafety: self.lower_unsafety(h.unsafety),
+ asyncness: self.lower_asyncness(h.asyncness),
+ constness: self.lower_constness(h.constness),
+ abi: self.lower_extern(h.ext),
+ }
+ }
+
+ pub(super) fn lower_abi(&mut self, abi: StrLit) -> abi::Abi {
+ abi::lookup(abi.symbol_unescaped.as_str()).unwrap_or_else(|| {
+ self.error_on_invalid_abi(abi);
+ abi::Abi::Rust
+ })
+ }
+
+ pub(super) fn lower_extern(&mut self, ext: Extern) -> abi::Abi {
+ match ext {
+ Extern::None => abi::Abi::Rust,
+ Extern::Implicit(_) => abi::Abi::FALLBACK,
+ Extern::Explicit(abi, _) => self.lower_abi(abi),
+ }
+ }
+
+ fn error_on_invalid_abi(&self, abi: StrLit) {
+ struct_span_err!(self.tcx.sess, abi.span, E0703, "invalid ABI: found `{}`", abi.symbol)
+ .span_label(abi.span, "invalid ABI")
+ .help(&format!("valid ABIs: {}", abi::all_names().join(", ")))
+ .emit();
+ }
+
+ fn lower_asyncness(&mut self, a: Async) -> hir::IsAsync {
+ match a {
+ Async::Yes { .. } => hir::IsAsync::Async,
+ Async::No => hir::IsAsync::NotAsync,
+ }
+ }
+
+ fn lower_constness(&mut self, c: Const) -> hir::Constness {
+ match c {
+ Const::Yes(_) => hir::Constness::Const,
+ Const::No => hir::Constness::NotConst,
+ }
+ }
+
+ pub(super) fn lower_unsafety(&mut self, u: Unsafe) -> hir::Unsafety {
+ match u {
+ Unsafe::Yes(_) => hir::Unsafety::Unsafe,
+ Unsafe::No => hir::Unsafety::Normal,
+ }
+ }
+
+ /// Return the pair of the lowered `generics` as `hir::Generics` and the evaluation of `f` with
+ /// the carried impl trait definitions and bounds.
+ #[instrument(level = "debug", skip(self, f))]
+ fn lower_generics<T>(
+ &mut self,
+ generics: &Generics,
+ parent_node_id: NodeId,
+ itctx: ImplTraitContext,
+ f: impl FnOnce(&mut Self) -> T,
+ ) -> (&'hir hir::Generics<'hir>, T) {
+ debug_assert!(self.impl_trait_defs.is_empty());
+ debug_assert!(self.impl_trait_bounds.is_empty());
+
+ // Error if `?Trait` bounds in where clauses don't refer directly to type parameters.
+ // Note: we used to clone these bounds directly onto the type parameter (and avoid lowering
+ // these into hir when we lower thee where clauses), but this makes it quite difficult to
+ // keep track of the Span info. Now, `add_implicitly_sized` in `AstConv` checks both param bounds and
+ // where clauses for `?Sized`.
+ for pred in &generics.where_clause.predicates {
+ let WherePredicate::BoundPredicate(ref bound_pred) = *pred else {
+ continue;
+ };
+ let compute_is_param = || {
+ // Check if the where clause type is a plain type parameter.
+ match self
+ .resolver
+ .get_partial_res(bound_pred.bounded_ty.id)
+ .map(|d| (d.base_res(), d.unresolved_segments()))
+ {
+ Some((Res::Def(DefKind::TyParam, def_id), 0))
+ if bound_pred.bound_generic_params.is_empty() =>
+ {
+ generics
+ .params
+ .iter()
+ .any(|p| def_id == self.local_def_id(p.id).to_def_id())
+ }
+ // Either the `bounded_ty` is not a plain type parameter, or
+ // it's not found in the generic type parameters list.
+ _ => false,
+ }
+ };
+ // We only need to compute this once per `WherePredicate`, but don't
+ // need to compute this at all unless there is a Maybe bound.
+ let mut is_param: Option<bool> = None;
+ for bound in &bound_pred.bounds {
+ if !matches!(*bound, GenericBound::Trait(_, TraitBoundModifier::Maybe)) {
+ continue;
+ }
+ let is_param = *is_param.get_or_insert_with(compute_is_param);
+ if !is_param {
+ self.diagnostic().span_err(
+ bound.span(),
+ "`?Trait` bounds are only permitted at the \
+ point where a type parameter is declared",
+ );
+ }
+ }
+ }
+
+ let mut predicates: SmallVec<[hir::WherePredicate<'hir>; 4]> = SmallVec::new();
+ predicates.extend(generics.params.iter().filter_map(|param| {
+ self.lower_generic_bound_predicate(
+ param.ident,
+ param.id,
+ &param.kind,
+ &param.bounds,
+ itctx,
+ PredicateOrigin::GenericParam,
+ )
+ }));
+ predicates.extend(
+ generics
+ .where_clause
+ .predicates
+ .iter()
+ .map(|predicate| self.lower_where_predicate(predicate)),
+ );
+
+ let mut params: SmallVec<[hir::GenericParam<'hir>; 4]> =
+ self.lower_generic_params_mut(&generics.params).collect();
+
+ // Introduce extra lifetimes if late resolution tells us to.
+ let extra_lifetimes = self.resolver.take_extra_lifetime_params(parent_node_id);
+ params.extend(extra_lifetimes.into_iter().filter_map(|(ident, node_id, res)| {
+ self.lifetime_res_to_generic_param(ident, node_id, res)
+ }));
+
+ let has_where_clause_predicates = !generics.where_clause.predicates.is_empty();
+ let where_clause_span = self.lower_span(generics.where_clause.span);
+ let span = self.lower_span(generics.span);
+ let res = f(self);
+
+ let impl_trait_defs = std::mem::take(&mut self.impl_trait_defs);
+ params.extend(impl_trait_defs.into_iter());
+
+ let impl_trait_bounds = std::mem::take(&mut self.impl_trait_bounds);
+ predicates.extend(impl_trait_bounds.into_iter());
+
+ let lowered_generics = self.arena.alloc(hir::Generics {
+ params: self.arena.alloc_from_iter(params),
+ predicates: self.arena.alloc_from_iter(predicates),
+ has_where_clause_predicates,
+ where_clause_span,
+ span,
+ });
+
+ (lowered_generics, res)
+ }
+
+ pub(super) fn lower_generic_bound_predicate(
+ &mut self,
+ ident: Ident,
+ id: NodeId,
+ kind: &GenericParamKind,
+ bounds: &[GenericBound],
+ itctx: ImplTraitContext,
+ origin: PredicateOrigin,
+ ) -> Option<hir::WherePredicate<'hir>> {
+ // Do not create a clause if we do not have anything inside it.
+ if bounds.is_empty() {
+ return None;
+ }
+
+ let bounds = self.lower_param_bounds(bounds, itctx);
+
+ let ident = self.lower_ident(ident);
+ let param_span = ident.span;
+ let span = bounds
+ .iter()
+ .fold(Some(param_span.shrink_to_hi()), |span: Option<Span>, bound| {
+ let bound_span = bound.span();
+ // We include bounds that come from a `#[derive(_)]` but point at the user's code,
+ // as we use this method to get a span appropriate for suggestions.
+ if !bound_span.can_be_used_for_suggestions() {
+ None
+ } else if let Some(span) = span {
+ Some(span.to(bound_span))
+ } else {
+ Some(bound_span)
+ }
+ })
+ .unwrap_or(param_span.shrink_to_hi());
+ match kind {
+ GenericParamKind::Const { .. } => None,
+ GenericParamKind::Type { .. } => {
+ let def_id = self.local_def_id(id).to_def_id();
+ let ty_path = self.arena.alloc(hir::Path {
+ span: param_span,
+ res: Res::Def(DefKind::TyParam, def_id),
+ segments: self.arena.alloc_from_iter([hir::PathSegment::from_ident(ident)]),
+ });
+ let ty_id = self.next_id();
+ let bounded_ty =
+ self.ty_path(ty_id, param_span, hir::QPath::Resolved(None, ty_path));
+ Some(hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
+ bounded_ty: self.arena.alloc(bounded_ty),
+ bounds,
+ span,
+ bound_generic_params: &[],
+ origin,
+ }))
+ }
+ GenericParamKind::Lifetime => {
+ let ident_span = self.lower_span(ident.span);
+ let ident = self.lower_ident(ident);
+ let lt_id = self.next_node_id();
+ let lifetime = self.new_named_lifetime(id, lt_id, ident_span, ident);
+ Some(hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
+ lifetime,
+ span,
+ bounds,
+ in_where_clause: false,
+ }))
+ }
+ }
+ }
+
+ fn lower_where_predicate(&mut self, pred: &WherePredicate) -> hir::WherePredicate<'hir> {
+ match *pred {
+ WherePredicate::BoundPredicate(WhereBoundPredicate {
+ ref bound_generic_params,
+ ref bounded_ty,
+ ref bounds,
+ span,
+ }) => hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
+ bound_generic_params: self.lower_generic_params(bound_generic_params),
+ bounded_ty: self
+ .lower_ty(bounded_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)),
+ bounds: self.arena.alloc_from_iter(bounds.iter().map(|bound| {
+ self.lower_param_bound(
+ bound,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
+ )
+ })),
+ span: self.lower_span(span),
+ origin: PredicateOrigin::WhereClause,
+ }),
+ WherePredicate::RegionPredicate(WhereRegionPredicate {
+ ref lifetime,
+ ref bounds,
+ span,
+ }) => hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
+ span: self.lower_span(span),
+ lifetime: self.lower_lifetime(lifetime),
+ bounds: self.lower_param_bounds(
+ bounds,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
+ ),
+ in_where_clause: true,
+ }),
+ WherePredicate::EqPredicate(WhereEqPredicate { id, ref lhs_ty, ref rhs_ty, span }) => {
+ hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
+ hir_id: self.lower_node_id(id),
+ lhs_ty: self
+ .lower_ty(lhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)),
+ rhs_ty: self
+ .lower_ty(rhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)),
+ span: self.lower_span(span),
+ })
+ }
+ }
+ }
+}
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
new file mode 100644
index 000000000..224dc3c23
--- /dev/null
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -0,0 +1,2501 @@
+//! Lowers the AST to the HIR.
+//!
+//! Since the AST and HIR are fairly similar, this is mostly a simple procedure,
+//! much like a fold. Where lowering involves a bit more work things get more
+//! interesting and there are some invariants you should know about. These mostly
+//! concern spans and IDs.
+//!
+//! Spans are assigned to AST nodes during parsing and then are modified during
+//! expansion to indicate the origin of a node and the process it went through
+//! being expanded. IDs are assigned to AST nodes just before lowering.
+//!
+//! For the simpler lowering steps, IDs and spans should be preserved. Unlike
+//! expansion we do not preserve the process of lowering in the spans, so spans
+//! should not be modified here. When creating a new node (as opposed to
+//! "folding" an existing one), create a new ID using `next_id()`.
+//!
+//! You must ensure that IDs are unique. That means that you should only use the
+//! ID from an AST node in a single HIR node (you can assume that AST node-IDs
+//! are unique). Every new node must have a unique ID. Avoid cloning HIR nodes.
+//! If you do, you must then set the new node's ID to a fresh one.
+//!
+//! Spans are used for error messages and for tools to map semantics back to
+//! source code. It is therefore not as important with spans as IDs to be strict
+//! about use (you can't break the compiler by screwing up a span). Obviously, a
+//! HIR node can only have a single span. But multiple nodes can have the same
+//! span and spans don't need to be kept in order, etc. Where code is preserved
+//! by lowering, it should have the same span as in the AST. Where HIR nodes are
+//! new it is probably best to give a span for the whole AST node being lowered.
+//! All nodes should have real spans; don't use dummy spans. Tools are likely to
+//! get confused if the spans from leaf AST nodes occur in multiple places
+//! in the HIR, especially for multiple identifiers.
+
+#![feature(box_patterns)]
+#![feature(let_chains)]
+#![feature(let_else)]
+#![feature(never_type)]
+#![recursion_limit = "256"]
+#![allow(rustc::potential_query_instability)]
+
+#[macro_use]
+extern crate tracing;
+
+use rustc_ast::visit;
+use rustc_ast::{self as ast, *};
+use rustc_ast_pretty::pprust;
+use rustc_data_structures::captures::Captures;
+use rustc_data_structures::fingerprint::Fingerprint;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::sorted_map::SortedMap;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::sync::Lrc;
+use rustc_errors::{struct_span_err, Applicability, Handler};
+use rustc_hir as hir;
+use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
+use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
+use rustc_hir::definitions::DefPathData;
+use rustc_hir::{ConstArg, GenericArg, ItemLocalId, ParamName, TraitCandidate};
+use rustc_index::vec::{Idx, IndexVec};
+use rustc_middle::span_bug;
+use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
+use rustc_session::parse::feature_err;
+use rustc_span::hygiene::MacroKind;
+use rustc_span::source_map::DesugaringKind;
+use rustc_span::symbol::{kw, sym, Ident, Symbol};
+use rustc_span::{Span, DUMMY_SP};
+
+use smallvec::SmallVec;
+use std::collections::hash_map::Entry;
+
+macro_rules! arena_vec {
+ ($this:expr; $($x:expr),*) => (
+ $this.arena.alloc_from_iter([$($x),*])
+ );
+}
+
+mod asm;
+mod block;
+mod expr;
+mod index;
+mod item;
+mod lifetime_collector;
+mod pat;
+mod path;
+
+struct LoweringContext<'a, 'hir> {
+ tcx: TyCtxt<'hir>,
+ resolver: &'a mut ResolverAstLowering,
+
+ /// Used to allocate HIR nodes.
+ arena: &'hir hir::Arena<'hir>,
+
+ /// Bodies inside the owner being lowered.
+ bodies: Vec<(hir::ItemLocalId, &'hir hir::Body<'hir>)>,
+ /// Attributes inside the owner being lowered.
+ attrs: SortedMap<hir::ItemLocalId, &'hir [Attribute]>,
+ /// Collect items that were created by lowering the current owner.
+ children: FxHashMap<LocalDefId, hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>>>,
+
+ generator_kind: Option<hir::GeneratorKind>,
+
+ /// When inside an `async` context, this is the `HirId` of the
+ /// `task_context` local bound to the resume argument of the generator.
+ task_context: Option<hir::HirId>,
+
+ /// Used to get the current `fn`'s def span to point to when using `await`
+ /// outside of an `async fn`.
+ current_item: Option<Span>,
+
+ catch_scope: Option<NodeId>,
+ loop_scope: Option<NodeId>,
+ is_in_loop_condition: bool,
+ is_in_trait_impl: bool,
+ is_in_dyn_type: bool,
+
+ current_hir_id_owner: LocalDefId,
+ item_local_id_counter: hir::ItemLocalId,
+ local_id_to_def_id: SortedMap<ItemLocalId, LocalDefId>,
+ trait_map: FxHashMap<ItemLocalId, Box<[TraitCandidate]>>,
+
+ impl_trait_defs: Vec<hir::GenericParam<'hir>>,
+ impl_trait_bounds: Vec<hir::WherePredicate<'hir>>,
+
+ /// NodeIds that are lowered inside the current HIR owner.
+ node_id_to_local_id: FxHashMap<NodeId, hir::ItemLocalId>,
+
+ allow_try_trait: Option<Lrc<[Symbol]>>,
+ allow_gen_future: Option<Lrc<[Symbol]>>,
+ allow_into_future: Option<Lrc<[Symbol]>>,
+}
+
+trait ResolverAstLoweringExt {
+ fn legacy_const_generic_args(&self, expr: &Expr) -> Option<Vec<usize>>;
+ fn get_partial_res(&self, id: NodeId) -> Option<PartialRes>;
+ fn get_import_res(&self, id: NodeId) -> PerNS<Option<Res<NodeId>>>;
+ fn get_label_res(&self, id: NodeId) -> Option<NodeId>;
+ fn get_lifetime_res(&self, id: NodeId) -> Option<LifetimeRes>;
+ fn take_extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)>;
+ fn decl_macro_kind(&self, def_id: LocalDefId) -> MacroKind;
+ /// Record the map from `from` local def id to `to` local def id, on `generics_def_id_map`
+ /// field.
+ fn record_def_id_remap(&mut self, from: LocalDefId, to: LocalDefId);
+ /// Get the previously recorded `to` local def id given the `from` local def id, obtained using
+ /// `generics_def_id_map` field.
+ fn get_remapped_def_id(&self, local_def_id: LocalDefId) -> LocalDefId;
+}
+
+impl ResolverAstLoweringExt for ResolverAstLowering {
+ fn legacy_const_generic_args(&self, expr: &Expr) -> Option<Vec<usize>> {
+ if let ExprKind::Path(None, path) = &expr.kind {
+ // Don't perform legacy const generics rewriting if the path already
+ // has generic arguments.
+ if path.segments.last().unwrap().args.is_some() {
+ return None;
+ }
+
+ let partial_res = self.partial_res_map.get(&expr.id)?;
+ if partial_res.unresolved_segments() != 0 {
+ return None;
+ }
+
+ if let Res::Def(DefKind::Fn, def_id) = partial_res.base_res() {
+ // We only support cross-crate argument rewriting. Uses
+ // within the same crate should be updated to use the new
+ // const generics style.
+ if def_id.is_local() {
+ return None;
+ }
+
+ if let Some(v) = self.legacy_const_generic_args.get(&def_id) {
+ return v.clone();
+ }
+ }
+ }
+
+ None
+ }
+
+ /// Obtains resolution for a `NodeId` with a single resolution.
+ fn get_partial_res(&self, id: NodeId) -> Option<PartialRes> {
+ self.partial_res_map.get(&id).copied()
+ }
+
+ /// Obtains per-namespace resolutions for `use` statement with the given `NodeId`.
+ fn get_import_res(&self, id: NodeId) -> PerNS<Option<Res<NodeId>>> {
+ self.import_res_map.get(&id).copied().unwrap_or_default()
+ }
+
+ /// Obtains resolution for a label with the given `NodeId`.
+ fn get_label_res(&self, id: NodeId) -> Option<NodeId> {
+ self.label_res_map.get(&id).copied()
+ }
+
+ /// Obtains resolution for a lifetime with the given `NodeId`.
+ fn get_lifetime_res(&self, id: NodeId) -> Option<LifetimeRes> {
+ self.lifetimes_res_map.get(&id).copied()
+ }
+
+ /// Obtain the list of lifetimes parameters to add to an item.
+ ///
+ /// Extra lifetime parameters should only be added in places that can appear
+ /// as a `binder` in `LifetimeRes`.
+ ///
+ /// The extra lifetimes that appear from the parenthesized `Fn`-trait desugaring
+ /// should appear at the enclosing `PolyTraitRef`.
+ fn take_extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)> {
+ self.extra_lifetime_params_map.remove(&id).unwrap_or_default()
+ }
+
+ fn decl_macro_kind(&self, def_id: LocalDefId) -> MacroKind {
+ self.builtin_macro_kinds.get(&def_id).copied().unwrap_or(MacroKind::Bang)
+ }
+
+ /// Push a remapping into the top-most map.
+ /// Panics if no map has been pushed.
+ /// Remapping is used when creating lowering `-> impl Trait` return
+ /// types to create the resulting opaque type.
+ #[tracing::instrument(level = "debug", skip(self))]
+ fn record_def_id_remap(&mut self, from: LocalDefId, to: LocalDefId) {
+ self.generics_def_id_map.last_mut().expect("no map pushed").insert(from, to);
+ }
+
+ fn get_remapped_def_id(&self, mut local_def_id: LocalDefId) -> LocalDefId {
+ // `generics_def_id_map` is a stack of mappings. As we go deeper in impl traits nesting we
+ // push new mappings so we need to try first the latest mappings, hence `iter().rev()`.
+ //
+ // Consider:
+ //
+ // `fn test<'a, 'b>() -> impl Trait<&'a u8, Ty = impl Sized + 'b> {}`
+ //
+ // We would end with a generics_def_id_map like:
+ //
+ // `[[fn#'b -> impl_trait#'b], [fn#'b -> impl_sized#'b]]`
+ //
+ // for the opaque type generated on `impl Sized + 'b`, We want the result to be:
+ // impl_sized#'b, so iterating forward is the wrong thing to do.
+ for map in self.generics_def_id_map.iter().rev() {
+ if let Some(r) = map.get(&local_def_id) {
+ debug!("def_id_remapper: remapping from `{local_def_id:?}` to `{r:?}`");
+ local_def_id = *r;
+ } else {
+ debug!("def_id_remapper: no remapping for `{local_def_id:?}` found in map");
+ }
+ }
+
+ local_def_id
+ }
+}
+
+/// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree,
+/// and if so, what meaning it has.
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+enum ImplTraitContext {
+ /// Treat `impl Trait` as shorthand for a new universal generic parameter.
+ /// Example: `fn foo(x: impl Debug)`, where `impl Debug` is conceptually
+ /// equivalent to a fresh universal parameter like `fn foo<T: Debug>(x: T)`.
+ ///
+ /// Newly generated parameters should be inserted into the given `Vec`.
+ Universal,
+
+ /// Treat `impl Trait` as shorthand for a new opaque type.
+ /// Example: `fn foo() -> impl Debug`, where `impl Debug` is conceptually
+ /// equivalent to a new opaque type like `type T = impl Debug; fn foo() -> T`.
+ ///
+ ReturnPositionOpaqueTy {
+ /// Origin: Either OpaqueTyOrigin::FnReturn or OpaqueTyOrigin::AsyncFn,
+ origin: hir::OpaqueTyOrigin,
+ },
+ /// Impl trait in type aliases.
+ TypeAliasesOpaqueTy,
+ /// `impl Trait` is not accepted in this position.
+ Disallowed(ImplTraitPosition),
+}
+
+/// Position in which `impl Trait` is disallowed.
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+enum ImplTraitPosition {
+ Path,
+ Variable,
+ Type,
+ Trait,
+ AsyncBlock,
+ Bound,
+ Generic,
+ ExternFnParam,
+ ClosureParam,
+ PointerParam,
+ FnTraitParam,
+ TraitParam,
+ ImplParam,
+ ExternFnReturn,
+ ClosureReturn,
+ PointerReturn,
+ FnTraitReturn,
+ TraitReturn,
+ ImplReturn,
+}
+
+impl std::fmt::Display for ImplTraitPosition {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ let name = match self {
+ ImplTraitPosition::Path => "path",
+ ImplTraitPosition::Variable => "variable binding",
+ ImplTraitPosition::Type => "type",
+ ImplTraitPosition::Trait => "trait",
+ ImplTraitPosition::AsyncBlock => "async block",
+ ImplTraitPosition::Bound => "bound",
+ ImplTraitPosition::Generic => "generic",
+ ImplTraitPosition::ExternFnParam => "`extern fn` param",
+ ImplTraitPosition::ClosureParam => "closure param",
+ ImplTraitPosition::PointerParam => "`fn` pointer param",
+ ImplTraitPosition::FnTraitParam => "`Fn` trait param",
+ ImplTraitPosition::TraitParam => "trait method param",
+ ImplTraitPosition::ImplParam => "`impl` method param",
+ ImplTraitPosition::ExternFnReturn => "`extern fn` return",
+ ImplTraitPosition::ClosureReturn => "closure return",
+ ImplTraitPosition::PointerReturn => "`fn` pointer return",
+ ImplTraitPosition::FnTraitReturn => "`Fn` trait return",
+ ImplTraitPosition::TraitReturn => "trait method return",
+ ImplTraitPosition::ImplReturn => "`impl` method return",
+ };
+
+ write!(f, "{}", name)
+ }
+}
+
+#[derive(Debug)]
+enum FnDeclKind {
+ Fn,
+ Inherent,
+ ExternFn,
+ Closure,
+ Pointer,
+ Trait,
+ Impl,
+}
+
+impl FnDeclKind {
+ fn impl_trait_return_allowed(&self) -> bool {
+ match self {
+ FnDeclKind::Fn | FnDeclKind::Inherent => true,
+ _ => false,
+ }
+ }
+}
+
+#[derive(Copy, Clone)]
+enum AstOwner<'a> {
+ NonOwner,
+ Crate(&'a ast::Crate),
+ Item(&'a ast::Item),
+ AssocItem(&'a ast::AssocItem, visit::AssocCtxt),
+ ForeignItem(&'a ast::ForeignItem),
+}
+
+fn index_crate<'a>(
+ node_id_to_def_id: &FxHashMap<NodeId, LocalDefId>,
+ krate: &'a Crate,
+) -> IndexVec<LocalDefId, AstOwner<'a>> {
+ let mut indexer = Indexer { node_id_to_def_id, index: IndexVec::new() };
+ indexer.index.ensure_contains_elem(CRATE_DEF_ID, || AstOwner::NonOwner);
+ indexer.index[CRATE_DEF_ID] = AstOwner::Crate(krate);
+ visit::walk_crate(&mut indexer, krate);
+ return indexer.index;
+
+ struct Indexer<'s, 'a> {
+ node_id_to_def_id: &'s FxHashMap<NodeId, LocalDefId>,
+ index: IndexVec<LocalDefId, AstOwner<'a>>,
+ }
+
+ impl<'a> visit::Visitor<'a> for Indexer<'_, 'a> {
+ fn visit_attribute(&mut self, _: &'a Attribute) {
+ // We do not want to lower expressions that appear in attributes,
+ // as they are not accessible to the rest of the HIR.
+ }
+
+ fn visit_item(&mut self, item: &'a ast::Item) {
+ let def_id = self.node_id_to_def_id[&item.id];
+ self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner);
+ self.index[def_id] = AstOwner::Item(item);
+ visit::walk_item(self, item)
+ }
+
+ fn visit_assoc_item(&mut self, item: &'a ast::AssocItem, ctxt: visit::AssocCtxt) {
+ let def_id = self.node_id_to_def_id[&item.id];
+ self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner);
+ self.index[def_id] = AstOwner::AssocItem(item, ctxt);
+ visit::walk_assoc_item(self, item, ctxt);
+ }
+
+ fn visit_foreign_item(&mut self, item: &'a ast::ForeignItem) {
+ let def_id = self.node_id_to_def_id[&item.id];
+ self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner);
+ self.index[def_id] = AstOwner::ForeignItem(item);
+ visit::walk_foreign_item(self, item);
+ }
+ }
+}
+
+/// Compute the hash for the HIR of the full crate.
+/// This hash will then be part of the crate_hash which is stored in the metadata.
+fn compute_hir_hash(
+ tcx: TyCtxt<'_>,
+ owners: &IndexVec<LocalDefId, hir::MaybeOwner<&hir::OwnerInfo<'_>>>,
+) -> Fingerprint {
+ let mut hir_body_nodes: Vec<_> = owners
+ .iter_enumerated()
+ .filter_map(|(def_id, info)| {
+ let info = info.as_owner()?;
+ let def_path_hash = tcx.hir().def_path_hash(def_id);
+ Some((def_path_hash, info))
+ })
+ .collect();
+ hir_body_nodes.sort_unstable_by_key(|bn| bn.0);
+
+ tcx.with_stable_hashing_context(|mut hcx| {
+ let mut stable_hasher = StableHasher::new();
+ hir_body_nodes.hash_stable(&mut hcx, &mut stable_hasher);
+ stable_hasher.finish()
+ })
+}
+
+pub fn lower_to_hir<'hir>(tcx: TyCtxt<'hir>, (): ()) -> hir::Crate<'hir> {
+ let sess = tcx.sess;
+ let krate = tcx.untracked_crate.steal();
+ let mut resolver = tcx.resolver_for_lowering(()).steal();
+
+ let ast_index = index_crate(&resolver.node_id_to_def_id, &krate);
+ let mut owners = IndexVec::from_fn_n(
+ |_| hir::MaybeOwner::Phantom,
+ tcx.definitions_untracked().def_index_count(),
+ );
+
+ for def_id in ast_index.indices() {
+ item::ItemLowerer {
+ tcx,
+ resolver: &mut resolver,
+ ast_index: &ast_index,
+ owners: &mut owners,
+ }
+ .lower_node(def_id);
+ }
+
+ // Drop AST to free memory
+ std::mem::drop(ast_index);
+ sess.time("drop_ast", || std::mem::drop(krate));
+
+ // Discard hygiene data, which isn't required after lowering to HIR.
+ if !sess.opts.unstable_opts.keep_hygiene_data {
+ rustc_span::hygiene::clear_syntax_context_map();
+ }
+
+ let hir_hash = compute_hir_hash(tcx, &owners);
+ hir::Crate { owners, hir_hash }
+}
+
+#[derive(Copy, Clone, PartialEq, Debug)]
+enum ParamMode {
+ /// Any path in a type context.
+ Explicit,
+ /// Path in a type definition, where the anonymous lifetime `'_` is not allowed.
+ ExplicitNamed,
+ /// The `module::Type` in `module::Type::method` in an expression.
+ Optional,
+}
+
+enum ParenthesizedGenericArgs {
+ Ok,
+ Err,
+}
+
+impl<'a, 'hir> LoweringContext<'a, 'hir> {
+ fn create_def(
+ &mut self,
+ parent: LocalDefId,
+ node_id: ast::NodeId,
+ data: DefPathData,
+ ) -> LocalDefId {
+ debug_assert_ne!(node_id, ast::DUMMY_NODE_ID);
+ assert!(
+ self.opt_local_def_id(node_id).is_none(),
+ "adding a def'n for node-id {:?} and data {:?} but a previous def'n exists: {:?}",
+ node_id,
+ data,
+ self.tcx.hir().def_key(self.local_def_id(node_id)),
+ );
+
+ let def_id = self.tcx.create_def(parent, data);
+
+ debug!("create_def: def_id_to_node_id[{:?}] <-> {:?}", def_id, node_id);
+ self.resolver.node_id_to_def_id.insert(node_id, def_id);
+
+ def_id
+ }
+
+ fn next_node_id(&mut self) -> NodeId {
+ let start = self.resolver.next_node_id;
+ let next = start.as_u32().checked_add(1).expect("input too large; ran out of NodeIds");
+ self.resolver.next_node_id = ast::NodeId::from_u32(next);
+ start
+ }
+
+ /// Given the id of some node in the AST, finds the `LocalDefId` associated with it by the name
+ /// resolver (if any), after applying any remapping from `get_remapped_def_id`.
+ ///
+ /// For example, in a function like `fn foo<'a>(x: &'a u32)`,
+ /// invoking with the id from the `ast::Lifetime` node found inside
+ /// the `&'a u32` type would return the `LocalDefId` of the
+ /// `'a` parameter declared on `foo`.
+ ///
+ /// This function also applies remapping from `get_remapped_def_id`.
+ /// These are used when synthesizing opaque types from `-> impl Trait` return types and so forth.
+ /// For example, in a function like `fn foo<'a>() -> impl Debug + 'a`,
+ /// we would create an opaque type `type FooReturn<'a1> = impl Debug + 'a1`.
+ /// When lowering the `Debug + 'a` bounds, we add a remapping to map `'a` to `'a1`.
+ fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> {
+ self.resolver
+ .node_id_to_def_id
+ .get(&node)
+ .map(|local_def_id| self.resolver.get_remapped_def_id(*local_def_id))
+ }
+
+ fn local_def_id(&self, node: NodeId) -> LocalDefId {
+ self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{:?}`", node))
+ }
+
+ /// Freshen the `LoweringContext` and ready it to lower a nested item.
+ /// The lowered item is registered into `self.children`.
+ ///
+ /// This function sets up `HirId` lowering infrastructure,
+ /// and stashes the shared mutable state to avoid pollution by the closure.
+ #[instrument(level = "debug", skip(self, f))]
+ fn with_hir_id_owner(
+ &mut self,
+ owner: NodeId,
+ f: impl FnOnce(&mut Self) -> hir::OwnerNode<'hir>,
+ ) {
+ let def_id = self.local_def_id(owner);
+
+ let current_attrs = std::mem::take(&mut self.attrs);
+ let current_bodies = std::mem::take(&mut self.bodies);
+ let current_node_ids = std::mem::take(&mut self.node_id_to_local_id);
+ let current_id_to_def_id = std::mem::take(&mut self.local_id_to_def_id);
+ let current_trait_map = std::mem::take(&mut self.trait_map);
+ let current_owner = std::mem::replace(&mut self.current_hir_id_owner, def_id);
+ let current_local_counter =
+ std::mem::replace(&mut self.item_local_id_counter, hir::ItemLocalId::new(1));
+ let current_impl_trait_defs = std::mem::take(&mut self.impl_trait_defs);
+ let current_impl_trait_bounds = std::mem::take(&mut self.impl_trait_bounds);
+
+ // Do not reset `next_node_id` and `node_id_to_def_id`:
+ // we want `f` to be able to refer to the `LocalDefId`s that the caller created.
+ // and the caller to refer to some of the subdefinitions' nodes' `LocalDefId`s.
+
+ // Always allocate the first `HirId` for the owner itself.
+ let _old = self.node_id_to_local_id.insert(owner, hir::ItemLocalId::new(0));
+ debug_assert_eq!(_old, None);
+
+ let item = f(self);
+ debug_assert_eq!(def_id, item.def_id());
+ // `f` should have consumed all the elements in these vectors when constructing `item`.
+ debug_assert!(self.impl_trait_defs.is_empty());
+ debug_assert!(self.impl_trait_bounds.is_empty());
+ let info = self.make_owner_info(item);
+
+ self.attrs = current_attrs;
+ self.bodies = current_bodies;
+ self.node_id_to_local_id = current_node_ids;
+ self.local_id_to_def_id = current_id_to_def_id;
+ self.trait_map = current_trait_map;
+ self.current_hir_id_owner = current_owner;
+ self.item_local_id_counter = current_local_counter;
+ self.impl_trait_defs = current_impl_trait_defs;
+ self.impl_trait_bounds = current_impl_trait_bounds;
+
+ let _old = self.children.insert(def_id, hir::MaybeOwner::Owner(info));
+ debug_assert!(_old.is_none())
+ }
+
+ /// Installs the remapping `remap` in scope while `f` is being executed.
+ /// This causes references to the `LocalDefId` keys to be changed to
+ /// refer to the values instead.
+ ///
+ /// The remapping is used when one piece of AST expands to multiple
+ /// pieces of HIR. For example, the function `fn foo<'a>(...) -> impl Debug + 'a`,
+ /// expands to both a function definition (`foo`) and a TAIT for the return value,
+ /// both of which have a lifetime parameter `'a`. The remapping allows us to
+ /// rewrite the `'a` in the return value to refer to the
+ /// `'a` declared on the TAIT, instead of the function.
+ fn with_remapping<R>(
+ &mut self,
+ remap: FxHashMap<LocalDefId, LocalDefId>,
+ f: impl FnOnce(&mut Self) -> R,
+ ) -> R {
+ self.resolver.generics_def_id_map.push(remap);
+ let res = f(self);
+ self.resolver.generics_def_id_map.pop();
+ res
+ }
+
+ fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> &'hir hir::OwnerInfo<'hir> {
+ let attrs = std::mem::take(&mut self.attrs);
+ let mut bodies = std::mem::take(&mut self.bodies);
+ let local_id_to_def_id = std::mem::take(&mut self.local_id_to_def_id);
+ let trait_map = std::mem::take(&mut self.trait_map);
+
+ #[cfg(debug_assertions)]
+ for (id, attrs) in attrs.iter() {
+ // Verify that we do not store empty slices in the map.
+ if attrs.is_empty() {
+ panic!("Stored empty attributes for {:?}", id);
+ }
+ }
+
+ bodies.sort_by_key(|(k, _)| *k);
+ let bodies = SortedMap::from_presorted_elements(bodies);
+ let (hash_including_bodies, hash_without_bodies) = self.hash_owner(node, &bodies);
+ let (nodes, parenting) =
+ index::index_hir(self.tcx.sess, &*self.tcx.definitions_untracked(), node, &bodies);
+ let nodes = hir::OwnerNodes {
+ hash_including_bodies,
+ hash_without_bodies,
+ nodes,
+ bodies,
+ local_id_to_def_id,
+ };
+ let attrs = {
+ let hash = self.tcx.with_stable_hashing_context(|mut hcx| {
+ let mut stable_hasher = StableHasher::new();
+ attrs.hash_stable(&mut hcx, &mut stable_hasher);
+ stable_hasher.finish()
+ });
+ hir::AttributeMap { map: attrs, hash }
+ };
+
+ self.arena.alloc(hir::OwnerInfo { nodes, parenting, attrs, trait_map })
+ }
+
+ /// Hash the HIR node twice, one deep and one shallow hash. This allows to differentiate
+ /// queries which depend on the full HIR tree and those which only depend on the item signature.
+ fn hash_owner(
+ &mut self,
+ node: hir::OwnerNode<'hir>,
+ bodies: &SortedMap<hir::ItemLocalId, &'hir hir::Body<'hir>>,
+ ) -> (Fingerprint, Fingerprint) {
+ self.tcx.with_stable_hashing_context(|mut hcx| {
+ let mut stable_hasher = StableHasher::new();
+ hcx.with_hir_bodies(true, node.def_id(), bodies, |hcx| {
+ node.hash_stable(hcx, &mut stable_hasher)
+ });
+ let hash_including_bodies = stable_hasher.finish();
+ let mut stable_hasher = StableHasher::new();
+ hcx.with_hir_bodies(false, node.def_id(), bodies, |hcx| {
+ node.hash_stable(hcx, &mut stable_hasher)
+ });
+ let hash_without_bodies = stable_hasher.finish();
+ (hash_including_bodies, hash_without_bodies)
+ })
+ }
+
+ /// This method allocates a new `HirId` for the given `NodeId` and stores it in
+ /// the `LoweringContext`'s `NodeId => HirId` map.
+ /// Take care not to call this method if the resulting `HirId` is then not
+ /// actually used in the HIR, as that would trigger an assertion in the
+ /// `HirIdValidator` later on, which makes sure that all `NodeId`s got mapped
+ /// properly. Calling the method twice with the same `NodeId` is fine though.
+ fn lower_node_id(&mut self, ast_node_id: NodeId) -> hir::HirId {
+ assert_ne!(ast_node_id, DUMMY_NODE_ID);
+
+ match self.node_id_to_local_id.entry(ast_node_id) {
+ Entry::Occupied(o) => {
+ hir::HirId { owner: self.current_hir_id_owner, local_id: *o.get() }
+ }
+ Entry::Vacant(v) => {
+ // Generate a new `HirId`.
+ let owner = self.current_hir_id_owner;
+ let local_id = self.item_local_id_counter;
+ let hir_id = hir::HirId { owner, local_id };
+
+ v.insert(local_id);
+ self.item_local_id_counter.increment_by(1);
+
+ assert_ne!(local_id, hir::ItemLocalId::new(0));
+ if let Some(def_id) = self.opt_local_def_id(ast_node_id) {
+ // Do not override a `MaybeOwner::Owner` that may already here.
+ self.children.entry(def_id).or_insert(hir::MaybeOwner::NonOwner(hir_id));
+ self.local_id_to_def_id.insert(local_id, def_id);
+ }
+
+ if let Some(traits) = self.resolver.trait_map.remove(&ast_node_id) {
+ self.trait_map.insert(hir_id.local_id, traits.into_boxed_slice());
+ }
+
+ hir_id
+ }
+ }
+ }
+
+ /// Generate a new `HirId` without a backing `NodeId`.
+ fn next_id(&mut self) -> hir::HirId {
+ let owner = self.current_hir_id_owner;
+ let local_id = self.item_local_id_counter;
+ assert_ne!(local_id, hir::ItemLocalId::new(0));
+ self.item_local_id_counter.increment_by(1);
+ hir::HirId { owner, local_id }
+ }
+
+ #[instrument(level = "trace", skip(self))]
+ fn lower_res(&mut self, res: Res<NodeId>) -> Res {
+ let res: Result<Res, ()> = res.apply_id(|id| {
+ let owner = self.current_hir_id_owner;
+ let local_id = self.node_id_to_local_id.get(&id).copied().ok_or(())?;
+ Ok(hir::HirId { owner, local_id })
+ });
+ trace!(?res);
+
+ // We may fail to find a HirId when the Res points to a Local from an enclosing HIR owner.
+ // This can happen when trying to lower the return type `x` in erroneous code like
+ // async fn foo(x: u8) -> x {}
+ // In that case, `x` is lowered as a function parameter, and the return type is lowered as
+ // an opaque type as a synthesized HIR owner.
+ res.unwrap_or(Res::Err)
+ }
+
+ fn expect_full_res(&mut self, id: NodeId) -> Res<NodeId> {
+ self.resolver.get_partial_res(id).map_or(Res::Err, |pr| {
+ if pr.unresolved_segments() != 0 {
+ panic!("path not fully resolved: {:?}", pr);
+ }
+ pr.base_res()
+ })
+ }
+
+ fn expect_full_res_from_use(&mut self, id: NodeId) -> impl Iterator<Item = Res<NodeId>> {
+ self.resolver.get_import_res(id).present_items()
+ }
+
+ fn diagnostic(&self) -> &Handler {
+ self.tcx.sess.diagnostic()
+ }
+
+ /// Reuses the span but adds information like the kind of the desugaring and features that are
+ /// allowed inside this span.
+ fn mark_span_with_reason(
+ &self,
+ reason: DesugaringKind,
+ span: Span,
+ allow_internal_unstable: Option<Lrc<[Symbol]>>,
+ ) -> Span {
+ self.tcx.with_stable_hashing_context(|hcx| {
+ span.mark_with_reason(allow_internal_unstable, reason, self.tcx.sess.edition(), hcx)
+ })
+ }
+
+ /// Intercept all spans entering HIR.
+ /// Mark a span as relative to the current owning item.
+ fn lower_span(&self, span: Span) -> Span {
+ if self.tcx.sess.opts.unstable_opts.incremental_relative_spans {
+ span.with_parent(Some(self.current_hir_id_owner))
+ } else {
+ // Do not make spans relative when not using incremental compilation.
+ span
+ }
+ }
+
+ fn lower_ident(&self, ident: Ident) -> Ident {
+ Ident::new(ident.name, self.lower_span(ident.span))
+ }
+
+ /// Converts a lifetime into a new generic parameter.
+ #[tracing::instrument(level = "debug", skip(self))]
+ fn lifetime_res_to_generic_param(
+ &mut self,
+ ident: Ident,
+ node_id: NodeId,
+ res: LifetimeRes,
+ ) -> Option<hir::GenericParam<'hir>> {
+ let (name, kind) = match res {
+ LifetimeRes::Param { .. } => {
+ (hir::ParamName::Plain(ident), hir::LifetimeParamKind::Explicit)
+ }
+ LifetimeRes::Fresh { param, .. } => {
+ // Late resolution delegates to us the creation of the `LocalDefId`.
+ let _def_id = self.create_def(
+ self.current_hir_id_owner,
+ param,
+ DefPathData::LifetimeNs(kw::UnderscoreLifetime),
+ );
+ debug!(?_def_id);
+
+ (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided)
+ }
+ LifetimeRes::Static | LifetimeRes::Error => return None,
+ res => panic!(
+ "Unexpected lifetime resolution {:?} for {:?} at {:?}",
+ res, ident, ident.span
+ ),
+ };
+ let hir_id = self.lower_node_id(node_id);
+ Some(hir::GenericParam {
+ hir_id,
+ name,
+ span: self.lower_span(ident.span),
+ pure_wrt_drop: false,
+ kind: hir::GenericParamKind::Lifetime { kind },
+ colon_span: None,
+ })
+ }
+
+ /// Lowers a lifetime binder that defines `generic_params`, returning the corresponding HIR
+ /// nodes. The returned list includes any "extra" lifetime parameters that were added by the
+ /// name resolver owing to lifetime elision; this also populates the resolver's node-id->def-id
+ /// map, so that later calls to `opt_node_id_to_def_id` that refer to these extra lifetime
+ /// parameters will be successful.
+ #[tracing::instrument(level = "debug", skip(self))]
+ #[inline]
+ fn lower_lifetime_binder(
+ &mut self,
+ binder: NodeId,
+ generic_params: &[GenericParam],
+ ) -> &'hir [hir::GenericParam<'hir>] {
+ let mut generic_params: Vec<_> = self.lower_generic_params_mut(generic_params).collect();
+ let extra_lifetimes = self.resolver.take_extra_lifetime_params(binder);
+ debug!(?extra_lifetimes);
+ generic_params.extend(extra_lifetimes.into_iter().filter_map(|(ident, node_id, res)| {
+ self.lifetime_res_to_generic_param(ident, node_id, res)
+ }));
+ let generic_params = self.arena.alloc_from_iter(generic_params);
+ debug!(?generic_params);
+
+ generic_params
+ }
+
+ fn with_dyn_type_scope<T>(&mut self, in_scope: bool, f: impl FnOnce(&mut Self) -> T) -> T {
+ let was_in_dyn_type = self.is_in_dyn_type;
+ self.is_in_dyn_type = in_scope;
+
+ let result = f(self);
+
+ self.is_in_dyn_type = was_in_dyn_type;
+
+ result
+ }
+
+ fn with_new_scopes<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> T {
+ let was_in_loop_condition = self.is_in_loop_condition;
+ self.is_in_loop_condition = false;
+
+ let catch_scope = self.catch_scope.take();
+ let loop_scope = self.loop_scope.take();
+ let ret = f(self);
+ self.catch_scope = catch_scope;
+ self.loop_scope = loop_scope;
+
+ self.is_in_loop_condition = was_in_loop_condition;
+
+ ret
+ }
+
+ fn lower_attrs(&mut self, id: hir::HirId, attrs: &[Attribute]) -> Option<&'hir [Attribute]> {
+ if attrs.is_empty() {
+ None
+ } else {
+ debug_assert_eq!(id.owner, self.current_hir_id_owner);
+ let ret = self.arena.alloc_from_iter(attrs.iter().map(|a| self.lower_attr(a)));
+ debug_assert!(!ret.is_empty());
+ self.attrs.insert(id.local_id, ret);
+ Some(ret)
+ }
+ }
+
+ fn lower_attr(&self, attr: &Attribute) -> Attribute {
+ // Note that we explicitly do not walk the path. Since we don't really
+ // lower attributes (we use the AST version) there is nowhere to keep
+ // the `HirId`s. We don't actually need HIR version of attributes anyway.
+ // Tokens are also not needed after macro expansion and parsing.
+ let kind = match attr.kind {
+ AttrKind::Normal(ref item, _) => AttrKind::Normal(
+ AttrItem {
+ path: item.path.clone(),
+ args: self.lower_mac_args(&item.args),
+ tokens: None,
+ },
+ None,
+ ),
+ AttrKind::DocComment(comment_kind, data) => AttrKind::DocComment(comment_kind, data),
+ };
+
+ Attribute { kind, id: attr.id, style: attr.style, span: self.lower_span(attr.span) }
+ }
+
+ fn alias_attrs(&mut self, id: hir::HirId, target_id: hir::HirId) {
+ debug_assert_eq!(id.owner, self.current_hir_id_owner);
+ debug_assert_eq!(target_id.owner, self.current_hir_id_owner);
+ if let Some(&a) = self.attrs.get(&target_id.local_id) {
+ debug_assert!(!a.is_empty());
+ self.attrs.insert(id.local_id, a);
+ }
+ }
+
+ fn lower_mac_args(&self, args: &MacArgs) -> MacArgs {
+ match *args {
+ MacArgs::Empty => MacArgs::Empty,
+ MacArgs::Delimited(dspan, delim, ref tokens) => {
+ // This is either a non-key-value attribute, or a `macro_rules!` body.
+ // We either not have any nonterminals present (in the case of an attribute),
+ // or have tokens available for all nonterminals in the case of a nested
+ // `macro_rules`: e.g:
+ //
+ // ```rust
+ // macro_rules! outer {
+ // ($e:expr) => {
+ // macro_rules! inner {
+ // () => { $e }
+ // }
+ // }
+ // }
+ // ```
+ //
+ // In both cases, we don't want to synthesize any tokens
+ MacArgs::Delimited(dspan, delim, tokens.flattened())
+ }
+ // This is an inert key-value attribute - it will never be visible to macros
+ // after it gets lowered to HIR. Therefore, we can extract literals to handle
+ // nonterminals in `#[doc]` (e.g. `#[doc = $e]`).
+ MacArgs::Eq(eq_span, MacArgsEq::Ast(ref expr)) => {
+ // In valid code the value always ends up as a single literal. Otherwise, a dummy
+ // literal suffices because the error is handled elsewhere.
+ let lit = if let ExprKind::Lit(lit) = &expr.kind {
+ lit.clone()
+ } else {
+ Lit {
+ token: token::Lit::new(token::LitKind::Err, kw::Empty, None),
+ kind: LitKind::Err(kw::Empty),
+ span: DUMMY_SP,
+ }
+ };
+ MacArgs::Eq(eq_span, MacArgsEq::Hir(lit))
+ }
+ MacArgs::Eq(_, MacArgsEq::Hir(ref lit)) => {
+ unreachable!("in literal form when lowering mac args eq: {:?}", lit)
+ }
+ }
+ }
+
+ /// Given an associated type constraint like one of these:
+ ///
+ /// ```ignore (illustrative)
+ /// T: Iterator<Item: Debug>
+ /// ^^^^^^^^^^^
+ /// T: Iterator<Item = Debug>
+ /// ^^^^^^^^^^^^
+ /// ```
+ ///
+ /// returns a `hir::TypeBinding` representing `Item`.
+ #[instrument(level = "debug", skip(self))]
+ fn lower_assoc_ty_constraint(
+ &mut self,
+ constraint: &AssocConstraint,
+ itctx: ImplTraitContext,
+ ) -> hir::TypeBinding<'hir> {
+ debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", constraint, itctx);
+ // lower generic arguments of identifier in constraint
+ let gen_args = if let Some(ref gen_args) = constraint.gen_args {
+ let gen_args_ctor = match gen_args {
+ GenericArgs::AngleBracketed(ref data) => {
+ self.lower_angle_bracketed_parameter_data(data, ParamMode::Explicit, itctx).0
+ }
+ GenericArgs::Parenthesized(ref data) => {
+ self.emit_bad_parenthesized_trait_in_assoc_ty(data);
+ self.lower_angle_bracketed_parameter_data(
+ &data.as_angle_bracketed_args(),
+ ParamMode::Explicit,
+ itctx,
+ )
+ .0
+ }
+ };
+ gen_args_ctor.into_generic_args(self)
+ } else {
+ self.arena.alloc(hir::GenericArgs::none())
+ };
+
+ let kind = match constraint.kind {
+ AssocConstraintKind::Equality { ref term } => {
+ let term = match term {
+ Term::Ty(ref ty) => self.lower_ty(ty, itctx).into(),
+ Term::Const(ref c) => self.lower_anon_const(c).into(),
+ };
+ hir::TypeBindingKind::Equality { term }
+ }
+ AssocConstraintKind::Bound { ref bounds } => {
+ // Piggy-back on the `impl Trait` context to figure out the correct behavior.
+ let (desugar_to_impl_trait, itctx) = match itctx {
+ // We are in the return position:
+ //
+ // fn foo() -> impl Iterator<Item: Debug>
+ //
+ // so desugar to
+ //
+ // fn foo() -> impl Iterator<Item = impl Debug>
+ ImplTraitContext::ReturnPositionOpaqueTy { .. }
+ | ImplTraitContext::TypeAliasesOpaqueTy { .. } => (true, itctx),
+
+ // We are in the argument position, but within a dyn type:
+ //
+ // fn foo(x: dyn Iterator<Item: Debug>)
+ //
+ // so desugar to
+ //
+ // fn foo(x: dyn Iterator<Item = impl Debug>)
+ ImplTraitContext::Universal if self.is_in_dyn_type => (true, itctx),
+
+ // In `type Foo = dyn Iterator<Item: Debug>` we desugar to
+ // `type Foo = dyn Iterator<Item = impl Debug>` but we have to override the
+ // "impl trait context" to permit `impl Debug` in this position (it desugars
+ // then to an opaque type).
+ //
+ // FIXME: this is only needed until `impl Trait` is allowed in type aliases.
+ ImplTraitContext::Disallowed(_) if self.is_in_dyn_type => {
+ (true, ImplTraitContext::TypeAliasesOpaqueTy)
+ }
+
+ // We are in the parameter position, but not within a dyn type:
+ //
+ // fn foo(x: impl Iterator<Item: Debug>)
+ //
+ // so we leave it as is and this gets expanded in astconv to a bound like
+ // `<T as Iterator>::Item: Debug` where `T` is the type parameter for the
+ // `impl Iterator`.
+ _ => (false, itctx),
+ };
+
+ if desugar_to_impl_trait {
+ // Desugar `AssocTy: Bounds` into `AssocTy = impl Bounds`. We do this by
+ // constructing the HIR for `impl bounds...` and then lowering that.
+
+ let parent_def_id = self.current_hir_id_owner;
+ let impl_trait_node_id = self.next_node_id();
+ self.create_def(parent_def_id, impl_trait_node_id, DefPathData::ImplTrait);
+
+ self.with_dyn_type_scope(false, |this| {
+ let node_id = this.next_node_id();
+ let ty = this.lower_ty(
+ &Ty {
+ id: node_id,
+ kind: TyKind::ImplTrait(impl_trait_node_id, bounds.clone()),
+ span: this.lower_span(constraint.span),
+ tokens: None,
+ },
+ itctx,
+ );
+
+ hir::TypeBindingKind::Equality { term: ty.into() }
+ })
+ } else {
+ // Desugar `AssocTy: Bounds` into a type binding where the
+ // later desugars into a trait predicate.
+ let bounds = self.lower_param_bounds(bounds, itctx);
+
+ hir::TypeBindingKind::Constraint { bounds }
+ }
+ }
+ };
+
+ hir::TypeBinding {
+ hir_id: self.lower_node_id(constraint.id),
+ ident: self.lower_ident(constraint.ident),
+ gen_args,
+ kind,
+ span: self.lower_span(constraint.span),
+ }
+ }
+
+ fn emit_bad_parenthesized_trait_in_assoc_ty(&self, data: &ParenthesizedArgs) {
+ let mut err = self.tcx.sess.struct_span_err(
+ data.span,
+ "parenthesized generic arguments cannot be used in associated type constraints",
+ );
+ // Suggest removing empty parentheses: "Trait()" -> "Trait"
+ if data.inputs.is_empty() {
+ let parentheses_span =
+ data.inputs_span.shrink_to_lo().to(data.inputs_span.shrink_to_hi());
+ err.multipart_suggestion(
+ "remove these parentheses",
+ vec![(parentheses_span, String::new())],
+ Applicability::MaybeIncorrect,
+ );
+ }
+ // Suggest replacing parentheses with angle brackets `Trait(params...)` to `Trait<params...>`
+ else {
+ // Start of parameters to the 1st argument
+ let open_param = data.inputs_span.shrink_to_lo().to(data
+ .inputs
+ .first()
+ .unwrap()
+ .span
+ .shrink_to_lo());
+ // End of last argument to end of parameters
+ let close_param =
+ data.inputs.last().unwrap().span.shrink_to_hi().to(data.inputs_span.shrink_to_hi());
+ err.multipart_suggestion(
+ &format!("use angle brackets instead",),
+ vec![(open_param, String::from("<")), (close_param, String::from(">"))],
+ Applicability::MaybeIncorrect,
+ );
+ }
+ err.emit();
+ }
+
+ #[instrument(level = "debug", skip(self))]
+ fn lower_generic_arg(
+ &mut self,
+ arg: &ast::GenericArg,
+ itctx: ImplTraitContext,
+ ) -> hir::GenericArg<'hir> {
+ match arg {
+ ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(&lt)),
+ ast::GenericArg::Type(ty) => {
+ match ty.kind {
+ TyKind::Infer if self.tcx.features().generic_arg_infer => {
+ return GenericArg::Infer(hir::InferArg {
+ hir_id: self.lower_node_id(ty.id),
+ span: self.lower_span(ty.span),
+ });
+ }
+ // We parse const arguments as path types as we cannot distinguish them during
+ // parsing. We try to resolve that ambiguity by attempting resolution in both the
+ // type and value namespaces. If we resolved the path in the value namespace, we
+ // transform it into a generic const argument.
+ TyKind::Path(ref qself, ref path) => {
+ if let Some(partial_res) = self.resolver.get_partial_res(ty.id) {
+ let res = partial_res.base_res();
+ if !res.matches_ns(Namespace::TypeNS) {
+ debug!(
+ "lower_generic_arg: Lowering type argument as const argument: {:?}",
+ ty,
+ );
+
+ // Construct an AnonConst where the expr is the "ty"'s path.
+
+ let parent_def_id = self.current_hir_id_owner;
+ let node_id = self.next_node_id();
+
+ // Add a definition for the in-band const def.
+ self.create_def(parent_def_id, node_id, DefPathData::AnonConst);
+
+ let span = self.lower_span(ty.span);
+ let path_expr = Expr {
+ id: ty.id,
+ kind: ExprKind::Path(qself.clone(), path.clone()),
+ span,
+ attrs: AttrVec::new(),
+ tokens: None,
+ };
+
+ let ct = self.with_new_scopes(|this| hir::AnonConst {
+ hir_id: this.lower_node_id(node_id),
+ body: this.lower_const_body(path_expr.span, Some(&path_expr)),
+ });
+ return GenericArg::Const(ConstArg { value: ct, span });
+ }
+ }
+ }
+ _ => {}
+ }
+ GenericArg::Type(self.lower_ty_direct(&ty, itctx))
+ }
+ ast::GenericArg::Const(ct) => GenericArg::Const(ConstArg {
+ value: self.lower_anon_const(&ct),
+ span: self.lower_span(ct.value.span),
+ }),
+ }
+ }
+
+ #[instrument(level = "debug", skip(self))]
+ fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext) -> &'hir hir::Ty<'hir> {
+ self.arena.alloc(self.lower_ty_direct(t, itctx))
+ }
+
+ fn lower_path_ty(
+ &mut self,
+ t: &Ty,
+ qself: &Option<QSelf>,
+ path: &Path,
+ param_mode: ParamMode,
+ itctx: ImplTraitContext,
+ ) -> hir::Ty<'hir> {
+ // Check whether we should interpret this as a bare trait object.
+ // This check mirrors the one in late resolution. We only introduce this special case in
+ // the rare occurence we need to lower `Fresh` anonymous lifetimes.
+ // The other cases when a qpath should be opportunistically made a trait object are handled
+ // by `ty_path`.
+ if qself.is_none()
+ && let Some(partial_res) = self.resolver.get_partial_res(t.id)
+ && partial_res.unresolved_segments() == 0
+ && let Res::Def(DefKind::Trait | DefKind::TraitAlias, _) = partial_res.base_res()
+ {
+ let (bounds, lifetime_bound) = self.with_dyn_type_scope(true, |this| {
+ let bound = this.lower_poly_trait_ref(
+ &PolyTraitRef {
+ bound_generic_params: vec![],
+ trait_ref: TraitRef { path: path.clone(), ref_id: t.id },
+ span: t.span
+ },
+ itctx,
+ );
+ let bounds = this.arena.alloc_from_iter([bound]);
+ let lifetime_bound = this.elided_dyn_bound(t.span);
+ (bounds, lifetime_bound)
+ });
+ let kind = hir::TyKind::TraitObject(bounds, lifetime_bound, TraitObjectSyntax::None);
+ return hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.next_id() };
+ }
+
+ let id = self.lower_node_id(t.id);
+ let qpath = self.lower_qpath(t.id, qself, path, param_mode, itctx);
+ self.ty_path(id, t.span, qpath)
+ }
+
+ fn ty(&mut self, span: Span, kind: hir::TyKind<'hir>) -> hir::Ty<'hir> {
+ hir::Ty { hir_id: self.next_id(), kind, span: self.lower_span(span) }
+ }
+
+ fn ty_tup(&mut self, span: Span, tys: &'hir [hir::Ty<'hir>]) -> hir::Ty<'hir> {
+ self.ty(span, hir::TyKind::Tup(tys))
+ }
+
+ fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir> {
+ let kind = match t.kind {
+ TyKind::Infer => hir::TyKind::Infer,
+ TyKind::Err => hir::TyKind::Err,
+ TyKind::Slice(ref ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
+ TyKind::Ptr(ref mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
+ TyKind::Rptr(ref region, ref mt) => {
+ let region = region.unwrap_or_else(|| {
+ let id = if let Some(LifetimeRes::ElidedAnchor { start, end }) =
+ self.resolver.get_lifetime_res(t.id)
+ {
+ debug_assert_eq!(start.plus(1), end);
+ start
+ } else {
+ self.next_node_id()
+ };
+ let span = self.tcx.sess.source_map().next_point(t.span.shrink_to_lo());
+ Lifetime { ident: Ident::new(kw::UnderscoreLifetime, span), id }
+ });
+ let lifetime = self.lower_lifetime(&region);
+ hir::TyKind::Rptr(lifetime, self.lower_mt(mt, itctx))
+ }
+ TyKind::BareFn(ref f) => {
+ let generic_params = self.lower_lifetime_binder(t.id, &f.generic_params);
+ hir::TyKind::BareFn(self.arena.alloc(hir::BareFnTy {
+ generic_params,
+ unsafety: self.lower_unsafety(f.unsafety),
+ abi: self.lower_extern(f.ext),
+ decl: self.lower_fn_decl(&f.decl, None, FnDeclKind::Pointer, None),
+ param_names: self.lower_fn_params_to_names(&f.decl),
+ }))
+ }
+ TyKind::Never => hir::TyKind::Never,
+ TyKind::Tup(ref tys) => hir::TyKind::Tup(
+ self.arena.alloc_from_iter(tys.iter().map(|ty| self.lower_ty_direct(ty, itctx))),
+ ),
+ TyKind::Paren(ref ty) => {
+ return self.lower_ty_direct(ty, itctx);
+ }
+ TyKind::Path(ref qself, ref path) => {
+ return self.lower_path_ty(t, qself, path, ParamMode::Explicit, itctx);
+ }
+ TyKind::ImplicitSelf => {
+ let res = self.expect_full_res(t.id);
+ let res = self.lower_res(res);
+ hir::TyKind::Path(hir::QPath::Resolved(
+ None,
+ self.arena.alloc(hir::Path {
+ res,
+ segments: arena_vec![self; hir::PathSegment::from_ident(
+ Ident::with_dummy_span(kw::SelfUpper)
+ )],
+ span: self.lower_span(t.span),
+ }),
+ ))
+ }
+ TyKind::Array(ref ty, ref length) => {
+ hir::TyKind::Array(self.lower_ty(ty, itctx), self.lower_array_length(length))
+ }
+ TyKind::Typeof(ref expr) => hir::TyKind::Typeof(self.lower_anon_const(expr)),
+ TyKind::TraitObject(ref bounds, kind) => {
+ let mut lifetime_bound = None;
+ let (bounds, lifetime_bound) = self.with_dyn_type_scope(true, |this| {
+ let bounds =
+ this.arena.alloc_from_iter(bounds.iter().filter_map(
+ |bound| match *bound {
+ GenericBound::Trait(
+ ref ty,
+ TraitBoundModifier::None | TraitBoundModifier::MaybeConst,
+ ) => Some(this.lower_poly_trait_ref(ty, itctx)),
+ // `~const ?Bound` will cause an error during AST validation
+ // anyways, so treat it like `?Bound` as compilation proceeds.
+ GenericBound::Trait(
+ _,
+ TraitBoundModifier::Maybe | TraitBoundModifier::MaybeConstMaybe,
+ ) => None,
+ GenericBound::Outlives(ref lifetime) => {
+ if lifetime_bound.is_none() {
+ lifetime_bound = Some(this.lower_lifetime(lifetime));
+ }
+ None
+ }
+ },
+ ));
+ let lifetime_bound =
+ lifetime_bound.unwrap_or_else(|| this.elided_dyn_bound(t.span));
+ (bounds, lifetime_bound)
+ });
+ hir::TyKind::TraitObject(bounds, lifetime_bound, kind)
+ }
+ TyKind::ImplTrait(def_node_id, ref bounds) => {
+ let span = t.span;
+ match itctx {
+ ImplTraitContext::ReturnPositionOpaqueTy { origin } => {
+ self.lower_opaque_impl_trait(span, origin, def_node_id, bounds, itctx)
+ }
+ ImplTraitContext::TypeAliasesOpaqueTy => {
+ let nested_itctx = ImplTraitContext::TypeAliasesOpaqueTy;
+ self.lower_opaque_impl_trait(
+ span,
+ hir::OpaqueTyOrigin::TyAlias,
+ def_node_id,
+ bounds,
+ nested_itctx,
+ )
+ }
+ ImplTraitContext::Universal => {
+ let span = t.span;
+ let ident = Ident::from_str_and_span(&pprust::ty_to_string(t), span);
+ let (param, bounds, path) =
+ self.lower_generic_and_bounds(def_node_id, span, ident, bounds);
+ self.impl_trait_defs.push(param);
+ if let Some(bounds) = bounds {
+ self.impl_trait_bounds.push(bounds);
+ }
+ path
+ }
+ ImplTraitContext::Disallowed(position) => {
+ let mut err = struct_span_err!(
+ self.tcx.sess,
+ t.span,
+ E0562,
+ "`impl Trait` only allowed in function and inherent method return types, not in {}",
+ position
+ );
+ err.emit();
+ hir::TyKind::Err
+ }
+ }
+ }
+ TyKind::MacCall(_) => panic!("`TyKind::MacCall` should have been expanded by now"),
+ TyKind::CVarArgs => {
+ self.tcx.sess.delay_span_bug(
+ t.span,
+ "`TyKind::CVarArgs` should have been handled elsewhere",
+ );
+ hir::TyKind::Err
+ }
+ };
+
+ hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.lower_node_id(t.id) }
+ }
+
+ /// Lowers a `ReturnPositionOpaqueTy` (`-> impl Trait`) or a `TypeAliasesOpaqueTy` (`type F =
+ /// impl Trait`): this creates the associated Opaque Type (TAIT) definition and then returns a
+ /// HIR type that references the TAIT.
+ ///
+ /// Given a function definition like:
+ ///
+ /// ```rust
+ /// fn test<'a, T: Debug>(x: &'a T) -> impl Debug + 'a {
+ /// x
+ /// }
+ /// ```
+ ///
+ /// we will create a TAIT definition in the HIR like
+ ///
+ /// ```
+ /// type TestReturn<'a, T, 'x> = impl Debug + 'x
+ /// ```
+ ///
+ /// and return a type like `TestReturn<'static, T, 'a>`, so that the function looks like:
+ ///
+ /// ```rust
+ /// fn test<'a, T: Debug>(x: &'a T) -> TestReturn<'static, T, 'a>
+ /// ```
+ ///
+ /// Note the subtlety around type parameters! The new TAIT, `TestReturn`, inherits all the
+ /// type parameters from the function `test` (this is implemented in the query layer, they aren't
+ /// added explicitly in the HIR). But this includes all the lifetimes, and we only want to
+ /// capture the lifetimes that are referenced in the bounds. Therefore, we add *extra* lifetime parameters
+ /// for the lifetimes that get captured (`'x`, in our example above) and reference those.
+ #[tracing::instrument(level = "debug", skip(self))]
+ fn lower_opaque_impl_trait(
+ &mut self,
+ span: Span,
+ origin: hir::OpaqueTyOrigin,
+ opaque_ty_node_id: NodeId,
+ bounds: &GenericBounds,
+ itctx: ImplTraitContext,
+ ) -> hir::TyKind<'hir> {
+ // Make sure we know that some funky desugaring has been going on here.
+ // This is a first: there is code in other places like for loop
+ // desugaring that explicitly states that we don't want to track that.
+ // Not tracking it makes lints in rustc and clippy very fragile, as
+ // frequently opened issues show.
+ let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None);
+
+ let opaque_ty_def_id = self.local_def_id(opaque_ty_node_id);
+ debug!(?opaque_ty_def_id);
+
+ // Contains the new lifetime definitions created for the TAIT (if any).
+ let mut collected_lifetimes = Vec::new();
+
+ // If this came from a TAIT (as opposed to a function that returns an RPIT), we only want
+ // to capture the lifetimes that appear in the bounds. So visit the bounds to find out
+ // exactly which ones those are.
+ let lifetimes_to_remap = if origin == hir::OpaqueTyOrigin::TyAlias {
+ // in a TAIT like `type Foo<'a> = impl Foo<'a>`, we don't keep all the lifetime parameters
+ Vec::new()
+ } else {
+ // in fn return position, like the `fn test<'a>() -> impl Debug + 'a` example,
+ // we only keep the lifetimes that appear in the `impl Debug` itself:
+ lifetime_collector::lifetimes_in_bounds(&self.resolver, bounds)
+ };
+ debug!(?lifetimes_to_remap);
+
+ self.with_hir_id_owner(opaque_ty_node_id, |lctx| {
+ let mut new_remapping = FxHashMap::default();
+
+ // If this opaque type is only capturing a subset of the lifetimes (those that appear
+ // in bounds), then create the new lifetime parameters required and create a mapping
+ // from the old `'a` (on the function) to the new `'a` (on the opaque type).
+ collected_lifetimes = lctx.create_lifetime_defs(
+ opaque_ty_def_id,
+ &lifetimes_to_remap,
+ &mut new_remapping,
+ );
+ debug!(?collected_lifetimes);
+ debug!(?new_remapping);
+
+ // Install the remapping from old to new (if any):
+ lctx.with_remapping(new_remapping, |lctx| {
+ // This creates HIR lifetime definitions as `hir::GenericParam`, in the given
+ // example `type TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection
+ // containing `&['x]`.
+ let lifetime_defs = lctx.arena.alloc_from_iter(collected_lifetimes.iter().map(
+ |&(new_node_id, lifetime)| {
+ let hir_id = lctx.lower_node_id(new_node_id);
+ debug_assert_ne!(lctx.opt_local_def_id(new_node_id), None);
+
+ let (name, kind) = if lifetime.ident.name == kw::UnderscoreLifetime {
+ (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided)
+ } else {
+ (
+ hir::ParamName::Plain(lifetime.ident),
+ hir::LifetimeParamKind::Explicit,
+ )
+ };
+
+ hir::GenericParam {
+ hir_id,
+ name,
+ span: lifetime.ident.span,
+ pure_wrt_drop: false,
+ kind: hir::GenericParamKind::Lifetime { kind },
+ colon_span: None,
+ }
+ },
+ ));
+ debug!(?lifetime_defs);
+
+ // Then when we lower the param bounds, references to 'a are remapped to 'a1, so we
+ // get back Debug + 'a1, which is suitable for use on the TAIT.
+ let hir_bounds = lctx.lower_param_bounds(bounds, itctx);
+ debug!(?hir_bounds);
+
+ let opaque_ty_item = hir::OpaqueTy {
+ generics: self.arena.alloc(hir::Generics {
+ params: lifetime_defs,
+ predicates: &[],
+ has_where_clause_predicates: false,
+ where_clause_span: lctx.lower_span(span),
+ span: lctx.lower_span(span),
+ }),
+ bounds: hir_bounds,
+ origin,
+ };
+ debug!(?opaque_ty_item);
+
+ lctx.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span)
+ })
+ });
+
+ // This creates HIR lifetime arguments as `hir::GenericArg`, in the given example `type
+ // TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection containing `&['x]`.
+ let lifetimes =
+ self.arena.alloc_from_iter(collected_lifetimes.into_iter().map(|(_, lifetime)| {
+ let id = self.next_node_id();
+ let span = lifetime.ident.span;
+
+ let ident = if lifetime.ident.name == kw::UnderscoreLifetime {
+ Ident::with_dummy_span(kw::UnderscoreLifetime)
+ } else {
+ lifetime.ident
+ };
+
+ let l = self.new_named_lifetime(lifetime.id, id, span, ident);
+ hir::GenericArg::Lifetime(l)
+ }));
+ debug!(?lifetimes);
+
+ // `impl Trait` now just becomes `Foo<'a, 'b, ..>`.
+ hir::TyKind::OpaqueDef(hir::ItemId { def_id: opaque_ty_def_id }, lifetimes)
+ }
+
+ /// Registers a new opaque type with the proper `NodeId`s and
+ /// returns the lowered node-ID for the opaque type.
+ fn generate_opaque_type(
+ &mut self,
+ opaque_ty_id: LocalDefId,
+ opaque_ty_item: hir::OpaqueTy<'hir>,
+ span: Span,
+ opaque_ty_span: Span,
+ ) -> hir::OwnerNode<'hir> {
+ let opaque_ty_item_kind = hir::ItemKind::OpaqueTy(opaque_ty_item);
+ // Generate an `type Foo = impl Trait;` declaration.
+ trace!("registering opaque type with id {:#?}", opaque_ty_id);
+ let opaque_ty_item = hir::Item {
+ def_id: opaque_ty_id,
+ ident: Ident::empty(),
+ kind: opaque_ty_item_kind,
+ vis_span: self.lower_span(span.shrink_to_lo()),
+ span: self.lower_span(opaque_ty_span),
+ };
+ hir::OwnerNode::Item(self.arena.alloc(opaque_ty_item))
+ }
+
+ /// Given a `parent_def_id`, a list of `lifetimes_in_bounds and a `remapping` hash to be
+ /// filled, this function creates new definitions for `Param` and `Fresh` lifetimes, inserts the
+ /// new definition, adds it to the remapping with the definition of the given lifetime and
+ /// returns a list of lifetimes to be lowered afterwards.
+ fn create_lifetime_defs(
+ &mut self,
+ parent_def_id: LocalDefId,
+ lifetimes_in_bounds: &[Lifetime],
+ remapping: &mut FxHashMap<LocalDefId, LocalDefId>,
+ ) -> Vec<(NodeId, Lifetime)> {
+ let mut result = Vec::new();
+
+ for lifetime in lifetimes_in_bounds {
+ let res = self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error);
+ debug!(?res);
+
+ match res {
+ LifetimeRes::Param { param: old_def_id, binder: _ } => {
+ if remapping.get(&old_def_id).is_none() {
+ let node_id = self.next_node_id();
+
+ let new_def_id = self.create_def(
+ parent_def_id,
+ node_id,
+ DefPathData::LifetimeNs(lifetime.ident.name),
+ );
+ remapping.insert(old_def_id, new_def_id);
+
+ result.push((node_id, *lifetime));
+ }
+ }
+
+ LifetimeRes::Fresh { param, binder: _ } => {
+ debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime);
+ if let Some(old_def_id) = self.opt_local_def_id(param) && remapping.get(&old_def_id).is_none() {
+ let node_id = self.next_node_id();
+
+ let new_def_id = self.create_def(
+ parent_def_id,
+ node_id,
+ DefPathData::LifetimeNs(kw::UnderscoreLifetime),
+ );
+ remapping.insert(old_def_id, new_def_id);
+
+ result.push((node_id, *lifetime));
+ }
+ }
+
+ LifetimeRes::Static | LifetimeRes::Error => {}
+
+ res => {
+ let bug_msg = format!(
+ "Unexpected lifetime resolution {:?} for {:?} at {:?}",
+ res, lifetime.ident, lifetime.ident.span
+ );
+ span_bug!(lifetime.ident.span, "{}", bug_msg);
+ }
+ }
+ }
+
+ result
+ }
+
+ fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> &'hir [Ident] {
+ // Skip the `...` (`CVarArgs`) trailing arguments from the AST,
+ // as they are not explicit in HIR/Ty function signatures.
+ // (instead, the `c_variadic` flag is set to `true`)
+ let mut inputs = &decl.inputs[..];
+ if decl.c_variadic() {
+ inputs = &inputs[..inputs.len() - 1];
+ }
+ self.arena.alloc_from_iter(inputs.iter().map(|param| match param.pat.kind {
+ PatKind::Ident(_, ident, _) => self.lower_ident(ident),
+ _ => Ident::new(kw::Empty, self.lower_span(param.pat.span)),
+ }))
+ }
+
+ // Lowers a function declaration.
+ //
+ // `decl`: the unlowered (AST) function declaration.
+ // `fn_def_id`: if `Some`, impl Trait arguments are lowered into generic parameters on the
+ // given DefId, otherwise impl Trait is disallowed. Must be `Some` if
+ // `make_ret_async` is also `Some`.
+ // `impl_trait_return_allow`: determines whether `impl Trait` can be used in return position.
+ // This guards against trait declarations and implementations where `impl Trait` is
+ // disallowed.
+ // `make_ret_async`: if `Some`, converts `-> T` into `-> impl Future<Output = T>` in the
+ // return type. This is used for `async fn` declarations. The `NodeId` is the ID of the
+ // return type `impl Trait` item.
+ #[tracing::instrument(level = "debug", skip(self))]
+ fn lower_fn_decl(
+ &mut self,
+ decl: &FnDecl,
+ fn_node_id: Option<NodeId>,
+ kind: FnDeclKind,
+ make_ret_async: Option<NodeId>,
+ ) -> &'hir hir::FnDecl<'hir> {
+ let c_variadic = decl.c_variadic();
+
+ // Skip the `...` (`CVarArgs`) trailing arguments from the AST,
+ // as they are not explicit in HIR/Ty function signatures.
+ // (instead, the `c_variadic` flag is set to `true`)
+ let mut inputs = &decl.inputs[..];
+ if c_variadic {
+ inputs = &inputs[..inputs.len() - 1];
+ }
+ let inputs = self.arena.alloc_from_iter(inputs.iter().map(|param| {
+ if fn_node_id.is_some() {
+ self.lower_ty_direct(&param.ty, ImplTraitContext::Universal)
+ } else {
+ self.lower_ty_direct(
+ &param.ty,
+ ImplTraitContext::Disallowed(match kind {
+ FnDeclKind::Fn | FnDeclKind::Inherent => {
+ unreachable!("fn should allow in-band lifetimes")
+ }
+ FnDeclKind::ExternFn => ImplTraitPosition::ExternFnParam,
+ FnDeclKind::Closure => ImplTraitPosition::ClosureParam,
+ FnDeclKind::Pointer => ImplTraitPosition::PointerParam,
+ FnDeclKind::Trait => ImplTraitPosition::TraitParam,
+ FnDeclKind::Impl => ImplTraitPosition::ImplParam,
+ }),
+ )
+ }
+ }));
+
+ let output = if let Some(ret_id) = make_ret_async {
+ self.lower_async_fn_ret_ty(
+ &decl.output,
+ fn_node_id.expect("`make_ret_async` but no `fn_def_id`"),
+ ret_id,
+ )
+ } else {
+ match decl.output {
+ FnRetTy::Ty(ref ty) => {
+ let context = match fn_node_id {
+ Some(fn_node_id) if kind.impl_trait_return_allowed() => {
+ let fn_def_id = self.local_def_id(fn_node_id);
+ ImplTraitContext::ReturnPositionOpaqueTy {
+ origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
+ }
+ }
+ _ => ImplTraitContext::Disallowed(match kind {
+ FnDeclKind::Fn | FnDeclKind::Inherent => {
+ unreachable!("fn should allow in-band lifetimes")
+ }
+ FnDeclKind::ExternFn => ImplTraitPosition::ExternFnReturn,
+ FnDeclKind::Closure => ImplTraitPosition::ClosureReturn,
+ FnDeclKind::Pointer => ImplTraitPosition::PointerReturn,
+ FnDeclKind::Trait => ImplTraitPosition::TraitReturn,
+ FnDeclKind::Impl => ImplTraitPosition::ImplReturn,
+ }),
+ };
+ hir::FnRetTy::Return(self.lower_ty(ty, context))
+ }
+ FnRetTy::Default(span) => hir::FnRetTy::DefaultReturn(self.lower_span(span)),
+ }
+ };
+
+ self.arena.alloc(hir::FnDecl {
+ inputs,
+ output,
+ c_variadic,
+ implicit_self: decl.inputs.get(0).map_or(hir::ImplicitSelfKind::None, |arg| {
+ use BindingMode::{ByRef, ByValue};
+ let is_mutable_pat = matches!(
+ arg.pat.kind,
+ PatKind::Ident(ByValue(Mutability::Mut) | ByRef(Mutability::Mut), ..)
+ );
+
+ match arg.ty.kind {
+ TyKind::ImplicitSelf if is_mutable_pat => hir::ImplicitSelfKind::Mut,
+ TyKind::ImplicitSelf => hir::ImplicitSelfKind::Imm,
+ // Given we are only considering `ImplicitSelf` types, we needn't consider
+ // the case where we have a mutable pattern to a reference as that would
+ // no longer be an `ImplicitSelf`.
+ TyKind::Rptr(_, ref mt)
+ if mt.ty.kind.is_implicit_self() && mt.mutbl == ast::Mutability::Mut =>
+ {
+ hir::ImplicitSelfKind::MutRef
+ }
+ TyKind::Rptr(_, ref mt) if mt.ty.kind.is_implicit_self() => {
+ hir::ImplicitSelfKind::ImmRef
+ }
+ _ => hir::ImplicitSelfKind::None,
+ }
+ }),
+ })
+ }
+
+ // Transforms `-> T` for `async fn` into `-> OpaqueTy { .. }`
+ // combined with the following definition of `OpaqueTy`:
+ //
+ // type OpaqueTy<generics_from_parent_fn> = impl Future<Output = T>;
+ //
+ // `output`: unlowered output type (`T` in `-> T`)
+ // `fn_def_id`: `DefId` of the parent function (used to create child impl trait definition)
+ // `opaque_ty_node_id`: `NodeId` of the opaque `impl Trait` type that should be created
+ #[tracing::instrument(level = "debug", skip(self))]
+ fn lower_async_fn_ret_ty(
+ &mut self,
+ output: &FnRetTy,
+ fn_node_id: NodeId,
+ opaque_ty_node_id: NodeId,
+ ) -> hir::FnRetTy<'hir> {
+ let span = output.span();
+
+ let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::Async, span, None);
+
+ let opaque_ty_def_id = self.local_def_id(opaque_ty_node_id);
+ let fn_def_id = self.local_def_id(fn_node_id);
+
+ // When we create the opaque type for this async fn, it is going to have
+ // to capture all the lifetimes involved in the signature (including in the
+ // return type). This is done by introducing lifetime parameters for:
+ //
+ // - all the explicitly declared lifetimes from the impl and function itself;
+ // - all the elided lifetimes in the fn arguments;
+ // - all the elided lifetimes in the return type.
+ //
+ // So for example in this snippet:
+ //
+ // ```rust
+ // impl<'a> Foo<'a> {
+ // async fn bar<'b>(&self, x: &'b Vec<f64>, y: &str) -> &u32 {
+ // // ^ '0 ^ '1 ^ '2
+ // // elided lifetimes used below
+ // }
+ // }
+ // ```
+ //
+ // we would create an opaque type like:
+ //
+ // ```
+ // type Bar<'a, 'b, '0, '1, '2> = impl Future<Output = &'2 u32>;
+ // ```
+ //
+ // and we would then desugar `bar` to the equivalent of:
+ //
+ // ```rust
+ // impl<'a> Foo<'a> {
+ // fn bar<'b, '0, '1>(&'0 self, x: &'b Vec<f64>, y: &'1 str) -> Bar<'a, 'b, '0, '1, '_>
+ // }
+ // ```
+ //
+ // Note that the final parameter to `Bar` is `'_`, not `'2` --
+ // this is because the elided lifetimes from the return type
+ // should be figured out using the ordinary elision rules, and
+ // this desugaring achieves that.
+
+ // Calculate all the lifetimes that should be captured
+ // by the opaque type. This should include all in-scope
+ // lifetime parameters, including those defined in-band.
+
+ // Contains the new lifetime definitions created for the TAIT (if any) generated for the
+ // return type.
+ let mut collected_lifetimes = Vec::new();
+ let mut new_remapping = FxHashMap::default();
+
+ let extra_lifetime_params = self.resolver.take_extra_lifetime_params(opaque_ty_node_id);
+ debug!(?extra_lifetime_params);
+ for (ident, outer_node_id, outer_res) in extra_lifetime_params {
+ let outer_def_id = self.local_def_id(outer_node_id);
+ let inner_node_id = self.next_node_id();
+
+ // Add a definition for the in scope lifetime def.
+ let inner_def_id = self.create_def(
+ opaque_ty_def_id,
+ inner_node_id,
+ DefPathData::LifetimeNs(ident.name),
+ );
+ new_remapping.insert(outer_def_id, inner_def_id);
+
+ let inner_res = match outer_res {
+ // Input lifetime like `'a`:
+ LifetimeRes::Param { param, .. } => {
+ LifetimeRes::Param { param, binder: fn_node_id }
+ }
+ // Input lifetime like `'1`:
+ LifetimeRes::Fresh { param, .. } => {
+ LifetimeRes::Fresh { param, binder: fn_node_id }
+ }
+ LifetimeRes::Static | LifetimeRes::Error => continue,
+ res => {
+ panic!(
+ "Unexpected lifetime resolution {:?} for {:?} at {:?}",
+ res, ident, ident.span
+ )
+ }
+ };
+
+ let lifetime = Lifetime { id: outer_node_id, ident };
+ collected_lifetimes.push((inner_node_id, lifetime, Some(inner_res)));
+ }
+
+ debug!(?collected_lifetimes);
+
+ // We only want to capture the lifetimes that appear in the bounds. So visit the bounds to
+ // find out exactly which ones those are.
+ // in fn return position, like the `fn test<'a>() -> impl Debug + 'a` example,
+ // we only keep the lifetimes that appear in the `impl Debug` itself:
+ let lifetimes_to_remap = lifetime_collector::lifetimes_in_ret_ty(&self.resolver, output);
+ debug!(?lifetimes_to_remap);
+
+ self.with_hir_id_owner(opaque_ty_node_id, |this| {
+ // If this opaque type is only capturing a subset of the lifetimes (those that appear
+ // in bounds), then create the new lifetime parameters required and create a mapping
+ // from the old `'a` (on the function) to the new `'a` (on the opaque type).
+ collected_lifetimes.extend(
+ this.create_lifetime_defs(
+ opaque_ty_def_id,
+ &lifetimes_to_remap,
+ &mut new_remapping,
+ )
+ .into_iter()
+ .map(|(new_node_id, lifetime)| (new_node_id, lifetime, None)),
+ );
+ debug!(?collected_lifetimes);
+ debug!(?new_remapping);
+
+ // Install the remapping from old to new (if any):
+ this.with_remapping(new_remapping, |this| {
+ // We have to be careful to get elision right here. The
+ // idea is that we create a lifetime parameter for each
+ // lifetime in the return type. So, given a return type
+ // like `async fn foo(..) -> &[&u32]`, we lower to `impl
+ // Future<Output = &'1 [ &'2 u32 ]>`.
+ //
+ // Then, we will create `fn foo(..) -> Foo<'_, '_>`, and
+ // hence the elision takes place at the fn site.
+ let future_bound =
+ this.lower_async_fn_output_type_to_future_bound(output, fn_def_id, span);
+
+ let generic_params = this.arena.alloc_from_iter(collected_lifetimes.iter().map(
+ |&(new_node_id, lifetime, _)| {
+ let hir_id = this.lower_node_id(new_node_id);
+ debug_assert_ne!(this.opt_local_def_id(new_node_id), None);
+
+ let (name, kind) = if lifetime.ident.name == kw::UnderscoreLifetime {
+ (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided)
+ } else {
+ (
+ hir::ParamName::Plain(lifetime.ident),
+ hir::LifetimeParamKind::Explicit,
+ )
+ };
+
+ hir::GenericParam {
+ hir_id,
+ name,
+ span: lifetime.ident.span,
+ pure_wrt_drop: false,
+ kind: hir::GenericParamKind::Lifetime { kind },
+ colon_span: None,
+ }
+ },
+ ));
+ debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params);
+
+ let opaque_ty_item = hir::OpaqueTy {
+ generics: this.arena.alloc(hir::Generics {
+ params: generic_params,
+ predicates: &[],
+ has_where_clause_predicates: false,
+ where_clause_span: this.lower_span(span),
+ span: this.lower_span(span),
+ }),
+ bounds: arena_vec![this; future_bound],
+ origin: hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
+ };
+
+ trace!("exist ty from async fn def id: {:#?}", opaque_ty_def_id);
+ this.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span)
+ })
+ });
+
+ // As documented above, we need to create the lifetime
+ // arguments to our opaque type. Continuing with our example,
+ // we're creating the type arguments for the return type:
+ //
+ // ```
+ // Bar<'a, 'b, '0, '1, '_>
+ // ```
+ //
+ // For the "input" lifetime parameters, we wish to create
+ // references to the parameters themselves, including the
+ // "implicit" ones created from parameter types (`'a`, `'b`,
+ // '`0`, `'1`).
+ //
+ // For the "output" lifetime parameters, we just want to
+ // generate `'_`.
+ let generic_args = self.arena.alloc_from_iter(collected_lifetimes.into_iter().map(
+ |(_, lifetime, res)| {
+ let id = self.next_node_id();
+ let span = lifetime.ident.span;
+
+ let ident = if lifetime.ident.name == kw::UnderscoreLifetime {
+ Ident::with_dummy_span(kw::UnderscoreLifetime)
+ } else {
+ lifetime.ident
+ };
+
+ let res = res.unwrap_or(
+ self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error),
+ );
+ let l = self.new_named_lifetime_with_res(id, span, ident, res);
+ hir::GenericArg::Lifetime(l)
+ },
+ ));
+
+ // Create the `Foo<...>` reference itself. Note that the `type
+ // Foo = impl Trait` is, internally, created as a child of the
+ // async fn, so the *type parameters* are inherited. It's
+ // only the lifetime parameters that we must supply.
+ let opaque_ty_ref =
+ hir::TyKind::OpaqueDef(hir::ItemId { def_id: opaque_ty_def_id }, generic_args);
+ let opaque_ty = self.ty(opaque_ty_span, opaque_ty_ref);
+ hir::FnRetTy::Return(self.arena.alloc(opaque_ty))
+ }
+
+ /// Transforms `-> T` into `Future<Output = T>`.
+ fn lower_async_fn_output_type_to_future_bound(
+ &mut self,
+ output: &FnRetTy,
+ fn_def_id: LocalDefId,
+ span: Span,
+ ) -> hir::GenericBound<'hir> {
+ // Compute the `T` in `Future<Output = T>` from the return type.
+ let output_ty = match output {
+ FnRetTy::Ty(ty) => {
+ // Not `OpaqueTyOrigin::AsyncFn`: that's only used for the
+ // `impl Future` opaque type that `async fn` implicitly
+ // generates.
+ let context = ImplTraitContext::ReturnPositionOpaqueTy {
+ origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
+ };
+ self.lower_ty(ty, context)
+ }
+ FnRetTy::Default(ret_ty_span) => self.arena.alloc(self.ty_tup(*ret_ty_span, &[])),
+ };
+
+ // "<Output = T>"
+ let future_args = self.arena.alloc(hir::GenericArgs {
+ args: &[],
+ bindings: arena_vec![self; self.output_ty_binding(span, output_ty)],
+ parenthesized: false,
+ span_ext: DUMMY_SP,
+ });
+
+ hir::GenericBound::LangItemTrait(
+ // ::std::future::Future<future_params>
+ hir::LangItem::Future,
+ self.lower_span(span),
+ self.next_id(),
+ future_args,
+ )
+ }
+
+ #[instrument(level = "trace", skip(self))]
+ fn lower_param_bound(
+ &mut self,
+ tpb: &GenericBound,
+ itctx: ImplTraitContext,
+ ) -> hir::GenericBound<'hir> {
+ match tpb {
+ GenericBound::Trait(p, modifier) => hir::GenericBound::Trait(
+ self.lower_poly_trait_ref(p, itctx),
+ self.lower_trait_bound_modifier(*modifier),
+ ),
+ GenericBound::Outlives(lifetime) => {
+ hir::GenericBound::Outlives(self.lower_lifetime(lifetime))
+ }
+ }
+ }
+
+ fn lower_lifetime(&mut self, l: &Lifetime) -> hir::Lifetime {
+ let span = self.lower_span(l.ident.span);
+ let ident = self.lower_ident(l.ident);
+ self.new_named_lifetime(l.id, l.id, span, ident)
+ }
+
+ #[tracing::instrument(level = "debug", skip(self))]
+ fn new_named_lifetime_with_res(
+ &mut self,
+ id: NodeId,
+ span: Span,
+ ident: Ident,
+ res: LifetimeRes,
+ ) -> hir::Lifetime {
+ let name = match res {
+ LifetimeRes::Param { param, .. } => {
+ let p_name = ParamName::Plain(ident);
+ let param = self.resolver.get_remapped_def_id(param);
+
+ hir::LifetimeName::Param(param, p_name)
+ }
+ LifetimeRes::Fresh { param, .. } => {
+ debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
+ let param = self.local_def_id(param);
+
+ hir::LifetimeName::Param(param, ParamName::Fresh)
+ }
+ LifetimeRes::Infer => hir::LifetimeName::Infer,
+ LifetimeRes::Static => hir::LifetimeName::Static,
+ LifetimeRes::Error => hir::LifetimeName::Error,
+ res => panic!("Unexpected lifetime resolution {:?} for {:?} at {:?}", res, ident, span),
+ };
+
+ debug!(?name);
+ hir::Lifetime { hir_id: self.lower_node_id(id), span: self.lower_span(span), name }
+ }
+
+ #[tracing::instrument(level = "debug", skip(self))]
+ fn new_named_lifetime(
+ &mut self,
+ id: NodeId,
+ new_id: NodeId,
+ span: Span,
+ ident: Ident,
+ ) -> hir::Lifetime {
+ let res = self.resolver.get_lifetime_res(id).unwrap_or(LifetimeRes::Error);
+ self.new_named_lifetime_with_res(new_id, span, ident, res)
+ }
+
+ fn lower_generic_params_mut<'s>(
+ &'s mut self,
+ params: &'s [GenericParam],
+ ) -> impl Iterator<Item = hir::GenericParam<'hir>> + Captures<'a> + Captures<'s> {
+ params.iter().map(move |param| self.lower_generic_param(param))
+ }
+
+ fn lower_generic_params(&mut self, params: &[GenericParam]) -> &'hir [hir::GenericParam<'hir>] {
+ self.arena.alloc_from_iter(self.lower_generic_params_mut(params))
+ }
+
+ #[instrument(level = "trace", skip(self))]
+ fn lower_generic_param(&mut self, param: &GenericParam) -> hir::GenericParam<'hir> {
+ let (name, kind) = self.lower_generic_param_kind(param);
+
+ let hir_id = self.lower_node_id(param.id);
+ self.lower_attrs(hir_id, &param.attrs);
+ hir::GenericParam {
+ hir_id,
+ name,
+ span: self.lower_span(param.span()),
+ pure_wrt_drop: self.tcx.sess.contains_name(&param.attrs, sym::may_dangle),
+ kind,
+ colon_span: param.colon_span.map(|s| self.lower_span(s)),
+ }
+ }
+
+ fn lower_generic_param_kind(
+ &mut self,
+ param: &GenericParam,
+ ) -> (hir::ParamName, hir::GenericParamKind<'hir>) {
+ match param.kind {
+ GenericParamKind::Lifetime => {
+ // AST resolution emitted an error on those parameters, so we lower them using
+ // `ParamName::Error`.
+ let param_name =
+ if let Some(LifetimeRes::Error) = self.resolver.get_lifetime_res(param.id) {
+ ParamName::Error
+ } else {
+ let ident = self.lower_ident(param.ident);
+ ParamName::Plain(ident)
+ };
+ let kind =
+ hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit };
+
+ (param_name, kind)
+ }
+ GenericParamKind::Type { ref default, .. } => {
+ let kind = hir::GenericParamKind::Type {
+ default: default.as_ref().map(|x| {
+ self.lower_ty(x, ImplTraitContext::Disallowed(ImplTraitPosition::Type))
+ }),
+ synthetic: false,
+ };
+
+ (hir::ParamName::Plain(self.lower_ident(param.ident)), kind)
+ }
+ GenericParamKind::Const { ref ty, kw_span: _, ref default } => {
+ let ty = self.lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
+ let default = default.as_ref().map(|def| self.lower_anon_const(def));
+ (
+ hir::ParamName::Plain(self.lower_ident(param.ident)),
+ hir::GenericParamKind::Const { ty, default },
+ )
+ }
+ }
+ }
+
+ fn lower_trait_ref(&mut self, p: &TraitRef, itctx: ImplTraitContext) -> hir::TraitRef<'hir> {
+ let path = match self.lower_qpath(p.ref_id, &None, &p.path, ParamMode::Explicit, itctx) {
+ hir::QPath::Resolved(None, path) => path,
+ qpath => panic!("lower_trait_ref: unexpected QPath `{:?}`", qpath),
+ };
+ hir::TraitRef { path, hir_ref_id: self.lower_node_id(p.ref_id) }
+ }
+
+ #[tracing::instrument(level = "debug", skip(self))]
+ fn lower_poly_trait_ref(
+ &mut self,
+ p: &PolyTraitRef,
+ itctx: ImplTraitContext,
+ ) -> hir::PolyTraitRef<'hir> {
+ let bound_generic_params =
+ self.lower_lifetime_binder(p.trait_ref.ref_id, &p.bound_generic_params);
+ let trait_ref = self.lower_trait_ref(&p.trait_ref, itctx);
+ hir::PolyTraitRef { bound_generic_params, trait_ref, span: self.lower_span(p.span) }
+ }
+
+ fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext) -> hir::MutTy<'hir> {
+ hir::MutTy { ty: self.lower_ty(&mt.ty, itctx), mutbl: mt.mutbl }
+ }
+
+ fn lower_param_bounds(
+ &mut self,
+ bounds: &[GenericBound],
+ itctx: ImplTraitContext,
+ ) -> hir::GenericBounds<'hir> {
+ self.arena.alloc_from_iter(self.lower_param_bounds_mut(bounds, itctx))
+ }
+
+ fn lower_param_bounds_mut<'s>(
+ &'s mut self,
+ bounds: &'s [GenericBound],
+ itctx: ImplTraitContext,
+ ) -> impl Iterator<Item = hir::GenericBound<'hir>> + Captures<'s> + Captures<'a> {
+ bounds.iter().map(move |bound| self.lower_param_bound(bound, itctx))
+ }
+
+ fn lower_generic_and_bounds(
+ &mut self,
+ node_id: NodeId,
+ span: Span,
+ ident: Ident,
+ bounds: &[GenericBound],
+ ) -> (hir::GenericParam<'hir>, Option<hir::WherePredicate<'hir>>, hir::TyKind<'hir>) {
+ // Add a definition for the in-band `Param`.
+ let def_id = self.local_def_id(node_id);
+
+ // Set the name to `impl Bound1 + Bound2`.
+ let param = hir::GenericParam {
+ hir_id: self.lower_node_id(node_id),
+ name: ParamName::Plain(self.lower_ident(ident)),
+ pure_wrt_drop: false,
+ span: self.lower_span(span),
+ kind: hir::GenericParamKind::Type { default: None, synthetic: true },
+ colon_span: None,
+ };
+
+ let preds = self.lower_generic_bound_predicate(
+ ident,
+ node_id,
+ &GenericParamKind::Type { default: None },
+ bounds,
+ ImplTraitContext::Universal,
+ hir::PredicateOrigin::ImplTrait,
+ );
+
+ let ty = hir::TyKind::Path(hir::QPath::Resolved(
+ None,
+ self.arena.alloc(hir::Path {
+ span: self.lower_span(span),
+ res: Res::Def(DefKind::TyParam, def_id.to_def_id()),
+ segments: arena_vec![self; hir::PathSegment::from_ident(self.lower_ident(ident))],
+ }),
+ ));
+
+ (param, preds, ty)
+ }
+
+ /// Lowers a block directly to an expression, presuming that it
+ /// has no attributes and is not targeted by a `break`.
+ fn lower_block_expr(&mut self, b: &Block) -> hir::Expr<'hir> {
+ let block = self.lower_block(b, false);
+ self.expr_block(block, AttrVec::new())
+ }
+
+ fn lower_array_length(&mut self, c: &AnonConst) -> hir::ArrayLen {
+ match c.value.kind {
+ ExprKind::Underscore => {
+ if self.tcx.features().generic_arg_infer {
+ hir::ArrayLen::Infer(self.lower_node_id(c.id), c.value.span)
+ } else {
+ feature_err(
+ &self.tcx.sess.parse_sess,
+ sym::generic_arg_infer,
+ c.value.span,
+ "using `_` for array lengths is unstable",
+ )
+ .emit();
+ hir::ArrayLen::Body(self.lower_anon_const(c))
+ }
+ }
+ _ => hir::ArrayLen::Body(self.lower_anon_const(c)),
+ }
+ }
+
+ fn lower_anon_const(&mut self, c: &AnonConst) -> hir::AnonConst {
+ self.with_new_scopes(|this| hir::AnonConst {
+ hir_id: this.lower_node_id(c.id),
+ body: this.lower_const_body(c.value.span, Some(&c.value)),
+ })
+ }
+
+ fn lower_unsafe_source(&mut self, u: UnsafeSource) -> hir::UnsafeSource {
+ match u {
+ CompilerGenerated => hir::UnsafeSource::CompilerGenerated,
+ UserProvided => hir::UnsafeSource::UserProvided,
+ }
+ }
+
+ fn lower_trait_bound_modifier(&mut self, f: TraitBoundModifier) -> hir::TraitBoundModifier {
+ match f {
+ TraitBoundModifier::None => hir::TraitBoundModifier::None,
+ TraitBoundModifier::MaybeConst => hir::TraitBoundModifier::MaybeConst,
+
+ // `MaybeConstMaybe` will cause an error during AST validation, but we need to pick a
+ // placeholder for compilation to proceed.
+ TraitBoundModifier::MaybeConstMaybe | TraitBoundModifier::Maybe => {
+ hir::TraitBoundModifier::Maybe
+ }
+ }
+ }
+
+ // Helper methods for building HIR.
+
+ fn stmt(&mut self, span: Span, kind: hir::StmtKind<'hir>) -> hir::Stmt<'hir> {
+ hir::Stmt { span: self.lower_span(span), kind, hir_id: self.next_id() }
+ }
+
+ fn stmt_expr(&mut self, span: Span, expr: hir::Expr<'hir>) -> hir::Stmt<'hir> {
+ self.stmt(span, hir::StmtKind::Expr(self.arena.alloc(expr)))
+ }
+
+ fn stmt_let_pat(
+ &mut self,
+ attrs: Option<&'hir [Attribute]>,
+ span: Span,
+ init: Option<&'hir hir::Expr<'hir>>,
+ pat: &'hir hir::Pat<'hir>,
+ source: hir::LocalSource,
+ ) -> hir::Stmt<'hir> {
+ let hir_id = self.next_id();
+ if let Some(a) = attrs {
+ debug_assert!(!a.is_empty());
+ self.attrs.insert(hir_id.local_id, a);
+ }
+ let local = hir::Local {
+ hir_id,
+ init,
+ pat,
+ els: None,
+ source,
+ span: self.lower_span(span),
+ ty: None,
+ };
+ self.stmt(span, hir::StmtKind::Local(self.arena.alloc(local)))
+ }
+
+ fn block_expr(&mut self, expr: &'hir hir::Expr<'hir>) -> &'hir hir::Block<'hir> {
+ self.block_all(expr.span, &[], Some(expr))
+ }
+
+ fn block_all(
+ &mut self,
+ span: Span,
+ stmts: &'hir [hir::Stmt<'hir>],
+ expr: Option<&'hir hir::Expr<'hir>>,
+ ) -> &'hir hir::Block<'hir> {
+ let blk = hir::Block {
+ stmts,
+ expr,
+ hir_id: self.next_id(),
+ rules: hir::BlockCheckMode::DefaultBlock,
+ span: self.lower_span(span),
+ targeted_by_break: false,
+ };
+ self.arena.alloc(blk)
+ }
+
+ fn pat_cf_continue(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
+ let field = self.single_pat_field(span, pat);
+ self.pat_lang_item_variant(span, hir::LangItem::ControlFlowContinue, field, None)
+ }
+
+ fn pat_cf_break(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
+ let field = self.single_pat_field(span, pat);
+ self.pat_lang_item_variant(span, hir::LangItem::ControlFlowBreak, field, None)
+ }
+
+ fn pat_some(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
+ let field = self.single_pat_field(span, pat);
+ self.pat_lang_item_variant(span, hir::LangItem::OptionSome, field, None)
+ }
+
+ fn pat_none(&mut self, span: Span) -> &'hir hir::Pat<'hir> {
+ self.pat_lang_item_variant(span, hir::LangItem::OptionNone, &[], None)
+ }
+
+ fn single_pat_field(
+ &mut self,
+ span: Span,
+ pat: &'hir hir::Pat<'hir>,
+ ) -> &'hir [hir::PatField<'hir>] {
+ let field = hir::PatField {
+ hir_id: self.next_id(),
+ ident: Ident::new(sym::integer(0), self.lower_span(span)),
+ is_shorthand: false,
+ pat,
+ span: self.lower_span(span),
+ };
+ arena_vec![self; field]
+ }
+
+ fn pat_lang_item_variant(
+ &mut self,
+ span: Span,
+ lang_item: hir::LangItem,
+ fields: &'hir [hir::PatField<'hir>],
+ hir_id: Option<hir::HirId>,
+ ) -> &'hir hir::Pat<'hir> {
+ let qpath = hir::QPath::LangItem(lang_item, self.lower_span(span), hir_id);
+ self.pat(span, hir::PatKind::Struct(qpath, fields, false))
+ }
+
+ fn pat_ident(&mut self, span: Span, ident: Ident) -> (&'hir hir::Pat<'hir>, hir::HirId) {
+ self.pat_ident_binding_mode(span, ident, hir::BindingAnnotation::Unannotated)
+ }
+
+ fn pat_ident_mut(&mut self, span: Span, ident: Ident) -> (hir::Pat<'hir>, hir::HirId) {
+ self.pat_ident_binding_mode_mut(span, ident, hir::BindingAnnotation::Unannotated)
+ }
+
+ fn pat_ident_binding_mode(
+ &mut self,
+ span: Span,
+ ident: Ident,
+ bm: hir::BindingAnnotation,
+ ) -> (&'hir hir::Pat<'hir>, hir::HirId) {
+ let (pat, hir_id) = self.pat_ident_binding_mode_mut(span, ident, bm);
+ (self.arena.alloc(pat), hir_id)
+ }
+
+ fn pat_ident_binding_mode_mut(
+ &mut self,
+ span: Span,
+ ident: Ident,
+ bm: hir::BindingAnnotation,
+ ) -> (hir::Pat<'hir>, hir::HirId) {
+ let hir_id = self.next_id();
+
+ (
+ hir::Pat {
+ hir_id,
+ kind: hir::PatKind::Binding(bm, hir_id, self.lower_ident(ident), None),
+ span: self.lower_span(span),
+ default_binding_modes: true,
+ },
+ hir_id,
+ )
+ }
+
+ fn pat(&mut self, span: Span, kind: hir::PatKind<'hir>) -> &'hir hir::Pat<'hir> {
+ self.arena.alloc(hir::Pat {
+ hir_id: self.next_id(),
+ kind,
+ span: self.lower_span(span),
+ default_binding_modes: true,
+ })
+ }
+
+ fn pat_without_dbm(&mut self, span: Span, kind: hir::PatKind<'hir>) -> hir::Pat<'hir> {
+ hir::Pat {
+ hir_id: self.next_id(),
+ kind,
+ span: self.lower_span(span),
+ default_binding_modes: false,
+ }
+ }
+
+ fn ty_path(
+ &mut self,
+ mut hir_id: hir::HirId,
+ span: Span,
+ qpath: hir::QPath<'hir>,
+ ) -> hir::Ty<'hir> {
+ let kind = match qpath {
+ hir::QPath::Resolved(None, path) => {
+ // Turn trait object paths into `TyKind::TraitObject` instead.
+ match path.res {
+ Res::Def(DefKind::Trait | DefKind::TraitAlias, _) => {
+ let principal = hir::PolyTraitRef {
+ bound_generic_params: &[],
+ trait_ref: hir::TraitRef { path, hir_ref_id: hir_id },
+ span: self.lower_span(span),
+ };
+
+ // The original ID is taken by the `PolyTraitRef`,
+ // so the `Ty` itself needs a different one.
+ hir_id = self.next_id();
+ hir::TyKind::TraitObject(
+ arena_vec![self; principal],
+ self.elided_dyn_bound(span),
+ TraitObjectSyntax::None,
+ )
+ }
+ _ => hir::TyKind::Path(hir::QPath::Resolved(None, path)),
+ }
+ }
+ _ => hir::TyKind::Path(qpath),
+ };
+
+ hir::Ty { hir_id, kind, span: self.lower_span(span) }
+ }
+
+ /// Invoked to create the lifetime argument(s) for an elided trait object
+ /// bound, like the bound in `Box<dyn Debug>`. This method is not invoked
+ /// when the bound is written, even if it is written with `'_` like in
+ /// `Box<dyn Debug + '_>`. In those cases, `lower_lifetime` is invoked.
+ fn elided_dyn_bound(&mut self, span: Span) -> hir::Lifetime {
+ let r = hir::Lifetime {
+ hir_id: self.next_id(),
+ span: self.lower_span(span),
+ name: hir::LifetimeName::ImplicitObjectLifetimeDefault,
+ };
+ debug!("elided_dyn_bound: r={:?}", r);
+ r
+ }
+}
+
+/// Helper struct for delayed construction of GenericArgs.
+struct GenericArgsCtor<'hir> {
+ args: SmallVec<[hir::GenericArg<'hir>; 4]>,
+ bindings: &'hir [hir::TypeBinding<'hir>],
+ parenthesized: bool,
+ span: Span,
+}
+
+impl<'hir> GenericArgsCtor<'hir> {
+ fn is_empty(&self) -> bool {
+ self.args.is_empty() && self.bindings.is_empty() && !self.parenthesized
+ }
+
+ fn into_generic_args(self, this: &LoweringContext<'_, 'hir>) -> &'hir hir::GenericArgs<'hir> {
+ let ga = hir::GenericArgs {
+ args: this.arena.alloc_from_iter(self.args),
+ bindings: self.bindings,
+ parenthesized: self.parenthesized,
+ span_ext: this.lower_span(self.span),
+ };
+ this.arena.alloc(ga)
+ }
+}
diff --git a/compiler/rustc_ast_lowering/src/lifetime_collector.rs b/compiler/rustc_ast_lowering/src/lifetime_collector.rs
new file mode 100644
index 000000000..81006e00f
--- /dev/null
+++ b/compiler/rustc_ast_lowering/src/lifetime_collector.rs
@@ -0,0 +1,115 @@
+use super::ResolverAstLoweringExt;
+use rustc_ast::visit::{self, BoundKind, LifetimeCtxt, Visitor};
+use rustc_ast::{
+ FnRetTy, GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, TraitBoundModifier, Ty,
+ TyKind,
+};
+use rustc_hir::def::LifetimeRes;
+use rustc_middle::span_bug;
+use rustc_middle::ty::ResolverAstLowering;
+use rustc_span::symbol::{kw, Ident};
+use rustc_span::Span;
+
+struct LifetimeCollectVisitor<'ast> {
+ resolver: &'ast ResolverAstLowering,
+ current_binders: Vec<NodeId>,
+ collected_lifetimes: Vec<Lifetime>,
+}
+
+impl<'ast> LifetimeCollectVisitor<'ast> {
+ fn new(resolver: &'ast ResolverAstLowering) -> Self {
+ Self { resolver, current_binders: Vec::new(), collected_lifetimes: Vec::new() }
+ }
+
+ fn record_lifetime_use(&mut self, lifetime: Lifetime) {
+ match self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error) {
+ LifetimeRes::Param { binder, .. } | LifetimeRes::Fresh { binder, .. } => {
+ if !self.current_binders.contains(&binder) {
+ if !self.collected_lifetimes.contains(&lifetime) {
+ self.collected_lifetimes.push(lifetime);
+ }
+ }
+ }
+ LifetimeRes::Static | LifetimeRes::Error => {
+ if !self.collected_lifetimes.contains(&lifetime) {
+ self.collected_lifetimes.push(lifetime);
+ }
+ }
+ LifetimeRes::Infer => {}
+ res => {
+ let bug_msg = format!(
+ "Unexpected lifetime resolution {:?} for {:?} at {:?}",
+ res, lifetime.ident, lifetime.ident.span
+ );
+ span_bug!(lifetime.ident.span, "{}", bug_msg);
+ }
+ }
+ }
+
+ /// This collect lifetimes that are elided, for nodes like `Foo<T>` where there are no explicit
+ /// lifetime nodes. Is equivalent to having "pseudo" nodes introduced for each of the node ids
+ /// in the list start..end.
+ fn record_elided_anchor(&mut self, node_id: NodeId, span: Span) {
+ if let Some(LifetimeRes::ElidedAnchor { start, end }) =
+ self.resolver.get_lifetime_res(node_id)
+ {
+ for i in start..end {
+ let lifetime = Lifetime { id: i, ident: Ident::new(kw::UnderscoreLifetime, span) };
+ self.record_lifetime_use(lifetime);
+ }
+ }
+ }
+}
+
+impl<'ast> Visitor<'ast> for LifetimeCollectVisitor<'ast> {
+ fn visit_lifetime(&mut self, lifetime: &'ast Lifetime, _: LifetimeCtxt) {
+ self.record_lifetime_use(*lifetime);
+ }
+
+ fn visit_path_segment(&mut self, path_span: Span, path_segment: &'ast PathSegment) {
+ self.record_elided_anchor(path_segment.id, path_span);
+ visit::walk_path_segment(self, path_span, path_segment);
+ }
+
+ fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef, m: &'ast TraitBoundModifier) {
+ self.current_binders.push(t.trait_ref.ref_id);
+
+ visit::walk_poly_trait_ref(self, t, m);
+
+ self.current_binders.pop();
+ }
+
+ fn visit_ty(&mut self, t: &'ast Ty) {
+ match t.kind {
+ TyKind::BareFn(_) => {
+ self.current_binders.push(t.id);
+ visit::walk_ty(self, t);
+ self.current_binders.pop();
+ }
+ TyKind::Rptr(None, _) => {
+ self.record_elided_anchor(t.id, t.span);
+ visit::walk_ty(self, t);
+ }
+ _ => {
+ visit::walk_ty(self, t);
+ }
+ }
+ }
+}
+
+pub fn lifetimes_in_ret_ty(resolver: &ResolverAstLowering, ret_ty: &FnRetTy) -> Vec<Lifetime> {
+ let mut visitor = LifetimeCollectVisitor::new(resolver);
+ visitor.visit_fn_ret_ty(ret_ty);
+ visitor.collected_lifetimes
+}
+
+pub fn lifetimes_in_bounds(
+ resolver: &ResolverAstLowering,
+ bounds: &GenericBounds,
+) -> Vec<Lifetime> {
+ let mut visitor = LifetimeCollectVisitor::new(resolver);
+ for bound in bounds {
+ visitor.visit_param_bound(bound, BoundKind::Bound);
+ }
+ visitor.collected_lifetimes
+}
diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs
new file mode 100644
index 000000000..bd2e76e55
--- /dev/null
+++ b/compiler/rustc_ast_lowering/src/pat.rs
@@ -0,0 +1,350 @@
+use super::ResolverAstLoweringExt;
+use super::{ImplTraitContext, LoweringContext, ParamMode};
+use crate::ImplTraitPosition;
+
+use rustc_ast::ptr::P;
+use rustc_ast::*;
+use rustc_data_structures::stack::ensure_sufficient_stack;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_hir::def::Res;
+use rustc_span::symbol::Ident;
+use rustc_span::{source_map::Spanned, Span};
+
+impl<'a, 'hir> LoweringContext<'a, 'hir> {
+ pub(crate) fn lower_pat(&mut self, pattern: &Pat) -> &'hir hir::Pat<'hir> {
+ self.arena.alloc(self.lower_pat_mut(pattern))
+ }
+
+ pub(crate) fn lower_pat_mut(&mut self, mut pattern: &Pat) -> hir::Pat<'hir> {
+ ensure_sufficient_stack(|| {
+ // loop here to avoid recursion
+ let node = loop {
+ match pattern.kind {
+ PatKind::Wild => break hir::PatKind::Wild,
+ PatKind::Ident(ref binding_mode, ident, ref sub) => {
+ let lower_sub = |this: &mut Self| sub.as_ref().map(|s| this.lower_pat(&*s));
+ break self.lower_pat_ident(pattern, binding_mode, ident, lower_sub);
+ }
+ PatKind::Lit(ref e) => {
+ break hir::PatKind::Lit(self.lower_expr_within_pat(e, false));
+ }
+ PatKind::TupleStruct(ref qself, ref path, ref pats) => {
+ let qpath = self.lower_qpath(
+ pattern.id,
+ qself,
+ path,
+ ParamMode::Optional,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+ );
+ let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple struct");
+ break hir::PatKind::TupleStruct(qpath, pats, ddpos);
+ }
+ PatKind::Or(ref pats) => {
+ break hir::PatKind::Or(
+ self.arena.alloc_from_iter(pats.iter().map(|x| self.lower_pat_mut(x))),
+ );
+ }
+ PatKind::Path(ref qself, ref path) => {
+ let qpath = self.lower_qpath(
+ pattern.id,
+ qself,
+ path,
+ ParamMode::Optional,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+ );
+ break hir::PatKind::Path(qpath);
+ }
+ PatKind::Struct(ref qself, ref path, ref fields, etc) => {
+ let qpath = self.lower_qpath(
+ pattern.id,
+ qself,
+ path,
+ ParamMode::Optional,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+ );
+
+ let fs = self.arena.alloc_from_iter(fields.iter().map(|f| hir::PatField {
+ hir_id: self.next_id(),
+ ident: self.lower_ident(f.ident),
+ pat: self.lower_pat(&f.pat),
+ is_shorthand: f.is_shorthand,
+ span: self.lower_span(f.span),
+ }));
+ break hir::PatKind::Struct(qpath, fs, etc);
+ }
+ PatKind::Tuple(ref pats) => {
+ let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple");
+ break hir::PatKind::Tuple(pats, ddpos);
+ }
+ PatKind::Box(ref inner) => {
+ break hir::PatKind::Box(self.lower_pat(inner));
+ }
+ PatKind::Ref(ref inner, mutbl) => {
+ break hir::PatKind::Ref(self.lower_pat(inner), mutbl);
+ }
+ PatKind::Range(ref e1, ref e2, Spanned { node: ref end, .. }) => {
+ break hir::PatKind::Range(
+ e1.as_deref().map(|e| self.lower_expr_within_pat(e, true)),
+ e2.as_deref().map(|e| self.lower_expr_within_pat(e, true)),
+ self.lower_range_end(end, e2.is_some()),
+ );
+ }
+ PatKind::Slice(ref pats) => break self.lower_pat_slice(pats),
+ PatKind::Rest => {
+ // If we reach here the `..` pattern is not semantically allowed.
+ break self.ban_illegal_rest_pat(pattern.span);
+ }
+ // return inner to be processed in next loop
+ PatKind::Paren(ref inner) => pattern = inner,
+ PatKind::MacCall(_) => panic!("{:?} shouldn't exist here", pattern.span),
+ }
+ };
+
+ self.pat_with_node_id_of(pattern, node)
+ })
+ }
+
+ fn lower_pat_tuple(
+ &mut self,
+ pats: &[P<Pat>],
+ ctx: &str,
+ ) -> (&'hir [hir::Pat<'hir>], Option<usize>) {
+ let mut elems = Vec::with_capacity(pats.len());
+ let mut rest = None;
+
+ let mut iter = pats.iter().enumerate();
+ for (idx, pat) in iter.by_ref() {
+ // Interpret the first `..` pattern as a sub-tuple pattern.
+ // Note that unlike for slice patterns,
+ // where `xs @ ..` is a legal sub-slice pattern,
+ // it is not a legal sub-tuple pattern.
+ match pat.kind {
+ // Found a sub-tuple rest pattern
+ PatKind::Rest => {
+ rest = Some((idx, pat.span));
+ break;
+ }
+ // Found a sub-tuple pattern `$binding_mode $ident @ ..`.
+ // This is not allowed as a sub-tuple pattern
+ PatKind::Ident(ref _bm, ident, Some(ref sub)) if sub.is_rest() => {
+ let sp = pat.span;
+ self.diagnostic()
+ .struct_span_err(
+ sp,
+ &format!("`{} @` is not allowed in a {}", ident.name, ctx),
+ )
+ .span_label(sp, "this is only allowed in slice patterns")
+ .help("remove this and bind each tuple field independently")
+ .span_suggestion_verbose(
+ sp,
+ &format!("if you don't need to use the contents of {}, discard the tuple's remaining fields", ident),
+ "..",
+ Applicability::MaybeIncorrect,
+ )
+ .emit();
+ }
+ _ => {}
+ }
+
+ // It was not a sub-tuple pattern so lower it normally.
+ elems.push(self.lower_pat_mut(pat));
+ }
+
+ for (_, pat) in iter {
+ // There was a previous sub-tuple pattern; make sure we don't allow more...
+ if pat.is_rest() {
+ // ...but there was one again, so error.
+ self.ban_extra_rest_pat(pat.span, rest.unwrap().1, ctx);
+ } else {
+ elems.push(self.lower_pat_mut(pat));
+ }
+ }
+
+ (self.arena.alloc_from_iter(elems), rest.map(|(ddpos, _)| ddpos))
+ }
+
+ /// Lower a slice pattern of form `[pat_0, ..., pat_n]` into
+ /// `hir::PatKind::Slice(before, slice, after)`.
+ ///
+ /// When encountering `($binding_mode $ident @)? ..` (`slice`),
+ /// this is interpreted as a sub-slice pattern semantically.
+ /// Patterns that follow, which are not like `slice` -- or an error occurs, are in `after`.
+ fn lower_pat_slice(&mut self, pats: &[P<Pat>]) -> hir::PatKind<'hir> {
+ let mut before = Vec::new();
+ let mut after = Vec::new();
+ let mut slice = None;
+ let mut prev_rest_span = None;
+
+ // Lowers `$bm $ident @ ..` to `$bm $ident @ _`.
+ let lower_rest_sub = |this: &mut Self, pat, bm, ident, sub| {
+ let lower_sub = |this: &mut Self| Some(this.pat_wild_with_node_id_of(sub));
+ let node = this.lower_pat_ident(pat, bm, ident, lower_sub);
+ this.pat_with_node_id_of(pat, node)
+ };
+
+ let mut iter = pats.iter();
+ // Lower all the patterns until the first occurrence of a sub-slice pattern.
+ for pat in iter.by_ref() {
+ match pat.kind {
+ // Found a sub-slice pattern `..`. Record, lower it to `_`, and stop here.
+ PatKind::Rest => {
+ prev_rest_span = Some(pat.span);
+ slice = Some(self.pat_wild_with_node_id_of(pat));
+ break;
+ }
+ // Found a sub-slice pattern `$binding_mode $ident @ ..`.
+ // Record, lower it to `$binding_mode $ident @ _`, and stop here.
+ PatKind::Ident(ref bm, ident, Some(ref sub)) if sub.is_rest() => {
+ prev_rest_span = Some(sub.span);
+ slice = Some(self.arena.alloc(lower_rest_sub(self, pat, bm, ident, sub)));
+ break;
+ }
+ // It was not a subslice pattern so lower it normally.
+ _ => before.push(self.lower_pat_mut(pat)),
+ }
+ }
+
+ // Lower all the patterns after the first sub-slice pattern.
+ for pat in iter {
+ // There was a previous subslice pattern; make sure we don't allow more.
+ let rest_span = match pat.kind {
+ PatKind::Rest => Some(pat.span),
+ PatKind::Ident(ref bm, ident, Some(ref sub)) if sub.is_rest() => {
+ // #69103: Lower into `binding @ _` as above to avoid ICEs.
+ after.push(lower_rest_sub(self, pat, bm, ident, sub));
+ Some(sub.span)
+ }
+ _ => None,
+ };
+ if let Some(rest_span) = rest_span {
+ // We have e.g., `[a, .., b, ..]`. That's no good, error!
+ self.ban_extra_rest_pat(rest_span, prev_rest_span.unwrap(), "slice");
+ } else {
+ // Lower the pattern normally.
+ after.push(self.lower_pat_mut(pat));
+ }
+ }
+
+ hir::PatKind::Slice(
+ self.arena.alloc_from_iter(before),
+ slice,
+ self.arena.alloc_from_iter(after),
+ )
+ }
+
+ fn lower_pat_ident(
+ &mut self,
+ p: &Pat,
+ binding_mode: &BindingMode,
+ ident: Ident,
+ lower_sub: impl FnOnce(&mut Self) -> Option<&'hir hir::Pat<'hir>>,
+ ) -> hir::PatKind<'hir> {
+ match self.resolver.get_partial_res(p.id).map(|d| d.base_res()) {
+ // `None` can occur in body-less function signatures
+ res @ (None | Some(Res::Local(_))) => {
+ let canonical_id = match res {
+ Some(Res::Local(id)) => id,
+ _ => p.id,
+ };
+
+ hir::PatKind::Binding(
+ self.lower_binding_mode(binding_mode),
+ self.lower_node_id(canonical_id),
+ self.lower_ident(ident),
+ lower_sub(self),
+ )
+ }
+ Some(res) => hir::PatKind::Path(hir::QPath::Resolved(
+ None,
+ self.arena.alloc(hir::Path {
+ span: self.lower_span(ident.span),
+ res: self.lower_res(res),
+ segments: arena_vec![self; hir::PathSegment::from_ident(self.lower_ident(ident))],
+ }),
+ )),
+ }
+ }
+
+ fn lower_binding_mode(&mut self, b: &BindingMode) -> hir::BindingAnnotation {
+ match *b {
+ BindingMode::ByValue(Mutability::Not) => hir::BindingAnnotation::Unannotated,
+ BindingMode::ByRef(Mutability::Not) => hir::BindingAnnotation::Ref,
+ BindingMode::ByValue(Mutability::Mut) => hir::BindingAnnotation::Mutable,
+ BindingMode::ByRef(Mutability::Mut) => hir::BindingAnnotation::RefMut,
+ }
+ }
+
+ fn pat_wild_with_node_id_of(&mut self, p: &Pat) -> &'hir hir::Pat<'hir> {
+ self.arena.alloc(self.pat_with_node_id_of(p, hir::PatKind::Wild))
+ }
+
+ /// Construct a `Pat` with the `HirId` of `p.id` lowered.
+ fn pat_with_node_id_of(&mut self, p: &Pat, kind: hir::PatKind<'hir>) -> hir::Pat<'hir> {
+ hir::Pat {
+ hir_id: self.lower_node_id(p.id),
+ kind,
+ span: self.lower_span(p.span),
+ default_binding_modes: true,
+ }
+ }
+
+ /// Emit a friendly error for extra `..` patterns in a tuple/tuple struct/slice pattern.
+ pub(crate) fn ban_extra_rest_pat(&self, sp: Span, prev_sp: Span, ctx: &str) {
+ self.diagnostic()
+ .struct_span_err(sp, &format!("`..` can only be used once per {} pattern", ctx))
+ .span_label(sp, &format!("can only be used once per {} pattern", ctx))
+ .span_label(prev_sp, "previously used here")
+ .emit();
+ }
+
+ /// Used to ban the `..` pattern in places it shouldn't be semantically.
+ fn ban_illegal_rest_pat(&self, sp: Span) -> hir::PatKind<'hir> {
+ self.diagnostic()
+ .struct_span_err(sp, "`..` patterns are not allowed here")
+ .note("only allowed in tuple, tuple struct, and slice patterns")
+ .emit();
+
+ // We're not in a list context so `..` can be reasonably treated
+ // as `_` because it should always be valid and roughly matches the
+ // intent of `..` (notice that the rest of a single slot is that slot).
+ hir::PatKind::Wild
+ }
+
+ fn lower_range_end(&mut self, e: &RangeEnd, has_end: bool) -> hir::RangeEnd {
+ match *e {
+ RangeEnd::Excluded if has_end => hir::RangeEnd::Excluded,
+ // No end; so `X..` behaves like `RangeFrom`.
+ RangeEnd::Excluded | RangeEnd::Included(_) => hir::RangeEnd::Included,
+ }
+ }
+
+ /// Matches `'-' lit | lit (cf. parser::Parser::parse_literal_maybe_minus)`,
+ /// or paths for ranges.
+ //
+ // FIXME: do we want to allow `expr -> pattern` conversion to create path expressions?
+ // That means making this work:
+ //
+ // ```rust,ignore (FIXME)
+ // struct S;
+ // macro_rules! m {
+ // ($a:expr) => {
+ // let $a = S;
+ // }
+ // }
+ // m!(S);
+ // ```
+ fn lower_expr_within_pat(&mut self, expr: &Expr, allow_paths: bool) -> &'hir hir::Expr<'hir> {
+ match expr.kind {
+ ExprKind::Lit(..) | ExprKind::ConstBlock(..) | ExprKind::Err => {}
+ ExprKind::Path(..) if allow_paths => {}
+ ExprKind::Unary(UnOp::Neg, ref inner) if matches!(inner.kind, ExprKind::Lit(_)) => {}
+ _ => {
+ self.diagnostic()
+ .span_err(expr.span, "arbitrary expressions aren't allowed in patterns");
+ return self.arena.alloc(self.expr_err(expr.span));
+ }
+ }
+ self.lower_expr(expr)
+ }
+}
diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs
new file mode 100644
index 000000000..393be3b45
--- /dev/null
+++ b/compiler/rustc_ast_lowering/src/path.rs
@@ -0,0 +1,406 @@
+use crate::ImplTraitPosition;
+
+use super::ResolverAstLoweringExt;
+use super::{GenericArgsCtor, LifetimeRes, ParenthesizedGenericArgs};
+use super::{ImplTraitContext, LoweringContext, ParamMode};
+
+use rustc_ast::{self as ast, *};
+use rustc_errors::{struct_span_err, Applicability};
+use rustc_hir as hir;
+use rustc_hir::def::{DefKind, PartialRes, Res};
+use rustc_hir::GenericArg;
+use rustc_span::symbol::{kw, Ident};
+use rustc_span::{BytePos, Span, DUMMY_SP};
+
+use smallvec::smallvec;
+use tracing::debug;
+
+impl<'a, 'hir> LoweringContext<'a, 'hir> {
+ #[instrument(level = "trace", skip(self))]
+ pub(crate) fn lower_qpath(
+ &mut self,
+ id: NodeId,
+ qself: &Option<QSelf>,
+ p: &Path,
+ param_mode: ParamMode,
+ itctx: ImplTraitContext,
+ ) -> hir::QPath<'hir> {
+ let qself_position = qself.as_ref().map(|q| q.position);
+ let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx));
+
+ let partial_res =
+ self.resolver.get_partial_res(id).unwrap_or_else(|| PartialRes::new(Res::Err));
+
+ let path_span_lo = p.span.shrink_to_lo();
+ let proj_start = p.segments.len() - partial_res.unresolved_segments();
+ let path = self.arena.alloc(hir::Path {
+ res: self.lower_res(partial_res.base_res()),
+ segments: self.arena.alloc_from_iter(p.segments[..proj_start].iter().enumerate().map(
+ |(i, segment)| {
+ let param_mode = match (qself_position, param_mode) {
+ (Some(j), ParamMode::Optional) if i < j => {
+ // This segment is part of the trait path in a
+ // qualified path - one of `a`, `b` or `Trait`
+ // in `<X as a::b::Trait>::T::U::method`.
+ ParamMode::Explicit
+ }
+ _ => param_mode,
+ };
+
+ let parenthesized_generic_args = match partial_res.base_res() {
+ // `a::b::Trait(Args)`
+ Res::Def(DefKind::Trait, _) if i + 1 == proj_start => {
+ ParenthesizedGenericArgs::Ok
+ }
+ // `a::b::Trait(Args)::TraitItem`
+ Res::Def(DefKind::AssocFn, _)
+ | Res::Def(DefKind::AssocConst, _)
+ | Res::Def(DefKind::AssocTy, _)
+ if i + 2 == proj_start =>
+ {
+ ParenthesizedGenericArgs::Ok
+ }
+ // Avoid duplicated errors.
+ Res::Err => ParenthesizedGenericArgs::Ok,
+ // An error
+ _ => ParenthesizedGenericArgs::Err,
+ };
+
+ self.lower_path_segment(
+ p.span,
+ segment,
+ param_mode,
+ parenthesized_generic_args,
+ itctx,
+ )
+ },
+ )),
+ span: self.lower_span(
+ p.segments[..proj_start]
+ .last()
+ .map_or(path_span_lo, |segment| path_span_lo.to(segment.span())),
+ ),
+ });
+
+ // Simple case, either no projections, or only fully-qualified.
+ // E.g., `std::mem::size_of` or `<I as Iterator>::Item`.
+ if partial_res.unresolved_segments() == 0 {
+ return hir::QPath::Resolved(qself, path);
+ }
+
+ // Create the innermost type that we're projecting from.
+ let mut ty = if path.segments.is_empty() {
+ // If the base path is empty that means there exists a
+ // syntactical `Self`, e.g., `&i32` in `<&i32>::clone`.
+ qself.expect("missing QSelf for <T>::...")
+ } else {
+ // Otherwise, the base path is an implicit `Self` type path,
+ // e.g., `Vec` in `Vec::new` or `<I as Iterator>::Item` in
+ // `<I as Iterator>::Item::default`.
+ let new_id = self.next_id();
+ self.arena.alloc(self.ty_path(new_id, path.span, hir::QPath::Resolved(qself, path)))
+ };
+
+ // Anything after the base path are associated "extensions",
+ // out of which all but the last one are associated types,
+ // e.g., for `std::vec::Vec::<T>::IntoIter::Item::clone`:
+ // * base path is `std::vec::Vec<T>`
+ // * "extensions" are `IntoIter`, `Item` and `clone`
+ // * type nodes are:
+ // 1. `std::vec::Vec<T>` (created above)
+ // 2. `<std::vec::Vec<T>>::IntoIter`
+ // 3. `<<std::vec::Vec<T>>::IntoIter>::Item`
+ // * final path is `<<<std::vec::Vec<T>>::IntoIter>::Item>::clone`
+ for (i, segment) in p.segments.iter().enumerate().skip(proj_start) {
+ let hir_segment = self.arena.alloc(self.lower_path_segment(
+ p.span,
+ segment,
+ param_mode,
+ ParenthesizedGenericArgs::Err,
+ itctx,
+ ));
+ let qpath = hir::QPath::TypeRelative(ty, hir_segment);
+
+ // It's finished, return the extension of the right node type.
+ if i == p.segments.len() - 1 {
+ return qpath;
+ }
+
+ // Wrap the associated extension in another type node.
+ let new_id = self.next_id();
+ ty = self.arena.alloc(self.ty_path(new_id, path_span_lo.to(segment.span()), qpath));
+ }
+
+ // We should've returned in the for loop above.
+
+ self.diagnostic().span_bug(
+ p.span,
+ &format!(
+ "lower_qpath: no final extension segment in {}..{}",
+ proj_start,
+ p.segments.len()
+ ),
+ );
+ }
+
+ pub(crate) fn lower_path_extra(
+ &mut self,
+ res: Res,
+ p: &Path,
+ param_mode: ParamMode,
+ ) -> &'hir hir::Path<'hir> {
+ self.arena.alloc(hir::Path {
+ res,
+ segments: self.arena.alloc_from_iter(p.segments.iter().map(|segment| {
+ self.lower_path_segment(
+ p.span,
+ segment,
+ param_mode,
+ ParenthesizedGenericArgs::Err,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+ )
+ })),
+ span: self.lower_span(p.span),
+ })
+ }
+
+ pub(crate) fn lower_path(
+ &mut self,
+ id: NodeId,
+ p: &Path,
+ param_mode: ParamMode,
+ ) -> &'hir hir::Path<'hir> {
+ let res = self.expect_full_res(id);
+ let res = self.lower_res(res);
+ self.lower_path_extra(res, p, param_mode)
+ }
+
+ pub(crate) fn lower_path_segment(
+ &mut self,
+ path_span: Span,
+ segment: &PathSegment,
+ param_mode: ParamMode,
+ parenthesized_generic_args: ParenthesizedGenericArgs,
+ itctx: ImplTraitContext,
+ ) -> hir::PathSegment<'hir> {
+ debug!("path_span: {:?}, lower_path_segment(segment: {:?})", path_span, segment,);
+ let (mut generic_args, infer_args) = if let Some(ref generic_args) = segment.args {
+ let msg = "parenthesized type parameters may only be used with a `Fn` trait";
+ match **generic_args {
+ GenericArgs::AngleBracketed(ref data) => {
+ self.lower_angle_bracketed_parameter_data(data, param_mode, itctx)
+ }
+ GenericArgs::Parenthesized(ref data) => match parenthesized_generic_args {
+ ParenthesizedGenericArgs::Ok => self.lower_parenthesized_parameter_data(data),
+ ParenthesizedGenericArgs::Err => {
+ let mut err = struct_span_err!(self.tcx.sess, data.span, E0214, "{}", msg);
+ err.span_label(data.span, "only `Fn` traits may use parentheses");
+ // Suggest replacing parentheses with angle brackets `Trait(params...)` to `Trait<params...>`
+ if !data.inputs.is_empty() {
+ // Start of the span to the 1st character of 1st argument
+ let open_param = data.inputs_span.shrink_to_lo().to(data
+ .inputs
+ .first()
+ .unwrap()
+ .span
+ .shrink_to_lo());
+ // Last character position of last argument to the end of the span
+ let close_param = data
+ .inputs
+ .last()
+ .unwrap()
+ .span
+ .shrink_to_hi()
+ .to(data.inputs_span.shrink_to_hi());
+ err.multipart_suggestion(
+ &format!("use angle brackets instead",),
+ vec![
+ (open_param, String::from("<")),
+ (close_param, String::from(">")),
+ ],
+ Applicability::MaybeIncorrect,
+ );
+ }
+ err.emit();
+ (
+ self.lower_angle_bracketed_parameter_data(
+ &data.as_angle_bracketed_args(),
+ param_mode,
+ itctx,
+ )
+ .0,
+ false,
+ )
+ }
+ },
+ }
+ } else {
+ (
+ GenericArgsCtor {
+ args: Default::default(),
+ bindings: &[],
+ parenthesized: false,
+ span: path_span.shrink_to_hi(),
+ },
+ param_mode == ParamMode::Optional,
+ )
+ };
+
+ let has_lifetimes =
+ generic_args.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_)));
+ if !generic_args.parenthesized && !has_lifetimes {
+ self.maybe_insert_elided_lifetimes_in_path(
+ path_span,
+ segment.id,
+ segment.ident.span,
+ &mut generic_args,
+ );
+ }
+
+ let res = self.expect_full_res(segment.id);
+ let id = self.lower_node_id(segment.id);
+ debug!(
+ "lower_path_segment: ident={:?} original-id={:?} new-id={:?}",
+ segment.ident, segment.id, id,
+ );
+
+ hir::PathSegment {
+ ident: self.lower_ident(segment.ident),
+ hir_id: Some(id),
+ res: Some(self.lower_res(res)),
+ infer_args,
+ args: if generic_args.is_empty() && generic_args.span.is_empty() {
+ None
+ } else {
+ Some(generic_args.into_generic_args(self))
+ },
+ }
+ }
+
+ fn maybe_insert_elided_lifetimes_in_path(
+ &mut self,
+ path_span: Span,
+ segment_id: NodeId,
+ segment_ident_span: Span,
+ generic_args: &mut GenericArgsCtor<'hir>,
+ ) {
+ let (start, end) = match self.resolver.get_lifetime_res(segment_id) {
+ Some(LifetimeRes::ElidedAnchor { start, end }) => (start, end),
+ None => return,
+ Some(_) => panic!(),
+ };
+ let expected_lifetimes = end.as_usize() - start.as_usize();
+ debug!(expected_lifetimes);
+
+ // Note: these spans are used for diagnostics when they can't be inferred.
+ // See rustc_resolve::late::lifetimes::LifetimeContext::add_missing_lifetime_specifiers_label
+ let elided_lifetime_span = if generic_args.span.is_empty() {
+ // If there are no brackets, use the identifier span.
+ // HACK: we use find_ancestor_inside to properly suggest elided spans in paths
+ // originating from macros, since the segment's span might be from a macro arg.
+ segment_ident_span.find_ancestor_inside(path_span).unwrap_or(path_span)
+ } else if generic_args.is_empty() {
+ // If there are brackets, but not generic arguments, then use the opening bracket
+ generic_args.span.with_hi(generic_args.span.lo() + BytePos(1))
+ } else {
+ // Else use an empty span right after the opening bracket.
+ generic_args.span.with_lo(generic_args.span.lo() + BytePos(1)).shrink_to_lo()
+ };
+
+ generic_args.args.insert_many(
+ 0,
+ (start.as_u32()..end.as_u32()).map(|i| {
+ let id = NodeId::from_u32(i);
+ let l = self.lower_lifetime(&Lifetime {
+ id,
+ ident: Ident::new(kw::UnderscoreLifetime, elided_lifetime_span),
+ });
+ GenericArg::Lifetime(l)
+ }),
+ );
+ }
+
+ pub(crate) fn lower_angle_bracketed_parameter_data(
+ &mut self,
+ data: &AngleBracketedArgs,
+ param_mode: ParamMode,
+ itctx: ImplTraitContext,
+ ) -> (GenericArgsCtor<'hir>, bool) {
+ let has_non_lt_args = data.args.iter().any(|arg| match arg {
+ AngleBracketedArg::Arg(ast::GenericArg::Lifetime(_))
+ | AngleBracketedArg::Constraint(_) => false,
+ AngleBracketedArg::Arg(ast::GenericArg::Type(_) | ast::GenericArg::Const(_)) => true,
+ });
+ let args = data
+ .args
+ .iter()
+ .filter_map(|arg| match arg {
+ AngleBracketedArg::Arg(arg) => Some(self.lower_generic_arg(arg, itctx)),
+ AngleBracketedArg::Constraint(_) => None,
+ })
+ .collect();
+ let bindings = self.arena.alloc_from_iter(data.args.iter().filter_map(|arg| match arg {
+ AngleBracketedArg::Constraint(c) => Some(self.lower_assoc_ty_constraint(c, itctx)),
+ AngleBracketedArg::Arg(_) => None,
+ }));
+ let ctor = GenericArgsCtor { args, bindings, parenthesized: false, span: data.span };
+ (ctor, !has_non_lt_args && param_mode == ParamMode::Optional)
+ }
+
+ fn lower_parenthesized_parameter_data(
+ &mut self,
+ data: &ParenthesizedArgs,
+ ) -> (GenericArgsCtor<'hir>, bool) {
+ // Switch to `PassThrough` mode for anonymous lifetimes; this
+ // means that we permit things like `&Ref<T>`, where `Ref` has
+ // a hidden lifetime parameter. This is needed for backwards
+ // compatibility, even in contexts like an impl header where
+ // we generally don't permit such things (see #51008).
+ let ParenthesizedArgs { span, inputs, inputs_span, output } = data;
+ let inputs = self.arena.alloc_from_iter(inputs.iter().map(|ty| {
+ self.lower_ty_direct(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam))
+ }));
+ let output_ty = match output {
+ FnRetTy::Ty(ty) => {
+ self.lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn))
+ }
+ FnRetTy::Default(_) => self.arena.alloc(self.ty_tup(*span, &[])),
+ };
+ let args = smallvec![GenericArg::Type(self.ty_tup(*inputs_span, inputs))];
+ let binding = self.output_ty_binding(output_ty.span, output_ty);
+ (
+ GenericArgsCtor {
+ args,
+ bindings: arena_vec![self; binding],
+ parenthesized: true,
+ span: data.inputs_span,
+ },
+ false,
+ )
+ }
+
+ /// An associated type binding `Output = $ty`.
+ pub(crate) fn output_ty_binding(
+ &mut self,
+ span: Span,
+ ty: &'hir hir::Ty<'hir>,
+ ) -> hir::TypeBinding<'hir> {
+ let ident = Ident::with_dummy_span(hir::FN_OUTPUT_NAME);
+ let kind = hir::TypeBindingKind::Equality { term: ty.into() };
+ let args = arena_vec![self;];
+ let bindings = arena_vec![self;];
+ let gen_args = self.arena.alloc(hir::GenericArgs {
+ args,
+ bindings,
+ parenthesized: false,
+ span_ext: DUMMY_SP,
+ });
+ hir::TypeBinding {
+ hir_id: self.next_id(),
+ gen_args,
+ span: self.lower_span(span),
+ ident,
+ kind,
+ }
+ }
+}