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/messages.ftl (renamed from compiler/rustc_ast_lowering/locales/en-US.ftl)12
-rw-r--r--compiler/rustc_ast_lowering/src/errors.rs18
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs92
-rw-r--r--compiler/rustc_ast_lowering/src/format.rs274
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs25
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs140
-rw-r--r--compiler/rustc_ast_lowering/src/path.rs25
7 files changed, 434 insertions, 152 deletions
diff --git a/compiler/rustc_ast_lowering/locales/en-US.ftl b/compiler/rustc_ast_lowering/messages.ftl
index 3ccd84398..21b2a3c22 100644
--- a/compiler/rustc_ast_lowering/locales/en-US.ftl
+++ b/compiler/rustc_ast_lowering/messages.ftl
@@ -139,3 +139,15 @@ ast_lowering_trait_fn_async =
.label = `async` because of this
.note = `async` trait functions are not currently supported
.note2 = consider using the `async-trait` crate: https://crates.io/crates/async-trait
+
+ast_lowering_bad_return_type_notation_inputs =
+ argument types not allowed with return type notation
+ .suggestion = remove the input types
+
+ast_lowering_bad_return_type_notation_needs_dots =
+ return type notation arguments must be elided with `..`
+ .suggestion = add `..`
+
+ast_lowering_bad_return_type_notation_output =
+ return type not allowed with return type notation
+ .suggestion = remove the return type
diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs
index 5e6b6050b..3e9f9b436 100644
--- a/compiler/rustc_ast_lowering/src/errors.rs
+++ b/compiler/rustc_ast_lowering/src/errors.rs
@@ -137,7 +137,7 @@ pub struct AsyncNonMoveClosureNotSupported {
#[derive(Diagnostic, Clone, Copy)]
#[diag(ast_lowering_functional_record_update_destructuring_assignment)]
-pub struct FunctionalRecordUpdateDestructuringAssignemnt {
+pub struct FunctionalRecordUpdateDestructuringAssignment {
#[primary_span]
#[suggestion(code = "", applicability = "machine-applicable")]
pub span: Span,
@@ -347,3 +347,19 @@ pub struct TraitFnAsync {
#[label]
pub span: Span,
}
+
+#[derive(Diagnostic)]
+pub enum BadReturnTypeNotation {
+ #[diag(ast_lowering_bad_return_type_notation_inputs)]
+ Inputs {
+ #[primary_span]
+ #[suggestion(code = "()", applicability = "maybe-incorrect")]
+ span: Span,
+ },
+ #[diag(ast_lowering_bad_return_type_notation_output)]
+ Output {
+ #[primary_span]
+ #[suggestion(code = "", applicability = "maybe-incorrect")]
+ span: Span,
+ },
+}
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index ffb30b1b3..1b1c4765b 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -1,6 +1,6 @@
use super::errors::{
AsyncGeneratorsNotSupported, AsyncNonMoveClosureNotSupported, AwaitOnlyInAsyncFnAndBlocks,
- BaseExpressionDoubleDot, ClosureCannotBeStatic, FunctionalRecordUpdateDestructuringAssignemnt,
+ BaseExpressionDoubleDot, ClosureCannotBeStatic, FunctionalRecordUpdateDestructuringAssignment,
GeneratorTooManyParameters, InclusiveRangeWithNoEnd, NotSupportedForLifetimeBinderAsyncClosure,
UnderscoreExprLhsAssign,
};
@@ -32,7 +32,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
ensure_sufficient_stack(|| {
match &e.kind {
- // Paranthesis expression does not have a HirId and is handled specially.
+ // Parenthesis expression does not have a HirId and is handled specially.
ExprKind::Paren(ex) => {
let mut ex = self.lower_expr_mut(ex);
// Include parens in span, but only if it is a super-span.
@@ -70,7 +70,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.lower_attrs(hir_id, &e.attrs);
let kind = match &e.kind {
- ExprKind::Box(inner) => hir::ExprKind::Box(self.lower_expr(inner)),
ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)),
ExprKind::ConstBlock(anon_const) => {
let anon_const = self.lower_anon_const(anon_const);
@@ -174,10 +173,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.arena.alloc_from_iter(arms.iter().map(|x| self.lower_arm(x))),
hir::MatchSource::Normal,
),
- ExprKind::Async(capture_clause, closure_node_id, block) => self.make_async_expr(
+ ExprKind::Async(capture_clause, block) => self.make_async_expr(
*capture_clause,
- hir_id,
- *closure_node_id,
+ e.id,
None,
e.span,
hir::AsyncGeneratorKind::Block,
@@ -316,7 +314,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
),
ExprKind::Try(sub_expr) => self.lower_expr_try(e.span, sub_expr),
- ExprKind::Paren(_) | ExprKind::ForLoop(..) => unreachable!("already handled"),
+ ExprKind::Paren(_) | ExprKind::ForLoop(..) => {
+ unreachable!("already handled")
+ }
ExprKind::MacCall(_) => panic!("{:?} shouldn't exist here", e.span),
};
@@ -434,7 +434,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
// `if let pat = val` or `if foo && let pat = val`, as we _do_ want `val` to live beyond the
// condition in this case.
//
- // In order to mantain the drop behavior for the non `let` parts of the condition,
+ // In order to maintain the drop behavior for the non `let` parts of the condition,
// we still wrap them in terminating scopes, e.g. `if foo && let pat = val` essentially
// gets transformed into `if { let _t = foo; _t } && let pat = val`
match &cond.kind {
@@ -578,14 +578,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
/// This results in:
///
/// ```text
- /// std::future::identity_future(static move? |_task_context| -> <ret_ty> {
+ /// static move? |_task_context| -> <ret_ty> {
/// <body>
- /// })
+ /// }
/// ```
pub(super) fn make_async_expr(
&mut self,
capture_clause: CaptureBy,
- outer_hir_id: hir::HirId,
closure_node_id: NodeId,
ret_ty: Option<hir::FnRetTy<'hir>>,
span: Span,
@@ -638,33 +637,36 @@ impl<'hir> LoweringContext<'_, 'hir> {
});
// `static |_task_context| -> <ret_ty> { body }`:
- let generator_kind = {
- let c = self.arena.alloc(hir::Closure {
- def_id: self.local_def_id(closure_node_id),
- binder: hir::ClosureBinder::Default,
- capture_clause,
- bound_generic_params: &[],
- fn_decl,
- body,
- fn_decl_span: self.lower_span(span),
- fn_arg_span: None,
- movability: Some(hir::Movability::Static),
- constness: hir::Constness::NotConst,
- });
-
- hir::ExprKind::Closure(c)
- };
-
- let hir_id = self.lower_node_id(closure_node_id);
- let unstable_span =
- self.mark_span_with_reason(DesugaringKind::Async, span, self.allow_gen_future.clone());
+ hir::ExprKind::Closure(self.arena.alloc(hir::Closure {
+ def_id: self.local_def_id(closure_node_id),
+ binder: hir::ClosureBinder::Default,
+ capture_clause,
+ bound_generic_params: &[],
+ fn_decl,
+ body,
+ fn_decl_span: self.lower_span(span),
+ fn_arg_span: None,
+ movability: Some(hir::Movability::Static),
+ constness: hir::Constness::NotConst,
+ }))
+ }
+ /// Forwards a possible `#[track_caller]` annotation from `outer_hir_id` to
+ /// `inner_hir_id` in case the `closure_track_caller` feature is enabled.
+ pub(super) fn maybe_forward_track_caller(
+ &mut self,
+ span: Span,
+ outer_hir_id: hir::HirId,
+ inner_hir_id: hir::HirId,
+ ) {
if self.tcx.features().closure_track_caller
&& let Some(attrs) = self.attrs.get(&outer_hir_id.local_id)
&& attrs.into_iter().any(|attr| attr.has_name(sym::track_caller))
{
+ let unstable_span =
+ self.mark_span_with_reason(DesugaringKind::Async, span, self.allow_gen_future.clone());
self.lower_attrs(
- hir_id,
+ inner_hir_id,
&[Attribute {
kind: AttrKind::Normal(ptr::P(NormalAttr {
item: AttrItem {
@@ -680,23 +682,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
}],
);
}
-
- let generator = hir::Expr { hir_id, kind: generator_kind, span: self.lower_span(span) };
-
- // FIXME(swatinem):
- // For some reason, the async block needs to flow through *any*
- // call (like the identity function), as otherwise type and lifetime
- // inference have a hard time figuring things out.
- // Without this, we would get:
- // E0720 in tests/ui/impl-trait/in-trait/default-body-with-rpit.rs
- // E0700 in tests/ui/self/self_lifetime-async.rs
-
- // `future::identity_future`:
- let identity_future =
- self.expr_lang_item_path(unstable_span, hir::LangItem::IdentityFuture, None);
-
- // `future::identity_future(generator)`:
- hir::ExprKind::Call(self.arena.alloc(identity_future), arena_vec![self; generator])
}
/// Desugar `<expr>.await` into:
@@ -1002,7 +987,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
// Transform `async |x: u8| -> X { ... }` into
- // `|x: u8| identity_future(|| -> X { ... })`.
+ // `|x: u8| || -> X { ... }`.
let body_id = this.lower_fn_body(&outer_decl, |this| {
let async_ret_ty = if let FnRetTy::Ty(ty) = &decl.output {
let itctx = ImplTraitContext::Disallowed(ImplTraitPosition::AsyncBlock);
@@ -1013,14 +998,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
let async_body = this.make_async_expr(
capture_clause,
- closure_hir_id,
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)
+ let hir_id = this.lower_node_id(inner_closure_id);
+ this.maybe_forward_track_caller(body.span, closure_hir_id, hir_id);
+ hir::Expr { hir_id, kind: async_body, span: this.lower_span(body.span) }
});
body_id
});
@@ -1246,7 +1232,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
);
let fields_omitted = match &se.rest {
StructRest::Base(e) => {
- self.tcx.sess.emit_err(FunctionalRecordUpdateDestructuringAssignemnt {
+ self.tcx.sess.emit_err(FunctionalRecordUpdateDestructuringAssignment {
span: e.span,
});
true
diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs
index 4095e225a..c41bdc440 100644
--- a/compiler/rustc_ast_lowering/src/format.rs
+++ b/compiler/rustc_ast_lowering/src/format.rs
@@ -2,18 +2,177 @@ use super::LoweringContext;
use rustc_ast as ast;
use rustc_ast::visit::{self, Visitor};
use rustc_ast::*;
-use rustc_data_structures::fx::FxIndexSet;
+use rustc_data_structures::fx::FxIndexMap;
use rustc_hir as hir;
use rustc_span::{
sym,
symbol::{kw, Ident},
- Span,
+ Span, Symbol,
};
+use std::borrow::Cow;
impl<'hir> LoweringContext<'_, 'hir> {
pub(crate) fn lower_format_args(&mut self, sp: Span, fmt: &FormatArgs) -> hir::ExprKind<'hir> {
- expand_format_args(self, sp, fmt)
+ // Never call the const constructor of `fmt::Arguments` if the
+ // format_args!() had any arguments _before_ flattening/inlining.
+ let allow_const = fmt.arguments.all_args().is_empty();
+ let mut fmt = Cow::Borrowed(fmt);
+ if self.tcx.sess.opts.unstable_opts.flatten_format_args {
+ fmt = flatten_format_args(fmt);
+ fmt = inline_literals(fmt);
+ }
+ expand_format_args(self, sp, &fmt, allow_const)
+ }
+}
+
+/// Flattens nested `format_args!()` into one.
+///
+/// Turns
+///
+/// `format_args!("a {} {} {}.", 1, format_args!("b{}!", 2), 3)`
+///
+/// into
+///
+/// `format_args!("a {} b{}! {}.", 1, 2, 3)`.
+fn flatten_format_args(mut fmt: Cow<'_, FormatArgs>) -> Cow<'_, FormatArgs> {
+ let mut i = 0;
+ while i < fmt.template.len() {
+ if let FormatArgsPiece::Placeholder(placeholder) = &fmt.template[i]
+ && let FormatTrait::Display | FormatTrait::Debug = &placeholder.format_trait
+ && let Ok(arg_index) = placeholder.argument.index
+ && let arg = fmt.arguments.all_args()[arg_index].expr.peel_parens_and_refs()
+ && let ExprKind::FormatArgs(_) = &arg.kind
+ // Check that this argument is not used by any other placeholders.
+ && fmt.template.iter().enumerate().all(|(j, p)|
+ i == j ||
+ !matches!(p, FormatArgsPiece::Placeholder(placeholder)
+ if placeholder.argument.index == Ok(arg_index))
+ )
+ {
+ // Now we need to mutate the outer FormatArgs.
+ // If this is the first time, this clones the outer FormatArgs.
+ let fmt = fmt.to_mut();
+
+ // Take the inner FormatArgs out of the outer arguments, and
+ // replace it by the inner arguments. (We can't just put those at
+ // the end, because we need to preserve the order of evaluation.)
+
+ let args = fmt.arguments.all_args_mut();
+ let remaining_args = args.split_off(arg_index + 1);
+ let old_arg_offset = args.len();
+ let mut fmt2 = &mut args.pop().unwrap().expr; // The inner FormatArgs.
+ let fmt2 = loop { // Unwrap the Expr to get to the FormatArgs.
+ match &mut fmt2.kind {
+ ExprKind::Paren(inner) | ExprKind::AddrOf(BorrowKind::Ref, _, inner) => fmt2 = inner,
+ ExprKind::FormatArgs(fmt2) => break fmt2,
+ _ => unreachable!(),
+ }
+ };
+
+ args.append(fmt2.arguments.all_args_mut());
+ let new_arg_offset = args.len();
+ args.extend(remaining_args);
+
+ // Correct the indexes that refer to the arguments after the newly inserted arguments.
+ for_all_argument_indexes(&mut fmt.template, |index| {
+ if *index >= old_arg_offset {
+ *index -= old_arg_offset;
+ *index += new_arg_offset;
+ }
+ });
+
+ // Now merge the placeholders:
+
+ let rest = fmt.template.split_off(i + 1);
+ fmt.template.pop(); // remove the placeholder for the nested fmt args.
+ // Insert the pieces from the nested format args, but correct any
+ // placeholders to point to the correct argument index.
+ for_all_argument_indexes(&mut fmt2.template, |index| *index += arg_index);
+ fmt.template.append(&mut fmt2.template);
+ fmt.template.extend(rest);
+
+ // Don't increment `i` here, so we recurse into the newly added pieces.
+ } else {
+ i += 1;
+ }
}
+ fmt
+}
+
+/// Inline literals into the format string.
+///
+/// Turns
+///
+/// `format_args!("Hello, {}! {} {}", "World", 123, x)`
+///
+/// into
+///
+/// `format_args!("Hello, World! 123 {}", x)`.
+fn inline_literals(mut fmt: Cow<'_, FormatArgs>) -> Cow<'_, FormatArgs> {
+ let mut was_inlined = vec![false; fmt.arguments.all_args().len()];
+ let mut inlined_anything = false;
+
+ for i in 0..fmt.template.len() {
+ let FormatArgsPiece::Placeholder(placeholder) = &fmt.template[i] else { continue };
+ let Ok(arg_index) = placeholder.argument.index else { continue };
+
+ let mut literal = None;
+
+ if let FormatTrait::Display = placeholder.format_trait
+ && placeholder.format_options == Default::default()
+ && let arg = fmt.arguments.all_args()[arg_index].expr.peel_parens_and_refs()
+ && let ExprKind::Lit(lit) = arg.kind
+ {
+ if let token::LitKind::Str | token::LitKind::StrRaw(_) = lit.kind
+ && let Ok(LitKind::Str(s, _)) = LitKind::from_token_lit(lit)
+ {
+ literal = Some(s);
+ } else if let token::LitKind::Integer = lit.kind
+ && let Ok(LitKind::Int(n, _)) = LitKind::from_token_lit(lit)
+ {
+ literal = Some(Symbol::intern(&n.to_string()));
+ }
+ }
+
+ if let Some(literal) = literal {
+ // Now we need to mutate the outer FormatArgs.
+ // If this is the first time, this clones the outer FormatArgs.
+ let fmt = fmt.to_mut();
+ // Replace the placeholder with the literal.
+ fmt.template[i] = FormatArgsPiece::Literal(literal);
+ was_inlined[arg_index] = true;
+ inlined_anything = true;
+ }
+ }
+
+ // Remove the arguments that were inlined.
+ if inlined_anything {
+ let fmt = fmt.to_mut();
+
+ let mut remove = was_inlined;
+
+ // Don't remove anything that's still used.
+ for_all_argument_indexes(&mut fmt.template, |index| remove[*index] = false);
+
+ // Drop all the arguments that are marked for removal.
+ let mut remove_it = remove.iter();
+ fmt.arguments.all_args_mut().retain(|_| remove_it.next() != Some(&true));
+
+ // Calculate the mapping of old to new indexes for the remaining arguments.
+ let index_map: Vec<usize> = remove
+ .into_iter()
+ .scan(0, |i, remove| {
+ let mapped = *i;
+ *i += !remove as usize;
+ Some(mapped)
+ })
+ .collect();
+
+ // Correct the indexes that refer to arguments that have shifted position.
+ for_all_argument_indexes(&mut fmt.template, |index| *index = index_map[*index]);
+ }
+
+ fmt
}
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
@@ -79,7 +238,7 @@ fn make_count<'hir>(
ctx: &mut LoweringContext<'_, 'hir>,
sp: Span,
count: &Option<FormatCount>,
- argmap: &mut FxIndexSet<(usize, ArgumentType)>,
+ argmap: &mut FxIndexMap<(usize, ArgumentType), Option<Span>>,
) -> hir::Expr<'hir> {
match count {
Some(FormatCount::Literal(n)) => {
@@ -93,7 +252,7 @@ fn make_count<'hir>(
}
Some(FormatCount::Argument(arg)) => {
if let Ok(arg_index) = arg.index {
- let (i, _) = argmap.insert_full((arg_index, ArgumentType::Usize));
+ let (i, _) = argmap.insert_full((arg_index, ArgumentType::Usize), arg.span);
let count_param = ctx.arena.alloc(ctx.expr_lang_item_type_relative(
sp,
hir::LangItem::FormatCount,
@@ -132,12 +291,14 @@ fn make_format_spec<'hir>(
ctx: &mut LoweringContext<'_, 'hir>,
sp: Span,
placeholder: &FormatPlaceholder,
- argmap: &mut FxIndexSet<(usize, ArgumentType)>,
+ argmap: &mut FxIndexMap<(usize, ArgumentType), Option<Span>>,
) -> hir::Expr<'hir> {
let position = match placeholder.argument.index {
Ok(arg_index) => {
- let (i, _) =
- argmap.insert_full((arg_index, ArgumentType::Format(placeholder.format_trait)));
+ let (i, _) = argmap.insert_full(
+ (arg_index, ArgumentType::Format(placeholder.format_trait)),
+ placeholder.span,
+ );
ctx.expr_usize(sp, i)
}
Err(_) => ctx.expr(
@@ -189,11 +350,26 @@ fn expand_format_args<'hir>(
ctx: &mut LoweringContext<'_, 'hir>,
macsp: Span,
fmt: &FormatArgs,
+ allow_const: bool,
) -> hir::ExprKind<'hir> {
+ let mut incomplete_lit = String::new();
let lit_pieces =
ctx.arena.alloc_from_iter(fmt.template.iter().enumerate().filter_map(|(i, piece)| {
match piece {
- &FormatArgsPiece::Literal(s) => Some(ctx.expr_str(fmt.span, s)),
+ &FormatArgsPiece::Literal(s) => {
+ // Coalesce adjacent literal pieces.
+ if let Some(FormatArgsPiece::Literal(_)) = fmt.template.get(i + 1) {
+ incomplete_lit.push_str(s.as_str());
+ None
+ } else if !incomplete_lit.is_empty() {
+ incomplete_lit.push_str(s.as_str());
+ let s = Symbol::intern(&incomplete_lit);
+ incomplete_lit.clear();
+ Some(ctx.expr_str(fmt.span, s))
+ } else {
+ Some(ctx.expr_str(fmt.span, s))
+ }
+ }
&FormatArgsPiece::Placeholder(_) => {
// Inject empty string before placeholders when not already preceded by a literal piece.
if i == 0 || matches!(fmt.template[i - 1], FormatArgsPiece::Placeholder(_)) {
@@ -212,7 +388,7 @@ fn expand_format_args<'hir>(
// Create a list of all _unique_ (argument, format trait) combinations.
// E.g. "{0} {0:x} {0} {1}" -> [(0, Display), (0, LowerHex), (1, Display)]
- let mut argmap = FxIndexSet::default();
+ let mut argmap = FxIndexMap::default();
for piece in &fmt.template {
let FormatArgsPiece::Placeholder(placeholder) = piece else { continue };
if placeholder.format_options != Default::default() {
@@ -220,7 +396,10 @@ fn expand_format_args<'hir>(
use_format_options = true;
}
if let Ok(index) = placeholder.argument.index {
- if !argmap.insert((index, ArgumentType::Format(placeholder.format_trait))) {
+ if argmap
+ .insert((index, ArgumentType::Format(placeholder.format_trait)), placeholder.span)
+ .is_some()
+ {
// Duplicate (argument, format trait) combination,
// which we'll only put once in the args array.
use_format_options = true;
@@ -244,6 +423,18 @@ fn expand_format_args<'hir>(
let arguments = fmt.arguments.all_args();
+ if allow_const && arguments.is_empty() && argmap.is_empty() {
+ // Generate:
+ // <core::fmt::Arguments>::new_const(lit_pieces)
+ let new = ctx.arena.alloc(ctx.expr_lang_item_type_relative(
+ macsp,
+ hir::LangItem::FormatArguments,
+ sym::new_const,
+ ));
+ let new_args = ctx.arena.alloc_from_iter([lit_pieces]);
+ return hir::ExprKind::Call(new, new_args);
+ }
+
// If the args array contains exactly all the original arguments once,
// in order, we can use a simple array instead of a `match` construction.
// However, if there's a yield point in any argument except the first one,
@@ -252,7 +443,7 @@ fn expand_format_args<'hir>(
// This is an optimization, speeding up compilation about 1-2% in some cases.
// See https://github.com/rust-lang/rust/pull/106770#issuecomment-1380790609
let use_simple_array = argmap.len() == arguments.len()
- && argmap.iter().enumerate().all(|(i, &(j, _))| i == j)
+ && argmap.iter().enumerate().all(|(i, (&(j, _), _))| i == j)
&& arguments.iter().skip(1).all(|arg| !may_contain_yield_point(&arg.expr));
let args = if use_simple_array {
@@ -266,14 +457,19 @@ fn expand_format_args<'hir>(
let elements: Vec<_> = arguments
.iter()
.zip(argmap)
- .map(|(arg, (_, ty))| {
- let sp = arg.expr.span.with_ctxt(macsp.ctxt());
+ .map(|(arg, ((_, ty), placeholder_span))| {
+ let placeholder_span =
+ placeholder_span.unwrap_or(arg.expr.span).with_ctxt(macsp.ctxt());
+ let arg_span = match arg.kind {
+ FormatArgumentKind::Captured(_) => placeholder_span,
+ _ => arg.expr.span.with_ctxt(macsp.ctxt()),
+ };
let arg = ctx.lower_expr(&arg.expr);
let ref_arg = ctx.arena.alloc(ctx.expr(
- sp,
+ arg_span,
hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, arg),
));
- make_argument(ctx, sp, ref_arg, ty)
+ make_argument(ctx, placeholder_span, ref_arg, ty)
})
.collect();
ctx.expr_array_ref(macsp, ctx.arena.alloc_from_iter(elements))
@@ -289,27 +485,26 @@ fn expand_format_args<'hir>(
// }
let args_ident = Ident::new(sym::args, macsp);
let (args_pat, args_hir_id) = ctx.pat_ident(macsp, args_ident);
- let args = ctx.arena.alloc_from_iter(argmap.iter().map(|&(arg_index, ty)| {
- if let Some(arg) = arguments.get(arg_index) {
- let sp = arg.expr.span.with_ctxt(macsp.ctxt());
+ let args = ctx.arena.alloc_from_iter(argmap.iter().map(
+ |(&(arg_index, ty), &placeholder_span)| {
+ let arg = &arguments[arg_index];
+ let placeholder_span =
+ placeholder_span.unwrap_or(arg.expr.span).with_ctxt(macsp.ctxt());
+ let arg_span = match arg.kind {
+ FormatArgumentKind::Captured(_) => placeholder_span,
+ _ => arg.expr.span.with_ctxt(macsp.ctxt()),
+ };
let args_ident_expr = ctx.expr_ident(macsp, args_ident, args_hir_id);
let arg = ctx.arena.alloc(ctx.expr(
- sp,
+ arg_span,
hir::ExprKind::Field(
args_ident_expr,
Ident::new(sym::integer(arg_index), macsp),
),
));
- make_argument(ctx, sp, arg, ty)
- } else {
- ctx.expr(
- macsp,
- hir::ExprKind::Err(
- ctx.tcx.sess.delay_span_bug(macsp, format!("no arg at {arg_index}")),
- ),
- )
- }
- }));
+ make_argument(ctx, placeholder_span, arg, ty)
+ },
+ ));
let elements: Vec<_> = arguments
.iter()
.map(|arg| {
@@ -409,3 +604,22 @@ fn may_contain_yield_point(e: &ast::Expr) -> bool {
visitor.visit_expr(e);
visitor.0
}
+
+fn for_all_argument_indexes(template: &mut [FormatArgsPiece], mut f: impl FnMut(&mut usize)) {
+ for piece in template {
+ let FormatArgsPiece::Placeholder(placeholder) = piece else { continue };
+ if let Ok(index) = &mut placeholder.argument.index {
+ f(index);
+ }
+ if let Some(FormatCount::Argument(FormatArgPosition { index: Ok(index), .. })) =
+ &mut placeholder.format_options.width
+ {
+ f(index);
+ }
+ if let Some(FormatCount::Argument(FormatArgPosition { index: Ok(index), .. })) =
+ &mut placeholder.format_options.precision
+ {
+ f(index);
+ }
+ }
+}
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 41295f2b7..f89e254a2 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -12,8 +12,8 @@ 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_index::vec::{Idx, IndexSlice, IndexVec};
+use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::source_map::DesugaringKind;
use rustc_span::symbol::{kw, sym, Ident};
@@ -25,7 +25,7 @@ use thin_vec::ThinVec;
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) ast_index: &'a IndexSlice<LocalDefId, AstOwner<'a>>,
pub(super) owners: &'a mut IndexVec<LocalDefId, hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>>>,
}
@@ -229,12 +229,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.lower_use_tree(use_tree, &prefix, id, vis_span, ident, attrs)
}
- ItemKind::Static(t, m, e) => {
+ ItemKind::Static(box ast::StaticItem { ty: t, mutability: m, expr: e }) => {
let (ty, body_id) = self.lower_const_item(t, span, e.as_deref());
hir::ItemKind::Static(ty, *m, body_id)
}
- ItemKind::Const(_, t, e) => {
- let (ty, body_id) = self.lower_const_item(t, span, e.as_deref());
+ ItemKind::Const(box ast::ConstItem { ty, expr, .. }) => {
+ let (ty, body_id) = self.lower_const_item(ty, span, expr.as_deref());
hir::ItemKind::Const(ty, body_id)
}
ItemKind::Fn(box Fn {
@@ -708,10 +708,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
let trait_item_def_id = hir_id.expect_owner();
let (generics, kind, has_default) = match &i.kind {
- AssocItemKind::Const(_, ty, default) => {
+ AssocItemKind::Const(box ConstItem { ty, expr, .. }) => {
let ty =
self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy));
- let body = default.as_ref().map(|x| self.lower_const_body(i.span, Some(x)));
+ let body = expr.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 { sig, generics, body: None, .. }) => {
@@ -809,7 +809,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.lower_attrs(hir_id, &i.attrs);
let (generics, kind) = match &i.kind {
- AssocItemKind::Const(_, ty, expr) => {
+ AssocItemKind::Const(box ConstItem { ty, expr, .. }) => {
let ty =
self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy));
(
@@ -1146,7 +1146,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
let async_expr = this.make_async_expr(
CaptureBy::Value,
- fn_id,
closure_id,
None,
body.span,
@@ -1180,7 +1179,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
},
);
- (this.arena.alloc_from_iter(parameters), this.expr(body.span, async_expr))
+ let hir_id = this.lower_node_id(closure_id);
+ this.maybe_forward_track_caller(body.span, fn_id, hir_id);
+ let expr = hir::Expr { hir_id, kind: async_expr, span: this.lower_span(body.span) };
+
+ (this.arena.alloc_from_iter(parameters), expr)
})
}
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index b20157f2c..f7ae96b7c 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -60,13 +60,13 @@ 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_index::vec::{Idx, IndexSlice, IndexVec};
use rustc_macros::fluent_messages;
use rustc_middle::{
span_bug,
ty::{ResolverAstLowering, TyCtxt},
};
-use rustc_session::parse::feature_err;
+use rustc_session::parse::{add_feature_diagnostics, feature_err};
use rustc_span::hygiene::MacroKind;
use rustc_span::source_map::DesugaringKind;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -92,7 +92,7 @@ mod lifetime_collector;
mod pat;
mod path;
-fluent_messages! { "../locales/en-US.ftl" }
+fluent_messages! { "../messages.ftl" }
struct LoweringContext<'a, 'hir> {
tcx: TyCtxt<'hir>,
@@ -414,7 +414,7 @@ fn index_crate<'a>(
/// 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<'_>>>,
+ owners: &IndexSlice<LocalDefId, hir::MaybeOwner<&hir::OwnerInfo<'_>>>,
) -> Fingerprint {
let mut hir_body_nodes: Vec<_> = owners
.iter_enumerated()
@@ -435,7 +435,9 @@ fn compute_hir_hash(
pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> {
let sess = tcx.sess;
- tcx.ensure().output_filenames(());
+ // Queries that borrow `resolver_for_lowering`.
+ tcx.ensure_with_value().output_filenames(());
+ tcx.ensure_with_value().early_lint_checks(());
let (mut resolver, krate) = tcx.resolver_for_lowering(()).steal();
let ast_index = index_crate(&resolver.node_id_to_def_id, &krate);
@@ -463,8 +465,10 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> {
rustc_span::hygiene::clear_syntax_context_map();
}
- let hir_hash = compute_hir_hash(tcx, &owners);
- hir::Crate { owners, hir_hash }
+ // Don't hash unless necessary, because it's expensive.
+ let opt_hir_hash =
+ if tcx.sess.needs_crate_hash() { Some(compute_hir_hash(tcx, &owners)) } else { None };
+ hir::Crate { owners, opt_hir_hash }
}
#[derive(Copy, Clone, PartialEq, Debug)]
@@ -478,7 +482,7 @@ enum ParamMode {
}
enum ParenthesizedGenericArgs {
- Ok,
+ ParenSugar,
Err,
}
@@ -657,42 +661,33 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
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 };
- let attrs = {
- let hash = self.tcx.with_stable_hashing_context(|mut hcx| {
+
+ // Don't hash unless necessary, because it's expensive.
+ let (opt_hash_including_bodies, attrs_hash) = if self.tcx.sess.needs_crate_hash() {
+ self.tcx.with_stable_hashing_context(|mut hcx| {
+ let mut stable_hasher = StableHasher::new();
+ hcx.with_hir_bodies(node.def_id(), &bodies, |hcx| {
+ node.hash_stable(hcx, &mut stable_hasher)
+ });
+ let h1 = stable_hasher.finish();
+
let mut stable_hasher = StableHasher::new();
attrs.hash_stable(&mut hcx, &mut stable_hasher);
- stable_hasher.finish()
- });
- hir::AttributeMap { map: attrs, hash }
+ let h2 = stable_hasher.finish();
+
+ (Some(h1), Some(h2))
+ })
+ } else {
+ (None, None)
};
+ let (nodes, parenting) =
+ index::index_hir(self.tcx.sess, &*self.tcx.definitions_untracked(), node, &bodies);
+ let nodes = hir::OwnerNodes { opt_hash_including_bodies, nodes, bodies };
+ let attrs = hir::AttributeMap { map: attrs, opt_hash: 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(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.without_hir_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
@@ -993,13 +988,60 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.lower_angle_bracketed_parameter_data(data, ParamMode::Explicit, itctx).0
}
GenericArgs::Parenthesized(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
+ if data.inputs.is_empty() && matches!(data.output, FnRetTy::Default(..)) {
+ let parenthesized = if self.tcx.features().return_type_notation {
+ hir::GenericArgsParentheses::ReturnTypeNotation
+ } else {
+ self.emit_bad_parenthesized_trait_in_assoc_ty(data);
+ hir::GenericArgsParentheses::No
+ };
+ GenericArgsCtor {
+ args: Default::default(),
+ bindings: &[],
+ parenthesized,
+ span: data.inputs_span,
+ }
+ } else if let Some(first_char) = constraint.ident.as_str().chars().next()
+ && first_char.is_ascii_lowercase()
+ {
+ let mut err = if !data.inputs.is_empty() {
+ self.tcx.sess.create_err(errors::BadReturnTypeNotation::Inputs {
+ span: data.inputs_span,
+ })
+ } else if let FnRetTy::Ty(ty) = &data.output {
+ self.tcx.sess.create_err(errors::BadReturnTypeNotation::Output {
+ span: data.inputs_span.shrink_to_hi().to(ty.span),
+ })
+ } else {
+ unreachable!("inputs are empty and return type is not provided")
+ };
+ if !self.tcx.features().return_type_notation
+ && self.tcx.sess.is_nightly_build()
+ {
+ add_feature_diagnostics(
+ &mut err,
+ &self.tcx.sess.parse_sess,
+ sym::return_type_notation,
+ );
+ }
+ err.emit();
+ GenericArgsCtor {
+ args: Default::default(),
+ bindings: &[],
+ parenthesized: hir::GenericArgsParentheses::ReturnTypeNotation,
+ span: data.span,
+ }
+ } else {
+ self.emit_bad_parenthesized_trait_in_assoc_ty(data);
+ // FIXME(return_type_notation): we could issue a feature error
+ // if the parens are empty and there's no return type.
+ self.lower_angle_bracketed_parameter_data(
+ &data.as_angle_bracketed_args(),
+ ParamMode::Explicit,
+ itctx,
+ )
+ .0
+ }
}
};
gen_args_ctor.into_generic_args(self)
@@ -2080,7 +2122,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let future_args = self.arena.alloc(hir::GenericArgs {
args: &[],
bindings: arena_vec![self; self.output_ty_binding(span, output_ty)],
- parenthesized: false,
+ parenthesized: hir::GenericArgsParentheses::No,
span_ext: DUMMY_SP,
});
@@ -2190,7 +2232,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
def_id: self.local_def_id(param.id),
name,
span: self.lower_span(param.span()),
- pure_wrt_drop: self.tcx.sess.contains_name(&param.attrs, sym::may_dangle),
+ pure_wrt_drop: attr::contains_name(&param.attrs, sym::may_dangle),
kind,
colon_span: param.colon_span.map(|s| self.lower_span(s)),
source,
@@ -2600,13 +2642,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
struct GenericArgsCtor<'hir> {
args: SmallVec<[hir::GenericArg<'hir>; 4]>,
bindings: &'hir [hir::TypeBinding<'hir>],
- parenthesized: bool,
+ parenthesized: hir::GenericArgsParentheses,
span: Span,
}
impl<'hir> GenericArgsCtor<'hir> {
fn is_empty(&self) -> bool {
- self.args.is_empty() && self.bindings.is_empty() && !self.parenthesized
+ self.args.is_empty()
+ && self.bindings.is_empty()
+ && self.parenthesized == hir::GenericArgsParentheses::No
}
fn into_generic_args(self, this: &LoweringContext<'_, 'hir>) -> &'hir hir::GenericArgs<'hir> {
diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs
index 592fc5aa6..8eb84c036 100644
--- a/compiler/rustc_ast_lowering/src/path.rs
+++ b/compiler/rustc_ast_lowering/src/path.rs
@@ -51,7 +51,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let parenthesized_generic_args = match base_res {
// `a::b::Trait(Args)`
Res::Def(DefKind::Trait, _) if i + 1 == proj_start => {
- ParenthesizedGenericArgs::Ok
+ ParenthesizedGenericArgs::ParenSugar
}
// `a::b::Trait(Args)::TraitItem`
Res::Def(DefKind::AssocFn, _)
@@ -59,10 +59,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
| Res::Def(DefKind::AssocTy, _)
if i + 2 == proj_start =>
{
- ParenthesizedGenericArgs::Ok
+ ParenthesizedGenericArgs::ParenSugar
}
// Avoid duplicated errors.
- Res::Err => ParenthesizedGenericArgs::Ok,
+ Res::Err => ParenthesizedGenericArgs::ParenSugar,
// An error
_ => ParenthesizedGenericArgs::Err,
};
@@ -180,7 +180,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.lower_angle_bracketed_parameter_data(data, param_mode, itctx)
}
GenericArgs::Parenthesized(data) => match parenthesized_generic_args {
- ParenthesizedGenericArgs::Ok => {
+ ParenthesizedGenericArgs::ParenSugar => {
self.lower_parenthesized_parameter_data(data, itctx)
}
ParenthesizedGenericArgs::Err => {
@@ -224,7 +224,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
GenericArgsCtor {
args: Default::default(),
bindings: &[],
- parenthesized: false,
+ parenthesized: hir::GenericArgsParentheses::No,
span: path_span.shrink_to_hi(),
},
param_mode == ParamMode::Optional,
@@ -233,7 +233,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let has_lifetimes =
generic_args.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_)));
- if !generic_args.parenthesized && !has_lifetimes {
+
+ // FIXME(return_type_notation): Is this correct? I think so.
+ if generic_args.parenthesized != hir::GenericArgsParentheses::ParenSugar && !has_lifetimes {
self.maybe_insert_elided_lifetimes_in_path(
path_span,
segment.id,
@@ -328,7 +330,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
AngleBracketedArg::Constraint(c) => Some(self.lower_assoc_ty_constraint(c, itctx)),
AngleBracketedArg::Arg(_) => None,
}));
- let ctor = GenericArgsCtor { args, bindings, parenthesized: false, span: data.span };
+ let ctor = GenericArgsCtor {
+ args,
+ bindings,
+ parenthesized: hir::GenericArgsParentheses::No,
+ span: data.span,
+ };
(ctor, !has_non_lt_args && param_mode == ParamMode::Optional)
}
@@ -376,7 +383,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
GenericArgsCtor {
args,
bindings: arena_vec![self; binding],
- parenthesized: true,
+ parenthesized: hir::GenericArgsParentheses::ParenSugar,
span: data.inputs_span,
},
false,
@@ -396,7 +403,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let gen_args = self.arena.alloc(hir::GenericArgs {
args,
bindings,
- parenthesized: false,
+ parenthesized: hir::GenericArgsParentheses::No,
span_ext: DUMMY_SP,
});
hir::TypeBinding {