diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:20:29 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:20:29 +0000 |
commit | 631cd5845e8de329d0e227aaa707d7ea228b8f8f (patch) | |
tree | a1b87c8f8cad01cf18f7c5f57a08f102771ed303 /compiler/rustc_ast_lowering | |
parent | Adding debian version 1.69.0+dfsg1-1. (diff) | |
download | rustc-631cd5845e8de329d0e227aaa707d7ea228b8f8f.tar.xz rustc-631cd5845e8de329d0e227aaa707d7ea228b8f8f.zip |
Merging upstream version 1.70.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
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.rs | 18 | ||||
-rw-r--r-- | compiler/rustc_ast_lowering/src/expr.rs | 92 | ||||
-rw-r--r-- | compiler/rustc_ast_lowering/src/format.rs | 274 | ||||
-rw-r--r-- | compiler/rustc_ast_lowering/src/item.rs | 25 | ||||
-rw-r--r-- | compiler/rustc_ast_lowering/src/lib.rs | 140 | ||||
-rw-r--r-- | compiler/rustc_ast_lowering/src/path.rs | 25 |
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(¶m.attrs, sym::may_dangle), + pure_wrt_drop: attr::contains_name(¶m.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 { |