diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs index 03683ec9203c1..f4e19c8fb89bc 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs @@ -2815,6 +2815,44 @@ impl ExprCollector<'_> { mutability: Mutability::Shared, }) }; + + // Assume that rustc version >= 1.89.0 iff lang item `format_arguments` exists + // but `format_unsafe_arg` does not + let fmt_args = + || crate::lang_item::lang_item(self.db, self.module.krate(), LangItem::FormatArguments); + let fmt_unsafe_arg = + || crate::lang_item::lang_item(self.db, self.module.krate(), LangItem::FormatUnsafeArg); + let use_format_args_since_1_89_0 = fmt_args().is_some() && fmt_unsafe_arg().is_none(); + + let idx = if use_format_args_since_1_89_0 { + self.collect_format_args_impl(syntax_ptr, fmt, argmap, lit_pieces, format_options) + } else { + self.collect_format_args_before_1_89_0_impl( + syntax_ptr, + fmt, + argmap, + lit_pieces, + format_options, + ) + }; + + self.source_map + .template_map + .get_or_insert_with(Default::default) + .format_args_to_captures + .insert(idx, (hygiene, mappings)); + idx + } + + /// `format_args!` expansion implementation for rustc versions < `1.89.0` + fn collect_format_args_before_1_89_0_impl( + &mut self, + syntax_ptr: AstPtr, + fmt: FormatArgs, + argmap: FxIndexSet<(usize, ArgumentType)>, + lit_pieces: ExprId, + format_options: ExprId, + ) -> ExprId { let arguments = &*fmt.arguments.arguments; let args = if arguments.is_empty() { @@ -2902,19 +2940,189 @@ impl ExprCollector<'_> { }); } - let idx = self.alloc_expr( + self.alloc_expr( Expr::Call { callee: new_v1_formatted, args: Box::new([lit_pieces, args, format_options, unsafe_arg_new]), }, syntax_ptr, - ); - self.source_map - .template_map - .get_or_insert_with(Default::default) - .format_args_to_captures - .insert(idx, (hygiene, mappings)); - idx + ) + } + + /// `format_args!` expansion implementation for rustc versions >= `1.89.0`, + /// especially since [this PR](https://github.com/rust-lang/rust/pull/140748) + fn collect_format_args_impl( + &mut self, + syntax_ptr: AstPtr, + fmt: FormatArgs, + argmap: FxIndexSet<(usize, ArgumentType)>, + lit_pieces: ExprId, + format_options: ExprId, + ) -> ExprId { + let arguments = &*fmt.arguments.arguments; + + let (let_stmts, args) = if arguments.is_empty() { + ( + // Generate: + // [] + vec![], + self.alloc_expr_desugared(Expr::Array(Array::ElementList { + elements: Box::default(), + })), + ) + } else if argmap.len() == 1 && arguments.len() == 1 { + // Only one argument, so we don't need to make the `args` tuple. + // + // Generate: + // super let args = [::new_display(&arg)]; + let args = argmap + .iter() + .map(|&(arg_index, ty)| { + let ref_arg = self.alloc_expr_desugared(Expr::Ref { + expr: arguments[arg_index].expr, + rawness: Rawness::Ref, + mutability: Mutability::Shared, + }); + self.make_argument(ref_arg, ty) + }) + .collect(); + let args = + self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args })); + let args_name = Name::new_symbol_root(sym::args); + let args_binding = self.alloc_binding( + args_name.clone(), + BindingAnnotation::Unannotated, + HygieneId::ROOT, + ); + let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None }); + self.add_definition_to_binding(args_binding, args_pat); + // TODO: We don't have `super let` yet. + let let_stmt = Statement::Let { + pat: args_pat, + type_ref: None, + initializer: Some(args), + else_branch: None, + }; + (vec![let_stmt], self.alloc_expr_desugared(Expr::Path(args_name.into()))) + } else { + // Generate: + // super let args = (&arg0, &arg1, &...); + let args_name = Name::new_symbol_root(sym::args); + let args_binding = self.alloc_binding( + args_name.clone(), + BindingAnnotation::Unannotated, + HygieneId::ROOT, + ); + let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None }); + self.add_definition_to_binding(args_binding, args_pat); + let elements = arguments + .iter() + .map(|arg| { + self.alloc_expr_desugared(Expr::Ref { + expr: arg.expr, + rawness: Rawness::Ref, + mutability: Mutability::Shared, + }) + }) + .collect(); + let args_tuple = self.alloc_expr_desugared(Expr::Tuple { exprs: elements }); + // TODO: We don't have `super let` yet + let let_stmt1 = Statement::Let { + pat: args_pat, + type_ref: None, + initializer: Some(args_tuple), + else_branch: None, + }; + + // Generate: + // super let args = [ + // ::new_display(args.0), + // ::new_lower_hex(args.1), + // ::new_debug(args.0), + // … + // ]; + let args = argmap + .iter() + .map(|&(arg_index, ty)| { + let args_ident_expr = + self.alloc_expr_desugared(Expr::Path(args_name.clone().into())); + let arg = self.alloc_expr_desugared(Expr::Field { + expr: args_ident_expr, + name: Name::new_tuple_field(arg_index), + }); + self.make_argument(arg, ty) + }) + .collect(); + let array = + self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args })); + let args_binding = self.alloc_binding( + args_name.clone(), + BindingAnnotation::Unannotated, + HygieneId::ROOT, + ); + let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None }); + self.add_definition_to_binding(args_binding, args_pat); + let let_stmt2 = Statement::Let { + pat: args_pat, + type_ref: None, + initializer: Some(array), + else_branch: None, + }; + (vec![let_stmt1, let_stmt2], self.alloc_expr_desugared(Expr::Path(args_name.into()))) + }; + + // Generate: + // &args + let args = self.alloc_expr_desugared(Expr::Ref { + expr: args, + rawness: Rawness::Ref, + mutability: Mutability::Shared, + }); + + let call_block = { + // Generate: + // unsafe { + // ::new_v1_formatted( + // lit_pieces, + // args, + // format_options, + // ) + // } + + let new_v1_formatted = LangItem::FormatArguments.ty_rel_path( + self.db, + self.module.krate(), + Name::new_symbol_root(sym::new_v1_formatted), + ); + let new_v1_formatted = + self.alloc_expr_desugared(new_v1_formatted.map_or(Expr::Missing, Expr::Path)); + let args = [lit_pieces, args, format_options]; + let call = self + .alloc_expr_desugared(Expr::Call { callee: new_v1_formatted, args: args.into() }); + + Expr::Unsafe { id: None, statements: Box::default(), tail: Some(call) } + }; + + if !let_stmts.is_empty() { + // Generate: + // { + // super let … + // super let … + // ::new_…(…) + // } + let call = self.alloc_expr_desugared(call_block); + self.alloc_expr( + Expr::Block { + id: None, + statements: let_stmts.into(), + tail: Some(call), + label: None, + }, + syntax_ptr, + ) + } else { + self.alloc_expr(call_block, syntax_ptr) + } } /// Generate a hir expression for a format_args placeholder specification. diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs index 29e249b07a72e..927e280d73943 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs @@ -178,14 +178,14 @@ fn main() { } #[test] -fn desugar_builtin_format_args() { +fn desugar_builtin_format_args_before_1_89_0() { let (db, body, def) = lower( r#" -//- minicore: fmt +//- minicore: fmt_before_1_89_0 fn main() { let are = "are"; let count = 10; - builtin#format_args("\u{1b}hello {count:02} {} friends, we {are:?} {0}{last}", "fancy", last = "!"); + builtin#format_args("\u{1b}hello {count:02} {} friends, we {are:?} {0}{last}", "fancy", orphan = (), last = "!"); } "#, ); @@ -249,14 +249,100 @@ fn main() { builtin#lang(Count::Implied), ), ], - unsafe { - builtin#lang(UnsafeArg::new)() + { + (); + unsafe { + builtin#lang(UnsafeArg::new)() + } }, ); }"#]] .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT)) } +#[test] +fn desugar_builtin_format_args() { + let (db, body, def) = lower( + r#" +//- minicore: fmt +fn main() { + let are = "are"; + let count = 10; + builtin#format_args("\u{1b}hello {count:02} {} friends, we {are:?} {0}{last}", "fancy", orphan = (), last = "!"); +} +"#, + ); + + expect![[r#" + fn main() { + let are = "are"; + let count = 10; + { + let args = (&"fancy", &(), &"!", &count, &are, ); + let args = [ + builtin#lang(Argument::new_display)( + args.3, + ), builtin#lang(Argument::new_display)( + args.0, + ), builtin#lang(Argument::new_debug)( + args.4, + ), builtin#lang(Argument::new_display)( + args.2, + ), + ]; + unsafe { + builtin#lang(Arguments::new_v1_formatted)( + &[ + "\u{1b}hello ", " ", " friends, we ", " ", "", + ], + &args, + &[ + builtin#lang(Placeholder::new)( + 0usize, + ' ', + builtin#lang(Alignment::Unknown), + 8u32, + builtin#lang(Count::Implied), + builtin#lang(Count::Is)( + 2, + ), + ), builtin#lang(Placeholder::new)( + 1usize, + ' ', + builtin#lang(Alignment::Unknown), + 0u32, + builtin#lang(Count::Implied), + builtin#lang(Count::Implied), + ), builtin#lang(Placeholder::new)( + 2usize, + ' ', + builtin#lang(Alignment::Unknown), + 0u32, + builtin#lang(Count::Implied), + builtin#lang(Count::Implied), + ), builtin#lang(Placeholder::new)( + 1usize, + ' ', + builtin#lang(Alignment::Unknown), + 0u32, + builtin#lang(Count::Implied), + builtin#lang(Count::Implied), + ), builtin#lang(Placeholder::new)( + 3usize, + ' ', + builtin#lang(Alignment::Unknown), + 0u32, + builtin#lang(Count::Implied), + builtin#lang(Count::Implied), + ), + ], + ) + } + }; + }"#]] + .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT)) +} + #[test] fn test_macro_hygiene() { let (db, body, def) = lower( @@ -295,29 +381,31 @@ impl SsrError { expect![[r#" fn main() { _ = ra_test_fixture::error::SsrError::new( - builtin#lang(Arguments::new_v1_formatted)( - &[ - "Failed to resolve path `", "`", - ], - &[ + { + let args = [ builtin#lang(Argument::new_display)( &node.text(), ), - ], - &[ - builtin#lang(Placeholder::new)( - 0usize, - ' ', - builtin#lang(Alignment::Unknown), - 0u32, - builtin#lang(Count::Implied), - builtin#lang(Count::Implied), - ), - ], + ]; unsafe { - builtin#lang(UnsafeArg::new)() - }, - ), + builtin#lang(Arguments::new_v1_formatted)( + &[ + "Failed to resolve path `", "`", + ], + &args, + &[ + builtin#lang(Placeholder::new)( + 0usize, + ' ', + builtin#lang(Alignment::Unknown), + 0u32, + builtin#lang(Count::Implied), + builtin#lang(Count::Implied), + ), + ], + ) + } + }, ); }"#]] .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT)) @@ -327,7 +415,7 @@ impl SsrError { fn regression_10300() { let (db, body, def) = lower( r#" -//- minicore: concat, panic +//- minicore: concat, panic, fmt_before_1_89_0 mod private { pub use core::concat; } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs index faff7d036a289..71c8808d331f1 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs @@ -304,6 +304,8 @@ impl LangItem { language_item_table! { // Variant name, Name, Getter method name, Target Generic requirements; Sized, sym::sized, sized_trait, Target::Trait, GenericRequirement::Exact(0); + MetaSized, sym::meta_sized, sized_trait, Target::Trait, GenericRequirement::Exact(0); + PointeeSized, sym::pointee_sized, sized_trait, Target::Trait, GenericRequirement::Exact(0); Unsize, sym::unsize, unsize_trait, Target::Trait, GenericRequirement::Minimum(1); /// Trait injected by `#[derive(PartialEq)]`, (i.e. "Partial EQ"). StructuralPeq, sym::structural_peq, structural_peq_trait, Target::Trait, GenericRequirement::None; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs index 0a546768dab4d..27a5dcbbc3ffe 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -581,11 +581,28 @@ impl<'a> TyLoweringContext<'a> { match bound { &TypeBound::Path(path, TraitBoundModifier::None) | &TypeBound::ForLifetime(_, path) => { // FIXME Don't silently drop the hrtb lifetimes here - if let Some((trait_ref, ctx)) = self.lower_trait_ref_from_path(path, self_ty) { - if !ignore_bindings { - assoc_bounds = ctx.assoc_type_bindings_from_type_bound(trait_ref.clone()); + if let Some((trait_ref, mut ctx)) = + self.lower_trait_ref_from_path(path, self_ty.clone()) + { + // FIXME(sized-hierarchy): Remove this bound modifications once we have implemented + // sized-hierarchy correctly. + let meta_sized = LangItem::MetaSized + .resolve_trait(ctx.ty_ctx().db, ctx.ty_ctx().resolver.krate()); + let pointee_sized = LangItem::PointeeSized + .resolve_trait(ctx.ty_ctx().db, ctx.ty_ctx().resolver.krate()); + if meta_sized.is_some_and(|it| it == trait_ref.hir_trait_id()) { + // Ignore this bound + } else if pointee_sized.is_some_and(|it| it == trait_ref.hir_trait_id()) { + // Regard this as `?Sized` bound + ctx.ty_ctx().unsized_types.insert(self_ty); + } else { + if !ignore_bindings { + assoc_bounds = + ctx.assoc_type_bindings_from_type_bound(trait_ref.clone()); + } + clause = + Some(crate::wrap_empty_binders(WhereClause::Implemented(trait_ref))); } - clause = Some(crate::wrap_empty_binders(WhereClause::Implemented(trait_ref))); } } &TypeBound::Path(path, TraitBoundModifier::Maybe) => { @@ -936,8 +953,32 @@ pub(crate) fn generic_predicates_for_param_query( | WherePredicate::TypeBound { target, bound, .. } => { let invalid_target = { ctx.lower_ty_only_param(*target) != Some(param_id) }; if invalid_target { - // If this is filtered out without lowering, `?Sized` is not gathered into `ctx.unsized_types` - if let TypeBound::Path(_, TraitBoundModifier::Maybe) = bound { + // FIXME(sized-hierarchy): Revisit and adjust this properly once we have implemented + // sized-hierarchy correctly. + // If this is filtered out without lowering, `?Sized` or `PointeeSized` is not gathered into + // `ctx.unsized_types` + let lower = || -> bool { + match bound { + TypeBound::Path(_, TraitBoundModifier::Maybe) => true, + TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => { + let TypeRef::Path(path) = &ctx.store[path.type_ref()] else { + return false; + }; + let Some(pointee_sized) = + LangItem::PointeeSized.resolve_trait(ctx.db, ctx.resolver.krate()) + else { + return false; + }; + // Lower the path directly with `Resolver` instead of PathLoweringContext` + // to prevent diagnostics duplications. + ctx.resolver.resolve_path_in_type_ns_fully(ctx.db, path).is_some_and( + |it| matches!(it, TypeNs::TraitId(tr) if tr == pointee_sized), + ) + } + _ => false, + } + }(); + if lower { ctx.lower_where_predicate(pred, true).for_each(drop); } return false; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs index 3abbbe45e6f87..c1f86960e154c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs @@ -984,3 +984,17 @@ fn main<'a, T: Foo + Bar + Baz>( |e| matches!(e, MirEvalError::MirLowerError(_, MirLowerError::GenericArgNotProvided(..))), ); } + +#[test] +fn format_args_pass() { + check_pass( + r#" +//- minicore: fmt +fn main() { + let x1 = format_args!(""); + let x2 = format_args!("{}", x1); + let x3 = format_args!("{} {}", x1, x2); +} +"#, + ); +} diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_is_method.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_is_method.rs index 3e6d0bec68a6f..517906b429a6f 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_is_method.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_is_method.rs @@ -1,3 +1,5 @@ +use std::slice; + use ide_db::assists::GroupLabel; use stdx::to_lower_snake_case; use syntax::ast::HasVisibility; @@ -52,7 +54,7 @@ pub(crate) fn generate_enum_is_method(acc: &mut Assists, ctx: &AssistContext<'_> let fn_name = format!("is_{}", &to_lower_snake_case(&variant_name.text())); // Return early if we've found an existing new fn - let impl_def = find_struct_impl(ctx, &parent_enum, &[fn_name.clone()])?; + let impl_def = find_struct_impl(ctx, &parent_enum, slice::from_ref(&fn_name))?; let target = variant.syntax().text_range(); acc.add_group( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_projection_method.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_projection_method.rs index 3974bcf618756..e4b0f83049768 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_projection_method.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_projection_method.rs @@ -1,3 +1,5 @@ +use std::slice; + use ide_db::assists::GroupLabel; use itertools::Itertools; use stdx::to_lower_snake_case; @@ -148,7 +150,7 @@ fn generate_enum_projection_method( let fn_name = format!("{fn_name_prefix}_{}", &to_lower_snake_case(&variant_name.text())); // Return early if we've found an existing new fn - let impl_def = find_struct_impl(ctx, &parent_enum, &[fn_name.clone()])?; + let impl_def = find_struct_impl(ctx, &parent_enum, slice::from_ref(&fn_name))?; let target = variant.syntax().text_range(); acc.add_group( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs index 6af8e1482c245..7ddbb74b82211 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs @@ -111,7 +111,7 @@ fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#, check_assist( term_search, r#"//- minicore: todo, unimplemented -fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#, +fn f() { let a: u128 = 1; let b: u128 = unimplemented$0!("asd") }"#, r#"fn f() { let a: u128 = 1; let b: u128 = a }"#, ) } @@ -121,7 +121,7 @@ fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#, check_assist( term_search, r#"//- minicore: todo, unimplemented -fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#, +fn f() { let a: u128 = 1; let b: u128 = unimplemented$0!() }"#, r#"fn f() { let a: u128 = 1; let b: u128 = a }"#, ) } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs index b46e4c32061b4..b2d18b796f195 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs @@ -1474,20 +1474,18 @@ fn main() { } "#, expect![[r#" + me foo() fn(&self) sn box Box::new(expr) sn call function(expr) sn const const {} sn dbg dbg!(expr) sn dbgr dbg!(&expr) sn deref *expr - sn if if expr {} sn match match expr {} - sn not !expr sn ref &expr sn refm &mut expr sn return return expr sn unsafe unsafe {} - sn while while expr {} "#]], ); } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs index 6bd5417b25d75..d8f6e813d8001 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs @@ -628,6 +628,17 @@ fn main() { #[test] fn orphan_unsafe_format_args() { // Checks that we don't place orphan arguments for formatting under an unsafe block. + check_diagnostics( + r#" +//- minicore: fmt_before_1_89_0 +fn foo() { + let p = 0xDEADBEEF as *const i32; + format_args!("", *p); + // ^^ error: dereference of raw pointer is unsafe and requires an unsafe function or block +} + "#, + ); + check_diagnostics( r#" //- minicore: fmt @@ -958,4 +969,18 @@ impl FooTrait for S2 { "#, ); } + + #[test] + fn no_false_positive_on_format_args_since_1_89_0() { + check_diagnostics( + r#" +//- minicore: fmt +fn test() { + let foo = 10; + let bar = true; + let _x = format_args!("{} {0} {} {last}", foo, bar, last = "!"); +} + "#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs index b9a98f88be761..f0003dae3f36f 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs @@ -143,7 +143,7 @@ fn foo() {} file_id: FileId( 1, ), - range: 135..140, + range: 446..451, }, ), ), diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs index d5cbb7328c14a..1ccd20c25e906 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs +++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs @@ -438,6 +438,8 @@ define_symbols! { shr, simd, sized, + meta_sized, + pointee_sized, skip, slice_len_fn, Some, @@ -496,6 +498,7 @@ define_symbols! { vectorcall, wasm, win64, + args, array, boxed_slice, completions, diff --git a/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs b/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs index 7240069753e82..1d821e96e550b 100644 --- a/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs +++ b/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs @@ -412,22 +412,36 @@ impl MiniCore { } let mut active_regions = Vec::new(); + let mut inactive_regions = Vec::new(); let mut seen_regions = Vec::new(); for line in lines { let trimmed = line.trim(); if let Some(region) = trimmed.strip_prefix("// region:") { - active_regions.push(region); - continue; + if let Some(region) = region.strip_prefix('!') { + inactive_regions.push(region); + continue; + } else { + active_regions.push(region); + continue; + } } if let Some(region) = trimmed.strip_prefix("// endregion:") { - let prev = active_regions.pop().unwrap(); + let (prev, region) = if let Some(region) = region.strip_prefix('!') { + (inactive_regions.pop().unwrap(), region) + } else { + (active_regions.pop().unwrap(), region) + }; assert_eq!(prev, region, "unbalanced region pairs"); continue; } - let mut line_region = false; - if let Some(idx) = trimmed.find("// :") { - line_region = true; + let mut active_line_region = false; + let mut inactive_line_region = false; + if let Some(idx) = trimmed.find("// :!") { + inactive_line_region = true; + inactive_regions.push(&trimmed[idx + "// :!".len()..]); + } else if let Some(idx) = trimmed.find("// :") { + active_line_region = true; active_regions.push(&trimmed[idx + "// :".len()..]); } @@ -438,18 +452,30 @@ impl MiniCore { seen_regions.push(region); keep &= self.has_flag(region); } + for ®ion in &inactive_regions { + assert!(!region.starts_with(' '), "region marker starts with a space: {region:?}"); + self.assert_valid_flag(region); + seen_regions.push(region); + keep &= !self.has_flag(region); + } if keep { buf.push_str(line); } - if line_region { + if active_line_region { active_regions.pop().unwrap(); } + if inactive_line_region { + inactive_regions.pop().unwrap(); + } } if !active_regions.is_empty() { panic!("unclosed regions: {active_regions:?} Add an `endregion` comment"); } + if !inactive_regions.is_empty() { + panic!("unclosed regions: {inactive_regions:?} Add an `endregion` comment"); + } for flag in &self.valid_flags { if !seen_regions.iter().any(|it| it == flag) { diff --git a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs index 4bdd791eb1671..20566f3acec1d 100644 --- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs +++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs @@ -26,17 +26,18 @@ //! deref: sized //! derive: //! discriminant: -//! drop: +//! drop: sized //! env: option //! eq: sized //! error: fmt //! fmt: option, result, transmute, coerce_unsized, copy, clone, derive +//! fmt_before_1_89_0: fmt //! fn: tuple //! from: sized, result //! future: pin //! coroutine: pin //! dispatch_from_dyn: unsize, pin -//! hash: +//! hash: sized //! include: //! index: sized //! infallible: @@ -76,33 +77,46 @@ pub mod marker { // region:sized + #[lang = "pointee_sized"] + #[fundamental] + #[rustc_specialization_trait] + #[rustc_coinductive] + pub trait PointeeSized {} + + #[lang = "meta_sized"] + #[fundamental] + #[rustc_specialization_trait] + #[rustc_coinductive] + pub trait MetaSized: PointeeSized {} + #[lang = "sized"] #[fundamental] #[rustc_specialization_trait] - pub trait Sized {} + #[rustc_coinductive] + pub trait Sized: MetaSized {} // endregion:sized // region:send pub unsafe auto trait Send {} - impl !Send for *const T {} - impl !Send for *mut T {} + impl !Send for *const T {} + impl !Send for *mut T {} // region:sync - unsafe impl Send for &T {} - unsafe impl Send for &mut T {} + unsafe impl Send for &T {} + unsafe impl Send for &mut T {} // endregion:sync // endregion:send // region:sync pub unsafe auto trait Sync {} - impl !Sync for *const T {} - impl !Sync for *mut T {} + impl !Sync for *const T {} + impl !Sync for *mut T {} // endregion:sync // region:unsize #[lang = "unsize"] - pub trait Unsize {} + pub trait Unsize: PointeeSized {} // endregion:unsize // region:unpin @@ -119,7 +133,7 @@ pub mod marker { // endregion:derive mod copy_impls { - use super::Copy; + use super::{Copy, PointeeSized}; macro_rules! impl_copy { ($($t:ty)*) => { @@ -136,9 +150,9 @@ pub mod marker { bool char } - impl Copy for *const T {} - impl Copy for *mut T {} - impl Copy for &T {} + impl Copy for *const T {} + impl Copy for *mut T {} + impl Copy for &T {} impl Copy for ! {} } // endregion:copy @@ -150,7 +164,7 @@ pub mod marker { // region:phantom_data #[lang = "phantom_data"] - pub struct PhantomData; + pub struct PhantomData; // endregion:phantom_data // region:discriminant @@ -205,9 +219,11 @@ pub mod default { // region:hash pub mod hash { + use crate::marker::PointeeSized; + pub trait Hasher {} - pub trait Hash { + pub trait Hash: PointeeSized { fn hash(&self, state: &mut H); } @@ -220,10 +236,11 @@ pub mod hash { // region:cell pub mod cell { + use crate::marker::PointeeSized; use crate::mem; #[lang = "unsafe_cell"] - pub struct UnsafeCell { + pub struct UnsafeCell { value: T, } @@ -237,7 +254,7 @@ pub mod cell { } } - pub struct Cell { + pub struct Cell { value: UnsafeCell, } @@ -356,7 +373,7 @@ pub mod convert { // endregion:from // region:as_ref - pub trait AsRef { + pub trait AsRef: crate::marker::PointeeSized { fn as_ref(&self) -> &T; } // endregion:as_ref @@ -367,9 +384,11 @@ pub mod convert { pub mod mem { // region:manually_drop + use crate::marker::PointeeSized; + #[lang = "manually_drop"] #[repr(transparent)] - pub struct ManuallyDrop { + pub struct ManuallyDrop { value: T, } @@ -380,7 +399,7 @@ pub mod mem { } // region:deref - impl crate::ops::Deref for ManuallyDrop { + impl crate::ops::Deref for ManuallyDrop { type Target = T; fn deref(&self) -> &T { &self.value @@ -427,7 +446,7 @@ pub mod mem { pub mod ptr { // region:drop #[lang = "drop_in_place"] - pub unsafe fn drop_in_place(to_drop: *mut T) { + pub unsafe fn drop_in_place(to_drop: *mut T) { unsafe { drop_in_place(to_drop) } } pub const unsafe fn read(src: *const T) -> T { @@ -443,7 +462,7 @@ pub mod ptr { // region:pointee #[lang = "pointee_trait"] #[rustc_deny_explicit_impl(implement_via_object = false)] - pub trait Pointee { + pub trait Pointee: crate::marker::PointeeSized { #[lang = "metadata_type"] type Metadata: Copy + Send + Sync + Ord + Hash + Unpin; } @@ -451,12 +470,14 @@ pub mod ptr { // region:non_null #[rustc_layout_scalar_valid_range_start(1)] #[rustc_nonnull_optimization_guaranteed] - pub struct NonNull { + pub struct NonNull { pointer: *const T, } // region:coerce_unsized - impl crate::ops::CoerceUnsized> for NonNull where - T: crate::marker::Unsize + impl + crate::ops::CoerceUnsized> for NonNull + where + T: crate::marker::Unsize, { } // endregion:coerce_unsized @@ -477,42 +498,44 @@ pub mod ptr { pub mod ops { // region:coerce_unsized mod unsize { - use crate::marker::Unsize; + use crate::marker::{PointeeSized, Unsize}; #[lang = "coerce_unsized"] - pub trait CoerceUnsized {} + pub trait CoerceUnsized {} - impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {} - impl<'a, 'b: 'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<&'a U> for &'b mut T {} - impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<*mut U> for &'a mut T {} - impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<*const U> for &'a mut T {} + impl<'a, T: PointeeSized + Unsize, U: PointeeSized> CoerceUnsized<&'a mut U> for &'a mut T {} + impl<'a, 'b: 'a, T: PointeeSized + Unsize, U: PointeeSized> CoerceUnsized<&'a U> for &'b mut T {} + impl<'a, T: PointeeSized + Unsize, U: PointeeSized> CoerceUnsized<*mut U> for &'a mut T {} + impl<'a, T: PointeeSized + Unsize, U: PointeeSized> CoerceUnsized<*const U> for &'a mut T {} - impl<'a, 'b: 'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} - impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<*const U> for &'a T {} + impl<'a, 'b: 'a, T: PointeeSized + Unsize, U: PointeeSized> CoerceUnsized<&'a U> for &'b T {} + impl<'a, T: PointeeSized + Unsize, U: PointeeSized> CoerceUnsized<*const U> for &'a T {} - impl, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} - impl, U: ?Sized> CoerceUnsized<*const U> for *mut T {} - impl, U: ?Sized> CoerceUnsized<*const U> for *const T {} + impl, U: PointeeSized> CoerceUnsized<*mut U> for *mut T {} + impl, U: PointeeSized> CoerceUnsized<*const U> for *mut T {} + impl, U: PointeeSized> CoerceUnsized<*const U> for *const T {} } pub use self::unsize::CoerceUnsized; // endregion:coerce_unsized // region:deref mod deref { + use crate::marker::PointeeSized; + #[lang = "deref"] - pub trait Deref { + pub trait Deref: PointeeSized { #[lang = "deref_target"] type Target: ?Sized; fn deref(&self) -> &Self::Target; } - impl Deref for &T { + impl Deref for &T { type Target = T; fn deref(&self) -> &T { loop {} } } - impl Deref for &mut T { + impl Deref for &mut T { type Target = T; fn deref(&self) -> &T { loop {} @@ -520,19 +543,19 @@ pub mod ops { } // region:deref_mut #[lang = "deref_mut"] - pub trait DerefMut: Deref { + pub trait DerefMut: Deref + PointeeSized { fn deref_mut(&mut self) -> &mut Self::Target; } // endregion:deref_mut // region:receiver #[lang = "receiver"] - pub trait Receiver { + pub trait Receiver: PointeeSized { #[lang = "receiver_target"] type Target: ?Sized; } - impl Receiver for P + impl Receiver for P where P: Deref, { @@ -1005,18 +1028,18 @@ pub mod ops { // region:dispatch_from_dyn mod dispatch_from_dyn { - use crate::marker::Unsize; + use crate::marker::{PointeeSized, Unsize}; #[lang = "dispatch_from_dyn"] pub trait DispatchFromDyn {} - impl<'a, T: ?Sized + Unsize, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {} + impl<'a, T: PointeeSized + Unsize, U: PointeeSized> DispatchFromDyn<&'a U> for &'a T {} - impl<'a, T: ?Sized + Unsize, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {} + impl<'a, T: PointeeSized + Unsize, U: PointeeSized> DispatchFromDyn<&'a mut U> for &'a mut T {} - impl, U: ?Sized> DispatchFromDyn<*const U> for *const T {} + impl, U: PointeeSized> DispatchFromDyn<*const U> for *const T {} - impl, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {} + impl, U: PointeeSized> DispatchFromDyn<*mut U> for *mut T {} } pub use self::dispatch_from_dyn::DispatchFromDyn; // endregion:dispatch_from_dyn @@ -1024,15 +1047,17 @@ pub mod ops { // region:eq pub mod cmp { + use crate::marker::PointeeSized; + #[lang = "eq"] - pub trait PartialEq { + pub trait PartialEq: PointeeSized { fn eq(&self, other: &Rhs) -> bool; fn ne(&self, other: &Rhs) -> bool { !self.eq(other) } } - pub trait Eq: PartialEq {} + pub trait Eq: PartialEq + PointeeSized {} // region:derive #[rustc_builtin_macro] @@ -1043,11 +1068,11 @@ pub mod cmp { // region:ord #[lang = "partial_ord"] - pub trait PartialOrd: PartialEq { + pub trait PartialOrd: PartialEq + PointeeSized { fn partial_cmp(&self, other: &Rhs) -> Option; } - pub trait Ord: Eq + PartialOrd { + pub trait Ord: Eq + PartialOrd + PointeeSized { fn cmp(&self, other: &Self) -> Ordering; } @@ -1070,6 +1095,8 @@ pub mod cmp { // region:fmt pub mod fmt { + use crate::marker::PointeeSized; + pub struct Error; pub type Result = crate::result::Result<(), Error>; pub struct Formatter<'a>; @@ -1105,10 +1132,10 @@ pub mod fmt { } } - pub trait Debug { + pub trait Debug: PointeeSized { fn fmt(&self, f: &mut Formatter<'_>) -> Result; } - pub trait Display { + pub trait Display: PointeeSized { fn fmt(&self, f: &mut Formatter<'_>) -> Result; } @@ -1175,6 +1202,7 @@ pub mod fmt { } } + // region:fmt_before_1_89_0 #[lang = "format_unsafe_arg"] pub struct UnsafeArg { _private: (), @@ -1185,6 +1213,7 @@ pub mod fmt { UnsafeArg { _private: () } } } + // endregion:fmt_before_1_89_0 } #[derive(Copy, Clone)] @@ -1204,6 +1233,7 @@ pub mod fmt { Arguments { pieces, fmt: None, args: &[] } } + // region:fmt_before_1_89_0 pub fn new_v1_formatted( pieces: &'a [&'static str], args: &'a [rt::Argument<'a>], @@ -1212,6 +1242,17 @@ pub mod fmt { ) -> Arguments<'a> { Arguments { pieces, fmt: Some(fmt), args } } + // endregion:fmt_before_1_89_0 + + // region:!fmt_before_1_89_0 + pub unsafe fn new_v1_formatted( + pieces: &'a [&'static str], + args: &'a [rt::Argument<'a>], + fmt: &'a [rt::Placeholder], + ) -> Arguments<'a> { + Arguments { pieces, fmt: Some(fmt), args } + } + // endregion:!fmt_before_1_89_0 pub const fn as_str(&self) -> Option<&'static str> { match (self.pieces, self.args) { @@ -1253,7 +1294,7 @@ pub mod fmt { } } - impl Debug for &T { + impl Debug for &T { fn fmt(&self, f: &mut Formatter<'_>) -> Result { (&**self).fmt(f) } @@ -1497,6 +1538,8 @@ pub mod iter { mod traits { mod iterator { + use crate::marker::PointeeSized; + #[doc(notable_trait)] #[lang = "iterator"] pub trait Iterator { @@ -1528,7 +1571,7 @@ pub mod iter { } // endregion:iterators } - impl Iterator for &mut I { + impl Iterator for &mut I { type Item = I::Item; fn next(&mut self) -> Option { (**self).next()